diff --git a/features/greet/greet.feature b/features/greet/greet.feature index 5a5ed68..ba2513d 100644 --- a/features/greet/greet.feature +++ b/features/greet/greet.feature @@ -15,6 +15,16 @@ Feature: Greet Service When I request a greeting for "John" Then the response should be "{\"message\":\"Hello John!\"}" + @critical @v2-gate + Scenario: v2 endpoint returns 404 when api.v2_enabled is disabled + # In the default tag-filter run (~@v2), the test server starts with + # v2_enabled=false. The v2EnabledGate middleware (ADR-0023 Phase 4) + # returns 404 with a JSON body explaining the flag state. + Given the server is running + When I send a POST request to v2 greet with name "John" + Then the status code should be 404 + And the response should contain "v2 API is currently disabled" + @v2 @api Scenario: v2 greeting with JSON POST request Given the server is running with v2 enabled diff --git a/pkg/bdd/testserver/server.go b/pkg/bdd/testserver/server.go index 23448d3..67c5636 100644 --- a/pkg/bdd/testserver/server.go +++ b/pkg/bdd/testserver/server.go @@ -741,8 +741,14 @@ func (s *Server) waitForServerReady() error { } } -// shouldEnableV2 determines if v2 API should be enabled for this test server -// This is the ONLY place that reads FEATURE and GODOG_TAGS env vars +// shouldEnableV2 determines if v2 API should be enabled for this test server. +// This is the ONLY place that reads FEATURE and GODOG_TAGS env vars. +// +// 2026-05-05: previous version used strings.Contains(tags, "@v2") which +// wrongly matched the negation `~@v2` as well. This made the "v1" greet +// sub-test (tags `~@v2 && ~@skip`) actually run with v2 enabled, masking +// the gate behavior we now test in feature `@v2-gate` scenario. Fixed +// here by inspecting each && clause and checking for positive inclusion. func (s *Server) shouldEnableV2() bool { feature := os.Getenv("FEATURE") @@ -753,9 +759,19 @@ func (s *Server) shouldEnableV2() bool { return false } - // For greet feature: enable v2 if tags include @v2 + // For greet feature: enable v2 if tags include `@v2` as a POSITIVE clause. + // Godog tag expression syntax: clauses separated by `&&` or `||`, negation + // via leading `~`. A positive clause matches exactly `@v2` (after trim). tags := os.Getenv("GODOG_TAGS") - return strings.Contains(tags, "@v2") + for _, clause := range strings.FieldsFunc(tags, func(r rune) bool { + return r == '&' || r == '|' || r == ' ' + }) { + clause = strings.TrimSpace(clause) + if clause == "@v2" { + return true + } + } + return false } // createTestConfig creates a test configuration