StorageTests.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  22. class StorageTests: XCTestCase {
  23. override class func setUp() {
  24. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  25. gcmSenderID: "00000000000000000-00000000000-000000000")
  26. options.projectID = "myProjectID"
  27. FirebaseApp.configure(name: "test-StorageTests", options: options)
  28. }
  29. func testBucketNotEnforced() throws {
  30. let app = try getApp(bucket: "")
  31. let storage = Storage.storage(app: app)
  32. _ = storage.reference(forURL: "gs://benwu-test1.storage.firebase.com/child")
  33. _ = storage.reference(forURL: "gs://benwu-test2.storage.firebase.com/child")
  34. }
  35. func testBucketEnforced() throws {
  36. let app = try getApp(bucket: "bucket")
  37. let storage = Storage.storage(app: app, url: "gs://benwu-test1.storage.firebase.com")
  38. let url = try XCTUnwrap(URL(string: "gs://benwu-test2.storage.firebase.com/child"))
  39. XCTAssertThrowsError(try storage.reference(for: url), "This was supposed to fail.") { error in
  40. XCTAssertEqual(
  41. "\(error)",
  42. "bucketMismatch(message: \"Provided bucket: `benwu-test2.storage.firebase.com` does not match the " +
  43. "Storage bucket of the current instance: `benwu-test1.storage.firebase.com`\")"
  44. )
  45. }
  46. }
  47. func testInitWithCustomURL() throws {
  48. let app = try getApp(bucket: "bucket")
  49. let storage = Storage.storage(app: app, url: "gs://foo-bar.appspot.com")
  50. XCTAssertEqual("gs://foo-bar.appspot.com/", storage.reference().description)
  51. let storage2 = Storage.storage(app: app, url: "gs://foo-bar.appspot.com/")
  52. XCTAssertEqual("gs://foo-bar.appspot.com/", storage2.reference().description)
  53. }
  54. func SKIPtestInitWithWrongScheme() throws {
  55. let app = try getApp(bucket: "bucket")
  56. XCTAssertThrowsObjCException {
  57. _ = Storage.storage(app: app, url: "http://foo-bar.appspot.com")
  58. }
  59. }
  60. func SKIPtestInitWithNoScheme() throws {
  61. let app = try getApp(bucket: "bucket")
  62. XCTAssertThrowsObjCException {
  63. _ = Storage.storage(app: app, url: "foo-bar.appspot.com")
  64. }
  65. }
  66. func testInitWithoutURL() throws {
  67. let app = try getApp(bucket: "bucket")
  68. XCTAssertNoThrowObjCException {
  69. _ = Storage.storage(app: app)
  70. }
  71. }
  72. func SKIPtestInitWithPath() throws {
  73. let app = try getApp(bucket: "bucket")
  74. XCTAssertThrowsObjCException {
  75. _ = Storage.storage(app: app, url: "gs://foo-bar.appspot.com/child")
  76. }
  77. }
  78. func testInitWithDefaultAndCustomURL() throws {
  79. let app = try getApp(bucket: "bucket")
  80. let defaultInstance = Storage.storage(app: app)
  81. let customInstance = Storage.storage(app: app, url: "gs://foo-bar.appspot.com")
  82. XCTAssertEqual("gs://foo-bar.appspot.com/", customInstance.reference().description)
  83. XCTAssertEqual("gs://bucket/", defaultInstance.reference().description)
  84. }
  85. func testStorageDefaultApp() throws {
  86. let app = try getApp(bucket: "bucket")
  87. let storage = Storage.storage(app: app)
  88. XCTAssertEqual(storage.app.name, app.name)
  89. }
  90. func SKIPtestStorageNoBucketInConfig() throws {
  91. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  92. gcmSenderID: "00000000000000000-00000000000-000000000")
  93. options.projectID = "myProjectID"
  94. let name = "StorageTestsNil"
  95. let app = FirebaseApp(instanceWithName: name, options: options)
  96. XCTAssertThrowsObjCException {
  97. _ = Storage.storage(app: app)
  98. }
  99. }
  100. func testStorageEmptyBucketInConfig() throws {
  101. let app = try getApp(bucket: "")
  102. let storage = Storage.storage(app: app)
  103. let ref = storage.reference(forURL: "gs://bucket/path/to/object")
  104. XCTAssertEqual(ref.bucket, "bucket")
  105. }
  106. func testStorageWrongBucketInConfig() throws {
  107. let app = try getApp(bucket: "notMyBucket")
  108. let storage = Storage.storage(app: app)
  109. let url = try XCTUnwrap(URL(string: "gs://bucket/path/to/object"))
  110. XCTAssertThrowsError(try storage.reference(for: url), "This was supposed to fail.") { error in
  111. XCTAssertEqual(
  112. "\(error)",
  113. "bucketMismatch(message: \"Provided bucket: `bucket` does not match the " +
  114. "Storage bucket of the current instance: `notMyBucket`\")"
  115. )
  116. }
  117. }
  118. func testUseEmulator() throws {
  119. let app = try getApp(bucket: "bucket-for-testUseEmulator")
  120. let storage = Storage.storage(app: app)
  121. storage.useEmulator(withHost: "localhost", port: 8080)
  122. XCTAssertNoThrow(storage.reference())
  123. }
  124. func SKIPtestUseEmulatorValidatesHost() throws {
  125. let app = try getApp(bucket: "bucket")
  126. let storage = Storage.storage(app: app, url: "gs://foo-bar.appspot.com")
  127. XCTAssertThrowsObjCException {
  128. storage.useEmulator(withHost: "", port: 8080)
  129. }
  130. }
  131. func SKIPtestUseEmulatorValidatesPort() throws {
  132. let app = try getApp(bucket: "bucket")
  133. let storage = Storage.storage(app: app, url: "gs://foo-bar.appspot.com")
  134. XCTAssertThrowsObjCException {
  135. storage.useEmulator(withHost: "localhost", port: -1)
  136. }
  137. }
  138. func SKIPtestUseEmulatorCannotBeCalledAfterObtainingReference() throws {
  139. let app = try getApp(bucket: "bucket")
  140. let storage = Storage.storage(app: app, url: "gs://benwu-test1.storage.firebase.com")
  141. _ = storage.reference()
  142. XCTAssertThrowsObjCException {
  143. storage.useEmulator(withHost: "localhost", port: 8080)
  144. }
  145. }
  146. func testRefDefaultApp() throws {
  147. let app = try getApp(bucket: "bucket")
  148. let storage = Storage(app: app, bucket: "bucket")
  149. let convenienceRef = storage.reference(forURL: "gs://bucket/path/to/object")
  150. let path = StoragePath(with: "bucket", object: "path/to/object")
  151. let builtRef = StorageReference(storage: storage, path: path)
  152. XCTAssertEqual(convenienceRef.description, builtRef.description)
  153. XCTAssertEqual(convenienceRef.storage.app, builtRef.storage.app)
  154. }
  155. func testRefCustomApp() throws {
  156. let secondApp = try getApp(bucket: "bucket2")
  157. let storage2 = Storage.storage(app: secondApp)
  158. let convenienceRef = storage2.reference(forURL: "gs://bucket2/path/to/object")
  159. let path = StoragePath(with: "bucket2", object: "path/to/object")
  160. let builtRef = StorageReference(storage: storage2, path: path)
  161. XCTAssertEqual(convenienceRef.description, builtRef.description)
  162. XCTAssertEqual(convenienceRef.storage.app, builtRef.storage.app)
  163. }
  164. func testRootRefDefaultApp() throws {
  165. let app = try getApp(bucket: "bucket")
  166. let storage = Storage.storage(app: app)
  167. let convenienceRef = storage.reference()
  168. let path = StoragePath(with: "bucket")
  169. let builtRef = StorageReference(storage: storage, path: path)
  170. XCTAssertEqual(convenienceRef.description, builtRef.description)
  171. XCTAssertEqual(convenienceRef.storage.app, builtRef.storage.app)
  172. }
  173. func testRefWithPathDefaultApp() throws {
  174. let app = try getApp(bucket: "bucket")
  175. let storage = Storage.storage(app: app)
  176. let convenienceRef = storage.reference(forURL: "gs://bucket/path/to/object")
  177. let path = StoragePath(with: "bucket", object: "path/to/object")
  178. let builtRef = StorageReference(storage: storage, path: path)
  179. XCTAssertEqual(convenienceRef.description, builtRef.description)
  180. XCTAssertEqual(convenienceRef.storage.app, builtRef.storage.app)
  181. }
  182. func testEqual() throws {
  183. let app = try getApp(bucket: "bucket")
  184. let storage = Storage.storage(app: app)
  185. let copy = try XCTUnwrap(storage.copy() as? Storage)
  186. XCTAssertEqual(storage.app.name, copy.app.name)
  187. XCTAssertEqual(storage.hash, copy.hash)
  188. }
  189. func testNotEqual() throws {
  190. let app = try getApp(bucket: "bucket")
  191. let storage = Storage.storage(app: app)
  192. let secondApp = try getApp(bucket: "bucket2")
  193. let storage2 = Storage.storage(app: secondApp)
  194. XCTAssertNotEqual(storage, storage2)
  195. XCTAssertNotEqual(storage.hash, storage2.hash)
  196. }
  197. func testHash() throws {
  198. let app = try getApp(bucket: "bucket")
  199. let storage = Storage.storage(app: app)
  200. let copy = try XCTUnwrap(storage.copy() as? Storage)
  201. XCTAssertEqual(storage.app.name, copy.app.name)
  202. }
  203. func testTranslateRetryTime() {
  204. // The 1st retry attempt runs after 1 second.
  205. // The 2nd retry attempt is delayed by 2 seconds (3s total)
  206. // The 3rd retry attempt is delayed by 4 seconds (7s total)
  207. // The 4th retry attempt is delayed by 8 seconds (15s total)
  208. // The 5th retry attempt is delayed by 16 seconds (31s total)
  209. // The 6th retry attempt is delayed by 32 seconds (63s total)
  210. // Thus, we should exit just between the 5th and 6th retry attempt and cut off before 32s.
  211. XCTAssertEqual(1.0, Storage.computeRetryInterval(fromRetryTime: 1.0))
  212. XCTAssertEqual(2.0, Storage.computeRetryInterval(fromRetryTime: 2.0))
  213. XCTAssertEqual(4.0, Storage.computeRetryInterval(fromRetryTime: 4.0))
  214. XCTAssertEqual(8.0, Storage.computeRetryInterval(fromRetryTime: 10.0))
  215. XCTAssertEqual(16.0, Storage.computeRetryInterval(fromRetryTime: 20.0))
  216. XCTAssertEqual(16.0, Storage.computeRetryInterval(fromRetryTime: 30.0))
  217. XCTAssertEqual(32.0, Storage.computeRetryInterval(fromRetryTime: 40.0))
  218. XCTAssertEqual(32.0, Storage.computeRetryInterval(fromRetryTime: 50.0))
  219. XCTAssertEqual(32.0, Storage.computeRetryInterval(fromRetryTime: 60.0))
  220. }
  221. func testRetryTimeChange() throws {
  222. let app = try getApp(bucket: "")
  223. let storage = Storage.storage(app: app)
  224. XCTAssertEqual(storage.maxOperationRetryInterval, 64)
  225. storage.maxOperationRetryTime = 11
  226. XCTAssertEqual(storage.maxOperationRetryTime, 11)
  227. XCTAssertEqual(storage.maxOperationRetryInterval, 8)
  228. }
  229. // MARK: Private Helpers
  230. // Cache the app associated with each Storage bucket
  231. private static var appDictionary: [String: FirebaseApp] = [:]
  232. private func getApp(bucket: String) throws -> FirebaseApp {
  233. let savedApp = StorageTests.appDictionary[bucket]
  234. guard savedApp == nil else {
  235. return try XCTUnwrap(savedApp)
  236. }
  237. let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:0000000000000000",
  238. gcmSenderID: "00000000000000000-00000000000-000000000")
  239. options.projectID = "myProjectID"
  240. options.storageBucket = bucket
  241. let name = "StorageTests\(bucket)"
  242. let app = FirebaseApp(instanceWithName: name, options: options)
  243. StorageTests.appDictionary[bucket] = app
  244. return app
  245. }
  246. private func XCTAssertThrowsObjCException(_ closure: @escaping () -> Void) {
  247. XCTAssertThrowsError(try ExceptionCatcher.catchException(closure))
  248. }
  249. private func XCTAssertNoThrowObjCException(_ closure: @escaping () -> Void) {
  250. XCTAssertNoThrow(try ExceptionCatcher.catchException(closure))
  251. }
  252. }