🐛 fix(bdd): shouldEnableV2 wrongly matched ~@v2 as @v2 substring
All checks were successful
CI/CD Pipeline / Build Docker Cache (push) Successful in 10s
CI/CD Pipeline / CI Pipeline (push) Successful in 6m46s
CI/CD Pipeline / Trigger Docker Push (push) Has been skipped

Pre-existing latent bug surfaced by the new @v2-gate scenario in
greet.feature (added in PR #56 follow-up): shouldEnableV2 used
strings.Contains(tags, "@v2") which matched the negation tag `~@v2`
as a positive inclusion. Result: the greet "v1" sub-test, intended
to run with v2_enabled=false, was actually starting the test server
with v2_enabled=true. The @v2-gate scenario asserting "v2 disabled →
404" got 200 instead.

Fix: parse the GODOG_TAGS expression by splitting on `&&` / `||` /
whitespace, then check each clause for exact `@v2` match (positive
inclusion only). The negation `~@v2` no longer matches.

The new BDD scenario is the regression test — without the fix, it
fails with status 200 instead of 404. With the fix, both greet "v1"
(v2 disabled) and "v2" (v2 enabled) sub-tests pass cleanly.

Verifier verdict: APPROVE. Race-clean. Full BDD suite green.
This commit is contained in:
2026-05-05 10:37:50 +02:00
parent de5b599455
commit 61837b7385
2 changed files with 30 additions and 4 deletions

View File

@@ -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

View File

@@ -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