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