StorageReferenceTests.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // Copyright 2022 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 Foundation
  15. import FirebaseCore
  16. @testable import FirebaseStorage
  17. import FirebaseAppCheckInterop
  18. import FirebaseAuthInterop
  19. import SharedTestUtilities
  20. import XCTest
  21. class StorageReferenceTests: XCTestCase {
  22. override class func setUp() {
  23. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  24. gcmSenderID: "00000000000000000-00000000000-000000000")
  25. options.projectID = "myProjectID-Ref"
  26. FirebaseApp.configure(name: "test-StorageReference", options: options)
  27. }
  28. var storage: Storage?
  29. override func setUp() {
  30. guard let app = try? getApp(bucket: "bucket") else {
  31. fatalError("")
  32. }
  33. storage = Storage.storage(app: app)
  34. }
  35. func testRoot() throws {
  36. let ref = storage!.reference(forURL: "gs://bucket/path/to/object")
  37. XCTAssertEqual(ref.root().description, "gs://bucket/")
  38. }
  39. func testRootWithURLAPI() throws {
  40. let url = try XCTUnwrap(URL(string: "gs://bucket/path/to/object"))
  41. let ref = try storage!.reference(for: url)
  42. XCTAssertEqual(ref.root().description, "gs://bucket/")
  43. }
  44. func testRootWithNoPath() throws {
  45. let ref = storage!.reference(forURL: "gs://bucket/")
  46. XCTAssertEqual(ref.root().description, "gs://bucket/")
  47. }
  48. func testMismatchedBucket() throws {
  49. do {
  50. let url = try XCTUnwrap(URL(string: "gs://bcket/"))
  51. _ = try storage!.reference(for: url)
  52. } catch let StorageError.bucketMismatch(string) {
  53. XCTAssertEqual(string, "Provided bucket: `bcket` does not match the Storage " +
  54. "bucket of the current instance: `bucket`")
  55. return
  56. }
  57. XCTFail()
  58. }
  59. func testMismatchedBucket2() throws {
  60. let url = try XCTUnwrap(URL(string: "gs://bcket/"))
  61. XCTAssertThrowsError(try storage!.reference(for: url), "This was supposed to fail.") { error in
  62. XCTAssertEqual(
  63. "\(error)",
  64. "bucketMismatch(message: \"Provided bucket: `bcket` does not match the Storage " +
  65. "bucket of the current instance: `bucket`\")"
  66. )
  67. }
  68. }
  69. func testBadBucketScheme() throws {
  70. do {
  71. let url = try XCTUnwrap(URL(string: "htttp://bucket/"))
  72. _ = try storage!.reference(for: url)
  73. } catch let StorageError.pathError(string) {
  74. XCTAssertEqual(
  75. string,
  76. "Internal error: URL scheme must be one of gs://, http://, or https://"
  77. )
  78. return
  79. }
  80. XCTFail()
  81. }
  82. func testBadBucketScheme2() throws {
  83. let url = try XCTUnwrap(URL(string: "htttp://bucket/"))
  84. XCTAssertThrowsError(try storage!.reference(for: url), "This was supposed to fail.") { error in
  85. XCTAssertEqual("\(error)",
  86. "pathError(message: \"Internal error: URL scheme must be one of gs://, " +
  87. "http://, or https://\")")
  88. }
  89. }
  90. func testSingleChild() throws {
  91. let ref = storage!.reference(forURL: "gs://bucket/")
  92. let childRef = ref.child("path")
  93. XCTAssertEqual(childRef.description, "gs://bucket/path")
  94. }
  95. func testMultipleChildrenSingleString() throws {
  96. let ref = storage!.reference(forURL: "gs://bucket/")
  97. let childRef = ref.child("path/to/object")
  98. XCTAssertEqual(childRef.description, "gs://bucket/path/to/object")
  99. }
  100. func testMultipleChildrenMultipleStrings() throws {
  101. let ref = storage!.reference(forURL: "gs://bucket/")
  102. let childRef = ref.child("path").child("to").child("object")
  103. XCTAssertEqual(childRef.description, "gs://bucket/path/to/object")
  104. }
  105. func testSameChildDifferentRef() throws {
  106. let ref = storage!.reference(forURL: "gs://bucket/")
  107. let firstRef = ref.child("1")
  108. let secondRef = ref.child("1")
  109. XCTAssertEqual(ref.description, "gs://bucket/")
  110. XCTAssertTrue(firstRef == secondRef)
  111. XCTAssertFalse(firstRef === secondRef)
  112. }
  113. func testDifferentChildDifferentRef() throws {
  114. let ref = storage!.reference(forURL: "gs://bucket/")
  115. let firstRef = ref.child("1")
  116. let secondRef = ref.child("2")
  117. XCTAssertEqual(ref.description, "gs://bucket/")
  118. XCTAssertFalse(firstRef == secondRef)
  119. XCTAssertFalse(firstRef === secondRef)
  120. }
  121. func testChildWithTrailingSlash() throws {
  122. let ref = storage!.reference(forURL: "gs://bucket/path/to/object/")
  123. XCTAssertEqual(ref.description, "gs://bucket/path/to/object")
  124. }
  125. func testChildWithLeadingSlash() throws {
  126. let ref = storage!.reference(forURL: "gs://bucket//path/to/object/")
  127. XCTAssertEqual(ref.description, "gs://bucket/path/to/object")
  128. }
  129. func testChildCompressSlashes() throws {
  130. let ref = storage!.reference(forURL: "gs://bucket//path/////to////object////")
  131. XCTAssertEqual(ref.description, "gs://bucket/path/to/object")
  132. }
  133. func testParent() throws {
  134. let ref = storage!.reference(forURL: "gs://bucket//path/to/object/")
  135. let parentRef = try XCTUnwrap(ref.parent())
  136. XCTAssertEqual(parentRef.description, "gs://bucket/path/to")
  137. }
  138. func testParentToRoot() throws {
  139. let ref = storage!.reference(forURL: "gs://bucket/path")
  140. let parentRef = try XCTUnwrap(ref.parent())
  141. XCTAssertEqual(parentRef.description, "gs://bucket/")
  142. }
  143. func testParentToRootTrailingSlash() throws {
  144. let ref = storage!.reference(forURL: "gs://bucket/path/")
  145. let parentRef = try XCTUnwrap(ref.parent())
  146. XCTAssertEqual(parentRef.description, "gs://bucket/")
  147. }
  148. func testParentAtRoot() throws {
  149. let ref = storage!.reference(forURL: "gs://bucket/")
  150. XCTAssertNil(ref.parent())
  151. }
  152. func testBucket() throws {
  153. let ref = storage!.reference(forURL: "gs://bucket//path/to/object/")
  154. XCTAssertEqual(ref.bucket, "bucket")
  155. }
  156. func testName() throws {
  157. let ref = storage!.reference(forURL: "gs://bucket/path/to/object/")
  158. XCTAssertEqual(ref.name, "object")
  159. }
  160. func testNameNoObject() throws {
  161. let ref = storage!.reference(forURL: "gs://bucket/")
  162. XCTAssertEqual(ref.name, "")
  163. }
  164. func testFullPath() throws {
  165. let ref = storage!.reference(forURL: "gs://bucket/path/to/object/")
  166. XCTAssertEqual(ref.fullPath, "path/to/object")
  167. }
  168. func testFullPathNoObject() throws {
  169. let ref = storage!.reference(forURL: "gs://bucket/")
  170. XCTAssertEqual(ref.fullPath, "")
  171. }
  172. func testCopy() throws {
  173. let ref = storage!.reference(forURL: "gs://bucket/")
  174. let copiedRef = ref.copy() as? StorageReference
  175. XCTAssertTrue(ref == copiedRef)
  176. XCTAssertFalse(ref === copiedRef)
  177. }
  178. func testReferenceWithNonExistentFileFailsWithCompletionResult() throws {
  179. let tempFilePath = NSTemporaryDirectory().appending("temp.data")
  180. let ref = storage!.reference(withPath: tempFilePath)
  181. let dummyFileURL = try XCTUnwrap(URL(string: "some_non_existing-folder/file.data"))
  182. let expectation = self.expectation(description: #function)
  183. ref.putFile(from: dummyFileURL) { result in
  184. expectation.fulfill()
  185. switch result {
  186. case .success:
  187. XCTFail("Unexpected success.", file: #file, line: #line)
  188. case let .failure(error):
  189. switch error {
  190. case let StorageError.unknown(message, serverError):
  191. let expectedDescription = "File at URL: \(dummyFileURL.absoluteString) " +
  192. "is not reachable. Ensure file URL is not a directory, symbolic link, or invalid url."
  193. XCTAssertEqual(expectedDescription, message)
  194. default:
  195. XCTFail("Failed to match expected Internal Error")
  196. }
  197. }
  198. }
  199. waitForExpectations(timeout: 0.5)
  200. }
  201. func testReferenceWithNonExistentFileFailsWithCompletionCallback() throws {
  202. let tempFilePath = NSTemporaryDirectory().appending("temp.data")
  203. let ref = storage!.reference(withPath: tempFilePath)
  204. let dummyFileURL = try XCTUnwrap(URL(string: "some_non_existing-folder/file.data"))
  205. let expectation = self.expectation(description: #function)
  206. ref.putFile(from: dummyFileURL) { metadata, error in
  207. expectation.fulfill()
  208. XCTAssertNil(metadata)
  209. let nsError = (error as? NSError)!
  210. XCTAssertEqual(nsError.code, StorageErrorCode.unknown.rawValue)
  211. let expectedDescription = "File at URL: \(dummyFileURL.absoluteString) " +
  212. "is not reachable. Ensure file URL is not a directory, symbolic link, or invalid url."
  213. XCTAssertEqual(expectedDescription, nsError.localizedDescription)
  214. XCTAssertEqual(nsError.domain, StorageErrorDomain)
  215. }
  216. waitForExpectations(timeout: 0.5)
  217. }
  218. func testReferenceWithNilFileFailsWithCompletionCallback() throws {
  219. let tempFilePath = NSTemporaryDirectory().appending("temp.data")
  220. let ref = storage!.reference(withPath: tempFilePath)
  221. let dummyFileURL = try XCTUnwrap(URL(string: "bad-url"))
  222. let expectation = self.expectation(description: #function)
  223. ref.putFile(from: dummyFileURL) { metadata, error in
  224. expectation.fulfill()
  225. XCTAssertNil(metadata)
  226. let nsError = (error as? NSError)!
  227. XCTAssertEqual(nsError.code, StorageErrorCode.unknown.rawValue)
  228. let expectedDescription = "File at URL: \(dummyFileURL.absoluteString) " +
  229. "is not reachable. Ensure file URL is not a directory, symbolic link, or invalid url."
  230. XCTAssertEqual(expectedDescription, nsError.localizedDescription)
  231. XCTAssertEqual(nsError.domain, StorageErrorDomain)
  232. }
  233. waitForExpectations(timeout: 1.0)
  234. }
  235. // MARK: Private Helpers
  236. // Cache the app associated with each Storage bucket
  237. private static var appDictionary: [String: FirebaseApp] = [:]
  238. private func getApp(bucket: String) throws -> FirebaseApp {
  239. let savedApp = StorageReferenceTests.appDictionary[bucket]
  240. guard savedApp == nil else {
  241. return try XCTUnwrap(savedApp)
  242. }
  243. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  244. gcmSenderID: "00000000000000000-00000000000-000000000")
  245. options.projectID = "myProjectID"
  246. options.storageBucket = bucket
  247. let name = "StorageTests\(bucket)"
  248. let app = FirebaseApp(instanceWithName: name, options: options)
  249. StorageReferenceTests.appDictionary[bucket] = app
  250. return app
  251. }
  252. }