StorageIntegration.swift 25 KB

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