blob: 1e8d0c1040dda46a34ca1f125fe0f4c760b22d91 [file] [log] [blame]
Chengyu Fanb25835b2015-04-28 17:09:35 -06001/** NDN-Atmos: Cataloging Service for distributed data originally developed
2 * for atmospheric science data
3 * Copyright (C) 2015 Colorado State University
4 *
5 * NDN-Atmos is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * NDN-Atmos is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with NDN-Atmos. If not, see <http://www.gnu.org/licenses/>.
17**/
18
19#include "query/query-adapter.hpp"
20#include "boost-test.hpp"
21#include "../../unit-test-time-fixture.hpp"
22#include "util/config-file.hpp"
23
24#include <boost/mpl/list.hpp>
25#include <boost/thread.hpp>
26#include <ndn-cxx/util/dummy-client-face.hpp>
27#include <boost/property_tree/info_parser.hpp>
28
29namespace atmos{
30namespace tests{
31 using ndn::util::DummyClientFace;
32 using ndn::util::makeDummyClientFace;
33
34 class QueryAdapterTest : public query::QueryAdapter<std::string>
35 {
36 public:
37 QueryAdapterTest(const std::shared_ptr<ndn::util::DummyClientFace>& face,
38 const std::shared_ptr<ndn::KeyChain>& keyChain)
39 : query::QueryAdapter<std::string>(face, keyChain)
40 {
41 }
42
43 virtual
44 ~QueryAdapterTest()
45 {
46 }
47
48 void setPrefix(const ndn::Name& prefix)
49 {
50 m_prefix = prefix;
51 }
52
53 void setSigningId(const ndn::Name& signingId)
54 {
55 m_signingId = signingId;
56 }
57
58 const ndn::Name
59 getPrefix()
60 {
61 return m_prefix;
62 }
63
64 const ndn::Name
65 getSigningId()
66 {
67 return m_signingId;
68 }
69
70 std::shared_ptr<ndn::Data>
71 getAckData(std::shared_ptr<const ndn::Interest> interest, const ndn::Name::Component& version)
72 {
73 return makeAckData(interest, version);
74 }
75
76 void
77 parseJsonTest(std::string& targetSql,
78 Json::Value& parsedFromString,
79 bool& autocomplete)
80 {
81 std::stringstream resultSql;
82 json2Sql(resultSql, parsedFromString, autocomplete);
83 targetSql.assign(resultSql.str());
84 }
85
86 std::shared_ptr<ndn::Data>
87 getReplyData(const ndn::Name& segmentPrefix,
88 const Json::Value& value,
89 uint64_t segmentNo,
90 bool isFinalBlock,
91 bool isAutocomplete)
92 {
93 return makeReplyData(segmentPrefix, value, segmentNo, isFinalBlock, isAutocomplete);
94 }
95
96 void
97 queryTest(std::shared_ptr<const ndn::Interest> interest)
98 {
99 runJsonQuery(interest);
100 }
101
102 void
103 prepareSegments(const ndn::Name& segmentPrefix,
104 const std::string& sqlString,
105 bool autocomplete)
106 {
107 BOOST_CHECK_EQUAL(sqlString, "SELECT name FROM cmip5 WHERE name=\'test\';");
108 Json::Value fileList;
109 fileList.append("/ndn/test1");
110 fileList.append("/ndn/test2");
111 fileList.append("/ndn/test3");
112
113 std::shared_ptr<ndn::Data> data = makeReplyData(segmentPrefix,
114 fileList,
115 0,
116 true,
117 false);
118 m_mutex.lock();
119 m_cache.insert(*data);
120 m_mutex.unlock();
121 }
122
123 std::shared_ptr<const ndn::Data>
124 getDataFromActiveQuery(const std::string& jsonQuery)
125 {
126 m_mutex.lock();
127 if (m_activeQueryToFirstResponse.find(jsonQuery) != m_activeQueryToFirstResponse.end()) {
128 auto iter = m_activeQueryToFirstResponse.find(jsonQuery);
129 if (iter != m_activeQueryToFirstResponse.end()) {
130 m_mutex.unlock();
131 return iter->second;
132 }
133 }
134 m_mutex.unlock();
135 return std::shared_ptr<const ndn::Data>();
136 }
137
138 std::shared_ptr<const ndn::Data>
139 getDataFromCache(const ndn::Interest& interest)
140 {
141 return m_cache.find(interest);
142 }
143
144 void
145 configAdapter(const util::ConfigSection& section,
146 const ndn::Name& prefix)
147 {
148 onConfig(section, false, std::string("test.txt"), prefix);
149 }
150 };
151
152 class QueryAdapterFixture : public UnitTestTimeFixture
153 {
154 public:
155 QueryAdapterFixture()
156 : face(makeDummyClientFace(io))
157 , keyChain(new ndn::KeyChain())
158 , queryAdapterTest1(face, keyChain)
159 , queryAdapterTest2(face, keyChain)
160 {
161 }
162
163 virtual
164 ~QueryAdapterFixture()
165 {
166 }
167
168 protected:
169 void
170 initializeQueryAdapterTest1()
171 {
172 util::ConfigSection section;
173 try {
174 std::stringstream ss;
175 ss << "signingId /test/signingId\
176 database \
177 { \
178 dbServer localhost \
179 dbName testdb \
180 dbUser testuser \
181 dbPasswd testpwd \
182 }";
183 boost::property_tree::read_info(ss, section);
184 }
185 catch (boost::property_tree::info_parser_error &e) {
186 std::cout << "Failed to read config file " << e.what() << std::endl;;
187 }
188 queryAdapterTest1.configAdapter(section, ndn::Name("/test"));
189 }
190
191 void
192 initializeQueryAdapterTest2()
193 {
194 util::ConfigSection section;
195 try {
196 std::stringstream ss;
197 ss << "database\
198 { \
199 dbServer localhost \
200 dbName testdb \
201 dbUser testuser \
202 dbPasswd testpwd \
203 }";
204 boost::property_tree::read_info(ss, section);
205 }
206 catch (boost::property_tree::info_parser_error &e) {
207 std::cout << "Failed to read config file " << e.what() << std::endl;;
208 }
209 queryAdapterTest2.configAdapter(section, ndn::Name("/test"));
210 }
211
212 protected:
213 std::shared_ptr<DummyClientFace> face;
214 std::shared_ptr<ndn::KeyChain> keyChain;
215 QueryAdapterTest queryAdapterTest1;
216 QueryAdapterTest queryAdapterTest2;
217 };
218
219 BOOST_FIXTURE_TEST_SUITE(QueryAdapterTestSuite, QueryAdapterFixture)
220
221 BOOST_AUTO_TEST_CASE(BasicQueryAdapterTest1)
222 {
223 BOOST_CHECK(queryAdapterTest1.getPrefix() == ndn::Name());
224 BOOST_CHECK(queryAdapterTest1.getSigningId() == ndn::Name());
225 }
226
227 BOOST_AUTO_TEST_CASE(BasicQueryAdapterTest2)
228 {
229 initializeQueryAdapterTest1();
230 BOOST_CHECK(queryAdapterTest1.getPrefix() == ndn::Name("/test"));
231 BOOST_CHECK(queryAdapterTest1.getSigningId() == ndn::Name("/test/signingId"));
232 }
233
234 BOOST_AUTO_TEST_CASE(QueryAdapterJsonParseNormalTest)
235 {
236 Json::Value testJson;
237 testJson["name"] = "test";
238 testJson["activity"] = "testActivity";
239 testJson["product"] = "testProduct";
240
241 std::string dstString;
242 bool autocomplete = false;
243 queryAdapterTest1.parseJsonTest(dstString, testJson, autocomplete);
244 BOOST_CHECK_EQUAL(dstString, "SELECT name FROM cmip5 WHERE\
245 activity=\'testActivity\' AND name='test\' AND product=\'testProduct\';");
246 BOOST_CHECK_EQUAL(autocomplete, false);
247 }
248
249 BOOST_AUTO_TEST_CASE(QueryAdapterJsonParseEmptyTest)
250 {
251 Json::Value testJson;
252
253 std::string dstString;
254 bool autocomplete = false;
255 queryAdapterTest1.parseJsonTest(dstString, testJson, autocomplete);
256 BOOST_CHECK_EQUAL(dstString, "SELECT name FROM cmip5 limit 0;");
257 BOOST_CHECK_EQUAL(autocomplete, false);
258 }
259
260 BOOST_AUTO_TEST_CASE(QueryAdapterJsonParseAllItemsTest)
261 {
262 Json::Value testJson;
263 testJson["name"] = "test";
264 testJson["activity"] = "testActivity";
265 testJson["product"] = "testProduct";
266 testJson["origanization"] = "testOrg";
267 testJson["model"] = "testModel";
268 testJson["experiment"] = "testExperiment";
269 testJson["frequency"] = "testFrenquency";
270 testJson["modeling realm"] = "testModeling";
271 testJson["variable name"] = "testVarName";
272 testJson["ensemble member"] = "testEnsembleMember";
273 testJson["ensemble"] = "testEnsemble";
274 testJson["sample granularity"] = "testSampleGranularity";
275 testJson["start time"] = "testStartTime";
276 testJson["field campaign"] = "testFieldCampaign";
277 testJson["optical properties for radiation"] = "testOptProperties";
278 testJson["grid resolution"] = "testGridResolution";
279 testJson["output type"] = "testOutputType";
280 testJson["timestamp"] = "testTimestamp";
281
282 std::string dstString;
283 bool autocomplete = false;
284 queryAdapterTest1.parseJsonTest(dstString, testJson, autocomplete);
285 BOOST_CHECK_EQUAL(dstString, "SELECT name FROM cmip5 WHERE activity=\'testActivity\' AND \
286ensemble=\'testEnsemble\' AND ensemble member=\'testEnsembleMember\' AND \
287experiment=\'testExperiment\' AND field campaign=\'testFieldCampaign\' AND \
288frequency=\'testFrenquency\' AND grid resolution=\'testGridResolution\' AND \
289model=\'testModel\' AND modeling realm=\'testModeling\' AND name=\'test\' AND \
290optical properties for radiation=\'testOptProperties\' AND origanization=\'testOrg\' AND \
291output type=\'testOutputType\' AND product=\'testProduct\' AND sample \
292granularity=\'testSampleGranularity\' AND start time=\'testStartTime\' AND \
293timestamp=\'testTimestamp\' AND variable name=\'testVarName\';");
294 BOOST_CHECK_EQUAL(autocomplete, false);
295 }
296
297 BOOST_AUTO_TEST_CASE(QueryAdapterJsonParseSearchTest)
298 {
299 Json::Value testJson;
300 testJson["name"] = "test";
301 testJson["?"] = "serchTest";
302
303 std::string dstString;
304 bool autocomplete = false;
305 queryAdapterTest1.parseJsonTest(dstString, testJson, autocomplete);
306 BOOST_CHECK_EQUAL(dstString,
307 "SELECT name FROM cmip5 WHERE name REGEXP \'^serchTest\' AND name=\'test\';");
308 BOOST_CHECK_EQUAL(autocomplete, true);
309 }
310
311 BOOST_AUTO_TEST_CASE(QueryAdapterMakeAckDataTest)
312 {
313 ndn::Interest interest(ndn::Name("/test/ack/data/json"));
314 interest.setInterestLifetime(ndn::time::milliseconds(1000));
315 interest.setMustBeFresh(true);
316 std::shared_ptr<const ndn::Interest> interestPtr = std::make_shared<ndn::Interest>(interest);
317
318 const ndn::name::Component version
319 = ndn::name::Component::fromVersion(1);
320
321 std::shared_ptr<ndn::Data> data = queryAdapterTest2.getAckData(interestPtr, version);
322 BOOST_CHECK_EQUAL(data->getName().toUri(), "/test/ack/data/json/%FD%01/OK");
323 BOOST_CHECK_EQUAL(data->getContent().value_size(), 0);
324 }
325
326 BOOST_AUTO_TEST_CASE(QueryAdapterMakeReplyDataTest1)
327 {
328 Json::Value fileList;
329 fileList.append("/ndn/test1");
330 fileList.append("/ndn/test2");
331
332 const ndn::Name prefix("/atmos/test/prefix");
333
334 std::shared_ptr<ndn::Data> data = queryAdapterTest2.getReplyData(prefix,
335 fileList,
336 1,
337 false,
338 false);
339 BOOST_CHECK_EQUAL(data->getName().toUri(), "/atmos/test/prefix/%00%01");
340 BOOST_CHECK_EQUAL(data->getFinalBlockId(), ndn::Name::Component(""));
341 const std::string jsonRes(reinterpret_cast<const char*>(data->getContent().value()));
342 Json::Value parsedFromString;
343 Json::Reader reader;
344 BOOST_CHECK_EQUAL(reader.parse(jsonRes, parsedFromString), true);
345 BOOST_CHECK_EQUAL(parsedFromString["results"].size(), 2);
346 BOOST_CHECK_EQUAL(parsedFromString["results"][0], "/ndn/test1");
347 BOOST_CHECK_EQUAL(parsedFromString["results"][1], "/ndn/test2");
348 }
349
350 BOOST_AUTO_TEST_CASE(QueryAdapterMakeReplyDataTest2)
351 {
352 Json::Value fileList;
353 fileList.append("/ndn/test1");
354 const ndn::Name prefix("/atmos/test/prefix");
355
356 std::shared_ptr<ndn::Data> data = queryAdapterTest2.getReplyData(prefix,
357 fileList,
358 2,
359 true,
360 true);
361 // the finalBlock does not work for jsNDN
362 BOOST_CHECK_EQUAL(data->getName().toUri(), "/atmos/test/prefix/%00%02");
363 BOOST_CHECK_EQUAL(data->getFinalBlockId(), ndn::Name::Component::fromSegment(2));
364 const std::string jsonRes(reinterpret_cast<const char*>(data->getContent().value()));
365 Json::Value parsedFromString;
366 Json::Reader reader;
367 BOOST_CHECK_EQUAL(reader.parse(jsonRes, parsedFromString), true);
368 BOOST_CHECK_EQUAL(parsedFromString["next"].size(), 1);
369 BOOST_CHECK_EQUAL(parsedFromString["next"][0], "/ndn/test1");
370 }
371
372 BOOST_AUTO_TEST_CASE(QueryAdapterQueryProcessTest)
373 {
374 initializeQueryAdapterTest2();
375 Json::Value query;
376 query["name"] = "test";
377 Json::FastWriter fastWriter;
378 std::string jsonMessage = fastWriter.write(query);
379 jsonMessage.erase(std::remove(jsonMessage.begin(), jsonMessage.end(), '\n'), jsonMessage.end());
380 std::shared_ptr<ndn::Interest> queryInterest
381 = std::make_shared<ndn::Interest>(ndn::Name("/test/query").append(jsonMessage.c_str()));
382
383 queryAdapterTest2.queryTest(queryInterest);
384 auto ackData = queryAdapterTest2.getDataFromActiveQuery(jsonMessage);
385
386 BOOST_CHECK(ackData);
387 if (ackData) {
388 BOOST_CHECK_EQUAL(ackData->getName().getPrefix(3),
389 ndn::Name("/test/query/%7B%22name%22%3A%22test%22%7D"));
390 BOOST_CHECK_EQUAL(ackData->getName().getSubName(4, 1), ndn::Name("OK"));
391 BOOST_CHECK_EQUAL(ackData->getContent().value_size(), 0);
392 }
393
394 std::shared_ptr<ndn::Interest> resultInterest
395 = std::make_shared<ndn::Interest>(ndn::Name("/test/query-results"));
396 auto replyData = queryAdapterTest2.getDataFromCache(*resultInterest);
397 BOOST_CHECK(replyData);
398 if (replyData){
399 BOOST_CHECK_EQUAL(replyData->getName().getPrefix(2), ndn::Name("/test/query-results"));
400 const std::string jsonRes(reinterpret_cast<const char*>(replyData->getContent().value()));
401 Json::Value parsedFromString;
402 Json::Reader reader;
403 BOOST_CHECK_EQUAL(reader.parse(jsonRes, parsedFromString), true);
404 BOOST_CHECK_EQUAL(parsedFromString["results"].size(), 3);
405 BOOST_CHECK_EQUAL(parsedFromString["results"][0], "/ndn/test1");
406 BOOST_CHECK_EQUAL(parsedFromString["results"][1], "/ndn/test2");
407 BOOST_CHECK_EQUAL(parsedFromString["results"][2], "/ndn/test3");
408 }
409 }
410
411 BOOST_AUTO_TEST_SUITE_END()
412
413}//tests
414}//atmos