package catalogue import ( "os" "path/filepath" "reflect" "testing" ) // A bar's blocks are a collection of text (design 57 L3, issue 781): the holder of node-bar names the kind as // `${collected:contribution:node-bar:block:bar=,place=
}`, which a handed collector has its client fill from the // items and an unhanded one has the controller fill as it fills the old placeholder. const ( collectedBarsText = "top\n${collected:contribution:node-bar:block:bar=top,place=status}" + "bottom\n${collected:contribution:node-bar:block:bar=bottom,place=status}" collectedBars = `{"module":"bars","version":"1","moved":true, "claims":[{"name":"node-bar","scope":"node","renders":{"block":"{{.shows}}"}}], "build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]}, "resources":[{"id":"conf","type":"file","path":"/etc/bars.conf","template":"files/bars"}]}` itemsOfPower = `{"module":"power","version":"1","moved":true, "items":[{"collection":"contribution:node-bar:block","name":"battery","if-capability":"battery","attributes":{"bar":"bottom","place":"status","order":"40"},"template":"files/battery"}, {"collection":"contribution:node-bar:block","name":"draw","attributes":{"bar":"bottom","place":"status","order":"45"},"template":"files/draw"}], "build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]}}` ) func collectedBarsOn(t *testing.T, caps map[string]bool) Resolution { t.Helper() bars := held(t, collectedBars, builtWith("bars", map[string]string{"bars": collectedBarsText})) power := held(t, itemsOfPower, builtWith("power", map[string]string{"battery": "B\n", "draw": "D ${machine:name}\n"})) r, err := Resolve(shelf(bars, power), []string{"bars", "power"}, workstation(), World{}) if err != nil { t.Fatal(err) } r.Account, r.Capabilities = "op", caps return r } func TestACollectorMayNameTheBarsBlocksAsACollectionAndNoOtherDataKind(t *testing.T) { bars := held(t, collectedBars, builtWith("bars", map[string]string{"bars": collectedBarsText})) if _, err := collectedBarsOn(t, nil).Compose(handingTo("store:5000")); err != nil { t.Fatalf("the handed collector is refused: %v", err) } if got := collectedPlaceholderProblems(bars, map[string]any{"id": "x", "content": "${collected:contribution:node-bar:block:bar=top,place=status}"}); len(got) != 0 { t.Fatalf("the check refuses it: %v", got) } // A data kind whose shape does not say its items are text stays refused. _, plain, _ := receivable(BarSeat, BarKindBlock) plain.Shape = &Shape{} if collectableAsText(plain) { t.Fatal("a shape not marked as text is collectable") } if _, _, err := oldCollection("contribution:node-bar:block", false); err != nil { t.Fatal(err) } } func TestTheBarsCollectionIsFilledTheOldWayWhereTheCollectorIsNotHanded(t *testing.T) { for _, caps := range []map[string]bool{nil, {"battery": true}} { got := composedFile(t, collectedBarsOn(t, caps), "bars.conf") want := "top\nbottom\n# power\nD workstation\n" if caps["battery"] { want = "top\nbottom\n# power\nB\n# power\nD workstation\n" } if got != want { t.Errorf("caps %v: the file is %q, want %q", caps, got, want) } } } func TestTheBarsCollectionIsNamedInTheHandedPlan(t *testing.T) { c, _ := composeWith(t, collectedBarsOn(t, map[string]bool{"battery": true}), handingTo("store:5000")) if !reflect.DeepEqual(c.Plans["bars"].Collections, []PlanCollection{{Name: "contribution:node-bar:block", Comment: "#"}}) { t.Fatalf("the plan collects %+v", c.Plans["bars"].Collections) } if n := len(c.Plans["power"].Items); n != 2 { t.Fatalf("the contributor's plan names %d items", n) } } // The bars of the catalogue's i3status-rust, with the blocks of power's items, compose to the files the old shaped // contribution made (issue 781). testdata/bars holds the catalogue's bars and block texts as of the move and the bars as // composed before it, for a machine with neither capability, the battery, the power meter and both. Where the // collector is not handed the controller fills the files; where it is, it names the items for the client, which // fills the same files (mesh-catalog's provisioner client holds that half against the same golden files). func TestTheBarsOfTheCatalogueAreTheSameHandedOrNot(t *testing.T) { read := func(name string) string { b, err := os.ReadFile(filepath.Join("testdata", "bars", name)) if err != nil { t.Fatal(err) } return string(b) } collector := `{"module":"bars","version":"1","moved":true,"claims":[{"name":"node-bar","scope":"node"}], "build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]}, "resources":[{"id":"top","type":"file","path":"/t","template":"files/top"}, {"id":"bottom","type":"file","path":"/b","template":"files/bottom"}]}` power := `{"module":"power","version":"1","moved":true, "items":[{"collection":"contribution:node-bar:block","name":"battery","if-capability":"battery","attributes":{"bar":"bottom","place":"status","order":"40"},"template":"files/battery"}, {"collection":"contribution:node-bar:block","name":"power-draw","if-capability":"power-meter","attributes":{"bar":"bottom","place":"status","order":"45"},"template":"files/draw"}], "build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]}}` for name, caps := range map[string]map[string]bool{"none": nil, "battery": {"battery": true}, "power-meter": {"power-meter": true}, "both": {"battery": true, "power-meter": true}} { bars := held(t, collector, builtWith("bars", map[string]string{"top": read("top-bar.toml"), "bottom": read("bottom-bar.toml")})) blocks := held(t, power, builtWith("power", map[string]string{"battery": read("bar-battery"), "draw": read("bar-power-draw")})) r, err := Resolve(shelf(bars, blocks), []string{"bars", "power"}, workstation(), World{}) if err != nil { t.Fatal(err) } r.Account, r.Capabilities = "op", caps // Not handed: the controller fills them. for id, which := range map[string]string{"bars.top": "top", "bars.bottom": "bottom"} { if got := composedFile(t, r, id); got != read(name+"."+which+"-bar.toml") { t.Errorf("%s, %s bar, not handed:\n%s\nwant\n%s", name, which, got, read(name+"."+which+"-bar.toml")) } } // Handed: the plan names the items the machine's capabilities allow, for the client to fill. c, _ := composeWith(t, r, handingTo("store:5000")) var names []string for _, it := range c.Plans["power"].Items { names = append(names, it.Name) } want := []string{} if caps["battery"] { want = append(want, "battery") } if caps["power-meter"] { want = append(want, "power-draw") } if !reflect.DeepEqual(append([]string{}, names...), want) { t.Errorf("%s: the plan names %v, want %v", name, names, want) } } }