diff --git a/FirebaseRemoteConfig/Tests/Swift/FakeUtils/MockURLProtocol.swift b/FirebaseRemoteConfig/Tests/Swift/FakeUtils/MockURLProtocol.swift new file mode 100644 index 00000000000..7761e4e523d --- /dev/null +++ b/FirebaseRemoteConfig/Tests/Swift/FakeUtils/MockURLProtocol.swift @@ -0,0 +1,62 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +class MockURLProtocol: URLProtocol { + #if compiler(>=6) + nonisolated(unsafe) static var requestHandler: ((URLRequest) throws -> ( + Data, + HTTPURLResponse + ))? + #else + static var requestHandler: ((URLRequest) throws -> ( + Data, + HTTPURLResponse + ))? + #endif + + override class func canInit(with request: URLRequest) -> Bool { + #if os(watchOS) + print("MockURLProtocol cannot be used on watchOS.") + return false + #else + return true + #endif // os(watchOS) + } + + override class func canonicalRequest(for request: URLRequest) -> URLRequest { + return request + } + + override func startLoading() { + guard let requestHandler = MockURLProtocol.requestHandler else { + fatalError("`requestHandler` is nil.") + } + guard let client = client else { + fatalError("`client` is nil.") + } + + do { + let (data, respopnse) = try requestHandler(request) + client.urlProtocol(self, didReceive: respopnse, cacheStoragePolicy: .notAllowed) + client.urlProtocol(self, didLoad: data) + client.urlProtocolDidFinishLoading(self) + } catch { + client.urlProtocol(self, didFailWithError: error) + } + } + + override func stopLoading() {} +} diff --git a/FirebaseRemoteConfig/Tests/Swift/FakeUtils/URLSessionPartialMock.swift b/FirebaseRemoteConfig/Tests/Swift/FakeUtils/URLSessionPartialMock.swift deleted file mode 100644 index f6809a0560e..00000000000 --- a/FirebaseRemoteConfig/Tests/Swift/FakeUtils/URLSessionPartialMock.swift +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import Foundation - -#if SWIFT_PACKAGE - import RemoteConfigFakeConsoleObjC -#endif - -// Create a partial mock by subclassing the URLSessionDataTask. -class URLSessionDataTaskMock: URLSessionDataTask, @unchecked Sendable { - private let closure: () -> Void - - init(closure: @escaping () -> Void) { - self.closure = closure - } - - override func resume() { - closure() - } -} - -class URLSessionMock: URLSession, @unchecked Sendable { - typealias CompletionHandler = (Data?, URLResponse?, Error?) -> Void - - private let fakeConsole: FakeConsole - init(with fakeConsole: FakeConsole) { - self.fakeConsole = fakeConsole - } - - // Properties to control what gets returned to the URLSession callback. - // error could also be added here. - var data: Data? - var response: URLResponse? - var etag = "" - - override func dataTask(with request: URLRequest, - completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) - -> URLSessionDataTask { - let consoleValues = fakeConsole.get() - if etag == "" || consoleValues["state"] as! String == RCNFetchResponseKeyStateUpdate { - // Time string in microseconds to insure a different string from previous change. - etag = String(NSDate().timeIntervalSince1970) - } - let jsonData = try! JSONSerialization.data(withJSONObject: consoleValues) - let response = HTTPURLResponse(url: URL(fileURLWithPath: "fakeURL"), - statusCode: 200, - httpVersion: nil, - headerFields: ["etag": etag]) - return URLSessionDataTaskMock { - completionHandler(jsonData, response, nil) - } - } -} diff --git a/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITestBase.swift b/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITestBase.swift index 8aa741f0437..d48600d0f24 100644 --- a/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITestBase.swift +++ b/FirebaseRemoteConfig/Tests/Swift/SwiftAPI/APITestBase.swift @@ -88,7 +88,24 @@ class APITestBase: XCTestCase { config.configRealtime = RealtimeMocks.mockRealtime(config.configRealtime) } fakeConsole = FakeConsole() - config.configFetch.fetchSession = URLSessionMock(with: fakeConsole) + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [MockURLProtocol.self] + config.configFetch.fetchSession = URLSession(configuration: configuration) + + var etag = "" + MockURLProtocol.requestHandler = { request in + let consoleValues = self.fakeConsole.get() + if etag == "" || consoleValues["state"] as! String == RCNFetchResponseKeyStateUpdate { + // Time string in microseconds to insure a different string from previous change. + etag = String(NSDate().timeIntervalSince1970) + } + let jsonData = try! JSONSerialization.data(withJSONObject: consoleValues) + let response = HTTPURLResponse(url: URL(fileURLWithPath: "fakeURL"), + statusCode: 200, + httpVersion: nil, + headerFields: ["etag": etag]) + return (jsonData, response!) + } fakeConsole.config = [Constants.key1: Constants.value1, Constants.jsonKey: jsonValue, diff --git a/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m b/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m index 1021d7014d1..9786af20cbf 100644 --- a/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m +++ b/FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m @@ -1916,7 +1916,7 @@ - (void)testSetCustomSignalsMultipleTimes { [_configInstances[i] setCustomSignals:testSignals1 withCompletion:^(NSError *_Nullable error) { XCTAssertNil(error); - [_configInstances[i] + [self->_configInstances[i] setCustomSignals:testSignals2 withCompletion:^(NSError *_Nullable error) { XCTAssertNil(error); diff --git a/scripts/build.sh b/scripts/build.sh index 2925f77d2da..9ad85b209a1 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -486,13 +486,12 @@ case "$product-$platform-$method" in ../../../FirebaseRemoteConfig/Tests/Swift/AccessToken.json # Integration tests are only run on iOS to minimize flake failures. - # TODO(ncooke3): Remove -sdk and -destination flags. + # TODO(ncooke3): Remove -sdk and -destination flags and replace with "${xcb_flags[@]}" RunXcodebuild \ -workspace 'gen/FirebaseRemoteConfig/FirebaseRemoteConfig.xcworkspace' \ -scheme "FirebaseRemoteConfig-Unit-swift-api-tests" \ -sdk 'iphonesimulator' \ -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.3.1' \ - "${xcb_flags[@]}" \ build \ test ;;