~ubuntu-branches/ubuntu/trusty/mysql-5.6/trusty

« back to all changes in this revision

Viewing changes to plugin/innodb_memcached/daemon_memcached/testsuite/basic_engine_testsuite.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-02-12 11:54:27 UTC
  • Revision ID: package-import@ubuntu.com-20140212115427-oq6tfsqxl1wuwehi
Tags: upstream-5.6.15
ImportĀ upstreamĀ versionĀ 5.6.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 
2
#undef NDEBUG
 
3
#include "config.h"
 
4
#include <assert.h>
 
5
#include <stdlib.h>
 
6
#include <string.h>
 
7
#include <unistd.h>
 
8
#include <pthread.h>
 
9
#include "basic_engine_testsuite.h"
 
10
 
 
11
struct test_harness test_harness;
 
12
 
 
13
/*
 
14
 * Make sure that get_info returns something and that repeated calls to it
 
15
 * return the same something.
 
16
 */
 
17
static enum test_result get_info_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
18
    const engine_info *info = h1->get_info(h);
 
19
    assert(info != NULL);
 
20
    assert(info == h1->get_info(h));
 
21
    return SUCCESS;
 
22
}
 
23
 
 
24
/*
 
25
 * Make sure that the structure returned by get_info has a non-null description.
 
26
 */
 
27
static enum test_result get_info_description_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
28
    const engine_info *info = h1->get_info(h);
 
29
    assert(info->description != NULL);
 
30
    return SUCCESS;
 
31
}
 
32
 
 
33
/*
 
34
 * Make sure that the structure returned by get_info has a valid number of
 
35
 * features and that the size of the feautes array equals that value
 
36
 */
 
37
static enum test_result get_info_features_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
38
    const engine_info *info = h1->get_info(h);
 
39
    uint32_t nfeats = info->num_features;
 
40
    assert (nfeats > 0);
 
41
    const feature_info *fi = info->features;
 
42
    while (nfeats-- > 0) {
 
43
        assert(fi++ != NULL);
 
44
    }
 
45
 
 
46
    return SUCCESS;
 
47
}
 
48
 
 
49
/*
 
50
 * Make sure we can successfully allocate an item, allocate op returns success
 
51
 * and that item struct is populated
 
52
 */
 
53
static enum test_result allocate_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
54
    item *test_item = NULL;
 
55
    void *key = "akey";
 
56
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1,1,1) == ENGINE_SUCCESS);
 
57
    assert(test_item != NULL);
 
58
    h1->release(h,NULL,test_item);
 
59
    return SUCCESS;
 
60
}
 
61
 
 
62
/*
 
63
 * Verify set behavior
 
64
 */
 
65
static enum test_result set_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
66
    item *it;
 
67
    void *key = "key";
 
68
    assert(h1->allocate(h, NULL, &it, key,
 
69
                        strlen(key), 1, 1, 0) == ENGINE_SUCCESS);
 
70
 
 
71
    uint64_t prev_cas;
 
72
    uint64_t cas = 0;
 
73
 
 
74
    for (int ii = 0; ii < 10; ++ii) {
 
75
        prev_cas = cas;
 
76
        assert(h1->store(h, NULL, it, &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
77
        assert(cas != prev_cas);
 
78
    }
 
79
    h1->release(h, NULL, it);
 
80
    return SUCCESS;
 
81
}
 
82
 
 
83
/*
 
84
 * Verify add behavior
 
85
 */
 
86
static enum test_result add_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
87
    item *it;
 
88
    void *key = "key";
 
89
    assert(h1->allocate(h, NULL, &it, key,
 
90
                        strlen(key), 1, 1, 0) == ENGINE_SUCCESS);
 
91
    uint64_t cas;
 
92
 
 
93
    for (int ii = 0; ii < 10; ++ii) {
 
94
        ENGINE_ERROR_CODE ret = h1->store(h, NULL, it, &cas, OPERATION_ADD, 0);
 
95
        if (ii == 0) {
 
96
            assert(ret == ENGINE_SUCCESS);
 
97
            assert(cas != 0);
 
98
        } else {
 
99
            assert(ret == ENGINE_NOT_STORED);
 
100
        }
 
101
    }
 
102
    h1->release(h, NULL, it);
 
103
    return SUCCESS;
 
104
}
 
105
 
 
106
/*
 
107
 * Verify replace behavior
 
108
 */
 
109
static enum test_result replace_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
110
    item *it;
 
111
    void *key = "key";
 
112
    assert(set_test(h, h1) == SUCCESS);
 
113
 
 
114
    assert(h1->allocate(h, NULL, &it, key,
 
115
                        strlen(key), sizeof(int), 1, 0) == ENGINE_SUCCESS);
 
116
    item_info item_info = { .nvalue = 1 };
 
117
    assert(h1->get_item_info(h, NULL, it, &item_info) == true);
 
