Add tests for feature manager#44
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a comprehensive set of unit tests around the FeatureManager API to validate initialization behavior, filter evaluation semantics, variant selection edge cases, and validation/provider error paths.
Changes:
- Adds tests for
NewFeatureManagerinitialization scenarios (nil provider, custom filters, nil filters in options). - Adds tests for
GetFeatureNames, missing/unknown filters, requirement type evaluation (Any/All), and filter error propagation. - Adds tests covering variant assignment edge cases, provider error propagation across APIs, and JSON deserialization into
FeatureManagement.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| expected := []string{"Feature1", "Feature2", "Feature3"} | ||
| for i, name := range names { | ||
| if name != expected[i] { | ||
| t.Errorf("Expected name %q at index %d, got %q", expected[i], i, name) | ||
| } | ||
| } |
There was a problem hiding this comment.
TestGetFeatureNames asserts a fixed ordering of returned names, but GetFeatureNames does not document any ordering guarantee (it just forwards whatever order the provider returns). This can make the test flaky or overly constraining for alternative providers; consider sorting both slices or comparing as sets instead of by index.
| var fm struct { | ||
| FeatureFlags []FeatureFlag `json:"feature_flags"` | ||
| } | ||
| json.Unmarshal([]byte(jsonData), &fm) |
There was a problem hiding this comment.
The result of json.Unmarshal is ignored here. If the JSON is malformed (or the schema changes), the test will fail later with a less actionable error; capture and assert the unmarshal error so failures point to the real cause.
| json.Unmarshal([]byte(jsonData), &fm) | |
| if err := json.Unmarshal([]byte(jsonData), &fm); err != nil { | |
| t.Fatalf("Failed to unmarshal test JSON: %v", err) | |
| } |
| var fm struct { | ||
| FeatureFlags []FeatureFlag `json:"feature_flags"` | ||
| } | ||
| json.Unmarshal([]byte(jsonData), &fm) |
There was a problem hiding this comment.
The result of json.Unmarshal is ignored here. Please check and fail the test on unmarshal error to avoid masking the root cause of failures.
| json.Unmarshal([]byte(jsonData), &fm) | |
| if err := json.Unmarshal([]byte(jsonData), &fm); err != nil { | |
| t.Fatalf("Failed to unmarshal test JSON: %v", err) | |
| } |
| enabled, _ := fm.IsEnabled("AnyFilterMixed") | ||
| if !enabled { | ||
| t.Error("Expected feature to be enabled when one filter returns true with RequirementTypeAny") | ||
| } | ||
| }) | ||
|
|
||
| t.Run("All filters false", func(t *testing.T) { | ||
| enabled, _ := fm.IsEnabled("AnyFilterAllFalse") |
There was a problem hiding this comment.
This subtest ignores the error returned from IsEnabled. If evaluation unexpectedly errors (e.g., validation or filter issues), the assertion may report an incorrect cause; assert err == nil before checking enabled.
| enabled, _ := fm.IsEnabled("AnyFilterMixed") | |
| if !enabled { | |
| t.Error("Expected feature to be enabled when one filter returns true with RequirementTypeAny") | |
| } | |
| }) | |
| t.Run("All filters false", func(t *testing.T) { | |
| enabled, _ := fm.IsEnabled("AnyFilterAllFalse") | |
| enabled, err := fm.IsEnabled("AnyFilterMixed") | |
| if err != nil { | |
| t.Fatalf("Expected no error evaluating feature AnyFilterMixed: %v", err) | |
| } | |
| if !enabled { | |
| t.Error("Expected feature to be enabled when one filter returns true with RequirementTypeAny") | |
| } | |
| }) | |
| t.Run("All filters false", func(t *testing.T) { | |
| enabled, err := fm.IsEnabled("AnyFilterAllFalse") | |
| if err != nil { | |
| t.Fatalf("Expected no error evaluating feature AnyFilterAllFalse: %v", err) | |
| } |
| enabled, _ := fm.IsEnabled("AnyFilterMixed") | ||
| if !enabled { | ||
| t.Error("Expected feature to be enabled when one filter returns true with RequirementTypeAny") | ||
| } | ||
| }) | ||
|
|
||
| t.Run("All filters false", func(t *testing.T) { | ||
| enabled, _ := fm.IsEnabled("AnyFilterAllFalse") |
There was a problem hiding this comment.
This subtest ignores the error returned from IsEnabled. Please assert the error is nil before asserting on the enabled state.
| enabled, _ := fm.IsEnabled("AnyFilterMixed") | |
| if !enabled { | |
| t.Error("Expected feature to be enabled when one filter returns true with RequirementTypeAny") | |
| } | |
| }) | |
| t.Run("All filters false", func(t *testing.T) { | |
| enabled, _ := fm.IsEnabled("AnyFilterAllFalse") | |
| enabled, err := fm.IsEnabled("AnyFilterMixed") | |
| if err != nil { | |
| t.Fatalf("Expected no error from IsEnabled: %v", err) | |
| } | |
| if !enabled { | |
| t.Error("Expected feature to be enabled when one filter returns true with RequirementTypeAny") | |
| } | |
| }) | |
| t.Run("All filters false", func(t *testing.T) { | |
| enabled, err := fm.IsEnabled("AnyFilterAllFalse") | |
| if err != nil { | |
| t.Fatalf("Expected no error from IsEnabled: %v", err) | |
| } |
NewFeatureManager initialization:
GetFeatureNames:
Unknown/missing filter:
RequirementType logic:
Filter error handling:
StatusOverride:
GetVariant edge cases:
IsEnabledWithAppContext:
Validation errors:
Provider errors:
FeatureManagement struct: