blob: 34d9f1d8a060be80975f54b5422b759d34db5b09 [file] [log] [blame]
Alex Vakulenko4866ac92014-08-20 12:53:33 -07001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <functional>
6#include <memory>
7
8#include <dbus/mock_bus.h>
9#include <dbus/mock_exported_object.h>
10#include <dbus/property.h>
11#include <chromeos/dbus/dbus_object.h>
12#include <gtest/gtest.h>
13
14#include "buffet/commands/command_dictionary.h"
15#include "buffet/commands/command_instance.h"
16#include "buffet/commands/dbus_command_proxy.h"
17#include "buffet/commands/unittest_utils.h"
Alex Vakulenko89d9d5e2014-09-12 10:27:23 -070018#include "buffet/libbuffet/dbus_constants.h"
Alex Vakulenko4866ac92014-08-20 12:53:33 -070019
20using ::testing::AnyNumber;
21using ::testing::Return;
22using ::testing::Invoke;
23using ::testing::_;
24
Alex Vakulenko4866ac92014-08-20 12:53:33 -070025using buffet::unittests::CreateDictionaryValue;
Alex Vakulenkof6b38712014-09-03 16:23:38 -070026using chromeos::dbus_utils::AsyncEventSequencer;
Alex Vakulenkof6b38712014-09-03 16:23:38 -070027using chromeos::dbus_utils::ExportedObjectManager;
Alex Vakulenko576c9792014-09-22 16:49:45 -070028using chromeos::VariantDictionary;
Alex Vakulenko4866ac92014-08-20 12:53:33 -070029
30namespace buffet {
31
32namespace {
33
34const char kTestCommandCategoty[] = "test_command_category";
35const char kTestCommandId[] = "cmd_1";
36
Alex Vakulenko4866ac92014-08-20 12:53:33 -070037} // namespace
38
39class DBusCommandProxyTest : public ::testing::Test {
40 public:
41 void SetUp() override {
42 // Set up a mock DBus bus object.
43 dbus::Bus::Options options;
44 options.bus_type = dbus::Bus::SYSTEM;
45 bus_ = new dbus::MockBus(options);
46 // By default, don't worry about threading assertions.
47 EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
48 EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
49
50 // Command instance.
51 auto json = CreateDictionaryValue(R"({
52 'robot': {
53 'jump': {
54 'parameters': {
55 'height': {
56 'type': 'integer',
57 'minimum': 0,
58 'maximum': 100
59 },
60 '_jumpType': {
61 'type': 'string',
62 'enum': ['_withAirFlip', '_withSpin', '_withKick']
63 }
64 }
65 }
66 }
67 })");
68 CHECK(dict_.LoadCommands(*json, kTestCommandCategoty, nullptr, nullptr))
69 << "Failed to parse test command dictionary";
70
71 json = CreateDictionaryValue(R"({
72 'name': 'robot.jump',
73 'parameters': {
74 'height': 53,
75 '_jumpType': '_withKick'
76 }
77 })");
78 command_instance_ = CommandInstance::FromJson(json.get(), dict_, nullptr);
79 command_instance_->SetID(kTestCommandId);
80
81 // Set up a mock ExportedObject to be used with the DBus command proxy.
82 std::string cmd_path = dbus_constants::kCommandServicePathPrefix;
83 cmd_path += kTestCommandId;
84 const dbus::ObjectPath kCmdObjPath(cmd_path);
85 // Use a mock exported object for the exported object manager.
86 mock_exported_object_command_ =
87 new dbus::MockExportedObject(bus_.get(), kCmdObjPath);
88 EXPECT_CALL(*bus_, GetExportedObject(kCmdObjPath)).Times(AnyNumber())
89 .WillRepeatedly(Return(mock_exported_object_command_.get()));
90 EXPECT_CALL(*mock_exported_object_command_,
91 ExportMethod(_, _, _, _)).Times(AnyNumber());
92
93 command_proxy_.reset(new DBusCommandProxy(nullptr, bus_,
94 command_instance_.get()));
Alex Vakulenkof6b38712014-09-03 16:23:38 -070095 command_instance_->SetProxy(command_proxy_.get());
96 command_proxy_->RegisterAsync(
97 AsyncEventSequencer::GetDefaultCompletionAction());
Alex Vakulenko4866ac92014-08-20 12:53:33 -070098 }
99
100 void TearDown() override {
101 EXPECT_CALL(*mock_exported_object_command_, Unregister()).Times(1);
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700102 command_instance_->SetProxy(nullptr);
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700103 command_proxy_.reset();
104 command_instance_.reset();
105 dict_.Clear();
106 bus_ = nullptr;
107 }
108
109 chromeos::dbus_utils::DBusObject* GetProxyDBusObject() {
110 return &command_proxy_->dbus_object_;
111 }
112
113 std::string GetStatus() const {
114 return command_proxy_->status_.value();
115 }
116
117 int32_t GetProgress() const {
118 return command_proxy_->progress_.value();
119 }
120
Alex Vakulenko576c9792014-09-22 16:49:45 -0700121 VariantDictionary GetParameters() const {
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700122 return command_proxy_->parameters_.value();
123 }
124
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700125 std::unique_ptr<dbus::Response> CallMethod(
126 const std::string& method_name,
127 const std::function<void(dbus::MessageWriter*)>& param_callback) {
128 dbus::MethodCall method_call(dbus_constants::kCommandInterface,
129 method_name);
130 method_call.SetSerial(1234);
131 dbus::MessageWriter writer(&method_call);
132 if (param_callback)
133 param_callback(&writer);
134 return chromeos::dbus_utils::CallMethod(*GetProxyDBusObject(),
135 &method_call);
136 }
137
138 static bool IsResponseError(const std::unique_ptr<dbus::Response>& response) {
139 return (response->GetMessageType() == dbus::Message::MESSAGE_ERROR);
140 }
141
142 static void VerifyResponse(
143 const std::unique_ptr<dbus::Response>& response,
144 const std::function<void(dbus::MessageReader*)>& result_callback) {
145 EXPECT_FALSE(IsResponseError(response));
146 dbus::MessageReader reader(response.get());
147 if (result_callback)
148 result_callback(&reader);
149 EXPECT_FALSE(reader.HasMoreData());
150 }
151
152 template<typename T>
153 T GetPropertyValue(const std::string& property_name) {
154 dbus::MethodCall method_call(dbus::kPropertiesInterface,
155 dbus::kPropertiesGet);
156 method_call.SetSerial(1234);
157 dbus::MessageWriter writer(&method_call);
158 writer.AppendString(dbus_constants::kCommandInterface);
159 writer.AppendString(property_name);
160 auto response = chromeos::dbus_utils::CallMethod(*GetProxyDBusObject(),
161 &method_call);
162 T value{};
163 VerifyResponse(response, [&value](dbus::MessageReader* reader) {
164 EXPECT_TRUE(chromeos::dbus_utils::PopValueFromReader(reader, &value));
165 });
166 return value;
167 }
168
169 std::unique_ptr<DBusCommandProxy> command_proxy_;
170 std::unique_ptr<CommandInstance> command_instance_;
171 CommandDictionary dict_;
172
173 scoped_refptr<dbus::MockExportedObject> mock_exported_object_command_;
174 scoped_refptr<dbus::MockBus> bus_;
175};
176
177TEST_F(DBusCommandProxyTest, Init) {
Alex Vakulenko576c9792014-09-22 16:49:45 -0700178 VariantDictionary params = {
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700179 {"height", int32_t{53}},
180 {"_jumpType", std::string{"_withKick"}},
181 };
182 EXPECT_EQ(CommandInstance::kStatusQueued, GetStatus());
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700183 EXPECT_EQ(0, GetProgress());
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700184 EXPECT_EQ(params, GetParameters());
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700185 EXPECT_EQ("robot.jump",
186 GetPropertyValue<std::string>(dbus_constants::kCommandName));
187 EXPECT_EQ(kTestCommandCategoty,
188 GetPropertyValue<std::string>(dbus_constants::kCommandCategory));
189 EXPECT_EQ(kTestCommandId,
190 GetPropertyValue<std::string>(dbus_constants::kCommandId));
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700191 EXPECT_EQ(CommandInstance::kStatusQueued,
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700192 GetPropertyValue<std::string>(dbus_constants::kCommandStatus));
193 EXPECT_EQ(0, GetPropertyValue<int32_t>(dbus_constants::kCommandProgress));
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700194 EXPECT_EQ(params,
Alex Vakulenko576c9792014-09-22 16:49:45 -0700195 GetPropertyValue<VariantDictionary>(
196 dbus_constants::kCommandParameters));
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700197}
198
199TEST_F(DBusCommandProxyTest, SetProgress) {
200 EXPECT_CALL(*mock_exported_object_command_, SendSignal(_)).Times(2);
201 auto response = CallMethod(dbus_constants::kCommandSetProgress,
202 [](dbus::MessageWriter* writer) {
203 writer->AppendInt32(10);
204 });
205 VerifyResponse(response, {});
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700206 EXPECT_EQ(CommandInstance::kStatusInProgress, GetStatus());
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700207 EXPECT_EQ(10, GetProgress());
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700208 EXPECT_EQ(CommandInstance::kStatusInProgress,
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700209 GetPropertyValue<std::string>(dbus_constants::kCommandStatus));
210 EXPECT_EQ(10, GetPropertyValue<int32_t>(dbus_constants::kCommandProgress));
211}
212
213TEST_F(DBusCommandProxyTest, SetProgress_OutOfRange) {
214 auto response = CallMethod(dbus_constants::kCommandSetProgress,
215 [](dbus::MessageWriter* writer) {
216 writer->AppendInt32(110);
217 });
218 EXPECT_TRUE(IsResponseError(response));
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700219 EXPECT_EQ(CommandInstance::kStatusQueued, GetStatus());
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700220 EXPECT_EQ(0, GetProgress());
221}
222
223TEST_F(DBusCommandProxyTest, Abort) {
224 EXPECT_CALL(*mock_exported_object_command_, SendSignal(_)).Times(1);
225 auto response = CallMethod(dbus_constants::kCommandAbort, {});
226 VerifyResponse(response, {});
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700227 EXPECT_EQ(CommandInstance::kStatusAborted, GetStatus());
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700228}
229
230TEST_F(DBusCommandProxyTest, Cancel) {
231 EXPECT_CALL(*mock_exported_object_command_, SendSignal(_)).Times(1);
232 auto response = CallMethod(dbus_constants::kCommandCancel, {});
233 VerifyResponse(response, {});
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700234 EXPECT_EQ(CommandInstance::kStatusCanceled, GetStatus());
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700235}
236
237TEST_F(DBusCommandProxyTest, Done) {
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700238 // 3 property updates:
239 // status: queued -> inProgress
240 // progress: 0 -> 100
241 // status: inProgress -> done
242 EXPECT_CALL(*mock_exported_object_command_, SendSignal(_)).Times(3);
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700243 auto response = CallMethod(dbus_constants::kCommandDone, {});
244 VerifyResponse(response, {});
Alex Vakulenkof6b38712014-09-03 16:23:38 -0700245 EXPECT_EQ(CommandInstance::kStatusDone, GetStatus());
Alex Vakulenko4866ac92014-08-20 12:53:33 -0700246 EXPECT_EQ(100, GetProgress());
247}
248
249} // namespace buffet