2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Mateusz Malicki <m.malicki2@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
22 * @author Mateusz Malicki (m.malicki2@samsung.com)
23 * @brief Unit tests of the client C API
28 #include "vasum-client.h"
29 #include "utils/latch.hpp"
30 #include "utils/scoped-dir.hpp"
31 #include "zones-manager.hpp"
32 #include "host-ipc-connection.hpp"
33 #include "host-ipc-definitions.hpp"
34 #include "logger/logger.hpp"
36 #ifdef DBUS_CONNECTION
37 #include "utils/glib-loop.hpp"
38 #endif //DBUS_CONNECTION
48 #include <sys/epoll.h>
50 using namespace vasum;
51 using namespace utils;
55 const std::string TEST_CONFIG_PATH =
56 VSM_TEST_CONFIG_INSTALL_DIR "/test-daemon.conf";
57 const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf
58 const std::string TEMPLATE_NAME = "console-ipc";
59 const int EVENT_TIMEOUT = 500; // ms
62 utils::ScopedDir mZonesPathGuard;
63 utils::ScopedDir mRunGuard;
64 #ifdef DBUS_CONNECTION
65 utils::ScopedGlibLoop mLoop;
66 #endif //DBUS_CONNECTION
68 std::unique_ptr<ZonesManager> cm;
71 : mZonesPathGuard(ZONES_PATH)
72 , mRunGuard("/tmp/ut-run")
73 , cm(new ZonesManager(TEST_CONFIG_PATH))
75 cm->createZone("zone1", TEMPLATE_NAME);
76 cm->createZone("zone2", TEMPLATE_NAME);
77 cm->createZone("zone3", TEMPLATE_NAME);
79 LOGI("------- setup complete --------");
84 LOGI("------- cleanup --------");
88 class SimpleEventLoop {
90 SimpleEventLoop(VsmClient client)
93 , mThread([this] { loop(); })
98 mIsProcessing = false;
104 std::atomic_bool mIsProcessing;
107 while (mIsProcessing) {
108 vsm_enter_eventloop(mClient, 0, EVENT_TIMEOUT);
113 class AggragatedEventLoop {
115 AggragatedEventLoop()
116 : mIsProcessing(true)
117 , mThread([this] { loop(); })
121 ~AggragatedEventLoop()
123 mIsProcessing = false;
127 VsmStatus addEventSource(VsmClient client) {
129 VsmStatus ret = vsm_get_poll_fd(client, &fd);
130 if (VSMCLIENT_SUCCESS != ret) {
133 mEventPoll.addFD(fd, EPOLLIN | EPOLLHUP | EPOLLRDHUP, [client] (int, ipc::epoll::Events) {
134 vsm_enter_eventloop(client, 0, 0);
137 return VSMCLIENT_SUCCESS;
140 std::atomic_bool mIsProcessing;
142 ipc::epoll::EventPoll mEventPoll;
143 std::vector<int> mFds;
146 while (mIsProcessing) {
147 mEventPoll.dispatchIteration(EVENT_TIMEOUT);
149 for (int fd : mFds) {
150 mEventPoll.removeFD(fd);
155 const std::set<std::string> EXPECTED_ZONES = { "zone1", "zone2", "zone3" };
157 void convertArrayToSet(VsmArrayString values, std::set<std::string>& ret)
159 for (VsmArrayString iValues = values; *iValues; iValues++) {
160 ret.insert(*iValues);
164 int getArrayStringLength(VsmArrayString astring, int max_len = -1)
167 for (i = 0; astring[i]; i++) {
175 VsmStatus makeSimpleRequest(VsmClient client)
177 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_connect(client));
179 VsmString zone = NULL;
180 VsmStatus status = vsm_get_active_zone_id(client, &zone);
181 vsm_string_free(zone);
182 // disconnect but not destroy
183 vsm_disconnect(client);
189 // make nice BOOST_*_EQUAL output
190 // (does not work inside anonymous namespace)
191 std::ostream& operator<<(std::ostream& out, VsmStatus status)
194 case VSMCLIENT_CUSTOM_ERROR: return out << "CUSTOM_ERROR";
195 case VSMCLIENT_IO_ERROR: return out << "IO_ERROR";
196 case VSMCLIENT_OPERATION_FAILED: return out << "OPERATION_FAILED";
197 case VSMCLIENT_INVALID_ARGUMENT: return out << "INVALID_ARGUMENT";
198 case VSMCLIENT_OTHER_ERROR: return out << "OTHER_ERROR";
199 case VSMCLIENT_SUCCESS: return out << "SUCCESS";
200 default: return out << "UNKNOWN(" << (int)status << ")";
204 BOOST_FIXTURE_TEST_SUITE(ClientSuite, Fixture)
206 BOOST_AUTO_TEST_CASE(NotRunningServer)
210 VsmClient client = vsm_client_create();
211 VsmStatus status = vsm_connect(client);
212 BOOST_CHECK_EQUAL(VSMCLIENT_IO_ERROR, status);
213 vsm_client_free(client);
216 BOOST_AUTO_TEST_CASE(GetZoneIds)
218 VsmClient client = vsm_client_create();
219 VsmStatus status = vsm_connect(client);
220 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
221 VsmArrayString values;
222 status = vsm_get_zone_ids(client, &values);
223 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
224 BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_ZONES.size() + 1u),
225 EXPECTED_ZONES.size());
227 std::set<std::string> zones;
228 convertArrayToSet(values, zones);
230 for (const auto& zone : zones) {
231 BOOST_CHECK(EXPECTED_ZONES.find(zone) != EXPECTED_ZONES.cend());
233 vsm_array_string_free(values);
234 vsm_client_free(client);
237 BOOST_AUTO_TEST_CASE(GetActiveZoneId)
239 VsmClient client = vsm_client_create();
240 VsmStatus status = vsm_connect(client);
241 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
243 status = vsm_get_active_zone_id(client, &zone);
244 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
246 BOOST_CHECK_EQUAL(zone, cm->getRunningForegroundZoneId());
248 vsm_string_free(zone);
249 vsm_client_free(client);
252 BOOST_AUTO_TEST_CASE(GetZoneRootPath)
254 const std::string zoneId = "zone1";
256 VsmClient client = vsm_client_create();
257 VsmStatus status = vsm_connect(client);
258 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
260 status = vsm_get_zone_rootpath(client, zoneId.c_str(), &rootpath);
261 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
263 BOOST_CHECK_EQUAL(rootpath, "/tmp/ut-zones/" + zoneId + "/rootfs");
265 vsm_string_free(rootpath);
266 vsm_client_free(client);
269 BOOST_AUTO_TEST_CASE(LookupZoneById)
271 const std::string activeZoneId = "zone1";
273 VsmClient client = vsm_client_create();
274 VsmStatus status = vsm_connect(client);
275 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
277 status = vsm_lookup_zone_by_id(client, activeZoneId.c_str(), &info);
278 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
280 BOOST_CHECK_EQUAL(info->id, activeZoneId);
281 BOOST_CHECK_EQUAL(info->state, RUNNING);
282 BOOST_CHECK_EQUAL(info->terminal, -1);
283 BOOST_CHECK_EQUAL(info->rootfs_path, "/tmp/ut-zones/" + activeZoneId + "/rootfs");
286 vsm_client_free(client);
289 BOOST_AUTO_TEST_CASE(SetActiveZone)
291 const std::string newActiveZoneId = "zone2";
293 BOOST_REQUIRE_NE(newActiveZoneId, cm->getRunningForegroundZoneId());
295 VsmClient client = vsm_client_create();
296 VsmStatus status = vsm_connect(client);
297 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
298 status = vsm_set_active_zone(client, newActiveZoneId.c_str());
299 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
300 BOOST_CHECK_EQUAL(newActiveZoneId, cm->getRunningForegroundZoneId());
301 vsm_client_free(client);
304 BOOST_AUTO_TEST_CASE(CreateZone)
306 const std::string newActiveZoneId = "";
308 VsmClient client = vsm_client_create();
309 VsmStatus status = vsm_connect(client);
310 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
311 status = vsm_create_zone(client, newActiveZoneId.c_str(), NULL);
312 BOOST_REQUIRE_EQUAL(VSMCLIENT_CUSTOM_ERROR, status);
313 vsm_client_free(client);
316 BOOST_AUTO_TEST_CASE(StartShutdownZone)
318 const std::string newActiveZoneId = "zone1";
320 VsmClient client = vsm_client_create();
321 VsmStatus status = vsm_connect(client);
322 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
323 status = vsm_shutdown_zone(client, newActiveZoneId.c_str());
324 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
325 status = vsm_start_zone(client, newActiveZoneId.c_str());
326 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
327 vsm_client_free(client);
330 BOOST_AUTO_TEST_CASE(LockUnlockZone)
332 const std::string newActiveZoneId = "zone2";
334 VsmClient client = vsm_client_create();
335 VsmStatus status = vsm_connect(client);
336 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
337 status = vsm_lock_zone(client, newActiveZoneId.c_str());
338 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
339 status = vsm_unlock_zone(client, newActiveZoneId.c_str());
340 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
341 vsm_client_free(client);
344 #ifdef ZONE_CONNECTION
345 BOOST_AUTO_TEST_CASE(FileMoveRequest)
347 const std::string path = "/tmp/fake_path";
348 const std::string secondZone = "fake_zone";
350 VsmClient client = vsm_client_create();
351 VsmStatus status = vsm_connect(client);
352 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
353 status = vsm_file_move_request(client, secondZone.c_str(), path.c_str());
354 BOOST_REQUIRE_EQUAL(VSMCLIENT_CUSTOM_ERROR, status);
355 BOOST_REQUIRE_EQUAL(api::FILE_MOVE_DESTINATION_NOT_FOUND,
356 vsm_get_status_message(client));
357 vsm_client_free(client);
360 BOOST_AUTO_TEST_CASE(Notification)
362 const std::string MSG_CONTENT = "msg";
363 const std::string MSG_APP = "app";
365 struct CallbackData {
366 Latch signalReceivedLatch;
367 std::vector< std::tuple<std::string, std::string, std::string> > receivedSignalMsg;
370 auto callback = [](const char* zone,
371 const char* application,
374 CallbackData& callbackData = *reinterpret_cast<CallbackData*>(data);
375 callbackData.receivedSignalMsg.push_back(std::make_tuple(zone, application, message));
376 callbackData.signalReceivedLatch.set();
379 CallbackData callbackData;
380 std::map<std::string, VsmClient> clients;
381 for (const auto& it : EXPECTED_ZONES) {
382 VsmClient client = vsm_client_create();
383 VsmStatus status = vsm_connect_custom(client, it.c_str());
384 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
385 clients[it.first] = client;
387 for (auto& client : clients) {
388 VsmStatus status = vsm_add_notification_callback(client.second,
392 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
394 for (auto& client : clients) {
395 VsmStatus status = vsm_notify_active_zone(client.second,
397 MSG_CONTENT.c_str());
398 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
401 BOOST_CHECK(callbackData.signalReceivedLatch.waitForN(clients.size() - 1u, EVENT_TIMEOUT));
402 BOOST_CHECK(callbackData.signalReceivedLatch.empty());
404 for (const auto& msg : callbackData.receivedSignalMsg) {
405 BOOST_CHECK(clients.count(std::get<0>(msg)) > 0);
406 BOOST_CHECK_EQUAL(std::get<1>(msg), MSG_APP);
407 BOOST_CHECK_EQUAL(std::get<2>(msg), MSG_CONTENT);
410 for (auto& client : clients) {
411 vsm_client_free(client.second);
416 BOOST_AUTO_TEST_CASE(GetZoneIdByPidTestSingle)
418 VsmClient client = vsm_client_create();
420 VsmStatus status = vsm_lookup_zone_by_pid(client, 1, &zone);
421 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
423 BOOST_CHECK_EQUAL(zone, std::string("host"));
425 vsm_string_free(zone);
426 vsm_client_free(client);
429 BOOST_AUTO_TEST_CASE(GetZoneIdByPidTestMultiple)
431 std::set<std::string> ids;
433 VsmClient client = vsm_client_create();
434 for (int n = 0; n < 100000; ++n) {
436 VsmStatus status = vsm_lookup_zone_by_pid(client, n, &zone);
437 if (status == VSMCLIENT_SUCCESS) {
439 vsm_string_free(zone);
441 BOOST_WARN_MESSAGE(status == VSMCLIENT_INVALID_ARGUMENT, vsm_get_status_message(client));
444 vsm_client_free(client);
446 BOOST_CHECK(ids.count("host") == 1);
448 for (const auto& dbus : EXPECTED_ZONES) {
449 BOOST_CHECK(ids.count(dbus) == 1);
453 BOOST_AUTO_TEST_CASE(GrantRevoke)
455 const std::string zoneId = "zone2";
456 const std::string dev = "tty3";
458 VsmClient client = vsm_client_create();
459 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_connect(client));
461 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_grant_device(client, zoneId.c_str(), dev.c_str(), 0));
462 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_revoke_device(client, zoneId.c_str(), dev.c_str()));
464 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_lock_zone(client, zoneId.c_str()));
465 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_grant_device(client, zoneId.c_str(), dev.c_str(), 0));
466 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_unlock_zone(client, zoneId.c_str()));
468 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_shutdown_zone(client, zoneId.c_str()));
469 BOOST_CHECK_EQUAL(VSMCLIENT_CUSTOM_ERROR, vsm_grant_device(client, zoneId.c_str(), dev.c_str(), 0));
470 BOOST_CHECK_EQUAL(VSMCLIENT_CUSTOM_ERROR, vsm_revoke_device(client, zoneId.c_str(), dev.c_str()));
472 vsm_client_free(client);
475 BOOST_AUTO_TEST_CASE(Provision)
477 VsmClient client = vsm_client_create();
478 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_connect(client));
479 const std::string zone = cm->getRunningForegroundZoneId();
480 VsmArrayString declarations;
481 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_list_declarations(client, zone.c_str(), &declarations));
482 BOOST_REQUIRE(declarations != NULL && declarations[0] == NULL);
483 vsm_array_string_free(declarations);
484 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_declare_link(client, "/tmp/fake", zone.c_str(), "/tmp/fake/"));
485 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_list_declarations(client, zone.c_str(), &declarations));
486 BOOST_REQUIRE(declarations != NULL && declarations[0] != NULL && declarations[1] == NULL);
487 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_remove_declaration(client, zone.c_str(), declarations[0]));
488 vsm_array_string_free(declarations);
489 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_list_declarations(client, zone.c_str(), &declarations));
490 BOOST_CHECK(declarations != NULL && declarations[0] == NULL);
491 vsm_array_string_free(declarations);
492 vsm_client_free(client);
495 BOOST_AUTO_TEST_CASE(ZoneGetNetdevs)
497 const std::string activeZoneId = "zone1";
499 VsmClient client = vsm_client_create();
500 VsmStatus status = vsm_connect(client);
501 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
502 VsmArrayString netdevs;
503 status = vsm_zone_get_netdevs(client, activeZoneId.c_str(), &netdevs);
504 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, status);
505 BOOST_REQUIRE(netdevs != NULL);
506 vsm_array_string_free(netdevs);
507 vsm_client_free(client);
510 BOOST_AUTO_TEST_CASE(DefaultDispatcher)
512 VsmClient client = vsm_client_create();
514 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
516 vsm_client_free(client);
519 BOOST_AUTO_TEST_CASE(SetDispatcher)
521 VsmClient client = vsm_client_create();
523 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_INTERNAL));
524 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
526 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_EXTERNAL));
528 SimpleEventLoop loop(client);
529 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
532 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_INTERNAL));
533 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
535 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_EXTERNAL));
537 SimpleEventLoop loop(client);
538 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
541 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_INTERNAL));
542 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
544 vsm_client_free(client);
547 BOOST_AUTO_TEST_CASE(GetPollFd)
549 VsmClient client1 = vsm_client_create();
550 VsmClient client2 = vsm_client_create();
552 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client1, VSMDISPATCHER_EXTERNAL));
553 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client2, VSMDISPATCHER_EXTERNAL));
555 AggragatedEventLoop loop;
556 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, loop.addEventSource(client1));
557 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, loop.addEventSource(client2));
559 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_connect(client1));
560 BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_connect(client2));
565 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_get_active_zone_id(client1, &zone));
566 vsm_string_free(zone);
568 BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_get_active_zone_id(client2, &zone));
569 vsm_string_free(zone);
571 // disconnect but not destroy
572 vsm_disconnect(client1);
573 vsm_disconnect(client2);
575 vsm_client_free(client1);
576 vsm_client_free(client2);
579 //TODO: We need createBridge from vasum::netdev
580 //BOOST_AUTO_TEST_CASE(CreateDestroyNetdev)
581 //BOOST_AUTO_TEST_CASE(LookupNetdev)
582 //BOOST_AUTO_TEST_CASE(GetSetDeleteIpAddr)
583 //BOOST_AUTO_TEST_CASE(NetdevUpDown)
587 BOOST_AUTO_TEST_SUITE_END()