StorageIntegration.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  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 FirebaseAuth
  15. import FirebaseCore
  16. import FirebaseStorage
  17. import FirebaseStorageSwift
  18. import XCTest
  19. class StorageIntegration: XCTestCase {
  20. var app: FirebaseApp!
  21. var auth: Auth!
  22. var storage: Storage!
  23. static var once = false
  24. static var signedIn = false
  25. override class func setUp() {
  26. FirebaseApp.configure()
  27. }
  28. override func setUp() {
  29. super.setUp()
  30. app = FirebaseApp.app()
  31. auth = Auth.auth(app: app)
  32. storage = Storage.storage(app: app!)
  33. if !StorageIntegration.signedIn {
  34. signInAndWait()
  35. }
  36. if !StorageIntegration.once {
  37. StorageIntegration.once = true
  38. let setupExpectation = expectation(description: "setUp")
  39. let largeFiles = ["ios/public/1mb"]
  40. let emptyFiles =
  41. ["ios/public/empty", "ios/public/list/a", "ios/public/list/b", "ios/public/list/prefix/c"]
  42. setupExpectation.expectedFulfillmentCount = largeFiles.count + emptyFiles.count
  43. do {
  44. let bundle = Bundle(for: StorageIntegration.self)
  45. let filePath = try XCTUnwrap(bundle.path(forResource: "1mb", ofType: "dat"),
  46. "Failed to get filePath")
  47. let data = try XCTUnwrap(try Data(contentsOf: URL(fileURLWithPath: filePath)),
  48. "Failed to load file")
  49. for largeFile in largeFiles {
  50. let ref = storage.reference().child(largeFile)
  51. ref.putData(data) { result in
  52. self.assertResultSuccess(result)
  53. setupExpectation.fulfill()
  54. }
  55. }
  56. for emptyFile in emptyFiles {
  57. let ref = storage.reference().child(emptyFile)
  58. ref.putData(data) { result in
  59. self.assertResultSuccess(result)
  60. setupExpectation.fulfill()
  61. }
  62. }
  63. waitForExpectations()
  64. } catch {
  65. XCTFail("Error thrown setting up files in setUp")
  66. }
  67. }
  68. }
  69. override func tearDown() {
  70. app = nil
  71. storage = nil
  72. super.tearDown()
  73. }
  74. func testGetMetadata() {
  75. let expectation = self.expectation(description: "testGetMetadata")
  76. let ref = storage.reference().child("ios/public/1mb")
  77. ref.getMetadata { result in
  78. self.assertResultSuccess(result)
  79. expectation.fulfill()
  80. }
  81. waitForExpectations()
  82. }
  83. func testUpdateMetadata() {
  84. let expectation = self.expectation(description: #function)
  85. let meta = StorageMetadata()
  86. meta.contentType = "lol/custom"
  87. meta.customMetadata = ["lol": "custom metadata is neat",
  88. "ちかてつ": "🚇",
  89. "shinkansen": "新幹線"]
  90. let ref = storage.reference(withPath: "ios/public/1mb")
  91. ref.updateMetadata(meta) { result in
  92. switch result {
  93. case let .success(metadata):
  94. XCTAssertEqual(meta.contentType, metadata.contentType)
  95. XCTAssertEqual(meta.customMetadata!["lol"], metadata.customMetadata!["lol"])
  96. XCTAssertEqual(meta.customMetadata!["ちかてつ"], metadata.customMetadata!["ちかてつ"])
  97. XCTAssertEqual(meta.customMetadata!["shinkansen"],
  98. metadata.customMetadata!["shinkansen"])
  99. case let .failure(error):
  100. XCTFail("Unexpected error \(error) from updateMetadata")
  101. }
  102. expectation.fulfill()
  103. }
  104. waitForExpectations()
  105. }
  106. func testDelete() throws {
  107. let expectation = self.expectation(description: #function)
  108. let ref = storage.reference(withPath: "ios/public/fileToDelete")
  109. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  110. ref.putData(data) { result in
  111. self.assertResultSuccess(result)
  112. ref.delete { error in
  113. XCTAssertNil(error, "Error should be nil")
  114. }
  115. expectation.fulfill()
  116. }
  117. waitForExpectations()
  118. }
  119. func testDeleteWithNilCompletion() throws {
  120. let expectation = self.expectation(description: #function)
  121. let ref = storage.reference(withPath: "ios/public/fileToDelete")
  122. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  123. ref.putData(data) { result in
  124. self.assertResultSuccess(result)
  125. ref.delete(completion: nil)
  126. expectation.fulfill()
  127. }
  128. waitForExpectations()
  129. }
  130. func testSimplePutData() throws {
  131. let expectation = self.expectation(description: #function)
  132. let ref = storage.reference(withPath: "ios/public/testBytesUpload")
  133. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  134. ref.putData(data) { result in
  135. self.assertResultSuccess(result)
  136. expectation.fulfill()
  137. }
  138. waitForExpectations()
  139. }
  140. func testSimplePutSpecialCharacter() throws {
  141. let expectation = self.expectation(description: #function)
  142. let ref = storage.reference(withPath: "ios/public/-._~!$'()*,=:@&+;")
  143. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  144. ref.putData(data) { result in
  145. self.assertResultSuccess(result)
  146. expectation.fulfill()
  147. }
  148. waitForExpectations()
  149. }
  150. func testSimplePutDataInBackgroundQueue() throws {
  151. let expectation = self.expectation(description: #function)
  152. let ref = storage.reference(withPath: "ios/public/testBytesUpload")
  153. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  154. DispatchQueue.global(qos: .background).async {
  155. ref.putData(data) { result in
  156. self.assertResultSuccess(result)
  157. expectation.fulfill()
  158. }
  159. }
  160. waitForExpectations()
  161. }
  162. func testSimplePutEmptyData() {
  163. let expectation = self.expectation(description: #function)
  164. let ref = storage.reference(withPath: "ios/public/testSimplePutEmptyData")
  165. let data = Data()
  166. ref.putData(data) { result in
  167. self.assertResultSuccess(result)
  168. expectation.fulfill()
  169. }
  170. waitForExpectations()
  171. }
  172. func testSimplePutDataUnauthorized() throws {
  173. let expectation = self.expectation(description: #function)
  174. let ref = storage.reference(withPath: "ios/private/secretfile.txt")
  175. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  176. ref.putData(data) { result in
  177. switch result {
  178. case .success:
  179. XCTFail("Unexpected success from unauthorized putData")
  180. case let .failure(error as NSError):
  181. XCTAssertEqual(error.code, StorageErrorCode.unauthorized.rawValue)
  182. expectation.fulfill()
  183. }
  184. }
  185. waitForExpectations()
  186. }
  187. func testSimplePutDataUnauthorizedThrow() throws {
  188. let expectation = self.expectation(description: #function)
  189. let ref = storage.reference(withPath: "ios/private/secretfile.txt")
  190. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  191. ref.putData(data) { result in
  192. do {
  193. try _ = result.get() // .failure will throw
  194. } catch {
  195. expectation.fulfill()
  196. return
  197. }
  198. XCTFail("Unexpected success from unauthorized putData")
  199. expectation.fulfill()
  200. }
  201. waitForExpectations()
  202. }
  203. func testSimplePutFile() throws {
  204. let expectation = self.expectation(description: #function)
  205. let putFileExpectation = self.expectation(description: "putFile")
  206. let ref = storage.reference(withPath: "ios/public/testSimplePutFile")
  207. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  208. let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
  209. let fileURL = tmpDirURL.appendingPathComponent("hello.txt")
  210. try data.write(to: fileURL, options: .atomicWrite)
  211. let task = ref.putFile(from: fileURL) { result in
  212. self.assertResultSuccess(result)
  213. putFileExpectation.fulfill()
  214. }
  215. task.observe(StorageTaskStatus.success) { snapshot in
  216. XCTAssertEqual(snapshot.description, "<State: Success>")
  217. expectation.fulfill()
  218. }
  219. var uploadedBytes: Int64 = -1
  220. task.observe(StorageTaskStatus.progress) { snapshot in
  221. XCTAssertTrue(snapshot.description.starts(with: "<State: Progress") ||
  222. snapshot.description.starts(with: "<State: Resume"))
  223. guard let progress = snapshot.progress else {
  224. XCTFail("Failed to get snapshot.progress")
  225. return
  226. }
  227. XCTAssertGreaterThanOrEqual(progress.completedUnitCount, uploadedBytes)
  228. uploadedBytes = progress.completedUnitCount
  229. }
  230. waitForExpectations()
  231. }
  232. func testAttemptToUploadDirectoryShouldFail() throws {
  233. // This `.numbers` file is actually a directory.
  234. let fileName = "HomeImprovement.numbers"
  235. let bundle = Bundle(for: StorageIntegration.self)
  236. let fileURL = try XCTUnwrap(bundle.url(forResource: fileName, withExtension: ""),
  237. "Failed to get filePath")
  238. let ref = storage.reference(withPath: "ios/public/" + fileName)
  239. ref.putFile(from: fileURL) { result in
  240. self.assertResultFailure(result)
  241. }
  242. }
  243. func testPutFileWithSpecialCharacters() throws {
  244. let expectation = self.expectation(description: #function)
  245. let fileName = "hello&+@_ .txt"
  246. let ref = storage.reference(withPath: "ios/public/" + fileName)
  247. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  248. let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
  249. let fileURL = tmpDirURL.appendingPathComponent("hello.txt")
  250. try data.write(to: fileURL, options: .atomicWrite)
  251. ref.putFile(from: fileURL) { result in
  252. switch result {
  253. case let .success(metadata):
  254. XCTAssertEqual(fileName, metadata.name)
  255. ref.getMetadata { result in
  256. self.assertResultSuccess(result)
  257. }
  258. case let .failure(error):
  259. XCTFail("Unexpected error \(error) from putFile")
  260. }
  261. expectation.fulfill()
  262. }
  263. waitForExpectations()
  264. }
  265. func testSimplePutDataNoMetadata() throws {
  266. let expectation = self.expectation(description: #function)
  267. let ref = storage.reference(withPath: "ios/public/testSimplePutDataNoMetadata")
  268. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  269. ref.putData(data) { result in
  270. self.assertResultSuccess(result)
  271. expectation.fulfill()
  272. }
  273. waitForExpectations()
  274. }
  275. func testSimplePutFileNoMetadata() throws {
  276. let expectation = self.expectation(description: #function)
  277. let fileName = "hello&+@_ .txt"
  278. let ref = storage.reference(withPath: "ios/public/" + fileName)
  279. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  280. let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
  281. let fileURL = tmpDirURL.appendingPathComponent("hello.txt")
  282. try data.write(to: fileURL, options: .atomicWrite)
  283. ref.putFile(from: fileURL) { result in
  284. self.assertResultSuccess(result)
  285. expectation.fulfill()
  286. }
  287. waitForExpectations()
  288. }
  289. func testSimpleGetData() {
  290. let expectation = self.expectation(description: #function)
  291. let ref = storage.reference(withPath: "ios/public/1mb")
  292. ref.getData(maxSize: 1024 * 1024) { result in
  293. self.assertResultSuccess(result)
  294. expectation.fulfill()
  295. }
  296. waitForExpectations()
  297. }
  298. func testSimpleGetDataInBackgroundQueue() {
  299. let expectation = self.expectation(description: #function)
  300. let ref = storage.reference(withPath: "ios/public/1mb")
  301. DispatchQueue.global(qos: .background).async {
  302. ref.getData(maxSize: 1024 * 1024) { result in
  303. self.assertResultSuccess(result)
  304. expectation.fulfill()
  305. }
  306. }
  307. waitForExpectations()
  308. }
  309. func testSimpleGetDataWithCustomCallbackQueue() {
  310. let expectation = self.expectation(description: #function)
  311. let callbackQueueLabel = "customCallbackQueue"
  312. let callbackQueueKey = DispatchSpecificKey<String>()
  313. let callbackQueue = DispatchQueue(label: callbackQueueLabel)
  314. callbackQueue.setSpecific(key: callbackQueueKey, value: callbackQueueLabel)
  315. storage.callbackQueue = callbackQueue
  316. let ref = storage.reference(withPath: "ios/public/1mb")
  317. ref.getData(maxSize: 1024 * 1024) { result in
  318. self.assertResultSuccess(result)
  319. XCTAssertFalse(Thread.isMainThread)
  320. let currentQueueLabel = DispatchQueue.getSpecific(key: callbackQueueKey)
  321. XCTAssertEqual(currentQueueLabel, callbackQueueLabel)
  322. expectation.fulfill()
  323. // Reset the callbackQueue to default (main queue).
  324. self.storage.callbackQueue = DispatchQueue.main
  325. callbackQueue.setSpecific(key: callbackQueueKey, value: nil)
  326. }
  327. waitForExpectations()
  328. }
  329. func testSimpleGetDataTooSmall() {
  330. let expectation = self.expectation(description: #function)
  331. let ref = storage.reference(withPath: "ios/public/1mb")
  332. ref.getData(maxSize: 1024) { result in
  333. switch result {
  334. case .success:
  335. XCTFail("Unexpected success from getData too small")
  336. case let .failure(error as NSError):
  337. XCTAssertEqual(error.code, StorageErrorCode.downloadSizeExceeded.rawValue)
  338. }
  339. expectation.fulfill()
  340. }
  341. waitForExpectations()
  342. }
  343. func testSimpleGetDownloadURL() {
  344. let expectation = self.expectation(description: #function)
  345. let ref = storage.reference(withPath: "ios/public/1mb")
  346. // Download URL format is
  347. // "https://firebasestorage.googleapis.com/v0/b/{bucket}/o/{path}?alt=media&token={token}"
  348. let downloadURLPattern =
  349. "^https:\\/\\/firebasestorage.googleapis.com\\/v0\\/b\\/[^\\/]*\\/o\\/" +
  350. "ios%2Fpublic%2F1mb\\?alt=media&token=[a-z0-9-]*$"
  351. ref.downloadURL { result in
  352. switch result {
  353. case let .success(downloadURL):
  354. do {
  355. let testRegex = try NSRegularExpression(pattern: downloadURLPattern)
  356. let urlString = downloadURL.absoluteString
  357. XCTAssertEqual(testRegex.numberOfMatches(in: urlString,
  358. range: NSRange(location: 0,
  359. length: urlString.count)), 1)
  360. } catch {
  361. XCTFail("Throw in downloadURL completion block")
  362. }
  363. case let .failure(error):
  364. XCTFail("Unexpected error \(error) from downloadURL")
  365. }
  366. expectation.fulfill()
  367. }
  368. waitForExpectations()
  369. }
  370. func testSimpleGetFile() throws {
  371. let expectation = self.expectation(description: #function)
  372. let ref = storage.reference(withPath: "ios/public/helloworld")
  373. let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
  374. let fileURL = tmpDirURL.appendingPathComponent("hello.txt")
  375. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  376. ref.putData(data) { result in
  377. switch result {
  378. case .success:
  379. let task = ref.write(toFile: fileURL)
  380. task.observe(StorageTaskStatus.success) { snapshot in
  381. do {
  382. let stringData = try String(contentsOf: fileURL, encoding: .utf8)
  383. XCTAssertEqual(stringData, "Hello Swift World")
  384. XCTAssertEqual(snapshot.description, "<State: Success>")
  385. } catch {
  386. XCTFail("Error processing success snapshot")
  387. }
  388. expectation.fulfill()
  389. }
  390. task.observe(StorageTaskStatus.progress) { snapshot in
  391. XCTAssertNil(snapshot.error, "Error should be nil")
  392. guard let progress = snapshot.progress else {
  393. XCTFail("Missing progress")
  394. return
  395. }
  396. print("\(progress.completedUnitCount) of \(progress.totalUnitCount)")
  397. }
  398. task.observe(StorageTaskStatus.failure) { snapshot in
  399. XCTAssertNil(snapshot.error, "Error should be nil")
  400. }
  401. case let .failure(error):
  402. XCTFail("Unexpected error \(error) from putData")
  403. expectation.fulfill()
  404. }
  405. }
  406. waitForExpectations()
  407. }
  408. private func assertMetadata(actualMetadata: StorageMetadata,
  409. expectedContentType: String,
  410. expectedCustomMetadata: [String: String]) {
  411. XCTAssertEqual(actualMetadata.cacheControl, "cache-control")
  412. XCTAssertEqual(actualMetadata.contentDisposition, "content-disposition")
  413. XCTAssertEqual(actualMetadata.contentEncoding, "gzip")
  414. XCTAssertEqual(actualMetadata.contentLanguage, "de")
  415. XCTAssertEqual(actualMetadata.contentType, expectedContentType)
  416. XCTAssertEqual(actualMetadata.md5Hash?.count, 24)
  417. for (key, value) in expectedCustomMetadata {
  418. XCTAssertEqual(actualMetadata.customMetadata![key], value)
  419. }
  420. }
  421. private func assertMetadataNil(actualMetadata: StorageMetadata) {
  422. XCTAssertNil(actualMetadata.cacheControl)
  423. XCTAssertNil(actualMetadata.contentDisposition)
  424. XCTAssertEqual(actualMetadata.contentEncoding, "identity")
  425. XCTAssertNil(actualMetadata.contentLanguage)
  426. XCTAssertNil(actualMetadata.contentType)
  427. XCTAssertEqual(actualMetadata.md5Hash?.count, 24)
  428. XCTAssertNil(actualMetadata.customMetadata)
  429. }
  430. func testUpdateMetadata2() {
  431. let expectation = self.expectation(description: #function)
  432. let ref = storage.reference(withPath: "ios/public/1mb")
  433. let metadata = StorageMetadata()
  434. metadata.cacheControl = "cache-control"
  435. metadata.contentDisposition = "content-disposition"
  436. metadata.contentEncoding = "gzip"
  437. metadata.contentLanguage = "de"
  438. metadata.contentType = "content-type-a"
  439. metadata.customMetadata = ["a": "b"]
  440. ref.updateMetadata(metadata) { updatedMetadata, error in
  441. XCTAssertNil(error, "Error should be nil")
  442. guard let updatedMetadata = updatedMetadata else {
  443. XCTFail("Metadata is nil")
  444. expectation.fulfill()
  445. return
  446. }
  447. self.assertMetadata(actualMetadata: updatedMetadata,
  448. expectedContentType: "content-type-a",
  449. expectedCustomMetadata: ["a": "b"])
  450. let metadata = updatedMetadata
  451. metadata.contentType = "content-type-b"
  452. metadata.customMetadata = ["a": "b", "c": "d"]
  453. ref.updateMetadata(metadata) { result in
  454. switch result {
  455. case let .success(updatedMetadata):
  456. self.assertMetadata(actualMetadata: updatedMetadata,
  457. expectedContentType: "content-type-b",
  458. expectedCustomMetadata: ["a": "b", "c": "d"])
  459. metadata.cacheControl = nil
  460. metadata.contentDisposition = nil
  461. metadata.contentEncoding = nil
  462. metadata.contentLanguage = nil
  463. metadata.contentType = nil
  464. metadata.customMetadata = nil
  465. ref.updateMetadata(metadata) { result in
  466. self.assertResultSuccess(result)
  467. expectation.fulfill()
  468. }
  469. case let .failure(error):
  470. XCTFail("Unexpected error \(error) from updateMetadata")
  471. expectation.fulfill()
  472. }
  473. }
  474. }
  475. waitForExpectations()
  476. }
  477. func testPagedListFiles() {
  478. let expectation = self.expectation(description: #function)
  479. let ref = storage.reference(withPath: "ios/public/list")
  480. ref.list(maxResults: 2) { result in
  481. switch result {
  482. case let .success(listResult):
  483. XCTAssertEqual(listResult.items, [ref.child("a"), ref.child("b")])
  484. XCTAssertEqual(listResult.prefixes, [])
  485. guard let pageToken = listResult.pageToken else {
  486. XCTFail("pageToken should not be nil")
  487. expectation.fulfill()
  488. return
  489. }
  490. ref.list(maxResults: 2, pageToken: pageToken) { result in
  491. switch result {
  492. case let .success(listResult):
  493. XCTAssertEqual(listResult.items, [])
  494. XCTAssertEqual(listResult.prefixes, [ref.child("prefix")])
  495. XCTAssertNil(listResult.pageToken, "pageToken should be nil")
  496. case let .failure(error):
  497. XCTFail("Unexpected error \(error) from list")
  498. }
  499. expectation.fulfill()
  500. }
  501. case let .failure(error):
  502. XCTFail("Unexpected error \(error) from list")
  503. expectation.fulfill()
  504. }
  505. }
  506. waitForExpectations()
  507. }
  508. func testListAllFiles() {
  509. let expectation = self.expectation(description: #function)
  510. let ref = storage.reference(withPath: "ios/public/list")
  511. ref.listAll { result in
  512. switch result {
  513. case let .success(listResult):
  514. XCTAssertEqual(listResult.items, [ref.child("a"), ref.child("b")])
  515. XCTAssertEqual(listResult.prefixes, [ref.child("prefix")])
  516. XCTAssertNil(listResult.pageToken, "pageToken should be nil")
  517. case let .failure(error):
  518. XCTFail("Unexpected error \(error) from list")
  519. }
  520. expectation.fulfill()
  521. }
  522. waitForExpectations()
  523. }
  524. private func signInAndWait() {
  525. let expectation = self.expectation(description: #function)
  526. auth.signIn(withEmail: Credentials.kUserName,
  527. password: Credentials.kPassword) { result, error in
  528. XCTAssertNil(error)
  529. StorageIntegration.signedIn = true
  530. print("Successfully signed in")
  531. expectation.fulfill()
  532. }
  533. waitForExpectations()
  534. }
  535. private func waitForExpectations() {
  536. let kFIRStorageIntegrationTestTimeout = 60.0
  537. waitForExpectations(timeout: kFIRStorageIntegrationTestTimeout,
  538. handler: { (error) -> Void in
  539. if let error = error {
  540. print(error)
  541. }
  542. })
  543. }
  544. private func assertResultSuccess<T>(_ result: Result<T, Error>,
  545. file: StaticString = #file, line: UInt = #line) {
  546. switch result {
  547. case let .success(value):
  548. XCTAssertNotNil(value, file: file, line: line)
  549. case let .failure(error):
  550. XCTFail("Unexpected error \(error)")
  551. }
  552. }
  553. private func assertResultFailure<T>(_ result: Result<T, Error>,
  554. file: StaticString = #file, line: UInt = #line) {
  555. switch result {
  556. case let .success(value):
  557. XCTFail("Unexpected success with value: \(value)")
  558. case let .failure(error):
  559. XCTAssertNotNil(error, file: file, line: line)
  560. }
  561. }
  562. }