package apply import ( "context" "errors" "strings" "testing" "git.novox.be/novox/mesh-sdk/go/declaration" "github.com/novox/mesh-host/internal/store" ) // A taken container keeps a found network by a per-machine setting (novox/hq ADR 0163, rule 4): // joined once it runs, part of its spec, and refused when it cannot be joined. func TestAContainerJoinsTheNetworksItKeeps(t *testing.T) { var ran []string connectFails := false run := func(_ context.Context, name string, args ...string) (string, error) { args = oldShape(name, args) if name != "docker" { return "", errors.New("not installed") } ran = append(ran, strings.Join(args, " ")) switch args[0] { case "info": return "29.0.0\n", nil case "container": if len(ran) > 2 { return "true\t" + specOfLast, nil } return "false\t\n", errors.New("no such container") case "run": return "deadbeef\n", nil case "network": if connectFails { return "", errors.New("network predecessor_default not found") } } return "", nil } d := parseTrusted(t, `{"declaration":1,"resources":[ {"id":"app","type":"container","name":"app","image":"`+pinned+`", "networks":["predecessor_default"]} ]}`) specOfLast = containerSpec(d.Resources[0].(*declaration.Container), inputs{}) alone := *d.Resources[0].(*declaration.Container) alone.Networks = nil if specOfLast == containerSpec(&alone, inputs{}) { t.Fatal("the kept network is not part of the container's spec: kept or let go, the container would be left alone") } report, _, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginCarried, run, nil, nil) if err != nil { t.Fatal(err) } joined := false for i, line := range ran { if line == "network connect predecessor_default app" { joined = true if ran[i-1] != "container inspect --format {{.State.Running}}\t{{index .Config.Labels \""+specLabel+"\"}} app" && !strings.HasPrefix(ran[i-1], "container inspect") { t.Errorf("joined before the container was read back as running: %v", ran) } } } if !joined || report.Outcomes[0].Action != "created" { t.Fatalf("the container did not join the kept network: %v\n%+v", ran, report.Outcomes) } connectFails, ran = true, nil if _, _, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginCarried, run, nil, nil); err == nil || !strings.Contains(err.Error(), "could not join the kept network predecessor_default") { t.Fatalf("a network that cannot be joined was passed over: %v", err) } } var specOfLast string func TestACapabilityReachesTheRuntimeAndTheSpec(t *testing.T) { var ran []string run := func(_ context.Context, name string, args ...string) (string, error) { args = oldShape(name, args) if name != "docker" { return "", errors.New("not installed") } switch args[0] { case "info": return "29.0.0\n", nil case "container": return "false\t\n", errors.New("no such container") case "run": ran = args return "deadbeef\n", nil } return "", nil } d := parseTrusted(t, `{"declaration":1,"resources":[ {"id":"fw","type":"container","name":"fw","image":"`+pinned+`","network":"host","capabilities":["NET_ADMIN"]} ]}`) _, _, _ = Apply(context.Background(), archHost(t), d, store.State{}, store.OriginCarried, run, nil, nil) granted := false for i, a := range ran { if a == "--cap-add" && i+1 < len(ran) && ran[i+1] == "NET_ADMIN" { granted = true } } if !granted { t.Fatalf("the capability was not granted: %v", ran) } with := d.Resources[0].(*declaration.Container) without := *with without.Capabilities = nil if containerSpec(with, inputs{}) == containerSpec(&without, inputs{}) { t.Fatal("a capability is not part of the container's spec") } } // A package may be declared absent (novox/hq ADR 0180): removed when it is installed, read back, // left alone when it is not. func TestAPackageDeclaredAbsentIsRemovedWhenPresentAndLeftWhenNot(t *testing.T) { installed := true var ran []string run := func(_ context.Context, name string, args ...string) (string, error) { args = oldShape(name, args) ran = append(ran, name+" "+strings.Join(args, " ")) if name != "pacman" { return "", nil } switch args[0] { case "-Q": if args[1] == "pacman" || installed { return args[1] + " 1.0\n", nil } return "", errors.New("package not found") case "-R": installed = false } return "", nil } d := parseTrusted(t, `{"declaration":1,"resources":[{"id":"front-end","type":"package","package":"ufw","absent":true}]}`) report, _, err := Apply(context.Background(), archHost(t), d, store.State{}, store.OriginCarried, run, nil, nil) if err != nil { t.Fatal(err) } if report.Outcomes[0].Action != "removed" || !strings.Contains(strings.Join(ran, "\n"), "pacman -R --noconfirm ufw") { t.Fatalf("an installed package declared absent was not removed: %+v\n%v", report.Outcomes[0], ran) } ran = nil report, _, err = Apply(context.Background(), archHost(t), d, store.State{}, store.OriginCarried, run, nil, nil) if err != nil { t.Fatal(err) } if report.Outcomes[0].Action != "unchanged" || strings.Contains(strings.Join(ran, "\n"), "-R") { t.Fatalf("a package already absent was touched: %+v\n%v", report.Outcomes[0], ran) } }