MCPcopy
hub / github.com/keploy/keploy / DeriveLifetime

Method DeriveLifetime

pkg/models/lifetime.go:117–226  ·  view source on GitHub ↗

DeriveLifetime resolves a mock's runtime Lifetime from its on-disk metadata tag, with a legacy-format fallback for recordings captured before the tag convention was universally applied. Idempotency: safe to call more than once on the same mock. The several ingest paths (disk loader, syncMock.AddMoc

()

Source from the content-addressed store, hash-verified

115// visible signal (surfaced at replay completion); per-call logging is
116// deliberately avoided because DeriveLifetime runs on every mock load.
117func (m *Mock) DeriveLifetime() {
118 // Idempotent short-circuit. LifetimeDerived is distinct from the
119 // Lifetime field itself because LifetimePerTest IS the zero value
120 // — without the bool, a PerTest classification is
121 // indistinguishable from "never derived", and the heavy switch +
122 // kind-fallback path would re-run on every ingest site (disk →
123 // StoreMocks → syncMock). The bool also guards
124 // legacyKindFallbackFires from double-counting when a mock passes
125 // through multiple ingest paths.
126 if m.TestModeInfo.LifetimeDerived {
127 return
128 }
129 defer func() { m.TestModeInfo.LifetimeDerived = true }()
130
131 // Protocol-specific override that runs BEFORE the tag-based
132 // classification. A small allowlist of MySQL command-phase packet
133 // types have input-independent responses (COM_PING → OK,
134 // COM_STATISTICS → stats blob, COM_DEBUG → server-side no-op,
135 // COM_RESET_CONNECTION → OK) and are typically recorded at app
136 // startup (JDBC / HikariCP pool warm-up) BEFORE any test window
137 // begins. Without this override they'd be tagged "mocks" (per-
138 // test) by the recorder → strict-window pre-filter drops them →
139 // replay fails at connection init with "no matching mock". The
140 // promotion keeps the on-disk tag unchanged (backward compatible
141 // with older replayers) but steers the in-memory routing so the
142 // mock lands in the session pool here.
143 //
144 // Deliberately narrow: only the four commands whose response we
145 // know is input-independent. COM_QUERY / COM_INIT_DB /
146 // COM_CHANGE_USER / COM_SET_OPTION all depend on input and must
147 // stay per-test.
148 if m.Kind == MySQL && mysqlIsSessionReusableCommand(m) {
149 m.TestModeInfo.Lifetime = LifetimeSession
150 return
151 }
152 tag := ""
153 if m.Spec.Metadata != nil {
154 tag = m.Spec.Metadata["type"]
155 }
156 switch tag {
157 case "config":
158 m.TestModeInfo.Lifetime = LifetimeSession
159 return
160 case "connection":
161 // LifetimeConnection requires a non-empty connID so the
162 // per-connID pool lookup (GetConnectionMocks) has a stable
163 // key. A mock tagged "connection" without a connID is
164 // malformed — fall through to session semantics (still
165 // reusable, just not connection-scoped) rather than
166 // promoting it to per-test (which would be consumed on
167 // first match and break replay for the paired execute).
168 if m.Spec.Metadata["connID"] != "" {
169 m.TestModeInfo.Lifetime = LifetimeConnection
170 return
171 }
172 m.TestModeInfo.Lifetime = LifetimeSession
173 return
174 }