package instancectl import ( "context" "encoding/json" "errors" "os" "path/filepath" "strings" "testing" ) func TestPlan11Rev2UnitFinalCheckAndSnapshot(t *testing.T) { for _, deny := range []bool{false, true} { t.Run(map[bool]string{true: "denied", false: "allowed"}[deny], func(t *testing.T) { u, ctl, in, _ := claimUnitFixture(t) u.UnitRoot, u.DataRoot = t.TempDir(), t.TempDir() if err := os.Chmod(u.UnitRoot, 0700); err != nil { t.Fatal(err) } launch := Launch{Schema: LaunchSchema, Host: in.Host, Argv: []string{LiveDir + "/" + in.Host, "--socket", "/run/app.sock", "--db", "/data/app.db"}, Env: []string{"TOKEN=secret"}} checks := 0 _, err := u.StartChecked(t.Context(), in, launch, func() error { checks++ source, dropin, e := u.launchPaths(in.Host) if e != nil { t.Fatal(e) } body, e := os.ReadFile(filepath.Join(source, "launch.json")) if e != nil { t.Fatal(e) } var got Launch if e = json.Unmarshal(body, &got); e != nil || strings.Join(got.Env, ",") != "TOKEN=secret" { t.Fatalf("snapshot %s %v", body, e) } body, e = os.ReadFile(filepath.Join(dropin, "60-claim-launch.conf")) if e != nil || !strings.Contains(string(body), "BindReadOnlyPaths="+filepath.Join(source, "launch.json")) { t.Fatalf("binding: %s %v", body, e) } if strings.Contains(ctl.joined(), "start ") { t.Fatal("check ran after start") } if deny { return errors.New("expired") } return nil }) if checks != 1 { t.Fatalf("checks=%d err=%v", checks, err) } if deny { if err == nil || strings.Contains(ctl.joined(), "start ") { t.Fatal("denial launched") } return } if err != nil { t.Fatal(err) } if err = u.Stop(context.Background(), in.Host); err != nil { t.Fatal(err) } source, dropin, _ := u.launchPaths(in.Host) for _, p := range []string{filepath.Join(source, "launch.json"), filepath.Join(dropin, "60-claim-launch.conf")} { if _, e := os.Stat(p); !errors.Is(e, os.ErrNotExist) { t.Fatalf("snapshot outlived stopped unit: %s %v", p, e) } } }) } } func TestPlan11Rev2UnitSameInvocation(t *testing.T) { u, ctl, in, _ := claimUnitFixture(t) s, err := u.Start(t.Context(), in) if err != nil { t.Fatal(err) } if err = u.Same(t.Context(), s); err != nil { t.Fatal(err) } ctl.invocation = "replacement" if err = u.Same(t.Context(), s); err == nil { t.Fatal("replacement accepted") } ctl.invocation = s.InvocationID ctl.pid++ if err = u.Same(t.Context(), s); err == nil { t.Fatal("replacement pid accepted") } }