-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Add comprehensive tests for feature-flagged tool handling #1747
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
43bc950
6c1bde3
f760044
727445f
ef7117a
81c8337
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -184,3 +184,141 @@ func TestToolsetMetadataConsistency(t *testing.T) { | |
| } | ||
| } | ||
| } | ||
|
|
||
| // TestFeatureFlaggedToolsAreMutuallyExclusive validates that when multiple tools share | ||
| // the same name with different feature flags, they are mutually exclusive (one uses | ||
| // FeatureFlagEnable while the other uses FeatureFlagDisable with the same flag name). | ||
| // This ensures there are no conflicts where two tools with the same name could be active | ||
| // simultaneously, which would cause "unknown tool" errors. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot this is not quite correct. unknown tool errors came from two tools with same name, and only one of them being returned from filter, and then being filterered out by feature flag. Actually duplicate tools would result in only one registered (as servers wouldn't allow duplicate name tools to be registered and returned), possible the wrong one which is also a problem. The main reason for the request to test this generically is to ensure that as new tools and consolidation work occur etc. we don't miss something like this again. We are protecting against both:
And specifically we are looking at features, because we already have duplicate protection otherwise.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated the test comment in commit 81c8337 to accurately describe what we're protecting against:
This correctly reflects that the test prevents issues where filtering returns the wrong variant or no variant at all, rather than just "unknown tool" errors. |
||
| func TestFeatureFlaggedToolsAreMutuallyExclusive(t *testing.T) { | ||
| tools := AllTools(stubTranslation) | ||
|
|
||
| // Group tools by name | ||
| toolsByName := make(map[string][]inventory.ServerTool) | ||
| for _, tool := range tools { | ||
| toolsByName[tool.Tool.Name] = append(toolsByName[tool.Tool.Name], tool) | ||
| } | ||
|
|
||
| // Check each group of tools with the same name | ||
| for name, group := range toolsByName { | ||
| if len(group) <= 1 { | ||
| continue // Single tool, no conflict possible | ||
| } | ||
|
|
||
| // Skip explicitly allowed duplicates (like get_label) | ||
| if name == "get_label" { | ||
| continue | ||
| } | ||
|
|
||
| t.Run(name, func(t *testing.T) { | ||
| // All tools with the same name must have feature flags | ||
| for i, tool := range group { | ||
| hasFlags := tool.FeatureFlagEnable != "" || tool.FeatureFlagDisable != "" | ||
| assert.True(t, hasFlags, | ||
| "Tool %q (variant %d/%d) shares a name with other tools but has no feature flags", | ||
| name, i+1, len(group)) | ||
| } | ||
|
|
||
| // Verify mutual exclusivity: collect all flags used | ||
| enableFlags := make(map[string]bool) | ||
| disableFlags := make(map[string]bool) | ||
|
|
||
| for _, tool := range group { | ||
| if tool.FeatureFlagEnable != "" { | ||
| enableFlags[tool.FeatureFlagEnable] = true | ||
| } | ||
| if tool.FeatureFlagDisable != "" { | ||
| disableFlags[tool.FeatureFlagDisable] = true | ||
| } | ||
| } | ||
|
|
||
| // For proper mutual exclusivity, we expect: | ||
| // - Same flag name used in both FeatureFlagEnable and FeatureFlagDisable | ||
| // - This ensures only one variant is active at a time | ||
| if len(group) == 2 { | ||
| // Most common case: two variants controlled by one flag | ||
| var flagName string | ||
| for flag := range enableFlags { | ||
| flagName = flag | ||
| break | ||
| } | ||
| for flag := range disableFlags { | ||
| if flagName == "" { | ||
| flagName = flag | ||
| } | ||
| } | ||
|
|
||
| if flagName != "" { | ||
| assert.True(t, enableFlags[flagName] || disableFlags[flagName], | ||
| "Tools sharing name %q should use the same flag for mutual exclusivity", name) | ||
|
|
||
| // Verify exactly one tool has FeatureFlagEnable=flagName and one has FeatureFlagDisable=flagName | ||
| enableCount := 0 | ||
| disableCount := 0 | ||
| for _, tool := range group { | ||
| if tool.FeatureFlagEnable == flagName { | ||
| enableCount++ | ||
| } | ||
| if tool.FeatureFlagDisable == flagName { | ||
| disableCount++ | ||
| } | ||
| } | ||
|
|
||
| // We should have at least one of each for proper mutual exclusivity | ||
| assert.True(t, enableCount > 0 || disableCount > 0, | ||
| "Tools sharing name %q should have proper feature flag configuration", name) | ||
| } | ||
| } | ||
|
|
||
| // Additional safety check: ensure no two tools could be enabled simultaneously | ||
| // by testing all possible flag states | ||
| testFlagStates := []map[string]bool{ | ||
| {}, // All flags off | ||
| // We'll add specific flag combinations based on what flags we found | ||
| } | ||
|
|
||
| // Add test cases for each unique flag | ||
| allFlags := make(map[string]bool) | ||
| for flag := range enableFlags { | ||
| allFlags[flag] = true | ||
| } | ||
| for flag := range disableFlags { | ||
| allFlags[flag] = true | ||
| } | ||
|
|
||
| for flag := range allFlags { | ||
| testFlagStates = append(testFlagStates, map[string]bool{flag: true}) | ||
| } | ||
|
|
||
| // Test each flag state | ||
| for stateIdx, flagState := range testFlagStates { | ||
| enabledCount := 0 | ||
| for _, tool := range group { | ||
| enabled := true | ||
|
|
||
| // Check FeatureFlagEnable - tool requires this flag to be ON | ||
| if tool.FeatureFlagEnable != "" { | ||
| if !flagState[tool.FeatureFlagEnable] { | ||
| enabled = false | ||
| } | ||
| } | ||
|
|
||
| // Check FeatureFlagDisable - tool is disabled if this flag is ON | ||
| if tool.FeatureFlagDisable != "" { | ||
| if flagState[tool.FeatureFlagDisable] { | ||
| enabled = false | ||
| } | ||
| } | ||
|
|
||
| if enabled { | ||
| enabledCount++ | ||
| } | ||
| } | ||
|
|
||
| assert.LessOrEqual(t, enabledCount, 1, | ||
| "Flag state %d for tool %q: At most one variant should be enabled (found %d enabled)", | ||
| stateIdx, name, enabledCount) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot I don't want a specific test, only generic. Delete this addition. Now it's fixed it's not useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Removed the specific test in commit 727445f. The generic tests provide comprehensive coverage across all feature flag combinations.