Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include <cppunit/TestAssert.h>
19 : #include <cppunit/TestFixture.h>
20 : #include <cppunit/extensions/HelperMacros.h>
21 :
22 : #include <condition_variable>
23 : #include <string>
24 : #include <thread>
25 : #include <restinio/all.hpp>
26 :
27 : #include "manager.h"
28 : #include "jamidht/jamiaccount.h"
29 : #include "../../test_runner.h"
30 : #include "account_const.h"
31 : #include "common.h"
32 :
33 : using namespace libjami::Account;
34 : using namespace restinio;
35 : using namespace std::literals::chrono_literals;
36 :
37 : namespace jami {
38 : namespace test {
39 :
40 :
41 : using RestRouter = restinio::router::express_router_t<>;
42 : struct RestRouterTraits : public restinio::default_traits_t
43 : {
44 : using request_handler_t = RestRouter;
45 : };
46 :
47 : class NameDirectoryTest : public CppUnit::TestFixture
48 : {
49 : public:
50 7 : NameDirectoryTest()
51 7 : {
52 : // Init daemon
53 7 : libjami::init(
54 : libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG));
55 7 : if (not Manager::instance().initialized) {
56 1 : CPPUNIT_ASSERT(libjami::start("jami-sample.yml"));
57 :
58 : // Create express router for our service.
59 1 : auto router = std::make_unique<router::express_router_t<>>();
60 1 : router->http_post(
61 : R"(/name/:name)",
62 1 : [](auto req, auto params) {
63 1 : const auto qp = parse_query(req->header().query());
64 : return req->create_response()
65 3 : .set_body(
66 : fmt::format("{{\"success\":true}}")
67 : )
68 2 : .done();
69 1 : });
70 1 : router->http_get(
71 : R"(/name/:name)",
72 2 : [](auto req, auto params) {
73 2 : const auto qp = parse_query(req->header().query());
74 2 : if (params["name"] == "taken") {
75 : return req->create_response()
76 3 : .set_body(
77 : fmt::format("{{\"name\":\"taken\",\"addr\":\"c0dec0dec0dec0dec0dec0dec0dec0dec0dec0de\"}}")
78 : )
79 1 : .done();
80 : }
81 : return req->create_response(restinio::status_not_found())
82 3 : .set_body(
83 : fmt::format("{{\"error\":\"name not registered\"}}")
84 : )
85 1 : .done();
86 2 : });
87 1 : router->http_get(
88 : R"(/addr/:addr)",
89 8 : [](auto req, auto params) {
90 8 : const auto qp = parse_query(req->header().query());
91 8 : if (params["addr"] == "c0dec0dec0dec0dec0dec0dec0dec0dec0dec0de") {
92 : return req->create_response()
93 0 : .set_body(
94 : fmt::format("{{\"name\":\"taken\",\"addr\":\"c0dec0dec0dec0dec0dec0dec0dec0dec0dec0de\"}}")
95 : )
96 0 : .done();
97 : }
98 : return req->create_response(restinio::status_not_found())
99 24 : .set_body(
100 : fmt::format("{{\"error\":\"address not registered\"}}")
101 : )
102 8 : .done();
103 8 : });
104 :
105 1 : router->non_matched_request_handler(
106 0 : [](auto req){
107 0 : return req->create_response(restinio::status_not_found()).connection_close().done();
108 : });
109 :
110 :
111 1 : auto settings = restinio::run_on_this_thread_settings_t<RestRouterTraits>();
112 1 : settings.address("localhost");
113 1 : settings.port(1412);
114 1 : settings.request_handler(std::move(router));
115 3 : httpServer_ = std::make_unique<restinio::http_server_t<RestRouterTraits>>(
116 2 : Manager::instance().ioContext(),
117 1 : std::forward<restinio::run_on_this_thread_settings_t<RestRouterTraits>>(std::move(settings))
118 1 : );
119 : // run http server
120 2 : serverThread_ = std::thread([this](){
121 2 : httpServer_->open_async([]{/*ok*/}, [](std::exception_ptr ex){
122 0 : std::rethrow_exception(ex);
123 : });
124 1 : httpServer_->io_context().run();
125 1 : });
126 1 : }
127 :
128 7 : }
129 14 : ~NameDirectoryTest() {
130 7 : libjami::fini();
131 7 : if (serverThread_.joinable())
132 1 : serverThread_.join();
133 14 : }
134 2 : static std::string name() { return "NameDirectory"; }
135 : void setUp();
136 : void tearDown();
137 :
138 : std::string aliceId;
139 :
140 : // http server
141 : std::thread serverThread_;
142 : std::unique_ptr<restinio::http_server_t<RestRouterTraits>> httpServer_;
143 :
144 : private:
145 : void testRegisterName();
146 : void testLookupName();
147 : void testLookupNameInvalid();
148 : void testLookupNameNotFound();
149 : void testLookupAddr();
150 : void testLookupAddrInvalid();
151 : void testLookupAddrNotFound();
152 :
153 2 : CPPUNIT_TEST_SUITE(NameDirectoryTest);
154 1 : CPPUNIT_TEST(testRegisterName);
155 1 : CPPUNIT_TEST(testLookupName);
156 1 : CPPUNIT_TEST(testLookupNameInvalid);
157 1 : CPPUNIT_TEST(testLookupNameNotFound);
158 1 : CPPUNIT_TEST(testLookupAddr);
159 1 : CPPUNIT_TEST(testLookupAddrInvalid);
160 1 : CPPUNIT_TEST(testLookupAddrNotFound);
161 4 : CPPUNIT_TEST_SUITE_END();
162 : };
163 :
164 : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(NameDirectoryTest, NameDirectoryTest::name());
165 :
166 : void
167 7 : NameDirectoryTest::setUp()
168 : {
169 14 : auto actors = load_actors_and_wait_for_announcement("actors/alice.yml");
170 7 : aliceId = actors["alice"];
171 7 : std::map<std::string, std::string> details;
172 7 : details[ConfProperties::RingNS::URI] = "http://localhost:1412";
173 7 : libjami::setAccountDetails(aliceId, details);
174 7 : }
175 :
176 : void
177 7 : NameDirectoryTest::tearDown()
178 : {
179 7 : wait_for_removal_of({aliceId});
180 7 : }
181 :
182 : void
183 1 : NameDirectoryTest::testRegisterName()
184 : {
185 1 : std::mutex mtx;
186 1 : std::unique_lock lk {mtx};
187 1 : std::condition_variable cv;
188 1 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
189 1 : bool nameRegistered {false};
190 : // Watch signals
191 1 : confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::NameRegistrationEnded>(
192 1 : [&](const std::string&,
193 : int status,
194 : const std::string&) {
195 1 : nameRegistered = status == 0;
196 1 : cv.notify_one();
197 1 : }));
198 1 : libjami::registerSignalHandlers(confHandlers);
199 1 : CPPUNIT_ASSERT(libjami::registerName(aliceId, "foo"));
200 3 : CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return nameRegistered; }));
201 1 : }
202 :
203 : void
204 1 : NameDirectoryTest::testLookupName()
205 : {
206 1 : std::mutex mtx;
207 1 : std::unique_lock lk {mtx};
208 1 : std::condition_variable cv;
209 1 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
210 1 : bool nameFound {false};
211 : // Watch signals
212 1 : confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::RegisteredNameFound>(
213 1 : [&](const std::string&,
214 : int status,
215 : const std::string&,
216 : const std::string&) {
217 1 : nameFound = status == 0;
218 1 : cv.notify_one();
219 1 : }));
220 1 : libjami::registerSignalHandlers(confHandlers);
221 1 : CPPUNIT_ASSERT(libjami::lookupName(aliceId, "", "taken"));
222 3 : CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return nameFound; }));
223 1 : }
224 :
225 : void
226 1 : NameDirectoryTest::testLookupNameInvalid()
227 : {
228 1 : std::mutex mtx;
229 1 : std::unique_lock lk {mtx};
230 1 : std::condition_variable cv;
231 1 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
232 1 : bool nameInvalid {false};
233 : // Watch signals
234 1 : confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::RegisteredNameFound>(
235 1 : [&](const std::string&,
236 : int status,
237 : const std::string&,
238 : const std::string&) {
239 1 : nameInvalid = status == 1;
240 1 : cv.notify_one();
241 1 : }));
242 1 : libjami::registerSignalHandlers(confHandlers);
243 1 : CPPUNIT_ASSERT(libjami::lookupName(aliceId, "", "===="));
244 2 : CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return nameInvalid; }));
245 1 : }
246 :
247 : void
248 1 : NameDirectoryTest::testLookupNameNotFound()
249 : {
250 1 : std::mutex mtx;
251 1 : std::unique_lock lk {mtx};
252 1 : std::condition_variable cv;
253 1 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
254 1 : bool nameNotFound {false};
255 : // Watch signals
256 1 : confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::RegisteredNameFound>(
257 1 : [&](const std::string&,
258 : int status,
259 : const std::string&,
260 : const std::string&) {
261 1 : nameNotFound = status == 2;
262 1 : cv.notify_one();
263 1 : }));
264 1 : libjami::registerSignalHandlers(confHandlers);
265 1 : CPPUNIT_ASSERT(libjami::lookupName(aliceId, "", "nottaken"));
266 3 : CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return nameNotFound; }));
267 1 : }
268 :
269 : void
270 1 : NameDirectoryTest::testLookupAddr()
271 : {
272 1 : std::mutex mtx;
273 1 : std::unique_lock lk {mtx};
274 1 : std::condition_variable cv;
275 1 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
276 1 : bool addrFound {false};
277 : // Watch signals
278 1 : confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::RegisteredNameFound>(
279 1 : [&](const std::string&,
280 : int status,
281 : const std::string&,
282 : const std::string&) {
283 1 : addrFound = status == 0;
284 1 : cv.notify_one();
285 1 : }));
286 1 : libjami::registerSignalHandlers(confHandlers);
287 1 : CPPUNIT_ASSERT(libjami::lookupAddress(aliceId, "", "c0dec0dec0dec0dec0dec0dec0dec0dec0dec0de"));
288 2 : CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return addrFound; }));
289 1 : }
290 :
291 : void
292 1 : NameDirectoryTest::testLookupAddrInvalid()
293 : {
294 1 : std::mutex mtx;
295 1 : std::unique_lock lk {mtx};
296 1 : std::condition_variable cv;
297 1 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
298 1 : bool addrInvalid {false};
299 : // Watch signals
300 1 : confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::RegisteredNameFound>(
301 1 : [&](const std::string&,
302 : int status,
303 : const std::string&,
304 : const std::string&) {
305 1 : addrInvalid = status == 1;
306 1 : cv.notify_one();
307 1 : }));
308 1 : libjami::registerSignalHandlers(confHandlers);
309 1 : CPPUNIT_ASSERT(libjami::lookupName(aliceId, "", "===="));
310 2 : CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return addrInvalid; }));
311 1 : }
312 :
313 : void
314 1 : NameDirectoryTest::testLookupAddrNotFound()
315 : {
316 1 : std::mutex mtx;
317 1 : std::unique_lock lk {mtx};
318 1 : std::condition_variable cv;
319 1 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
320 1 : bool addrNotFound {false};
321 : // Watch signals
322 1 : confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::RegisteredNameFound>(
323 1 : [&](const std::string&,
324 : int status,
325 : const std::string&,
326 : const std::string&) {
327 1 : addrNotFound = status == 2;
328 1 : cv.notify_one();
329 1 : }));
330 1 : libjami::registerSignalHandlers(confHandlers);
331 1 : CPPUNIT_ASSERT(libjami::lookupAddress(aliceId, "", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
332 3 : CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return addrNotFound; }));
333 1 : }
334 :
335 : } // namespace test
336 : } // namespace jami
337 :
338 1 : RING_TEST_RUNNER(jami::test::NameDirectoryTest::name())
|