fix(02-03): resolve relative seed specs and skip only recorded seeds
Manifest seed paths are fixtures-relative. Skip re-hitting the backend only when every seed step already has a recorded status so a hand-written spec can be recorded in place. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -315,14 +315,6 @@ func RecordManifest(ctx context.Context, m Manifest, cfg ManifestConfig) (Covera
|
|||||||
}
|
}
|
||||||
|
|
||||||
func recordSeed(ctx context.Context, seed *Seed, cfg ManifestConfig) error {
|
func recordSeed(ctx context.Context, seed *Seed, cfg ManifestConfig) error {
|
||||||
spec, err := LoadFlow(seed.Spec)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
flow, err := RecordFlow(ctx, spec, RecordConfig{Target: cfg.Target, Store: cfg.Store, Rules: cfg.Rules})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dest := seed.Fixture
|
dest := seed.Fixture
|
||||||
if dest == "" {
|
if dest == "" {
|
||||||
dest = seed.Spec
|
dest = seed.Spec
|
||||||
@@ -330,12 +322,58 @@ func recordSeed(ctx context.Context, seed *Seed, cfg ManifestConfig) error {
|
|||||||
if cfg.Fixtures != "" && !filepath.IsAbs(dest) {
|
if cfg.Fixtures != "" && !filepath.IsAbs(dest) {
|
||||||
dest = filepath.Join(cfg.Fixtures, dest)
|
dest = filepath.Join(cfg.Fixtures, dest)
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(dest); err == nil && !cfg.Update {
|
if !cfg.Update {
|
||||||
return nil
|
if recorded, err := seedAlreadyRecorded(dest); err != nil {
|
||||||
|
return err
|
||||||
|
} else if recorded {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spec, err := LoadFlow(resolveSeedSpec(seed.Spec, cfg.Fixtures))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flow, err := RecordFlow(ctx, spec, RecordConfig{Target: cfg.Target, Store: cfg.Store, Rules: cfg.Rules})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return SaveFlow(dest, flow)
|
return SaveFlow(dest, flow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func seedAlreadyRecorded(path string) (bool, error) {
|
||||||
|
st, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if st.IsDir() || st.Size() == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
flow, err := LoadFlow(path)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
for _, step := range flow.Steps {
|
||||||
|
if step.Response.Status == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(flow.Steps) > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveSeedSpec(spec, fixtures string) string {
|
||||||
|
if spec == "" || filepath.IsAbs(spec) || fixtures == "" {
|
||||||
|
return spec
|
||||||
|
}
|
||||||
|
joined := filepath.Join(fixtures, spec)
|
||||||
|
if _, err := os.Stat(joined); err == nil {
|
||||||
|
return joined
|
||||||
|
}
|
||||||
|
return spec
|
||||||
|
}
|
||||||
|
|
||||||
func recordRoute(ctx context.Context, route Route, cfg ManifestConfig) error {
|
func recordRoute(ctx context.Context, route Route, cfg ManifestConfig) error {
|
||||||
for _, c := range route.Cases {
|
for _, c := range route.Cases {
|
||||||
dest := caseFixturePath(cfg.Fixtures, route, c)
|
dest := caseFixturePath(cfg.Fixtures, route, c)
|
||||||
|
|||||||
@@ -365,3 +365,44 @@ func TestCoveragePendingMismatchDoesNotFail(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRecordSeedResolvesRelativeSpec(t *testing.T) {
|
||||||
|
fixtures := t.TempDir()
|
||||||
|
if err := os.MkdirAll(filepath.Join(fixtures, "seed"), 0o755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
spec := Flow{Version: 1, Name: "seed", Steps: []Step{{
|
||||||
|
ID: "ok",
|
||||||
|
Request: Request{Method: http.MethodGet, Path: "/seed"},
|
||||||
|
}}}
|
||||||
|
if err := SaveFlow(filepath.Join(fixtures, "seed", "bootstrap.yaml"), spec); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hits := 0
|
||||||
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
hits++
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = w.Write([]byte(`{"ok":true}`))
|
||||||
|
}))
|
||||||
|
t.Cleanup(srv.Close)
|
||||||
|
m := Manifest{
|
||||||
|
Version: 1,
|
||||||
|
AuthGroups: []string{"public"},
|
||||||
|
Seed: &Seed{Spec: "seed/bootstrap.yaml", Fixture: "seed/bootstrap.yaml"},
|
||||||
|
Routes: []Route{{
|
||||||
|
ID: "GET /later public", Method: http.MethodGet, Path: "/later",
|
||||||
|
AuthGroup: "public", Status: StatusPending,
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
if _, err := RecordManifest(context.Background(), m, ManifestConfig{Target: srv.URL, Fixtures: fixtures}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if hits != 1 {
|
||||||
|
t.Fatalf("seed hits %d", hits)
|
||||||
|
}
|
||||||
|
if _, err := RecordManifest(context.Background(), m, ManifestConfig{Target: srv.URL, Fixtures: fixtures}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if hits != 1 {
|
||||||
|
t.Fatalf("existing seed must not re-hit PHP: %d", hits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user