StorageReferenceTests.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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(\"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)", "pathError(\"Internal error: URL scheme must be one of gs://, " +
  86. "http://, or https://\")")
  87. }
  88. }
  89. func testSingleChild() throws {
  90. let ref = storage!.reference(forURL: "gs://bucket/")
  91. let childRef = ref.child("path")
  92. XCTAssertEqual(childRef.description, "gs://bucket/path")
  93. }
  94. func testMultipleChildrenSingleString() throws {
  95. let ref = storage!.reference(forURL: "gs://bucket/")
  96. let childRef = ref.child("path/to/object")
  97. XCTAssertEqual(childRef.description, "gs://bucket/path/to/object")
  98. }
  99. func testMultipleChildrenMultipleStrings() throws {
  100. let ref = storage!.reference(forURL: "gs://bucket/")
  101. let childRef = ref.child("path").child("to").child("object")
  102. XCTAssertEqual(childRef.description, "gs://bucket/path/to/object")
  103. }
  104. func testSameChildDifferentRef() throws {
  105. let ref = storage!.reference(forURL: "gs://bucket/")
  106. let firstRef = ref.child("1")
  107. let secondRef = ref.child("1")
  108. XCTAssertEqual(ref.description, "gs://bucket/")
  109. XCTAssertTrue(firstRef == secondRef)
  110. XCTAssertFalse(firstRef === secondRef)
  111. }
  112. func testDifferentChildDifferentRef() throws {
  113. let ref = storage!.reference(forURL: "gs://bucket/")
  114. let firstRef = ref.child("1")
  115. let secondRef = ref.child("2")
  116. XCTAssertEqual(ref.description, "gs://bucket/")
  117. XCTAssertFalse(firstRef == secondRef)
  118. XCTAssertFalse(firstRef === secondRef)
  119. }
  120. func testChildWithTrailingSlash() throws {
  121. let ref = storage!.reference(forURL: "gs://bucket/path/to/object/")
  122. XCTAssertEqual(ref.description, "gs://bucket/path/to/object")
  123. }
  124. func testChildWithLeadingSlash() throws {
  125. let ref = storage!.reference(forURL: "gs://bucket//path/to/object/")
  126. XCTAssertEqual(ref.description, "gs://bucket/path/to/object")
  127. }
  128. func testChildCompressSlashes() throws {
  129. let ref = storage!.reference(forURL: "gs://bucket//path/////to////object////")
  130. XCTAssertEqual(ref.description, "gs://bucket/path/to/object")
  131. }
  132. func testParent() throws {
  133. let ref = storage!.reference(forURL: "gs://bucket//path/to/object/")
  134. let parentRef = try XCTUnwrap(ref.parent())
  135. XCTAssertEqual(parentRef.description, "gs://bucket/path/to")
  136. }
  137. func testParentToRoot() throws {
  138. let ref = storage!.reference(forURL: "gs://bucket/path")
  139. let parentRef = try XCTUnwrap(ref.parent())
  140. XCTAssertEqual(parentRef.description, "gs://bucket/")
  141. }
  142. func testParentToRootTrailingSlash() throws {
  143. let ref = storage!.reference(forURL: "gs://bucket/path/")
  144. let parentRef = try XCTUnwrap(ref.parent())
  145. XCTAssertEqual(parentRef.description, "gs://bucket/")
  146. }
  147. func testParentAtRoot() throws {
  148. let ref = storage!.reference(forURL: "gs://bucket/")
  149. XCTAssertNil(ref.parent())
  150. }
  151. func testBucket() throws {
  152. let ref = storage!.reference(forURL: "gs://bucket//path/to/object/")
  153. XCTAssertEqual(ref.bucket, "bucket")
  154. }
  155. func testName() throws {
  156. let ref = storage!.reference(forURL: "gs://bucket/path/to/object/")
  157. XCTAssertEqual(ref.name, "object")
  158. }
  159. func testNameNoObject() throws {
  160. let ref = storage!.reference(forURL: "gs://bucket/")
  161. XCTAssertEqual(ref.name, "")
  162. }
  163. func testFullPath() throws {
  164. let ref = storage!.reference(forURL: "gs://bucket/path/to/object/")
  165. XCTAssertEqual(ref.fullPath, "path/to/object")
  166. }
  167. func testFullPathNoObject() throws {
  168. let ref = storage!.reference(forURL: "gs://bucket/")
  169. XCTAssertEqual(ref.fullPath, "")
  170. }
  171. func testCopy() throws {
  172. let ref = storage!.reference(forURL: "gs://bucket/")
  173. let copiedRef = ref.copy() as? StorageReference
  174. XCTAssertTrue(ref == copiedRef)
  175. XCTAssertFalse(ref === copiedRef)
  176. }
  177. func testReferenceWithNonExistentFileFailsWithCompletionResult() throws {
  178. let tempFilePath = NSTemporaryDirectory().appending("temp.data")
  179. let ref = storage!.reference(withPath: tempFilePath)
  180. let dummyFileURL = try XCTUnwrap(URL(string: "some_non_existing-folder/file.data"))
  181. let expectation = self.expectation(description: #function)
  182. ref.putFile(from: dummyFileURL) { result in
  183. expectation.fulfill()
  184. switch result {
  185. case .success:
  186. XCTFail("Unexpected success.", file: #file, line: #line)
  187. case let .failure(error):
  188. switch error {
  189. case let StorageError.unknown(message):
  190. let expectedDescription = "File at URL: \(dummyFileURL.absoluteString) " +
  191. "is not reachable. Ensure file URL is not a directory, symbolic link, or invalid url."
  192. XCTAssertEqual(expectedDescription, message)
  193. default:
  194. XCTFail("Failed to match expected Internal Error")
  195. }
  196. }
  197. }
  198. waitForExpectations(timeout: 0.5)
  199. }
  200. func testReferenceWithNonExistentFileFailsWithCompletionCallback() throws {
  201. let tempFilePath = NSTemporaryDirectory().appending("temp.data")
  202. let ref = storage!.reference(withPath: tempFilePath)
  203. let dummyFileURL = try XCTUnwrap(URL(string: "some_non_existing-folder/file.data"))
  204. let expectation = self.expectation(description: #function)
  205. ref.putFile(from: dummyFileURL) { metadata, error in
  206. expectation.fulfill()
  207. XCTAssertNil(metadata)
  208. let nsError = (error as? NSError)!
  209. XCTAssertEqual(nsError.code, StorageErrorCode.unknown.rawValue)
  210. let expectedDescription = "File at URL: \(dummyFileURL.absoluteString) " +
  211. "is not reachable. Ensure file URL is not a directory, symbolic link, or invalid url."
  212. XCTAssertEqual(expectedDescription, nsError.localizedDescription)
  213. XCTAssertEqual(nsError.domain, StorageErrorDomain)
  214. }
  215. waitForExpectations(timeout: 0.5)
  216. }
  217. func testReferenceWithNilFileFailsWithCompletionCallback() throws {
  218. let tempFilePath = NSTemporaryDirectory().appending("temp.data")
  219. let ref = storage!.reference(withPath: tempFilePath)
  220. let dummyFileURL = try XCTUnwrap(URL(string: "bad-url"))
  221. let expectation = self.expectation(description: #function)
  222. ref.putFile(from: dummyFileURL) { metadata, error in
  223. expectation.fulfill()
  224. XCTAssertNil(metadata)
  225. let nsError = (error as? NSError)!
  226. XCTAssertEqual(nsError.code, StorageErrorCode.unknown.rawValue)
  227. let expectedDescription = "File at URL: \(dummyFileURL.absoluteString) " +
  228. "is not reachable. Ensure file URL is not a directory, symbolic link, or invalid url."
  229. XCTAssertEqual(expectedDescription, nsError.localizedDescription)
  230. XCTAssertEqual(nsError.domain, StorageErrorDomain)
  231. }
  232. waitForExpectations(timeout: 1.0)
  233. }
  234. // MARK: Private Helpers
  235. // Cache the app associated with each Storage bucket
  236. private static var appDictionary: [String: FirebaseApp] = [:]
  237. private func getApp(bucket: String) throws -> FirebaseApp {
  238. let savedApp = StorageReferenceTests.appDictionary[bucket]
  239. guard savedApp == nil else {
  240. return try XCTUnwrap(savedApp)
  241. }
  242. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  243. gcmSenderID: "00000000000000000-00000000000-000000000")
  244. options.projectID = "myProjectID"
  245. options.storageBucket = bucket
  246. let name = "StorageTests\(bucket)"
  247. let app = FirebaseApp(instanceWithName: name, options: options)
  248. StorageReferenceTests.appDictionary[bucket] = app
  249. return app
  250. }
  251. }