package host import ( "context" "encoding/json" "os" "path/filepath" "testing" "time" "github.com/carlosframework/platform/internal/activator" "github.com/carlosframework/platform/internal/domains" "github.com/carlosframework/platform/internal/provision" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/release" ) func TestPlan14OrdinaryDispatchSourceGap(t *testing.T) { t.Setenv("CARLOS_HOST_CLAIM", "") store := release.NewDirStore(t.TempDir()) account := domains.Sqid(2) manifest, err := json.Marshal(map[string]any{"id": 2, "sqid": account, "name": "fixture", "created_at": time.Now()}) if err != nil { t.Fatal(err) } if _, err := store.Put(t.Context(), "accounts/"+account+"/account.json", manifest, ""); err != nil { t.Fatal(err) } if err := provision.PutManifest(t.Context(), store, account, "app", provision.Manifest{Schema: 1, App: "app", Domain: "example.com", Pool: "test"}); err != nil { t.Fatal(err) } record := provision.Record{Schema: 1, Host: "app.example.com", Slug: "app", Account: account, App: "app", Region: "ie", Pool: "test", Channel: "stable", CreatedAt: time.Now()} if err := provision.CreateRecord(t.Context(), store, record); err != nil { t.Fatal(err) } _, before, err := store.Get(t.Context(), provision.RecordKey(account, "app", record.Host)) if err != nil { t.Fatal(err) } for _, nested := range []bool{false, true} { t.Run(map[bool]string{false: "flat", true: "nested"}[nested], func(t *testing.T) { reg, err := registry.Open(filepath.Join(t.TempDir(), "registry.db")) if err != nil { t.Fatal(err) } defer reg.Close() cfg := provision.ReconcileConfig{Region: "ie", Pools: []string{"test"}, DataDir: t.TempDir()} if nested { cfg.Layout = func(context.Context, release.Store) (string, error) { return release.LayoutModeNested, nil } } if err := provision.Reconcile(t.Context(), store, reg, cfg); err != nil { t.Fatal(err) } row, err := reg.Get(record.Host) if err != nil || row == nil { t.Fatalf("provisioned route: %+v %v", row, err) } wantSocket := provision.DefaultSocket(record.Host) if nested { wantSocket = provision.NestedSocket(record.Host) } if row.Unit != "" || row.Backing != "" || row.Socket != wantSocket { t.Fatalf("unexpected ordinary route: %+v", row) } source := &proofBindingSource{store: store} for _, forge := range []string{"honest", "unit", "backing", "both"} { candidate := *row if forge == "unit" || forge == "both" { candidate.Unit = "console.service" } if forge == "backing" || forge == "both" { candidate.Backing = registry.BackingUnit } need, err := source.needsRestart(t.Context(), candidate) if err != nil || need { t.Fatalf("%s ordinary record dispatched: need=%v err=%v", forge, need, err) } if err := reg.Delete(candidate.Host); err != nil { t.Fatal(err) } if err := reg.Upsert(candidate); err != nil { t.Fatal(err) } u := &plan14OrdinaryUnits{} checks := rootRestartChecks{targetFile: os.Open, dispatch: source.needsRestart} if err := rootRestartRouteWith(reg, u, "", nil, nil, checks)(record.Host); err != nil { t.Fatal(err) } if candidate.Unit == "" { if len(u.effects) != 1 || u.effects[0] != activator.UnitName(record.Host) { t.Fatalf("ordinary restart: %v", u.effects) } } else if len(u.effects) != 0 { t.Fatalf("forged named restart: %v", u.effects) } } }) } _, after, err := store.Get(t.Context(), provision.RecordKey(account, "app", record.Host)) if err != nil || before != after { t.Fatalf("record changed between local layouts: %v", err) } } func TestPlan14NamedRecordDispatch(t *testing.T) { t.Parallel() e, rt, u, _, _ := plan14AdoptionFixture(t) source := productionProofBindingSource(e.store, u, u.opt) need, err := source.needsRestart(t.Context(), rt) if err != nil || !need { t.Fatalf("named record excluded: need=%v err=%v", need, err) } } type plan14OrdinaryUnits struct{ plan14RestartUnits } func (u *plan14OrdinaryUnits) TryRestart(unit string) error { u.effects = append(u.effects, unit) return nil }