2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Jan Olszak <j.olszak@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 Jan Olszak (j.olszak@samsung.com)
23 * @brief Unit tests of the ContainersManager class
29 #include "containers-manager.hpp"
30 #include "container-dbus-definitions.hpp"
31 #include "host-dbus-definitions.hpp"
32 #include "test-dbus-definitions.hpp"
33 // TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager
34 #include "fake-power-manager-dbus-definitions.hpp"
35 #include "exception.hpp"
37 #include "dbus/connection.hpp"
38 #include "dbus/exception.hpp"
39 #include "utils/glib-loop.hpp"
40 #include "config/exception.hpp"
41 #include "utils/latch.hpp"
42 #include "utils/fs.hpp"
43 #include "utils/img.hpp"
52 #include <condition_variable>
53 #include <boost/filesystem.hpp>
55 using namespace security_containers;
56 using namespace config;
57 using namespace security_containers::utils;
62 const std::string TEST_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/test-daemon.conf";
63 const std::string TEST_DBUS_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/test-dbus-daemon.conf";
64 const std::string BUGGY_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-daemon.conf";
65 const std::string BUGGY_FOREGROUND_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-foreground-daemon.conf";
66 const std::string BUGGY_DEFAULTID_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-default-daemon.conf";
67 const std::string TEST_CONTAINER_CONF_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/containers/";
68 const std::string TEST_CONTAINER_LIBVIRT_CONF_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/libvirt-config/";
69 const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/missing-daemon.conf";
70 const int EVENT_TIMEOUT = 5000;
71 const int TEST_DBUS_CONNECTION_CONTAINERS_COUNT = 3;
72 const std::string PREFIX_CONSOLE_NAME = "ut-containers-manager-console";
73 const std::string TEST_APP_NAME = "testapp";
74 const std::string TEST_MESSAGE = "testmessage";
75 const std::string FILE_CONTENT = "File content\n"
78 const std::string NON_EXISTANT_CONTAINER_ID = "NON_EXISTANT_CONTAINER_ID";
82 static const int HOST_ID = 0;
84 typedef std::function<void(const std::string& argument,
85 MethodResultBuilder::Pointer result
86 )> TestApiMethodCallback;
87 typedef std::function<void()> AddContainerResultCallback;
89 typedef std::map<std::string, std::string> Dbuses;
93 mClient(DbusConnection::create(acquireAddress())),
95 mPendingDisconnect(false)
99 void setName(const std::string& name)
101 mClient->setName(name,
102 std::bind(&DbusAccessory::onNameAcquired, this),
103 std::bind(&DbusAccessory::onDisconnect, this));
107 throw dbus::DbusOperationException("Could not acquire name.");
113 std::unique_lock<std::mutex> lock(mMutex);
114 mNameCondition.wait(lock, [this] {return mNameAcquired || mPendingDisconnect;});
115 return mNameAcquired;
118 void onNameAcquired()
120 std::unique_lock<std::mutex> lock(mMutex);
121 mNameAcquired = true;
122 mNameCondition.notify_one();
127 std::unique_lock<std::mutex> lock(mMutex);
128 mPendingDisconnect = true;
129 mNameCondition.notify_one();
132 void signalSubscribe(const DbusConnection::SignalCallback& callback)
134 mClient->signalSubscribe(callback, isHost() ? api::host::BUS_NAME : api::container::BUS_NAME);
137 void emitSignal(const std::string& objectPath,
138 const std::string& interface,
139 const std::string& name,
140 GVariant* parameters)
142 mClient->emitSignal(objectPath, interface, name, parameters);
145 void callMethodNotify()
147 GVariant* parameters = g_variant_new("(ss)", TEST_APP_NAME.c_str(), TEST_MESSAGE.c_str());
148 mClient->callMethod(api::container::BUS_NAME,
149 api::container::OBJECT_PATH,
150 api::container::INTERFACE,
151 api::container::METHOD_NOTIFY_ACTIVE_CONTAINER,
156 std::string callMethodMove(const std::string& dest, const std::string& path)
158 GVariant* parameters = g_variant_new("(ss)", dest.c_str(), path.c_str());
159 GVariantPtr result = mClient->callMethod(api::container::BUS_NAME,
160 api::container::OBJECT_PATH,
161 api::container::INTERFACE,
162 api::container::METHOD_FILE_MOVE_REQUEST,
166 const gchar* retcode = NULL;
167 g_variant_get(result.get(), "(&s)", &retcode);
168 return std::string(retcode);
171 void registerTestApiObject(const TestApiMethodCallback& callback)
173 auto handler = [callback](const std::string& objectPath,
174 const std::string& interface,
175 const std::string& methodName,
176 GVariant* parameters,
177 MethodResultBuilder::Pointer result) {
178 if (objectPath == testapi::OBJECT_PATH &&
179 interface == testapi::INTERFACE &&
180 methodName == testapi::METHOD) {
181 const gchar* argument = NULL;
182 g_variant_get(parameters, "(&s)", &argument);
184 callback(argument, result);
188 mClient->registerObject(testapi::OBJECT_PATH, testapi::DEFINITION, handler);
191 std::string testApiProxyCall(const std::string& target, const std::string& argument)
193 GVariant* parameters = g_variant_new("(s)", argument.c_str());
194 GVariantPtr result = proxyCall(target,
196 testapi::OBJECT_PATH,
200 const gchar* ret = NULL;
201 g_variant_get(result.get(), "(&s)", &ret);
206 GVariantPtr proxyCall(const std::string& target,
207 const std::string& busName,
208 const std::string& objectPath,
209 const std::string& interface,
210 const std::string& method,
211 GVariant* parameters)
213 GVariant* packedParameters = g_variant_new("(sssssv)",
220 GVariantPtr result = mClient->callMethod(isHost() ? api::host::BUS_NAME :
221 api::container::BUS_NAME,
222 isHost() ? api::host::OBJECT_PATH :
223 api::container::OBJECT_PATH,
224 isHost() ? api::host::INTERFACE :
225 api::container::INTERFACE,
226 api::METHOD_PROXY_CALL,
229 GVariant* unpackedResult = NULL;
230 g_variant_get(result.get(), "(v)", &unpackedResult);
231 return GVariantPtr(unpackedResult, g_variant_unref);
234 Dbuses callMethodGetContainerDbuses()
238 GVariantPtr result = mClient->callMethod(api::host::BUS_NAME,
239 api::host::OBJECT_PATH,
240 api::host::INTERFACE,
241 api::host::METHOD_GET_CONTAINER_DBUSES,
244 GVariant* array = NULL;
245 g_variant_get(result.get(), "(*)", &array);
246 dbus::GVariantPtr autounref(array, g_variant_unref);
247 size_t count = g_variant_n_children(array);
248 for (size_t n = 0; n < count; ++n) {
249 const char* containerId = NULL;
250 const char* dbusAddress = NULL;
251 g_variant_get_child(array, n, "{&s&s}", &containerId, &dbusAddress);
252 dbuses.insert(Dbuses::value_type(containerId, dbusAddress));
257 std::vector<std::string> callMethodGetContainerIds()
260 GVariantPtr result = mClient->callMethod(api::host::BUS_NAME,
261 api::host::OBJECT_PATH,
262 api::host::INTERFACE,
263 api::host::METHOD_GET_CONTAINER_ID_LIST,
267 GVariant* array = NULL;
268 g_variant_get(result.get(), "(*)", &array);
270 size_t arraySize = g_variant_n_children(array);
271 std::vector<std::string> containerIds;
272 for (size_t i = 0; i < arraySize; ++i) {
273 const char* id = NULL;
274 g_variant_get_child(array, i, "&s", &id);
275 containerIds.push_back(id);
278 g_variant_unref(array);
282 std::string callMethodGetActiveContainerId()
285 GVariantPtr result = mClient->callMethod(api::host::BUS_NAME,
286 api::host::OBJECT_PATH,
287 api::host::INTERFACE,
288 api::host::METHOD_GET_ACTIVE_CONTAINER_ID,
292 const char* containerId = NULL;
293 g_variant_get(result.get(), "(&s)", &containerId);
297 void callMethodSetActiveContainer(const std::string& id)
300 GVariant* parameters = g_variant_new("(s)", id.c_str());
301 GVariantPtr result = mClient->callMethod(api::host::BUS_NAME,
302 api::host::OBJECT_PATH,
303 api::host::INTERFACE,
304 api::host::METHOD_SET_ACTIVE_CONTAINER,
310 void callAsyncMethodAddContainer(const std::string& id,
311 const AddContainerResultCallback& result)
313 auto asyncResult = [result](dbus::AsyncMethodCallResult& asyncMethodCallResult) {
314 BOOST_CHECK(g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT));
319 GVariant* parameters = g_variant_new("(s)", id.c_str());
320 mClient->callMethodAsync(api::host::BUS_NAME,
321 api::host::OBJECT_PATH,
322 api::host::INTERFACE,
323 api::host::METHOD_ADD_CONTAINER,
331 DbusConnection::Pointer mClient;
333 bool mPendingDisconnect;
335 std::condition_variable mNameCondition;
337 bool isHost() const {
338 return mId == HOST_ID;
341 std::string acquireAddress() const
344 return "unix:path=/var/run/dbus/system_bus_socket";
346 return "unix:path=/tmp/ut-containers-manager/console" + std::to_string(mId) +
347 "-dbus/dbus/system_bus_socket";
351 std::function<bool(const std::exception&)> expectedMessage(const std::string& message) {
352 return [=](const std::exception& e) {
353 return e.what() == message;
357 class FileCleanerRAII {
359 FileCleanerRAII(const std::vector<std::string>& filePathsToClean):
360 mFilePathsToClean(filePathsToClean)
365 namespace fs = boost::filesystem;
366 for (const auto& file : mFilePathsToClean) {
375 const std::vector<std::string> mFilePathsToClean;
379 security_containers::utils::ScopedGlibLoop mLoop;
385 BOOST_FIXTURE_TEST_SUITE(ContainersManagerSuite, Fixture)
387 BOOST_AUTO_TEST_CASE(ConstructorDestructorTest)
389 std::unique_ptr<ContainersManager> cm;
390 BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_CONFIG_PATH)));
391 BOOST_REQUIRE_NO_THROW(cm.reset());
394 BOOST_AUTO_TEST_CASE(BuggyConfigTest)
396 BOOST_REQUIRE_THROW(ContainersManager cm(BUGGY_CONFIG_PATH), ConfigException);
399 BOOST_AUTO_TEST_CASE(MissingConfigTest)
401 BOOST_REQUIRE_THROW(ContainersManager cm(MISSING_CONFIG_PATH), ConfigException);
404 BOOST_AUTO_TEST_CASE(StartAllTest)
406 ContainersManager cm(TEST_CONFIG_PATH);
407 BOOST_REQUIRE_NO_THROW(cm.startAll());
408 BOOST_CHECK(cm.getRunningForegroundContainerId() == "ut-containers-manager-console1");
411 BOOST_AUTO_TEST_CASE(BuggyForegroundTest)
413 ContainersManager cm(BUGGY_FOREGROUND_CONFIG_PATH);
414 BOOST_REQUIRE_NO_THROW(cm.startAll());
415 BOOST_CHECK(cm.getRunningForegroundContainerId() == "ut-containers-manager-console2");
418 BOOST_AUTO_TEST_CASE(BuggyDefaultTest)
420 BOOST_REQUIRE_THROW(ContainersManager cm(BUGGY_DEFAULTID_CONFIG_PATH),
421 ContainerOperationException);
424 BOOST_AUTO_TEST_CASE(StopAllTest)
426 ContainersManager cm(TEST_CONFIG_PATH);
427 BOOST_REQUIRE_NO_THROW(cm.startAll());
428 BOOST_REQUIRE_NO_THROW(cm.stopAll());
429 BOOST_CHECK(cm.getRunningForegroundContainerId().empty());
432 BOOST_AUTO_TEST_CASE(DetachOnExitTest)
435 ContainersManager cm(TEST_CONFIG_PATH);
436 BOOST_REQUIRE_NO_THROW(cm.startAll());
437 cm.setContainersDetachOnExit();
440 ContainersManager cm(TEST_CONFIG_PATH);
441 BOOST_REQUIRE_NO_THROW(cm.startAll());
445 BOOST_AUTO_TEST_CASE(FocusTest)
447 ContainersManager cm(TEST_CONFIG_PATH);
448 BOOST_REQUIRE_NO_THROW(cm.startAll());
449 BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console2"));
450 BOOST_CHECK(cm.getRunningForegroundContainerId() == "ut-containers-manager-console2");
451 BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console1"));
452 BOOST_CHECK(cm.getRunningForegroundContainerId() == "ut-containers-manager-console1");
453 BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console3"));
454 BOOST_CHECK(cm.getRunningForegroundContainerId() == "ut-containers-manager-console3");
457 BOOST_AUTO_TEST_CASE(NotifyActiveContainerTest)
459 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
462 Latch signalReceivedLatch;
463 std::map<int, std::vector<std::string>> signalReceivedSourcesMap;
465 std::map<int, std::unique_ptr<DbusAccessory>> dbuses;
466 for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) {
467 dbuses[i] = std::unique_ptr<DbusAccessory>(new DbusAccessory(i));
470 auto handler = [](Latch& latch,
471 std::vector<std::string>& receivedSignalSources,
472 const std::string& /*senderBusName*/,
473 const std::string& objectPath,
474 const std::string& interface,
475 const std::string& signalName,
476 GVariant* parameters)
478 if (objectPath == api::container::OBJECT_PATH &&
479 interface == api::container::INTERFACE &&
480 signalName == api::container::SIGNAL_NOTIFICATION &&
481 g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) {
483 const gchar* container = NULL;
484 const gchar* application = NULL;
485 const gchar* message = NULL;
486 g_variant_get(parameters, "(&s&s&s)", &container, &application, &message);
487 receivedSignalSources.push_back(container);
488 if (application == TEST_APP_NAME && message == TEST_MESSAGE) {
494 using namespace std::placeholders;
495 for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) {
496 dbuses[i]->signalSubscribe(std::bind(handler,
497 std::ref(signalReceivedLatch),
498 std::ref(signalReceivedSourcesMap[i]),
499 _1, _2, _3, _4, _5));
501 for (auto& dbus : dbuses) {
502 dbus.second->callMethodNotify();
505 BOOST_CHECK(signalReceivedLatch.waitForN(dbuses.size() - 1, EVENT_TIMEOUT));
506 BOOST_CHECK(signalReceivedLatch.empty());
508 //check if there are no signals that was received more than once
509 for (const auto& source : signalReceivedSourcesMap[1]) {
510 BOOST_CHECK_EQUAL(std::count(signalReceivedSourcesMap[1].begin(),
511 signalReceivedSourcesMap[1].end(),
514 //check if all signals was received by active container
515 BOOST_CHECK_EQUAL(signalReceivedSourcesMap[1].size(), dbuses.size() - 1);
516 //check if no signals was received by inactive container
517 for (size_t i = 2; i <= dbuses.size(); ++i) {
518 BOOST_CHECK(signalReceivedSourcesMap[i].empty());
524 BOOST_AUTO_TEST_CASE(DisplayOffTest)
526 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
527 BOOST_REQUIRE_NO_THROW(cm.startAll());
529 std::vector<std::unique_ptr<DbusAccessory>> clients;
530 for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) {
531 clients.push_back(std::unique_ptr<DbusAccessory>(new DbusAccessory(i)));
534 for (auto& client : clients) {
535 client->setName(fake_power_manager_api::BUS_NAME);
539 std::unique_lock<std::mutex> Lock(Mutex);
540 std::condition_variable Condition;
541 auto cond = [&cm]() -> bool {
542 return cm.getRunningForegroundContainerId() == "ut-containers-manager-console1-dbus";
545 for (auto& client : clients) {
546 // TEST SWITCHING TO DEFAULT CONTAINER
547 // focus non-default container
548 BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console3-dbus"));
550 // emit signal from dbus connection
551 BOOST_REQUIRE_NO_THROW(client->emitSignal(fake_power_manager_api::OBJECT_PATH,
552 fake_power_manager_api::INTERFACE,
553 fake_power_manager_api::SIGNAL_DISPLAY_OFF,
556 // check if default container has focus
557 BOOST_CHECK(Condition.wait_for(Lock, std::chrono::milliseconds(EVENT_TIMEOUT), cond));
561 BOOST_AUTO_TEST_CASE(MoveFileTest)
563 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
566 Latch notificationLatch;
567 std::string notificationSource;
568 std::string notificationPath;
569 std::string notificationRetcode;
571 std::map<int, std::unique_ptr<DbusAccessory>> dbuses;
572 for (int i = 1; i <= 2; ++i) {
573 dbuses[i] = std::unique_ptr<DbusAccessory>(new DbusAccessory(i));
576 auto handler = [&](const std::string& /*senderBusName*/,
577 const std::string& objectPath,
578 const std::string& interface,
579 const std::string& signalName,
580 GVariant* parameters)
582 if (objectPath == api::container::OBJECT_PATH &&
583 interface == api::container::INTERFACE &&
584 signalName == api::container::SIGNAL_NOTIFICATION &&
585 g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) {
587 const gchar* source = NULL;
588 const gchar* path = NULL;
589 const gchar* retcode = NULL;
590 g_variant_get(parameters, "(&s&s&s)", &source, &path, &retcode);
592 notificationSource = source;
593 notificationPath = path;
594 notificationRetcode = retcode;
595 notificationLatch.set();
599 // subscribe the second (destination) container for notifications
600 dbuses.at(2)->signalSubscribe(handler);
602 const std::string TMP = "/tmp";
603 const std::string NO_PATH = "path_doesnt_matter_here";
604 const std::string BUGGY_PATH = TMP + "/this_file_does_not_exist";
605 const std::string BUGGY_CONTAINER = "this-container-does-not-exist";
606 const std::string CONTAINER1 = "ut-containers-manager-console1-dbus";
607 const std::string CONTAINER2 = "ut-containers-manager-console2-dbus";
608 const std::string CONTAINER1PATH = TMP + "/" + CONTAINER1 + TMP;
609 const std::string CONTAINER2PATH = TMP + "/" + CONTAINER2 + TMP;
611 // sending to a non existing container
612 BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(BUGGY_CONTAINER, NO_PATH),
613 api::container::FILE_MOVE_DESTINATION_NOT_FOUND);
614 BOOST_CHECK(notificationLatch.empty());
617 BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER1, NO_PATH),
618 api::container::FILE_MOVE_WRONG_DESTINATION);
619 BOOST_CHECK(notificationLatch.empty());
621 // no permission to send
622 BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER2, "/etc/secret1"),
623 api::container::FILE_MOVE_NO_PERMISSIONS_SEND);
624 BOOST_CHECK(notificationLatch.empty());
626 // no permission to receive
627 BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER2, "/etc/secret2"),
628 api::container::FILE_MOVE_NO_PERMISSIONS_RECEIVE);
629 BOOST_CHECK(notificationLatch.empty());
632 BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER2, BUGGY_PATH),
633 api::container::FILE_MOVE_FAILED);
634 BOOST_CHECK(notificationLatch.empty());
636 // a working scenario
637 namespace fs = boost::filesystem;
638 boost::system::error_code ec;
639 fs::remove_all(CONTAINER1PATH, ec);
640 fs::remove_all(CONTAINER2PATH, ec);
641 BOOST_REQUIRE(fs::create_directories(CONTAINER1PATH, ec));
642 BOOST_REQUIRE(fs::create_directories(CONTAINER2PATH, ec));
643 BOOST_REQUIRE(utils::saveFileContent(CONTAINER1PATH + "/file", FILE_CONTENT));
645 BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER2, TMP + "/file"),
646 api::container::FILE_MOVE_SUCCEEDED);
647 BOOST_CHECK(notificationLatch.wait(EVENT_TIMEOUT));
648 BOOST_CHECK(notificationLatch.empty());
649 BOOST_CHECK_EQUAL(notificationSource, CONTAINER1);
650 BOOST_CHECK_EQUAL(notificationPath, TMP + "/file");
651 BOOST_CHECK_EQUAL(notificationRetcode, api::container::FILE_MOVE_SUCCEEDED);
652 BOOST_CHECK(!fs::exists(CONTAINER1PATH + "/file"));
653 BOOST_CHECK_EQUAL(utils::readFileContent(CONTAINER2PATH + "/file"), FILE_CONTENT);
655 fs::remove_all(CONTAINER1PATH, ec);
656 fs::remove_all(CONTAINER2PATH, ec);
659 BOOST_AUTO_TEST_CASE(AllowSwitchToDefaultTest)
661 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
662 BOOST_REQUIRE_NO_THROW(cm.startAll());
664 std::vector<std::unique_ptr<DbusAccessory>> clients;
665 for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) {
666 clients.push_back(std::unique_ptr<DbusAccessory>(new DbusAccessory(i)));
669 for (auto& client : clients) {
670 client->setName(fake_power_manager_api::BUS_NAME);
673 std::mutex condMutex;
674 std::unique_lock<std::mutex> condLock(condMutex);
675 std::condition_variable condition;
676 auto cond = [&cm]() -> bool {
677 return cm.getRunningForegroundContainerId() == "ut-containers-manager-console1-dbus";
680 for (auto& client : clients) {
681 // focus non-default container with allowed switching
682 BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console3-dbus"));
684 // emit signal from dbus connection
685 BOOST_REQUIRE_NO_THROW(client->emitSignal(fake_power_manager_api::OBJECT_PATH,
686 fake_power_manager_api::INTERFACE,
687 fake_power_manager_api::SIGNAL_DISPLAY_OFF,
690 // check if default container has focus
691 BOOST_CHECK(condition.wait_for(condLock, std::chrono::milliseconds(EVENT_TIMEOUT), cond));
693 // focus non-default container with disabled switching
694 BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console2-dbus"));
696 // emit signal from dbus connection
697 BOOST_REQUIRE_NO_THROW(client->emitSignal(fake_power_manager_api::OBJECT_PATH,
698 fake_power_manager_api::INTERFACE,
699 fake_power_manager_api::SIGNAL_DISPLAY_OFF,
702 // now default container should not be focused
703 BOOST_CHECK(!condition.wait_for(condLock, std::chrono::milliseconds(EVENT_TIMEOUT), cond));
707 BOOST_AUTO_TEST_CASE(ProxyCallTest)
709 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
712 std::map<int, std::unique_ptr<DbusAccessory>> dbuses;
713 for (int i = 0; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) {
714 dbuses[i] = std::unique_ptr<DbusAccessory>(new DbusAccessory(i));
717 for (auto& dbus : dbuses) {
718 dbus.second->setName(testapi::BUS_NAME);
720 const int id = dbus.first;
721 auto handler = [id](const std::string& argument, MethodResultBuilder::Pointer result) {
722 if (argument.empty()) {
723 result->setError("org.tizen.containers.Error.Test", "Test error");
725 std::string ret = "reply from " + std::to_string(id) + ": " + argument;
726 result->set(g_variant_new("(s)", ret.c_str()));
729 dbus.second->registerTestApiObject(handler);
732 // host -> container2
733 BOOST_CHECK_EQUAL("reply from 2: param1",
734 dbuses.at(0)->testApiProxyCall("ut-containers-manager-console2-dbus",
738 BOOST_CHECK_EQUAL("reply from 0: param2",
739 dbuses.at(0)->testApiProxyCall("host",
742 // container1 -> host
743 BOOST_CHECK_EQUAL("reply from 0: param3",
744 dbuses.at(1)->testApiProxyCall("host",
747 // container1 -> container2
748 BOOST_CHECK_EQUAL("reply from 2: param4",
749 dbuses.at(1)->testApiProxyCall("ut-containers-manager-console2-dbus",
752 // container2 -> container2
753 BOOST_CHECK_EQUAL("reply from 2: param5",
754 dbuses.at(2)->testApiProxyCall("ut-containers-manager-console2-dbus",
758 BOOST_CHECK_EXCEPTION(dbuses.at(0)->testApiProxyCall("unknown", "param"),
760 expectedMessage("Unknown proxy call target"));
763 BOOST_CHECK_EXCEPTION(dbuses.at(0)->testApiProxyCall("host", ""),
765 expectedMessage("Test error"));
768 BOOST_CHECK_EXCEPTION(dbuses.at(0)->proxyCall("host",
773 g_variant_new("(s)", "arg")),
775 expectedMessage("Proxy call forbidden"));
779 const DbusAccessory::Dbuses EXPECTED_DBUSES_NO_DBUS = {
780 {"ut-containers-manager-console1", ""},
781 {"ut-containers-manager-console2", ""},
782 {"ut-containers-manager-console3", ""}};
784 const DbusAccessory::Dbuses EXPECTED_DBUSES_STOPPED = {
785 {"ut-containers-manager-console1-dbus", ""},
786 {"ut-containers-manager-console2-dbus", ""},
787 {"ut-containers-manager-console3-dbus", ""}};
789 const DbusAccessory::Dbuses EXPECTED_DBUSES_STARTED = {
790 {"ut-containers-manager-console1-dbus",
791 "unix:path=/tmp/ut-containers-manager/console1-dbus/dbus/system_bus_socket"},
792 {"ut-containers-manager-console2-dbus",
793 "unix:path=/tmp/ut-containers-manager/console2-dbus/dbus/system_bus_socket"},
794 {"ut-containers-manager-console3-dbus",
795 "unix:path=/tmp/ut-containers-manager/console3-dbus/dbus/system_bus_socket"}};
798 BOOST_AUTO_TEST_CASE(GetContainerDbusesTest)
800 DbusAccessory host(DbusAccessory::HOST_ID);
801 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
803 BOOST_CHECK(EXPECTED_DBUSES_STOPPED == host.callMethodGetContainerDbuses());
805 BOOST_CHECK(EXPECTED_DBUSES_STARTED == host.callMethodGetContainerDbuses());
807 BOOST_CHECK(EXPECTED_DBUSES_STOPPED == host.callMethodGetContainerDbuses());
810 BOOST_AUTO_TEST_CASE(GetContainerDbusesNoDbusTest)
812 DbusAccessory host(DbusAccessory::HOST_ID);
813 ContainersManager cm(TEST_CONFIG_PATH);
814 BOOST_CHECK(EXPECTED_DBUSES_NO_DBUS == host.callMethodGetContainerDbuses());
816 BOOST_CHECK(EXPECTED_DBUSES_NO_DBUS == host.callMethodGetContainerDbuses());
818 BOOST_CHECK(EXPECTED_DBUSES_NO_DBUS == host.callMethodGetContainerDbuses());
821 BOOST_AUTO_TEST_CASE(ContainerDbusesSignalsTest)
824 DbusAccessory::Dbuses collectedDbuses;
826 DbusAccessory host(DbusAccessory::HOST_ID);
828 auto onSignal = [&] (const std::string& /*senderBusName*/,
829 const std::string& objectPath,
830 const std::string& interface,
831 const std::string& signalName,
832 GVariant* parameters) {
833 if (objectPath == api::host::OBJECT_PATH &&
834 interface == api::host::INTERFACE &&
835 signalName == api::host::SIGNAL_CONTAINER_DBUS_STATE) {
837 const gchar* containerId = NULL;
838 const gchar* dbusAddress = NULL;
839 g_variant_get(parameters, "(&s&s)", &containerId, &dbusAddress);
841 collectedDbuses.insert(DbusAccessory::Dbuses::value_type(containerId, dbusAddress));
846 host.signalSubscribe(onSignal);
849 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
851 BOOST_CHECK(signalLatch.empty());
852 BOOST_CHECK(collectedDbuses.empty());
856 BOOST_CHECK(signalLatch.waitForN(TEST_DBUS_CONNECTION_CONTAINERS_COUNT, EVENT_TIMEOUT));
857 BOOST_CHECK(signalLatch.empty());
858 BOOST_CHECK(EXPECTED_DBUSES_STARTED == collectedDbuses);
859 collectedDbuses.clear();
862 BOOST_CHECK(signalLatch.waitForN(TEST_DBUS_CONNECTION_CONTAINERS_COUNT, EVENT_TIMEOUT));
863 BOOST_CHECK(signalLatch.empty());
864 BOOST_CHECK(EXPECTED_DBUSES_STOPPED == collectedDbuses);
868 BOOST_AUTO_TEST_CASE(GetContainerIdsTest)
870 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
872 DbusAccessory dbus(DbusAccessory::HOST_ID);
874 std::vector<std::string> containerIds = {"ut-containers-manager-console1-dbus",
875 "ut-containers-manager-console2-dbus",
876 "ut-containers-manager-console3-dbus"};
877 std::vector<std::string> returnedIds = dbus.callMethodGetContainerIds();
879 BOOST_CHECK(std::is_permutation(returnedIds.begin(),
881 containerIds.begin()));
884 BOOST_AUTO_TEST_CASE(GetActiveContainerIdTest)
886 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
889 DbusAccessory dbus(DbusAccessory::HOST_ID);
891 std::vector<std::string> containerIds = {"ut-containers-manager-console1-dbus",
892 "ut-containers-manager-console2-dbus",
893 "ut-containers-manager-console3-dbus"};
895 for (std::string& containerId: containerIds){
896 cm.focus(containerId);
897 BOOST_CHECK(dbus.callMethodGetActiveContainerId() == containerId);
901 BOOST_CHECK(dbus.callMethodGetActiveContainerId() == "");
904 BOOST_AUTO_TEST_CASE(SetActiveContainerTest)
906 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
909 DbusAccessory dbus(DbusAccessory::HOST_ID);
911 std::vector<std::string> containerIds = {"ut-containers-manager-console1-dbus",
912 "ut-containers-manager-console2-dbus",
913 "ut-containers-manager-console3-dbus"};
915 for (std::string& containerId: containerIds){
916 BOOST_REQUIRE_NO_THROW(dbus.callMethodSetActiveContainer(containerId));
917 BOOST_CHECK(dbus.callMethodGetActiveContainerId() == containerId);
920 BOOST_REQUIRE_THROW(dbus.callMethodSetActiveContainer(NON_EXISTANT_CONTAINER_ID),
924 BOOST_REQUIRE_THROW(dbus.callMethodSetActiveContainer("ut-containers-manager-console1-dbus"),
928 BOOST_AUTO_TEST_CASE(AddContainerTest)
930 const std::string newContainerId = "test1234";
931 const std::vector<std::string> newContainerConfigs = {
932 TEST_CONTAINER_CONF_PATH + newContainerId + ".conf",
933 TEST_CONTAINER_LIBVIRT_CONF_PATH + newContainerId + ".xml",
934 TEST_CONTAINER_LIBVIRT_CONF_PATH + newContainerId + "-network.xml",
935 TEST_CONTAINER_LIBVIRT_CONF_PATH + newContainerId + "-nwfilter.xml",
937 FileCleanerRAII cleaner(newContainerConfigs);
939 ContainersManager cm(TEST_DBUS_CONFIG_PATH);
943 auto resultCallback = [&]() {
947 DbusAccessory dbus(DbusAccessory::HOST_ID);
949 // create new container
950 dbus.callAsyncMethodAddContainer(newContainerId, resultCallback);
951 callDone.wait(EVENT_TIMEOUT);
953 // focus new container
954 BOOST_REQUIRE_NO_THROW(cm.focus(newContainerId));
955 BOOST_CHECK(cm.getRunningForegroundContainerId() == newContainerId);
958 BOOST_AUTO_TEST_SUITE_END()