~ci-train-bot/thumbnailer/thumbnailer-ubuntu-yakkety-landing-072

« back to all changes in this revision

Viewing changes to tests/core/persistent_string_cache/persistent_string_cache_test.cpp

  • Committer: CI Train Bot
  • Author(s): Michi Henning
  • Date: 2015-09-15 11:04:11 UTC
  • mfrom: (125.1.2 landing150915)
  • Revision ID: ci-train-bot@canonical.com-20150915110411-233xw0fljaq7p2o0
Landing changes on devel to trunk.
Approved by: James Henstridge

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2015 Canonical Ltd.
3
 
 *
4
 
 * This program is free software: you can redistribute it and/or modify
5
 
 * it under the terms of the GNU Lesser General Public License version 3 as
6
 
 * published by the Free Software Foundation.
7
 
 *
8
 
 * This program is distributed in the hope that it will be useful,
9
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
 * GNU Lesser General Public License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU Lesser General Public License
14
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
 
 *
16
 
 * Authored by: Michi Henning <michi.henning@canonical.com>
17
 
 */
18
 
 
19
 
#include <core/persistent_string_cache.h>
20
 
 
21
 
#include <boost/filesystem.hpp>
22
 
#include <gtest/gtest.h>
23
 
 
24
 
#include <thread>
25
 
 
26
 
using namespace std;
27
 
using namespace core;
28
 
 
29
 
// Removes the contents of db_dir, but not db_dir itself.
30
 
 
31
 
void unlink_db(string const& db_dir)
32
 
{
33
 
    namespace fs = boost::filesystem;
34
 
    try
35
 
    {
36
 
        for (fs::directory_iterator end, it(db_dir); it != end; ++it)
37
 
        {
38
 
            remove_all(it->path());
39
 
        }
40
 
    }
41
 
    catch (...)
42
 
    {
43
 
    }
44
 
}
45
 
 
46
 
string const test_db = TEST_DIR "/db";
47
 
 
48
 
TEST(PersistentStringCache, basic)
49
 
{
50
 
    unlink_db(test_db);
51
 
 
52
 
    {
53
 
        // Constructor and move constructor.
54
 
        auto c = PersistentStringCache::open(test_db, 1024, CacheDiscardPolicy::lru_only);
55
 
        PersistentStringCache c2(move(*c));
56
 
        EXPECT_EQ(1024, c2.max_size_in_bytes());
57
 
    }
58
 
 
59
 
    {
60
 
        // Constructor and move assignment.
61
 
        auto c = PersistentStringCache::open(test_db);
62
 
        auto c2 = PersistentStringCache::open(test_db + "2", 2048, CacheDiscardPolicy::lru_ttl);
63
 
        *c = move(*c2);
64
 
        EXPECT_EQ(2048, c->max_size_in_bytes());
65
 
    }
66
 
 
67
 
    // Tests below are cursory, simply calling each method once.
68
 
    // Note: get_or_put() is tested by PersistentStringCacheImpl_test.cpp.
69
 
    {
70
 
        auto c = PersistentStringCache::open(test_db);
71
 
 
72
 
        Optional<string> val;
73
 
        Optional<string> metadata;
74
 
        Optional<PersistentStringCache::Data> data;
75
 
 
76
 
        val = c->get("x");
77
 
        EXPECT_FALSE(val);
78
 
        data = c->get_data("x");
79
 
        EXPECT_FALSE(data);
80
 
        metadata = c->get_metadata("x");
81
 
        EXPECT_FALSE(metadata);
82
 
        EXPECT_FALSE(c->contains_key("x"));
83
 
        EXPECT_EQ(0, c->size());
84
 
        EXPECT_EQ(0, c->size_in_bytes());
85
 
        EXPECT_EQ(1024, c->max_size_in_bytes());
86
 
        EXPECT_GE(c->disk_size_in_bytes(), 0);  // For coverage
87
 
        EXPECT_EQ(CacheDiscardPolicy::lru_only, c->discard_policy());
88
 
        EXPECT_TRUE(c->put("x", ""));
89
 
        EXPECT_TRUE(c->put("x", "x", 1));
90
 
        EXPECT_TRUE(c->put("x", "y", ""));
91
 
        EXPECT_TRUE(c->put("x", "y", 1, "z", 1));
92
 
        EXPECT_TRUE(c->put_metadata("x", "z"));
93
 
        EXPECT_TRUE(c->put_metadata("x", "z", 1));
94
 
        data = c->take_data("x");
95
 
        EXPECT_TRUE(bool(data));
96
 
        EXPECT_EQ("y", data->value);
97
 
        EXPECT_EQ("z", data->metadata);
98
 
        PersistentStringCache::Data data2;
99
 
        data2 = *data;  // Assignment operator
100
 
        EXPECT_EQ("y", data2.value);
101
 
        EXPECT_EQ("z", data2.metadata);
102
 
        val = c->take("x");
103
 
        EXPECT_FALSE(val);
104
 
        EXPECT_FALSE(c->invalidate("x"));
105
 
        EXPECT_FALSE(c->touch("x"));
106
 
        c->invalidate();
107
 
        c->compact();
108
 
        c->put("x", "");
109
 
        c->invalidate({"x"});
110
 
        EXPECT_FALSE(c->contains_key("x"));
111
 
        c->clear_stats();
112
 
        c->resize(2048);
113
 
        c->trim_to(0);
114
 
 
115
 
        auto handler = [&](string const&, CacheEvent, PersistentCacheStats const&)
116
 
        {
117
 
        };
118
 
 
119
 
        c->set_handler(AllCacheEvents, handler);
120
 
        c->set_handler(CacheEvent::get, handler);
121
 
    }
122
 
}
123
 
 
124
 
