Feature 57 (config and provisioning): modules declare config and provisions, their files rendered from templates; synced with main (issues of feature 57, 874)
This commit is contained in:
@@ -1,87 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// i3status-rust renders the blocks other modules contribute (novox/hq ADR 0255): a bar-neutral piece
|
||||
// — what it shows, on which bar, where — in its own grammar, through the template its claim gives. The
|
||||
// controller runs the template; these tests run it the same way, with the one function it is given.
|
||||
|
||||
func blockTemplate(t *testing.T) *template.Template {
|
||||
t.Helper()
|
||||
m := readManifest(t)
|
||||
src, err := os.ReadFile("../../files/block.tmpl")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m.Claims[0].Renders["block"] != string(src) {
|
||||
t.Fatal("the claim's template is not files/block.tmpl")
|
||||
}
|
||||
quote := func(v any) (string, error) {
|
||||
b, err := json.Marshal(fmt.Sprint(v))
|
||||
return string(b), err
|
||||
}
|
||||
return template.Must(template.New("block").Funcs(template.FuncMap{"quote": quote}).Parse(string(src)))
|
||||
}
|
||||
|
||||
func render(t *testing.T, tmpl *template.Template, piece string) string {
|
||||
t.Helper()
|
||||
view := map[string]any{"module": "power", "machine": "laptop"}
|
||||
if err := json.Unmarshal([]byte(piece), &view); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var b bytes.Buffer
|
||||
if err := tmpl.Execute(&b, view); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(b.String(), "<no value>") {
|
||||
t.Fatalf("%s rendered a missing value: %q", piece, b.String())
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func TestAContributedBatteryIsI3statusRustsBatteryBlock(t *testing.T) {
|
||||
tmpl := blockTemplate(t)
|
||||
got := render(t, tmpl, `{"bar":"bottom","place":"status","shows":"battery"}`)
|
||||
if !strings.HasPrefix(got, "[[block]]\nblock = \"battery\"\nformat = ") || strings.Contains(got, "device") ||
|
||||
!strings.Contains(got, `missing_format = ""`) || !strings.HasSuffix(got, "\n\n") {
|
||||
t.Fatalf("%q", got)
|
||||
}
|
||||
got = render(t, tmpl, `{"bar":"bottom","place":"status","shows":"battery","options":{"device":"BAT1"}}`)
|
||||
if !strings.Contains(got, "block = \"battery\"\ndevice = \"BAT1\"\nformat = ") {
|
||||
t.Fatalf("%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAContributedCommandIsACustomBlockQuoted(t *testing.T) {
|
||||
got := render(t, blockTemplate(t),
|
||||
`{"bar":"bottom","place":"status","shows":"command","options":{"command":"say \"hi\"","interval":5}}`)
|
||||
want := "[[block]]\nblock = \"custom\"\ncommand = \"say \\\"hi\\\"\"\ninterval = 5\n\n"
|
||||
if got != want {
|
||||
t.Fatalf("%q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
// The blocks other modules contribute are a collection of text (design 57 L3, novox/hq ADR 0349 clause 13): each
|
||||
// contributor gives its block in i3status-rust's grammar, and the bars place the collection where they want it.
|
||||
|
||||
func TestEachBarPlacesBothPlacesOnce(t *testing.T) {
|
||||
m := readManifest(t)
|
||||
for _, bar := range []string{"bottom", "top"} {
|
||||
content := m.resource(t, bar+"-bar")["content"].(string)
|
||||
content := m.text(t, bar+"-bar")
|
||||
for _, place := range []string{"resources", "status"} {
|
||||
ph := "${contribution:node-bar:block:bar=" + bar + ",place=" + place + "}"
|
||||
ph := "${collected:contribution:node-bar:block:bar=" + bar + ",place=" + place + "}"
|
||||
if strings.Count(content, ph) != 1 {
|
||||
t.Errorf("the %s bar places %s %d times", bar, ph, strings.Count(content, ph))
|
||||
}
|
||||
}
|
||||
}
|
||||
bottom := m.resource(t, "bottom-bar")["content"].(string)
|
||||
bottom := m.text(t, "bottom-bar")
|
||||
resources := strings.Index(bottom, "place=resources")
|
||||
if !(strings.Index(bottom, `block = "memory"`) < resources && resources < strings.Index(bottom, `block = "docker"`)) ||
|
||||
!(strings.Index(bottom, `block = "sound"`) < strings.Index(bottom, "place=status") &&
|
||||
@@ -91,30 +31,33 @@ func TestEachBarPlacesBothPlacesOnce(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTheMemoryIsWhatProgramsHoldNotTheCache(t *testing.T) {
|
||||
bottom := readManifest(t).resource(t, "bottom-bar")["content"].(string)
|
||||
bottom := readManifest(t).text(t, "bottom-bar")
|
||||
if !strings.Contains(bottom, `format = "$icon $mem_used.eng(w:2) ($mem_used_percents.eng(w:2))"`) ||
|
||||
strings.Contains(bottom, "mem_total_used") {
|
||||
t.Fatal("the memory block counts the cache as used")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAContributedStateIsACustomBlockReadingThisMachinesValue(t *testing.T) {
|
||||
tmpl := blockTemplate(t)
|
||||
got := render(t, tmpl, `{"bar":"bottom","place":"status","shows":"state","options":{"state":"power.draw"}}`)
|
||||
want := "[[block]]\nblock = \"custom\"\ncommand = \"~/.local/bin/i3status-value power.draw laptop\"\ninterval = 5\nhide_when_empty = true\n\n"
|
||||
if got != want {
|
||||
t.Fatalf("%q, want %q", got, want)
|
||||
func TestABarNamesNoTemplateOfItsOwnForTheBlocksItPlaces(t *testing.T) {
|
||||
m := readManifest(t)
|
||||
for _, id := range []string{"top-bar", "bottom-bar"} {
|
||||
if strings.Contains(m.text(t, id), "${contribution:") {
|
||||
t.Errorf("the %s still places a contribution the old way", id)
|
||||
}
|
||||
}
|
||||
got = render(t, tmpl, `{"bar":"bottom","place":"status","shows":"state","options":{"state":"power.draw","key":"desk"}}`)
|
||||
if !strings.Contains(got, "i3status-value power.draw desk") {
|
||||
t.Fatalf("%q", got)
|
||||
if _, err := os.Stat("../../files/block.tmpl"); err == nil {
|
||||
t.Error("files/block.tmpl is still there, and no claim renders it")
|
||||
}
|
||||
// And the bundle finds what it rendered.
|
||||
}
|
||||
|
||||
func TestTheBundleFindsTheValueARenderedBlockShows(t *testing.T) {
|
||||
// What the power module's block renders on a machine called laptop.
|
||||
got := "[[block]]\nblock = \"custom\"\ncommand = \"~/.local/bin/i3status-value power.draw laptop\"\ninterval = 5\nhide_when_empty = true\n\n"
|
||||
f := filepath.Join(t.TempDir(), "bottom-bar.toml")
|
||||
if err := os.WriteFile(f, []byte(got), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if w := wantedIn([]string{f}); len(w) != 1 || w[0] != (Wanted{"power.draw", "desk"}) {
|
||||
if w := wantedIn([]string{f}); len(w) != 1 || w[0] != (Wanted{"power.draw", "laptop"}) {
|
||||
t.Fatalf("%v", w)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user