blob: 99d7e9020d9362c0bcd19d7e9910bc3b8d2ff780 [file] [log] [blame]
Chengyu Fanc7b87ad2015-07-09 16:44:37 -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 "publish/publish-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 PublishAdapterTest : public publish::PublishAdapter<std::string>
35 {
36 public:
37 PublishAdapterTest(const std::shared_ptr<ndn::util::DummyClientFace>& face,
Chengyu Fancfb80c72015-10-19 16:50:04 -060038 const std::shared_ptr<ndn::KeyChain>& keyChain,
39 std::shared_ptr<chronosync::Socket>& syncSocket)
40 : publish::PublishAdapter<std::string>(face, keyChain, syncSocket)
Chengyu Fanc7b87ad2015-07-09 16:44:37 -060041 {
42 }
43
44 virtual
45 ~PublishAdapterTest()
46 {
47 }
48
Chengyu Fanf4c747a2015-08-18 13:56:01 -060049 void
50 setDatabaseTable(const std::string& databaseTable)
51 {
52 m_databaseTable = databaseTable;
53 }
54
55 void
56 setTableFields(const std::vector<std::string>& tableFields)
Chengyu Fan46398212015-08-11 11:23:13 -060057 {
58 m_tableColumns = tableFields;
59 }
60
Chengyu Fanc7b87ad2015-07-09 16:44:37 -060061 const ndn::Name
62 getPrefix()
63 {
64 return m_prefix;
65 }
66
67 const ndn::Name
68 getSigningId()
69 {
70 return m_signingId;
71 }
72
73 const ndn::Name
74 getSyncPrefix()
75 {
76 return m_syncPrefix;
77 }
78
79 void
80 configAdapter(const util::ConfigSection& section,
81 const ndn::Name& prefix)
82 {
83 onConfig(section, false, std::string("test.txt"), prefix);
84 }
85
86 bool
Chengyu Fan46398212015-08-11 11:23:13 -060087 testJson2Sql(std::stringstream& sqlString,
88 Json::Value& jsonValue,
89 util::DatabaseOperation operation)
90 {
91 return json2Sql(sqlString, jsonValue, operation);
92 }
93
94 bool
95 testName2Fields(std::stringstream& sqlString,
96 std::string& fileName)
97 {
98 return name2Fields(sqlString, fileName);
99 }
100
101 bool
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600102 testValidatePublicationChanges(const std::shared_ptr<const ndn::Data>& data)
103 {
104 return validatePublicationChanges(data);
105 }
106 };
107
108 class PublishAdapterFixture : public UnitTestTimeFixture
109 {
110 public:
111 PublishAdapterFixture()
112 : face(makeDummyClientFace(io))
113 , keyChain(new ndn::KeyChain())
Chengyu Fanf4c747a2015-08-18 13:56:01 -0600114 , databaseTable("cmip5")
Chengyu Fancfb80c72015-10-19 16:50:04 -0600115 , publishAdapterTest1(face, keyChain, syncSocket)
116 , publishAdapterTest2(face, keyChain, syncSocket)
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600117 {
Chengyu Fan46398212015-08-11 11:23:13 -0600118 std::string cx("sha256"), c0("name"), c1("activity"), c2("product"), c3("organization");
119 std::string c4("model"), c5("experiment"), c6("frequency"), c7("modeling_realm");
120 std::string c8("variable_name"), c9("ensemble"), c10("time");
121 tableFields.push_back(cx);
122 tableFields.push_back(c0);
123 tableFields.push_back(c1);
124 tableFields.push_back(c2);
125 tableFields.push_back(c3);
126 tableFields.push_back(c4);
127 tableFields.push_back(c5);
128 tableFields.push_back(c6);
129 tableFields.push_back(c7);
130 tableFields.push_back(c8);
131 tableFields.push_back(c9);
132 tableFields.push_back(c10);
Chengyu Fanf4c747a2015-08-18 13:56:01 -0600133 publishAdapterTest1.setDatabaseTable(databaseTable);
134 publishAdapterTest1.setTableFields(tableFields);
135 publishAdapterTest2.setDatabaseTable(databaseTable);
136 publishAdapterTest2.setTableFields(tableFields);
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600137 }
138
139 virtual
140 ~PublishAdapterFixture()
141 {
142 }
143
144 protected:
145 void
146 initializePublishAdapterTest1()
147 {
148 util::ConfigSection section;
149 try {
150 std::stringstream ss;
151 ss << "database \
152 { \
153 dbServer localhost \
154 dbName testdb \
155 dbUser testuser \
156 dbPasswd testpwd \
157 } \
158 sync \
159 { \
160 prefix ndn:/ndn/broadcast1 \
161 }";
162 boost::property_tree::read_info(ss, section);
163 }
164 catch (boost::property_tree::info_parser_error &e) {
165 std::cout << "Failed to read config file " << e.what() << std::endl;
166 }
Chengyu Fanf4c747a2015-08-18 13:56:01 -0600167
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600168 publishAdapterTest1.configAdapter(section, ndn::Name("/test"));
169 }
170
171 void
172 initializePublishAdapterTest2()
173 {
174 util::ConfigSection section;
175 try {
176 std::stringstream ss;
177 ss << "\
178 signingId /prefix/signingId \
179 database \
180 { \
181 dbServer localhost \
182 dbName testdb \
183 dbUser testuser \
184 dbPasswd testpwd \
185 } \
186 sync \
187 { \
188 }";
189 boost::property_tree::read_info(ss, section);
190 }
191 catch (boost::property_tree::info_parser_error &e) {
192 std::cout << "Failed to read config file " << e.what() << std::endl;;
193 }
Chengyu Fanf4c747a2015-08-18 13:56:01 -0600194
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600195 publishAdapterTest2.configAdapter(section, ndn::Name("/test"));
196 }
197
198 protected:
199 std::shared_ptr<DummyClientFace> face;
200 std::shared_ptr<ndn::KeyChain> keyChain;
Chengyu Fancfb80c72015-10-19 16:50:04 -0600201 std::shared_ptr<chronosync::Socket> syncSocket;
Chengyu Fanf4c747a2015-08-18 13:56:01 -0600202 std::vector<std::string> tableFields;
203 std::string databaseTable;
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600204 PublishAdapterTest publishAdapterTest1;
205 PublishAdapterTest publishAdapterTest2;
206 };
207
208 BOOST_FIXTURE_TEST_SUITE(PublishAdapterTestSuite, PublishAdapterFixture)
209
210 BOOST_AUTO_TEST_CASE(BasicPublishAdapterTest1)
211 {
212 BOOST_CHECK(publishAdapterTest1.getPrefix() == ndn::Name());
213 BOOST_CHECK(publishAdapterTest1.getSigningId() == ndn::Name());
214 BOOST_CHECK(publishAdapterTest1.getSyncPrefix() == ndn::Name());
215 }
216
217 BOOST_AUTO_TEST_CASE(BasicPublishAdapterTest2)
218 {
219 initializePublishAdapterTest1();
220 BOOST_CHECK(publishAdapterTest1.getPrefix() == ndn::Name("/test"));
221 BOOST_CHECK(publishAdapterTest1.getSigningId() == ndn::Name());
222 BOOST_CHECK(publishAdapterTest1.getSyncPrefix() == ndn::Name("ndn:/ndn/broadcast1"));
223
224 initializePublishAdapterTest2();
225 BOOST_CHECK(publishAdapterTest2.getPrefix() == ndn::Name("/test"));
226 BOOST_CHECK(publishAdapterTest2.getSigningId() == ndn::Name("/prefix/signingId"));
227 BOOST_CHECK(publishAdapterTest2.getSyncPrefix() ==
228 ndn::Name("ndn:/ndn-atmos/broadcast/chronosync"));
229 }
230
Chengyu Fan46398212015-08-11 11:23:13 -0600231 BOOST_AUTO_TEST_CASE(PublishAdapterName2FieldsNormalTest)
232 {
233 std::string testFileName1 = "/1/2/3/4/5/6/7/8/9/10";
234 std::stringstream ss;
235 std::string expectString1 = ",'1','2','3','4','5','6','7','8','9','10'";
236 BOOST_CHECK_EQUAL(publishAdapterTest1.testName2Fields(ss, testFileName1), true);
237 BOOST_CHECK_EQUAL(ss.str(), expectString1);
238
239 ss.str("");
240 ss.clear();
241 std::string testFileName2 = "ndn:/1/2/3/4/5/6/777/8/99999/10";
242 std::string expectString2 = ",'1','2','3','4','5','6','777','8','99999','10'";
243 BOOST_CHECK_EQUAL(publishAdapterTest1.testName2Fields(ss, testFileName2), true);
244 BOOST_CHECK_EQUAL(ss.str(), expectString2);
245 }
246
247 BOOST_AUTO_TEST_CASE(PublishAdapterName2FieldsFailureTest)
248 {
249 std::string testFileName1 = "/1/2/3/4/5/6/7/8/9/10/11";//too much components
250 std::stringstream ss;
251 BOOST_CHECK_EQUAL(publishAdapterTest1.testName2Fields(ss, testFileName1), false);
252
253 ss.str("");
254 ss.clear();
255 std::string testFileName2 = "1234567890";
256 BOOST_CHECK_EQUAL(publishAdapterTest1.testName2Fields(ss, testFileName2), false);
257
258 ss.str("");
259 ss.clear();
260 std::string testFileName3 = "ndn:/1/2/3/4/5"; //too little components
261 BOOST_CHECK_EQUAL(publishAdapterTest1.testName2Fields(ss, testFileName3), false);
262 }
263
264 BOOST_AUTO_TEST_CASE(PublishAdapterSqlStringNormalTest)
265 {
266 Json::Value testJson;
267 testJson["add"][0] = "/1/2/3/4/5/6/7/8/9/10";
268 testJson["add"][1] = "ndn:/a/b/c/d/eee/f/gg/h/iiii/j";
269 testJson["remove"][0] = "ndn:/1/2/3/4/5/6/7/8/9/10";
270 testJson["remove"][1] = "/a/b/c/d";
271 testJson["remove"][2] = "/test/for/remove";
272
273 std::stringstream ss;
274 std::string expectRes1 = "INSERT INTO cmip5 (sha256, name, activity, product, organization, \
275model, experiment, frequency, modeling_realm, variable_name, ensemble, time) VALUES(\
276'3738C9C0E0297DE7FE0EE538030597442DEEFF0F2C88778404D7B6E4BAD589F6','/1/2/3/4/5/6/7/8/9/10',\
277'1','2','3','4','5','6','7','8','9','10'),\
278('F93128EE9B7769105C6BDF6AA0FAA8CB4ED429395DDBC2CDDBFBA05F35B320FB','ndn:/a/b/c/d/eee/f/gg/h/iiii/j'\
279,'a','b','c','d','eee','f','gg','h','iiii','j');";
280 BOOST_CHECK_EQUAL(publishAdapterTest1.testJson2Sql(ss, testJson, util::ADD), true);
281 BOOST_CHECK_EQUAL(ss.str(), expectRes1);
282
283 ss.str("");
284 ss.clear();
Chengyu Fan71b712b2015-09-09 22:13:56 -0600285 std::string expectRes2 = "DELETE FROM cmip5 WHERE name IN ('ndn:/1/2/3/4/5/6/7/8/9/10',\
Chengyu Fan46398212015-08-11 11:23:13 -0600286'/a/b/c/d','/test/for/remove');";
287 BOOST_CHECK_EQUAL(publishAdapterTest1.testJson2Sql(ss, testJson, util::REMOVE), true);
288 BOOST_CHECK_EQUAL(ss.str(), expectRes2);
289 }
290
291 BOOST_AUTO_TEST_CASE(PublishAdapterSqlStringFailureTest)
292 {
293 Json::Value testJson;
294 testJson["add"][0] = "/1/2/3/4/5/6/7/8/9/10";
295 testJson["add"][1] = "/a/b/c/d/eee/f/gg/h/iiii/j/kkk"; //too much components
296 std::stringstream ss;
297 bool res = publishAdapterTest1.testJson2Sql(ss, testJson, util::REMOVE);
298 BOOST_CHECK(res == false);
299 }
300
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600301 BOOST_AUTO_TEST_CASE(PublishAdapterValidateDataTestSuccess)
302 {
303 ndn::Name dataName("/test/publisher/12345"); // data name must be prefix+nonce
304 Json::Value testJson;
305 testJson["add"][0] = "/test/publisher/1";
306 testJson["add"][1] = "/test/publisher/2";
307 testJson["remove"][0] = "/test/publisher/5";
308
309 Json::FastWriter fastWriter;
310 const std::string jsonMessage = fastWriter.write(testJson);
311 const char* payload = jsonMessage.c_str();
312 size_t payLoadLength = jsonMessage.size() + 1;
313
314 std::shared_ptr<ndn::Data> data = std::make_shared<ndn::Data>(dataName);
315 data->setContent(reinterpret_cast<const uint8_t*>(payload), payLoadLength);
316 data->setFreshnessPeriod(ndn::time::milliseconds(10000));
317
318 BOOST_CHECK_EQUAL(true, publishAdapterTest1.testValidatePublicationChanges(data));
319
320 ndn::Name dataName2("/"); // short data name
321 Json::Value testJson2;
322 testJson2["add"][0] = "/test/publisher2/1";
323 testJson2["remove"][0] = "/test/publisher/1/2/3";
324
325 const std::string jsonMessage2 = fastWriter.write(testJson2);
326 const char* payload2 = jsonMessage2.c_str();
327 size_t payLoadLength2 = jsonMessage2.size() + 1;
328
329 std::shared_ptr<ndn::Data> data2 = std::make_shared<ndn::Data>(dataName2);
330 data2->setContent(reinterpret_cast<const uint8_t*>(payload2), payLoadLength2);
331 data2->setFreshnessPeriod(ndn::time::milliseconds(10000));
332 BOOST_CHECK_EQUAL(true, publishAdapterTest1.testValidatePublicationChanges(data2));
333 }
334
335 BOOST_AUTO_TEST_CASE(PublishAdapterValidateDataTestFail)
336 {
337 ndn::Name dataName1("test/publisher2/12345"); // data name must be prefix+nonce
338 Json::Value testJson1;
339 testJson1["add"][0] = "/test/publisher2/1";
340 testJson1["remove"][0] = "/test/publisher/1/2/3";
341 testJson1["remove"][1] = "/test/publisher2/4";
342
343 Json::FastWriter fastWriter;
344 const std::string jsonMessage1 = fastWriter.write(testJson1);
345 const char* payload1 = jsonMessage1.c_str();
346 size_t payLoadLength1 = jsonMessage1.size() + 1;
347
348 std::shared_ptr<ndn::Data> data1 = std::make_shared<ndn::Data>(dataName1);
349 data1->setContent(reinterpret_cast<const uint8_t*>(payload1), payLoadLength1);
350 data1->setFreshnessPeriod(ndn::time::milliseconds(10000));
351
352 BOOST_CHECK_EQUAL(false, publishAdapterTest1.testValidatePublicationChanges(data1));
353 }
354
355 BOOST_AUTO_TEST_SUITE_END()
356
357}//tests
358}//atmos