MemoryStorageTests.swift 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. //
  2. // MemoryStorageTests.swift
  3. // Kingfisher
  4. //
  5. // Created by Wei Wang on 2018/11/12.
  6. //
  7. // Copyright (c) 2019 Wei Wang <onevcat@gmail.com>
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. import XCTest
  27. @testable import Kingfisher
  28. extension Int: @retroactive CacheCostCalculable {
  29. public var cacheCost: Int {
  30. return 1
  31. }
  32. }
  33. class MemoryStorageTests: XCTestCase {
  34. var storage: MemoryStorage.Backend<Int>!
  35. override func setUp() {
  36. super.setUp()
  37. let config = MemoryStorage.Config(totalCostLimit: 3)
  38. storage = MemoryStorage.Backend(config: config)
  39. }
  40. override func tearDown() {
  41. storage = nil
  42. super.tearDown()
  43. }
  44. func testConfigSettingStorage() {
  45. XCTAssertEqual(storage.config.totalCostLimit, 3)
  46. XCTAssertEqual(storage.storage.totalCostLimit, 3)
  47. storage.config = MemoryStorage.Config(totalCostLimit: 10)
  48. XCTAssertEqual(storage.config.totalCostLimit, 10)
  49. XCTAssertEqual(storage.storage.totalCostLimit, 10)
  50. storage.config.countLimit = 100
  51. XCTAssertEqual(storage.config.countLimit, 100)
  52. XCTAssertEqual(storage.storage.countLimit, 100)
  53. }
  54. func testStoreAndGetValue() {
  55. XCTAssertFalse(storage.isCached(forKey: "1"))
  56. storage.store(value: 1, forKey: "1")
  57. XCTAssertTrue(storage.isCached(forKey: "1"))
  58. XCTAssertEqual(storage.value(forKey: "1"), 1)
  59. }
  60. func testStoreValueOverwriting() {
  61. storage.store(value: 1, forKey: "1")
  62. XCTAssertEqual(storage.value(forKey: "1"), 1)
  63. storage.store(value: 100, forKey: "1")
  64. XCTAssertEqual(storage.value(forKey: "1"), 100)
  65. }
  66. func testRemoveValue() {
  67. XCTAssertFalse(storage.isCached(forKey: "1"))
  68. storage.store(value: 1, forKey: "1")
  69. XCTAssertTrue(storage.isCached(forKey: "1"))
  70. storage.remove(forKey: "1")
  71. XCTAssertFalse(storage.isCached(forKey: "1"))
  72. }
  73. func testRemoveAllValues() {
  74. storage.store(value: 1, forKey: "1")
  75. storage.store(value: 2, forKey: "2")
  76. XCTAssertTrue(storage.isCached(forKey: "1"))
  77. XCTAssertTrue(storage.isCached(forKey: "2"))
  78. storage.removeAll()
  79. XCTAssertFalse(storage.isCached(forKey: "1"))
  80. XCTAssertFalse(storage.isCached(forKey: "2"))
  81. }
  82. func testStoreWithExpiration() {
  83. let exp = expectation(description: #function)
  84. XCTAssertFalse(storage.isCached(forKey: "1"))
  85. storage.store(value: 1, forKey: "1", expiration: .seconds(0.1))
  86. XCTAssertTrue(storage.isCached(forKey: "1"))
  87. XCTAssertFalse(storage.isCached(forKey: "2"))
  88. storage.store(value: 2, forKey: "2")
  89. XCTAssertTrue(storage.isCached(forKey: "2"))
  90. delay(0.2) {
  91. XCTAssertFalse(self.storage.isCached(forKey: "1"))
  92. XCTAssertTrue(self.storage.isCached(forKey: "2"))
  93. // But the object is still in underlying cache.
  94. let obj = self.storage.storage.object(forKey: "1")
  95. XCTAssertNotNil(obj)
  96. exp.fulfill()
  97. }
  98. waitForExpectations(timeout: 3, handler: nil)
  99. }
  100. func testStoreWithConfigExpiration() {
  101. let exp = expectation(description: #function)
  102. storage.config.expiration = .seconds(0.1)
  103. XCTAssertFalse(storage.isCached(forKey: "1"))
  104. storage.store(value: 1, forKey: "1")
  105. XCTAssertTrue(storage.isCached(forKey: "1"))
  106. delay(0.2) {
  107. XCTAssertFalse(self.storage.isCached(forKey: "1"))
  108. // But the object is still in underlying cache.
  109. let obj = self.storage.storage.object(forKey: "1")
  110. XCTAssertNotNil(obj)
  111. exp.fulfill()
  112. }
  113. waitForExpectations(timeout: 3, handler: nil)
  114. }
  115. func testStoreWithExpirationExtending() {
  116. let exp = expectation(description: #function)
  117. XCTAssertFalse(storage.isCached(forKey: "1"))
  118. storage.store(value: 1, forKey: "1", expiration: .seconds(1))
  119. XCTAssertTrue(storage.isCached(forKey: "1"))
  120. delay(0.1) {
  121. let expirationDate1 = self.storage.storage.object(forKey: "1")?.estimatedExpiration
  122. XCTAssertNotNil(expirationDate1)
  123. // Request for the object to extend it's expiration date
  124. let obj = self.storage.value(forKey: "1", extendingExpiration: .expirationTime(.seconds(5)))
  125. XCTAssertNotNil(obj)
  126. let expirationDate2 = self.storage.storage.object(forKey: "1")?.estimatedExpiration
  127. XCTAssertNotNil(expirationDate2)
  128. XCTAssertNotEqual(expirationDate1!, expirationDate2!)
  129. XCTAssert(expirationDate1!.isPast(referenceDate: expirationDate2!))
  130. exp.fulfill()
  131. }
  132. waitForExpectations(timeout: 3, handler: nil)
  133. }
  134. func testStoreWithExpirationNotExtending() {
  135. let exp = expectation(description: #function)
  136. XCTAssertFalse(storage.isCached(forKey: "1"))
  137. storage.store(value: 1, forKey: "1", expiration: .seconds(1))
  138. XCTAssertTrue(storage.isCached(forKey: "1"))
  139. delay(0.1) {
  140. let expirationDate1 = self.storage.storage.object(forKey: "1")?.estimatedExpiration
  141. XCTAssertNotNil(expirationDate1)
  142. // Request for the object to extend it's expiration date
  143. let obj = self.storage.value(forKey: "1", extendingExpiration: .none)
  144. XCTAssertNotNil(obj)
  145. let expirationDate2 = self.storage.storage.object(forKey: "1")?.estimatedExpiration
  146. XCTAssertNotNil(expirationDate2)
  147. XCTAssertEqual(expirationDate1, expirationDate2)
  148. exp.fulfill()
  149. }
  150. waitForExpectations(timeout: 3, handler: nil)
  151. }
  152. func testRemoveExpired() {
  153. let exp = expectation(description: #function)
  154. XCTAssertFalse(storage.isCached(forKey: "1"))
  155. storage.store(value: 1, forKey: "1", expiration: .seconds(0.1))
  156. XCTAssertTrue(storage.isCached(forKey: "1"))
  157. delay(0.2) {
  158. XCTAssertFalse(self.storage.isCached(forKey: "1"))
  159. // But the object is still in underlying cache.
  160. XCTAssertNotNil(self.storage.storage.object(forKey: "1"))
  161. self.storage.removeExpired()
  162. // It should be removed now.
  163. XCTAssertNil(self.storage.storage.object(forKey: "1"))
  164. exp.fulfill()
  165. }
  166. waitForExpectations(timeout: 3, handler: nil)
  167. }
  168. func testExtendExpirationByAccessing() {
  169. let exp = expectation(description: #function)
  170. let expiration = StorageExpiration.seconds(0.5)
  171. storage.store(value: 1, forKey: "1", expiration: expiration)
  172. delay(0.3) {
  173. // This should extend the expiration to (0.3 + 0.5) from initially created.
  174. let v = self.storage.value(forKey: "1")
  175. XCTAssertEqual(v, 1)
  176. }
  177. delay(0.6) {
  178. // Accessing `isCached` does not extend expiration
  179. XCTAssertTrue(self.storage.isCached(forKey: "1"))
  180. }
  181. delay(1) {
  182. XCTAssertFalse(self.storage.isCached(forKey: "1"))
  183. exp.fulfill()
  184. }
  185. waitForExpectations(timeout: 3, handler: nil)
  186. }
  187. func testAutoCleanExpiredMemory() {
  188. let exp = expectation(description: #function)
  189. let config = MemoryStorage.Config(totalCostLimit: 3, cleanInterval: 0.1)
  190. storage = MemoryStorage.Backend(config: config)
  191. storage.store(value: 1, forKey: "1", expiration: .seconds(0.1))
  192. XCTAssertTrue(storage.isCached(forKey: "1"))
  193. XCTAssertEqual(self.storage.keys.count, 1)
  194. delay(0.2) {
  195. XCTAssertFalse(self.storage.isCached(forKey: "1"))
  196. XCTAssertNil(self.storage.storage.object(forKey: "1"))
  197. XCTAssertEqual(self.storage.keys.count, 0)
  198. exp.fulfill()
  199. }
  200. waitForExpectations(timeout: 3, handler: nil)
  201. }
  202. func testStorageObject() {
  203. let now = Date()
  204. let obj = MemoryStorage.StorageObject(1, expiration: .seconds(1))
  205. XCTAssertEqual(obj.value, 1)
  206. XCTAssertEqual(
  207. obj.estimatedExpiration.timeIntervalSince1970,
  208. now.addingTimeInterval(1).timeIntervalSince1970,
  209. accuracy: 0.3)
  210. let exp = expectation(description: #function)
  211. delay(0.5) {
  212. obj.extendExpiration()
  213. XCTAssertEqual(
  214. obj.estimatedExpiration.timeIntervalSince1970,
  215. now.addingTimeInterval(1.5).timeIntervalSince1970,
  216. accuracy: 0.3)
  217. exp.fulfill()
  218. }
  219. waitForExpectations(timeout: 3, handler: nil)
  220. }
  221. }