StorageIntegration.swift 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  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 testSimpleGetDataWithCustomCallbackQueue() {
  338. let expectation = self.expectation(description: #function)
  339. let callbackQueueLabel = "customCallbackQueue"
  340. let callbackQueueKey = DispatchSpecificKey<String>()
  341. let callbackQueue = DispatchQueue(label: callbackQueueLabel)
  342. callbackQueue.setSpecific(key: callbackQueueKey, value: callbackQueueLabel)
  343. storage.callbackQueue = callbackQueue
  344. let ref = storage.reference(withPath: "ios/public/1mb")
  345. ref.getData(maxSize: 1024 * 1024) { data, error in
  346. XCTAssertNotNil(data, "Data should not be nil")
  347. XCTAssertNil(error, "Error should be nil")
  348. XCTAssertFalse(Thread.isMainThread)
  349. let currentQueueLabel = DispatchQueue.getSpecific(key: callbackQueueKey)
  350. XCTAssertEqual(currentQueueLabel, callbackQueueLabel)
  351. expectation.fulfill()
  352. // Reset the callbackQueue to default (main queue).
  353. self.storage.callbackQueue = DispatchQueue.main
  354. callbackQueue.setSpecific(key: callbackQueueKey, value: nil)
  355. }
  356. waitForExpectations()
  357. }
  358. func testSimpleGetDataTooSmall() {
  359. let expectation = self.expectation(description: #function)
  360. let ref = storage.reference(withPath: "ios/public/1mb")
  361. ref.getData(maxSize: 1024, completion: { data, error in
  362. XCTAssertNil(data, "Data should be nil")
  363. XCTAssertNotNil(error, "Error should not be nil")
  364. XCTAssertEqual((error! as NSError).code, StorageErrorCode.downloadSizeExceeded.rawValue)
  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 downloadURLPattern =
  375. "^https:\\/\\/firebasestorage.googleapis.com:443\\/v0\\/b\\/[^\\/]*\\/o\\/" +
  376. "ios%2Fpublic%2F1mb\\?alt=media&token=[a-z0-9-]*$"
  377. ref.downloadURL(completion: { downloadURL, error in
  378. XCTAssertNil(error, "Error should be nil")
  379. do {
  380. let testRegex = try NSRegularExpression(pattern: downloadURLPattern)
  381. let downloadURL = try XCTUnwrap(downloadURL, "Failed to unwrap downloadURL")
  382. let urlString = downloadURL.absoluteString
  383. XCTAssertEqual(testRegex.numberOfMatches(in: urlString,
  384. range: NSRange(location: 0,
  385. length: urlString.count)), 1)
  386. expectation.fulfill()
  387. } catch {
  388. XCTFail("Throw in downloadURL completion block")
  389. }
  390. })
  391. waitForExpectations()
  392. }
  393. func testSimpleGetFileWithCompletion() throws {
  394. let expectation = self.expectation(description: #function)
  395. let ref = storage.reference(withPath: "ios/public/cookie")
  396. let cookieString = "Here's a 🍪, yay!"
  397. let data = try XCTUnwrap(cookieString.data(using: .utf8), "Data construction failed")
  398. ref.putData(data, metadata: nil, completion: { metadata, error in
  399. XCTAssertNotNil(metadata, "Metadata should not be nil")
  400. XCTAssertNil(error, "Error should be nil")
  401. let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
  402. let fileURL = tmpDirURL.appendingPathComponent("cookie.txt")
  403. ref.write(toFile: fileURL) { url, error in
  404. XCTAssertNil(error, "Error should be nil")
  405. guard let url = url else {
  406. XCTFail("Failed to unwrap url")
  407. return
  408. }
  409. XCTAssertEqual(fileURL, url)
  410. do {
  411. let stringData = try String(contentsOf: fileURL, encoding: .utf8)
  412. XCTAssertEqual(stringData, cookieString)
  413. expectation.fulfill()
  414. } catch {
  415. XCTFail("Could not get String contents of fetched data")
  416. }
  417. }
  418. })
  419. waitForExpectations()
  420. }
  421. func testSimpleGetFile() throws {
  422. let expectation = self.expectation(description: #function)
  423. let ref = storage.reference(withPath: "ios/public/helloworld")
  424. let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
  425. let fileURL = tmpDirURL.appendingPathComponent("hello.txt")
  426. let data = try XCTUnwrap("Hello Swift World".data(using: .utf8), "Data construction failed")
  427. ref.putData(data, metadata: nil, completion: { metadata, error in
  428. XCTAssertNotNil(metadata, "Metadata should not be nil")
  429. XCTAssertNil(error, "Error should be nil")
  430. let task = ref.write(toFile: fileURL)
  431. task.observe(StorageTaskStatus.success, handler: { snapshot in
  432. do {
  433. let stringData = try String(contentsOf: fileURL, encoding: .utf8)
  434. XCTAssertEqual(stringData, "Hello Swift World")
  435. XCTAssertEqual(snapshot.description, "<State: Success>")
  436. expectation.fulfill()
  437. } catch {
  438. XCTFail("Exception processing success snapshot")
  439. }
  440. })
  441. task.observe(StorageTaskStatus.progress, handler: { snapshot in
  442. XCTAssertNil(snapshot.error, "Error should be nil")
  443. guard let progress = snapshot.progress else {
  444. XCTFail("Missing progress")
  445. return
  446. }
  447. print("\(progress.completedUnitCount) of \(progress.totalUnitCount)")
  448. })
  449. task.observe(StorageTaskStatus.failure, handler: { snapshot in
  450. XCTAssertNil(snapshot.error, "Error should be nil")
  451. })
  452. })
  453. waitForExpectations()
  454. }
  455. func testCancelDownload() throws {
  456. let expectation = self.expectation(description: #function)
  457. let ref = storage.reference(withPath: "ios/public/1mb")
  458. let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
  459. let fileURL = tmpDirURL.appendingPathComponent("hello.dat")
  460. let task = ref.write(toFile: fileURL)
  461. var failed = false // Only fail once
  462. task.observe(StorageTaskStatus.failure, handler: { snapshot in
  463. XCTAssertTrue(snapshot.description.starts(with: "<State: Failed"))
  464. if !failed {
  465. failed = true
  466. expectation.fulfill()
  467. }
  468. })
  469. task.observe(StorageTaskStatus.progress, handler: { _ in
  470. task.cancel()
  471. })
  472. waitForExpectations()
  473. }
  474. private func assertMetadata(actualMetadata: StorageMetadata,
  475. expectedContentType: String,
  476. expectedCustomMetadata: [String: String]) {
  477. XCTAssertEqual(actualMetadata.cacheControl, "cache-control")
  478. XCTAssertEqual(actualMetadata.contentDisposition, "content-disposition")
  479. XCTAssertEqual(actualMetadata.contentEncoding, "gzip")
  480. XCTAssertEqual(actualMetadata.contentLanguage, "de")
  481. XCTAssertEqual(actualMetadata.contentType, expectedContentType)
  482. XCTAssertEqual(actualMetadata.md5Hash?.count, 24)
  483. for (key, value) in expectedCustomMetadata {
  484. XCTAssertEqual(actualMetadata.customMetadata![key], value)
  485. }
  486. }
  487. private func assertMetadataNil(actualMetadata: StorageMetadata) {
  488. XCTAssertNil(actualMetadata.cacheControl)
  489. XCTAssertNil(actualMetadata.contentDisposition)
  490. XCTAssertEqual(actualMetadata.contentEncoding, "identity")
  491. XCTAssertNil(actualMetadata.contentLanguage)
  492. XCTAssertNil(actualMetadata.contentType)
  493. XCTAssertEqual(actualMetadata.md5Hash?.count, 24)
  494. XCTAssertNil(actualMetadata.customMetadata)
  495. }
  496. func testUpdateMetadata2() {
  497. let expectation = self.expectation(description: #function)
  498. let ref = storage.reference(withPath: "ios/public/1mb")
  499. let metadata = StorageMetadata()
  500. metadata.cacheControl = "cache-control"
  501. metadata.contentDisposition = "content-disposition"
  502. metadata.contentEncoding = "gzip"
  503. metadata.contentLanguage = "de"
  504. metadata.contentType = "content-type-a"
  505. metadata.customMetadata = ["a": "b"]
  506. ref.updateMetadata(metadata, completion: { updatedMetadata, error in
  507. XCTAssertNil(error, "Error should be nil")
  508. guard let updatedMetadata = updatedMetadata else {
  509. XCTFail("Metadata is nil")
  510. return
  511. }
  512. self.assertMetadata(actualMetadata: updatedMetadata,
  513. expectedContentType: "content-type-a",
  514. expectedCustomMetadata: ["a": "b"])
  515. let metadata = updatedMetadata
  516. metadata.contentType = "content-type-b"
  517. metadata.customMetadata = ["a": "b", "c": "d"]
  518. ref.updateMetadata(metadata, completion: { updatedMetadata, error in
  519. XCTAssertNil(error, "Error should be nil")
  520. self.assertMetadata(actualMetadata: updatedMetadata!,
  521. expectedContentType: "content-type-b",
  522. expectedCustomMetadata: ["a": "b", "c": "d"])
  523. guard let metadata = updatedMetadata else {
  524. XCTFail("Metadata is nil")
  525. return
  526. }
  527. metadata.cacheControl = nil
  528. metadata.contentDisposition = nil
  529. metadata.contentEncoding = nil
  530. metadata.contentLanguage = nil
  531. metadata.contentType = nil
  532. metadata.customMetadata = Dictionary()
  533. ref.updateMetadata(metadata, completion: { updatedMetadata, error in
  534. XCTAssertNil(error, "Error should be nil")
  535. self.assertMetadataNil(actualMetadata: updatedMetadata!)
  536. expectation.fulfill()
  537. })
  538. })
  539. })
  540. waitForExpectations()
  541. }
  542. func testResumeGetFile() {
  543. let expectation = self.expectation(description: #function)
  544. let ref = storage.reference(withPath: "ios/public/1mb")
  545. let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
  546. let fileURL = tmpDirURL.appendingPathComponent("hello.txt")
  547. let task = ref.write(toFile: fileURL)
  548. task.observe(StorageTaskStatus.success, handler: { snapshot in
  549. XCTAssertEqual(snapshot.description, "<State: Success>")
  550. expectation.fulfill()
  551. })
  552. var resumeAtBytes: Int32 = 256 * 1024
  553. var downloadedBytes: Int64 = 0
  554. var computationResult: Double = 0.0
  555. task.observe(StorageTaskStatus.progress, handler: { snapshot in
  556. XCTAssertTrue(snapshot.description.starts(with: "<State: Progress") ||
  557. snapshot.description.starts(with: "<State: Resume"))
  558. guard let progress = snapshot.progress else {
  559. XCTFail("Failed to get snapshot.progress")
  560. return
  561. }
  562. XCTAssertGreaterThanOrEqual(progress.completedUnitCount, downloadedBytes)
  563. downloadedBytes = progress.completedUnitCount
  564. if progress.completedUnitCount > resumeAtBytes {
  565. // Making sure the main run loop is busy.
  566. for i: Int32 in 0 ... 499 {
  567. DispatchQueue.global(qos: .default).async {
  568. computationResult = sqrt(Double(INT_MAX - i))
  569. }
  570. }
  571. print("Pausing")
  572. task.pause()
  573. resumeAtBytes = INT_MAX
  574. }
  575. })
  576. task.observe(StorageTaskStatus.pause, handler: { snapshot in
  577. XCTAssertEqual(snapshot.description, "<State: Paused>")
  578. print("Resuming")
  579. task.resume()
  580. })
  581. waitForExpectations()
  582. XCTAssertEqual(INT_MAX, resumeAtBytes)
  583. XCTAssertEqual(sqrt(Double(INT_MAX - 499)), computationResult, accuracy: 0.1)
  584. }
  585. func testResumeGetFileInBackgroundQueue() {
  586. let expectation = self.expectation(description: #function)
  587. let ref = storage.reference(withPath: "ios/public/1mb")
  588. let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
  589. let fileURL = tmpDirURL.appendingPathComponent("hello.txt")
  590. let task = ref.write(toFile: fileURL)
  591. task.observe(StorageTaskStatus.success, handler: { snapshot in
  592. XCTAssertEqual(snapshot.description, "<State: Success>")
  593. expectation.fulfill()
  594. })
  595. var resumeAtBytes: Int32 = 256 * 1024
  596. var downloadedBytes: Int64 = 0
  597. task.observe(StorageTaskStatus.progress, handler: { snapshot in
  598. XCTAssertTrue(snapshot.description.starts(with: "<State: Progress") ||
  599. snapshot.description.starts(with: "<State: Resume"))
  600. guard let progress = snapshot.progress else {
  601. XCTFail("Failed to get snapshot.progress")
  602. return
  603. }
  604. XCTAssertGreaterThanOrEqual(progress.completedUnitCount, downloadedBytes)
  605. downloadedBytes = progress.completedUnitCount
  606. if progress.completedUnitCount > resumeAtBytes {
  607. print("Pausing")
  608. DispatchQueue.global(qos: .background).async {
  609. task.pause()
  610. }
  611. resumeAtBytes = INT_MAX
  612. }
  613. })
  614. task.observe(StorageTaskStatus.pause, handler: { snapshot in
  615. XCTAssertEqual(snapshot.description, "<State: Paused>")
  616. print("Resuming")
  617. task.resume()
  618. })
  619. waitForExpectations()
  620. XCTAssertEqual(INT_MAX, resumeAtBytes)
  621. }
  622. func testPagedListFiles() {
  623. let expectation = self.expectation(description: #function)
  624. let ref = storage.reference(withPath: "ios/public/list")
  625. ref.list(maxResults: 2) { listResult, error in
  626. XCTAssertNotNil(listResult, "listResult should not be nil")
  627. XCTAssertNil(error, "Error should be nil")
  628. XCTAssertEqual(listResult.items, [ref.child("a"), ref.child("b")])
  629. XCTAssertEqual(listResult.prefixes, [])
  630. guard let pageToken = listResult.pageToken else {
  631. XCTFail("pageToken should not be nil")
  632. return
  633. }
  634. ref.list(maxResults: 2, pageToken: pageToken) { listResult, error in
  635. XCTAssertNotNil(listResult, "listResult should not be nil")
  636. XCTAssertNil(error, "Error should be nil")
  637. XCTAssertEqual(listResult.items, [])
  638. XCTAssertEqual(listResult.prefixes, [ref.child("prefix")])
  639. XCTAssertNil(listResult.pageToken, "pageToken should be nil")
  640. expectation.fulfill()
  641. }
  642. }
  643. waitForExpectations()
  644. }
  645. func testListAllFiles() {
  646. let expectation = self.expectation(description: #function)
  647. let ref = storage.reference(withPath: "ios/public/list")
  648. ref.listAll { listResult, error in
  649. XCTAssertNotNil(listResult, "listResult should not be nil")
  650. XCTAssertNil(error, "Error should be nil")
  651. XCTAssertEqual(listResult.items, [ref.child("a"), ref.child("b")])
  652. XCTAssertEqual(listResult.prefixes, [ref.child("prefix")])
  653. XCTAssertNil(listResult.pageToken, "pageToken should be nil")
  654. expectation.fulfill()
  655. }
  656. waitForExpectations()
  657. }
  658. private func signInAndWait() {
  659. let expectation = self.expectation(description: #function)
  660. auth.signIn(withEmail: Credentials.kUserName,
  661. password: Credentials.kPassword) { result, error in
  662. XCTAssertNil(error)
  663. StorageIntegration.signedIn = true
  664. print("Successfully signed in")
  665. expectation.fulfill()
  666. }
  667. waitForExpectations()
  668. }
  669. private func waitForExpectations() {
  670. let kFIRStorageIntegrationTestTimeout = 60.0
  671. waitForExpectations(timeout: kFIRStorageIntegrationTestTimeout,
  672. handler: { (error) -> Void in
  673. if let error = error {
  674. print(error)
  675. }
  676. })
  677. }
  678. }