118
 
 
119
    uint64_t prev_cas;
 
120
    uint64_t cas = 0;
 
121
 
 
122
    for (int ii = 0; ii < 10; ++ii) {
 
123
        prev_cas = cas;
 
124
        *(int*)(item_info.value[0].iov_base) = ii;
 
125
        assert(h1->store(h, NULL, it, &cas, OPERATION_REPLACE,0) == ENGINE_SUCCESS);
 
126
        assert(cas != prev_cas);
 
127
    }
 
128
    h1->release(h, NULL, it);
 
129
 
 
130
    assert(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_SUCCESS);
 
131
    assert(h1->get_item_info(h, NULL, it, &item_info) == true);
 
132
    assert(item_info.value[0].iov_len == sizeof(int));
 
133
    assert(*(int*)(item_info.value[0].iov_base) == 9);
 
134
    h1->release(h, NULL, it);
 
135
 
 
136
    return SUCCESS;
 
137
}
 
138
 
 
139
/*
 
140
 * Verify append behavior
 
141
 */
 
142
static enum test_result append_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
143
    item *it;
 
144
    void *key = "key";
 
145
    uint64_t cas;
 
146
 
 
147
    assert(h1->allocate(h, NULL, &it, key,
 
148
                        strlen(key), 5, 1, 0) == ENGINE_SUCCESS);
 
149
    item_info item_info = { .nvalue = 1 };
 
150
    assert(h1->get_item_info(h, NULL, it, &item_info) == true);
 
151
    memcpy(item_info.value[0].iov_base, "HELLO", 5);
 
152
    assert(h1->store(h, NULL, it, &cas, OPERATION_SET, 0) == ENGINE_SUCCESS);
 
153
    h1->release(h, NULL, it);
 
154
    assert(h1->allocate(h, NULL, &it, key,
 
155
                        strlen(key), 6, 1, 0) == ENGINE_SUCCESS);
 
156
    item_info.nvalue = 1;
 
157
    assert(h1->get_item_info(h, NULL, it, &item_info) == true);
 
158
    memcpy(item_info.value[0].iov_base, " WORLD", 6);
 
159
    assert(h1->store(h, NULL, it, &cas, OPERATION_APPEND, 0) == ENGINE_SUCCESS);
 
160
    h1->release(h, NULL, it);
 
161
 
 
162
    assert(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_SUCCESS);
 
163
    assert(h1->get_item_info(h, NULL, it, &item_info) == true);
 
164
    assert(item_info.value[0].iov_len == 11);
 
165
    assert(memcmp(item_info.value[0].iov_base, "HELLO WORLD", 11) == 0);
 
166
    h1->release(h, NULL, it);
 
167
 
 
168
    return SUCCESS;
 
169
}
 
170
 
 
171
/*
 
172
 * Verify prepend behavior
 
173
 */
 
174
static enum test_result prepend_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
175
    item *it;
 
176
    void *key = "key";
 
177
    uint64_t cas;
 
178
 
 
179
    assert(h1->allocate(h, NULL, &it, key,
 
180
                        strlen(key), 5, 1, 0) == ENGINE_SUCCESS);
 
181
    item_info item_info = { .nvalue = 1 };
 
182
    assert(h1->get_item_info(h, NULL, it, &item_info) == true);
 
183
    memcpy(item_info.value[0].iov_base, "HELLO", 5);
 
184
    assert(h1->store(h, NULL, it, &cas, OPERATION_SET, 0) == ENGINE_SUCCESS);
 
185
    h1->release(h, NULL, it);
 
186
    assert(h1->allocate(h, NULL, &it, key,
 
187
                        strlen(key), 6, 1, 0) == ENGINE_SUCCESS);
 
188
    item_info.nvalue = 1;
 
189
    assert(h1->get_item_info(h, NULL, it, &item_info) == true);
 
190
    memcpy(item_info.value[0].iov_base, " WORLD", 6);
 
191
    assert(h1->store(h, NULL, it, &cas, OPERATION_PREPEND, 0) == ENGINE_SUCCESS);
 
192
    h1->release(h, NULL, it);
 
193
 
 
194
    assert(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_SUCCESS);
 
195
    assert(h1->get_item_info(h, NULL, it, &item_info) == true);
 
196
    assert(item_info.value[0].iov_len == 11);
 
197
    assert(memcmp(item_info.value[0].iov_base, " WORLDHELLO", 11) == 0);
 
198
    h1->release(h, NULL, it);
 
199
 
 
200
    return SUCCESS;
 
201
}
 
202
 
 
203
/*
 
204
 * Make sure when we can successfully store an item after it has been allocated
 
205
 * and that the cas for the stored item has been generated.
 
206
 */
 
207
static enum test_result store_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
208
    item *test_item = NULL;
 
209
    void *key = "bkey";
 
210
    uint64_t cas = 0;
 
