package hostfloor import ( "os" "path/filepath" "testing" ) func TestPlan14ParticipationFlagOffFloor(t *testing.T) { t.Setenv("CARLOS_HOST_CLAIM", "") for _, mirror := range []string{"absent", "empty", "pending", "symlink"} { t.Run(mirror, func(t *testing.T) { d := Disk{Dir: t.TempDir(), Participation: floorParticipationFixture(t)} if err := d.Participation.State.Remove("census.json"); err != nil { t.Fatal(err) } d.Participation.VerifyLaunches = nil data := t.TempDir() dir := filepath.Join(data, ".hostexec") if mirror == "empty" || mirror == "pending" { if err := os.Mkdir(dir, 0700); err != nil { t.Fatal(err) } } if mirror == "pending" { if err := os.WriteFile(filepath.Join(dir, "pending.json"), []byte(`{}`), 0600); err != nil { t.Fatal(err) } } if mirror == "symlink" { if err := os.Symlink(t.TempDir(), dir); err != nil { t.Fatal(err) } } for _, strict := range []bool{false, true} { want := mirror == "empty" || (!strict && mirror == "absent") if err := d.CheckParticipation(t.Context(), data, strict); (err == nil) != want { t.Fatalf("strict=%t err=%v want admitted=%t", strict, err, want) } } want := mirror == "empty" if err := d.ControllersIdle(t.Context(), data); (err == nil) != want { t.Fatalf("idle=%v want admitted=%t", err, want) } if err := d.Begin(t.Context(), "legacy-update", data); (err == nil) != want { t.Fatalf("begin=%v want admitted=%t", err, want) } marker := filepath.Join(d.Dir, "update-begun.json") if _, err := os.Stat(marker); (err == nil) != want { t.Fatalf("marker=%v", err) } if want { if err := d.EndParticipation(t.Context(), "legacy-update", func() error { return RemoveDurable(marker) }); err != nil { t.Fatal(err) } if _, err := os.Stat(marker); !os.IsNotExist(err) { t.Fatalf("completion retained marker: %v", err) } } if _, err := d.Participation.UpdateID(); !os.IsNotExist(err) { t.Fatalf("legacy floor created root reservation: %v", err) } }) } } func TestPlan14ParticipationRetainedCensusFloor(t *testing.T) { for _, flag := range []string{"", "1"} { for _, state := range []string{"idle", "pending", "no-launch-proof", "malformed", "missing"} { t.Run(flag+"/"+state, func(t *testing.T) { t.Setenv("CARLOS_HOST_CLAIM", flag) d := Disk{Dir: t.TempDir(), Participation: floorParticipationFixture(t)} data := t.TempDir() if err := os.Mkdir(filepath.Join(data, ".hostexec"), 0700); err != nil { t.Fatal(err) } switch state { case "pending": if err := d.Participation.State.Write("shop.example.json", []byte(`{"Status":"pending"}`)); err != nil { t.Fatal(err) } case "no-launch-proof": d.Participation.VerifyLaunches = nil case "malformed": if err := d.Participation.State.Write("census.json", []byte(`{`)); err != nil { t.Fatal(err) } case "missing": if err := d.Participation.State.Remove("census.json"); err != nil { t.Fatal(err) } } want := state == "idle" || (state == "missing" && flag == "") if err := d.ControllersIdle(t.Context(), data); (err == nil) != want { t.Fatalf("idle=%v want admitted=%t", err, want) } if err := d.Begin(t.Context(), "update", data); (err == nil) != want { t.Fatalf("begin=%v want admitted=%t", err, want) } if state == "idle" { if err := d.Participation.Acquire(t.Context(), func() error { t.Fatal("acquired across update"); return nil }); err == nil { t.Fatal("update did not exclude acquisition") } if err := d.EndParticipation(t.Context(), "update", nil); err != nil { t.Fatal(err) } } }) } } }