StorageMetadataTests.swift 11 KB

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