APITests.swift 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. // Copyright 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import FirebaseCore
  15. @testable import FirebaseRemoteConfig
  16. import XCTest
  17. class APITests: APITestBase {
  18. func testFetchThenActivate() {
  19. let expectation = self.expectation(description: #function)
  20. config.fetch { status, error in
  21. if let error {
  22. XCTFail("Fetch Error \(error)")
  23. }
  24. XCTAssertEqual(status, RemoteConfigFetchStatus.success)
  25. self.config.activate { _, error in
  26. XCTAssertNil(error)
  27. XCTAssertEqual(self.config[Constants.key1].stringValue, Constants.value1)
  28. expectation.fulfill()
  29. }
  30. }
  31. waitForExpectations()
  32. }
  33. func testFetchWithExpirationThenActivate() {
  34. let expectation = self.expectation(description: #function)
  35. config.fetch(withExpirationDuration: 0) { status, error in
  36. if let error {
  37. XCTFail("Fetch Error \(error)")
  38. }
  39. XCTAssertEqual(status, RemoteConfigFetchStatus.success)
  40. self.config.activate { _, error in
  41. XCTAssertNil(error)
  42. XCTAssertEqual(self.config[Constants.key1].stringValue, Constants.value1)
  43. expectation.fulfill()
  44. }
  45. }
  46. waitForExpectations()
  47. }
  48. func testFetchAndActivate() {
  49. let expectation = self.expectation(description: #function)
  50. config.fetchAndActivate { status, error in
  51. XCTAssertEqual(status, .successFetchedFromRemote)
  52. if let error {
  53. XCTFail("Fetch and Activate Error \(error)")
  54. }
  55. XCTAssertEqual(self.config[Constants.key1].stringValue, Constants.value1)
  56. expectation.fulfill()
  57. }
  58. waitForExpectations()
  59. }
  60. // Test New API.
  61. // Contrast with testChangedActivateWillNotFlag in FakeConsole.swift.
  62. func testUnchangedActivateWillFlag() {
  63. let expectation = self.expectation(description: #function)
  64. config.fetch { status, error in
  65. if let error {
  66. XCTFail("Fetch Error \(error)")
  67. }
  68. XCTAssertEqual(status, RemoteConfigFetchStatus.success)
  69. self.config.activate { changed, error in
  70. XCTAssertTrue(!APITests.useFakeConfig || changed)
  71. XCTAssertNil(error)
  72. XCTAssertEqual(self.config[Constants.key1].stringValue, Constants.value1)
  73. expectation.fulfill()
  74. }
  75. }
  76. waitForExpectations()
  77. let expectation2 = self.expectation(description: #function + "2")
  78. config.fetch { status, error in
  79. if let error {
  80. XCTFail("Fetch Error \(error)")
  81. }
  82. XCTAssertEqual(status, RemoteConfigFetchStatus.success)
  83. self.config.activate { changed, error in
  84. XCTAssertFalse(changed)
  85. XCTAssertNil(error)
  86. XCTAssertEqual(self.config[Constants.key1].stringValue, Constants.value1)
  87. expectation2.fulfill()
  88. }
  89. }
  90. waitForExpectations()
  91. }
  92. func testFetchAndActivateUnchangedConfig() throws {
  93. guard APITests.useFakeConfig == false else { return }
  94. let expectation = self.expectation(description: #function)
  95. XCTAssertEqual(config.settings.minimumFetchInterval, 0)
  96. let serialQueue = DispatchQueue(label: "\(#function)Queue")
  97. let group = DispatchGroup()
  98. group.enter()
  99. serialQueue.async {
  100. // Represents pre-fetch occurring sometime in past.
  101. self.config.fetch { status, error in
  102. XCTAssertNil(error, "Fetch Error \(error!)")
  103. XCTAssertEqual(status, .success)
  104. group.leave()
  105. }
  106. }
  107. serialQueue.async {
  108. group.wait()
  109. group.enter()
  110. // Represents a `fetchAndActivate` being made to pull latest changes from Remote Config.
  111. self.config.fetchAndActivate { status, error in
  112. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  113. // Since no updates to remote config have occurred we use the `.successUsingPreFetchedData`.
  114. // The behavior of the next test changed in Firebase 7.0.0.
  115. // It's an open question which is correct, but it should only
  116. // be changed in a major release.
  117. // See https://github.com/firebase/firebase-ios-sdk/pull/8788
  118. // XCTAssertEqual(status, .successUsingPreFetchedData)
  119. XCTAssertEqual(status, .successFetchedFromRemote)
  120. // The `lastETagUpdateTime` should either be older or the same time as `lastFetchTime`.
  121. if let lastFetchTime = try? XCTUnwrap(self.config.lastFetchTime) {
  122. XCTAssertLessThanOrEqual(Double(self.config.settings.lastETagUpdateTime),
  123. Double(lastFetchTime.timeIntervalSince1970))
  124. } else {
  125. XCTFail("Could not unwrap lastFetchTime.")
  126. }
  127. expectation.fulfill()
  128. }
  129. }
  130. waitForExpectations()
  131. }
  132. // MARK: - RemoteConfigRealtime Tests
  133. func testRealtimeRemoteConfigFakeConsole() {
  134. guard APITests.useFakeConfig == true else { return }
  135. let expectation = self.expectation(description: #function)
  136. let registration = config.addOnConfigUpdateListener { RemoteConfigUpdate, Error in
  137. XCTAssertNil(Error, "Realtime error \(Error!)")
  138. XCTAssertNotNil(RemoteConfigUpdate)
  139. expectation.fulfill()
  140. }
  141. waitForExpectations()
  142. registration.remove()
  143. }
  144. func testRealtimeRemoteConfigRealConsole() {
  145. guard APITests.useFakeConfig == false else { return }
  146. let expectation = self.expectation(description: #function)
  147. let registration = config.addOnConfigUpdateListener { RemoteConfigUpdate, Error in
  148. XCTAssertNil(Error, "Realtime error \(Error!)")
  149. XCTAssertNotNil(RemoteConfigUpdate)
  150. XCTAssertNotNil(RemoteConfigUpdate?.updatedKeys.contains(Constants.jedi))
  151. expectation.fulfill()
  152. }
  153. console.updateRemoteConfigValue(Constants.yoda, forKey: Constants.jedi)
  154. waitForExpectations()
  155. registration.remove()
  156. }
  157. // MARK: - RemoteConfigConsole Tests
  158. func testFetchConfigThenUpdateConsoleThenFetchAgain() {
  159. guard APITests.useFakeConfig == false else { return }
  160. let expectation = self.expectation(description: #function)
  161. config.fetchAndActivate { status, error in
  162. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  163. XCTAssertEqual(self.config.configValue(forKey: Constants.jedi).stringValue, Constants.obiwan)
  164. expectation.fulfill()
  165. }
  166. waitForExpectations()
  167. // Synchronously update the console.
  168. console.updateRemoteConfigValue(Constants.yoda, forKey: Constants.jedi)
  169. let expectation2 = self.expectation(description: #function + "2")
  170. config.fetchAndActivate { status, error in
  171. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  172. XCTAssertEqual(self.config.configValue(forKey: Constants.jedi).stringValue, Constants.yoda)
  173. expectation2.fulfill()
  174. }
  175. waitForExpectations()
  176. }
  177. func testFetchConfigThenAddValueOnConsoleThenFetchAgain() {
  178. guard APITests.useFakeConfig == false else { return }
  179. // Ensure no Sith Lord has been written to Remote Config yet.
  180. let expectation = self.expectation(description: #function)
  181. config.fetchAndActivate { status, error in
  182. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  183. XCTAssertTrue(self.config.configValue(forKey: Constants.sith).dataValue.isEmpty)
  184. expectation.fulfill()
  185. }
  186. waitForExpectations()
  187. // Synchronously update the console
  188. console.updateRemoteConfigValue(Constants.darthSidious, forKey: Constants.sith)
  189. // Verify the Sith Lord can now be fetched from Remote Config.
  190. let expectation2 = self.expectation(description: #function + "2")
  191. config.fetchAndActivate { status, error in
  192. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  193. XCTAssertEqual(
  194. self.config.configValue(forKey: Constants.sith).stringValue,
  195. Constants.darthSidious
  196. )
  197. expectation2.fulfill()
  198. }
  199. waitForExpectations()
  200. }
  201. func testFetchConfigThenDeleteValueOnConsoleThenFetchAgain() {
  202. guard APITests.useFakeConfig == false else { return }
  203. let expectation = self.expectation(description: #function)
  204. config.fetchAndActivate { status, error in
  205. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  206. XCTAssertEqual(self.config.configValue(forKey: Constants.jedi).stringValue, Constants.obiwan)
  207. expectation.fulfill()
  208. }
  209. waitForExpectations()
  210. // Synchronously delete value on the console.
  211. console.removeRemoteConfigValue(forKey: Constants.jedi)
  212. let expectation2 = self.expectation(description: #function + "2")
  213. config.fetchAndActivate { status, error in
  214. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  215. XCTAssertTrue(self.config.configValue(forKey: Constants.jedi).dataValue.isEmpty,
  216. "Remote config should have been deleted.")
  217. expectation2.fulfill()
  218. }
  219. waitForExpectations()
  220. }
  221. // MARK: - Private Helpers
  222. private func waitForExpectations() {
  223. let kTestTimeout = 10.0
  224. waitForExpectations(timeout: kTestTimeout,
  225. handler: { error in
  226. if let error {
  227. print(error)
  228. }
  229. })
  230. }
  231. }