Skip to content

Commit

Permalink
RolloutCacheManager test coverage (#607)
Browse files Browse the repository at this point in the history
  • Loading branch information
gthea committed Jan 27, 2025
1 parent 04f456f commit afee1de
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 7 deletions.
4 changes: 4 additions & 0 deletions Split.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,7 @@
C5E967572D38013000112DAC /* GeneralInfoStorageMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5E967562D38013000112DAC /* GeneralInfoStorageMock.swift */; };
C5E9675F2D3849BE00112DAC /* RolloutDefinitionsCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5E9675E2D3849BE00112DAC /* RolloutDefinitionsCache.swift */; };
C5E967602D3849BE00112DAC /* RolloutDefinitionsCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5E9675E2D3849BE00112DAC /* RolloutDefinitionsCache.swift */; };
C5E967622D395DAA00112DAC /* RolloutCacheManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5E967612D395DAA00112DAC /* RolloutCacheManagerTest.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -1944,6 +1945,7 @@
C5E967542D37FDD500112DAC /* RolloutCacheConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RolloutCacheConfigurationTest.swift; sourceTree = "<group>"; };
C5E967562D38013000112DAC /* GeneralInfoStorageMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralInfoStorageMock.swift; sourceTree = "<group>"; };
C5E9675E2D3849BE00112DAC /* RolloutDefinitionsCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RolloutDefinitionsCache.swift; sourceTree = "<group>"; };
C5E967612D395DAA00112DAC /* RolloutCacheManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RolloutCacheManagerTest.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -3385,6 +3387,7 @@
95ABF4B9293003C1006ED016 /* ConfigTest.swift */,
95B0A99F2BC6B72200C31A9E /* SplitClientTests.swift */,
C5E967542D37FDD500112DAC /* RolloutCacheConfigurationTest.swift */,
C5E967612D395DAA00112DAC /* RolloutCacheManagerTest.swift */,
);
path = Init;
sourceTree = "<group>";
Expand Down Expand Up @@ -4339,6 +4342,7 @@
954F9B072570309400140B81 /* SplitDaoTest.swift in Sources */,
95F20F4A27EB533000B5B30A /* TreatmentManagerTest.swift in Sources */,
59F4AAA324FFCD5000A1C69A /* SyncEventBroadcasterStub.swift in Sources */,
C5E967622D395DAA00112DAC /* RolloutCacheManagerTest.swift in Sources */,
95ABF4C029314D3D006ED016 /* ImpressionsStorageTest.swift in Sources */,
5921ED3125378ECD000D6C8B /* StreamingInitTest.swift in Sources */,
95C717DE268CE137002ADB83 /* ImpressionsCountDaoStub.swift in Sources */,
Expand Down
12 changes: 11 additions & 1 deletion SplitTests/DatesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import Foundation
import XCTest

//@testable import Split
@testable import Split

class DatesTest: XCTestCase {

Expand Down Expand Up @@ -47,4 +47,14 @@ class DatesTest: XCTestCase {

return calendar.date(from: dateComponents)!
}

func testSecondsToDays() {
let seconds: Int64 = 86400
let days = Date.secondsToDays(seconds: seconds)
XCTAssertEqual(days, 1, "1 day should be the result")

let seconds2: Int64 = 172800
let days2 = Date.secondsToDays(seconds: seconds2)
XCTAssertEqual(days2, 2, "2 days should be the result")
}
}
9 changes: 7 additions & 2 deletions SplitTests/Fake/Storage/MySegmentsStorageStub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,14 @@ class MySegmentsStorageStub: MySegmentsStorage {
return count
}

