MemoryStorageTests.swift 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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: 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. try! storage.store(value: 1, forKey: "1")
  57. XCTAssertTrue(storage.isCached(forKey: "1"))
  58. XCTAssertEqual(try! storage.value(forKey: "1"), 1)
  59. }
  60. func testStoreValueOverwritting() {
  61. try! storage.store(value: 1, forKey: "1")
  62. XCTAssertEqual(try! storage.value(forKey: "1"), 1)
  63. try! storage.store(value: 100, forKey: "1")
  64. XCTAssertEqual(try! storage.value(forKey: "1"), 100)
  65. }
  66. func testRemoveValue() {
  67. XCTAssertFalse(storage.isCached(forKey: "1"))
  68. try! storage.store(value: 1, forKey: "1")
  69. XCTAssertTrue(storage.isCached(forKey: "1"))
  70. try! storage.remove(forKey: "1")
  71. XCTAssertFalse(storage.isCached(forKey: "1"))
  72. }
  73. func testRemoveAllValues() {
  74. try! storage.store(value: 1, forKey: "1")
  75. try! storage.store(value: 2, forKey: "2")
  76. XCTAssertTrue(storage.isCached(forKey: "1"))
  77. XCTAssertTrue(storage.isCached(forKey: "2"))
  78. try! 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. try! storage.store(value: 1, forKey: "1", expiration: .seconds(0.1))
  86. XCTAssertTrue(storage.isCached(forKey: "1"))
  87. XCTAssertFalse(storage.isCached(forKey: "2"))
  88. try! 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. try! 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 testRemoveExpired() {
  116. let exp = expectation(description: #function)
  117. XCTAssertFalse(storage.isCached(forKey: "1"))
  118. try! storage.store(value: 1, forKey: "1", expiration: .seconds(0.1))
  119. XCTAssertTrue(storage.isCached(forKey: "1"))
  120. delay(0.2) {
  121. XCTAssertFalse(self.storage.isCached(forKey: "1"))
  122. // But the object is still in underlying cache.
  123. XCTAssertNotNil(self.storage.storage.object(forKey: "1"))
  124. self.storage.removeExpired()
  125. // It should be removed now.
  126. XCTAssertNil(self.storage.storage.object(forKey: "1"))
  127. exp.fulfill()
  128. }
  129. waitForExpectations(timeout: 3, handler: nil)
  130. }
  131. func testExtendExpirationByAccessing() {
  132. let exp = expectation(description: #function)
  133. let expiration = StorageExpiration.seconds(0.5)
  134. try! storage.store(value: 1, forKey: "1", expiration: expiration)
  135. delay(0.3) {
  136. // This should extend the expiration to (0.3 + 0.5) from initially created.
  137. let v = try! self.storage.value(forKey: "1")
  138. XCTAssertEqual(v, 1)
  139. }
  140. delay(0.6) {
  141. // Accessing `isCached` does not extend expiration
  142. XCTAssertTrue(self.storage.isCached(forKey: "1"))
  143. }
  144. delay(1) {
  145. XCTAssertFalse(self.storage.isCached(forKey: "1"))
  146. exp.fulfill()
  147. }
  148. waitForExpectations(timeout: 3, handler: nil)
  149. }
  150. func testAutoCleanExpiredMemory() {
  151. let exp = expectation(description: #function)
  152. let config = MemoryStorage.Config(totalCostLimit: 3, cleanInterval: 0.1)
  153. storage = MemoryStorage.Backend(config: config)
  154. try! storage.store(value: 1, forKey: "1", expiration: .seconds(0.1))
  155. XCTAssertTrue(storage.isCached(forKey: "1"))
  156. XCTAssertEqual(self.storage.keys.count, 1)
  157. delay(0.2) {
  158. XCTAssertFalse(self.storage.isCached(forKey: "1"))
  159. XCTAssertNil(self.storage.storage.object(forKey: "1"))
  160. XCTAssertEqual(self.storage.keys.count, 0)
  161. exp.fulfill()
  162. }
  163. waitForExpectations(timeout: 3, handler: nil)
  164. }
  165. func testStorageObject() {
  166. let now = Date()
  167. let obj = MemoryStorage.StorageObject(1, key: "1", expiration: .seconds(1))
  168. XCTAssertEqual(obj.value, 1)
  169. XCTAssertEqual(
  170. obj.estimatedExpiration.timeIntervalSince1970,
  171. now.addingTimeInterval(1).timeIntervalSince1970,
  172. accuracy: 0.2)
  173. let exp = expectation(description: #function)
  174. delay(0.5) {
  175. obj.extendExpiration()
  176. XCTAssertEqual(
  177. obj.estimatedExpiration.timeIntervalSince1970,
  178. now.addingTimeInterval(1.5).timeIntervalSince1970,
  179. accuracy: 0.2)
  180. exp.fulfill()
  181. }
  182. waitForExpectations(timeout: 3, handler: nil)
  183. }
  184. }