@@ -7,6 +7,11 @@ import Testing
77struct POSLocalCatalogEligibilityServiceTests {
88 private let siteID : Int64 = 123
99
10+ // Default remote feature flag provider that returns true
11+ private func makeRemoteFeatureFlagProvider( returning value: Bool = true ) -> @Sendable ( ) async -> Bool {
12+ return { value }
13+ }
14+
1015 // MARK: - Catalog Size Within Limit
1116
1217 @Test ( " Catalog size within limit returns eligible " )
@@ -19,6 +24,7 @@ struct POSLocalCatalogEligibilityServiceTests {
1924 catalogSizeChecker: sizeChecker,
2025 systemStatusService: systemStatusService,
2126 isLocalCatalogFeatureFlagEnabled: true ,
27+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
2228 catalogSizeLimit: 1000
2329 )
2430 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -36,6 +42,7 @@ struct POSLocalCatalogEligibilityServiceTests {
3642 catalogSizeChecker: sizeChecker,
3743 systemStatusService: systemStatusService,
3844 isLocalCatalogFeatureFlagEnabled: true ,
45+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
3946 catalogSizeLimit: 1000
4047 )
4148 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -55,6 +62,7 @@ struct POSLocalCatalogEligibilityServiceTests {
5562 catalogSizeChecker: sizeChecker,
5663 systemStatusService: systemStatusService,
5764 isLocalCatalogFeatureFlagEnabled: true ,
65+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
5866 catalogSizeLimit: 1000
5967 )
6068 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -88,6 +96,7 @@ struct POSLocalCatalogEligibilityServiceTests {
8896 catalogSizeChecker: sizeChecker,
8997 systemStatusService: systemStatusService,
9098 isLocalCatalogFeatureFlagEnabled: true ,
99+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
91100 catalogSizeLimit: 1000
92101 )
93102 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -119,6 +128,7 @@ struct POSLocalCatalogEligibilityServiceTests {
119128 catalogSizeChecker: sizeChecker,
120129 systemStatusService: systemStatusService,
121130 isLocalCatalogFeatureFlagEnabled: true ,
131+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
122132 catalogSizeLimit: 1000
123133 )
124134 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -144,6 +154,7 @@ struct POSLocalCatalogEligibilityServiceTests {
144154 catalogSizeChecker: sizeChecker,
145155 systemStatusService: systemStatusService,
146156 isLocalCatalogFeatureFlagEnabled: true ,
157+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
147158 catalogSizeLimit: 1000
148159 )
149160 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -169,6 +180,7 @@ struct POSLocalCatalogEligibilityServiceTests {
169180 catalogSizeChecker: sizeChecker,
170181 systemStatusService: systemStatusService,
171182 isLocalCatalogFeatureFlagEnabled: true ,
183+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
172184 catalogSizeLimit: 1000
173185 )
174186 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -199,8 +211,8 @@ struct POSLocalCatalogEligibilityServiceTests {
199211
200212 // MARK: - Feature Flag
201213
202- @Test ( " Feature flag disabled returns ineligible" )
203- func testFeatureFlagDisabledReturnsIneligible ( ) async throws {
214+ @Test ( " Local feature flag disabled returns ineligible" )
215+ func testLocalFeatureFlagDisabledReturnsIneligible ( ) async throws {
204216 let sizeChecker = MockPOSCatalogSizeChecker (
205217 sizeToReturn: . success( POSCatalogSize ( productCount: 500 , variationCount: 400 ) )
206218 )
@@ -209,6 +221,7 @@ struct POSLocalCatalogEligibilityServiceTests {
209221 catalogSizeChecker: sizeChecker,
210222 systemStatusService: systemStatusService,
211223 isLocalCatalogFeatureFlagEnabled: false ,
224+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
212225 catalogSizeLimit: 1000
213226 )
214227 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -229,6 +242,61 @@ struct POSLocalCatalogEligibilityServiceTests {
229242 #expect( sizeChecker. checkCatalogSizeCallCount == 0 )
230243 }
231244
245+ @Test ( " Remote feature flag disabled returns ineligible after refresh " )
246+ func testRemoteFeatureFlagDisabledReturnsIneligible( ) async throws {
247+ let sizeChecker = MockPOSCatalogSizeChecker (
248+ sizeToReturn: . success( POSCatalogSize ( productCount: 500 , variationCount: 400 ) )
249+ )
250+ let systemStatusService = MockPOSSystemStatusService ( )
251+ let service = POSLocalCatalogEligibilityService (
252+ catalogSizeChecker: sizeChecker,
253+ systemStatusService: systemStatusService,
254+ isLocalCatalogFeatureFlagEnabled: true ,
255+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( returning: false ) ,
256+ catalogSizeLimit: 1000
257+ )
258+ try await service. updatePOSEligibility ( isEligible: true , for: siteID)
259+
260+ // First refresh might check catalog (using default true before fetch completes)
261+ _ = try ? await service. refreshEligibilityState ( for: siteID)
262+
263+ // Second refresh should use the fetched remote flag value (false)
264+ let state = try await service. refreshEligibilityState ( for: siteID)
265+
266+ guard case . ineligible( let reason) = state else {
267+ Issue . record ( " Expected ineligible state after remote flag fetch " )
268+ return
269+ }
270+
271+ guard case . featureFlagDisabled = reason else {
272+ Issue . record ( " Expected featureFlagDisabled reason " )
273+ return
274+ }
275+
276+ // Second refresh should not have checked catalog size (short-circuited by flag)
277+ // First refresh might have checked it (count could be 0 or 1)
278+ #expect( sizeChecker. checkCatalogSizeCallCount <= 1 )
279+ }
280+
281+ @Test ( " Both feature flags required for eligibility " )
282+ func testBothFeatureFlagsRequiredForEligibility( ) async throws {
283+ let sizeChecker = MockPOSCatalogSizeChecker (
284+ sizeToReturn: . success( POSCatalogSize ( productCount: 500 , variationCount: 400 ) )
285+ )
286+ let systemStatusService = MockPOSSystemStatusService ( )
287+
288+ // Test with both flags enabled - should be eligible
289+ let serviceWithBothEnabled = POSLocalCatalogEligibilityService (
290+ catalogSizeChecker: sizeChecker,
291+ systemStatusService: systemStatusService,
292+ isLocalCatalogFeatureFlagEnabled: true ,
293+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( returning: true ) ,
294+ catalogSizeLimit: 1000
295+ )
296+ try await serviceWithBothEnabled. updatePOSEligibility ( isEligible: true , for: siteID)
297+ #expect( try await serviceWithBothEnabled. catalogEligibility ( for: siteID) == . eligible)
298+ }
299+
232300 // MARK: - Custom Size Limit
233301
234302 @Test ( " Custom size limit is respected " )
@@ -241,6 +309,7 @@ struct POSLocalCatalogEligibilityServiceTests {
241309 catalogSizeChecker: sizeChecker,
242310 systemStatusService: systemStatusService,
243311 isLocalCatalogFeatureFlagEnabled: true ,
312+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
244313 catalogSizeLimit: 100 // Custom lower limit
245314 )
246315 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -273,6 +342,7 @@ struct POSLocalCatalogEligibilityServiceTests {
273342 catalogSizeChecker: sizeChecker,
274343 systemStatusService: systemStatusService,
275344 isLocalCatalogFeatureFlagEnabled: true ,
345+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
276346 catalogSizeLimit: 1000
277347 )
278348
@@ -305,6 +375,7 @@ struct POSLocalCatalogEligibilityServiceTests {
305375 catalogSizeChecker: sizeChecker,
306376 systemStatusService: systemStatusService,
307377 isLocalCatalogFeatureFlagEnabled: true ,
378+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
308379 catalogSizeLimit: 1000
309380 )
310381
@@ -336,6 +407,7 @@ struct POSLocalCatalogEligibilityServiceTests {
336407 catalogSizeChecker: sizeChecker,
337408 systemStatusService: systemStatusService,
338409 isLocalCatalogFeatureFlagEnabled: true ,
410+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
339411 catalogSizeLimit: 1000
340412 )
341413
@@ -390,6 +462,7 @@ struct POSLocalCatalogEligibilityServiceTests {
390462 catalogSizeChecker: sizeChecker,
391463 systemStatusService: systemStatusService,
392464 isLocalCatalogFeatureFlagEnabled: true ,
465+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
393466 catalogSizeLimit: 1000
394467 )
395468 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
@@ -449,6 +522,7 @@ struct POSLocalCatalogEligibilityServiceTests {
449522 catalogSizeChecker: sizeChecker,
450523 systemStatusService: systemStatusService,
451524 isLocalCatalogFeatureFlagEnabled: true ,
525+ remoteFeatureFlagProvider: makeRemoteFeatureFlagProvider ( ) ,
452526 catalogSizeLimit: 1000
453527 )
454528 try await service. updatePOSEligibility ( isEligible: true , for: siteID)
0 commit comments