StorageMetadataTests.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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. @testable import FirebaseStorage
  16. import GTMSessionFetcherCore
  17. import XCTest
  18. class StorageMetadataTests: StorageTestHelpers {
  19. func testInitializeNoMetadata() {
  20. let metadata = StorageMetadata(dictionary: [:])
  21. XCTAssertNotNil(metadata)
  22. }
  23. func testInitializeFullMetadata() {
  24. let metaDict = [
  25. "bucket": "bucket",
  26. "cacheControl": "max-age=3600, no-cache",
  27. "contentDisposition": "inline",
  28. "contentEncoding": "gzip",
  29. "contentLanguage": "en-us",
  30. "contentType": "application/octet-stream",
  31. "customMetadata": ["foo": ["bar": "baz"]],
  32. "generation": "12345",
  33. "metageneration": "67890",
  34. "name": "path/to/object",
  35. "timeCreated": "1992-08-07T17:22:53.108Z",
  36. "updated": "2016-03-01T20:16:01.673Z",
  37. "md5Hash": "d41d8cd98f00b204e9800998ecf8427e",
  38. "size": 1337,
  39. ] as [String: AnyHashable]
  40. let metadata = StorageMetadata(dictionary: metaDict)
  41. XCTAssertNotNil(metadata)
  42. XCTAssertEqual(metadata.bucket, metaDict["bucket"] as? String)
  43. XCTAssertEqual(metadata.cacheControl, metaDict["cacheControl"] as? String)
  44. XCTAssertEqual(metadata.contentDisposition, metaDict["contentDisposition"] as? String)
  45. XCTAssertEqual(metadata.contentEncoding, metaDict["contentEncoding"] as? String)
  46. XCTAssertEqual(metadata.contentType, metaDict["contentType"] as? String)
  47. XCTAssertEqual(metadata.customMetadata, metaDict["customMetadata"] as? [String: String])
  48. XCTAssertEqual(metadata.md5Hash, metaDict["md5Hash"] as? String)
  49. XCTAssertEqual("\(metadata.generation)", "12345")
  50. XCTAssertEqual("\(metadata.metageneration)", "67890")
  51. XCTAssertEqual(metadata.path, metaDict["name"] as? String)
  52. XCTAssertEqual(StorageMetadata.RFC3339StringFromDate(metadata.timeCreated!),
  53. metaDict["timeCreated"] as? String)
  54. XCTAssertEqual(StorageMetadata.RFC3339StringFromDate(metadata.updated!),
  55. metaDict["updated"] as? String)
  56. XCTAssertEqual(metadata.size, 1337)
  57. }
  58. func testDictionaryRepresentation() {
  59. let metaDict = [
  60. "bucket": "bucket",
  61. "cacheControl": "max-age=3600, no-cache",
  62. "contentDisposition": "inline",
  63. "contentEncoding": "gzip",
  64. "contentLanguage": "en-us",
  65. "contentType": "application/octet-stream",
  66. "customMetadata": ["foo": ["bar": "baz"]],
  67. "generation": "12345",
  68. "metageneration": "67890",
  69. "name": "path/to/object",
  70. "timeCreated": "1992-08-07T17:22:53.108Z",
  71. "updated": "2016-03-01T20:16:01.673Z",
  72. "md5Hash": "d41d8cd98f00b204e9800998ecf8427e",
  73. "size": 1337,
  74. ] as [String: AnyHashable]
  75. let metadata = StorageMetadata(dictionary: metaDict)
  76. let dictRepresentation = metadata.dictionaryRepresentation()
  77. XCTAssertNotNil(dictRepresentation)
  78. XCTAssertEqual(dictRepresentation["bucket"] as? String, metaDict["bucket"] as? String)
  79. XCTAssertEqual(
  80. dictRepresentation["cacheControl"] as? String,
  81. metaDict["cacheControl"] as? String
  82. )
  83. XCTAssertEqual(
  84. dictRepresentation["contentDisposition"] as? String,
  85. metaDict["contentDisposition"] as? String
  86. )
  87. XCTAssertEqual(
  88. dictRepresentation["contentEncoding"] as? String,
  89. metaDict["contentEncoding"] as? String
  90. )
  91. XCTAssertEqual(dictRepresentation["contentType"] as? String, metaDict["contentType"] as? String)
  92. XCTAssertEqual(dictRepresentation["customMetadata"] as? [String: String],
  93. metaDict["customMetadata"] as? [String: String])
  94. XCTAssertEqual(dictRepresentation["md5Hash"] as? String, metaDict["md5Hash"] as? String)
  95. XCTAssertEqual(dictRepresentation["generation"] as? String, "12345")
  96. XCTAssertEqual(dictRepresentation["metageneration"] as? String, "67890")
  97. XCTAssertEqual(dictRepresentation["name"] as? String, metaDict["name"] as? String)
  98. XCTAssertEqual(dictRepresentation["timeCreated"] as? String,
  99. metaDict["timeCreated"] as? String)
  100. XCTAssertEqual(dictRepresentation["updated"] as? String,
  101. metaDict["updated"] as? String)
  102. XCTAssertEqual(dictRepresentation["size"] as? Int64, 1337)
  103. }
  104. func testInitializeEmptyDownloadURL() {
  105. let metaDict = ["bucket": "bucket", "name": "/path/to/object"]
  106. let rootReference = rootReference()
  107. let task = StorageGetDownloadURLTask(reference: rootReference,
  108. fetcherService: GTMSessionFetcherService(),
  109. queue: DispatchQueue.main,
  110. completion: nil)
  111. let actualURL = task.downloadURLFromMetadataDictionary(metaDict)
  112. XCTAssertNil(actualURL)
  113. }
  114. func testInitializeDownloadURLFromToken() {
  115. let metaDict = [
  116. "bucket": "bucket",
  117. "downloadTokens": "12345,ignored",
  118. "name": "path/to/object",
  119. ] as [String: String]
  120. let rootReference = rootReference()
  121. let escapedPath = StorageUtils.GCSEscapedString(metaDict["name"]!)
  122. let expectedURL =
  123. "https://firebasestorage.googleapis.com:443/v0/b/bucket/o/\(escapedPath)?alt=media&token=12345"
  124. let task = StorageGetDownloadURLTask(reference: rootReference,
  125. fetcherService: GTMSessionFetcherService(),
  126. queue: DispatchQueue.main,
  127. completion: nil)
  128. let actualURL = task.downloadURLFromMetadataDictionary(metaDict)
  129. XCTAssertEqual(actualURL?.absoluteString, expectedURL)
  130. }
  131. // Regression test for #10370
  132. func testInitializeDownloadURLFromTokenWithEmptyMetadata() {
  133. let metaDict = [
  134. "bucket": "bucket",
  135. "downloadTokens": "12345,ignored",
  136. "name": "path/to/object",
  137. "metadata": {},
  138. ] as [String: Any]
  139. let rootReference = rootReference()
  140. let escapedPath = StorageUtils.GCSEscapedString("path/to/object")
  141. let expectedURL =
  142. "https://firebasestorage.googleapis.com:443/v0/b/bucket/o/\(escapedPath)?alt=media&token=12345"
  143. let task = StorageGetDownloadURLTask(reference: rootReference,
  144. fetcherService: GTMSessionFetcherService(),
  145. queue: DispatchQueue.main,
  146. completion: nil)
  147. let actualURL = task.downloadURLFromMetadataDictionary(metaDict)
  148. XCTAssertEqual(actualURL?.absoluteString, expectedURL)
  149. }
  150. func testInitializeMetadataWithFile() {
  151. let metaDict = ["bucket": "bucket", "name": "/path/to/file"]
  152. let metadata = StorageMetadata(dictionary: metaDict)
  153. metadata.fileType = .file
  154. XCTAssertTrue(metadata.isFile)
  155. XCTAssertFalse(metadata.isFolder)
  156. }
  157. func testInitializeMetadataWithFolder() {
  158. let metaDict = ["bucket": "bucket", "name": "/path/to/folder"]
  159. let metadata = StorageMetadata(dictionary: metaDict)
  160. metadata.fileType = .folder
  161. XCTAssertFalse(metadata.isFile)
  162. XCTAssertTrue(metadata.isFolder)
  163. }
  164. func testReflexiveMetadataEquality() {
  165. let metaDict = ["bucket": "bucket", "name": "/path/to/file"]
  166. let metadata0 = StorageMetadata(dictionary: metaDict)
  167. let metadata1 = metadata0
  168. XCTAssertEqual(metadata0, metadata1)
  169. }
  170. func testNonsenseMetadataEquality() {
  171. let metaDict = [
  172. "bucket": "bucket",
  173. "name": "path/to/object",
  174. ] as [String: String]
  175. let metadata0 = StorageMetadata(dictionary: metaDict)
  176. XCTAssertNotEqual(metadata0, StorageMetadata())
  177. }
  178. func testMetadataEquality() {
  179. let metaDict = [
  180. "bucket": "bucket",
  181. "name": "/path/to/file",
  182. "md5Hash": "d41d8cd98f00b204e9800998ecf8427e",
  183. ]
  184. let metadata0 = StorageMetadata(dictionary: metaDict)
  185. let metadata1 = StorageMetadata(dictionary: metaDict)
  186. XCTAssertEqual(metadata0, metadata1)
  187. }
  188. func testMetadataMd5Inequality() {
  189. let metaDict0 = ["md5Hash": "d41d8cd98f00b204e9800998ecf8427e"]
  190. let metaDict1 = ["md5Hash": "d41d8cd98f00b204e9800998ecf8427f"]
  191. let metadata0 = StorageMetadata(dictionary: metaDict0)
  192. let metadata1 = StorageMetadata(dictionary: metaDict1)
  193. XCTAssertNotEqual(metadata0, metadata1)
  194. }
  195. func testMetadataCopy() {
  196. let metaDict = [
  197. "bucket": "bucket",
  198. "name": "/path/to/file",
  199. "md5Hash": "d41d8cd98f00b204e9800998ecf8427e",
  200. ]
  201. let metadata0 = StorageMetadata(dictionary: metaDict)
  202. let metadata1 = metadata0.copy() as? StorageMetadata
  203. // Verify that copied object has a new reference.
  204. XCTAssertFalse(metadata0 === metadata1)
  205. XCTAssertEqual(metadata0, metadata1)
  206. }
  207. func testUpdatedMetadata() {
  208. let oldMetadata = [
  209. "contentLanguage": "old",
  210. "metadata": ["foo": "old", "bar": "old"],
  211. ] as [String: AnyHashable]
  212. let metadata = StorageMetadata(dictionary: oldMetadata)
  213. metadata.contentLanguage = "new"
  214. metadata.customMetadata = ["foo": "new", "bar": "old"]
  215. let update = metadata.updatedMetadata()
  216. let expectedUpdate = [
  217. "contentLanguage": "new",
  218. "metadata": ["foo": "new"],
  219. "bucket": "",
  220. ] as [String: AnyHashable]
  221. XCTAssertEqual(update, expectedUpdate)
  222. }
  223. func testUpdatedMetadataWithEmptyUpdate() {
  224. let oldMetadata = [
  225. "contentLanguage": "old",
  226. "metadata": ["foo": "old", "bar": "old"],
  227. ] as [String: AnyHashable]
  228. let metadata = StorageMetadata(dictionary: oldMetadata)
  229. let update = metadata.updatedMetadata()
  230. XCTAssertEqual(update, ["bucket": ""])
  231. }
  232. func testUpdatedMetadataWithDelete() {
  233. let oldMetadata = [
  234. "contentLanguage": "old",
  235. "metadata": ["foo": "old", "bar": "old"],
  236. ] as [String: AnyHashable]
  237. let metadata = StorageMetadata(dictionary: oldMetadata)
  238. metadata.contentLanguage = nil
  239. metadata.customMetadata = ["foo": "old"]
  240. let update = metadata.updatedMetadata()
  241. let expected = ["bucket": "",
  242. "contentLanguage": NSNull(),
  243. "metadata": ["bar": NSNull()]] as [String: AnyHashable]
  244. XCTAssertEqual(update, expected)
  245. }
  246. func testMetadataHashEquality() {
  247. let metaDict = [
  248. "bucket": "bucket",
  249. "name": "path/to/object",
  250. ] as [String: String]
  251. let metadata0 = StorageMetadata(dictionary: metaDict)
  252. let metadata1 = StorageMetadata(dictionary: metaDict)
  253. XCTAssertFalse(metadata0 === metadata1)
  254. XCTAssertTrue(metadata0 == metadata1)
  255. XCTAssertEqual(metadata0.hash, metadata1.hash)
  256. }
  257. func testZuluTimeOffset() {
  258. let metaDict = ["timeCreated": "1992-08-07T17:22:53.108Z"]
  259. let metadata = StorageMetadata(dictionary: metaDict)
  260. XCTAssertNotNil(metadata)
  261. }
  262. func testZuluZeroTimeOffset() {
  263. let metaDict = ["timeCreated": "1992-08-07T17:22:53.108+0000"]
  264. let metadata = StorageMetadata(dictionary: metaDict)
  265. XCTAssertNotNil(metadata)
  266. }
  267. func testGoogleStandardTimeOffset() {
  268. let metaDict = ["timeCreated": "1992-08-07T17:22:53.108-0700"]
  269. let metadata = StorageMetadata(dictionary: metaDict)
  270. XCTAssertNotNil(metadata)
  271. }
  272. func testUnspecifiedTimeOffset() {
  273. let metaDict = ["timeCreated": "1992-08-07T17:22:53.108-0000"]
  274. let metadata = StorageMetadata(dictionary: metaDict)
  275. XCTAssertNotNil(metadata)
  276. }
  277. func testNoTimeOffset() {
  278. let metaDict = ["timeCreated": "1992-08-07T17:22:53.108"]
  279. let metadata = StorageMetadata(dictionary: metaDict)
  280. XCTAssertNotNil(metadata)
  281. }
  282. }