211
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1,1,1) == ENGINE_SUCCESS);
 
212
    assert(h1->store(h, NULL, test_item, &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
213
    assert(cas != 0);
 
214
    h1->release(h,NULL,test_item);
 
215
    return SUCCESS;
 
216
}
 
217
 
 
218
/*
 
219
 * Make sure when we can successfully retrieve an item that has been stored in
 
220
 * the engine
 
221
 */
 
222
static enum test_result get_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
223
    item *test_item = NULL;
 
224
    item *test_item_get = NULL;
 
225
    void *key = "get_test_key";
 
226
    uint64_t cas = 0;
 
227
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1,0, 0) == ENGINE_SUCCESS);
 
228
    assert(h1->store(h, NULL, test_item, &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
229
    assert(h1->get(h,NULL,&test_item_get,key,strlen(key),0) == ENGINE_SUCCESS);
 
230
    h1->release(h,NULL,test_item);
 
231
    h1->release(h,NULL,test_item_get);
 
232
    return SUCCESS;
 
233
}
 
234
 
 
235
static enum test_result expiry_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
236
    item *test_item = NULL;
 
237
    item *test_item_get = NULL;
 
238
    void *key = "get_test_key";
 
239
    uint64_t cas = 0;
 
240
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1, 0, 10) == ENGINE_SUCCESS);
 
241
    assert(h1->store(h, NULL, test_item, &cas, OPERATION_SET, 0) == ENGINE_SUCCESS);
 
242
    test_harness.time_travel(11);
 
243
    assert(h1->get(h,NULL,&test_item_get,key,strlen(key),0) == ENGINE_KEY_ENOENT);
 
244
    h1->release(h,NULL,test_item);
 
245
    return SUCCESS;
 
246
}
 
247
 
 
248
/*
 
249
 * Make sure that we can release an item. For the most part all this test does
 
250
 * is ensure that thinds dont go splat when we call release. It does nothing to
 
251
 * ensure that release did much of anything.
 
252
 */
 
253
static enum test_result release_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
254
    item *test_item = NULL;
 
255
    void *key = "release_test_key";
 
256
    uint64_t cas = 0;
 
257
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1, 0, 0) == ENGINE_SUCCESS);
 
258
    assert(h1->store(h, NULL, test_item, &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
259
    h1->release(h, NULL, test_item);
 
260
    return SUCCESS;
 
261
}
 
262
 
 
263
/*
 
264
 * Make sure that we can remove an item and that after the item has been
 
265
 * removed it can not be retrieved.
 
266
 */
 
267
static enum test_result remove_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
268
    item *test_item = NULL;
 
269
    void *key = "remove_test_key";
 
270
    uint64_t cas = 0;
 
271
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1,0, 0) == ENGINE_SUCCESS);
 
272
    assert(h1->store(h, NULL, test_item, &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
273
    assert(h1->remove(h, NULL, key, strlen(key), cas, 0) == ENGINE_SUCCESS);
 
274
    item *check_item = test_item;
 
275
    assert(h1->get(h, NULL, &check_item, key, strlen(key), 0) ==  ENGINE_KEY_ENOENT);
 
276
    assert(check_item == NULL);
 
277
    h1->release(h, NULL, test_item);
 
278
    return SUCCESS;
 
279
}
 
280
 
 
281
/*
 
282
 * Make sure we can arithmetic operations to set the initial value of a key and
 
283
 * to then later increment that value
 
284
 */
 
285
static enum test_result incr_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
286
    item *test_item = NULL;
 
287
    void *key = "incr_test_key";
 
288
    uint64_t cas = 0;
 
289
    uint64_t res = 0;
 
290
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1, 0, 0) == ENGINE_SUCCESS);
 
291
    assert(h1->arithmetic(h, NULL, key, strlen(key), true, true, 0, 1,
 
292
           0, &cas, &res, 0 ) == ENGINE_SUCCESS);
 
293
    assert(res == 1);
 
294
    assert(h1->arithmetic(h, NULL, key, strlen(key), true, false, 1, 0,
 
295
           0, &cas, &res, 0 ) == ENGINE_SUCCESS);
 
296
    assert(res == 2);
 
297
    h1->release(h, NULL, test_item);
 
298
    return SUCCESS;
 
299
}
 
300
 
 
301
static void *incr_test_main(void *arg) {
 
302
    ENGINE_HANDLE *h = arg;
 
303
    ENGINE_HANDLE_V1 *h1 = arg;
 
304
    void *key = "incr_test_key";
 
305
    uint64_t cas = 0;
 
306
    uint64_t res = 0;
 
307
 
 
308
    for (int ii = 0; ii < 1000; ++ii) {
 
309
        assert(h1->arithmetic(h, NULL, key, strlen(key), false, false, 1, 0,
 
310
                              0, &cas, &res, 0 ) == ENGINE_SUCCESS);
 
311
 
 
312
    }
 
313
 
 
314
    return NULL;
 
315
}
 