var clearCalled = false
var clearCalledTimes = 0
var clearCalled: Bool {
get {
return clearCalledTimes > 0
}
}
func clear() {
clearCalled = true
clearCalledTimes+=1
segments.removeAll()
}
}
9 changes: 7 additions & 2 deletions SplitTests/Fake/Storage/SplitsStorageStub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ class SplitsStorageStub: SplitsStorage {
var flagsSpec: String = ""

var loadLocalCalled = false
var clearCalled = false
var clearCalledTimes = 0
var clearCalled: Bool {
get {
return clearCalledTimes > 0
}
}

var updatedWithoutChecksSplit: Split?
var updatedWithoutChecksExp: XCTestExpectation?
Expand Down Expand Up @@ -92,7 +97,7 @@ class SplitsStorageStub: SplitsStorage {
}

func clear() {
clearCalled = true
clearCalledTimes+=1
inMemorySplits.removeAll()
}

Expand Down
142 changes: 142 additions & 0 deletions SplitTests/Init/RolloutCacheManagerTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import XCTest
@testable import Split

final class RolloutCacheManagerTest: XCTestCase {

private var rolloutCacheManager: RolloutCacheManager!
private var splitsStorage: SplitsStorageStub!
private var segmentsStorage: MySegmentsStorageStub!
private var generalInfoStorage: GeneralInfoStorageMock!

override func setUpWithError() throws {
splitsStorage = SplitsStorageStub()
segmentsStorage = MySegmentsStorageStub()
generalInfoStorage = GeneralInfoStorageMock()
}

func testValidateCacheCallsListener() throws {
rolloutCacheManager = getCacheManager(expiration: 10)

let result = validateCache()

XCTAssertTrue(result)
}

func testValidateCacheCallsClearOnStoragesWhenExpirationIsSurpassed() throws {
rolloutCacheManager = getCacheManager(expiration: 9)
generalInfoStorage.setUpdateTimestamp(timestamp: getTimestamp(plusDays: -10))

let result = validateCache()

XCTAssertTrue(result)
XCTAssertTrue(splitsStorage.clearCalled)
XCTAssertTrue(segmentsStorage.clearCalled)
}

func testValidateCacheDoesNotCallClearOnStoragesWhenExpirationIsNotSurpassedAndClearOnInitIsFalse() throws {
rolloutCacheManager = getCacheManager(expiration: 10)
generalInfoStorage.setUpdateTimestamp(timestamp: getTimestamp(plusDays: -1))

let result = validateCache()

XCTAssertTrue(result)
XCTAssertFalse(splitsStorage.clearCalled)
XCTAssertFalse(segmentsStorage.clearCalled)
}

func testValidateCacheCallsClearOnStoragesWhenExpirationIsNotSurpassedAndClearOnInitIsTrue() throws {
rolloutCacheManager = getCacheManager(expiration: 10, clearOnInit: true)
generalInfoStorage.setUpdateTimestamp(timestamp: getTimestamp(plusDays: -1))

let result = validateCache()

XCTAssertTrue(result)
XCTAssertTrue(splitsStorage.clearCalled)
XCTAssertTrue(segmentsStorage.clearCalled)
}

func testValidateCacheCallsClearOnStorageOnlyOnceWhenExecutedConsecutively() throws {
rolloutCacheManager = getCacheManager(expiration: 10, clearOnInit: true)
generalInfoStorage.setUpdateTimestamp(timestamp: getTimestamp(plusDays: -1))

let clearCalledTimes = segmentsStorage.clearCalledTimes
let result = validateCache()
let result2 = validateCache()

XCTAssertTrue(result)
XCTAssertTrue(result2)
XCTAssertEqual(clearCalledTimes, 0)
XCTAssertEqual(splitsStorage.clearCalledTimes, 1)
XCTAssertEqual(segmentsStorage.clearCalledTimes, 1)
}

func testValidateCacheUpdatesLastClearTimestampWhenStoragesAreCleared() throws {
rolloutCacheManager = getCacheManager(expiration: 10, clearOnInit: true)
generalInfoStorage.setUpdateTimestamp(timestamp: getTimestamp(plusDays: -1))
let initialLastClearTimestamp = generalInfoStorage.getRolloutCacheLastClearTimestamp()

let result = validateCache()

XCTAssertTrue(result)
XCTAssertEqual(splitsStorage.clearCalledTimes, 1)
XCTAssertEqual(segmentsStorage.clearCalledTimes, 1)
XCTAssertGreaterThan(generalInfoStorage.getRolloutCacheLastClearTimestamp(), initialLastClearTimestamp)
}

func testValidateCacheDoesNotUpdateLastClearTimestampWhenStoragesAreNotCleared() throws {
rolloutCacheManager = getCacheManager(expiration: 10)
let updateTimestamp = getTimestamp(plusDays: -1)
generalInfoStorage.setUpdateTimestamp(timestamp: updateTimestamp)
generalInfoStorage.rolloutCacheLastClearTimestamp = 123456

let result = validateCache()

XCTAssertTrue(result)
XCTAssertFalse(splitsStorage.clearCalled)
XCTAssertFalse(segmentsStorage.clearCalled)
XCTAssertEqual(generalInfoStorage.getRolloutCacheLastClearTimestamp(), 123456)
}

func testDefaultValueForUpdateTimestampDoesNotClearCache() throws {
rolloutCacheManager = getCacheManager(expiration: 10)
let result = validateCache()

XCTAssertTrue(result)
XCTAssertFalse(splitsStorage.clearCalled)
XCTAssertFalse(segmentsStorage.clearCalled)
}

func testDefaultValueForLastClearTimestampClearsCacheWhenClearOnInitIsTrue() throws {
rolloutCacheManager = getCacheManager(expiration: 10, clearOnInit: true)
let result = validateCache()

XCTAssertTrue(result)
XCTAssertEqual(splitsStorage.clearCalledTimes, 1)
XCTAssertEqual(segmentsStorage.clearCalledTimes, 1)
}

private func getCacheManager(expiration: Int, clearOnInit: Bool = false) -> RolloutCacheManager {
return DefaultRolloutCacheManager(
generalInfoStorage: generalInfoStorage,
rolloutCacheConfiguration: RolloutCacheConfiguration.builder()
.set(expirationDays: expiration)
.set(clearOnInit: clearOnInit)
.build(),
storages: splitsStorage, segmentsStorage)
}

private func getTimestamp(plusDays: Int) -> Int64 {
return Date.now() + Int64(plusDays * 86400)
}

/// Runs validate cache and waits for it to finish
/// Returns true if it was successful
private func validateCache() -> Bool {
let latch = DispatchSemaphore(value: 0)
rolloutCacheManager.validateCache {
latch.signal()
}

return latch.wait(timeout: DispatchTime.now() + 5) == .success
}
}
33 changes: 33 additions & 0 deletions SplitTests/Storage/MyLargeSegmentsStorageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,37 @@ class MyLargeSegmentsStorageTests: XCTestCase {
XCTAssertEqual(100, cn1)
XCTAssertEqual(200, cn2)
}

func testClearAll() {
let otherKey = "otherKey"
persistentStorage.persistedSegments = [userKey : dummyChange,
otherKey: SegmentChange(segments: ["s1"], changeNumber: 44)
]
mySegmentsStorage.loadLocal(forKey: userKey)
mySegmentsStorage.loadLocal(forKey: otherKey)

let changeNum = mySegmentsStorage.changeNumber(forKey: userKey)
let segments = mySegmentsStorage.getAll(forKey: userKey)
let otherChangeNum = mySegmentsStorage.changeNumber(forKey: otherKey)
let otherSegments = mySegmentsStorage.getAll(forKey: otherKey)

mySegmentsStorage.clear()

let newChangeNum = mySegmentsStorage.changeNumber(forKey: userKey)
let newSegments = mySegmentsStorage.getAll(forKey: userKey)
let newOtherChangeNum = mySegmentsStorage.changeNumber(forKey: otherKey)
let newOtherSegments = mySegmentsStorage.getAll(forKey: otherKey)

XCTAssertEqual(100, changeNum)
XCTAssertEqual(3, segments.count)
XCTAssertTrue(segments.contains("s1"))
XCTAssertTrue(segments.contains("s3"))
XCTAssertEqual(44, otherChangeNum)
XCTAssertEqual(1, otherSegments.count)
XCTAssertTrue(otherSegments.contains("s1"))
XCTAssertEqual(newChangeNum, -1)
XCTAssertEqual(newSegments.count, 0)
XCTAssertEqual(newOtherChangeNum, -1)
XCTAssertEqual(newOtherSegments.count, 0)
}
}
21 changes: 20 additions & 1 deletion SplitTests/Storage/MySegmentsDaoTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,26 @@ class MySegmentsDaoTest: XCTestCase {

XCTAssertNotEqual(userKey, segment.userKey)
XCTAssertFalse(segment.segmentList?.contains("s1") ?? true)
}
}

