1 /****************************************************************************** 2 3 Kept with "_slowtest" suffix because sleep is used to ensure cache 4 invalidation timeout works. 5 6 Copyright: 7 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 8 All rights reserved. 9 10 License: 11 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 12 Alternatively, this file may be distributed under the terms of the Tango 13 3-Clause BSD License (see LICENSE_BSD.txt for details). 14 15 *******************************************************************************/ 16 17 module ocean.util.container.cache.ExpiredCacheReloader_test; 18 19 20 import ocean.util.container.cache.ExpiredCacheReloader; 21 import ocean.util.serialize.contiguous; 22 23 import ocean.io.select.EpollSelectDispatcher, 24 ocean.io.select.client.TimerEvent; 25 26 import ocean.core.Test; 27 28 import core.sys.posix.time; 29 30 /****************************************************************************** 31 32 Trivial struct type to imitate stored value 33 34 ******************************************************************************/ 35 36 struct Trivial 37 { 38 int field; 39 } 40 41 /****************************************************************************** 42 43 Simulates the real time for the cache below. 44 45 ******************************************************************************/ 46 47 private time_t now = 0; 48 49 /****************************************************************************** 50 51 Advances the simulated real time. 52 53 Params: 54 seconds = amount of seconds to advance the simulated real time 55 56 ******************************************************************************/ 57 58 private void wait(long seconds) 59 { 60 now += seconds; 61 } 62 63 /****************************************************************************** 64 65 CachingStructLoader mock implementation 66 67 ******************************************************************************/ 68 69 class TestCache(S) : ExpiredCacheReloader!(S) 70 { 71 alias typeof(super) Super; 72 73 static class Cache: Super.Cache 74 { 75 this ( ) 76 { 77 super(5, 1); // max 5 items, 1 second 78 } 79 80 /// Use the simulated time rather than the real time clock. 81 82 override protected time_t now ( ) 83 { 84 return .now; 85 } 86 } 87 88 // data source for missing records 89 void[][hash_t] source; 90 91 bool add_empty; 92 93 void addToSource(hash_t key, S value) 94 { 95 auto elem = key in this.source; 96 if (elem is null) 97 this.source[key] = null; 98 Serializer.serialize(value, this.source[key]); 99 } 100 101 this (Cache cache) 102 { 103 super(cache); 104 this.add_empty = true; 105 } 106 107 void addEmptyValues(bool newval) 108 { 109 this.add_empty = newval; 110 } 111 112 override protected void getData ( hash_t key, scope void delegate ( Contiguous!(S) data ) got ) 113 { 114 auto data = key in this.source; 115 if (data) 116 { 117 auto instance = Deserializer.deserialize!(S)(*data); 118 got(instance); 119 } 120 else 121 { 122 if (this.add_empty) 123 { 124 got(Contiguous!(S)(null)); 125 } 126 } 127 } 128 } 129 130 /****************************************************************************** 131 132 Various test related objects/types reused by all test cases 133 134 ******************************************************************************/ 135 136 alias TestCache!(Trivial) Cache; 137 138 private Cache.Cache cache_storage; 139 140 private Cache cache; 141 142 static this() 143 { 144 cache_storage = new Cache.Cache; 145 cache = new Cache(cache_storage); 146 } 147 148 /****************************************************************************** 149 150 Cleans all global state. Called in the beginning of each new test case. 151 152 ******************************************************************************/ 153 154 private void reset() 155 { 156 cache_storage.clear(); 157 cache.source = null; 158 } 159 160 /****************************************************************************** 161 162 Tests 163 164 ******************************************************************************/ 165 166 // Empty cache 167 unittest 168 { 169 reset(); 170 171 auto result = 42 in cache; 172 test!("is")(result, null); 173 } 174 175 // Missing item cached 176 unittest 177 { 178 reset(); 179 180 auto result = 42 in cache; 181 cache.addToSource(42, Trivial(42)); 182 result = 42 in cache; 183 test!("is")(result, null); 184 } 185 186 // Missing item cached not cached if (add_empty_values == false) 187 unittest 188 { 189 reset(); 190 cache.addEmptyValues(false); 191 scope(exit) cache.addEmptyValues(true); 192 193 auto result = 42 in cache; 194 test!("is")(result, null); 195 cache.addToSource(42, Trivial(42)); 196 result = 42 in cache; 197 test!("!is")(result, null); 198 } 199 200 // Missing item updated after timeout 201 unittest 202 { 203 reset(); 204 205 auto result = 42 in cache; 206 cache.addToSource(42, Trivial(42)); 207 result = 42 in cache; 208 209 wait(2); 210 result = 42 in cache; 211 test!("!is")(result, null); 212 test!("==")(result.field, 42); 213 } 214 215 // Exists on first access 216 unittest 217 { 218 reset(); 219 220 cache.addToSource(43, Trivial(43)); 221 auto result = 43 in cache; 222 test!("!is")(result, null); 223 test!("==")(result.field, 43); 224 225 // also verify persistent identity 226 auto result2 = 43 in cache; 227 test!("is")(result, result2); 228 }