316
 
 
317
 
 
318
/*
 
319
 * Make sure we can arithmetic operations to set the initial value of a key and
 
320
 * to then later increment that value
 
321
 */
 
322
static enum test_result mt_incr_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
323
#ifdef __arm__
 
324
    const int max_threads = 1;
 
325
#else
 
326
    const int max_threads = 30;
 
327
#endif
 
328
    pthread_t tid[max_threads];
 
329
 
 
330
    if (max_threads < 2) {
 
331
        return SKIPPED;
 
332
    }
 
333
 
 
334
    item *test_item = NULL;
 
335
    void *key = "incr_test_key";
 
336
    uint64_t cas = 0;
 
337
    uint64_t res = 0;
 
338
    assert(h1->allocate(h, NULL, &test_item, key,
 
339
                        strlen(key), 1, 0, 0) == ENGINE_SUCCESS);
 
340
    assert(h1->arithmetic(h, NULL, key, strlen(key), true, true, 0, 1,
 
341
                          0, &cas, &res, 0 ) == ENGINE_SUCCESS);
 
342
    h1->release(h, NULL, test_item);
 
343
 
 
344
    for (int ii = 0; ii < max_threads; ++ii) {
 
345
        assert(pthread_create(&tid[ii], NULL, incr_test_main, h) == 0);
 
346
    }
 
347
 
 
348
    for (int ii = 0; ii < max_threads; ++ii) {
 
349
        void *ret;
 
350
        assert(pthread_join(tid[ii], &ret) == 0);
 
351
        assert(ret == NULL);
 
352
    }
 
353
 
 
354
    return SUCCESS;
 
355
}
 
356
 
 
357
/*
 
358
 * Make sure we can arithmetic operations to set the initial value of a key and
 
359
 * to then later decrement that value
 
360
 */
 
361
static enum test_result decr_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
362
    item *test_item = NULL;
 
363
    void *key = "decr_test_key";
 
364
    uint64_t cas = 0;
 
365
    uint64_t res = 0;
 
366
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1,0, 0) == ENGINE_SUCCESS);
 
367
    assert(h1->arithmetic(h, NULL, key, strlen(key), false, true, 0, 1,
 
368
           0, &cas, &res, 0 ) == ENGINE_SUCCESS);
 
369
    assert(res == 1);
 
370
    assert(h1->arithmetic(h, NULL, key, strlen(key), false, false, 1, 0,
 
371
           0, &cas, &res, 0 ) == ENGINE_SUCCESS);
 
372
    assert(res == 0);
 
373
    h1->release(h, NULL, test_item);
 
374
    return SUCCESS;
 
375
}
 
376
 
 
377
/*
 
378
 * Make sure we can successfully perform a flush operation and that any item
 
379
 * stored before the flush can not be retrieved
 
380
 */
 
381
static enum test_result flush_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
382
    item *test_item = NULL;
 
383
    void *key = "flush_test_key";
 
384
    uint64_t cas = 0;
 
385
    test_harness.time_travel(3);
 
386
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1, 0, 0) == ENGINE_SUCCESS);
 
387
    assert(h1->store(h, NULL, test_item, &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
388
    assert(h1->flush(h, NULL, 0) == ENGINE_SUCCESS);
 
389
    item *check_item = test_item;
 
390
    assert(h1->get(h, NULL, &check_item, key, strlen(key), 0) ==  ENGINE_KEY_ENOENT);
 
391
    assert(check_item == NULL);
 
392
    h1->release(h, NULL, test_item);
 
393
    return SUCCESS;
 
394
}
 
395
 
 
396
/*
 
397
 * Make sure we can successfully retrieve the item info struct for an item and
 
398
 * that the contents of the item_info are as expected.
 
399
 */
 
400
static enum test_result get_item_info_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
401
    item *test_item = NULL;
 
402
    char *key = "get_item_info_test_key";
 
403
    uint64_t cas = 0;
 
404
    const rel_time_t exp = 1;
 
405
    item_info ii = { .nvalue = 1 };
 
406
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1,0, exp) == ENGINE_SUCCESS);
 