func testDeleteAll() {
let helper = IntegrationCoreDataHelper.get(databaseName: "test",
dispatchQueue: DispatchQueue(label: "impression dao test"))
mySegmentsDao = CoreDataMySegmentsDao(coreDataHelper: helper,
entity: .mySegment)
let userKey = "ukey"
let change = SegmentChange(segments: ["s1", "s2"])
mySegmentsDao.update(userKey: userKey, change: change)

let initialResultFromDB = mySegmentsDao.getBy(userKey: userKey)

mySegmentsDao.deleteAll()

let finalResultFromDB = mySegmentsDao.getBy(userKey: userKey)

XCTAssertEqual(2, initialResultFromDB?.segments.count)
XCTAssertNil(finalResultFromDB)
}

func getBy(userKey: String, coreDataHelper: CoreDataHelper) -> (userKey: String?, segmentList: String?) {
var loadedUserKey: String? = nil
Expand Down
34 changes: 33 additions & 1 deletion SplitTests/Storage/MySegmentsStorageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,39 @@ class MySegmentsStorageTests: XCTestCase {

XCTAssertEqual(-1, cn1)
XCTAssertEqual(-1, cn2)

}

func testClearAll() {
let otherKey = "otherKey"
persistentStorage.persistedSegments = [userKey : dummySegments,
otherKey: SegmentChange(segments: ["s1"], changeNumber: 44)
]
mySegmentsStorage.loadLocal(forKey: userKey)
mySegmentsStorage.loadLocal(forKey: otherKey)

let changeNum = mySegmentsStorage.changeNumber(forKey: userKey)
let segments = mySegmentsStorage.getAll(forKey: userKey)
let otherChangeNum = mySegmentsStorage.changeNumber(forKey: otherKey)
let otherSegments = mySegmentsStorage.getAll(forKey: otherKey)

mySegmentsStorage.clear()

let newChangeNum = mySegmentsStorage.changeNumber(forKey: userKey)
let newSegments = mySegmentsStorage.getAll(forKey: userKey)
let newOtherChangeNum = mySegmentsStorage.changeNumber(forKey: otherKey)
let newOtherSegments = mySegmentsStorage.getAll(forKey: otherKey)

// for now, CN is always -1 for regular my segments
XCTAssertEqual(-1, changeNum)
XCTAssertEqual(3, segments.count)
XCTAssertTrue(segments.contains("s1"))
XCTAssertTrue(segments.contains("s3"))
XCTAssertEqual(-1, otherChangeNum)
XCTAssertEqual(1, otherSegments.count)
XCTAssertTrue(otherSegments.contains("s1"))
XCTAssertEqual(newChangeNum, -1)
XCTAssertEqual(newSegments.count, 0)
XCTAssertEqual(newOtherChangeNum, -1)
XCTAssertEqual(newOtherSegments.count, 0)
}
}
8 changes: 8 additions & 0 deletions SplitTests/Storage/PersistentMySegmentsStorageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,13 @@ class PersistentMySegmentsStorageTests: XCTestCase {

XCTAssertNil(segments?.segments.count)
}

func testDeleteAllCallsDeleteAllOnDao() {
let initialDeleteAllCalled = mySegmentsDao.deleteAllCalled
mySegmentsStorage.deleteAll()
let finalDeleteAllCalled = mySegmentsDao.deleteAllCalled
XCTAssertFalse(initialDeleteAllCalled)
XCTAssertTrue(finalDeleteAllCalled)
}
}

0 comments on commit afee1de

Please sign in to comment.