1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5 
6 #include <memcached/engine.h>
7 
8 #include "suite_stubs.h"
9 
10 int expiry = 3600;
11 bool hasError = false;
12 struct test_harness testHarness;
13 
14 static const char *key = "key";
15 
test_setup(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)16 bool test_setup(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
17     (void)h; (void)h1;
18     delay(2);
19     return true;
20 }
21 
teardown(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)22 bool teardown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
23     (void)h; (void)h1;
24     return true;
25 }
26 
delay(int amt)27 void delay(int amt) {
28     testHarness.time_travel(amt);
29     hasError = false;
30 }
31 
storeItem(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1,ENGINE_STORE_OPERATION op)32 static void storeItem(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
33                       ENGINE_STORE_OPERATION op) {
34     item *it = NULL;
35     uint64_t cas = 0;
36     char *value = "0";
37     const int flags = 0;
38     const void *cookie = NULL;
39 
40     if (op == OPERATION_APPEND) {
41         value = "-suffix";
42     } else if (op == OPERATION_PREPEND) {
43         value = "prefix-";
44     }
45 
46     size_t vlen = strlen(value);
47 
48     ENGINE_ERROR_CODE rv = ENGINE_SUCCESS;
49 
50     rv = h1->allocate(h, cookie, &it,
51                       key, strlen(key),
52                       vlen, flags, expiry);
53     assert(rv == ENGINE_SUCCESS);
54 
55     item_info info;
56     info.nvalue = 1;
57     if (!h1->get_item_info(h, cookie, it, &info)) {
58         abort();
59     }
60 
61     memcpy(info.value[0].iov_base, value, vlen);
62     h1->item_set_cas(h, cookie, it, 0);
63 
64     rv = h1->store(h, cookie, it, &cas, op, 0);
65 
66     hasError = rv != ENGINE_SUCCESS;
67 }
68 
add(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)69 void add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
70     storeItem(h, h1, OPERATION_ADD);
71 }
72 
append(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)73 void append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
74     storeItem(h, h1, OPERATION_APPEND);
75 }
76 
decr(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)77 void decr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
78     uint64_t cas;
79     uint64_t result;
80     hasError = h1->arithmetic(h, NULL, key, strlen(key), false, false, 1, 0, expiry,
81                               &cas, &result,
82                               0) != ENGINE_SUCCESS;
83 }
84 
decrWithDefault(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)85 void decrWithDefault(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
86     uint64_t cas;
87     uint64_t result;
88     hasError = h1->arithmetic(h, NULL, key, strlen(key), false, true, 1, 0, expiry,
89                               &cas, &result,
90                               0) != ENGINE_SUCCESS;
91 }
92 
prepend(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)93 void prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
94     storeItem(h, h1, OPERATION_PREPEND);
95 }
96 
flush(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)97 void flush(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
98     hasError = h1->flush(h, NULL, 0);
99 }
100 
del(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)101 void del(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
102     hasError = h1->remove(h, NULL, key, strlen(key), 0, 0) != ENGINE_SUCCESS;
103 }
104 
set(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)105 void set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
106     storeItem(h, h1, OPERATION_SET);
107 }
108 
incr(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)109 void incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
110     uint64_t cas;
111     uint64_t result;
112     hasError = h1->arithmetic(h, NULL, key, strlen(key), true, false, 1, 0, expiry,
113                               &cas, &result,
114                               0) != ENGINE_SUCCESS;
115 }
116 
incrWithDefault(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)117 void incrWithDefault(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
118     uint64_t cas;
119     uint64_t result;
120     hasError = h1->arithmetic(h, NULL, key, strlen(key), true, true, 1, 0, expiry,
121                               &cas, &result,
122                               0) != ENGINE_SUCCESS;
123 }
124 
125 
checkValue(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1,const char * exp)126 void checkValue(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1, const char* exp) {
127     item *i = NULL;
128     ENGINE_ERROR_CODE rv = h1->get(h, NULL, &i, key, strlen(key), 0);
129     assert(rv == ENGINE_SUCCESS);
130 
131     item_info info;
132     info.nvalue = 1;
133     h1->get_item_info(h, NULL, i, &info);
134 
135     char buf[info.value[0].iov_len + 1];
136     memcpy(buf, info.value[0].iov_base, info.value[0].iov_len);
137     buf[sizeof(buf) - 1] = 0x00;
138     assert(info.nvalue == 1);
139     if (strlen(exp) > info.value[0].iov_len) {
140         fprintf(stderr, "Expected at least %d bytes for ``%s'', got %d as ``%s''\n",
141                 (int)strlen(exp), exp, (int)info.value[0].iov_len, buf);
142         abort();
143     }
144 
145     if (memcmp(info.value[0].iov_base, exp, strlen(exp)) != 0) {
146         fprintf(stderr, "Expected ``%s'', got ``%s''\n", exp, buf);
147         abort();
148     }
149 }
150 
assertNotExists(ENGINE_HANDLE * h,ENGINE_HANDLE_V1 * h1)151 void assertNotExists(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
152     item *i;
153     ENGINE_ERROR_CODE rv = h1->get(h, NULL, &i, key, strlen(key), 0);
154     assert(rv == ENGINE_KEY_ENOENT);
155 }
156 
157 MEMCACHED_PUBLIC_API
setup_suite(struct test_harness * th)158 bool setup_suite(struct test_harness *th) {
159     testHarness = *th;
160     return true;
161 }
162