| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "buffet/commands/dbus_command_dispatcher.h" |
| |
| #include <memory> |
| #include <string> |
| |
| #include <chromeos/dbus/exported_object_manager.h> |
| #include <dbus/mock_bus.h> |
| #include <dbus/mock_exported_object.h> |
| #include <dbus/object_manager.h> |
| #include <dbus/object_path.h> |
| #include <gtest/gtest.h> |
| |
| #include "buffet/commands/command_dictionary.h" |
| #include "buffet/commands/command_queue.h" |
| #include "buffet/commands/unittest_utils.h" |
| #include "buffet/dbus_constants.h" |
| |
| using buffet::unittests::CreateDictionaryValue; |
| using chromeos::dbus_utils::AsyncEventSequencer; |
| using testing::AnyNumber; |
| using testing::InSequence; |
| using testing::Invoke; |
| using testing::Return; |
| using testing::_; |
| |
| namespace buffet { |
| |
| namespace { |
| const char kCommandCategory[] = "test_category"; |
| |
| } // anonymous namespace |
| |
| class DBusCommandDispacherTest : public testing::Test { |
| public: |
| void SetUp() override { |
| command_queue_.SetNowForTest(base::Time::Max()); |
| |
| const dbus::ObjectPath kExportedObjectManagerPath("/test/om_path"); |
| std::string cmd_path = dbus_constants::kCommandServicePathPrefix; |
| cmd_path += "1"; |
| const dbus::ObjectPath kCmdObjPath(cmd_path); |
| |
| dbus::Bus::Options options; |
| options.bus_type = dbus::Bus::SYSTEM; |
| bus_ = new dbus::MockBus(options); |
| // By default, don't worry about threading assertions. |
| EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber()); |
| EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber()); |
| // Use a mock exported object manager. |
| mock_exported_object_manager_ = new dbus::MockExportedObject( |
| bus_.get(), kExportedObjectManagerPath); |
| EXPECT_CALL(*bus_, GetExportedObject(kExportedObjectManagerPath)) |
| .WillRepeatedly(Return(mock_exported_object_manager_.get())); |
| EXPECT_CALL(*mock_exported_object_manager_, |
| ExportMethod(_, _, _, _)).Times(AnyNumber()); |
| om_.reset(new chromeos::dbus_utils::ExportedObjectManager( |
| bus_.get(), kExportedObjectManagerPath)); |
| om_->RegisterAsync(AsyncEventSequencer::GetDefaultCompletionAction()); |
| command_dispatcher_.reset( |
| new DBusCommandDispacher(om_->GetBus(), om_.get())); |
| command_queue_.SetCommandDispachInterface(command_dispatcher_.get()); |
| // Use a mock exported object for command proxy. |
| mock_exported_command_proxy_ = new dbus::MockExportedObject( |
| bus_.get(), kCmdObjPath); |
| EXPECT_CALL(*bus_, GetExportedObject(kCmdObjPath)) |
| .WillRepeatedly(Return(mock_exported_command_proxy_.get())); |
| EXPECT_CALL(*mock_exported_command_proxy_, ExportMethod(_, _, _, _)) |
| .WillRepeatedly(Invoke(MockExportMethod)); |
| |
| auto json = CreateDictionaryValue(R"({ |
| 'base': { |
| 'reboot': { |
| 'parameters': {'delay': 'integer'}, |
| 'results': {} |
| }, |
| 'shutdown': { |
| 'parameters': {}, |
| 'results': {} |
| } |
| } |
| })"); |
| CHECK(dictionary_.LoadCommands(*json, kCommandCategory, nullptr, nullptr)) |
| << "Failed to load command dictionary"; |
| } |
| |
| void TearDown() override { |
| EXPECT_CALL(*mock_exported_object_manager_, Unregister()).Times(1); |
| om_.reset(); |
| bus_ = nullptr; |
| } |
| |
| static void MockExportMethod( |
| const std::string& interface_name, |
| const std::string& method_name, |
| dbus::ExportedObject::MethodCallCallback method_call_callback, |
| dbus::ExportedObject::OnExportedCallback on_exported_callback) { |
| on_exported_callback.Run(interface_name, method_name, true); |
| } |
| |
| |
| void AddNewCommand(const std::string& json, const std::string& id) { |
| auto command_instance = CommandInstance::FromJson( |
| CreateDictionaryValue(json.c_str()).get(), dictionary_, nullptr); |
| command_instance->SetID(id); |
| // Two interfaces are added - Command and Properties. |
| EXPECT_CALL(*mock_exported_object_manager_, SendSignal(_)).Times(2); |
| command_queue_.Add(std::move(command_instance)); |
| } |
| |
| DBusCommandProxy* FindProxy(CommandInstance* command_instance) { |
| CHECK_EQ(command_instance->proxies_.size(), 1U); |
| return static_cast<DBusCommandProxy*>(command_instance->proxies_[0].get()); |
| } |
| |
| void FinishCommand(DBusCommandProxy* proxy) { |
| proxy->Done(); |
| } |
| |
| void SetProgress(DBusCommandProxy* proxy, int progress) { |
| proxy->SetProgress(nullptr, progress); |
| } |
| |
| |
| scoped_refptr<dbus::MockBus> bus_; |
| scoped_refptr<dbus::MockExportedObject> mock_exported_object_manager_; |
| scoped_refptr<dbus::MockExportedObject> mock_exported_command_proxy_; |
| std::unique_ptr<chromeos::dbus_utils::ExportedObjectManager> om_; |
| CommandDictionary dictionary_; |
| CommandQueue command_queue_; |
| std::unique_ptr<DBusCommandDispacher> command_dispatcher_; |
| }; |
| |
| TEST_F(DBusCommandDispacherTest, Test_Command_Base_Shutdown) { |
| const std::string id = "id0000"; |
| AddNewCommand("{'name':'base.shutdown'}", id); |
| CommandInstance* command_instance = command_queue_.Find(id); |
| ASSERT_NE(nullptr, command_instance); |
| DBusCommandProxy* command_proxy = FindProxy(command_instance); |
| ASSERT_NE(nullptr, command_proxy); |
| EXPECT_EQ(CommandInstance::kStatusQueued, command_instance->GetStatus()); |
| |
| // Two properties are set, Progress = 50%, Status = "inProgress" |
| EXPECT_CALL(*mock_exported_command_proxy_, SendSignal(_)).Times(2); |
| SetProgress(command_proxy, 50); |
| EXPECT_EQ(CommandInstance::kStatusInProgress, command_instance->GetStatus()); |
| EXPECT_EQ(50, command_instance->GetProgress()); |
| |
| // Command must be removed from the queue and proxy destroyed after calling |
| // FinishCommand(). |
| // Two properties are set, Progress = 100%, Status = "done" |
| EXPECT_CALL(*mock_exported_command_proxy_, SendSignal(_)).Times(2); |
| // D-Bus command proxy is going away. |
| EXPECT_CALL(*mock_exported_command_proxy_, Unregister()).Times(1); |
| // Two interfaces are being removed on the D-Bus command object. |
| EXPECT_CALL(*mock_exported_object_manager_, SendSignal(_)).Times(2); |
| FinishCommand(command_proxy); |
| |
| EXPECT_EQ(nullptr, command_queue_.Find(id)); |
| } |
| |
| TEST_F(DBusCommandDispacherTest, Test_Command_Base_Reboot) { |
| const std::string id = "id0001"; |
| AddNewCommand(R"({ |
| 'name': 'base.reboot', |
| 'parameters': { |
| 'delay': 20 |
| } |
| })", id); |
| CommandInstance* command_instance = command_queue_.Find(id); |
| ASSERT_NE(nullptr, command_instance); |
| DBusCommandProxy* command_proxy = FindProxy(command_instance); |
| ASSERT_NE(nullptr, command_proxy); |
| EXPECT_EQ(CommandInstance::kStatusQueued, command_instance->GetStatus()); |
| |
| // Two properties are set, Progress = 50%, Status = "inProgress" |
| EXPECT_CALL(*mock_exported_command_proxy_, SendSignal(_)).Times(2); |
| SetProgress(command_proxy, 50); |
| EXPECT_EQ(CommandInstance::kStatusInProgress, command_instance->GetStatus()); |
| EXPECT_EQ(50, command_instance->GetProgress()); |
| |
| // Command must be removed from the queue and proxy destroyed after calling |
| // FinishCommand(). |
| // Two properties are set, Progress = 100%, Status = "done" |
| EXPECT_CALL(*mock_exported_command_proxy_, SendSignal(_)).Times(2); |
| // D-Bus command proxy is going away. |
| EXPECT_CALL(*mock_exported_command_proxy_, Unregister()).Times(1); |
| // Two interfaces are being removed on the D-Bus command object. |
| EXPECT_CALL(*mock_exported_object_manager_, SendSignal(_)).Times(2); |
| FinishCommand(command_proxy); |
| |
| EXPECT_EQ(nullptr, command_queue_.Find(id)); |
| } |
| |
| |
| } // namespace buffet |