TEST(PersistentStringCache, stats)
125
 
{
126
 
    {
127
 
        PersistentCacheStats s;
128
 
        EXPECT_EQ("", s.cache_path());
129
 
        EXPECT_EQ(CacheDiscardPolicy::lru_only, s.policy());
130
 
        EXPECT_EQ(0, s.size());
131
 
        EXPECT_EQ(0, s.size_in_bytes());
132
 
        EXPECT_EQ(0, s.max_size_in_bytes());
133
 
        EXPECT_EQ(0, s.hits());
134
 
        EXPECT_EQ(0, s.misses());
135
 
        EXPECT_EQ(0, s.hits_since_last_miss());
136
 
        EXPECT_EQ(0, s.misses_since_last_hit());
137
 
        EXPECT_EQ(0, s.longest_hit_run());
138
 
        EXPECT_EQ(0, s.longest_miss_run());
139
 
        EXPECT_EQ(0, s.ttl_evictions());
140
 
        EXPECT_EQ(0, s.lru_evictions());
141
 
        EXPECT_EQ(chrono::system_clock::time_point(), s.most_recent_hit_time());
142
 
        EXPECT_EQ(chrono::system_clock::time_point(), s.most_recent_miss_time());
143
 
        EXPECT_EQ(chrono::system_clock::time_point(), s.longest_hit_run_time());
144
 
        EXPECT_EQ(chrono::system_clock::time_point(), s.longest_miss_run_time());
145
 
        auto hist = s.histogram();
146
 
        for (unsigned i = 0; i < hist.size(); ++i)
147
 
        {
148
 
            EXPECT_EQ(0, hist[i]);  // Other bins must still be empty.
149
 
        }
150
 
    }
151
 
 
152
 
    {
153
 
        unlink_db(test_db);
154
 
 
155
 
        auto c = PersistentStringCache::open(test_db, 1024, CacheDiscardPolicy::lru_ttl);
156
 
 
157
 
        // Check that we start out with everything initialized.
158
 
        auto s = c->stats();
159
 
        EXPECT_EQ(test_db, s.cache_path());
160
 
        EXPECT_EQ(CacheDiscardPolicy::lru_ttl, s.policy());
161
 
        EXPECT_EQ(0, s.size());
162
 
        EXPECT_EQ(0, s.size_in_bytes());
163
 
        EXPECT_EQ(1024, s.max_size_in_bytes());
164
 
        EXPECT_EQ(0, s.hits());
165
 
        EXPECT_EQ(0, s.misses());
166
 
        EXPECT_EQ(0, s.hits_since_last_miss());
167
 
        EXPECT_EQ(0, s.misses_since_last_hit());
168
 
        EXPECT_EQ(0, s.longest_hit_run());
169
 
        EXPECT_EQ(0, s.longest_miss_run());
170
 
        EXPECT_EQ(0, s.ttl_evictions());
171
 
        EXPECT_EQ(0, s.lru_evictions());
172
 
        EXPECT_EQ(chrono::system_clock::time_point(), s.most_recent_hit_time());
173
 
        EXPECT_EQ(chrono::system_clock::time_point(), s.most_recent_miss_time());
174
 
        EXPECT_EQ(chrono::system_clock::time_point(), s.longest_hit_run_time());
175
 
        EXPECT_EQ(chrono::system_clock::time_point(), s.longest_miss_run_time());
176
 
 
177
 
        // Incur a miss followed by a hit.
178
 
        auto now = chrono::system_clock::now();
179
 
        c->put("x", "y");
180
 
        EXPECT_FALSE(c->get("y"));
181
 
        EXPECT_TRUE(bool(c->get("x")));
182
 
 
183
 
        s = c->stats();
184
 
        EXPECT_EQ(test_db, s.cache_path());                  // Must not have changed.
185
 
        EXPECT_EQ(CacheDiscardPolicy::lru_ttl, s.policy());  // Must not have changed.
186
 
        EXPECT_EQ(1, s.size());
187
 
        EXPECT_EQ(2, s.size_in_bytes());
188
 
        EXPECT_EQ(1024, s.max_size_in_bytes());              // Must not have changed.
189
 
        EXPECT_EQ(1, s.hits());
190
 
        EXPECT_EQ(1, s.misses());
191
 
        EXPECT_EQ(1, s.hits_since_last_miss());
192
 
        EXPECT_EQ(0, s.misses_since_last_hit());
193
 
        EXPECT_EQ(1, s.longest_hit_run());
194
 
        EXPECT_EQ(1, s.longest_miss_run());
195
 
        EXPECT_EQ(0, s.ttl_evictions());
196
 
        EXPECT_EQ(0, s.lru_evictions());
197
 
        EXPECT_NE(chrono::system_clock::time_point(), s.most_recent_hit_time());
198
 
        EXPECT_GE(s.most_recent_hit_time(), now);
199
 
        EXPECT_NE(chrono::system_clock::time_point(), s.most_recent_miss_time());
200
 
        EXPECT_GE(s.most_recent_miss_time(), now);
201
 
        EXPECT_NE(chrono::system_clock::time_point(), s.longest_hit_run_time());
202
 
        EXPECT_GE(s.longest_hit_run_time(), now);
203
 
        EXPECT_NE(chrono::system_clock::time_point(), s.longest_miss_run_time());
204
 
        EXPECT_GE(s.longest_miss_run_time(), now);
205
 
 
206
 
        auto last_hit_time = s.most_recent_hit_time();
207
 
        auto last_miss_time = s.most_recent_miss_time();
208
 
        auto hit_run_time = s.longest_hit_run_time();
209
 
        auto miss_run_time = s.longest_miss_run_time();
210
 
 
211
 
        // Two more hits.
212
 
        now = chrono::system_clock::now();
213
 
        EXPECT_TRUE(bool(c->get("x")));
214
 
        EXPECT_TRUE(bool(c->get("x")));
215
 
 
216
 
        s = c->stats();
217
 
        EXPECT_EQ(3, s.hits());
218
 
        EXPECT_EQ(1, s.misses());
219
 
        EXPECT_EQ(3, s.hits_since_last_miss());
220
 
        EXPECT_EQ(0, s.misses_since_last_hit());
221
 
        EXPECT_EQ(3, s.longest_hit_run());
222
 
        EXPECT_EQ(1, s.longest_miss_run());
223
 
        EXPECT_EQ(0, s.ttl_evictions());
224
 
        EXPECT_EQ(0, s.lru_evictions());
225
 
        EXPECT_LE(last_hit_time, s.most_recent_hit_time());
226
 
        EXPECT_EQ(last_miss_time, s.most_recent_miss_time());
227
 
        EXPECT_LE(hit_run_time, s.longest_hit_run_time());
228
 
        EXPECT_EQ(miss_run_time, s.longest_miss_run_time());
229
 
 
230
 
        last_hit_time = s.most_recent_hit_time();
231
 
        last_miss_time = s.most_recent_miss_time();
232
 
        hit_run_time = s.longest_hit_run_time();
233
 
        miss_run_time = s.longest_miss_run_time();
234
 
 
235
 
        // Four more misses
236
 
        now = chrono::system_clock::now();
237
 
        EXPECT_FALSE(c->get("y"));
238
 
        EXPECT_FALSE(c->get("y"));
239
 
        EXPECT_FALSE(c->get("y"));
240
 
        EXPECT_FALSE(c->get("y"));
241
 
 
242
 
        s = c->stats();
243
 
        EXPECT_EQ(3, s.hits());
244
 
        EXPECT_EQ(5, s.misses());
245
 
        EXPECT_EQ(0, s.hits_since_last_miss());
246
 
        EXPECT_EQ(4, s.misses_since_last_hit());
247
 
        EXPECT_EQ(3, s.longest_hit_run());
248
 
        EXPECT_EQ(4, s.longest_miss_run());
249
 
        EXPECT_EQ(0, s.ttl_evictions());
250
 
        EXPECT_EQ(0, s.lru_evictions());
251
 
        EXPECT_EQ(last_hit_time, s.most_recent_hit_time());
252
 
        EXPECT_LE(last_miss_time, s.most_recent_miss_time());
253
 
        EXPECT_EQ(hit_run_time, s.longest_hit_run_time());
254
 
        EXPECT_LE(miss_run_time, s.longest_miss_run_time());
255
 
 
256
 
        last_hit_time = s.most_recent_hit_time();
257
 
        last_miss_time = s.most_recent_miss_time();
258
 
        hit_run_time = s.longest_hit_run_time();
259
 
        miss_run_time = s.longest_miss_run_time();
260
 
 
261
 
        // One more hit
262
 
        now = chrono::system_clock::now();
263
 
        EXPECT_TRUE(bool(c->get("x")));
264
 
 
265
 
        s = c->stats();
266
 
        EXPECT_EQ(4, s.hits());
267
 
        EXPECT_EQ(5, s.misses());
268
 
        EXPECT_EQ(1, s.hits_since_last_miss());
269
 
        EXPECT_EQ(0, s.misses_since_last_hit());
270
 
        EXPECT_EQ(3, s.longest_hit_run());
271
 
        EXPECT_EQ(4, s.longest_miss_run());
272
 
        EXPECT_EQ(0, s.ttl_evictions());
273
 
        EXPECT_EQ(0, s.lru_evictions());
274
 
        EXPECT_LE(last_hit_time, s.most_recent_hit_time());
275
 
        EXPECT_EQ(last_miss_time, s.most_recent_miss_time());
276
 
        EXPECT_LE(hit_run_time, s.longest_hit_run_time());
277
 
        EXPECT_EQ(miss_run_time, s.longest_miss_run_time());
278
 
 
279
 
        last_hit_time = s.most_recent_hit_time();
280
 
        last_miss_time = s.most_recent_miss_time();
281
 
        hit_run_time = s.longest_hit_run_time();
282
 
        miss_run_time = s.longest_miss_run_time();
283
 
 
284
 
        {
285
 
            // Copy constructor.
286
 
            auto s2(s);
287
 
            EXPECT_EQ(test_db, s2.cache_path());
288
 
            EXPECT_EQ(CacheDiscardPolicy::lru_ttl, s2.policy());
289
 
            EXPECT_EQ(1, s2.size());
290
 
            EXPECT_EQ(2, s2.size_in_bytes());
291
 
            EXPECT_EQ(1024, s2.max_size_in_bytes());
292
 
            EXPECT_EQ(4, s2.hits());
293
 
            EXPECT_EQ(5, s2.misses());
294
 
            EXPECT_EQ(1, s2.hits_since_last_miss());
295
 
            EXPECT_EQ(0, s2.misses_since_last_hit());
296
 
            EXPECT_EQ(3, s.longest_hit_run());
297
 
            EXPECT_EQ(4, s.longest_miss_run());
298
 
            EXPECT_EQ(last_hit_time, s2.most_recent_hit_time());
299
 
            EXPECT_EQ(last_miss_time, s2.most_recent_miss_time());
300
 
            EXPECT_EQ(hit_run_time, s2.longest_hit_run_time());
301
 
            EXPECT_EQ(miss_run_time, s2.longest_miss_run_time());
302
 
        }
303
 
 
304
 
        {
305
 
            // Assignment operator.
306
 
            PersistentCacheStats s2;
307
 
            s2 = s;
308
 
            EXPECT_EQ(test_db, s2.cache_path());
309
 
            EXPECT_EQ(CacheDiscardPolicy::lru_ttl, s2.policy());
310
 
            EXPECT_EQ(1, s2.size());
311
 
            EXPECT_EQ(2, s2.size_in_bytes());
312
 
            EXPECT_EQ(1024, s2.max_size_in_bytes());
313
 
            EXPECT_EQ(4, s2.hits());
314
 
            EXPECT_EQ(5, s2.misses());
315
 
            EXPECT_EQ(1, s2.hits_since_last_miss());
316
 
            EXPECT_EQ(0, s2.misses_since_last_hit());
317
 
            EXPECT_EQ(3, s.longest_hit_run());
318
 
            EXPECT_EQ(4, s.longest_miss_run());
319
 
            EXPECT_EQ(last_hit_time, s2.most_recent_hit_time());
320
 
            EXPECT_EQ(last_miss_time, s2.most_recent_miss_time());
321
 
            EXPECT_EQ(hit_run_time, s2.longest_hit_run_time());
322
 
            EXPECT_EQ(miss_run_time, s2.longest_miss_run_time());
323
 
        }
324
 
 
325
 
        {
326
 
            // Move constructor.
327
 
            PersistentCacheStats s2(move(s));
328
 
            EXPECT_EQ(test_db, s2.cache_path());
329
 
            EXPECT_EQ(CacheDiscardPolicy::lru_ttl, s2.policy());
330
 
            EXPECT_EQ(1, s2.size());
331
 
            EXPECT_EQ(2, s2.size_in_bytes());
332
 
            EXPECT_EQ(1024, s2.max_size_in_bytes());
333
 
            EXPECT_EQ(4, s2.hits());
334
 
            EXPECT_EQ(5, s2.misses());
335
 
            EXPECT_EQ(1, s2.hits_since_last_miss());
336
 
            EXPECT_EQ(0, s2.misses_since_last_hit());
337
 
            EXPECT_EQ(3, s.longest_hit_run());
338
 
            EXPECT_EQ(4, s.longest_miss_run());
339
 
            EXPECT_EQ(last_hit_time, s2.most_recent_hit_time());
340
 
            EXPECT_EQ(last_miss_time, s2.most_recent_miss_time());
341
 
            EXPECT_EQ(hit_run_time, s2.longest_hit_run_time());
342
 
            EXPECT_EQ(miss_run_time, s2.longest_miss_run_time());
343
 
 
344
 
            s.cache_path();  // Moved-from instance must be usable.
345
 
 
346
 
            // Move assignment.
347
 
            PersistentCacheStats s3;
348
 
            s3 = move(s2);
349
 
            EXPECT_EQ(test_db, s3.cache_path());
350
 
            EXPECT_EQ(CacheDiscardPolicy::lru_ttl, s3.policy());
351
 
            EXPECT_EQ(1, s3.size());
352
 
            EXPECT_EQ(2, s3.size_in_bytes());
353
 
            EXPECT_EQ(1024, s3.max_size_in_bytes());
354
 
            EXPECT_EQ(4, s3.hits());
355
 
            EXPECT_EQ(5, s3.misses());
356
 
            EXPECT_EQ(1, s3.hits_since_last_miss());
357
 
            EXPECT_EQ(0, s3.misses_since_last_hit());
358
 
            EXPECT_EQ(3, s.longest_hit_run());
359
 
            EXPECT_EQ(4, s.longest_miss_run());
360
 
            EXPECT_EQ(last_hit_time, s3.most_recent_hit_time());
361
 
            EXPECT_EQ(last_miss_time, s3.most_recent_miss_time());
362
 
            EXPECT_EQ(hit_run_time, s3.longest_hit_run_time());
363
 
            EXPECT_EQ(miss_run_time, s3.longest_miss_run_time());
364
 
 
365
 
            s2.cache_path();  // Moved-from instance must be usable.
366
 
        }
367
 
 
368
 
        // To get coverage for copying and moving from the internal instance,
369
 
        // we need to use an event handler because the event handler is passed the
370
 
        // shared_ptr to the internal instance, whereas c->stats() returns a copy.
371
 
 
372
 
        auto copy_construct_handler = [&](string const&, CacheEvent, PersistentCacheStats const& s)
373
 
        {
374
 
            PersistentCacheStats s2(s);
375
 
            EXPECT_EQ(test_db, s2.cache_path());
376
 
            EXPECT_EQ(CacheDiscardPolicy::lru_ttl, s2.policy());
377
 
            EXPECT_EQ(1, s2.size());
378
 
            EXPECT_EQ(2, s2.size_in_bytes());
379
 
            EXPECT_EQ(1024, s2.max_size_in_bytes());
380
 
            EXPECT_EQ(4, s2.hits());
381
 
            EXPECT_EQ(5, s2.misses());
382
 
            EXPECT_EQ(1, s2.hits_since_last_miss());
383
 
            EXPECT_EQ(0, s2.misses_since_last_hit());
384
 
            EXPECT_EQ(3, s.longest_hit_run());
385
 
            EXPECT_EQ(4, s.longest_miss_run());
386
 
            EXPECT_EQ(last_hit_time, s2.most_recent_hit_time());
387
 
            EXPECT_EQ(last_miss_time, s2.most_recent_miss_time());
388
 
            EXPECT_EQ(hit_run_time, s2.longest_hit_run_time());
389
 
            EXPECT_EQ(miss_run_time, s2.longest_miss_run_time());
390
 
 
391
 
            EXPECT_EQ(test_db, s.cache_path());  // Source must remain intact.
392
 
        };
393
 
        c->set_handler(CacheEvent::touch, copy_construct_handler);
394
 
        c->touch("x");
395
 
 
396
 
        auto move_assign_handler = [&](string const&, CacheEvent, PersistentCacheStats const& s)
397
 
        {
398
 
            PersistentCacheStats s2;
399
 
            s2 = move(s);
400
 
            EXPECT_EQ(test_db, s2.cache_path());
401
 
            EXPECT_EQ(CacheDiscardPolicy::lru_ttl, s2.policy());
402
 
            EXPECT_EQ(1, s2.size());
403
 
            EXPECT_EQ(2, s2.size_in_bytes());
404
 
            EXPECT_EQ(1024, s2.max_size_in_bytes());
405
 
            EXPECT_EQ(4, s2.hits());
406
 
            EXPECT_EQ(5, s2.misses());
407
 
            EXPECT_EQ(1, s2.hits_since_last_miss());
408
 
            EXPECT_EQ(0, s2.misses_since_last_hit());
409
 
            EXPECT_EQ(3, s.longest_hit_run());
410
 
            EXPECT_EQ(4, s.longest_miss_run());
411
 
            EXPECT_EQ(last_hit_time, s2.most_recent_hit_time());
412
 
            EXPECT_EQ(last_miss_time, s2.most_recent_miss_time());
413
 
            EXPECT_EQ(hit_run_time, s2.longest_hit_run_time());
414
 
            EXPECT_EQ(miss_run_time, s2.longest_miss_run_time());
415
 
 
416
 
            EXPECT_EQ(test_db, s.cache_path());  // Moved-from instance wasn't really moved from.
417
 
        };
418
 
        c->set_handler(CacheEvent::touch, move_assign_handler);
419
 
        c->touch("x");
420
 
 
421
 
        // Move construction is impossible because handlers are passed a const ref
422
 
        // to the internal instance.
423
 
    }
424
 
 
425
 
    {
426
 
        unlink_db(test_db);
427
 
 
428
 
        auto c = PersistentStringCache::open(test_db, 1024, CacheDiscardPolicy::lru_ttl);
429
 
 
430
 
        // Check that eviction counts are correct.
431
 
        c->put("1", string(200, 'a'));
432
 
        c->put("2", string(200, 'a'));
433
 
        c->put("3", string(200, 'a'));
434
 
        c->put("4", string(200, 'a'));
435
 
        c->put("5", string(200, 'a'));
436
 
 
437
 
        // Cache almost full now (1005 bytes). Adding a 401-byte record must evict two entries.
438
 
        c->put("6", string(400, 'a'));
439
 
        EXPECT_EQ(1004, c->size_in_bytes());
440
 
        auto s = c->stats();
441
 
        EXPECT_EQ(4, s.size());
442
 
        EXPECT_EQ(0, s.ttl_evictions());
443
 
        EXPECT_EQ(2, s.lru_evictions());
444
 
 
445
 
        // Add two records that expire in 500ms. These must evict two more entries.
446
 
        auto later = chrono::system_clock::now() + chrono::milliseconds(500);
447
 
        c->put("7", string(200, 'a'), later);
448
 
        c->put("8", string(200, 'a'), later);
449
 
        EXPECT_EQ(1004, c->size_in_bytes());
450
 
        s = c->stats();
451
 
        EXPECT_EQ(4, s.size());
452
 
        EXPECT_EQ(0, s.ttl_evictions());
453
 
        EXPECT_EQ(4, s.lru_evictions());
454
 
 
455
 
        // Wait until records have expired.
456
 
        while (chrono::system_clock::now() <= later)
457
 
        {
458
 
            this_thread::sleep_for(chrono::milliseconds(5));
459
 
        }
460
 
 
461
 
        // Add a single record. That must evict both expired entries, even though evicting one would be enough.
462
 
        c->put("9", string(300, 'a'));
463
 
        EXPECT_EQ(903, c->size_in_bytes());
464
 
        s = c->stats();
465
 
        EXPECT_EQ(3, s.size());
466
 
        EXPECT_EQ(2, s.ttl_evictions());
467
 
        EXPECT_EQ(4, s.lru_evictions());
468
 
    }
469
 
}