407
    assert(h1->store(h, NULL, test_item, &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
408
    /* Had this been actual code, there'd be a connection here */
 
409
    assert(h1->get_item_info(h, NULL, test_item, &ii) == true);
 
410
    assert(ii.cas == cas);
 
411
    assert(ii.flags == 0);
 
412
    assert(strcmp(key,ii.key) == 0);
 
413
    assert(ii.nkey == strlen(key));
 
414
    assert(ii.nbytes == 1);
 
415
    assert(ii.exptime == exp);
 
416
    h1->release(h, NULL, test_item);
 
417
    return SUCCESS;
 
418
}
 
419
 
 
420
static enum test_result item_set_cas_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
421
    item *test_item = NULL;
 
422
    char *key = "item_set_cas_test_key";
 
423
    uint64_t cas = 0;
 
424
    const rel_time_t exp = 1;
 
425
    item_info ii = { .nvalue = 1 };
 
426
    assert(h1->allocate(h, NULL, &test_item, key, strlen(key), 1,0, exp) == ENGINE_SUCCESS);
 
427
    assert(h1->store(h, NULL, test_item, &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
428
    uint64_t newcas = cas + 1;
 
429
    h1->item_set_cas(h, NULL, test_item, newcas);
 
430
    assert(h1->get_item_info(h, NULL, test_item, &ii) == true);
 
431
    assert(ii.cas == newcas);
 
432
    h1->release(h, NULL, test_item);
 
433
    return SUCCESS;
 
434
}
 
435
 
 
436
uint32_t evictions;
 
437
static void eviction_stats_handler(const char *key, const uint16_t klen,
 
438
                                   const char *val, const uint32_t vlen,
 
439
                                   const void *cookie) {
 
440
    if (memcmp(key, "evictions", klen) == 0) {
 
441
        char buffer[vlen + 1];
 
442
        memcpy(buffer, val, vlen);
 
443
        buffer[vlen] = '\0';
 
444
        evictions = atoi(buffer);
 
445
    }
 
446
}
 
447
 
 
448
static enum test_result lru_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
449
    item *test_item = NULL;
 
450
    const char *hot_key = "hot_key";
 
451
    uint64_t cas = 0;
 
452
    assert(h1->allocate(h, NULL, &test_item,
 
453
                        hot_key, strlen(hot_key), 4096, 0, 0) == ENGINE_SUCCESS);
 
454
    assert(h1->store(h, NULL, test_item,
 
455
                     &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
456
    h1->release(h, NULL, test_item);
 
457
 
 
458
    int ii;
 
459
    for (ii = 0; ii < 250; ++ii) {
 
460
        assert(h1->get(h, NULL, &test_item,
 
461
                       hot_key, strlen(hot_key), 0) ==  ENGINE_SUCCESS);
 
462
        h1->release(h, NULL, test_item);
 
463
        char key[1024];
 
464
        size_t keylen = snprintf(key, sizeof(key), "lru_test_key_%08d", ii);
 
465
        assert(h1->allocate(h, NULL, &test_item,
 
466
                            key, keylen, 4096, 0, 0) == ENGINE_SUCCESS);
 
467
        assert(h1->store(h, NULL, test_item,
 
468
                         &cas, OPERATION_SET,0) == ENGINE_SUCCESS);
 
469
        h1->release(h, NULL, test_item);
 
470
        assert(h1->get_stats(h, NULL, NULL, 0,
 
471
                             eviction_stats_handler) == ENGINE_SUCCESS);
 
472
        if (evictions == 2) {
 
473
            break;
 
474
        }
 
475
    }
 
476
 
 
477
    assert(ii < 250);
 
478
    for (int jj = 0; jj <= ii; ++jj) {
 
479
        char key[1024];
 
480
        size_t keylen = snprintf(key, sizeof(key), "lru_test_key_%08d", jj);
 
481
        if (jj == 0 || jj == 1) {
 
482
            assert(h1->get(h, NULL, &test_item,
 
483
                           key, keylen, 0) == ENGINE_KEY_ENOENT);
 
484
        } else {
 
485
            assert(h1->get(h, NULL, &test_item,
 
486
                           key, keylen, 0) == ENGINE_SUCCESS);
 
487
            assert(test_item != NULL);
 
488
            h1->release(h, NULL, test_item);
 
489
        }
 
490
    }
 
491
    return SUCCESS;
 
492
}
 
493
 
 
494
static enum test_result get_stats_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
495
    return PENDING;
 
496
}
 
497
 
 
498
static enum test_result reset_stats_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
499
    return PENDING;
 
500
}
 
501
 
 
502
static enum test_result get_stats_struct_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
503
    return PENDING;
 
504
}
 
505
 
 
506
static enum test_result aggregate_stats_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
507
    return PENDING;
 
508
}
 
509
 
 
510
static protocol_binary_response_header *last_response;
 
511
 
 
512
static void release_last_response(void) {
 
513
    free(last_response);
 
514
    last_response = NULL;
 
515
}
 
516
 
 
517
static bool response_handler(const void *key, uint16_t keylen,
 
518
                             const void *ext, uint8_t extlen,
 
519
                             const void *body, uint32_t bodylen,
 
520
                             uint8_t datatype, uint16_t status,
 
521
                             uint64_t cas, const void *cookie)
 
