StorageIntegration.swift 28 KB

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