APITests.swift 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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 = 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 = 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 = 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 = 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 = 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: - RemoteConfigConsole Tests
  133. func testFetchConfigThenUpdateConsoleThenFetchAgain() {
  134. guard APITests.useFakeConfig == false else { return }
  135. let expectation = self.expectation(description: #function)
  136. config.fetchAndActivate { status, error in
  137. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  138. if let configValue = self.config.configValue(forKey: Constants.jedi).stringValue {
  139. XCTAssertEqual(configValue, Constants.obiwan)
  140. } else {
  141. XCTFail("Could not unwrap config value for key: \(Constants.jedi)")
  142. }
  143. expectation.fulfill()
  144. }
  145. waitForExpectations()
  146. // Synchronously update the console.
  147. console.updateRemoteConfigValue(Constants.yoda, forKey: Constants.jedi)
  148. let expectation2 = self.expectation(description: #function + "2")
  149. config.fetchAndActivate { status, error in
  150. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  151. if let configValue = self.config.configValue(forKey: Constants.jedi).stringValue {
  152. XCTAssertEqual(configValue, Constants.yoda)
  153. } else {
  154. XCTFail("Could not unwrap config value for key: \(Constants.jedi)")
  155. }
  156. expectation2.fulfill()
  157. }
  158. waitForExpectations()
  159. }
  160. func testFetchConfigThenAddValueOnConsoleThenFetchAgain() {
  161. guard APITests.useFakeConfig == false else { return }
  162. // Ensure no Sith Lord has been written to Remote Config yet.
  163. let expectation = self.expectation(description: #function)
  164. config.fetchAndActivate { status, error in
  165. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  166. XCTAssertTrue(self.config.configValue(forKey: Constants.sith).dataValue.isEmpty)
  167. expectation.fulfill()
  168. }
  169. waitForExpectations()
  170. // Synchronously update the console
  171. console.updateRemoteConfigValue(Constants.darthSidious, forKey: Constants.sith)
  172. // Verify the Sith Lord can now be fetched from Remote Config.
  173. let expectation2 = self.expectation(description: #function + "2")
  174. config.fetchAndActivate { status, error in
  175. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  176. if let configValue = self.config.configValue(forKey: Constants.sith).stringValue {
  177. XCTAssertEqual(configValue, Constants.darthSidious)
  178. } else {
  179. XCTFail("Could not unwrap config value for key: \(Constants.sith)")
  180. }
  181. expectation2.fulfill()
  182. }
  183. waitForExpectations()
  184. }
  185. func testFetchConfigThenDeleteValueOnConsoleThenFetchAgain() {
  186. guard APITests.useFakeConfig == false else { return }
  187. let expectation = self.expectation(description: #function)
  188. config.fetchAndActivate { status, error in
  189. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  190. if let configValue = self.config.configValue(forKey: Constants.jedi).stringValue {
  191. XCTAssertEqual(configValue, Constants.obiwan)
  192. } else {
  193. XCTFail("Could not unwrap config value for key: \(Constants.jedi)")
  194. }
  195. expectation.fulfill()
  196. }
  197. waitForExpectations()
  198. // Synchronously delete value on the console.
  199. console.removeRemoteConfigValue(forKey: Constants.jedi)
  200. let expectation2 = self.expectation(description: #function + "2")
  201. config.fetchAndActivate { status, error in
  202. XCTAssertNil(error, "Fetch & Activate Error \(error!)")
  203. XCTAssertTrue(self.config.configValue(forKey: Constants.jedi).dataValue.isEmpty,
  204. "Remote config should have been deleted.")
  205. expectation2.fulfill()
  206. }
  207. waitForExpectations()
  208. }
  209. // MARK: - Private Helpers
  210. private func waitForExpectations() {
  211. let kTestTimeout = 10.0
  212. waitForExpectations(timeout: kTestTimeout,
  213. handler: { error in
  214. if let error = error {
  215. print(error)
  216. }
  217. })
  218. }
  219. }