feat(02-02): capture, scrub, and strictly diff stateful flows
Resolve named placeholders from a private variable store, mask dates and ids after shape checks, and keep comparing independent steps. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -19,22 +19,44 @@ func ReplayFlow(ctx context.Context, flow Flow, cfg ReplayConfig) (Result, error
|
||||
client = defaultClient()
|
||||
}
|
||||
limit := maxBody(cfg.MaxBody)
|
||||
store := cfg.Store
|
||||
if store == nil {
|
||||
store = mustMemoryStore()
|
||||
}
|
||||
result := Result{OK: true, Steps: make([]StepResult, 0, len(flow.Steps))}
|
||||
skipRest := false
|
||||
for _, step := range flow.Steps {
|
||||
got, err := doStep(ctx, client, cfg.Target, step.Request, limit)
|
||||
if skipRest {
|
||||
result.Steps = append(result.Steps, StepResult{ID: step.ID, Skipped: true})
|
||||
continue
|
||||
}
|
||||
sr := StepResult{ID: step.ID, OK: true}
|
||||
req, err := expandRequest(step.Request, store)
|
||||
if err != nil {
|
||||
sr.OK = false
|
||||
result.OK = false
|
||||
sr.Diffs = append(sr.Diffs, Diff{Path: "request", Expected: "resolved placeholders", Actual: err.Error()})
|
||||
result.Steps = append(result.Steps, sr)
|
||||
skipRest = true
|
||||
continue
|
||||
}
|
||||
got, err := doStep(ctx, client, cfg.Target, req, limit)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("tide: replay step %s: %w", step.ID, err)
|
||||
}
|
||||
sr := StepResult{ID: step.ID, OK: true}
|
||||
if step.Response.Status != 0 && got.Status != step.Response.Status {
|
||||
live := step
|
||||
live.Request = req
|
||||
live.Response = got
|
||||
if err := CaptureStep(store, &live); err != nil {
|
||||
sr.OK = false
|
||||
sr.Diffs = append(sr.Diffs, Diff{
|
||||
Path: "status",
|
||||
Expected: fmt.Sprintf("%d", step.Response.Status),
|
||||
Actual: fmt.Sprintf("%d", got.Status),
|
||||
})
|
||||
result.OK = false
|
||||
sr.Diffs = append(sr.Diffs, Diff{Path: "capture", Expected: "captured value", Actual: err.Error()})
|
||||
result.Steps = append(result.Steps, sr)
|
||||
skipRest = true
|
||||
continue
|
||||
}
|
||||
sr.Diffs = append(sr.Diffs, compareBodies(step.Response, got)...)
|
||||
_ = ScrubStep(store, &live)
|
||||
sr.Diffs = append(sr.Diffs, compareStep(step, live.Response)...)
|
||||
if len(sr.Diffs) > 0 {
|
||||
sr.OK = false
|
||||
result.OK = false
|
||||
@@ -46,3 +68,22 @@ func ReplayFlow(ctx context.Context, flow Flow, cfg ReplayConfig) (Result, error
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func mustMemoryStore() *Store {
|
||||
s, _ := OpenStore("")
|
||||
return s
|
||||
}
|
||||
|
||||
func compareStep(want Step, got Response) []Diff {
|
||||
var diffs []Diff
|
||||
if want.Response.Status != 0 && got.Status != want.Response.Status {
|
||||
diffs = append(diffs, Diff{
|
||||
Path: "status",
|
||||
Expected: fmt.Sprintf("%d", want.Response.Status),
|
||||
Actual: fmt.Sprintf("%d", got.Status),
|
||||
})
|
||||
}
|
||||
diffs = append(diffs, compareHeaders(want.Response.Headers, got.Headers, want.Headers)...)
|
||||
diffs = append(diffs, compareBodies(want.Response, got, want)...)
|
||||
return diffs
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user