package tide import ( "context" "net/http" "net/http/httptest" "sync/atomic" "testing" ) func TestFlowMismatchContinuesAndCaptureSkipsRest(t *testing.T) { var hits atomic.Int32 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { hits.Add(1) w.Header().Set("Content-Type", "application/json") switch r.URL.Path { case "/one": _, _ = w.Write([]byte(`{"data":"no"}`)) default: _, _ = w.Write([]byte(`{"data":"ok"}`)) } })) t.Cleanup(srv.Close) mismatch := Flow{ Version: 1, Name: "mismatch-continue", Steps: []Step{ { ID: "a", Request: Request{Method: http.MethodGet, Path: "/one"}, Response: Response{Status: 200, Headers: jsonCT(), Body: Body(`{"data":"yes"}`)}, }, { ID: "b", Request: Request{Method: http.MethodGet, Path: "/two"}, Response: Response{Status: 200, Headers: jsonCT(), Body: Body(`{"data":"ok"}`)}, }, }, } res, err := ReplayFlow(context.Background(), mismatch, ReplayConfig{Target: srv.URL}) if err == nil { t.Fatal("mismatch must error") } if hits.Load() != 2 { t.Fatalf("mismatch should continue, hits=%d", hits.Load()) } if len(res.Steps) != 2 || res.Steps[1].Skipped || !res.Steps[1].OK { t.Fatalf("step b should run and pass: %+v", res.Steps) } hits.Store(0) captureFail := Flow{ Version: 1, Name: "capture-skip", Steps: []Step{ { ID: "a", Request: Request{Method: http.MethodGet, Path: "/two"}, Response: Response{Status: 200, Headers: jsonCT(), Body: Body(`{"data":"ok"}`)}, Capture: []CaptureRule{{From: "response.json", Path: "$.token", As: "jwt:alice"}}, }, { ID: "b", Request: Request{Method: http.MethodGet, Path: "/two"}, Response: Response{Status: 200, Headers: jsonCT(), Body: Body(`{"data":"ok"}`)}, }, }, } res, err = ReplayFlow(context.Background(), captureFail, ReplayConfig{Target: srv.URL}) if err == nil { t.Fatal("failed capture must error") } if hits.Load() != 1 { t.Fatalf("capture fail should skip rest, hits=%d", hits.Load()) } if len(res.Steps) != 2 || !res.Steps[1].Skipped { t.Fatalf("step b should skip: %+v", res.Steps) } }