522
{
 
523
    assert(last_response == NULL);
 
524
    last_response = malloc(sizeof(*last_response) + keylen + extlen + bodylen);
 
525
    if (last_response == NULL) {
 
526
        return false;
 
527
    }
 
528
    protocol_binary_response_header *r = last_response;
 
529
    r->response.magic = PROTOCOL_BINARY_RES;
 
530
    r->response.opcode = 0xff; // we don't know this!
 
531
    r->response.keylen = htons(keylen);
 
532
    r->response.extlen = extlen;
 
533
    r->response.datatype = PROTOCOL_BINARY_RAW_BYTES;
 
534
    r->response.status = htons(status);
 
535
    r->response.bodylen = htonl(keylen + extlen + bodylen);
 
536
    r->response.opaque = 0xffffff; // we don't know this
 
537
    r->response.cas = cas;
 
538
    char *ptr = (void*)(r + 1);
 
539
    memcpy(ptr, ext, extlen);
 
540
    ptr += extlen;
 
541
    memcpy(ptr, key, keylen);
 
542
    ptr += keylen;
 
543
    memcpy(ptr, body, bodylen);
 
544
 
 
545
    return true;
 
546
}
 
547
 
 
548
static enum test_result touch_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
549
    union request {
 
550
        protocol_binary_request_touch touch;
 
551
        char buffer[512];
 
552
    };
 
553
 
 
554
    void *key = "get_test_key";
 
555
    size_t keylen = strlen(key);
 
556
    union request r = {
 
557
        .touch = {
 
558
            .message = {
 
559
                .header.request = {
 
560
                    .magic = PROTOCOL_BINARY_REQ,
 
561
                    .opcode = PROTOCOL_BINARY_CMD_TOUCH,
 
562
                    .keylen = htons((uint16_t)keylen),
 
563
                    .extlen = 4,
 
564
                    .datatype = PROTOCOL_BINARY_RAW_BYTES,
 
565
                    .vbucket = 0,
 
566
                    .bodylen = htonl(keylen + 4),
 
567
                    .opaque = 0xdeadbeef,
 
568
                    .cas = 0
 
569
                },
 
570
                .body = {
 
571
                    .expiration = htonl(10)
 
572
                }
 
573
            }
 
574
        }
 
575
    };
 
576
 
 
577
    memcpy(r.buffer + sizeof(r.touch.bytes), key, keylen);
 
578
    ENGINE_ERROR_CODE ret;
 
579
    ret = h1->unknown_command(h, NULL, &r.touch.message.header, response_handler);
 
580
    assert(ret == ENGINE_SUCCESS);
 
581
    assert(last_response != NULL);
 
582
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
 
583
    assert(last_response->response.keylen == 0);
 
584
    assert(last_response->response.extlen == 0);
 
585
    assert(last_response->response.bodylen == 0);
 
586
    release_last_response();
 
587
 
 
588
    // store and get a key
 
589
    assert(get_test(h, h1) == SUCCESS);
 
590
 
 
591
    // Set expiry time to 10 secs..
 
592
    ret = h1->unknown_command(h, NULL, &r.touch.message.header, response_handler);
 
593
    assert(ret == ENGINE_SUCCESS);
 
594
    assert(last_response != NULL);
 
595
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
596
    assert(last_response->response.keylen == 0);
 
597
    assert(last_response->response.extlen == 0);
 
598
    assert(last_response->response.bodylen == 0);
 
599
    release_last_response();
 
600
 
 
601
    // time-travel 11 secs..
 
602
    test_harness.time_travel(11);
 
603
 
 
604
    // The item should have expired now...
 
605
    item *item = NULL;
 
606
    assert(h1->get(h, NULL, &item, key, keylen, 0) == ENGINE_KEY_ENOENT);
 
607
 
 
608
    // Verify that it doesn't accept bogus packets. extlen is mandatory
 
609
    r.touch.message.header.request.extlen = 0;
 
610
    r.touch.message.header.request.bodylen = htonl(keylen);
 
611
    ret = h1->unknown_command(h, NULL, &r.touch.message.header, response_handler);
 
612
    assert(ret == ENGINE_SUCCESS);
 
613
    assert(last_response != NULL);
 
614
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_EINVAL);
 
615
    release_last_response();
 
616
 
 
617
    // key is mandatory!
 
618
    r.touch.message.header.request.extlen = 4;
 
619
    r.touch.message.header.request.keylen = 0;
 
620
    r.touch.message.header.request.bodylen = htonl(4);
 
621
    ret = h1->unknown_command(h, NULL, &r.touch.message.header, response_handler);
 
622
    assert(ret == ENGINE_SUCCESS);
 
623
    assert(last_response != NULL);
 
624
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_EINVAL);
 
625
    release_last_response();
 
626
 
 
627
    return SUCCESS;
 
628
}
 
629
 
 
630
static enum test_result gat_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
631
    union request {
 
632
        protocol_binary_request_gat gat;
 
633
        char buffer[512];
 
634
    };
 
635
 
 
636
    void *key = "get_test_key";
 
637
    size_t keylen = strlen(key);
 
