diff --git a/LaunchDarkly/GeneratedCode/mocks.generated.swift b/LaunchDarkly/GeneratedCode/mocks.generated.swift index 0dcc38e6..4392a032 100644 --- a/LaunchDarkly/GeneratedCode/mocks.generated.swift +++ b/LaunchDarkly/GeneratedCode/mocks.generated.swift @@ -300,6 +300,16 @@ final class EventReportingMock: EventReporting { // MARK: - FeatureFlagCachingMock final class FeatureFlagCachingMock: FeatureFlagCaching { + // MARK: maxCachedUsers + var maxCachedUsersSetCount = 0 + var setMaxCachedUsersCallback: (() -> Void)? + var maxCachedUsers: Int = 5 { + didSet { + maxCachedUsersSetCount += 1 + setMaxCachedUsersCallback?() + } + } + // MARK: retrieveFeatureFlags var retrieveFeatureFlagsCallCount = 0 var retrieveFeatureFlagsCallback: (() -> Void)? diff --git a/LaunchDarkly/LaunchDarkly/LDClient.swift b/LaunchDarkly/LaunchDarkly/LDClient.swift index 1933c96a..3f4007e8 100644 --- a/LaunchDarkly/LaunchDarkly/LDClient.swift +++ b/LaunchDarkly/LaunchDarkly/LDClient.swift @@ -307,6 +307,8 @@ public class LDClient { @available(*, deprecated, message: "Please use the startCompleteWhenFlagsReceived method instead") public func start(config: LDConfig, user: LDUser? = nil, completion: (() -> Void)? = nil) { Log.debug(typeName(and: #function, appending: ": ") + "starting") + flagCache.maxCachedUsers = config.maxCachedUsers + cacheConverter = self.serviceFactory.makeCacheConverter(maxCachedUsers: config.maxCachedUsers) let wasStarted = hasStarted let wasOnline = isOnline isStarting = true @@ -338,6 +340,8 @@ public class LDClient { */ public func startCompleteWhenFlagsReceived(config: LDConfig, user: LDUser? = nil, completion: (() -> Void)? = nil) { Log.debug(typeName(and: #function, appending: ": ") + "starting") + flagCache.maxCachedUsers = config.maxCachedUsers + cacheConverter = self.serviceFactory.makeCacheConverter(maxCachedUsers: config.maxCachedUsers) let wasStarted = hasStarted let wasOnline = isOnline isStarting = true @@ -1015,9 +1019,9 @@ public class LDClient { self.serviceFactory = serviceFactory } environmentReporter = self.serviceFactory.makeEnvironmentReporter() - flagCache = self.serviceFactory.makeFeatureFlagCache() + flagCache = self.serviceFactory.makeFeatureFlagCache(maxCachedUsers: LDConfig.Defaults.maxCachedUsers) LDUserWrapper.configureKeyedArchiversToHandleVersion2_3_0AndOlderUserCacheFormat() - cacheConverter = self.serviceFactory.makeCacheConverter() + cacheConverter = self.serviceFactory.makeCacheConverter(maxCachedUsers: LDConfig.Defaults.maxCachedUsers) flagChangeNotifier = self.serviceFactory.makeFlagChangeNotifier() throttler = self.serviceFactory.makeThrottler(maxDelay: Throttler.Constants.defaultDelay, environmentReporter: environmentReporter) diff --git a/LaunchDarkly/LaunchDarkly/Models/LDConfig.swift b/LaunchDarkly/LaunchDarkly/Models/LDConfig.swift index 7a718408..405268dc 100644 --- a/LaunchDarkly/LaunchDarkly/Models/LDConfig.swift +++ b/LaunchDarkly/LaunchDarkly/Models/LDConfig.swift @@ -69,6 +69,9 @@ public struct LDConfig { /// The default setting for whether we request evaluation reasons for all flags. static let evaluationReasons = false + + /// The default setting for the maximum number of locally cached users. + static let maxCachedUsers = 5 } /// The minimum values allowed to be set into LDConfig. @@ -179,6 +182,9 @@ public struct LDConfig { /// Enables requesting evaluation reasons for all flags. (Default: false) public var evaluationReasons: Bool = Defaults.evaluationReasons + + /// An Integer that tells UserEnvironmentFlagCache the maximum number of users to locally cache. Can be set to -1 for unlimited cached users. + public var maxCachedUsers: Int = Defaults.maxCachedUsers /// LaunchDarkly defined minima for selected configurable items public let minima: Minima @@ -241,6 +247,7 @@ extension LDConfig: Equatable { && lhs.inlineUserInEvents == rhs.inlineUserInEvents && lhs.isDebugMode == rhs.isDebugMode && lhs.evaluationReasons == rhs.evaluationReasons + && lhs.maxCachedUsers == rhs.maxCachedUsers } } diff --git a/LaunchDarkly/LaunchDarkly/Service Objects/Cache/CacheConverter.swift b/LaunchDarkly/LaunchDarkly/Service Objects/Cache/CacheConverter.swift index 5e2c214a..01dcb6b4 100644 --- a/LaunchDarkly/LaunchDarkly/Service Objects/Cache/CacheConverter.swift +++ b/LaunchDarkly/LaunchDarkly/Service Objects/Cache/CacheConverter.swift @@ -28,8 +28,8 @@ final class CacheConverter: CacheConverting { private(set) var deprecatedCaches = [DeprecatedCacheModel: DeprecatedCache]() let maxAge: TimeInterval - init(serviceFactory: ClientServiceCreating, maxAge: TimeInterval = Constants.maxAge) { - currentCache = serviceFactory.makeFeatureFlagCache() + init(serviceFactory: ClientServiceCreating, maxCachedUsers: Int, maxAge: TimeInterval = Constants.maxAge) { + currentCache = serviceFactory.makeFeatureFlagCache(maxCachedUsers: maxCachedUsers) self.maxAge = maxAge DeprecatedCacheModel.allCases.forEach { version in deprecatedCaches[version] = serviceFactory.makeDeprecatedCacheModel(version) diff --git a/LaunchDarkly/LaunchDarkly/Service Objects/Cache/UserEnvironmentFlagCache.swift b/LaunchDarkly/LaunchDarkly/Service Objects/Cache/UserEnvironmentFlagCache.swift index 3f9e18e6..92a63e62 100644 --- a/LaunchDarkly/LaunchDarkly/Service Objects/Cache/UserEnvironmentFlagCache.swift +++ b/LaunchDarkly/LaunchDarkly/Service Objects/Cache/UserEnvironmentFlagCache.swift @@ -13,6 +13,8 @@ enum FlagCachingStoreMode: CaseIterable { //sourcery: autoMockable protocol FeatureFlagCaching { + //sourcery: defaultMockValue = 5 + var maxCachedUsers: Int { get set } func retrieveFeatureFlags(forUserWithKey userKey: String, andMobileKey mobileKey: String) -> [LDFlagKey: FeatureFlag]? func storeFeatureFlags(_ featureFlags: [LDFlagKey: FeatureFlag], forUser user: LDUser, andMobileKey mobileKey: String, lastUpdated: Date, storeMode: FlagCachingStoreMode) } @@ -21,7 +23,6 @@ final class UserEnvironmentFlagCache: FeatureFlagCaching { struct Constants { static let cacheStoreOperationQueueLabel = "com.launchDarkly.FeatureFlagCaching.cacheStoreOperationQueue" - static let maxCachedUsers = 5 } struct CacheKeys { @@ -29,11 +30,13 @@ final class UserEnvironmentFlagCache: FeatureFlagCaching { } private(set) var keyedValueCache: KeyedValueCaching + var maxCachedUsers: Int private static let cacheStoreOperationQueue = DispatchQueue(label: Constants.cacheStoreOperationQueueLabel, qos: .background) - init(withKeyedValueCache keyedValueCache: KeyedValueCaching) { + init(withKeyedValueCache keyedValueCache: KeyedValueCaching, maxCachedUsers: Int) { self.keyedValueCache = keyedValueCache + self.maxCachedUsers = maxCachedUsers } func retrieveFeatureFlags(forUserWithKey userKey: String, andMobileKey mobileKey: String) -> [LDFlagKey: FeatureFlag]? { @@ -85,7 +88,7 @@ final class UserEnvironmentFlagCache: FeatureFlagCaching { } private func removeOldestUsersIfNeeded(from cacheableUserEnvironmentsCollection: [UserKey: CacheableUserEnvironmentFlags]) -> [UserKey: CacheableUserEnvironmentFlags] { - guard cacheableUserEnvironmentsCollection.count > Constants.maxCachedUsers + guard cacheableUserEnvironmentsCollection.count > maxCachedUsers && maxCachedUsers >= 0 else { return cacheableUserEnvironmentsCollection } @@ -93,7 +96,7 @@ final class UserEnvironmentFlagCache: FeatureFlagCaching { var userEnvironmentsCollection = cacheableUserEnvironmentsCollection.sorted { pair1, pair2 -> Bool in pair2.value.lastUpdated.isEarlierThan(pair1.value.lastUpdated) } - while userEnvironmentsCollection.count > Constants.maxCachedUsers { + while userEnvironmentsCollection.count > maxCachedUsers && maxCachedUsers >= 0 { userEnvironmentsCollection.removeLast() } return [UserKey: CacheableUserEnvironmentFlags](userEnvironmentsCollection, uniquingKeysWith: { value1, _ in diff --git a/LaunchDarkly/LaunchDarkly/Service Objects/ClientServiceFactory.swift b/LaunchDarkly/LaunchDarkly/Service Objects/ClientServiceFactory.swift index 238ead10..a7a4b244 100644 --- a/LaunchDarkly/LaunchDarkly/Service Objects/ClientServiceFactory.swift +++ b/LaunchDarkly/LaunchDarkly/Service Objects/ClientServiceFactory.swift @@ -10,8 +10,8 @@ import DarklyEventSource protocol ClientServiceCreating { func makeKeyedValueCache() -> KeyedValueCaching - func makeFeatureFlagCache() -> FeatureFlagCaching - func makeCacheConverter() -> CacheConverting + func makeFeatureFlagCache(maxCachedUsers: Int) -> FeatureFlagCaching + func makeCacheConverter(maxCachedUsers: Int) -> CacheConverting func makeDeprecatedCacheModel(_ model: DeprecatedCacheModel) -> DeprecatedCache func makeDarklyServiceProvider(config: LDConfig, user: LDUser) -> DarklyServiceProvider func makeFlagSynchronizer(streamingMode: LDStreamingMode, pollingInterval: TimeInterval, useReport: Bool, service: DarklyServiceProvider) -> LDFlagSynchronizing @@ -36,12 +36,12 @@ final class ClientServiceFactory: ClientServiceCreating { UserDefaults.standard } - func makeFeatureFlagCache() -> FeatureFlagCaching { - UserEnvironmentFlagCache(withKeyedValueCache: makeKeyedValueCache()) + func makeFeatureFlagCache(maxCachedUsers: Int) -> FeatureFlagCaching { + UserEnvironmentFlagCache(withKeyedValueCache: makeKeyedValueCache(), maxCachedUsers: maxCachedUsers) } - func makeCacheConverter() -> CacheConverting { - CacheConverter(serviceFactory: self) + func makeCacheConverter(maxCachedUsers: Int) -> CacheConverting { + CacheConverter(serviceFactory: self, maxCachedUsers: maxCachedUsers) } func makeDeprecatedCacheModel(_ model: DeprecatedCacheModel) -> DeprecatedCache { diff --git a/LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift b/LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift index 34688ac6..16c5077a 100644 --- a/LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift @@ -461,7 +461,7 @@ final class LDClientSpec: QuickSpec { expect(testContext.recordedEvent?.key) == newUser.key } it("converts cached data") { - expect(testContext.cacheConvertingMock.convertCacheDataCallCount) == 2 + expect(testContext.cacheConvertingMock.convertCacheDataCallCount) == 1 //only called once because CacheConverter is replaced during start expect(testContext.cacheConvertingMock.convertCacheDataReceivedArguments?.user) == newUser expect(testContext.cacheConvertingMock.convertCacheDataReceivedArguments?.config) == newConfig } @@ -514,7 +514,7 @@ final class LDClientSpec: QuickSpec { expect(testContext.recordedEvent?.key) == newUser.key } it("converts cached data") { - expect(testContext.cacheConvertingMock.convertCacheDataCallCount) == 2 + expect(testContext.cacheConvertingMock.convertCacheDataCallCount) == 1 //only called once because CacheConverter is replaced during start expect(testContext.cacheConvertingMock.convertCacheDataReceivedArguments?.user) == newUser expect(testContext.cacheConvertingMock.convertCacheDataReceivedArguments?.config) == newConfig } @@ -558,7 +558,7 @@ final class LDClientSpec: QuickSpec { expect(testContext.recordedEvent?.key) == testContext.user.key } it("converts cached data") { - expect(testContext.cacheConvertingMock.convertCacheDataCallCount) == 2 + expect(testContext.cacheConvertingMock.convertCacheDataCallCount) == 1 //only called once because CacheConverter is replaced during start expect(testContext.cacheConvertingMock.convertCacheDataReceivedArguments?.user) == testContext.user expect(testContext.cacheConvertingMock.convertCacheDataReceivedArguments?.config) == testContext.config } diff --git a/LaunchDarkly/LaunchDarklyTests/Mocks/ClientServiceMockFactory.swift b/LaunchDarkly/LaunchDarklyTests/Mocks/ClientServiceMockFactory.swift index 312cf61e..ebfa88db 100644 --- a/LaunchDarkly/LaunchDarklyTests/Mocks/ClientServiceMockFactory.swift +++ b/LaunchDarkly/LaunchDarklyTests/Mocks/ClientServiceMockFactory.swift @@ -16,12 +16,12 @@ final class ClientServiceMockFactory: ClientServiceCreating { var makeFeatureFlagCacheReturnValue = FeatureFlagCachingMock() var makeFeatureFlagCacheCallCount = 0 - func makeFeatureFlagCache() -> FeatureFlagCaching { + func makeFeatureFlagCache(maxCachedUsers: Int = 5) -> FeatureFlagCaching { makeFeatureFlagCacheCallCount += 1 return makeFeatureFlagCacheReturnValue } - func makeCacheConverter() -> CacheConverting { + func makeCacheConverter(maxCachedUsers: Int = 5) -> CacheConverting { return CacheConvertingMock() } diff --git a/LaunchDarkly/LaunchDarklyTests/Models/Cache/CacheableUserEnvironmentFlagsSpec.swift b/LaunchDarkly/LaunchDarklyTests/Models/Cache/CacheableUserEnvironmentFlagsSpec.swift index 99e68790..af50a751 100644 --- a/LaunchDarkly/LaunchDarklyTests/Models/Cache/CacheableUserEnvironmentFlagsSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Models/Cache/CacheableUserEnvironmentFlagsSpec.swift @@ -254,7 +254,7 @@ final class CacheableUserEnvironmentFlagsSpec: QuickSpec { describe("dictionaryValues") { context("with multiple CacheableUserEnvironments") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cacheableUserEnvironmentsCollectionDictionary = testContext.userEnvironmentFlagsCollection.dictionaryValues } @@ -286,7 +286,7 @@ final class CacheableUserEnvironmentFlagsSpec: QuickSpec { describe("makeCacheableUserEnvironmentsCollection") { context("with multiple CacheableUserEnvironments dictionaries") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cacheableUserEnvironmentsCollectionDictionary = testContext.userEnvironmentFlagsCollection.dictionaryValues cacheableUserEnvironmentsCollection = CacheableUserEnvironmentFlags.makeCollection(from: cacheableUserEnvironmentsCollectionDictionary) @@ -320,7 +320,7 @@ final class CacheableUserEnvironmentFlagsSpec: QuickSpec { var badUserKey: String! context("missing userKey") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cacheableUserEnvironmentsCollectionDictionary = testContext.userEnvironmentFlagsCollection.dictionaryValues //Create a new CacheableUserEnvironment @@ -343,7 +343,7 @@ final class CacheableUserEnvironmentFlagsSpec: QuickSpec { } context("missing environmentFlags") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cacheableUserEnvironmentsCollectionDictionary = testContext.userEnvironmentFlagsCollection.dictionaryValues //Create a new CacheableUserEnvironment @@ -369,7 +369,7 @@ final class CacheableUserEnvironmentFlagsSpec: QuickSpec { var badUserKey: String! context("type mismatched userKey") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cacheableUserEnvironmentsCollectionDictionary = testContext.userEnvironmentFlagsCollection.dictionaryValues //Create a new CacheableUserEnvironment @@ -392,7 +392,7 @@ final class CacheableUserEnvironmentFlagsSpec: QuickSpec { } context("type mismatched environmentFlags") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cacheableUserEnvironmentsCollectionDictionary = testContext.userEnvironmentFlagsCollection.dictionaryValues //Create a new CacheableUserEnvironment @@ -468,7 +468,7 @@ extension Int { extension CacheableUserEnvironmentFlags { struct Constants { static let environmentCount = 3 - static let userCount = UserEnvironmentFlagCache.Constants.maxCachedUsers + static let userCount = LDConfig.Defaults.maxCachedUsers } static func stubCollection(environmentCount: Int = Constants.environmentCount, diff --git a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/CacheConverterSpec.swift b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/CacheConverterSpec.swift index 36464e7a..fd8ff8cc 100644 --- a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/CacheConverterSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/CacheConverterSpec.swift @@ -30,9 +30,9 @@ final class CacheConverterSpec: QuickSpec { init(maxAge: TimeInterval? = nil, createCacheData: Bool = false, deprecatedCacheData: DeprecatedCacheModel? = nil) { if let maxAge = maxAge { - cacheConverter = CacheConverter(serviceFactory: clientServiceFactoryMock, maxAge: maxAge) + cacheConverter = CacheConverter(serviceFactory: clientServiceFactoryMock, maxCachedUsers: LDConfig.Defaults.maxCachedUsers, maxAge: maxAge) } else { - cacheConverter = CacheConverter(serviceFactory: clientServiceFactoryMock) + cacheConverter = CacheConverter(serviceFactory: clientServiceFactoryMock, maxCachedUsers: LDConfig.Defaults.maxCachedUsers) } expiredCacheThreshold = Date().addingTimeInterval(maxAge ?? CacheConverter.Constants.maxAge) if createCacheData { diff --git a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV2Spec.swift b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV2Spec.swift index f7645589..84bcee51 100644 --- a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV2Spec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV2Spec.swift @@ -107,7 +107,7 @@ final class DeprecatedCacheModelV2Spec: QuickSpec { context("when cached data exists") { context("and a cached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) } it("retrieves the cached data") { testContext.users.forEach { user in @@ -123,7 +123,7 @@ final class DeprecatedCacheModelV2Spec: QuickSpec { } context("and an uncached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cachedData = testContext.modelV2cache.retrieveFlags(for: testContext.uncachedUser.key, and: testContext.uncachedMobileKey) } @@ -142,7 +142,7 @@ final class DeprecatedCacheModelV2Spec: QuickSpec { describe("removeData") { context("no modelV2 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let oldestLastUpdatedDate = testContext.sortedLastUpdatedDates.first! expirationDate = oldestLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -154,7 +154,7 @@ final class DeprecatedCacheModelV2Spec: QuickSpec { } context("some modelV2 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let selectedLastUpdatedDate = testContext.sortedLastUpdatedDates[testContext.users.count / 2] expirationDate = selectedLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -172,7 +172,7 @@ final class DeprecatedCacheModelV2Spec: QuickSpec { } context("all modelV2 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) @@ -185,7 +185,7 @@ final class DeprecatedCacheModelV2Spec: QuickSpec { } context("no modelV2 cached data exists") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) testContext.keyedValueCacheMock.dictionaryReturnValue = nil //mock simulates no modelV2 cached data diff --git a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV3Spec.swift b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV3Spec.swift index 2a233a76..5ee59f1f 100644 --- a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV3Spec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV3Spec.swift @@ -107,7 +107,7 @@ final class DeprecatedCacheModelV3Spec: QuickSpec { context("when cached data exists") { context("and a cached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) } it("retrieves the cached data") { testContext.users.forEach { user in @@ -123,7 +123,7 @@ final class DeprecatedCacheModelV3Spec: QuickSpec { } context("and an uncached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cachedData = testContext.modelV3cache.retrieveFlags(for: testContext.uncachedUser.key, and: testContext.uncachedMobileKey) } @@ -142,7 +142,7 @@ final class DeprecatedCacheModelV3Spec: QuickSpec { describe("removeData") { context("no modelV3 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let oldestLastUpdatedDate = testContext.sortedLastUpdatedDates.first! expirationDate = oldestLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -154,7 +154,7 @@ final class DeprecatedCacheModelV3Spec: QuickSpec { } context("some modelV3 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let selectedLastUpdatedDate = testContext.sortedLastUpdatedDates[testContext.users.count / 2] expirationDate = selectedLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -172,7 +172,7 @@ final class DeprecatedCacheModelV3Spec: QuickSpec { } context("all modelV3 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) @@ -185,7 +185,7 @@ final class DeprecatedCacheModelV3Spec: QuickSpec { } context("no modelV3 cached data exists") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) testContext.keyedValueCacheMock.dictionaryReturnValue = nil //mock simulates no modelV3 cached data diff --git a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV4Spec.swift b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV4Spec.swift index 150675ce..daf9a623 100644 --- a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV4Spec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV4Spec.swift @@ -107,7 +107,7 @@ final class DeprecatedCacheModelV4Spec: QuickSpec { context("when cached data exists") { context("and a cached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) } it("retrieves the cached data") { testContext.users.forEach { user in @@ -123,7 +123,7 @@ final class DeprecatedCacheModelV4Spec: QuickSpec { } context("and an uncached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cachedData = testContext.modelV4cache.retrieveFlags(for: testContext.uncachedUser.key, and: testContext.uncachedMobileKey) } @@ -142,7 +142,7 @@ final class DeprecatedCacheModelV4Spec: QuickSpec { describe("removeData") { context("no modelV4 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let oldestLastUpdatedDate = testContext.sortedLastUpdatedDates.first! expirationDate = oldestLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -154,7 +154,7 @@ final class DeprecatedCacheModelV4Spec: QuickSpec { } context("some modelV4 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let selectedLastUpdatedDate = testContext.sortedLastUpdatedDates[testContext.users.count / 2] expirationDate = selectedLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -172,7 +172,7 @@ final class DeprecatedCacheModelV4Spec: QuickSpec { } context("all modelV4 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) @@ -185,7 +185,7 @@ final class DeprecatedCacheModelV4Spec: QuickSpec { } context("no modelV4 cached data exists") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) testContext.keyedValueCacheMock.dictionaryReturnValue = nil //mock simulates no modelV4 cached data diff --git a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV5Spec.swift b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV5Spec.swift index a604d370..bf0a2b2b 100644 --- a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV5Spec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV5Spec.swift @@ -120,7 +120,7 @@ final class DeprecatedCacheModelV5Spec: QuickSpec { context("when cached data exists") { context("and a cached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) } it("retrieves the cached data") { testContext.users.forEach { user in @@ -136,7 +136,7 @@ final class DeprecatedCacheModelV5Spec: QuickSpec { } context("and an uncached mobileKey is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cachedData = testContext.modelV5cache.retrieveFlags(for: testContext.users.first!.key, and: testContext.uncachedMobileKey) } @@ -147,7 +147,7 @@ final class DeprecatedCacheModelV5Spec: QuickSpec { } context("and an uncached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cachedData = testContext.modelV5cache.retrieveFlags(for: testContext.uncachedUser.key, and: testContext.mobileKeys.first!) } @@ -166,7 +166,7 @@ final class DeprecatedCacheModelV5Spec: QuickSpec { describe("removeData") { context("no modelV5 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let oldestLastUpdatedDate = testContext.sortedLastUpdatedDates.first! expirationDate = oldestLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -178,7 +178,7 @@ final class DeprecatedCacheModelV5Spec: QuickSpec { } context("some modelV5 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let selectedLastUpdatedDate = testContext.sortedLastUpdatedDates[testContext.users.count / 2] expirationDate = selectedLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -196,7 +196,7 @@ final class DeprecatedCacheModelV5Spec: QuickSpec { } context("all modelV5 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) @@ -209,7 +209,7 @@ final class DeprecatedCacheModelV5Spec: QuickSpec { } context("no modelV5 cached data exists") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) testContext.keyedValueCacheMock.dictionaryReturnValue = nil //mock simulates no modelV5 cached data diff --git a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV6Spec.swift b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV6Spec.swift index f3bbfece..8fc4e2ef 100644 --- a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV6Spec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/DeprecatedCacheModelV6Spec.swift @@ -120,7 +120,7 @@ final class DeprecatedCacheModelV6Spec: QuickSpec { context("when cached data exists") { context("and a cached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) } it("retrieves the cached data") { testContext.users.forEach { user in @@ -136,7 +136,7 @@ final class DeprecatedCacheModelV6Spec: QuickSpec { } context("and an uncached mobileKey is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cachedData = testContext.modelV6cache.retrieveFlags(for: testContext.users.first!.key, and: testContext.uncachedMobileKey) } @@ -147,7 +147,7 @@ final class DeprecatedCacheModelV6Spec: QuickSpec { } context("and an uncached user is requested") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) cachedData = testContext.modelV6cache.retrieveFlags(for: testContext.uncachedUser.key, and: testContext.mobileKeys.first!) } @@ -166,7 +166,7 @@ final class DeprecatedCacheModelV6Spec: QuickSpec { describe("removeData") { context("no modelV6 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let oldestLastUpdatedDate = testContext.sortedLastUpdatedDates.first! expirationDate = oldestLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -178,7 +178,7 @@ final class DeprecatedCacheModelV6Spec: QuickSpec { } context("some modelV6 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let selectedLastUpdatedDate = testContext.sortedLastUpdatedDates[testContext.users.count / 2] expirationDate = selectedLastUpdatedDate.lastUpdated.addingTimeInterval(-Constants.offsetInterval) @@ -196,7 +196,7 @@ final class DeprecatedCacheModelV6Spec: QuickSpec { } context("all modelV6 cached data expired") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) @@ -209,7 +209,7 @@ final class DeprecatedCacheModelV6Spec: QuickSpec { } context("no modelV6 cached data exists") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) let newestLastUpdatedDate = testContext.sortedLastUpdatedDates.last! expirationDate = newestLastUpdatedDate.lastUpdated.addingTimeInterval(Constants.offsetInterval) testContext.keyedValueCacheMock.dictionaryReturnValue = nil //mock simulates no modelV6 cached data diff --git a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/UserEnvironmentFlagCacheSpec.swift b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/UserEnvironmentFlagCacheSpec.swift index 0c728f31..500677b5 100644 --- a/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/UserEnvironmentFlagCacheSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Service Objects/Cache/UserEnvironmentFlagCacheSpec.swift @@ -53,8 +53,8 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { }.first! } - init(userCount: Int = 1) { - userEnvironmentFlagCache = UserEnvironmentFlagCache(withKeyedValueCache: keyedValueCacheMock) + init(userCount: Int = 1, maxUsers: Int = 5) { + userEnvironmentFlagCache = UserEnvironmentFlagCache(withKeyedValueCache: keyedValueCacheMock, maxCachedUsers: maxUsers) let mobileKeys: [MobileKey] (users, userEnvironmentsCollection, mobileKeys) = CacheableUserEnvironmentFlags.stubCollection(userCount: userCount) self.mobileKeys.formUnion(Set(mobileKeys)) @@ -96,7 +96,9 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { override func spec() { initSpec() retrieveFeatureFlagsSpec() - storeFeatureFlagsSpec() + storeFeatureFlagsSpec(maxUsers: LDConfig.Defaults.maxCachedUsers) + storeFeatureFlagsSpec(maxUsers: 3) + storeUnlimitedUsersSpec(maxUsers: -1) } private func initSpec() { @@ -135,7 +137,7 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { context("the user is stored") { context("and the environment is stored") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) retrievingUser = testContext.selectedUser retrievingMobileKey = testContext.selectedMobileKey @@ -147,7 +149,7 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { } context("and the environment is not stored") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) retrievingUser = testContext.selectedUser retrievingMobileKey = (CacheableUserEnvironmentFlags.Constants.environmentCount + 1).mobileKey @@ -160,7 +162,7 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { } context("the user is not stored") { beforeEach { - testContext = TestContext(userCount: UserEnvironmentFlagCache.Constants.maxCachedUsers) + testContext = TestContext(userCount: LDConfig.Defaults.maxCachedUsers) retrievingUser = LDUser.stub() retrievingMobileKey = testContext.selectedMobileKey @@ -173,8 +175,80 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { } } } + + private func storeUnlimitedUsersSpec(maxUsers: Int) { + var testContext: TestContext! + var storingUser: LDUser! + var storingMobileKey: String! + var storingLastUpdated: Date! + var userCount: Int! + var newFeatureFlags: [LDFlagKey: FeatureFlag]! + + context("and an existing user adds a new environment") { + beforeEach { + userCount = 5 + testContext = TestContext(userCount: userCount, maxUsers: maxUsers) + storingUser = testContext.selectedUser + storingMobileKey = (CacheableUserEnvironmentFlags.Constants.environmentCount + 1).mobileKey + newFeatureFlags = [Constants.newFlagKey: FeatureFlag.stub(flagKey: Constants.newFlagKey, flagValue: Constants.newFlagValue)] + storingUser.flagStore = FlagMaintainingMock(flags: newFeatureFlags) + storingLastUpdated = Date() + } + it("stores the users flags") { + FlagCachingStoreMode.allCases.forEach { (storeMode) in + testContext.storeFlags(newFeatureFlags, + forUser: storingUser, + andMobileKey: storingMobileKey, + lastUpdated: storingLastUpdated, + storeMode: storeMode) + + expect(testContext.keyedValueCacheMock.setReceivedArguments?.forKey) == UserEnvironmentFlagCache.CacheKeys.cachedUserEnvironmentFlags + + let setCachedUserEnvironmentsCollection = testContext.keyedValueCacheMock.setReceivedArguments?.value as? [UserKey: [String: Any]] + expect(setCachedUserEnvironmentsCollection?.count) == userCount + testContext.users.forEach { (user) in + expect(setCachedUserEnvironmentsCollection?.keys.contains(user.key)) == true + + let setCachedUserEnvironments = setCachedUserEnvironmentsCollection?[user.key] + expect(setCachedUserEnvironments?.userKey) == user.key + if user.key == storingUser.key { + expect(setCachedUserEnvironments?.cacheableLastUpdated) == storingLastUpdated.stringEquivalentDate + } else { + expect(setCachedUserEnvironments?.cacheableLastUpdated) == testContext.userEnvironmentsCollection.lastUpdated(forKey: user.key)?.stringEquivalentDate + } + + let setCachedEnvironmentFlagsCollection = setCachedUserEnvironments?.environmentFlags + if user.key == storingUser.key { + expect(setCachedEnvironmentFlagsCollection?.count) == CacheableUserEnvironmentFlags.Constants.environmentCount + 1 + } else { + expect(setCachedEnvironmentFlagsCollection?.count) == CacheableUserEnvironmentFlags.Constants.environmentCount + } + + var mobileKeys = [MobileKey](testContext.mobileKeys) + mobileKeys.append(storingMobileKey) + mobileKeys.forEach { (mobileKey) in + guard mobileKey != storingMobileKey || user.key == storingUser.key + else { + return + } + expect(setCachedEnvironmentFlagsCollection?.keys.contains(mobileKey)) == true + + let setCachedEnvironmentFlags = setCachedEnvironmentFlagsCollection?[mobileKey] + expect(setCachedEnvironmentFlags?.userKey) == user.key + expect(setCachedEnvironmentFlags?.mobileKey) == mobileKey + if user.key == storingUser.key && mobileKey == storingMobileKey { + expect(setCachedEnvironmentFlags?.featureFlags) == newFeatureFlags + } else { + expect(setCachedEnvironmentFlags?.featureFlags) == testContext.featureFlags(forUserKey: user.key, andMobileKey: mobileKey) + } + } + } + } + } + } + } - private func storeFeatureFlagsSpec() { + private func storeFeatureFlagsSpec(maxUsers: Int) { var testContext: TestContext! var storingUser: LDUser! var storingMobileKey: String! @@ -186,7 +260,7 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { context("when no user flags are stored") { beforeEach { userCount = 0 - testContext = TestContext(userCount: userCount) + testContext = TestContext(userCount: userCount, maxUsers: maxUsers) storingUser = LDUser.stub() storingLastUpdated = Date().addingTimeInterval(TimeInterval(days: -1)) storingMobileKey = UUID().uuidString @@ -223,8 +297,8 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { context("when less than the max number of users flags are stored") { context("and an existing users flags are changed") { beforeEach { - userCount = UserEnvironmentFlagCache.Constants.maxCachedUsers - 1 - testContext = TestContext(userCount: userCount) + userCount = maxUsers - 1 + testContext = TestContext(userCount: userCount, maxUsers: maxUsers) storingUser = testContext.selectedUser storingMobileKey = testContext.selectedMobileKey newFeatureFlags = [Constants.newFlagKey: FeatureFlag.stub(flagKey: Constants.newFlagKey, flagValue: Constants.newFlagValue)] @@ -275,8 +349,8 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { } context("and an existing user adds a new environment") { beforeEach { - userCount = UserEnvironmentFlagCache.Constants.maxCachedUsers - 1 - testContext = TestContext(userCount: userCount) + userCount = maxUsers - 1 + testContext = TestContext(userCount: userCount, maxUsers: maxUsers) storingUser = testContext.selectedUser storingMobileKey = (CacheableUserEnvironmentFlags.Constants.environmentCount + 1).mobileKey newFeatureFlags = [Constants.newFlagKey: FeatureFlag.stub(flagKey: Constants.newFlagKey, flagValue: Constants.newFlagValue)] @@ -337,8 +411,8 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { } context("and a new users flags are stored") { beforeEach { - userCount = UserEnvironmentFlagCache.Constants.maxCachedUsers - 1 - testContext = TestContext(userCount: userCount) + userCount = maxUsers - 1 + testContext = TestContext(userCount: userCount, maxUsers: maxUsers) storingUser = LDUser.stub(key: (userCount + 1).userKey) storingMobileKey = 1.mobileKey newFeatureFlags = [Constants.newFlagKey: FeatureFlag.stub(flagKey: Constants.newFlagKey, flagValue: Constants.newFlagValue)] @@ -398,8 +472,8 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { context("when max number of users flags are stored") { context("and an existing users flags are changed") { beforeEach { - userCount = UserEnvironmentFlagCache.Constants.maxCachedUsers - testContext = TestContext(userCount: userCount) + userCount = maxUsers + testContext = TestContext(userCount: userCount, maxUsers: maxUsers) storingUser = testContext.selectedUser storingMobileKey = testContext.selectedMobileKey newFeatureFlags = [Constants.newFlagKey: FeatureFlag.stub(flagKey: Constants.newFlagKey, flagValue: Constants.newFlagValue)] @@ -450,8 +524,8 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { } context("and an existing user adds a new environment") { beforeEach { - userCount = UserEnvironmentFlagCache.Constants.maxCachedUsers - testContext = TestContext(userCount: userCount) + userCount = maxUsers + testContext = TestContext(userCount: userCount, maxUsers: maxUsers) storingUser = testContext.selectedUser storingMobileKey = (CacheableUserEnvironmentFlags.Constants.environmentCount + 1).mobileKey newFeatureFlags = [Constants.newFlagKey: FeatureFlag.stub(flagKey: Constants.newFlagKey, flagValue: Constants.newFlagValue)] @@ -512,8 +586,8 @@ final class UserEnvironmentFlagCacheSpec: QuickSpec { } context("and a new users flags are stored") { beforeEach { - userCount = UserEnvironmentFlagCache.Constants.maxCachedUsers - testContext = TestContext(userCount: userCount) + userCount = maxUsers + testContext = TestContext(userCount: userCount, maxUsers: maxUsers) storingUser = LDUser.stub(key: (userCount + 1).userKey) storingMobileKey = 1.mobileKey newFeatureFlags = [Constants.newFlagKey: FeatureFlag.stub(flagKey: Constants.newFlagKey, flagValue: Constants.newFlagValue)]