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 }