From 7faf0c0bc7ac9a7d595797ecaa9990579d87b7b3 Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Thu, 4 Jun 2026 14:09:16 +0530 Subject: [PATCH] feat(mux-elasticsearch): opt-in schema-noise demo mode for outgoing ES body Adds an env-gated (STAMP_CREATED_AT) demo mode to the mux-elasticsearch sample so it can exercise keploy's new schema-based request-body noise detection for HTTP mocks (keploy/keploy#4234, issue #4233): - createDocument stamps a server-side created_at on the indexed document, so the OUTGOING Elasticsearch request body carries a volatile field that drifts between a keploy recording and each replay -- exactly what --schema-noise-detection detects and persists as req_body_noise: { body.created_at: [] } on the ES mock. - The ES client disables HTTP keep-alives in demo mode so each outgoing call closes its connection and keploy can finalize the mock (a pooled keep-alive connection is otherwise buffered until shutdown and dropped). Both behaviours are OFF by default, so the app's normal behaviour and the committed keploy recordings are unchanged; only the schema-noise-detection CI pipeline sets STAMP_CREATED_AT=1. go.mod: promote the two directly-imported modules out of the indirect block (go mod tidy). Co-Authored-By: Claude Opus 4.8 (1M context) --- mux-elasticsearch/app.go | 32 +++++++++++++++++++++++++++++++- mux-elasticsearch/go.mod | 7 +++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/mux-elasticsearch/app.go b/mux-elasticsearch/app.go index 61aaab07..7e658cba 100644 --- a/mux-elasticsearch/app.go +++ b/mux-elasticsearch/app.go @@ -26,9 +26,26 @@ type App struct { const SearchIndex = "documents" +// schemaNoiseDemo reports whether the keploy schema-noise-detection demo mode +// is enabled (env STAMP_CREATED_AT). It is OFF by default, so the app's normal +// behaviour and the committed keploy recordings are unchanged; the +// schema-noise-detection CI pipeline turns it on. +func schemaNoiseDemo() bool { return os.Getenv("STAMP_CREATED_AT") != "" } + func (a *App) Initialize() error { var err error - a.DB, err = elasticsearch.NewDefaultClient() + cfg := elasticsearch.Config{} + if schemaNoiseDemo() { + // DisableKeepAlives so every outgoing Elasticsearch call uses a fresh + // connection that closes right after the response. keploy finalizes an + // outgoing HTTP mock when the connection closes; on a pooled keep-alive + // connection it would otherwise buffer the request/response until the + // app shuts down and lose them when the context is cancelled. + cfg.Transport = &http.Transport{DisableKeepAlives: true} + } + // Addresses are taken from the ELASTICSEARCH_URL env when cfg.Addresses is + // empty (NewClient honours it, same as NewDefaultClient). + a.DB, err = elasticsearch.NewClient(cfg) if err != nil { return fmt.Errorf("error : %s", err) @@ -58,6 +75,12 @@ type Document struct { ID string `json:"id,omitempty"` Title string `json:"title"` Content string `json:"content"` + // CreatedAt is stamped server-side on every create, so the document body + // sent to Elasticsearch carries a volatile field that differs between a + // keploy recording and each replay. This is what + // `--schema-noise-detection` detects and persists as + // req_body_noise: { body.created_at: [] } on the outgoing ES mock. + CreatedAt int64 `json:"created_at,omitempty"` } type CreateDocumentResponse struct { @@ -82,6 +105,13 @@ func (a *App) createDocument(w http.ResponseWriter, r *http.Request) { return } + // In schema-noise demo mode, stamp a server-side creation time so the + // outgoing ES request body drifts every run (the volatile field the + // schema-noise-detection pipeline detects). Off by default. + if schemaNoiseDemo() { + doc.CreatedAt = time.Now().UnixNano() + } + data, err := json.Marshal(doc) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/mux-elasticsearch/go.mod b/mux-elasticsearch/go.mod index f967e611..b8b8ac26 100644 --- a/mux-elasticsearch/go.mod +++ b/mux-elasticsearch/go.mod @@ -2,12 +2,15 @@ module mux-elasticsearch go 1.22 +require ( + github.com/elastic/go-elasticsearch/v8 v8.14.0 + github.com/gorilla/mux v1.8.1 +) + require ( github.com/elastic/elastic-transport-go/v8 v8.6.0 // indirect - github.com/elastic/go-elasticsearch/v8 v8.14.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/gorilla/mux v1.8.1 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect