From 63fa49884823dc775a468d440e1072f5274f478f Mon Sep 17 00:00:00 2001 From: Fabrizio Demaria Date: Fri, 12 Jan 2024 11:51:00 +0100 Subject: [PATCH] fix: [TMP] Try fix flaky tests, part 2 Signed-off-by: Fabrizio Demaria --- .../Apply/FlagApplierWithRetries.swift | 45 +++++++------------ .../ConfidenceProvider/Http/HttpClient.swift | 4 +- .../Http/NetworkClient.swift | 32 ++++++------- .../CacheDataInteractorTests.swift | 20 ++++----- .../Helpers/HttpClientMock.swift | 8 ++-- 5 files changed, 46 insertions(+), 63 deletions(-) diff --git a/Sources/ConfidenceProvider/Apply/FlagApplierWithRetries.swift b/Sources/ConfidenceProvider/Apply/FlagApplierWithRetries.swift index 17fca728..b6dbb173 100644 --- a/Sources/ConfidenceProvider/Apply/FlagApplierWithRetries.swift +++ b/Sources/ConfidenceProvider/Apply/FlagApplierWithRetries.swift @@ -57,7 +57,7 @@ final class FlagApplierWithRetries: FlagApplier { private func triggerBatch() async { async let cacheData = await cacheDataInteractor.cache - await cacheData.resolveEvents.async { resolveEvent in + await cacheData.resolveEvents.asyncForEach { resolveEvent in let appliesToSend = resolveEvent.events.filter { $0.status == .created } .chunk(size: 20) @@ -65,13 +65,7 @@ final class FlagApplierWithRetries: FlagApplier { return } - let a = resolveEvent.events.count - let b = resolveEvent.events.filter { $0.status == .created }.count - if (a != b) { - print("JAHA") - } - - await appliesToSend.async { chunk in + await appliesToSend.asyncForEach { chunk in await self.writeStatus(resolveToken: resolveEvent.resolveToken, events: chunk, status: .sending) await executeApply( resolveToken: resolveEvent.resolveToken, @@ -90,8 +84,7 @@ final class FlagApplierWithRetries: FlagApplier { private func writeStatus(resolveToken: String, events: [FlagApply], status: ApplyEventStatus) async { let lastIndex = events.count - 1 - await events.enumerated().async { index, event in - print("<< Setting Status \(status) to \(event.name)") + await events.enumerated().asyncForEach { index, event in var data = await self.cacheDataInteractor.setEventStatus( resolveToken: resolveToken, name: event.name, @@ -131,27 +124,25 @@ final class FlagApplierWithRetries: FlagApplier { sdk: Sdk(id: metadata.name, version: metadata.version) ) - performRequest(request: request) { result in - Task { - switch result { - case .success: - await completion(true) - case .failure(let error): - self.logApplyError(error: error) - await completion(false) - } + await performRequest(request: request) { result in + switch result { + case .success: + await completion(true) + case .failure(let error): + self.logApplyError(error: error) + await completion(false) } } } private func performRequest( request: ApplyFlagsRequest, - completion: @escaping (ApplyFlagResult) -> Void - ) { + completion: @escaping (ApplyFlagResult) async -> Void + ) async { do { - try httpClient.post(path: ":apply", data: request, completion: completion) + try await httpClient.post(path: ":apply", data: request, completion: completion) } catch { - completion(.failure(handleError(error: error))) + await completion(.failure(handleError(error: error))) } } @@ -177,13 +168,11 @@ final class FlagApplierWithRetries: FlagApplier { } extension Sequence { - func async( - _ transform: (Element) async throws -> T + func asyncForEach( + _ transform: (Element) async throws -> Void ) async rethrows { - var values = [T]() - for element in self { - try await values.append(transform(element)) + try await transform(element) } } } diff --git a/Sources/ConfidenceProvider/Http/HttpClient.swift b/Sources/ConfidenceProvider/Http/HttpClient.swift index 2f747604..8f0d1721 100644 --- a/Sources/ConfidenceProvider/Http/HttpClient.swift +++ b/Sources/ConfidenceProvider/Http/HttpClient.swift @@ -6,8 +6,8 @@ protocol HttpClient { func post( path: String, data: Codable, - completion: @escaping (HttpClientResult) -> Void - ) throws + completion: @escaping (HttpClientResult) async -> Void + ) async throws func post(path: String, data: Codable) async throws -> HttpClientResponse } diff --git a/Sources/ConfidenceProvider/Http/NetworkClient.swift b/Sources/ConfidenceProvider/Http/NetworkClient.swift index 9928ac4a..c4320050 100644 --- a/Sources/ConfidenceProvider/Http/NetworkClient.swift +++ b/Sources/ConfidenceProvider/Http/NetworkClient.swift @@ -44,27 +44,23 @@ final class NetworkClient: HttpClient { func post( path: String, data: Codable, - completion: @escaping (HttpClientResult) -> Void - ) throws { + completion: @escaping (HttpClientResult) async -> Void + ) async throws { let request = try buildRequest(path: path, data: data) - perform(request: request, retry: self.retry) { response, data, error in - if let error { - completion(.failure(error)) - return - } - guard let response, let data else { - completion(.failure(ConfidenceError.internalError(message: "Bad response"))) - return - } - do { - let httpClientResult: HttpClientResponse = - try self.buildResponse(response: response, data: data) - completion(.success(httpClientResult)) - } catch { - completion(.failure(error)) - } + let (data, response) = try await URLSession.shared.data(for: request) + guard let response = response as? HTTPURLResponse, response.statusCode == 202 else { + await completion(.failure(HttpClientError.internalError)) + return + } + + do { + let httpClientResult: HttpClientResponse = + try self.buildResponse(response: response, data: data) + await completion(.success(httpClientResult)) + } catch { + await completion(.failure(error)) } } diff --git a/Tests/ConfidenceProviderTests/CacheDataInteractorTests.swift b/Tests/ConfidenceProviderTests/CacheDataInteractorTests.swift index 30ba8ace..1b07bde3 100644 --- a/Tests/ConfidenceProviderTests/CacheDataInteractorTests.swift +++ b/Tests/ConfidenceProviderTests/CacheDataInteractorTests.swift @@ -27,19 +27,17 @@ final class CacheDataInteractorTests: XCTestCase { func testCacheDataInteractor_addEventToEmptyCache() async throws { // Given cache data interactor with no previously stored data let cacheDataInteractor = CacheDataInteractor(cacheData: .empty()) - Task { - let cache = await cacheDataInteractor.cache - XCTAssertEqual(cache.resolveEvents.count, 0) - } - Task { - // When cache data add method is called - _ = await cacheDataInteractor.add(resolveToken: "token", flagName: "name", applyTime: Date()) + let cache = await cacheDataInteractor.cache + XCTAssertEqual(cache.resolveEvents.count, 0) - // Then event is added with - let cache = await cacheDataInteractor.cache - XCTAssertEqual(cache.resolveEvents.count, 1) - } + + // When cache data add method is called + _ = await cacheDataInteractor.add(resolveToken: "token", flagName: "name", applyTime: Date()) + + // Then event is added with + let cache2 = await cacheDataInteractor.cache + XCTAssertEqual(cache2.resolveEvents.count, 1) } func testCacheDataInteractor_addEventToPreFilledCache() async throws { diff --git a/Tests/ConfidenceProviderTests/Helpers/HttpClientMock.swift b/Tests/ConfidenceProviderTests/Helpers/HttpClientMock.swift index 6d325e6c..3a46a0d8 100644 --- a/Tests/ConfidenceProviderTests/Helpers/HttpClientMock.swift +++ b/Tests/ConfidenceProviderTests/Helpers/HttpClientMock.swift @@ -22,13 +22,13 @@ final class HttpClientMock: HttpClient { func post( path: String, data: Codable, - completion: @escaping (ConfidenceProvider.HttpClientResult) -> Void - ) throws where T: Decodable { + completion: @escaping (ConfidenceProvider.HttpClientResult) async -> Void + ) async throws where T: Decodable { do { let result: HttpClientResponse = try handlePost(path: path, data: data) - completion(.success(result)) + await completion(.success(result)) } catch { - completion(.failure(error)) + await completion(.failure(error)) } }