@@ -150,6 +150,132 @@ def fake_telemetry_callback(self, evaluation_event):
150150 assert evaluation_event
151151 self .called_telemetry = True
152152
153+ # method: duplicate_feature_flag_handling
154+ def test_duplicate_feature_flags_last_wins (self ):
155+ """Test that when multiple feature flags have the same ID, the last one wins."""
156+ feature_flags = {
157+ "feature_management" : {
158+ "feature_flags" : [
159+ {
160+ "id" : "DuplicateFlag" ,
161+ "description" : "First" ,
162+ "enabled" : "true" ,
163+ "conditions" : {"client_filters" : []},
164+ },
165+ {
166+ "id" : "DuplicateFlag" ,
167+ "description" : "Second" ,
168+ "enabled" : "false" ,
169+ "conditions" : {"client_filters" : []},
170+ },
171+ {
172+ "id" : "DuplicateFlag" ,
173+ "description" : "Third" ,
174+ "enabled" : "true" ,
175+ "conditions" : {"client_filters" : []},
176+ },
177+ ]
178+ }
179+ }
180+ feature_manager = FeatureManager (feature_flags )
181+
182+ # The last flag should win (enabled: true)
183+ assert feature_manager .is_enabled ("DuplicateFlag" ) == True
184+
185+ # Should only list unique names
186+ flag_names = feature_manager .list_feature_flag_names ()
187+ assert "DuplicateFlag" in flag_names
188+ # Count how many times DuplicateFlag appears in the list
189+ duplicate_count = flag_names .count ("DuplicateFlag" )
190+ assert duplicate_count == 1 , f"Expected DuplicateFlag to appear once, but appeared { duplicate_count } times"
191+
192+ def test_duplicate_feature_flags_last_wins_disabled (self ):
193+ """Test that when multiple feature flags have the same ID, the last one wins even if disabled."""
194+ feature_flags = {
195+ "feature_management" : {
196+ "feature_flags" : [
197+ {
198+ "id" : "DuplicateFlag" ,
199+ "description" : "First" ,
200+ "enabled" : "true" ,
201+ "conditions" : {"client_filters" : []},
202+ },
203+ {
204+ "id" : "DuplicateFlag" ,
205+ "description" : "Second" ,
206+ "enabled" : "true" ,
207+ "conditions" : {"client_filters" : []},
208+ },
209+ {
210+ "id" : "DuplicateFlag" ,
211+ "description" : "Third" ,
212+ "enabled" : "false" ,
213+ "conditions" : {"client_filters" : []},
214+ },
215+ ]
216+ }
217+ }
218+ feature_manager = FeatureManager (feature_flags )
219+
220+ # The last flag should win (enabled: false)
221+ assert feature_manager .is_enabled ("DuplicateFlag" ) == False
222+
223+ def test_duplicate_feature_flags_mixed_with_unique (self ):
224+ """Test behavior with a mix of duplicate and unique feature flags."""
225+ feature_flags = {
226+ "feature_management" : {
227+ "feature_flags" : [
228+ {
229+ "id" : "UniqueFlag1" ,
230+ "description" : "First unique" ,
231+ "enabled" : "true" ,
232+ "conditions" : {"client_filters" : []},
233+ },
234+ {
235+ "id" : "DuplicateFlag" ,
236+ "description" : "First duplicate" ,
237+ "enabled" : "false" ,
238+ "conditions" : {"client_filters" : []},
239+ },
240+ {
241+ "id" : "UniqueFlag2" ,
242+ "description" : "Second unique" ,
243+ "enabled" : "false" ,
244+ "conditions" : {"client_filters" : []},
245+ },
246+ {
247+ "id" : "DuplicateFlag" ,
248+ "description" : "Second duplicate" ,
249+ "enabled" : "true" ,
250+ "conditions" : {"client_filters" : []},
251+ },
252+ {
253+ "id" : "UniqueFlag3" ,
254+ "description" : "Third unique" ,
255+ "enabled" : "true" ,
256+ "conditions" : {"client_filters" : []},
257+ },
258+ ]
259+ }
260+ }
261+ feature_manager = FeatureManager (feature_flags )
262+
263+ # Test unique flags work as expected
264+ assert feature_manager .is_enabled ("UniqueFlag1" ) == True
265+ assert feature_manager .is_enabled ("UniqueFlag2" ) == False
266+ assert feature_manager .is_enabled ("UniqueFlag3" ) == True
267+
268+ # Test duplicate flag - last should win (enabled: true)
269+ assert feature_manager .is_enabled ("DuplicateFlag" ) == True
270+
271+ # Test list includes all unique names
272+ flag_names = feature_manager .list_feature_flag_names ()
273+ expected_names = ["UniqueFlag1" , "DuplicateFlag" , "UniqueFlag2" , "UniqueFlag3" ]
274+ assert set (flag_names ) == set (expected_names )
275+ # Ensure each name appears only once
276+ for name in expected_names :
277+ assert flag_names .count (name ) == 1
278+
153279
154280class AlwaysOn (FeatureFilter ):
155281 def evaluate (self , context , ** kwargs ):
0 commit comments