1 #include "config.h"
2 #include "iotests.h"
3 #include "internal.h"
4 
5 class SnappyUnitTest : public MockUnitTest
6 {
7   protected:
setCompression(std::string mode)8     void setCompression(std::string mode)
9     {
10         MockEnvironment::getInstance()->setCompression(mode);
11     }
12 
isCompressed(std::string & key)13     bool isCompressed(std::string &key)
14     {
15         const Json::Value info = MockEnvironment::getInstance()->getKeyInfo(key);
16         for (Json::Value::const_iterator ii = info.begin(); ii != info.end(); ii++) {
17             const Json::Value &node = *ii;
18             if (node.isNull()) {
19                 continue;
20             }
21             if (node["Conf"]["Type"] == "master") {
22                 return node["Cache"]["Snappy"].asBool();
23             }
24         }
25         return false;
26     }
27 };
28 
29 struct SnappyCookie {
30     lcb_error_t rc;
31     bool called;
32     std::string value;
33 
resetSnappyCookie34     void reset()
35     {
36         rc = LCB_SUCCESS;
37         called = false;
38     }
SnappyCookieSnappyCookie39     SnappyCookie() : rc(LCB_SUCCESS), called(false) {}
40 
~SnappyCookieSnappyCookie41     ~SnappyCookie() {}
42 };
43 
44 extern "C" {
storecb(lcb_t,int,const lcb_RESPBASE * rb)45 static void storecb(lcb_t, int, const lcb_RESPBASE *rb)
46 {
47     SnappyCookie *cookie = reinterpret_cast< SnappyCookie * >(rb->cookie);
48     cookie->called = true;
49     cookie->rc = rb->rc;
50 }
getcb(lcb_t,int,const lcb_RESPBASE * rb)51 static void getcb(lcb_t, int, const lcb_RESPBASE *rb)
52 {
53     SnappyCookie *cookie = reinterpret_cast< SnappyCookie * >(rb->cookie);
54     cookie->called = true;
55     cookie->rc = rb->rc;
56     const lcb_RESPGET *resp = reinterpret_cast< const lcb_RESPGET * >(rb);
57     cookie->value.assign((char *)resp->value, resp->nvalue);
58 }
59 }
60 
TEST_F(SnappyUnitTest,testSpec)61 TEST_F(SnappyUnitTest, testSpec)
62 {
63     SKIP_UNLESS_MOCK();
64     HandleWrap hw;
65     lcb_t instance;
66 
67     setCompression("passive");
68     createConnection(hw, instance);
69     lcb_cntl_setu32(instance, LCB_CNTL_COMPRESSION_OPTS, LCB_COMPRESS_INOUT);
70     lcb_install_callback3(instance, LCB_CALLBACK_GET, getcb);
71     lcb_install_callback3(instance, LCB_CALLBACK_STORE, storecb);
72 
73     std::string key("hello");
74     std::string value("A big black bug bit a big black bear, made the big black bear bleed blood");
75     std::string compressed("IPA big black bug bit a.\x14");
76 
77     SnappyCookie cookie;
78     lcb_CMDSTORE scmd;
79     lcb_CMDGET gcmd;
80 
81     scmd = lcb_CMDSTORE();
82     scmd.operation = LCB_UPSERT;
83     LCB_CMD_SET_KEY(&scmd, key.c_str(), key.size());
84     LCB_CMD_SET_VALUE(&scmd, value.c_str(), value.size());
85     cookie = SnappyCookie();
86     lcb_store3(instance, &cookie, &scmd);
87     lcb_wait(instance);
88     ASSERT_TRUE(cookie.called);
89     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
90     /* now we have negotiated snappy feature */
91     cookie = SnappyCookie();
92     lcb_store3(instance, &cookie, &scmd);
93     lcb_wait(instance);
94     ASSERT_TRUE(cookie.called);
95     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
96 
97     cookie = SnappyCookie();
98     gcmd = lcb_CMDGET();
99     LCB_CMD_SET_KEY(&gcmd, key.c_str(), key.size());
100     lcb_get3(instance, &cookie, &gcmd);
101     lcb_wait(instance);
102     ASSERT_TRUE(cookie.called);
103     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
104     ASSERT_STREQ(value.c_str(), cookie.value.c_str());
105     ASSERT_TRUE(isCompressed(key));
106 
107     lcb_cntl_setu32(instance, LCB_CNTL_COMPRESSION_OPTS, LCB_COMPRESS_OUT);
108     cookie = SnappyCookie();
109     gcmd = lcb_CMDGET();
110     LCB_CMD_SET_KEY(&gcmd, key.c_str(), key.size());
111     lcb_get3(instance, &cookie, &gcmd);
112     lcb_wait(instance);
113     ASSERT_TRUE(cookie.called);
114     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
115     ASSERT_STREQ(compressed.c_str(), cookie.value.c_str());
116 
117     setCompression("off");
118     hw.destroy();
119     createConnection(hw, instance);
120     lcb_cntl_setu32(instance, LCB_CNTL_COMPRESSION_OPTS, LCB_COMPRESS_INOUT);
121     lcb_install_callback3(instance, LCB_CALLBACK_GET, getcb);
122     lcb_install_callback3(instance, LCB_CALLBACK_STORE, storecb);
123 
124     cookie = SnappyCookie();
125     gcmd = lcb_CMDGET();
126     LCB_CMD_SET_KEY(&gcmd, key.c_str(), key.size());
127     lcb_get3(instance, &cookie, &gcmd);
128     lcb_wait(instance);
129     ASSERT_TRUE(cookie.called);
130     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
131     ASSERT_STREQ(value.c_str(), cookie.value.c_str());
132 
133     cookie = SnappyCookie();
134     lcb_store3(instance, &cookie, &scmd);
135     lcb_wait(instance);
136     ASSERT_TRUE(cookie.called);
137     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
138     ASSERT_FALSE(isCompressed(key));
139 }
140 
TEST_F(SnappyUnitTest,testIOV)141 TEST_F(SnappyUnitTest, testIOV)
142 {
143 
144     SKIP_UNLESS_MOCK();
145     HandleWrap hw;
146     lcb_t instance;
147 
148     setCompression("passive");
149     createConnection(hw, instance);
150     lcb_cntl_setu32(instance, LCB_CNTL_COMPRESSION_OPTS, LCB_COMPRESS_INOUT);
151     lcb_install_callback3(instance, LCB_CALLBACK_GET, getcb);
152     lcb_install_callback3(instance, LCB_CALLBACK_STORE, storecb);
153 
154     std::string key("hello");
155     std::string value1("A big black bug bit ");
156     std::string value2("a big black bear, ");
157     std::string value3("made the big black ");
158     std::string value4("bear bleed blood");
159     std::string value = value1 + value2 + value3 + value4;
160     std::string compressed("IPA big black bug bit a.\x14");
161 
162     SnappyCookie cookie;
163     lcb_CMDSTORE scmd;
164     lcb_CMDGET gcmd;
165 
166     lcb_IOV iov[4];
167     unsigned int niov = 4;
168     iov[0].iov_base = (void *)value1.c_str();
169     iov[0].iov_len = value1.size();
170     iov[1].iov_base = (void *)value2.c_str();
171     iov[1].iov_len = value2.size();
172     iov[2].iov_base = (void *)value3.c_str();
173     iov[2].iov_len = value3.size();
174     iov[3].iov_base = (void *)value4.c_str();
175     iov[3].iov_len = value4.size();
176 
177     scmd = lcb_CMDSTORE();
178     scmd.operation = LCB_UPSERT;
179     LCB_CMD_SET_KEY(&scmd, key.c_str(), key.size());
180     LCB_CMD_SET_VALUEIOV(&scmd, iov, niov);
181     cookie = SnappyCookie();
182     lcb_store3(instance, &cookie, &scmd);
183     lcb_wait(instance);
184     ASSERT_TRUE(cookie.called);
185     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
186     /* now we have negotiated snappy feature */
187     cookie = SnappyCookie();
188     lcb_store3(instance, &cookie, &scmd);
189     lcb_wait(instance);
190     ASSERT_TRUE(cookie.called);
191     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
192 
193     cookie = SnappyCookie();
194     gcmd = lcb_CMDGET();
195     LCB_CMD_SET_KEY(&gcmd, key.c_str(), key.size());
196     lcb_get3(instance, &cookie, &gcmd);
197     lcb_wait(instance);
198     ASSERT_TRUE(cookie.called);
199     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
200     ASSERT_STREQ(value.c_str(), cookie.value.c_str());
201     ASSERT_TRUE(isCompressed(key));
202 
203     lcb_cntl_setu32(instance, LCB_CNTL_COMPRESSION_OPTS, LCB_COMPRESS_OUT);
204     cookie = SnappyCookie();
205     gcmd = lcb_CMDGET();
206     LCB_CMD_SET_KEY(&gcmd, key.c_str(), key.size());
207     lcb_get3(instance, &cookie, &gcmd);
208     lcb_wait(instance);
209     ASSERT_TRUE(cookie.called);
210     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
211     ASSERT_STREQ(compressed.c_str(), cookie.value.c_str());
212 }
213 
214 
TEST_F(SnappyUnitTest,testSettings)215 TEST_F(SnappyUnitTest, testSettings)
216 {
217 
218     SKIP_UNLESS_MOCK();
219     HandleWrap hw;
220     lcb_t instance;
221 
222     setCompression("passive");
223     createConnection(hw, instance);
224     lcb_cntl_string(instance, "compression", "deflate_only");
225     lcb_install_callback3(instance, LCB_CALLBACK_GET, getcb);
226     lcb_install_callback3(instance, LCB_CALLBACK_STORE, storecb);
227 
228     std::string key("hello");
229     std::string value("A big black bug bit a big black bear, made the big black bear bleed blood");
230     std::string compressed("IPA big black bug bit a.\x14");
231 
232     SnappyCookie cookie;
233     lcb_CMDSTORE scmd;
234     lcb_CMDGET gcmd;
235 
236     scmd = lcb_CMDSTORE();
237     scmd.operation = LCB_UPSERT;
238     LCB_CMD_SET_KEY(&scmd, key.c_str(), key.size());
239     LCB_CMD_SET_VALUE(&scmd, value.c_str(), value.size());
240     cookie = SnappyCookie();
241     lcb_store3(instance, &cookie, &scmd);
242     lcb_wait(instance);
243     ASSERT_TRUE(cookie.called);
244     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
245     /* now we have negotiated snappy feature */
246     cookie = SnappyCookie();
247     lcb_store3(instance, &cookie, &scmd);
248     lcb_wait(instance);
249     ASSERT_TRUE(cookie.called);
250     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
251 
252     value = "A big black bug";
253     compressed = "A big black bug";
254     scmd = lcb_CMDSTORE();
255     scmd.operation = LCB_UPSERT;
256     LCB_CMD_SET_KEY(&scmd, key.c_str(), key.size());
257     LCB_CMD_SET_VALUE(&scmd, value.c_str(), value.size());
258     cookie = SnappyCookie();
259     lcb_store3(instance, &cookie, &scmd);
260     lcb_wait(instance);
261     ASSERT_TRUE(cookie.called);
262     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
263 
264     cookie = SnappyCookie();
265     gcmd = lcb_CMDGET();
266     LCB_CMD_SET_KEY(&gcmd, key.c_str(), key.size());
267     lcb_get3(instance, &cookie, &gcmd);
268     lcb_wait(instance);
269     ASSERT_TRUE(cookie.called);
270     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
271     ASSERT_STREQ(compressed.c_str(), cookie.value.c_str());
272 
273     lcb_cntl_string(instance, "compression_min_size", "1024"); /* greater than size of the value */
274     value = "A big black bug bit a big black bear, made the big black bear bleed blood";
275     compressed = "A big black bug bit a big black bear, made the big black bear bleed blood";
276     scmd = lcb_CMDSTORE();
277     scmd.operation = LCB_UPSERT;
278     LCB_CMD_SET_KEY(&scmd, key.c_str(), key.size());
279     LCB_CMD_SET_VALUE(&scmd, value.c_str(), value.size());
280     cookie = SnappyCookie();
281     lcb_store3(instance, &cookie, &scmd);
282     lcb_wait(instance);
283     ASSERT_TRUE(cookie.called);
284     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
285 
286     cookie = SnappyCookie();
287     gcmd = lcb_CMDGET();
288     LCB_CMD_SET_KEY(&gcmd, key.c_str(), key.size());
289     lcb_get3(instance, &cookie, &gcmd);
290     lcb_wait(instance);
291     ASSERT_TRUE(cookie.called);
292     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
293     ASSERT_STREQ(compressed.c_str(), cookie.value.c_str());
294 
295     lcb_cntl_string(instance, "compression_min_size", "40"); /* less than size of the value */
296     lcb_cntl_string(instance, "compression_min_ratio", "0.1"); /* expect to reduce size in 10 times */
297     value = "A big black bug bit a big black bear, made the big black bear bleed blood";
298     compressed = "A big black bug bit a big black bear, made the big black bear bleed blood";
299     scmd = lcb_CMDSTORE();
300     scmd.operation = LCB_UPSERT;
301     LCB_CMD_SET_KEY(&scmd, key.c_str(), key.size());
302     LCB_CMD_SET_VALUE(&scmd, value.c_str(), value.size());
303     cookie = SnappyCookie();
304     lcb_store3(instance, &cookie, &scmd);
305     lcb_wait(instance);
306     ASSERT_TRUE(cookie.called);
307     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
308 
309     cookie = SnappyCookie();
310     gcmd = lcb_CMDGET();
311     LCB_CMD_SET_KEY(&gcmd, key.c_str(), key.size());
312     lcb_get3(instance, &cookie, &gcmd);
313     lcb_wait(instance);
314     ASSERT_TRUE(cookie.called);
315     ASSERT_EQ(LCB_SUCCESS, cookie.rc);
316     ASSERT_STREQ(compressed.c_str(), cookie.value.c_str());
317 }
318