638
    union request r = {
 
639
        .gat = {
 
640
            .message = {
 
641
                .header.request = {
 
642
                    .magic = PROTOCOL_BINARY_REQ,
 
643
                    .opcode = PROTOCOL_BINARY_CMD_GAT,
 
644
                    .keylen = htons((uint16_t)keylen),
 
645
                    .extlen = 4,
 
646
                    .datatype = PROTOCOL_BINARY_RAW_BYTES,
 
647
                    .vbucket = 0,
 
648
                    .bodylen = htonl(keylen + 4),
 
649
                    .opaque = 0xdeadbeef,
 
650
                    .cas = 0
 
651
                },
 
652
                .body = {
 
653
                    .expiration = htonl(10)
 
654
                }
 
655
            }
 
656
        }
 
657
    };
 
658
 
 
659
    memcpy(r.buffer + sizeof(r.gat.bytes), key, keylen);
 
660
    ENGINE_ERROR_CODE ret;
 
661
    ret = h1->unknown_command(h, NULL, &r.gat.message.header, response_handler);
 
662
    assert(ret == ENGINE_SUCCESS);
 
663
    assert(last_response != NULL);
 
664
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
 
665
    assert(last_response->response.keylen == 0);
 
666
    assert(last_response->response.extlen == 0);
 
667
    assert(last_response->response.bodylen == 0);
 
668
    release_last_response();
 
669
 
 
670
    // store and get a key
 
671
    assert(get_test(h, h1) == SUCCESS);
 
672
 
 
673
    // Set expiry time to 10 secs..
 
674
    ret = h1->unknown_command(h, NULL, &r.gat.message.header, response_handler);
 
675
    assert(ret == ENGINE_SUCCESS);
 
676
    assert(last_response != NULL);
 
677
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
678
    assert(last_response->response.keylen == 0);
 
679
    assert(last_response->response.extlen == 4);
 
680
    assert(ntohl(last_response->response.bodylen) == 5); // get_test sets 1 byte datalen
 
681
    release_last_response();
 
682
 
 
683
    // time-travel 11 secs..
 
684
    test_harness.time_travel(11);
 
685
 
 
686
    // The item should have expired now...
 
687
    item *item = NULL;
 
688
    assert(h1->get(h, NULL, &item, key, keylen, 0) == ENGINE_KEY_ENOENT);
 
689
 
 
690
    // Verify that it doesn't accept bogus packets. extlen is mandatory
 
691
    r.gat.message.header.request.extlen = 0;
 
692
    r.gat.message.header.request.bodylen = htonl(keylen);
 
693
    ret = h1->unknown_command(h, NULL, &r.gat.message.header, response_handler);
 
694
    assert(ret == ENGINE_SUCCESS);
 
695
    assert(last_response != NULL);
 
696
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_EINVAL);
 
697
    release_last_response();
 
698
 
 
699
    // key is mandatory!
 
700
    r.gat.message.header.request.extlen = 4;
 
701
    r.gat.message.header.request.keylen = 0;
 
702
    r.gat.message.header.request.bodylen = htonl(4);
 
703
    ret = h1->unknown_command(h, NULL, &r.gat.message.header, response_handler);
 
704
    assert(ret == ENGINE_SUCCESS);
 
705
    assert(last_response != NULL);
 
706
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_EINVAL);
 
707
    release_last_response();
 
708
 
 
709
    return SUCCESS;
 
710
}
 
711
 
 
712
static enum test_result gatq_test(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
 
713
    union request {
 
714
        protocol_binary_request_gat gat;
 
715
        char buffer[512];
 
716
    };
 
717
 
 
718
    void *key = "get_test_key";
 
719
    size_t keylen = strlen(key);
 
720
    union request r = {
 
721
        .gat = {
 
722
            .message = {
 
723
                .header.request = {
 
724
                    .magic = PROTOCOL_BINARY_REQ,
 
725
                    .opcode = PROTOCOL_BINARY_CMD_GATQ,
 
726
                    .keylen = htons((uint16_t)keylen),
 
727
                    .extlen = 4,
 
728
                    .datatype = PROTOCOL_BINARY_RAW_BYTES,
 
729
                    .vbucket = 0,
 
730
                    .bodylen = htonl(keylen + 4),
 
731
                    .opaque = 0xdeadbeef,
 
732
                    .cas = 0
 
733
                },
 
734
                .body = {
 
735
                    .expiration = htonl(10)
 
736
                }
 
737
            }
 
738
        }
 
739
    };
 
740
 
 
741
    memcpy(r.buffer + sizeof(r.gat.bytes), key, keylen);
 
742
    ENGINE_ERROR_CODE ret;
 
743
    ret = h1->unknown_command(h, NULL, &r.gat.message.header, response_handler);
 
744
    assert(ret == ENGINE_SUCCESS);
 
745
 
 
746
    // GATQ is quiet and should not produce any result
 
747
    assert(last_response == NULL);
 
748
 
 
749
    // store and get a key
 
750
    assert(get_test(h, h1) == SUCCESS);
 
751
 
 
752
    // Set expiry time to 10 secs..
 
753
    ret = h1->unknown_command(h, NULL, &r.gat.message.header, response_handler);
 
754
    assert(ret == ENGINE_SUCCESS);
 
755
    assert(last_response != NULL);
 
756
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_SUCCESS);
 
