- Add a generic tide flow schema with YAML fixture IO and HTTP record/replay - Register parity:record and parity:replay on the bonfire summer tool - Diff JSON scalars at $.path and non-JSON bodies at the changed byte offset Co-authored-by: Cursor <cursoragent@cursor.com>
49 lines
1.3 KiB
Go
49 lines
1.3 KiB
Go
package tide
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// ReplayFlow executes each recorded step against target and diffs responses.
|
|
func ReplayFlow(ctx context.Context, flow Flow, cfg ReplayConfig) (Result, error) {
|
|
if err := validateFlow(flow); err != nil {
|
|
return Result{}, err
|
|
}
|
|
if strings.TrimSpace(cfg.Target) == "" {
|
|
return Result{}, fmt.Errorf("tide: replay target is required")
|
|
}
|
|
client := cfg.Client
|
|
if client == nil {
|
|
client = defaultClient()
|
|
}
|
|
limit := maxBody(cfg.MaxBody)
|
|
result := Result{OK: true, Steps: make([]StepResult, 0, len(flow.Steps))}
|
|
for _, step := range flow.Steps {
|
|
got, err := doStep(ctx, client, cfg.Target, step.Request, 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 {
|
|
sr.OK = false
|
|
sr.Diffs = append(sr.Diffs, Diff{
|
|
Path: "status",
|
|
Expected: fmt.Sprintf("%d", step.Response.Status),
|
|
Actual: fmt.Sprintf("%d", got.Status),
|
|
})
|
|
}
|
|
sr.Diffs = append(sr.Diffs, compareBodies(step.Response, got)...)
|
|
if len(sr.Diffs) > 0 {
|
|
sr.OK = false
|
|
result.OK = false
|
|
}
|
|
result.Steps = append(result.Steps, sr)
|
|
}
|
|
if !result.OK {
|
|
return result, &MismatchError{Result: result}
|
|
}
|
|
return result, nil
|
|
}
|