Skip to content

Commit 236d76d

Browse files
authored
[FSSDK-6907]: Adds a check to only save valid datafile in cache. (#514)
* Adding check to only save datafile in cache if valid.
1 parent ccda0bd commit 236d76d

File tree

5 files changed

+92
-21
lines changed

5 files changed

+92
-21
lines changed

Sources/Customization/DefaultDatafileHandler.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2019-2022, Optimizely, Inc. and contributors
2+
// Copyright 2019-2023, Optimizely, Inc. and contributors
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -158,12 +158,18 @@ open class DefaultDatafileHandler: OPTDatafileHandler {
158158
open func getResponseData(sdkKey: String, response: HTTPURLResponse, url: URL?) -> Data? {
159159
if let url = url, let data = try? Data(contentsOf: url) {
160160
self.logger.d { String(data: data, encoding: .utf8) ?? "" }
161-
self.saveDatafile(sdkKey: sdkKey, dataFile: data)
162-
if let lastModified = response.getLastModified() {
163-
self.sharedDataStore.setLastModified(sdkKey: sdkKey, lastModified: lastModified)
161+
// Check datafile is valid json
162+
do {
163+
// Try deserializing datafile, isValidJSONObject is not applicable here
164+
_ = try JSONSerialization.jsonObject(with: data)
165+
self.saveDatafile(sdkKey: sdkKey, dataFile: data)
166+
if let lastModified = response.getLastModified() {
167+
self.sharedDataStore.setLastModified(sdkKey: sdkKey, lastModified: lastModified)
168+
}
169+
return data
170+
} catch {
171+
self.logger.w("Error deserializing datafile: \(error.localizedDescription)")
164172
}
165-
166-
return data
167173
}
168174

169175
return nil

Tests/OptimizelyTests-Common/DatafileHandlerTests.swift

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2019, 2021, Optimizely, Inc. and contributors
2+
// Copyright 2019, 2021, 2023, Optimizely, Inc. and contributors
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -65,7 +65,65 @@ class DatafileHandlerTests: XCTestCase {
6565
// This is an example of a functional test case.
6666
// Use XCTAssert and related functions to verify your tests produce the correct results.
6767
}
68+
69+
func testDatafileDownloadWith200AndValidDatafile() {
70+
// Datafile and last updated should not be saved in this case
71+
let handler = MockDatafileHandler(statusCode: 200, localResponseData:"{}")
72+
let expectation = XCTestExpectation(description: "no-nil data")
73+
74+
handler.downloadDatafile(sdkKey: sdkKey) { (result) in
75+
if case let .success(data) = result {
76+
XCTAssert(data != nil)
77+
expectation.fulfill()
78+
}
79+
}
80+
81+
wait(for: [expectation], timeout: 3)
82+
XCTAssertTrue(handler.isDatafileSaved(sdkKey: sdkKey))
83+
XCTAssertNotNil(handler.sharedDataStore.getLastModified(sdkKey: sdkKey))
84+
}
85+
6886

87+
func testDatafileDownloadWith200AndInvalidDatafile() {
88+
// Datafile and last updated should not be saved in this case
89+
let handler = MockDatafileHandler(statusCode: 200, localResponseData: "1231")
90+
let expectation = XCTestExpectation(description: "wait to get failure")
91+
92+
handler.downloadDatafile(sdkKey: sdkKey) { (result) in
93+
if case .success(_) = result {
94+
XCTFail()
95+
}
96+
if case .failure(_) = result {
97+
expectation.fulfill()
98+
}
99+
}
100+
101+
wait(for: [expectation], timeout: 3)
102+
XCTAssertFalse(handler.isDatafileSaved(sdkKey: sdkKey))
103+
XCTAssertNil(handler.sharedDataStore.getLastModified(sdkKey: sdkKey))
104+
}
105+
106+
func testStartWith200AndInvalidDatafile() {
107+
let handler = MockDatafileHandler(statusCode: 200, localResponseData: "1231")
108+
let expectation = XCTestExpectation(description: "wait to get failure")
109+
110+
let optimizely = OptimizelyClient(sdkKey: sdkKey,
111+
datafileHandler: handler,
112+
periodicDownloadInterval: 1)
113+
114+
optimizely.start(completion: { result in
115+
if case let .failure(error) = result {
116+
print(error)
117+
XCTAssert(true)
118+
expectation.fulfill()
119+
}
120+
})
121+
122+
wait(for: [expectation], timeout: 3)
123+
XCTAssertFalse(handler.isDatafileSaved(sdkKey: sdkKey))
124+
XCTAssertNil(handler.sharedDataStore.getLastModified(sdkKey: sdkKey))
125+
}
126+
69127
func testDatafileDownload500() {
70128
OTUtils.createDatafileCache(sdkKey: sdkKey)
71129

@@ -184,7 +242,7 @@ class DatafileHandlerTests: XCTestCase {
184242

185243
func testPeriodicDownload() {
186244
let expection = XCTestExpectation(description: "Expect 10 periodic downloads")
187-
let handler = MockDatafileHandler(statusCode: 200)
245+
let handler = MockDatafileHandler(statusCode: 200, localResponseData: "{}")
188246
let now = Date()
189247
var count = 0
190248
var seconds = 0
@@ -205,7 +263,7 @@ class DatafileHandlerTests: XCTestCase {
205263

206264
func testPeriodicDownload_PollingShouldNotBeAccumulatedWhileInBackground() {
207265
let expectation = XCTestExpectation(description: "polling")
208-
let handler = MockDatafileHandler(statusCode: 200)
266+
let handler = MockDatafileHandler(statusCode: 200, localResponseData: "{}")
209267
let now = Date()
210268

211269
let updateInterval = 1
@@ -336,7 +394,7 @@ class DatafileHandlerTests: XCTestCase {
336394
// will return 500
337395
return MockUrlSession(withError: true)
338396
} else {
339-
return MockUrlSession(statusCode: 200)
397+
return MockUrlSession(statusCode: 200, localResponseData: "{}")
340398
}
341399
}
342400
}

Tests/OptimizelyTests-Common/NetworkReachabilityTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2021, Optimizely, Inc. and contributors
2+
// Copyright 2021, 2023 Optimizely, Inc. and contributors
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -119,7 +119,7 @@ class NetworkReachabilityTests: XCTestCase {
119119
}
120120

121121
func testFetchDatafile_numContiguousFails() {
122-
let handler = MockDatafileHandler(withError: true)
122+
let handler = MockDatafileHandler(withError: true, localResponseData: "{}")
123123
let reachability = handler.reachability
124124

125125
var exp = expectation(description: "r")
@@ -164,7 +164,7 @@ class NetworkReachabilityTests: XCTestCase {
164164
}
165165

166166
func testFetchDatafile_checkReachability() {
167-
let handler = MockDatafileHandler(withError: true)
167+
let handler = MockDatafileHandler(withError: true, localResponseData: "{}")
168168
let reachability = handler.reachability
169169

170170
reachability.stop()
@@ -196,7 +196,7 @@ class NetworkReachabilityTests: XCTestCase {
196196

197197
// no valid datafile cache
198198

199-
let handler = MockDatafileHandler(withError: true)
199+
let handler = MockDatafileHandler(withError: true, localResponseData: "{}")
200200
let reachability = handler.reachability
201201

202202
reachability.stop()

Tests/OptimizelyTests-MultiClients/DatafileHandlerTests_MultiClients.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2021, Optimizely, Inc. and contributors
2+
// Copyright 2021, 2023, Optimizely, Inc. and contributors
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@ class DatafileHandlerTests_MultiClients: XCTestCase {
3939

4040
func testConcurrentDownloadDatafiles() {
4141
// use a shared DatafileHandler instance
42-
let mockHandler = MockDatafileHandler(statusCode: 200)
42+
let mockHandler = MockDatafileHandler(statusCode: 200, localResponseData: "{}")
4343

4444
sdkKeys = OTUtils.makeRandomSdkKeys(100)
4545

@@ -153,7 +153,7 @@ class DatafileHandlerTests_MultiClients: XCTestCase {
153153

154154
func testConcurrentAccessLastModified() {
155155
// use a shared DatafileHandler instance
156-
let mockHandler = MockDatafileHandler(statusCode: 200)
156+
let mockHandler = MockDatafileHandler(statusCode: 200, localResponseData: "{}")
157157

158158
sdkKeys = OTUtils.makeRandomSdkKeys(100)
159159

@@ -241,7 +241,7 @@ class DatafileHandlerTests_MultiClients: XCTestCase {
241241
}
242242

243243
// use a shared DatafileHandler instance
244-
let mockHandler = MockDatafileHandler(statusCode: 200)
244+
let mockHandler = MockDatafileHandler(statusCode: 200, localResponseData: "{}")
245245

246246
let numSdks = 50
247247
sdkKeys = OTUtils.makeRandomSdkKeys(numSdks)

Tests/TestUtils/MockUrlSession.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class MockUrlSession: URLSession {
2828
var localResponseData: String?
2929
var settingsMap: [String: (Int, Bool)]?
3030
var handler: MockDatafileHandler?
31+
let lock = DispatchQueue(label: "mock-session-lock")
3132

3233
class MockDownloadTask: URLSessionDownloadTask {
3334
var task: () -> Void
@@ -54,15 +55,19 @@ class MockUrlSession: URLSession {
5455
}
5556

5657
init(handler: MockDatafileHandler? = nil, statusCode: Int = 0, withError: Bool = false, localResponseData: String? = nil) {
57-
Self.validSessions += 1
58+
lock.async {
59+
Self.validSessions += 1
60+
}
5861
self.handler = handler
5962
self.statusCode = statusCode
6063
self.withError = withError
6164
self.localResponseData = localResponseData
6265
}
6366

6467
init(handler: MockDatafileHandler? = nil, settingsMap: [String: (Int, Bool)]) {
65-
Self.validSessions += 1
68+
lock.async {
69+
Self.validSessions += 1
70+
}
6671
self.handler = handler
6772
self.statusCode = 0
6873
self.withError = false
@@ -113,6 +118,8 @@ class MockUrlSession: URLSession {
113118
}
114119

115120
override func finishTasksAndInvalidate() {
116-
Self.validSessions -= 1
121+
lock.async {
122+
Self.validSessions -= 1
123+
}
117124
}
118125
}

0 commit comments

Comments
 (0)