package console import ( "context" "crypto/ed25519" "encoding/json" "testing" "time" "github.com/carlosframework/platform/internal/hostops" "github.com/carlosframework/platform/internal/provision" "github.com/carlosframework/platform/internal/release" ) // Exercise the actual wrapper composition. The injected checker permits // these test writes; this tests encoding/context propagation, not authority. func TestPlan9B8SequenceThroughConsoleEffectAndMutationStack(t *testing.T) { ctx := context.Background() raw := release.NewDirStore(t.TempDir()) pub, _, err := ed25519.GenerateKey(nil) if err != nil { t.Fatal(err) } now := time.Now() w, err := hostops.NewControlWriter(raw, pub, func() time.Time { return now }) if err != nil { t.Fatal(err) } a := hostops.AppAdmission{V: 1, AppID: "app-id", Revision: 1, Epoch: 1, State: "open", Registrations: map[string]hostops.Registration{}, Effects: map[string]hostops.Effect{}} body, _ := json.Marshal(a) if _, err = raw.Put(ctx, "apps/bab/site/admission.json", body, ""); err != nil { t.Fatal(err) } owner := hostops.RegistrationOwner{Console: "console", Enrollment: "enrolled", Controller: "controller"} h, err := w.RegisterStart(ctx, "bab", "site", "app-id", "registration", hostops.Registration{Kind: "create", Host: "one.example.com", Claim: hostops.SavedClaim{Absent: true}, Owner: owner, AppID: "app-id", Epoch: 1, CreatedAt: now}, now) if err != nil { t.Fatal(err) } records, err := hostops.NewConditionalRecordStore(raw, pub) if err != nil { t.Fatal(err) } observed := 0 data, err := hostops.NewObservedMutationBoundary(true, records, func(context.Context, hostops.MutationTarget) error { return nil }, func(e hostops.MutationEvent) { if e.Verdict == nil { observed++ } }) if err != nil { t.Fatal(err) } store := claimEffectStore{data: data, effects: claimStoreEffects{OperationID: "registration", Runner: h.Runner(func() time.Time { return now })}} rec := provision.Record{Schema: 1, Account: "bab", App: "site", Host: "one.example.com", Region: "ie", Channel: "stable", CreatedAt: now} // Seed legacy bytes outside the claim stack, then let the inner boundary // introduce the sequence. The typed outer writer must return exactly one. if err = provision.CreateRecord(ctx, raw, rec); err != nil { t.Fatal(err) } got, err := provision.SetRecordMove(ctx, store, rec.Account, rec.App, rec.Host, func(*provision.Record) error { return nil }) if err != nil || got.RecordSeq != 1 { t.Fatalf("first claim write: %+v %v", got, err) } got, tag, err := provision.GetRecordETag(ctx, store, rec.Account, rec.App, rec.Host) if err != nil { t.Fatal(err) } got.Channel = "edge" if err = provision.UpdateRecord(ctx, store, *got, tag); err != nil { t.Fatal(err) } afterUpdate, updateReadErr := provision.GetRecord(ctx, raw, rec.Account, rec.App, rec.Host) if updateReadErr != nil || afterUpdate.RecordSeq != 2 { t.Fatalf("whole-record update: %+v %v", afterUpdate, updateReadErr) } got, err = provision.SetRecordMove(ctx, store, rec.Account, rec.App, rec.Host, func(*provision.Record) error { return nil }) if err != nil || got.RecordSeq != 3 { t.Fatalf("populated writes: %+v %v", got, err) } current, err := provision.GetRecord(ctx, raw, rec.Account, rec.App, rec.Host) if err != nil || current.RecordSeq != got.RecordSeq { t.Fatalf("returned vs stored: %+v %v", current, err) } side := provision.SidecarRecord{Schema: 1, Account: "bab", App: "site", Name: "worker", Host: provision.SidecarHost("worker", "site", "bab"), CreatedAt: now} if err = provision.CreateSidecarRecord(ctx, store, side); err != nil { t.Fatal(err) } body, _, err = raw.Get(ctx, provision.SidecarRecordKey("bab", "site", "worker")) if err != nil { t.Fatal(err) } _, seq, err := provision.RecordSequence(body) if err != nil || seq != 1 || observed != 4 { t.Fatalf("sidecar seq=%d observations=%d err=%v", seq, observed, err) } }