// Package suite is the FLUID conformance harness. // // It asserts the seven minimal-conformance requirements of // FluidAPIStandards.md section 36 and the mechanically checkable subset of the // sixteen architectural invariants in ArchitectureBlueprint.md section 55. // // Everything here runs with no external services and no human steps. A // conformance claim that needed someone to run through it by hand would be a // claim nobody re-checks after the first time. package suite import ( "context" "crypto/ed25519" "fmt" "net/http" "net/http/httptest" "path/filepath" "testing" "time" _ "modernc.org/sqlite" echo "github.com/tegwick/fluid-core/examples/echo-interface" "github.com/tegwick/fluid-core/internal/contract" "github.com/tegwick/fluid-core/internal/evidence" "github.com/tegwick/fluid-core/internal/intent" "github.com/tegwick/fluid-core/internal/observation" "github.com/tegwick/fluid-core/internal/policy" "github.com/tegwick/fluid-core/internal/publish" "github.com/tegwick/fluid-core/internal/runtime" "github.com/tegwick/fluid-core/internal/science" "github.com/tegwick/fluid-core/internal/signing" "github.com/tegwick/fluid-core/internal/validate" ) // Interface is the fixture's interface identifier. const Interface contract.InterfaceID = "echo-interface" // IntentDocument is the fixture's governing intent. const IntentDocument = `# Interface Evolution Intent — echo-interface **Current operational authority mode:** FLUID-4 ## Mission Serve entries to consumers, and learn from how they ask for them. ` // Operator is the fixture's human actor. var Operator = contract.Actor{Type: contract.ActorTypeHuman, ID: "conformance"} // Harness is a fully wired FLUID deployment over the echo fixture. type Harness struct { T *testing.T Store *evidence.SQLStore Intents *intent.Store Registry *runtime.Registry Gateway *runtime.Gateway Emitter *runtime.Emitter Ingest *observation.Ingest Pipeline *publish.Pipeline Validator *validate.OpenAPIValidator Signer *signing.Signer PublicKey ed25519.PublicKey Hypotheses *science.HypothesisStore Experiments *science.ExperimentController adapters map[contract.RevisionID]*httptest.Server } // New builds a harness with both fixture revisions published and R-1 stable. func New(t *testing.T) *Harness { t.Helper() ctx := context.Background() store, err := evidence.OpenSQLite(ctx, filepath.Join(t.TempDir(), "conformance.db")) if err != nil { t.Fatalf("open evidence store: %v", err) } t.Cleanup(func() { _ = store.Close() }) intents := intent.New(store, Interface) if _, err := intents.Put(ctx, "IEI-1", IntentDocument); err != nil { t.Fatalf("record intent: %v", err) } if err := intents.SetActive(ctx, "IEI-1"); err != nil { t.Fatalf("activate intent: %v", err) } signer, pub, err := signing.GenerateKey("conformance-key") if err != nil { t.Fatal(err) } limits := policy.DefaultLimits() // The fixture's intent grants FLUID-4, and the loop under test promotes a // contract adaptation, so the fixture permits that class explicitly. limits.AllowedAdaptationClasses = append(limits.AllowedAdaptationClasses, contract.AdaptationClassContract) limits.RequiredMode = intent.ModeExperimental gate := policy.NewGate(limits) pipeline, err := publish.New(publish.Options{ Gate: gate, Signer: signer, Store: store, Intents: intents, }) if err != nil { t.Fatal(err) } salt := []byte("conformance-salt-of-sufficient-length") ingest, err := observation.NewIngest(store, Interface, observation.DefaultRedactionPolicy(salt)) if err != nil { t.Fatal(err) } h := &Harness{ T: t, Store: store, Intents: intents, Pipeline: pipeline, Validator: validate.NewOpenAPIValidator(), Signer: signer, PublicKey: pub, Ingest: ingest, adapters: map[contract.RevisionID]*httptest.Server{}, } // A verifying registry: the router must accept only signed descriptors. h.Registry = runtime.NewVerifiedRegistry(Interface, signing.NewVerifier(map[string]ed25519.PublicKey{"conformance-key": pub})) h.adapters["R-1"] = httptest.NewServer(echo.NewR1()) h.adapters["R-2"] = httptest.NewServer(echo.NewR2()) t.Cleanup(func() { for _, s := range h.adapters { s.Close() } }) h.Emitter = runtime.NewEmitter(ingest, runtime.EmitterOptions{Buffer: 8192, Workers: 2}) gw, err := runtime.NewGateway(runtime.GatewayOptions{ Interface: Interface, Registry: h.Registry, Resolver: runtime.NewResolver(h.Registry, true), Connector: runtime.NewConnector(), Emitter: h.Emitter, Cohorts: observation.NewCohortEngine("agents", observation.DefaultRedactionPolicy(salt)), Response: runtime.ResponsePolicy{FeedbackPath: "/v1/feedback"}, Validator: h.Validator, }) if err != nil { t.Fatal(err) } h.Gateway = gw h.Hypotheses = science.NewHypothesisStore(store, Interface) h.Experiments = science.NewExperimentController(store, h.Hypotheses, Interface) h.PublishRevision("R-1", "examples/echo-interface/r1.openapi.yaml", nil) h.PublishRevision("R-2", "examples/echo-interface/r2.openapi.yaml", []contract.AdaptationClass{contract.AdaptationClassContract}) h.InstallPolicy(1, "R-1", nil) return h } // PublishRevision takes a revision through the full pipeline and registers it. func (h *Harness) PublishRevision(id contract.RevisionID, contractPath string, classes []contract.AdaptationClass) contract.Revision { h.T.Helper() ctx := context.Background() raw := readRepoFile(h.T, contractPath) digest := signing.Digest(raw) if err := h.Validator.Register(digest, raw); err != nil { h.T.Fatalf("register contract for %s: %v", id, err) } pc := contract.RevisionPolicyPolicyCheckPassed descriptor := contract.Revision{ SchemaVersion: "0.1", ID: id, Interface: Interface, State: contract.RevisionStateStable, Contract: contract.RevisionContract{ Type: contract.RevisionContractTypeOpenapi, Digest: digest, Source: contractPath, }, Runtime: contract.RevisionRuntime{Upstream: h.adapters[id].URL}, Intent: contract.RevisionIntent{Version: "IEI-1"}, Policy: contract.RevisionPolicy{ Compatibility: contract.RevisionPolicyCompatibilityAdditive, SecurityCheck: contract.RevisionPolicySecurityCheckPassed, PolicyCheck: &pc, }, } if classes == nil { classes = []contract.AdaptationClass{contract.AdaptationClassPresentation} } verified, report, err := h.Pipeline.Run(ctx, publish.NewCandidate(descriptor, Operator), publish.PromotionRequest{ AdaptationClasses: classes, ComplexityDelta: 0.2, RequestedTrafficShare: 0.2, Approved: true, ApprovedBy: &Operator, }) if err != nil { h.T.Fatalf("publish %s: %v (%+v)", id, err, report.Stages) } if err := h.Pipeline.Publish(ctx, verified); err != nil { h.T.Fatalf("record %s: %v", id, err) } if err := h.Registry.PutRevision(verified.Descriptor()); err != nil { h.T.Fatalf("register %s: %v", id, err) } return verified.Descriptor() } // InstallPolicy loads a routing policy into the registry. func (h *Harness) InstallPolicy(generation int64, defaultRevision contract.RevisionID, rules []contract.RoutingPolicyRulesItem) { h.T.Helper() if rules == nil { rules = []contract.RoutingPolicyRulesItem{} } if err := h.Registry.PutPolicy(contract.RoutingPolicy{ SchemaVersion: "0.1", Interface: Interface, Generation: generation, DefaultRevision: defaultRevision, Rules: rules, }); err != nil { h.T.Fatalf("install policy generation %d: %v", generation, err) } } // Call issues a request through the gateway as a named consumer. func (h *Harness) Call(consumer, method, target string) *httptest.ResponseRecorder { h.T.Helper() req := httptest.NewRequest(method, target, nil) req.Header.Set("X-FLUID-Consumer", consumer) rec := httptest.NewRecorder() h.Gateway.ServeHTTP(rec, req) return rec } // CallPinned issues a request pinned to a specific revision. func (h *Harness) CallPinned(consumer string, rev contract.RevisionID, method, target string) *httptest.ResponseRecorder { h.T.Helper() req := httptest.NewRequest(method, target, nil) req.Header.Set("X-FLUID-Consumer", consumer) req.Header.Set("X-FLUID-Revision", string(rev)) rec := httptest.NewRecorder() h.Gateway.ServeHTTP(rec, req) return rec } // Drain flushes buffered telemetry so assertions see every event. // // It flushes rather than closes: the harness keeps serving after a drain, and // closing here would mean every later request emitted into a dead emitter. func (h *Harness) Drain() { if !h.Emitter.Flush(5 * time.Second) { h.T.Fatal("telemetry did not reach the store within 5s") } } // Telemetry returns everything recorded for the interface. func (h *Harness) Telemetry() []contract.FluidTelemetry { h.T.Helper() rows, err := h.Store.Telemetry(context.Background(), evidence.TelemetryFilter{InterfaceID: Interface}) if err != nil { h.T.Fatal(err) } return rows } // Events returns audit events for an entity. func (h *Harness) Events(entityID string) []contract.FluidEvent { h.T.Helper() events, err := h.Store.Events(context.Background(), evidence.EventFilter{EntityID: entityID}) if err != nil { h.T.Fatal(err) } return events } // AdapterURL returns a fixture adapter's address. func (h *Harness) AdapterURL(rev contract.RevisionID) string { return h.adapters[rev].URL } // StopAdapter kills a fixture adapter, for failure-containment tests. func (h *Harness) StopAdapter(rev contract.RevisionID) { h.adapters[rev].Close() } // mustStatus fails unless the response carries the expected status. func mustStatus(t *testing.T, rec *httptest.ResponseRecorder, want int, context string) { t.Helper() if rec.Code != want { t.Fatalf("%s: status %d, want %d; body %s", context, rec.Code, want, rec.Body.String()) } } var _ = fmt.Sprintf var _ = http.MethodGet