757
    assert(last_response->response.keylen == 0);
 
758
    assert(last_response->response.extlen == 4);
 
759
    assert(ntohl(last_response->response.bodylen) == 5); // get_test sets 1 byte datalen
 
760
    release_last_response();
 
761
 
 
762
    // time-travel 11 secs..
 
763
    test_harness.time_travel(11);
 
764
 
 
765
    // The item should have expired now...
 
766
    item *item = NULL;
 
767
    assert(h1->get(h, NULL, &item, key, keylen, 0) == ENGINE_KEY_ENOENT);
 
768
 
 
769
    // Verify that it doesn't accept bogus packets. extlen is mandatory
 
770
    r.gat.message.header.request.extlen = 0;
 
771
    r.gat.message.header.request.bodylen = htonl(keylen);
 
772
    ret = h1->unknown_command(h, NULL, &r.gat.message.header, response_handler);
 
773
    assert(ret == ENGINE_SUCCESS);
 
774
    assert(last_response != NULL);
 
775
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_EINVAL);
 
776
    release_last_response();
 
777
 
 
778
    // key is mandatory!
 
779
    r.gat.message.header.request.extlen = 4;
 
780
    r.gat.message.header.request.keylen = 0;
 
781
    r.gat.message.header.request.bodylen = htonl(4);
 
782
    ret = h1->unknown_command(h, NULL, &r.gat.message.header, response_handler);
 
783
    assert(ret == ENGINE_SUCCESS);
 
784
    assert(last_response != NULL);
 
785
    assert(ntohs(last_response->response.status) == PROTOCOL_BINARY_RESPONSE_EINVAL);
 
786
    release_last_response();
 
787
 
 
788
    return SUCCESS;
 
789
}
 
790
 
 
791
MEMCACHED_PUBLIC_API
 
792
engine_test_t* get_tests(void) {
 
793
    static engine_test_t tests[]  = {
 
794
        {"get info test", get_info_test, NULL, NULL, NULL},
 
795
        {"get info description test", get_info_description_test, NULL, NULL, NULL},
 
796
        {"get info features test", get_info_features_test, NULL, NULL, NULL},
 
797
        {"allocate test", allocate_test, NULL, NULL, NULL},
 
798
        {"set test", set_test, NULL, NULL, NULL},
 
799
        {"add test", add_test, NULL, NULL, NULL},
 
800
        {"replace test", replace_test, NULL, NULL, NULL},
 
801
        {"append test", append_test, NULL, NULL, NULL},
 
802
        {"prepend test", prepend_test, NULL, NULL, NULL},
 
803
        {"store test", store_test, NULL, NULL, NULL},
 
804
        {"get test", get_test, NULL, NULL, NULL},
 
805
        {"expiry test", expiry_test, NULL, NULL, NULL},
 
806
        {"remove test", remove_test, NULL, NULL, NULL},
 
807
        {"release test", release_test, NULL, NULL, NULL},
 
808
        {"incr test", incr_test, NULL, NULL, NULL},
 
809
        {"mt incr test", mt_incr_test, NULL, NULL, NULL},
 
810
        {"decr test", decr_test, NULL, NULL, NULL},
 
811
        {"flush test", flush_test, NULL, NULL, NULL},
 
812
        {"get item info test", get_item_info_test, NULL, NULL, NULL},
 
813
        {"set cas test", item_set_cas_test, NULL, NULL, NULL},
 
814
        {"LRU test", lru_test, NULL, NULL, "cache_size=48"},
 
815
        {"get stats test", get_stats_test, NULL, NULL, NULL},
 
816
        {"reset stats test", reset_stats_test, NULL, NULL, NULL},
 
817
        {"get stats struct test", get_stats_struct_test, NULL, NULL, NULL},
 
818
        {"aggregate stats test", aggregate_stats_test, NULL, NULL, NULL},
 
819
        {"touch", touch_test, NULL, NULL, NULL},
 
820
        {"Get And Touch", gat_test, NULL, NULL, NULL},
 
821
        {"Get And Touch Quiet", gatq_test, NULL, NULL, NULL},
 
822
        {NULL, NULL, NULL, NULL, NULL}
 
823
    };
 
824
    return tests;
 
825
}
 
826
 
 
827
MEMCACHED_PUBLIC_API
 
828
bool setup_suite(struct test_harness *th) {
 
829
    test_harness = *th;
 
830
    return true;
 
831
}
 
832