Skip to content

Commit

Permalink
Bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
configcat-developer committed Oct 13, 2018
1 parent e97b8db commit 77714ff
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 33 deletions.
2 changes: 1 addition & 1 deletion ConfigCat.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |spec|

spec.name = "ConfigCat"
spec.version = "2.0.0"
spec.version = "2.1.0"
spec.summary = "ConfigCat Swift SDK"
spec.swift_version = "4.2"

Expand Down
2 changes: 1 addition & 1 deletion Sources/AsyncResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public class Async {
public final class AsyncResult<Value> : Async {
fileprivate var result: Value?

override init() {
public override init() {
super.init()
}

Expand Down
12 changes: 9 additions & 3 deletions Sources/ConfigCatClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public final class ConfigCatClient : ConfigCatClientProtocol {
? try self.refreshPolicy.getConfiguration().get()
: try self.refreshPolicy.getConfiguration().get(timeout: self.maxWaitTimeForSyncCallsInSeconds)

return self.deserializeJson(for: key, json: config, defaultValue: defaultValue, user: user)
return try ConfigCatClient.parser.parseValue(for: key, json: config,user: user)
} catch {
os_log("An error occurred during reading the configuration. %@", log: ConfigCatClient.log, type: .error, error.localizedDescription)
return self.getDefaultConfig(for: key, defaultValue: defaultValue, user: user)
Expand All @@ -66,8 +66,14 @@ public final class ConfigCatClient : ConfigCatClientProtocol {

self.refreshPolicy.getConfiguration()
.apply { config in
let result = self.deserializeJson(for: key, json: config, defaultValue: defaultValue, user: user)
completion(result)
do {
let result: Value = try ConfigCatClient.parser.parseValue(for: key, json: config, user: user)
completion(result)
} catch {
os_log("An error occurred during deserializaton. %@", log: ConfigCatClient.log, type: .error, error.localizedDescription)
let result = self.getDefaultConfig(for: key, defaultValue: defaultValue, user: user)
completion(result)
}
}
}

Expand Down
63 changes: 42 additions & 21 deletions Sources/ExpiringCachePolicy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public final class ExpiringCachePolicy : RefreshPolicy {
fileprivate let initialized = Synced<Bool>(initValue: false)
fileprivate let isFetching = Synced<Bool>(initValue: false)
fileprivate var fetching = AsyncResult<String>()
fileprivate let initAsync = Async()

/**
Initializes a new `ExpiringCachePolicy`.
Expand Down Expand Up @@ -41,39 +42,59 @@ public final class ExpiringCachePolicy : RefreshPolicy {

public override func getConfiguration() -> AsyncResult<String> {
if self.lastRefreshTime.timeIntervalSinceNow < -self.cacheRefreshIntervalInSeconds {
if !self.isFetching.testAndSet(expect: false, new: true) {
let initialized = self.initAsync.completed
if initialized && !self.isFetching.testAndSet(expect: false, new: true) {
return self.useAsyncRefresh
? self.readCache()
: self.fetching
}

os_log("Cache expired, refreshing", log: ExpiringCachePolicy.log, type: .debug)
self.fetching = self.fetcher.getConfigurationJson()
.apply(completion: { response in
let cached = super.cache.get()
if response.isFetched() && response.body != cached {
super.cache.set(value: response.body)
self.isFetching.set(new: false)
self.initialized.set(new: true)
}

if !response.isFailed() {
self.lastRefreshTime = Date()
}

return response.isFetched()
? response.body
: cached
if(initialized) {
self.fetching = self.fetch()
if(self.useAsyncRefresh) {
return self.readCache()
}
return self.fetching
} else {
if(self.isFetching.testAndSet(expect: false, new: true)) {
self.fetching = self.fetch()
}
return self.initAsync.apply(completion: {
return self.cache.get()
})

return self.useAsyncRefresh && self.initialized.get()
? self.readCache()
: self.fetching;
}
}

return self.readCache()
}

private func fetch() -> AsyncResult<String> {
return self.fetcher.getConfigurationJson()
.apply(completion: { response in
let cached = super.cache.get()
if response.isFetched() && response.body != cached {
super.cache.set(value: response.body)
}

if !response.isFailed() {
self.lastRefreshTime = Date()
}

if(self.initialized.testAndSet(expect: false, new: true)) {
self.initAsync.complete()
}

if(response.isFetched()) {
self.isFetching.set(new: false)
}

return response.isFetched()
? response.body
: cached
})
}

private func readCache() -> AsyncResult<String> {
os_log("Reading from cache", log: ExpiringCachePolicy.log, type: .debug)
return AsyncResult<String>.completed(result: self.cache.get())
Expand Down
37 changes: 37 additions & 0 deletions Tests/ConfigCatClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ class ConfigCatClientTests: XCTestCase {
XCTAssertEqual(10, config)
}

func testGetIntValueFailedInvalidJson() {
mockSession.enqueueResponse(response: Response(body: "", statusCode: 200))
let client = self.createClient()
let config = client.getValue(for: "fakeKey", defaultValue: 10)

XCTAssertEqual(10, config)
}

func testGetStringValue() {
mockSession.enqueueResponse(response: Response(body: String(format: self.testJsonFormat, "\"fake\""), statusCode: 200))
let client = self.createClient()
Expand Down Expand Up @@ -82,6 +90,35 @@ class ConfigCatClientTests: XCTestCase {
XCTAssertEqual(Float(55), config)
}

func testGetLatestOnFail() {
mockSession.enqueueResponse(response: Response(body: String(format: self.testJsonFormat, "55"), statusCode: 200))
mockSession.enqueueResponse(response: Response(body: "", statusCode: 500))
let client = self.createClient()
var config = client.getValue(for: "fakeKey", defaultValue: 0)
XCTAssertEqual(55, config)
config = client.getValue(for: "fakeKey", defaultValue: 0)
XCTAssertEqual(55, config)
}

func testGetLatestOnFailAsync() {
mockSession.enqueueResponse(response: Response(body: String(format: self.testJsonFormat, "55"), statusCode: 200))
mockSession.enqueueResponse(response: Response(body: "", statusCode: 500))
let client = self.createClient()
let config = AsyncResult<Int>()
client.getValueAsync(for: "fakeKey", defaultValue: 0) { (result) in
config.complete(result: result)
}

XCTAssertEqual(55, try config.get())

let config2 = AsyncResult<Int>()
client.getValueAsync(for: "fakeKey", defaultValue: 0) { (result) in
config2.complete(result: result)
}

XCTAssertEqual(55, try config2.get())
}

func testForceRefresh() {
mockSession.enqueueResponse(response: Response(body: String(format: self.testJsonFormat, "\"test\""), statusCode: 200))
mockSession.enqueueResponse(response: Response(body: String(format: self.testJsonFormat, "\"test2\""), statusCode: 200))
Expand Down
7 changes: 0 additions & 7 deletions Tests/RolloutIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,6 @@ class RolloutIntegrationTests: XCTestCase {
XCTAssertEqual(0, errors.count)
return
}

func stringFromAny(_ value:Any?) -> String {
if let nonNil = value, !(nonNil is NSNull) {
return String(describing: nonNil)
}
return ""
}
}

extension Array {
Expand Down

0 comments on commit 77714ff

Please sign in to comment.