1 /* -*- MODE: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2010 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 
18 // Usage: (to repeatedly run just a single test case)
19 // make engine_tests IS_LOOP=-L EP_TEST_NUM=3
20 
21 #include "config.h"
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #ifdef _MSC_VER
28 #include <direct.h>
29 #define mkdir(a, b) _mkdir(a)
30 #else
31 #include <sys/wait.h>
32 #endif
33 
34 #include <cstdlib>
35 #include <iostream>
36 #include <map>
37 #include <set>
38 #include <sstream>
39 #include <string>
40 #include <vector>
41 
42 #include <platform/dirutils.h>
43 
44 #include "atomic.h"
45 #include "ep-engine/command_ids.h"
46 #include "ep_test_apis.h"
47 #include "ep_testsuite.h"
48 #include "locks.h"
49 #include "mock/mock_dcp.h"
50 #include "mutex.h"
51 
52 #include <snappy-c.h>
53 #include <JSON_checker.h>
54 
55 #ifdef linux
56 /* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
57  * optimize the conversion functions, but the prototypes generate warnings
58  * from gcc. The conversion methods isn't the bottleneck for my app, so
59  * just remove the warnings by undef'ing the optimization ..
60  */
61 #undef ntohs
62 #undef ntohl
63 #undef htons
64 #undef htonl
65 #endif
66 
67 // ptr_fun don't like the extern "C" thing for unlock cookie.. cast it
68 // away ;)
69 typedef void (*UNLOCK_COOKIE_T)(const void *cookie);
70 
71 extern "C" bool abort_msg(const char *expr, const char *msg, int line);
72 
73 template <typename T>
checkeqfn(T exp, T got, const char *msg, const char *file, const int linenum)74 static void checkeqfn(T exp, T got, const char *msg, const char *file, const int linenum) {
75     if (exp != got) {
76         std::stringstream ss;
77         ss << "Expected `" << exp << "', got `" << got << "' - " << msg;
78         abort_msg(ss.str().c_str(), file, linenum);
79     }
80 }
81 
82 #define checkeq(a, b, c) checkeqfn(a, b, c, __FILE__, __LINE__)
83 
84 extern "C" {
85 
86 #define check(expr, msg) \
87     static_cast<void>((expr) ? 0 : abort_msg(#expr, msg, __LINE__))
88 
89 #define WHITESPACE_DB "whitespace sucks.db"
90 #define MULTI_DISPATCHER_CONFIG \
91     "ht_size=129;ht_locks=3;chk_remover_stime=1;chk_period=60"
92 
93 struct test_harness testHarness;
94 
95 class ThreadData {
96 public:
ThreadData(ENGINE_HANDLE *eh, ENGINE_HANDLE_V1 *ehv1, int e=0)97     ThreadData(ENGINE_HANDLE *eh, ENGINE_HANDLE_V1 *ehv1,
98                int e=0) : h(eh), h1(ehv1), extra(e) {}
99     ENGINE_HANDLE    *h;
100     ENGINE_HANDLE_V1 *h1;
101     int               extra;
102 };
103 
abort_msg(const char *expr, const char *msg, int line)104 bool abort_msg(const char *expr, const char *msg, int line) {
105     fprintf(stderr, "%s:%d Test failed: `%s' (%s)\n",
106             __FILE__, line, msg, expr);
107     abort();
108     // UNREACHABLE
109     return false;
110 }
111 
112 static const char *dbname_env;
rmdb(void)113 static enum test_result rmdb(void)
114 {
115     const char *files[] = { WHITESPACE_DB,
116                             "/tmp/test",
117                             "/tmp/mutation.log",
118                             dbname_env,
119                             NULL };
120     int ii = 0;
121     while (files[ii] != NULL) {
122         CouchbaseDirectoryUtilities::rmrf(files[ii]);
123         if (access(files[ii], F_OK) != -1) {
124             std::cerr << "Failed to remove: " << files[ii] << " " << std::endl;
125             return FAIL;
126         }
127         ++ii;
128     }
129 
130     return SUCCESS;
131 }
132 
skipped_test_function(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)133 static enum test_result skipped_test_function(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
134     (void) h;
135     (void) h1;
136     return SKIPPED;
137 }
138 
teardown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)139 static bool teardown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
140     (void)h; (void)h1;
141     vals.clear();
142     return true;
143 }
144 
createTapConn(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char *name)145 static const void* createTapConn(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
146                                  const char *name) {
147     const void *cookie = testHarness.create_cookie();
148     testHarness.lock_cookie(cookie);
149     TAP_ITERATOR iter = h1->get_tap_iterator(h, cookie, name,
150                                              strlen(name),
151                                              TAP_CONNECT_FLAG_DUMP, NULL,
152                                              0);
153     check(iter != NULL, "Failed to create a tap iterator");
154     return cookie;
155 }
156 
check_key_value(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char* key, const char* val, size_t vlen, uint16_t vbucket = 0)157 static void check_key_value(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
158                             const char* key, const char* val, size_t vlen,
159                             uint16_t vbucket = 0) {
160     item_info info;
161     check(get_item_info(h, h1, &info, key, vbucket), "checking key and value");
162     check(info.nvalue == 1, "info.nvalue != 1");
163     check(vlen == info.value[0].iov_len, "Value length mismatch");
164     check(memcmp(info.value[0].iov_base, val, vlen) == 0, "Data mismatch");
165 }
166 
test_setup(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)167 static bool test_setup(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
168     wait_for_warmup_complete(h, h1);
169 
170     check(h1->get_stats(h, NULL, "prev-vbucket", 12, add_stats) == ENGINE_SUCCESS,
171           "Failed to get the previous state of vbuckets");
172     if (vals.find("vb_0") == vals.end()) {
173         check(set_vbucket_state(h, h1, 0, vbucket_state_active),
174               "Failed to set VB0 state.");
175     }
176 
177     wait_for_stat_change(h, h1, "ep_vb_snapshot_total", 0);
178 
179     // warmup is complete, notify ep engine that it must now enable
180     // data traffic
181     protocol_binary_request_header *pkt = createPacket(PROTOCOL_BINARY_CMD_ENABLE_TRAFFIC);
182     check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
183           "Failed to enable data traffic");
184     free(pkt);
185 
186     return true;
187 }
188 
test_getl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)189 static enum test_result test_getl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
190     const char *key = "k1";
191     uint16_t vbucketId = 0;
192     uint32_t expiration = 25;
193 
194     getl(h, h1, key, vbucketId, expiration);
195     check(last_status == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT,
196           "expected the key to be missing...");
197     if (last_body != NULL && (strcmp(last_body, "NOT_FOUND") != 0)) {
198         fprintf(stderr, "Should have returned NOT_FOUND. Getl Failed");
199         abort();
200     }
201 
202     item *i = NULL;
203     check(store(h, h1, NULL, OPERATION_SET, key, "{\"lock\":\"data\"}",
204                 &i, 0, vbucketId, 3600, PROTOCOL_BINARY_DATATYPE_JSON)
205           == ENGINE_SUCCESS, "Failed to store an item.");
206     h1->release(h, NULL, i);
207 
208     /* retry getl, should succeed */
209     getl(h, h1, key, vbucketId, expiration);
210     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
211           "Expected to be able to getl on first try");
212     check(strcmp("{\"lock\":\"data\"}", last_body) == 0, "Body was malformed.");
213     check(last_datatype == PROTOCOL_BINARY_DATATYPE_JSON,
214             "Expected datatype to be JSON");
215 
216     /* wait 16 seconds */
217     testHarness.time_travel(16);
218 
219     /* lock's taken so this should fail */
220     getl(h, h1, key, vbucketId, expiration);
221     check(last_status == PROTOCOL_BINARY_RESPONSE_ETMPFAIL,
222           "Expected to fail getl on second try");
223 
224     if (last_body != NULL && (strcmp(last_body, "LOCK_ERROR") != 0)) {
225         fprintf(stderr, "Should have returned LOCK_ERROR. Getl Failed");
226         abort();
227     }
228 
229     check(store(h, h1, NULL, OPERATION_SET, key, "lockdata2", &i, 0, vbucketId)
230           != ENGINE_SUCCESS, "Should have failed to store an item.");
231     h1->release(h, NULL, i);
232 
233     /* wait another 10 seconds */
234     testHarness.time_travel(10);
235 
236     /* retry set, should succeed */
237     check(store(h, h1, NULL, OPERATION_SET, key, "lockdata", &i, 0, vbucketId)
238           == ENGINE_SUCCESS, "Failed to store an item.");
239     h1->release(h, NULL, i);
240 
241     /* point to wrong vbucket, to test NOT_MY_VB response */
242     getl(h, h1, key, 10, expiration);
243     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
244           "Should have received not my vbucket response");
245 
246     /* acquire lock, should succeed */
247     getl(h, h1, key, vbucketId, expiration);
248     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
249           "Aquire lock should have succeeded");
250     check(last_datatype == PROTOCOL_BINARY_RAW_BYTES,
251             "Expected datatype to be RAW BYTES");
252 
253     /* try an incr operation followed by a delete, both of which should fail */
254     uint64_t cas = 0;
255     uint64_t result = 0;
256 
257     check(h1->arithmetic(h, NULL, key, 2, true, false, 1, 1, 0,
258                          &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
259                          0)  == ENGINE_TMPFAIL, "Incr failed");
260 
261 
262     check(del(h, h1, key, 0, 0) == ENGINE_TMPFAIL, "Delete failed");
263 
264 
265     /* bug MB 2699 append after getl should fail with ENGINE_TMPFAIL */
266 
267     testHarness.time_travel(26);
268 
269     char binaryData1[] = "abcdefg\0gfedcba";
270     char binaryData2[] = "abzdefg\0gfedcba";
271 
272     check(storeCasVb11(h, h1, NULL, OPERATION_SET, key,
273                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
274           == ENGINE_SUCCESS,
275           "Failed set.");
276     h1->release(h, NULL, i);
277 
278     /* acquire lock, should succeed */
279     getl(h, h1, key, vbucketId, expiration);
280     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
281           "Aquire lock should have succeeded");
282 
283     /* append should fail */
284     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, key,
285                        binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
286           == ENGINE_TMPFAIL,
287           "Append should fail.");
288     h1->release(h, NULL, i);
289 
290     /* bug MB 3252 & MB 3354.
291      * 1. Set a key with an expiry value.
292      * 2. Take a lock on the item before it expires
293      * 3. Wait for the item to expire
294      * 4. Perform a CAS operation, should fail
295      * 5. Perform a set operation, should succeed
296      */
297     const char *ekey = "test_expiry";
298     const char *edata = "some test data here.";
299 
300     item *it = NULL;
301 
302     check(h1->allocate(h, NULL, &it, ekey, strlen(ekey), strlen(edata), 0, 2,
303           PROTOCOL_BINARY_RAW_BYTES) == ENGINE_SUCCESS, "Allocation Failed");
304 
305     item_info info;
306     info.nvalue = 1;
307     if (!h1->get_item_info(h, NULL, it, &info)) {
308         abort();
309     }
310     memcpy(info.value[0].iov_base, edata, strlen(edata));
311 
312     check(h1->store(h, NULL, it, &cas, OPERATION_SET, 0) ==
313         ENGINE_SUCCESS, "Failed to Store item");
314     check_key_value(h, h1, ekey, edata, strlen(edata));
315     h1->release(h, NULL, it);
316 
317     testHarness.time_travel(3);
318     cas = last_cas;
319 
320     /* cas should fail */
321     check(storeCasVb11(h, h1, NULL, OPERATION_CAS, ekey,
322                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, cas, 0)
323           != ENGINE_SUCCESS,
324           "CAS succeeded.");
325     h1->release(h, NULL, i);
326 
327     /* but a simple store should succeed */
328     check(store(h, h1, NULL, OPERATION_SET, ekey, edata, &i, 0, vbucketId)
329           == ENGINE_SUCCESS, "Failed to store an item.");
330     h1->release(h, NULL, i);
331     return SUCCESS;
332 }
333 
test_unl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)334 static enum test_result test_unl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
335 
336     const char *key = "k2";
337     uint16_t vbucketId = 0;
338 
339     unl(h, h1, key, vbucketId);
340     check(last_status != PROTOCOL_BINARY_RESPONSE_SUCCESS,
341           "expected the key to be missing...");
342 
343     item *i = NULL;
344     check(store(h, h1, NULL, OPERATION_SET, key, "lockdata", &i, 0, vbucketId)
345           == ENGINE_SUCCESS, "Failed to store an item.");
346     h1->release(h, NULL, i);
347 
348     /* getl, should succeed */
349     getl(h, h1, key, vbucketId, 0);
350     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
351           "Expected to be able to getl on first try");
352 
353     /* save the returned cas value for later */
354     uint64_t cas = last_cas;
355 
356     /* lock's taken unlocking with a random cas value should fail */
357     unl(h, h1, key, vbucketId);
358     check(last_status == PROTOCOL_BINARY_RESPONSE_ETMPFAIL,
359           "Expected to fail getl on second try");
360 
361     if (last_body != NULL && (strcmp(last_body, "UNLOCK_ERROR") != 0)) {
362         fprintf(stderr, "Should have returned UNLOCK_ERROR. Unl Failed");
363         abort();
364     }
365 
366     unl(h, h1, key, vbucketId, cas);
367     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
368           "Expected to succed unl with correct cas");
369 
370     /* acquire lock, should succeed */
371     getl(h, h1, key, vbucketId, 0);
372 
373     /* wait 16 seconds */
374     testHarness.time_travel(16);
375 
376     /* lock has expired, unl should fail */
377     unl(h, h1, key, vbucketId, last_cas);
378     check(last_status == PROTOCOL_BINARY_RESPONSE_ETMPFAIL,
379           "Expected to fail unl on lock timeout");
380 
381     return SUCCESS;
382 }
383 
test_wrong_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, ENGINE_STORE_OPERATION op)384 static enum test_result test_wrong_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
385                                                ENGINE_STORE_OPERATION op) {
386     item *i = NULL;
387     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
388     uint64_t cas = 11;
389     if (op == OPERATION_ADD) {
390         // Add operation with cas != 0 doesn't make sense
391         cas = 0;
392     }
393     check(store(h, h1, NULL, op,
394                 "key", "somevalue", &i, cas, 1) == ENGINE_NOT_MY_VBUCKET,
395         "Expected not_my_vbucket");
396     h1->release(h, NULL, i);
397     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
398     return SUCCESS;
399 }
400 
test_pending_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, ENGINE_STORE_OPERATION op)401 static enum test_result test_pending_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
402                                                  ENGINE_STORE_OPERATION op) {
403     const void *cookie = testHarness.create_cookie();
404     testHarness.set_ewouldblock_handling(cookie, false);
405     item *i = NULL;
406     check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
407     check(verify_vbucket_state(h, h1, 1, vbucket_state_pending), "Bucket state was not set to pending.");
408     uint64_t cas = 11;
409     if (op == OPERATION_ADD) {
410         // Add operation with cas != 0 doesn't make sense..
411         cas = 0;
412     }
413     check(store(h, h1, cookie, op,
414                 "key", "somevalue", &i, cas, 1) == ENGINE_EWOULDBLOCK,
415         "Expected woodblock");
416     h1->release(h, NULL, i);
417     testHarness.destroy_cookie(cookie);
418     return SUCCESS;
419 }
420 
test_replica_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, ENGINE_STORE_OPERATION op)421 static enum test_result test_replica_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
422                                                  ENGINE_STORE_OPERATION op) {
423     item *i = NULL;
424     check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
425     check(verify_vbucket_state(h, h1, 1, vbucket_state_replica), "Bucket state was not set to replica.");
426     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
427 
428     uint64_t cas = 11;
429     if (op == OPERATION_ADD) {
430         // performing add with a CAS != 0 doesn't make sense...
431         cas = 0;
432     }
433     check(store(h, h1, NULL, op,
434                 "key", "somevalue", &i, cas, 1) == ENGINE_NOT_MY_VBUCKET,
435         "Expected not my vbucket");
436     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
437     h1->release(h, NULL, i);
438     return SUCCESS;
439 }
440 
441 //
442 // ----------------------------------------------------------------------
443 // The actual tests are below.
444 // ----------------------------------------------------------------------
445 //
446 
test_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)447 static enum test_result test_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
448     check(verify_key(h, h1, "k") == ENGINE_KEY_ENOENT, "Expected miss.");
449     return SUCCESS;
450 }
451 
test_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)452 static enum test_result test_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
453     item *i = NULL;
454     check(ENGINE_SUCCESS ==
455           store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
456           "Error setting.");
457     h1->release(h, NULL, i);
458     return SUCCESS;
459 }
460 
461 struct handle_pair {
462     ENGINE_HANDLE *h;
463     ENGINE_HANDLE_V1 *h1;
464 };
465 
466 extern "C" {
conc_del_set_thread(void *arg)467     static void conc_del_set_thread(void *arg) {
468         struct handle_pair *hp = static_cast<handle_pair *>(arg);
469         item *it = NULL;
470 
471         for (int i = 0; i < 5000; ++i) {
472             store(hp->h, hp->h1, NULL, OPERATION_ADD,
473                   "key", "somevalue", &it);
474             hp->h1->release(hp->h, NULL, it);
475             usleep(10);
476             checkeq(ENGINE_SUCCESS,
477                     store(hp->h, hp->h1, NULL, OPERATION_SET,
478                           "key", "somevalue", &it),
479                     "Error setting.");
480             hp->h1->release(hp->h, NULL, it);
481             usleep(10);
482             // Ignoring the result here -- we're racing.
483             del(hp->h, hp->h1, "key", 0, 0);
484             usleep(10);
485         }
486     }
487 
conc_incr_thread(void *arg)488     static void conc_incr_thread(void *arg) {
489         struct handle_pair *hp = static_cast<handle_pair *>(arg);
490         uint64_t cas = 0, result = 0;
491 
492         for (int i = 0; i < 10; i++) {
493             check(hp->h1->arithmetic(hp->h, NULL, "key", 3, true, true, 1, 1, 0,
494                                      &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
495                                      0) == ENGINE_SUCCESS,
496                                      "Failed arithmetic operation");
497         }
498     }
499 }
500 
test_conc_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)501 static enum test_result test_conc_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
502 
503     const int n_threads = 8;
504     cb_thread_t threads[n_threads];
505     struct handle_pair hp = {h, h1};
506 
507     wait_for_persisted_value(h, h1, "key", "value1");
508 
509     for (int i = 0; i < n_threads; i++) {
510         int r = cb_create_thread(&threads[i], conc_del_set_thread, &hp, 0);
511         cb_assert(r == 0);
512     }
513 
514     for (int i = 0; i < n_threads; i++) {
515         int r = cb_join_thread(threads[i]);
516         cb_assert(r == 0);
517     }
518 
519     wait_for_flusher_to_settle(h, h1);
520 
521     testHarness.reload_engine(&h, &h1,
522                               testHarness.engine_path,
523                               testHarness.get_current_testcase()->cfg,
524                               true, false);
525     wait_for_warmup_complete(h, h1);
526 
527     cb_assert(0 == get_int_stat(h, h1, "ep_warmed_dups"));
528 
529     return SUCCESS;
530 }
531 
test_conc_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)532 static enum test_result test_conc_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
533     const int n_threads = 10;
534     cb_thread_t threads[n_threads];
535     struct handle_pair hp = {h, h1};
536     item *i = NULL;
537     check(store(h, h1, NULL, OPERATION_SET, "key", "0", &i) == ENGINE_SUCCESS,
538           "store failure");
539     h1->release(h, NULL, i);
540 
541     for (int i = 0; i < n_threads; i++) {
542         int r = cb_create_thread(&threads[i], conc_incr_thread, &hp, 0);
543         cb_assert(r == 0);
544     }
545 
546     for (int i = 0; i < n_threads; i++) {
547         int r = cb_join_thread(threads[i]);
548         cb_assert(r == 0);
549     }
550 
551     check_key_value(h, h1, "key", "100", 3);
552 
553     return SUCCESS;
554 }
555 
556 
test_set_get_hit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)557 static enum test_result test_set_get_hit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
558     item *i = NULL;
559     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
560           "store failure");
561     check_key_value(h, h1, "key", "somevalue", 9);
562     h1->release(h, NULL, i);
563     return SUCCESS;
564 }
565 
test_set_get_hit_bin(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)566 static enum test_result test_set_get_hit_bin(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
567     char binaryData[] = "abcdefg\0gfedcba";
568     cb_assert(sizeof(binaryData) != strlen(binaryData));
569 
570     item *i = NULL;
571     check(ENGINE_SUCCESS ==
572           storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
573                        binaryData, sizeof(binaryData), 82758, &i, 0, 0),
574           "Failed to set.");
575     h1->release(h, NULL, i);
576     check_key_value(h, h1, "key", binaryData, sizeof(binaryData));
577     return SUCCESS;
578 }
579 
test_set_with_cas_non_existent(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)580 static enum test_result test_set_with_cas_non_existent(ENGINE_HANDLE *h,
581                                                        ENGINE_HANDLE_V1 *h1) {
582     const char *key = "test_expiry_flush";
583     item *i = NULL;
584 
585     check(h1->allocate(h, NULL, &i, key, strlen(key), 10, 0, 0,
586           PROTOCOL_BINARY_RAW_BYTES) == ENGINE_SUCCESS, "Allocation failed.");
587 
588     Item *it = reinterpret_cast<Item*>(i);
589     it->setCas(1234);
590 
591     uint64_t cas = 0;
592     check(h1->store(h, NULL, i, &cas, OPERATION_SET, 0) == ENGINE_KEY_ENOENT,
593           "Expected not found");
594     h1->release(h, NULL, i);
595 
596     return SUCCESS;
597 }
598 
test_set_change_flags(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)599 static enum test_result test_set_change_flags(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
600     item *i = NULL;
601     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
602           "Failed to set.");
603     h1->release(h, NULL, i);
604 
605     item_info info;
606     uint32_t flags = 828258;
607     check(get_item_info(h, h1, &info, "key"), "Failed to get value.");
608     cb_assert(info.flags != flags);
609 
610     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
611                        "newvalue", strlen("newvalue"), flags, &i, 0, 0) == ENGINE_SUCCESS,
612           "Failed to set again.");
613     h1->release(h, NULL, i);
614 
615     check(get_item_info(h, h1, &info, "key"), "Failed to get value.");
616 
617     return info.flags == flags ? SUCCESS : FAIL;
618 }
619 
test_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)620 static enum test_result test_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
621     item *i = NULL;
622     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
623           "Failed to do initial set.");
624     h1->release(h, NULL, i);
625     check(store(h, h1, NULL, OPERATION_CAS, "key", "failcas", &i) != ENGINE_SUCCESS,
626           "Failed to fail initial CAS.");
627     h1->release(h, NULL, i);
628     check_key_value(h, h1, "key", "somevalue", 9);
629 
630     check(h1->get(h, NULL, &i, "key", 3, 0) == ENGINE_SUCCESS,
631           "Failed to get value.");
632 
633     item_info info;
634     info.nvalue = 1;
635     check(h1->get_item_info(h, NULL, i, &info), "Failed to get item info.");
636     h1->release(h, NULL, i);
637 
638     check(store(h, h1, NULL, OPERATION_CAS, "key", "winCas", &i,
639                 info.cas) == ENGINE_SUCCESS,
640           "Failed to store CAS");
641     h1->release(h, NULL, i);
642     check_key_value(h, h1, "key", "winCas", 6);
643 
644     uint64_t cval = 99999;
645     check(store(h, h1, NULL, OPERATION_CAS, "non-existing", "winCas", &i,
646                 cval) == ENGINE_KEY_ENOENT,
647           "CAS for non-existing key returned the wrong error code");
648     h1->release(h, NULL, i);
649     return SUCCESS;
650 }
651 
test_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)652 static enum test_result test_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
653     item *i = NULL;
654     check(store(h, h1, NULL, OPERATION_ADD,"key", "somevalue", &i) == ENGINE_SUCCESS,
655           "Failed to add value.");
656     h1->release(h, NULL, i);
657     check(store(h, h1, NULL, OPERATION_ADD,"key", "somevalue", &i) == ENGINE_NOT_STORED,
658           "Failed to fail to re-add value.");
659     h1->release(h, NULL, i);
660 
661     // This aborts on failure.
662     check_key_value(h, h1, "key", "somevalue", 9);
663 
664     // Expiration above was an hour, so let's go to The Future
665     testHarness.time_travel(3800);
666 
667     check(store(h, h1, NULL, OPERATION_ADD,"key", "newvalue", &i) == ENGINE_SUCCESS,
668           "Failed to add value again.");
669     h1->release(h, NULL, i);
670     check_key_value(h, h1, "key", "newvalue", 8);
671     return SUCCESS;
672 }
673 
test_add_add_with_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)674 static enum test_result test_add_add_with_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
675     item *i = NULL;
676     check(store(h, h1, NULL, OPERATION_ADD, "key",
677                 "somevalue", &i) == ENGINE_SUCCESS,
678           "Failed set.");
679     check_key_value(h, h1, "key", "somevalue", 9);
680     item_info info;
681     info.nvalue = 1;
682     info.nvalue = 1;
683     check(h1->get_item_info(h, NULL, i, &info) == true,
684           "Should be able to get info");
685 
686     item *i2 = NULL;
687     ENGINE_ERROR_CODE ret;
688     check((ret = store(h, h1, NULL, OPERATION_ADD, "key",
689                        "somevalue", &i2, info.cas)) == ENGINE_KEY_EEXISTS,
690           "Should not be able to add the key two times");
691 
692     h1->release(h, NULL, i);
693     h1->release(h, NULL, i2);
694     return SUCCESS;
695 }
696 
test_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)697 static enum test_result test_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
698     item *i = NULL;
699     check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue", &i) != ENGINE_SUCCESS,
700           "Failed to fail to replace non-existing value.");
701     h1->release(h, NULL, i);
702     check(store(h, h1, NULL, OPERATION_SET,"key", "somevalue", &i) == ENGINE_SUCCESS,
703           "Failed to set value.");
704     h1->release(h, NULL, i);
705     check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue", &i) == ENGINE_SUCCESS,
706           "Failed to replace existing value.");
707     h1->release(h, NULL, i);
708     check_key_value(h, h1, "key", "somevalue", 9);
709     return SUCCESS;
710 }
711 
test_replace_with_eviction(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)712 static enum test_result test_replace_with_eviction(ENGINE_HANDLE *h,
713                                                    ENGINE_HANDLE_V1 *h1) {
714     item *i = NULL;
715     check(store(h, h1, NULL, OPERATION_SET,"key", "somevalue", &i) == ENGINE_SUCCESS,
716           "Failed to set value.");
717     h1->release(h, NULL, i);
718     wait_for_flusher_to_settle(h, h1);
719     evict_key(h, h1, "key");
720     int numBgFetched = get_int_stat(h, h1, "ep_bg_fetched");
721 
722     check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue1", &i) == ENGINE_SUCCESS,
723           "Failed to replace existing value.");
724 
725     check(h1->get_stats(h, NULL, NULL, 0, add_stats) == ENGINE_SUCCESS,
726           "Failed to get stats.");
727     std::string eviction_policy = vals.find("ep_item_eviction_policy")->second;
728     if (eviction_policy == "full_eviction") {
729         numBgFetched++;
730     }
731 
732     check(get_int_stat(h, h1, "ep_bg_fetched") == numBgFetched,
733           "Bg fetched value didn't match");
734 
735     h1->release(h, NULL, i);
736     check_key_value(h, h1, "key", "somevalue1", 10);
737     return SUCCESS;
738 }
739 
test_incr_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)740 static enum test_result test_incr_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
741     uint64_t cas = 0, result = 0;
742     h1->arithmetic(h, NULL, "key", 3, true, false, 1, 0, 0,
743                    &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
744                    0);
745     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected to not find key");
746     return SUCCESS;
747 }
748 
test_incr_default(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)749 static enum test_result test_incr_default(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
750     uint64_t cas = 0, result = 0;
751     check(h1->arithmetic(h, NULL, "key", 3, true, true, 1, 1, 0,
752                          &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
753                          0) == ENGINE_SUCCESS,
754           "Failed first arith");
755     check(result == 1, "Failed result verification.");
756 
757     check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
758                          &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
759                          0) == ENGINE_SUCCESS,
760           "Failed second arith.");
761     check(result == 2, "Failed second result verification.");
762 
763     check(h1->arithmetic(h, NULL, "key", 3, true, true, 1, 1, 0,
764                          &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
765                          0) == ENGINE_SUCCESS,
766           "Failed third arith.");
767     check(result == 3, "Failed third result verification.");
768 
769     check_key_value(h, h1, "key", "3", 1);
770     return SUCCESS;
771 }
772 
test_append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)773 static enum test_result test_append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
774     item *i = NULL;
775 
776     // MB-11332: append on non-existing key should return NOT_STORED
777     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
778                        "foo\r\n", 5, 82758, &i, 0, 0)
779           == ENGINE_NOT_STORED,
780           "MB-11332: Failed append.");
781 
782     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
783                        "\r\n", 2, 82758, &i, 0, 0)
784           == ENGINE_SUCCESS,
785           "Failed set.");
786     h1->release(h, NULL, i);
787 
788     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
789                        "foo\r\n", 5, 82758, &i, 0, 0)
790           == ENGINE_SUCCESS,
791           "Failed append.");
792     h1->release(h, NULL, i);
793 
794     check_key_value(h, h1, "key", "\r\nfoo\r\n", 7);
795 
796     char binaryData1[] = "abcdefg\0gfedcba\r\n";
797     char binaryData2[] = "abzdefg\0gfedcba\r\n";
798     size_t dataSize = 20*1024*1024;
799     char *bigBinaryData3 = new char[dataSize];
800     memset(bigBinaryData3, '\0', dataSize);
801 
802     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
803                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
804           == ENGINE_SUCCESS,
805           "Failed set.");
806     h1->release(h, NULL, i);
807 
808     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
809                        bigBinaryData3, dataSize, 82758, &i, 0, 0)
810           == ENGINE_E2BIG,
811           "Expected append failure.");
812     h1->release(h, NULL, i);
813     delete[] bigBinaryData3;
814 
815     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
816                        binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
817           == ENGINE_SUCCESS,
818           "Failed append.");
819     h1->release(h, NULL, i);
820 
821     std::string expected;
822     expected.append(binaryData1, sizeof(binaryData1) - 1);
823     expected.append(binaryData2, sizeof(binaryData2) - 1);
824 
825     check_key_value(h, h1, "key", expected.data(), expected.length());
826     return SUCCESS;
827 }
828 
test_prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)829 static enum test_result test_prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
830     item *i = NULL;
831 
832     // MB-11332: prepend on non-existing key should return NOT_STORED
833     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
834                        "foo\r\n", 5, 82758, &i, 0, 0)
835           == ENGINE_NOT_STORED,
836           "MB-11332: Failed prepend.");
837 
838 
839     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
840                        "\r\n", 2, 82758, &i, 0, 0)
841           == ENGINE_SUCCESS,
842           "Failed set.");
843     h1->release(h, NULL, i);
844 
845     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
846                        "foo\r\n", 5, 82758, &i, 0, 0)
847           == ENGINE_SUCCESS,
848           "Failed append.");
849     h1->release(h, NULL, i);
850 
851     check_key_value(h, h1, "key", "foo\r\n\r\n", 7);
852 
853     char binaryData1[] = "abcdefg\0gfedcba\r\n";
854     char binaryData2[] = "abzdefg\0gfedcba\r\n";
855     size_t dataSize = 20*1024*1024;
856     char *bigBinaryData3 = new char[dataSize];
857     memset(bigBinaryData3, '\0', dataSize);
858 
859     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
860                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
861           == ENGINE_SUCCESS,
862           "Failed set.");
863     h1->release(h, NULL, i);
864 
865     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
866                        bigBinaryData3, dataSize, 82758, &i, 0, 0)
867           == ENGINE_E2BIG,
868           "Expected prepend failure.");
869     h1->release(h, NULL, i);
870     delete[] bigBinaryData3;
871 
872     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
873                        binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
874           == ENGINE_SUCCESS,
875           "Failed append.");
876     h1->release(h, NULL, i);
877 
878     std::string expected;
879     expected.append(binaryData2, sizeof(binaryData2) - 1);
880     expected.append(binaryData1, sizeof(binaryData1) - 1);
881 
882     check_key_value(h, h1, "key", expected.data(), expected.length());
883     return SUCCESS;
884 }
885 
test_append_compressed(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)886 static enum test_result test_append_compressed(ENGINE_HANDLE *h,
887                                                ENGINE_HANDLE_V1 *h1) {
888 
889     item *i = NULL;
890 
891     size_t len = snappy_max_compressed_length(2);
892     char *newBuf = (char *) malloc (len);
893     snappy_compress("\r\n", 2, newBuf, &len);
894     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key1",
895                        (const char *)newBuf, len, 82758, &i, 0, 0, 3600,
896                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
897           == ENGINE_SUCCESS, "Failed set.");
898     h1->release(h, NULL, i);
899     free (newBuf);
900 
901     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key1",
902                        "foo\r\n", 5, 82758, &i, 0, 0)
903           == ENGINE_SUCCESS,
904           "Failed append uncompressed to compressed.");
905     h1->release(h, NULL, i);
906 
907     size_t len1 = snappy_max_compressed_length(7);
908     char *newBuf1 = (char *) malloc (len1);
909     snappy_compress("\r\nfoo\r\n", 7, newBuf1, &len1);
910 
911     item_info info;
912     check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
913     check(info.nvalue == 1, "info.nvalue != 1");
914     check(len1 == info.value[0].iov_len, "Value length mismatch");
915     check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
916     check(info.datatype == 0x02, "Datatype mismatch");
917     free (newBuf1);
918 
919     len = snappy_max_compressed_length(3);
920     newBuf = (char *) malloc (len);
921     snappy_compress("bar", 3, newBuf, &len);
922     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key1",
923                        (const char*)newBuf, len, 82758, &i, 0, 0, 3600,
924                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
925             == ENGINE_SUCCESS,
926             "Failed append compressed to compressed.");
927     h1->release(h, NULL, i);
928     free (newBuf);
929 
930     len1 = snappy_max_compressed_length(10);
931     newBuf1 = (char *) malloc (len1);
932     snappy_compress("\r\nfoo\r\nbar", 10, newBuf1, &len1);
933 
934     check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
935     check(info.nvalue == 1, "info.nvalue != 1");
936     check(len1 == info.value[0].iov_len, "Value length mismatch");
937     check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
938     check(info.datatype == 0x02, "Datatype mismatch");
939     free (newBuf1);
940 
941     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key2",
942                        "foo", 3, 82758, &i, 0, 0, 3600,
943                        PROTOCOL_BINARY_RAW_BYTES)
944           == ENGINE_SUCCESS, "Failed set.");
945     h1->release(h, NULL, i);
946 
947     len = snappy_max_compressed_length(3);
948     newBuf = (char *) malloc (len);
949     snappy_compress("bar", 3, newBuf, &len);
950     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key2",
951                        newBuf, len, 82758, &i, 0, 0, 3600,
952                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
953             == ENGINE_SUCCESS,
954             "Failed append compressed to uncompressed.");
955     h1->release(h, NULL, i);
956     free (newBuf);
957 
958     check(get_item_info(h, h1, &info, "key2", 0), "checking key and value");
959     check(info.nvalue == 1, "info.nvalue != 1");
960     check(info.value[0].iov_len == 6, "Value length mismatch");
961     check(memcmp(info.value[0].iov_base, "foobar", 6) == 0, "Data mismatch");
962     check(info.datatype == 0x00, "Datatype mismatch");
963 
964     return SUCCESS;
965 }
966 
test_prepend_compressed(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)967 static enum test_result test_prepend_compressed(ENGINE_HANDLE *h,
968                                                ENGINE_HANDLE_V1 *h1) {
969 
970     item *i = NULL;
971 
972     size_t len = snappy_max_compressed_length(2);
973     char *newBuf = (char *) malloc (len);
974     snappy_compress("\r\n", 2, newBuf, &len);
975     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key1",
976                        (const char *)newBuf, len, 82758, &i, 0, 0, 3600,
977                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
978           == ENGINE_SUCCESS, "Failed set.");
979     h1->release(h, NULL, i);
980     free (newBuf);
981 
982     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key1",
983                        "foo\r\n", 5, 82758, &i, 0, 0)
984           == ENGINE_SUCCESS,
985           "Failed prepend uncompressed to compressed.");
986     h1->release(h, NULL, i);
987 
988     size_t len1 = snappy_max_compressed_length(7);
989     char *newBuf1 = (char *) malloc (len1);
990     snappy_compress("foo\r\n\r\n", 7, newBuf1, &len1);
991 
992     item_info info;
993     check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
994     check(info.nvalue == 1, "info.nvalue != 1");
995     check(len1 == info.value[0].iov_len, "Value length mismatch");
996     check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
997     check(info.datatype == 0x02, "Datatype mismatch");
998     free (newBuf1);
999 
1000     len = snappy_max_compressed_length(3);
1001     newBuf = (char *) malloc (len);
1002     snappy_compress("bar", 3, newBuf, &len);
1003     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key1",
1004                        (const char*)newBuf, len, 82758, &i, 0, 0, 3600,
1005                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1006             == ENGINE_SUCCESS,
1007             "Failed prepend compressed to compressed.");
1008     h1->release(h, NULL, i);
1009     free (newBuf);
1010 
1011     len1 = snappy_max_compressed_length(10);
1012     newBuf1 = (char *) malloc (len1);
1013     snappy_compress("barfoo\r\n\r\n", 10, newBuf1, &len1);
1014 
1015     check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
1016     check(info.nvalue == 1, "info.nvalue != 1");
1017     check(len1 == info.value[0].iov_len, "Value length mismatch");
1018     check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
1019     check(info.datatype == 0x02, "Datatype mismatch");
1020     free (newBuf1);
1021 
1022     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key2",
1023                        "foo", 3, 82758, &i, 0, 0, 3600,
1024                        PROTOCOL_BINARY_RAW_BYTES)
1025           == ENGINE_SUCCESS, "Failed set.");
1026     h1->release(h, NULL, i);
1027 
1028     len = snappy_max_compressed_length(3);
1029     newBuf = (char *) malloc (len);
1030     snappy_compress("bar", 3, newBuf, &len);
1031     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key2",
1032                        newBuf, len, 82758, &i, 0, 0, 3600,
1033                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1034             == ENGINE_SUCCESS,
1035             "Failed prepend compressed to uncompressed.");
1036     h1->release(h, NULL, i);
1037     free (newBuf);
1038 
1039     check(get_item_info(h, h1, &info, "key2", 0), "checking key and value");
1040     check(info.nvalue == 1, "info.nvalue != 1");
1041     check(info.value[0].iov_len == 6, "Value length mismatch");
1042     check(memcmp(info.value[0].iov_base, "barfoo", 6) == 0, "Data mismatch");
1043     check(info.datatype == 0x00, "Datatype mismatch");
1044 
1045     return SUCCESS;
1046 }
1047 
test_append_prepend_to_json(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1048 static enum test_result test_append_prepend_to_json(ENGINE_HANDLE *h,
1049                                                     ENGINE_HANDLE_V1 *h1) {
1050     item *i = NULL;
1051     item_info info;
1052 
1053     const char* key1 = "foo1";
1054     const char* key2 = "foo2";
1055     const char* value1 = "{\"foo1\":\"bar1\"}";
1056     const char* value2 = "{\"foo2\":\"bar2\"}";
1057 
1058     // APPEND
1059     check(storeCasVb11(h, h1, NULL, OPERATION_SET, key1,
1060                        value1, strlen(value1), 82758, &i, 0, 0,
1061                        3600, PROTOCOL_BINARY_DATATYPE_JSON)
1062           == ENGINE_SUCCESS, "Failed set.");
1063     h1->release(h, NULL, i);
1064 
1065     check(h1->get(h, NULL, &i, key1, strlen(key1), 0) == ENGINE_SUCCESS,
1066             "Unable to get stored item");
1067     h1->release(h, NULL, i);
1068     info.nvalue = 1;
1069     h1->get_item_info(h, NULL, i, &info);
1070     check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1071                         (int)info.value[0].iov_len) == 1, "Expected JSON");
1072     check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1073 
1074     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, key1,
1075                        value2, strlen(value2), 82758, &i, 0, 0)
1076           == ENGINE_SUCCESS,
1077           "Failed append.");
1078     h1->release(h, NULL, i);
1079 
1080     check(h1->get(h, NULL, &i, key1, strlen(key1), 0) == ENGINE_SUCCESS,
1081             "Unable to get stored item");
1082     info.nvalue = 1;
1083     h1->get_item_info(h, NULL, i, &info);
1084     h1->release(h, NULL, i);
1085     check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1086                         (int)info.value[0].iov_len) == 0, "Expected Binary");
1087     check(info.datatype == PROTOCOL_BINARY_RAW_BYTES,
1088                 "Invalid datatype after append");
1089 
1090     // PREPEND
1091     check(storeCasVb11(h, h1, NULL, OPERATION_SET, key2,
1092                        value1, strlen(value1), 82758, &i, 0, 0,
1093                        3600, PROTOCOL_BINARY_DATATYPE_JSON)
1094           == ENGINE_SUCCESS, "Failed set.");
1095     h1->release(h, NULL, i);
1096 
1097     check(h1->get(h, NULL, &i, key2, strlen(key2), 0) == ENGINE_SUCCESS,
1098             "Unable to get stored item");
1099     info.nvalue = 1;
1100     h1->get_item_info(h, NULL, i, &info);
1101     h1->release(h, NULL, i);
1102     check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1103                         (int)info.value[0].iov_len) == 1, "Expected JSON");
1104     check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1105 
1106     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, key2,
1107                        value2, strlen(value2), 82758, &i, 0, 0)
1108           == ENGINE_SUCCESS,
1109           "Failed prepend.");
1110     h1->release(h, NULL, i);
1111 
1112     check(h1->get(h, NULL, &i, key2, strlen(key2), 0) == ENGINE_SUCCESS,
1113             "Unable to get stored item");
1114     h1->release(h, NULL, i);
1115     info.nvalue = 1;
1116     h1->get_item_info(h, NULL, i, &info);
1117     check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1118                         (int)info.value[0].iov_len) == 0, "Expected Binary");
1119     check(info.datatype == PROTOCOL_BINARY_RAW_BYTES,
1120                 "Invalid datatype after prepend");
1121 
1122     return SUCCESS;
1123 }
1124 
test_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1125 static enum test_result test_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1126     uint64_t cas = 0, result = 0;
1127     item *i = NULL;
1128     check(store(h, h1, NULL, OPERATION_ADD,"key", "1", &i) == ENGINE_SUCCESS,
1129           "Failed to add value.");
1130     h1->release(h, NULL, i);
1131 
1132     check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
1133                          &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
1134                          0) == ENGINE_SUCCESS,
1135           "Failed to incr value.");
1136 
1137     check_key_value(h, h1, "key", "2", 1);
1138     return SUCCESS;
1139 }
1140 
test_bug2799(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1141 static enum test_result test_bug2799(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1142     uint64_t cas = 0, result = 0;
1143     item *i = NULL;
1144     check(store(h, h1, NULL, OPERATION_ADD, "key", "1", &i) == ENGINE_SUCCESS,
1145           "Failed to add value.");
1146     h1->release(h, NULL, i);
1147 
1148     check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
1149                          &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
1150                          0) == ENGINE_SUCCESS,
1151           "Failed to incr value.");
1152 
1153     check_key_value(h, h1, "key", "2", 1);
1154 
1155     testHarness.time_travel(3617);
1156 
1157     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1158     return SUCCESS;
1159 }
1160 
test_flush(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1161 static enum test_result test_flush(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1162     item *i = NULL;
1163     // First try to delete something we know to not be there.
1164     check(del(h, h1, "key", 0, 0) == ENGINE_KEY_ENOENT, "Failed to fail initial delete.");
1165     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1166           "Failed set.");
1167     h1->release(h, NULL, i);
1168     check_key_value(h, h1, "key", "somevalue", 9);
1169     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1170           "Failed to flush");
1171     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1172 
1173     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1174           "Failed post-flush set.");
1175     h1->release(h, NULL, i);
1176     check_key_value(h, h1, "key", "somevalue", 9);
1177 
1178     return SUCCESS;
1179 }
1180 
test_flush_disabled(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1181 static enum test_result test_flush_disabled(ENGINE_HANDLE *h,
1182                                             ENGINE_HANDLE_V1 *h1) {
1183     item *i = NULL;
1184     // start an engine with disabled flush, the flush() should be noop and
1185     // we expect to see the key after flush()
1186 
1187     // store a key and check its existence
1188     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1189           "Failed set.");
1190     h1->release(h, NULL, i);
1191     check_key_value(h, h1, "key", "somevalue", 9);
1192     // expect error msg engine does not support operation
1193     check(h1->flush(h, NULL, 0) == ENGINE_ENOTSUP, "Flush should be disabled");
1194     //check the key
1195     check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1196 
1197     // restart engine with flush enabled and redo the test, we expect flush to succeed
1198     std::string param = "flushall_enabled=false";
1199     std::string config = testHarness.get_current_testcase()->cfg;
1200     size_t found = config.find(param);
1201     if(found != config.npos) {
1202         config.replace(found, param.size(), "flushall_enabled=true");
1203     }
1204     testHarness.reload_engine(&h, &h1,
1205                               testHarness.engine_path,
1206                               config.c_str(),
1207                               true, false);
1208     wait_for_warmup_complete(h, h1);
1209 
1210     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS, "Flush should be enabled");
1211 
1212     //expect missing key
1213     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1214 
1215     return SUCCESS;
1216 }
1217 
test_flush_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1218 static enum test_result test_flush_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1219     item *i = NULL;
1220     int mem_used = get_int_stat(h, h1, "mem_used");
1221     int overhead = get_int_stat(h, h1, "ep_overhead");
1222     int cacheSize = get_int_stat(h, h1, "ep_total_cache_size");
1223     int nonResident = get_int_stat(h, h1, "ep_num_non_resident");
1224 
1225     int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
1226     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1227           "Failed set.");
1228     h1->release(h, NULL, i);
1229     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i) == ENGINE_SUCCESS,
1230           "Failed set.");
1231     h1->release(h, NULL, i);
1232     testHarness.time_travel(65);
1233     wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
1234 
1235     check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1236     check(ENGINE_SUCCESS == verify_key(h, h1, "key2"), "Expected key2");
1237 
1238     check_key_value(h, h1, "key", "somevalue", 9);
1239     check_key_value(h, h1, "key2", "somevalue", 9);
1240 
1241     int mem_used2 = get_int_stat(h, h1, "mem_used");
1242     int overhead2 = get_int_stat(h, h1, "ep_overhead");
1243     int cacheSize2 = get_int_stat(h, h1, "ep_total_cache_size");
1244 
1245     cb_assert(mem_used2 > mem_used);
1246     // "mem_used2 - overhead2" (i.e., ep_kv_size) should be greater than the hashtable cache size
1247     // due to the checkpoint overhead
1248     cb_assert(mem_used2 - overhead2 > cacheSize2);
1249 
1250     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS, "Failed to flush");
1251     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1252     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key2"), "Expected missing key");
1253 
1254     wait_for_flusher_to_settle(h, h1);
1255 
1256     mem_used2 = get_int_stat(h, h1, "mem_used");
1257     overhead2 = get_int_stat(h, h1, "ep_overhead");
1258     cacheSize2 = get_int_stat(h, h1, "ep_total_cache_size");
1259     int nonResident2 = get_int_stat(h, h1, "ep_num_non_resident");
1260 
1261     cb_assert(mem_used2 == mem_used);
1262     cb_assert(overhead2 == overhead);
1263     cb_assert(nonResident2 == nonResident);
1264     cb_assert(cacheSize2 == cacheSize);
1265 
1266     return SUCCESS;
1267 }
1268 
test_flush_multiv(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1269 static enum test_result test_flush_multiv(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1270     item *i = NULL;
1271     check(set_vbucket_state(h, h1, 2, vbucket_state_active), "Failed to set vbucket state.");
1272     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1273           "Failed set.");
1274     h1->release(h, NULL, i);
1275     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i,
1276                 0, 2) == ENGINE_SUCCESS,
1277           "Failed set in vb2.");
1278     h1->release(h, NULL, i);
1279 
1280     check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1281     check(ENGINE_SUCCESS == verify_key(h, h1, "key2", 2), "Expected key2");
1282 
1283     check_key_value(h, h1, "key", "somevalue", 9);
1284     check_key_value(h, h1, "key2", "somevalue", 9, 2);
1285 
1286     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS, "Failed to flush");
1287 
1288     vals.clear();
1289     check(h1->get_stats(h, NULL, NULL, 0, add_stats) == ENGINE_SUCCESS,
1290           "Failed to get stats.");
1291     check(vals.find("ep_flush_all") != vals.end(), "Failed to get the status of flush_all");
1292 
1293     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1294     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key2", 2), "Expected missing key");
1295 
1296     return SUCCESS;
1297 }
1298 
checkCurrItemsAfterShutdown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, int numItems2Load, bool shutdownForce)1299 static int checkCurrItemsAfterShutdown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1300                                        int numItems2Load, bool shutdownForce) {
1301     std::vector<std::string> keys;
1302     for (int index = 0; index < numItems2Load; ++index) {
1303         std::stringstream s;
1304         s << "keys_2_load-" << index;
1305         std::string key(s.str());
1306         keys.push_back(key);
1307     }
1308 
1309     check(get_int_stat(h, h1, "ep_total_persisted") == 0,
1310           "Expected ep_total_persisted equals 0");
1311     check(get_int_stat(h, h1, "curr_items") == 0,
1312           "Expected curr_items equals 0");
1313 
1314     // stop flusher before loading new items
1315     protocol_binary_request_header *pkt = createPacket(PROTOCOL_BINARY_CMD_STOP_PERSISTENCE);
1316     check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
1317           "CMD_STOP_PERSISTENCE failed!");
1318     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
1319           "Failed to stop persistence!");
1320     free(pkt);
1321 
1322     std::vector<std::string>::iterator itr;
1323     for (itr = keys.begin(); itr != keys.end(); ++itr) {
1324         item *i;
1325         check(store(h, h1, NULL, OPERATION_SET, itr->c_str(), "oracle", &i, 0, 0)
1326               == ENGINE_SUCCESS, "Failed to store a value");
1327         h1->release(h, NULL, i);
1328     }
1329 
1330     check(get_int_stat(h, h1, "ep_total_persisted") == 0,
1331           "Incorrect ep_total_persisted, expected 0");
1332     std::stringstream ss;
1333     ss << "Incorrect curr_items, expected " << numItems2Load;
1334     std::string errmsg(ss.str());
1335     check(get_int_stat(h, h1, "curr_items") == numItems2Load,
1336           errmsg.c_str());
1337 
1338     // resume flusher before shutdown + warmup
1339     pkt = createPacket(PROTOCOL_BINARY_CMD_START_PERSISTENCE);
1340     check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
1341           "CMD_START_PERSISTENCE failed!");
1342     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
1343           "Failed to start persistence!");
1344     free(pkt);
1345 
1346     // shutdown engine force and restart
1347     testHarness.reload_engine(&h, &h1,
1348                               testHarness.engine_path,
1349                               testHarness.get_current_testcase()->cfg,
1350                               true, shutdownForce);
1351     wait_for_warmup_complete(h, h1);
1352     return get_int_stat(h, h1, "curr_items");
1353 }
1354 
test_flush_shutdown_force(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1355 static enum test_result test_flush_shutdown_force(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1356     int numItems2load = 3000;
1357     bool shutdownForce = true;
1358     int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
1359     check (currItems <= numItems2load,
1360            "Number of curr items should be <= 3000, unless previous "
1361            "shutdown force had to wait for the flusher");
1362     return SUCCESS;
1363 }
1364 
test_flush_shutdown_noforce(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1365 static enum test_result test_flush_shutdown_noforce(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1366     int numItems2load = 3000;
1367     bool shutdownForce = false;
1368     int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
1369     check (currItems == numItems2load,
1370            "Number of curr items should be equal to 3000, unless previous "
1371            "shutdown did not wait for the flusher");
1372     return SUCCESS;
1373 }
1374 
test_flush_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1375 static enum test_result test_flush_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1376     item *i = NULL;
1377     // First try to delete something we know to not be there.
1378     check(del(h, h1, "key", 0, 0) == ENGINE_KEY_ENOENT, "Failed to fail initial delete.");
1379     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1380           "Failed set.");
1381     h1->release(h, NULL, i);
1382     check_key_value(h, h1, "key", "somevalue", 9);
1383 
1384     // Restart once to ensure written to disk.
1385     testHarness.reload_engine(&h, &h1,
1386                               testHarness.engine_path,
1387                               testHarness.get_current_testcase()->cfg,
1388                               true, false);
1389     wait_for_warmup_complete(h, h1);
1390 
1391     // Read value from disk.
1392     check_key_value(h, h1, "key", "somevalue", 9);
1393 
1394     // Flush
1395     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1396           "Failed to flush");
1397 
1398     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i) == ENGINE_SUCCESS,
1399           "Failed post-flush set.");
1400     h1->release(h, NULL, i);
1401     check_key_value(h, h1, "key2", "somevalue", 9);
1402 
1403     // Restart again, ensure written to disk.
1404     testHarness.reload_engine(&h, &h1,
1405                               testHarness.engine_path,
1406                               testHarness.get_current_testcase()->cfg,
1407                               true, false);
1408     wait_for_warmup_complete(h, h1);
1409 
1410     check(store(h, h1, NULL, OPERATION_SET, "key3", "somevalue", &i) == ENGINE_SUCCESS,
1411           "Failed post-flush, post-restart set.");
1412     h1->release(h, NULL, i);
1413     check_key_value(h, h1, "key3", "somevalue", 9);
1414 
1415     // Read value again, should not be there.
1416     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1417     return SUCCESS;
1418 }
1419 
test_flush_multiv_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1420 static enum test_result test_flush_multiv_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1421     item *i = NULL;
1422     check(set_vbucket_state(h, h1, 2, vbucket_state_active), "Failed to set vbucket state.");
1423     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1424           "Failed set.");
1425     h1->release(h, NULL, i);
1426     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i,
1427                 0, 2) == ENGINE_SUCCESS,
1428           "Failed set in vb2.");
1429     h1->release(h, NULL, i);
1430 
1431     // Restart once to ensure written to disk.
1432     testHarness.reload_engine(&h, &h1,
1433                               testHarness.engine_path,
1434                               testHarness.get_current_testcase()->cfg,
1435                               true, false);
1436     wait_for_warmup_complete(h, h1);
1437 
1438     // Read value from disk.
1439     check_key_value(h, h1, "key", "somevalue", 9);
1440 
1441     // Flush
1442     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1443           "Failed to flush");
1444 
1445     // Restart again, ensure written to disk.
1446     testHarness.reload_engine(&h, &h1,
1447                               testHarness.engine_path,
1448                               testHarness.get_current_testcase()->cfg,
1449                               true, false);
1450     wait_for_warmup_complete(h, h1);
1451 
1452     // Read value again, should not be there.
1453     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1454     check(verify_vbucket_missing(h, h1, 2), "Bucket 2 came back.");
1455     return SUCCESS;
1456 }
1457 
test_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1458 static enum test_result test_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1459     item *i = NULL;
1460     // First try to delete something we know to not be there.
1461     check(del(h, h1, "key", 0, 0) == ENGINE_KEY_ENOENT, "Failed to fail initial delete.");
1462     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1463           "Failed set.");
1464     Item *it = reinterpret_cast<Item*>(i);
1465     uint64_t orig_cas = it->getCas();
1466     h1->release(h, NULL, i);
1467     check_key_value(h, h1, "key", "somevalue", 9);
1468 
1469     uint64_t cas = 0;
1470     check(h1->remove(h, NULL, "key", 3, &cas, 0) == ENGINE_SUCCESS,
1471           "Failed remove with value.");
1472     check(orig_cas + 1 == cas, "Cas mismatch on delete");
1473     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1474 
1475     // Can I time travel to an expired object and delete it?
1476     checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1477             "Failed set.");
1478     h1->release(h, NULL, i);
1479     testHarness.time_travel(3617);
1480     checkeq(ENGINE_KEY_ENOENT, del(h, h1, "key", 0, 0),
1481             "Did not get ENOENT removing an expired object.");
1482     checkeq(ENGINE_KEY_ENOENT, verify_key(h, h1, "key"), "Expected missing key");
1483 
1484     return SUCCESS;
1485 }
1486 
test_set_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1487 static enum test_result test_set_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1488     item *i = NULL;
1489     checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1490             "Failed set.");
1491     h1->release(h, NULL, i);
1492     check_key_value(h, h1, "key", "somevalue", 9);
1493     checkeq(ENGINE_SUCCESS, del(h, h1, "key", 0, 0),
1494             "Failed remove with value.");
1495     checkeq(ENGINE_KEY_ENOENT, verify_key(h, h1, "key"), "Expected missing key");
1496     wait_for_flusher_to_settle(h, h1);
1497     wait_for_stat_to_be(h, h1, "curr_items", 0);
1498     return SUCCESS;
1499 }
1500 
test_set_delete_invalid_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1501 static enum test_result test_set_delete_invalid_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1502     item *i = NULL;
1503     check(store(h, h1, NULL, OPERATION_SET, "key",
1504                 "somevalue", &i) == ENGINE_SUCCESS,
1505           "Failed set.");
1506     check_key_value(h, h1, "key", "somevalue", 9);
1507     item_info info;
1508     info.nvalue = 1;
1509     check(h1->get_item_info(h, NULL, i, &info) == true,
1510           "Should be able to get info");
1511     h1->release(h, NULL, i);
1512 
1513     check(del(h, h1, "key", info.cas + 1, 0) == ENGINE_KEY_EEXISTS,
1514           "Didn't expect to be able to remove the item with wrong cas");
1515     return SUCCESS;
1516 }
1517 
test_bug2509(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1518 static enum test_result test_bug2509(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1519     for (int j = 0; j < 10000; ++j) {
1520         item *itm = NULL;
1521         checkeq(ENGINE_SUCCESS,
1522                 store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &itm),
1523                 "Failed set.");
1524         h1->release(h, NULL, itm);
1525         usleep(10);
1526         checkeq(ENGINE_SUCCESS, del(h, h1, "key", 0, 0), "Failed remove with value.");
1527         usleep(10);
1528     }
1529 
1530     // Restart again, to verify we don't have any duplicates.
1531     testHarness.reload_engine(&h, &h1,
1532                               testHarness.engine_path,
1533                               testHarness.get_current_testcase()->cfg,
1534                               true, false);
1535     wait_for_warmup_complete(h, h1);
1536 
1537     return get_int_stat(h, h1, "ep_warmup_dups") == 0 ? SUCCESS : FAIL;
1538 }
1539 
test_bug7023(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1540 static enum test_result test_bug7023(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1541     std::vector<std::string> keys;
1542     // Make a vbucket mess.
1543     for (int j = 0; j < 10000; ++j) {
1544         std::stringstream ss;
1545         ss << "key" << j;
1546         std::string key(ss.str());
1547         keys.push_back(key);
1548     }
1549 
1550     std::vector<std::string>::iterator it;
1551     for (int j = 0; j < 5; ++j) {
1552         check(set_vbucket_state(h, h1, 0, vbucket_state_dead), "Failed set set vbucket 0 dead.");
1553         vbucketDelete(h, h1, 0);
1554         check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
1555               "Expected vbucket deletion to work.");
1556         check(set_vbucket_state(h, h1, 0, vbucket_state_active), "Failed set set vbucket 0 active.");
1557         for (it = keys.begin(); it != keys.end(); ++it) {
1558             item *i;
1559             check(store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i)
1560                   == ENGINE_SUCCESS, "Failed to store a value");
1561         }
1562     }
1563     wait_for_flusher_to_settle(h, h1);
1564 
1565     // Restart again, to verify no data loss.
1566     testHarness.reload_engine(&h, &h1,
1567                               testHarness.engine_path,
1568                               testHarness.get_current_testcase()->cfg,
1569                               true, false);
1570     wait_for_warmup_complete(h, h1);
1571     return get_int_stat(h, h1, "ep_warmup_value_count", "warmup") == 10000 ? SUCCESS : FAIL;
1572 }
1573 
test_delete_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1574 static enum test_result test_delete_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1575     wait_for_persisted_value(h, h1, "key", "value1");
1576 
1577     check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
1578 
1579     wait_for_persisted_value(h, h1, "key", "value2");
1580 
1581     testHarness.reload_engine(&h, &h1,
1582                               testHarness.engine_path,
1583                               testHarness.get_current_testcase()->cfg,
1584                               true, false);
1585     wait_for_warmup_complete(h, h1);
1586 
1587     check_key_value(h, h1, "key", "value2", 6);
1588     check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
1589     wait_for_flusher_to_settle(h, h1);
1590 
1591     testHarness.reload_engine(&h, &h1,
1592                               testHarness.engine_path,
1593                               testHarness.get_current_testcase()->cfg,
1594                               true, false);
1595     wait_for_warmup_complete(h, h1);
1596 
1597     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1598 
1599     return SUCCESS;
1600 }
1601 
test_get_delete_missing_file(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1602 static enum test_result test_get_delete_missing_file(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1603     const char *key = "key";
1604     wait_for_persisted_value(h, h1, key, "value2delete");
1605 
1606     // whack the db file and directory where the key is stored
1607     rmdb();
1608 
1609     item *i = NULL;
1610     int errorCode = h1->get(h, NULL, &i, key, strlen(key), 0);
1611     h1->release(h, NULL, i);
1612 
1613     // ep engine must be unaware of well-being of the db file as long as
1614     // the item is still in the memory
1615     check(errorCode == ENGINE_SUCCESS, "Expected success for get");
1616 
1617     i = NULL;
1618     evict_key(h, h1, key);
1619     errorCode = h1->get(h, NULL, &i, key, strlen(key), 0);
1620     h1->release(h, NULL, i);
1621 
1622     // ep engine must be now aware of the ill-fated db file where
1623     // the item is supposedly stored
1624     check(errorCode == ENGINE_TMPFAIL, "Expected tmp fail for get");
1625 
1626     return SUCCESS;
1627 }
1628 
1629 
test_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1630 static enum test_result test_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1631     item *i = NULL;
1632     static const char val[] = "somevalue";
1633     ENGINE_ERROR_CODE ret;
1634     check((ret = store(h, h1, NULL, OPERATION_SET, "key", val, &i)) == ENGINE_SUCCESS,
1635           "Failed set.");
1636     h1->release(h, NULL, i);
1637 
1638     testHarness.reload_engine(&h, &h1,
1639                               testHarness.engine_path,
1640                               testHarness.get_current_testcase()->cfg,
1641                               true, false);
1642     wait_for_warmup_complete(h, h1);
1643     check_key_value(h, h1, "key", val, strlen(val));
1644     return SUCCESS;
1645 }
1646 
test_restart_session_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1647 static enum test_result test_restart_session_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1648     createTapConn(h, h1, "tap_client_thread");
1649 
1650     testHarness.reload_engine(&h, &h1,
1651                               testHarness.engine_path,
1652                               testHarness.get_current_testcase()->cfg,
1653                               true, false);
1654     wait_for_warmup_complete(h, h1);
1655     createTapConn(h, h1, "tap_client_thread");
1656 
1657     check(h1->get_stats(h, NULL, "tap", 3, add_stats) == ENGINE_SUCCESS,
1658           "Failed to get stats.");
1659     std::string val = vals["eq_tapq:tap_client_thread:backfill_completed"];
1660     check(strcmp(val.c_str(), "true") == 0, "Don't expect the backfill upon restart");
1661     return SUCCESS;
1662 }
1663 
test_specialKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1664 static enum test_result test_specialKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1665     item *i = NULL;
1666     ENGINE_ERROR_CODE ret;
1667 
1668     // Simplified Chinese "Couchbase"
1669     static const char key0[] = "沙发数据库";
1670     static const char val0[] = "some Chinese value";
1671     check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0, &i)) == ENGINE_SUCCESS,
1672           "Failed set Chinese key");
1673     check_key_value(h, h1, key0, val0, strlen(val0));
1674     h1->release(h, NULL, i);
1675     // Traditional Chinese "Couchbase"
1676     static const char key1[] = "沙發數據庫";
1677     static const char val1[] = "some Traditional Chinese value";
1678     check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1, &i)) == ENGINE_SUCCESS,
1679           "Failed set Traditional Chinese key");
1680     h1->release(h, NULL, i);
1681     // Korean "couch potato"
1682     static const char key2[] = "쇼파감자";
1683     static const char val2[] = "some Korean value";
1684     check((ret = store(h, h1, NULL, OPERATION_SET, key2, val2, &i)) == ENGINE_SUCCESS,
1685           "Failed set Korean key");
1686     h1->release(h, NULL, i);
1687     // Russian "couch potato"
1688     static const char key3[] = "лодырь, лентяй";
1689     static const char val3[] = "some Russian value";
1690     check((ret = store(h, h1, NULL, OPERATION_SET, key3, val3, &i)) == ENGINE_SUCCESS,
1691           "Failed set Russian key");
1692     h1->release(h, NULL, i);
1693     // Japanese "couch potato"
1694     static const char key4[] = "カウチポテト";
1695     static const char val4[] = "some Japanese value";
1696     check((ret = store(h, h1, NULL, OPERATION_SET, key4, val4, &i)) == ENGINE_SUCCESS,
1697           "Failed set Japanese key");
1698     h1->release(h, NULL, i);
1699     // Indian char key, and no idea what it is
1700     static const char key5[] = "हरियानवी";
1701     static const char val5[] = "some Indian value";
1702     check((ret = store(h, h1, NULL, OPERATION_SET, key5, val5, &i)) == ENGINE_SUCCESS,
1703           "Failed set Indian key");
1704     h1->release(h, NULL, i);
1705     // Portuguese translation "couch potato"
1706     static const char key6[] = "sedentário";
1707     static const char val6[] = "some Portuguese value";
1708     check((ret = store(h, h1, NULL, OPERATION_SET, key6, val6, &i)) == ENGINE_SUCCESS,
1709           "Failed set Portuguese key");
1710     h1->release(h, NULL, i);
1711     // Arabic translation "couch potato"
1712     static const char key7[] = "الحافلةالبطاطة";
1713     static const char val7[] = "some Arabic value";
1714     check((ret = store(h, h1, NULL, OPERATION_SET, key7, val7, &i)) == ENGINE_SUCCESS,
1715           "Failed set Arabic key");
1716     h1->release(h, NULL, i);
1717 
1718     testHarness.reload_engine(&h, &h1,
1719                               testHarness.engine_path,
1720                               testHarness.get_current_testcase()->cfg,
1721                               true, false);
1722     wait_for_warmup_complete(h, h1);
1723     check_key_value(h, h1, key0, val0, strlen(val0));
1724     check_key_value(h, h1, key1, val1, strlen(val1));
1725     check_key_value(h, h1, key2, val2, strlen(val2));
1726     check_key_value(h, h1, key3, val3, strlen(val3));
1727     check_key_value(h, h1, key4, val4, strlen(val4));
1728     check_key_value(h, h1, key5, val5, strlen(val5));
1729     check_key_value(h, h1, key6, val6, strlen(val6));
1730     check_key_value(h, h1, key7, val7, strlen(val7));
1731     return SUCCESS;
1732 }
1733 
test_binKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1734 static enum test_result test_binKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1735     item *i = NULL;
1736     ENGINE_ERROR_CODE ret;
1737 
1738     // binary key with char values beyond 0x7F
1739     static const char key0[] = "\xe0\xed\xf1\x6f\x7f\xf8\xfa";
1740     static const char val0[] = "some value val8";
1741     check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0, &i)) == ENGINE_SUCCESS,
1742           "Failed set binary key0");
1743     check_key_value(h, h1, key0, val0, strlen(val0));
1744     h1->release(h, NULL, i);
1745     // binary keys with char values beyond 0x7F
1746     static const char key1[] = "\xf1\xfd\xfe\xff\xf0\xf8\xef";
1747     static const char val1[] = "some value val9";
1748     check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1, &i)) == ENGINE_SUCCESS,
1749           "Failed set binary key1");
1750     check_key_value(h, h1, key1, val1, strlen(val1));
1751     h1->release(h, NULL, i);
1752     // binary keys with special utf-8 BOM (Byte Order Mark) values 0xBB 0xBF 0xEF
1753     static const char key2[] = "\xff\xfe\xbb\xbf\xef";
1754     static const char val2[] = "some utf-8 bom value";
1755     check((ret = store(h, h1, NULL, OPERATION_SET, key2, val2, &i)) == ENGINE_SUCCESS,
1756           "Failed set binary utf-8 bom key");
1757     check_key_value(h, h1, key2, val2, strlen(val2));
1758     h1->release(h, NULL, i);
1759     // binary keys with special utf-16BE BOM values "U+FEFF"
1760     static const char key3[] = "U+\xfe\xff\xefU+\xff\xfe";
1761     static const char val3[] = "some utf-16 bom value";
1762     check((ret = store(h, h1, NULL, OPERATION_SET, key3, val3, &i)) == ENGINE_SUCCESS,
1763           "Failed set binary utf-16 bom key");
1764     check_key_value(h, h1, key3, val3, strlen(val3));
1765     h1->release(h, NULL, i);
1766 
1767     testHarness.reload_engine(&h, &h1,
1768                               testHarness.engine_path,
1769                               testHarness.get_current_testcase()->cfg,
1770                               true, false);
1771     wait_for_warmup_complete(h, h1);
1772     check_key_value(h, h1, key0, val0, strlen(val0));
1773     check_key_value(h, h1, key1, val1, strlen(val1));
1774     check_key_value(h, h1, key2, val2, strlen(val2));
1775     check_key_value(h, h1, key3, val3, strlen(val3));
1776     return SUCCESS;
1777 }
1778 
test_restart_bin_val(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1779 static enum test_result test_restart_bin_val(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1780 
1781 
1782 
1783     char binaryData[] = "abcdefg\0gfedcba";
1784     cb_assert(sizeof(binaryData) != strlen(binaryData));
1785 
1786     item *i = NULL;
1787     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1788                        binaryData, sizeof(binaryData), 82758, &i, 0, 0)
1789           == ENGINE_SUCCESS,
1790           "Failed set.");
1791     h1->release(h, NULL, i);
1792 
1793     testHarness.reload_engine(&h, &h1,
1794                               testHarness.engine_path,
1795                               testHarness.get_current_testcase()->cfg,
1796                               true, false);
1797     wait_for_warmup_complete(h, h1);
1798 
1799     check_key_value(h, h1, "key", binaryData, sizeof(binaryData));
1800     return SUCCESS;
1801 }
1802 
test_wrong_vb_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1803 static enum test_result test_wrong_vb_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1804     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
1805     check(ENGINE_NOT_MY_VBUCKET == verify_key(h, h1, "key", 1),
1806           "Expected wrong bucket.");
1807     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
1808     return SUCCESS;
1809 }
1810 
test_vb_get_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1811 static enum test_result test_vb_get_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1812     check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
1813     const void *cookie = testHarness.create_cookie();
1814     testHarness.set_ewouldblock_handling(cookie, false);
1815 
1816     item *i = NULL;
1817     check(ENGINE_EWOULDBLOCK == h1->get(h, cookie, &i, "key", strlen("key"), 1),
1818           "Expected woodblock.");
1819     h1->release(h, NULL, i);
1820 
1821     testHarness.destroy_cookie(cookie);
1822     return SUCCESS;
1823 }
1824 
test_vb_get_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1825 static enum test_result test_vb_get_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1826     check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
1827     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
1828     check(ENGINE_NOT_MY_VBUCKET == verify_key(h, h1, "key", 1),
1829           "Expected not my bucket.");
1830     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
1831     return SUCCESS;
1832 }
1833 
test_wrong_vb_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1834 static enum test_result test_wrong_vb_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1835     uint64_t cas, result;
1836     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
1837     check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
1838                          &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
1839                          1) == ENGINE_NOT_MY_VBUCKET,
1840           "Expected not my vbucket.");
1841     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
1842     return SUCCESS;
1843 }
1844 
test_vb_incr_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1845 static enum test_result test_vb_incr_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1846     const void *cookie = testHarness.create_cookie();
1847     testHarness.set_ewouldblock_handling(cookie, false);
1848     uint64_t cas, result;
1849     check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
1850     check(h1->arithmetic(h, cookie, "key", 3, true, false, 1, 1, 0,
1851                          &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
1852                          1) == ENGINE_EWOULDBLOCK,
1853           "Expected woodblock.");
1854     testHarness.destroy_cookie(cookie);
1855     return SUCCESS;
1856 }
1857 
test_vb_incr_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1858 static enum test_result test_vb_incr_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1859     uint64_t cas, result;
1860     check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
1861     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
1862     check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
1863                          &cas, PROTOCOL_BINARY_RAW_BYTES, &result,
1864                          1) == ENGINE_NOT_MY_VBUCKET,
1865           "Expected not my bucket.");
1866     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
1867     return SUCCESS;
1868 }
1869 
test_wrong_vb_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1870 static enum test_result test_wrong_vb_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1871     return test_wrong_vb_mutation(h, h1, OPERATION_SET);
1872 }
1873 
test_wrong_vb_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1874 static enum test_result test_wrong_vb_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1875     return test_wrong_vb_mutation(h, h1, OPERATION_CAS);
1876 }
1877 
test_wrong_vb_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1878 static enum test_result test_wrong_vb_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1879     return test_wrong_vb_mutation(h, h1, OPERATION_ADD);
1880 }
1881 
test_wrong_vb_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1882 static enum test_result test_wrong_vb_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1883     return test_wrong_vb_mutation(h, h1, OPERATION_REPLACE);
1884 }
1885 
test_wrong_vb_append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1886 static enum test_result test_wrong_vb_append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1887     return test_wrong_vb_mutation(h, h1, OPERATION_APPEND);
1888 }
1889 
test_wrong_vb_prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1890 static enum test_result test_wrong_vb_prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1891     return test_wrong_vb_mutation(h, h1, OPERATION_PREPEND);
1892 }
1893 
test_wrong_vb_del(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1894 static enum test_result test_wrong_vb_del(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1895     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
1896     check(ENGINE_NOT_MY_VBUCKET == del(h, h1, "key", 0, 1), "Expected wrong bucket.");
1897     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
1898     return SUCCESS;
1899 }
1900 
test_expiry(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1901 static enum test_result test_expiry(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1902     const char *key = "test_expiry";
1903     const char *data = "some test data here.";
1904 
1905     item *it = NULL;
1906 
1907     ENGINE_ERROR_CODE rv;
1908     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 2,
1909                       PROTOCOL_BINARY_RAW_BYTES);
1910     check(rv == ENGINE_SUCCESS, "Allocation failed.");
1911 
1912     item_info info;
1913     info.nvalue = 1;
1914     if (!h1->get_item_info(h, NULL, it, &info)) {
1915         abort();
1916     }
1917     memcpy(info.value[0].iov_base, data, strlen(data));
1918 
1919     uint64_t cas = 0;
1920     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
1921     check(rv == ENGINE_SUCCESS, "Set failed.");
1922     check_key_value(h, h1, key, data, strlen(data));
1923     h1->release(h, NULL, it);
1924 
1925     testHarness.time_travel(5);
1926     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
1927           "Item didn't expire");
1928 
1929     int expired_access = get_int_stat(h, h1, "ep_expired_access");
1930     int expired_pager = get_int_stat(h, h1, "ep_expired_pager");
1931     int active_expired = get_int_stat(h, h1, "vb_active_expired");
1932     check(expired_pager == 0, "Expected zero expired item by pager");
1933     check(expired_access == 1, "Expected an expired item on access");
1934     check(active_expired == 1, "Expected an expired active item");
1935     checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, key, data, &it),
1936             "Failed set.");
1937     h1->release(h, NULL, it);
1938 
1939     std::stringstream ss;
1940     ss << "curr_items stat should be still 1 after ";
1941     ss << "overwriting the key that was expired, but not purged yet";
1942     checkeq(1, get_int_stat(h, h1, "curr_items"), ss.str().c_str());
1943 
1944     return SUCCESS;
1945 }
1946 
test_expiry_loader(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1947 static enum test_result test_expiry_loader(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1948     const char *key = "test_expiry_loader";
1949     const char *data = "some test data here.";
1950 
1951     item *it = NULL;
1952 
1953     ENGINE_ERROR_CODE rv;
1954     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 2,
1955                       PROTOCOL_BINARY_RAW_BYTES);
1956     check(rv == ENGINE_SUCCESS, "Allocation failed.");
1957 
1958     item_info info;
1959     info.nvalue = 1;
1960     if (!h1->get_item_info(h, NULL, it, &info)) {
1961         abort();
1962     }
1963     memcpy(info.value[0].iov_base, data, strlen(data));
1964 
1965     uint64_t cas = 0;
1966     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
1967     check(rv == ENGINE_SUCCESS, "Set failed.");
1968     check_key_value(h, h1, key, data, strlen(data));
1969     h1->release(h, NULL, it);
1970 
1971     testHarness.time_travel(3);
1972 
1973     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
1974           "Item didn't expire");
1975 
1976     // Restart the engine to ensure the above expired item is not loaded
1977     testHarness.reload_engine(&h, &h1,
1978                               testHarness.engine_path,
1979                               testHarness.get_current_testcase()->cfg,
1980                               true, false);
1981     wait_for_warmup_complete(h, h1);
1982     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_value_count", "warmup"));
1983 
1984     return SUCCESS;
1985 }
1986 
test_expiration_on_warmup(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)1987 static enum test_result test_expiration_on_warmup(ENGINE_HANDLE *h,
1988                                                   ENGINE_HANDLE_V1 *h1) {
1989     const char *key = "KEY";
1990     const char *data = "VALUE";
1991 
1992     item *it = NULL;
1993 
1994     ENGINE_ERROR_CODE rv;
1995     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 3,
1996                       PROTOCOL_BINARY_RAW_BYTES);
1997     check(rv == ENGINE_SUCCESS, "Allocation failed.");
1998 
1999     item_info info;
2000     info.nvalue = 1;
2001     if (!h1->get_item_info(h, NULL, it, &info)) {
2002         abort();
2003     }
2004     memcpy(info.value[0].iov_base, data, strlen(data));
2005 
2006     uint64_t cas = 0;
2007     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2008     check(rv == ENGINE_SUCCESS, "Set failed.");
2009     check_key_value(h, h1, key, data, strlen(data));
2010     h1->release(h, NULL, it);
2011     wait_for_flusher_to_settle(h, h1);
2012 
2013     check(get_int_stat(h, h1, "curr_items") == 1, "Failed store item");
2014     testHarness.time_travel(5);
2015 
2016     // Restart the engine to ensure the above item is expired
2017     testHarness.reload_engine(&h, &h1,
2018                               testHarness.engine_path,
2019                               testHarness.get_current_testcase()->cfg,
2020                               true, false);
2021     wait_for_warmup_complete(h, h1);
2022     int pager_runs = get_int_stat(h, h1, "ep_num_expiry_pager_runs");
2023     wait_for_stat_change(h, h1, "ep_num_expiry_pager_runs", pager_runs);
2024     wait_for_flusher_to_settle(h, h1);
2025     check(get_int_stat(h, h1, "curr_items") == 0,
2026             "The item should have been expired.");
2027 
2028     return SUCCESS;
2029 
2030 }
2031 
test_bug3454(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2032 static enum test_result test_bug3454(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2033     const char *key = "test_expiry_duplicate_warmup";
2034     const char *data = "some test data here.";
2035 
2036     item *it = NULL;
2037 
2038     ENGINE_ERROR_CODE rv;
2039     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 5,
2040                       PROTOCOL_BINARY_RAW_BYTES);
2041     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2042 
2043     item_info info;
2044     info.nvalue = 1;
2045     if (!h1->get_item_info(h, NULL, it, &info)) {
2046         abort();
2047     }
2048     memcpy(info.value[0].iov_base, data, strlen(data));
2049 
2050     uint64_t cas = 0;
2051     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2052     check(rv == ENGINE_SUCCESS, "Set failed.");
2053     check_key_value(h, h1, key, data, strlen(data));
2054     h1->release(h, NULL, it);
2055     wait_for_flusher_to_settle(h, h1);
2056 
2057     // Advance the ep_engine time by 10 sec for the above item to be expired.
2058     testHarness.time_travel(10);
2059     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
2060           "Item didn't expire");
2061 
2062     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 0,
2063                       PROTOCOL_BINARY_RAW_BYTES);
2064     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2065 
2066     info.nvalue = 1;
2067     if (!h1->get_item_info(h, NULL, it, &info)) {
2068         abort();
2069     }
2070     memcpy(info.value[0].iov_base, data, strlen(data));
2071 
2072     cas = 0;
2073     // Add a new item with the same key.
2074     rv = h1->store(h, NULL, it, &cas, OPERATION_ADD, 0);
2075     check(rv == ENGINE_SUCCESS, "Add failed.");
2076     check_key_value(h, h1, key, data, strlen(data));
2077     h1->release(h, NULL, it);
2078 
2079     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_SUCCESS,
2080           "Item shouldn't expire");
2081     h1->release(h, NULL, it);
2082 
2083     // Restart the engine to ensure the above unexpired new item is loaded
2084     testHarness.reload_engine(&h, &h1,
2085                               testHarness.engine_path,
2086                               testHarness.get_current_testcase()->cfg,
2087                               true, false);
2088     wait_for_warmup_complete(h, h1);
2089     cb_assert(1 == get_int_stat(h, h1, "ep_warmup_value_count", "warmup"));
2090     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_dups", "warmup"));
2091 
2092     return SUCCESS;
2093 }
2094 
test_bug3522(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2095 static enum test_result test_bug3522(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2096     const char *key = "test_expiry_no_items_warmup";
2097     const char *data = "some test data here.";
2098 
2099     item *it = NULL;
2100 
2101     ENGINE_ERROR_CODE rv;
2102     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 0,
2103                       PROTOCOL_BINARY_RAW_BYTES);
2104     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2105 
2106     item_info info;
2107     info.nvalue = 1;
2108     if (!h1->get_item_info(h, NULL, it, &info)) {
2109         abort();
2110     }
2111     memcpy(info.value[0].iov_base, data, strlen(data));
2112 
2113     uint64_t cas = 0;
2114     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2115     check(rv == ENGINE_SUCCESS, "Set failed.");
2116     check_key_value(h, h1, key, data, strlen(data));
2117     h1->release(h, NULL, it);
2118     wait_for_flusher_to_settle(h, h1);
2119 
2120     // Add a new item with the same key and 2 sec of expiration.
2121     const char *new_data = "new data here.";
2122     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(new_data), 0, 2,
2123                       PROTOCOL_BINARY_RAW_BYTES);
2124     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2125 
2126     info.nvalue = 1;
2127     if (!h1->get_item_info(h, NULL, it, &info)) {
2128         abort();
2129     }
2130     memcpy(info.value[0].iov_base, new_data, strlen(new_data));
2131 
2132     int pager_runs = get_int_stat(h, h1, "ep_num_expiry_pager_runs");
2133     cas = 0;
2134     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2135     check(rv == ENGINE_SUCCESS, "Set failed.");
2136     check_key_value(h, h1, key, new_data, strlen(new_data));
2137     h1->release(h, NULL, it);
2138     testHarness.time_travel(3);
2139     wait_for_stat_change(h, h1, "ep_num_expiry_pager_runs", pager_runs);
2140     wait_for_flusher_to_settle(h, h1);
2141 
2142     // Restart the engine.
2143     testHarness.reload_engine(&h, &h1,
2144                               testHarness.engine_path,
2145                               testHarness.get_current_testcase()->cfg,
2146                               true, false);
2147     wait_for_warmup_complete(h, h1);
2148     // TODO: modify this for a better test case
2149     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_dups", "warmup"));
2150 
2151     return SUCCESS;
2152 }
2153 
test_get_replica_active_state(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2154 static enum test_result test_get_replica_active_state(ENGINE_HANDLE *h,
2155                                                       ENGINE_HANDLE_V1 *h1) {
2156     protocol_binary_request_header *pkt;
2157     pkt = prepare_get_replica(h, h1, vbucket_state_active);
2158     check(h1->unknown_command(h, NULL, pkt, add_response) ==
2159           ENGINE_SUCCESS, "Get Replica Failed");
2160     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2161           "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
2162 
2163     return SUCCESS;
2164 }
2165 
test_get_replica_pending_state(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2166 static enum test_result test_get_replica_pending_state(ENGINE_HANDLE *h,
2167                                                        ENGINE_HANDLE_V1 *h1) {
2168     protocol_binary_request_header *pkt;
2169 
2170     const void *cookie = testHarness.create_cookie();
2171     testHarness.set_ewouldblock_handling(cookie, false);
2172     pkt = prepare_get_replica(h, h1, vbucket_state_pending);
2173     check(h1->unknown_command(h, cookie, pkt, add_response) ==
2174           ENGINE_EWOULDBLOCK, "Should have returned error for pending state");
2175     testHarness.destroy_cookie(cookie);
2176     return SUCCESS;
2177 }
2178 
test_get_replica_dead_state(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2179 static enum test_result test_get_replica_dead_state(ENGINE_HANDLE *h,
2180                                                     ENGINE_HANDLE_V1 *h1) {
2181     protocol_binary_request_header *pkt;
2182     pkt = prepare_get_replica(h, h1, vbucket_state_dead);
2183     check(h1->unknown_command(h, NULL, pkt, add_response) ==
2184           ENGINE_SUCCESS, "Get Replica Failed");
2185     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2186           "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
2187 
2188     return SUCCESS;
2189 }
2190 
test_get_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2191 static enum test_result test_get_replica(ENGINE_HANDLE *h,
2192                                          ENGINE_HANDLE_V1 *h1) {
2193     protocol_binary_request_header *pkt;
2194     pkt = prepare_get_replica(h, h1, vbucket_state_replica);
2195     check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
2196                               "Get Replica Failed");
2197     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
2198           "Expected PROTOCOL_BINARY_RESPONSE_SUCCESS response.");
2199     check(strcmp("replicadata", last_body) == 0,
2200                  "Should have returned identical value");
2201 
2202     return SUCCESS;
2203 }
2204 
test_get_replica_non_resident(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2205 static enum test_result test_get_replica_non_resident(ENGINE_HANDLE *h,
2206                                                       ENGINE_HANDLE_V1 *h1) {
2207 
2208     item *i = NULL;
2209     check(store(h, h1, NULL, OPERATION_SET, "key", "value", &i, 0, 0)
2210           == ENGINE_SUCCESS, "Store Failed");
2211     h1->release(h, NULL, i);
2212     wait_for_flusher_to_settle(h, h1);
2213     wait_for_stat_to_be(h, h1, "ep_total_persisted", 1);
2214 
2215     evict_key(h, h1, "key", 0, "Ejected.");
2216     check(set_vbucket_state(h, h1, 0, vbucket_state_replica),
2217           "Failed to set vbucket to replica");
2218 
2219     get_replica(h, h1, "key", 0);
2220     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "Expected success");
2221 
2222     return SUCCESS;
2223 }
2224 
test_get_replica_invalid_key(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2225 static enum test_result test_get_replica_invalid_key(ENGINE_HANDLE *h,
2226                                                      ENGINE_HANDLE_V1 *h1) {
2227     protocol_binary_request_header *pkt;
2228     bool makeinvalidkey = true;
2229     pkt = prepare_get_replica(h, h1, vbucket_state_replica, makeinvalidkey);
2230     check(h1->unknown_command(h, NULL, pkt, add_response) ==
2231           ENGINE_SUCCESS, "Get Replica Failed");
2232     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2233           "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
2234     return SUCCESS;
2235 }
2236 
test_vb_del_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2237 static enum test_result test_vb_del_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2238     const void *cookie = testHarness.create_cookie();
2239     testHarness.set_ewouldblock_handling(cookie, false);
2240     check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
2241     check(ENGINE_EWOULDBLOCK == del(h, h1, "key", 0, 1, cookie),
2242           "Expected woodblock.");
2243     testHarness.destroy_cookie(cookie);
2244     return SUCCESS;
2245 }
2246 
test_vb_del_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2247 static enum test_result test_vb_del_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2248     check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
2249     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2250     check(ENGINE_NOT_MY_VBUCKET == del(h, h1, "key", 0, 1),
2251           "Expected not my vbucket.");
2252     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2253     return SUCCESS;
2254 }
2255 
test_touch(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2256 static enum test_result test_touch(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2257     // key is a mandatory field!
2258     touch(h, h1, NULL, 0, (time(NULL) + 10));
2259     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2260 
2261     // extlen is a mandatory field!
2262     protocol_binary_request_header *request;
2263     request = createPacket(PROTOCOL_BINARY_CMD_TOUCH, 0, 0, NULL, 0, "akey", 4);
2264     check(h1->unknown_command(h, NULL, request, add_response) == ENGINE_SUCCESS,
2265           "Failed to call touch");
2266     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2267     free(request);
2268 
2269     // Try to touch an unknown item...
2270     touch(h, h1, "mykey", 0, (time(NULL) + 10));
2271     check(last_status == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, "Testing unknown key");
2272 
2273     // illegal vbucket
2274     touch(h, h1, "mykey", 5, (time(NULL) + 10));
2275     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, "Testing illegal vbucket");
2276 
2277     // Store the item!
2278     item *itm = NULL;
2279     check(store(h, h1, NULL, OPERATION_SET, "mykey", "somevalue", &itm) == ENGINE_SUCCESS,
2280           "Failed set.");
2281     h1->release(h, NULL, itm);
2282 
2283     check_key_value(h, h1, "mykey", "somevalue", strlen("somevalue"));
2284 
2285     touch(h, h1, "mykey", 0, (time(NULL) + 10));
2286     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch mykey");
2287 
2288     // time-travel 9 secs..
2289     testHarness.time_travel(9);
2290 
2291     // The item should still exist
2292     check_key_value(h, h1, "mykey", "somevalue", 9);
2293 
2294     // time-travel 2 secs..
2295     testHarness.time_travel(2);
2296 
2297     // The item should have expired now...
2298     check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2299     return SUCCESS;
2300 }
2301 
test_touch_mb7342(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2302 static enum test_result test_touch_mb7342(ENGINE_HANDLE *h,
2303                                           ENGINE_HANDLE_V1 *h1) {
2304     const char *key = "MB-7342";
2305     // Store the item!
2306     item *itm = NULL;
2307     check(store(h, h1, NULL, OPERATION_SET, key, "v", &itm) == ENGINE_SUCCESS,
2308           "Failed set.");
2309     h1->release(h, NULL, itm);
2310 
2311     touch(h, h1, key, 0, 0);
2312     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch key");
2313 
2314     check_key_value(h, h1, key, "v", 1);
2315 
2316     // Travel a loong time to see if the object is still there (the default
2317     // store sets an exp time of 3600
2318     testHarness.time_travel(3700);
2319 
2320     check_key_value(h, h1, key, "v", 1);
2321 
2322     return SUCCESS;
2323 }
2324 
test_touch_mb10277(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2325 static enum test_result test_touch_mb10277(ENGINE_HANDLE *h,
2326                                             ENGINE_HANDLE_V1 *h1) {
2327     const char *key = "MB-10277";
2328     // Store the item!
2329     item *itm = NULL;
2330     check(store(h, h1, NULL, OPERATION_SET, key, "v", &itm) == ENGINE_SUCCESS,
2331           "Failed set.");
2332     h1->release(h, NULL, itm);
2333     wait_for_flusher_to_settle(h, h1);
2334     evict_key(h, h1, key, 0, "Ejected.");
2335 
2336     touch(h, h1, key, 0, 3600); // A new expiration time remains in the same.
2337     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch key");
2338 
2339     return SUCCESS;
2340 }
2341 
test_gat(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2342 static enum test_result test_gat(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2343     // key is a mandatory field!
2344     gat(h, h1, NULL, 0, 10);
2345     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2346 
2347     // extlen is a mandatory field!
2348     protocol_binary_request_header *request;
2349     request = createPacket(PROTOCOL_BINARY_CMD_GAT, 0, 0, NULL, 0, "akey", 4);
2350     check(h1->unknown_command(h, NULL, request, add_response) == ENGINE_SUCCESS,
2351           "Failed to call gat");
2352     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2353     free(request);
2354 
2355     // Try to gat an unknown item...
2356     gat(h, h1, "mykey", 0, 10);
2357     check(last_status == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, "Testing unknown key");
2358 
2359     // illegal vbucket
2360     gat(h, h1, "mykey", 5, 10);
2361     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, "Testing illegal vbucket");
2362 
2363     // Store the item!
2364     item *itm = NULL;
2365     check(store(h, h1, NULL, OPERATION_SET, "mykey", "{\"some\":\"value\"}",
2366                 &itm, 0, 0, 3600, PROTOCOL_BINARY_DATATYPE_JSON) == ENGINE_SUCCESS,
2367           "Failed set.");
2368     h1->release(h, NULL, itm);
2369 
2370     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2371             strlen("{\"some\":\"value\"}"));
2372 
2373     gat(h, h1, "mykey", 0, 10);
2374     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "gat mykey");
2375     check(last_datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Expected datatype to be JSON");
2376     check(memcmp(last_body, "{\"some\":\"value\"}", sizeof("{\"some\":\"value\"}")) == 0,
2377           "Invalid data returned");
2378 
2379     // time-travel 9 secs..
2380     testHarness.time_travel(9);
2381 
2382     // The item should still exist
2383     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2384                     strlen("{\"some\":\"value\"}"));
2385 
2386     // time-travel 2 secs..
2387     testHarness.time_travel(2);
2388 
2389     // The item should have expired now...
2390     check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2391     return SUCCESS;
2392 }
2393 
test_gatq(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2394 static enum test_result test_gatq(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2395     // key is a mandatory field!
2396     gat(h, h1, NULL, 0, 10, true);
2397     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2398 
2399     // extlen is a mandatory field!
2400     protocol_binary_request_header *request;
2401     request = createPacket(PROTOCOL_BINARY_CMD_GATQ, 0, 0, NULL, 0, "akey", 4);
2402     check(h1->unknown_command(h, NULL, request, add_response) == ENGINE_SUCCESS,
2403           "Failed to call gatq");
2404     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2405     free(request);
2406 
2407     // Try to gatq an unknown item...
2408     last_status = static_cast<protocol_binary_response_status>(0xffff);
2409     gat(h, h1, "mykey", 0, 10, true);
2410 
2411     // We should not have sent any response!
2412     check(last_status == (protocol_binary_response_status)0xffff, "Testing unknown key");
2413 
2414     // illegal vbucket
2415     gat(h, h1, "mykey", 5, 10, true);
2416     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2417           "Testing illegal vbucket");
2418 
2419     // Store the item!
2420     item *itm = NULL;
2421     check(store(h, h1, NULL, OPERATION_SET, "mykey", "{\"some\":\"value\"}",
2422                 &itm, 0, 0, 3600, PROTOCOL_BINARY_DATATYPE_JSON) == ENGINE_SUCCESS,
2423           "Failed set.");
2424     h1->release(h, NULL, itm);
2425 
2426     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2427                     strlen("{\"some\":\"value\"}"));
2428 
2429     gat(h, h1, "mykey", 0, 10, true);
2430     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "gat mykey");
2431     check(last_datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Expected datatype to be JSON");
2432     check(memcmp(last_body, "{\"some\":\"value\"}", sizeof("{\"some\":\"value\"}")) == 0,
2433           "Invalid data returned");
2434 
2435     // time-travel 9 secs..
2436     testHarness.time_travel(9);
2437 
2438     // The item should still exist
2439     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2440                     strlen("{\"some\":\"value\"}"));
2441 
2442     // time-travel 2 secs..
2443     testHarness.time_travel(2);
2444 
2445     // The item should have expired now...
2446     check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2447     return SUCCESS;
2448 }
2449 
test_mb5215(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2450 static enum test_result test_mb5215(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2451     item *itm = NULL;
2452     check(store(h, h1, NULL, OPERATION_SET, "coolkey", "cooler", &itm)
2453           == ENGINE_SUCCESS, "Failed set.");
2454     h1->release(h, NULL, itm);
2455 
2456     check_key_value(h, h1, "coolkey", "cooler", strlen("cooler"));
2457 
2458     // set new exptime to 111
2459     int expTime = time(NULL) + 111;
2460 
2461     touch(h, h1, "coolkey", 0, expTime);
2462     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch coolkey");
2463 
2464     //reload engine
2465     testHarness.reload_engine(&h, &h1,
2466                               testHarness.engine_path,
2467                               testHarness.get_current_testcase()->cfg,
2468                               true, false);
2469     wait_for_warmup_complete(h, h1);
2470 
2471     //verify persisted expiration time
2472     const char *statkey = "key coolkey 0";
2473     int newExpTime;
2474     check(h1->get(h, NULL, &itm, "coolkey", 7, 0) == ENGINE_SUCCESS,
2475           "Missing key");
2476     h1->release(h, NULL, itm);
2477     newExpTime = get_int_stat(h, h1, "key_exptime", statkey);
2478     check(newExpTime == expTime, "Failed to persist new exptime");
2479 
2480     // evict key, touch expiration time, and verify
2481     evict_key(h, h1, "coolkey", 0, "Ejected.");
2482 
2483     expTime = time(NULL) + 222;
2484     touch(h, h1, "coolkey", 0, expTime);
2485     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch coolkey");
2486 
2487     testHarness.reload_engine(&h, &h1,
2488                               testHarness.engine_path,
2489                               testHarness.get_current_testcase()->cfg,
2490                               true, false);
2491     wait_for_warmup_complete(h, h1);
2492 
2493     check(h1->get(h, NULL, &itm, "coolkey", 7, 0) == ENGINE_SUCCESS,
2494           "Missing key");
2495     h1->release(h, NULL, itm);
2496     newExpTime = get_int_stat(h, h1, "key_exptime", statkey);
2497     check(newExpTime == expTime, "Failed to persist new exptime");
2498 
2499     return SUCCESS;
2500 }
2501 
test_alloc_limit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2502 static enum test_result test_alloc_limit(ENGINE_HANDLE *h,
2503                                          ENGINE_HANDLE_V1 *h1) {
2504     item *it = NULL;
2505     ENGINE_ERROR_CODE rv;
2506 
2507     rv = h1->allocate(h, NULL, &it, "key", 3, 20 * 1024 * 1024, 0, 0,
2508                       PROTOCOL_BINARY_RAW_BYTES);
2509     check(rv == ENGINE_SUCCESS, "Allocated 20MB item");
2510     h1->release(h, NULL, it);
2511 
2512     rv = h1->allocate(h, NULL, &it, "key", 3, (20 * 1024 * 1024) + 1, 0, 0,
2513                       PROTOCOL_BINARY_RAW_BYTES);
2514     check(rv == ENGINE_E2BIG, "Object too big");
2515 
2516     return SUCCESS;
2517 }
2518 
test_whitespace_db(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2519 static enum test_result test_whitespace_db(ENGINE_HANDLE *h,
2520                                            ENGINE_HANDLE_V1 *h1) {
2521     vals.clear();
2522     check(h1->get_stats(h, NULL, NULL, 0, add_stats) == ENGINE_SUCCESS,
2523           "Failed to get stats.");
2524     if (vals["ep_dbname"] != std::string(WHITESPACE_DB)) {
2525         std::cerr << "Expected dbname = ``" << WHITESPACE_DB << "''"
2526                   << ", got ``" << vals["ep_dbname"] << "''" << std::endl;
2527         return FAIL;
2528     }
2529 
2530     check(access(WHITESPACE_DB, F_OK) != -1, "I expected the whitespace db to exist");
2531     return SUCCESS;
2532 }
2533 
test_memory_limit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2534 static enum test_result test_memory_limit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2535     set_param(h, h1, protocol_binary_engine_param_flush, "mutation_mem_threshold", "95");
2536     int used = get_int_stat(h, h1, "mem_used");
2537     double mem_threshold =
2538         static_cast<double>(get_int_stat(h, h1, "ep_mutation_mem_threshold")) / 100;
2539     int max = static_cast<int>(get_int_stat(h, h1, "ep_max_size") * mem_threshold);
2540     check(get_int_stat(h, h1, "ep_oom_errors") == 0 &&
2541           get_int_stat(h, h1, "ep_tmp_oom_errors") == 0, "Expected no OOM errors.");
2542     cb_assert(used < max);
2543 
2544     char data[8192];
2545     memset(data, 'x', sizeof(data));
2546     size_t vlen = max - used - 192;
2547     data[vlen] = 0x00;
2548 
2549     item *i = NULL;
2550     // So if we add an item,
2551     check(store(h, h1, NULL, OPERATION_SET, "key", data, &i) == ENGINE_SUCCESS,
2552           "store failure");
2553     check_key_value(h, h1, "key", data, vlen);
2554     h1->release(h, NULL, i);
2555 
2556     // There should be no room for another.
2557     ENGINE_ERROR_CODE second = store(h, h1, NULL, OPERATION_SET, "key2", data, &i);
2558     check(second == ENGINE_ENOMEM || second == ENGINE_TMPFAIL,
2559           "should have failed second set");
2560     h1->release(h, NULL, i);
2561     check(get_int_stat(h, h1, "ep_oom_errors") == 1 ||
2562           get_int_stat(h, h1, "ep_tmp_oom_errors") == 1, "Expected an OOM error.");
2563 
2564     ENGINE_ERROR_CODE overwrite = store(h, h1, NULL, OPERATION_SET, "key", data, &i);
2565     check(overwrite == ENGINE_ENOMEM || overwrite == ENGINE_TMPFAIL,
2566           "should have failed second override");
2567     h1->release(h, NULL, i);
2568     check(get_int_stat(h, h1, "ep_oom_errors") == 2 ||
2569           get_int_stat(h, h1, "ep_tmp_oom_errors") == 2, "Expected another OOM error.");
2570     check_key_value(h, h1, "key", data, vlen);
2571     check(ENGINE_SUCCESS != verify_key(h, h1, "key2"), "Expected a failure in GET");
2572     int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
2573     // Until we remove that item
2574     check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
2575     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
2576     testHarness.time_travel(65);
2577     wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
2578 
2579     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue2", &i) == ENGINE_SUCCESS,
2580           "should have succeded on the last set");
2581     check_key_value(h, h1, "key2", "somevalue2", 10);
2582     h1->release(h, NULL, i);
2583     return SUCCESS;
2584 }
2585 
test_vbucket_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2586 static enum test_result test_vbucket_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2587     return verify_vbucket_missing(h, h1, 1) ? SUCCESS : FAIL;
2588 }
2589 
test_vbucket_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2590 static enum test_result test_vbucket_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2591     return verify_vbucket_state(h, h1, 0, vbucket_state_active) ? SUCCESS : FAIL;
2592 }
2593 
test_vbucket_create(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2594 static enum test_result test_vbucket_create(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2595     if (!verify_vbucket_missing(h, h1, 1)) {
2596         fprintf(stderr, "vbucket wasn't missing.\n");
2597         return FAIL;
2598     }
2599 
2600     if (!set_vbucket_state(h, h1, 1, vbucket_state_active)) {
2601         fprintf(stderr, "set state failed.\n");
2602         return FAIL;
2603     }
2604 
2605     return verify_vbucket_state(h, h1, 1, vbucket_state_active) ? SUCCESS : FAIL;
2606 }
2607 
test_vbucket_compact(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)2608 static enum test_result test_vbucket_compact(ENGINE_HANDLE *h,
2609                                              ENGINE_HANDLE_V1 *h1) {
2610     const char *key = "Carss";
2611     const char *value = "pollute";
2612     if (!verify_vbucket_missing(h, h1, 0)) {
2613         fprintf(stderr, "vbucket wasn't missing.\n");
2614         return FAIL;
2615     }
2616 
2617     if (!set_vbucket_state(h, h1, 0, vbucket_state_active)) {
2618         fprintf(stderr, "set state failed.\n");
2619         return FAIL;
2620     }
2621 
2622     check(verify_vbucket_state(h, h1, 0, vbucket_state_active),
2623             "VBucket state not active");
2624 
2625     // Set two keys - one to be expired and other to remain...
2626     item *itm = NULL;
2627     check(store(h, h1, NULL, OPERATION_SET, key, value, &itm)
2628           == ENGINE_SUCCESS, "Failed set.");
2629     h1->release(h, NULL, itm);
2630 
2631     check_key_value(h, h1, key, value, strlen(value));
2632 
2633     // Set a non-expiring key...
2634     check(store(h, h1, NULL, OPERATION_SET, "trees", "cleanse", &itm)
2635           == ENGINE_SUCCESS, "Failed set.");
2636     h1->release(h, NULL, itm);
2637 
2638     check_key_value(h,