blob: 4e208ed87cb5532056803dbd797d7a96a6327d76 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02005#include "src/commands/command_instance.h"
Alex Deymof6cbe322014-11-10 19:55:35 -08006
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -07007#include <gtest/gtest.h>
8
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02009#include "src/commands/command_dictionary.h"
10#include "src/commands/prop_types.h"
11#include "src/commands/schema_utils.h"
12#include "src/commands/unittest_utils.h"
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070013
Vitaly Bukab6f015a2015-07-09 14:59:23 -070014namespace weave {
Vitaly Buka5f0d1d02015-04-29 11:39:55 -070015
Vitaly Buka0f6b2ec2015-08-20 15:35:19 -070016using test::CreateDictionaryValue;
17using test::CreateValue;
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070018
19namespace {
20
21class CommandInstanceTest : public ::testing::Test {
22 protected:
Alex Vakulenko5a9e7182014-08-11 15:59:58 -070023 void SetUp() override {
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070024 auto json = CreateDictionaryValue(R"({
25 'base': {
26 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +040027 'parameters': {},
28 'results': {}
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070029 }
30 },
31 'robot': {
32 'jump': {
33 'parameters': {
34 'height': {
35 'type': 'integer',
36 'minimum': 0,
37 'maximum': 100
38 },
39 '_jumpType': {
40 'type': 'string',
41 'enum': ['_withAirFlip', '_withSpin', '_withKick']
42 }
Anton Muhin71fb9d52014-11-21 22:22:39 +040043 },
Vitaly Buka4f4e2282015-07-23 17:50:07 -070044 'progress': {'progress': 'integer'},
45 'results': {'testResult': 'integer'}
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070046 },
47 'speak': {
48 'parameters': {
49 'phrase': {
50 'type': 'string',
51 'enum': ['beamMeUpScotty', 'iDontDigOnSwine',
52 'iPityDaFool', 'dangerWillRobinson']
53 },
54 'volume': {
55 'type': 'integer',
56 'minimum': 0,
57 'maximum': 10
58 }
Anton Muhin71fb9d52014-11-21 22:22:39 +040059 },
Vitaly Buka4f4e2282015-07-23 17:50:07 -070060 'results': {'foo': 'integer'}
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070061 }
62 }
63 })");
Vitaly Buka453c4dd2015-10-04 18:01:50 -070064 CHECK(dict_.LoadCommands(*json, nullptr, nullptr))
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070065 << "Failed to parse test command dictionary";
66 }
Vitaly Buka5f0d1d02015-04-29 11:39:55 -070067 CommandDictionary dict_;
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070068};
69
70} // anonymous namespace
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070071
Anton Muhincfde8692014-11-25 03:36:59 +040072TEST_F(CommandInstanceTest, Test) {
Vitaly Buka5f0d1d02015-04-29 11:39:55 -070073 StringPropType str_prop;
74 IntPropType int_prop;
Vitaly Buka774cdf52015-07-21 13:55:00 -070075 ValueMap params;
Vitaly Bukac58a8282015-07-29 01:25:20 -070076 params["phrase"] =
77 str_prop.CreateValue(base::StringValue{"iPityDaFool"}, nullptr);
78 params["volume"] = int_prop.CreateValue(base::FundamentalValue{5}, nullptr);
Vitaly Buka0209da42015-10-08 00:07:18 -070079 CommandInstance instance{"robot.speak", Command::Origin::kCloud,
Vitaly Buka15f59092015-07-24 16:54:32 -070080 dict_.FindCommand("robot.speak"), params};
Anton Muhincfde8692014-11-25 03:36:59 +040081
Vitaly Buka4f4e2282015-07-23 17:50:07 -070082 EXPECT_TRUE(
Vitaly Buka2f548972015-10-08 19:34:49 -070083 instance.Complete(*CreateDictionaryValue("{'foo': 239}"), nullptr));
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070084
Alex Vakulenkofedc4872014-08-20 12:38:43 -070085 EXPECT_EQ("", instance.GetID());
Anton Muhincfde8692014-11-25 03:36:59 +040086 EXPECT_EQ("robot.speak", instance.GetName());
Vitaly Buka0209da42015-10-08 00:07:18 -070087 EXPECT_EQ(Command::Origin::kCloud, instance.GetOrigin());
Vitaly Buka8d8d2192015-07-21 22:25:09 -070088 EXPECT_JSON_EQ("{'phrase': 'iPityDaFool', 'volume': 5}",
89 *instance.GetParameters());
90 EXPECT_JSON_EQ("{'foo': 239}", *instance.GetResults());
Alex Vakulenkof784e212015-04-20 12:33:52 -070091
Vitaly Buka15f59092015-07-24 16:54:32 -070092 CommandInstance instance2{"base.reboot",
Vitaly Buka0209da42015-10-08 00:07:18 -070093 Command::Origin::kLocal,
Vitaly Buka15f59092015-07-24 16:54:32 -070094 dict_.FindCommand("base.reboot"),
95 {}};
Vitaly Buka0209da42015-10-08 00:07:18 -070096 EXPECT_EQ(Command::Origin::kLocal, instance2.GetOrigin());
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070097}
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070098
Anton Muhincfde8692014-11-25 03:36:59 +040099TEST_F(CommandInstanceTest, SetID) {
Vitaly Buka15f59092015-07-24 16:54:32 -0700100 CommandInstance instance{"base.reboot",
Vitaly Buka0209da42015-10-08 00:07:18 -0700101 Command::Origin::kLocal,
Vitaly Buka15f59092015-07-24 16:54:32 -0700102 dict_.FindCommand("base.reboot"),
103 {}};
Alex Vakulenkofedc4872014-08-20 12:38:43 -0700104 instance.SetID("command_id");
105 EXPECT_EQ("command_id", instance.GetID());
106}
107
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700108TEST_F(CommandInstanceTest, FromJson) {
109 auto json = CreateDictionaryValue(R"({
110 'name': 'robot.jump',
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700111 'id': 'abcd',
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700112 'parameters': {
113 'height': 53,
114 '_jumpType': '_withKick'
Anton Muhin71fb9d52014-11-21 22:22:39 +0400115 },
116 'results': {}
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700117 })");
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700118 std::string id;
Vitaly Buka0209da42015-10-08 00:07:18 -0700119 auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud,
Vitaly Buka15f59092015-07-24 16:54:32 -0700120 dict_, &id, nullptr);
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700121 EXPECT_EQ("abcd", id);
122 EXPECT_EQ("abcd", instance->GetID());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700123 EXPECT_EQ("robot.jump", instance->GetName());
Vitaly Buka8d8d2192015-07-21 22:25:09 -0700124 EXPECT_JSON_EQ("{'height': 53, '_jumpType': '_withKick'}",
125 *instance->GetParameters());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700126}
127
128TEST_F(CommandInstanceTest, FromJson_ParamsOmitted) {
129 auto json = CreateDictionaryValue("{'name': 'base.reboot'}");
Vitaly Buka0209da42015-10-08 00:07:18 -0700130 auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud,
Vitaly Buka15f59092015-07-24 16:54:32 -0700131 dict_, nullptr, nullptr);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700132 EXPECT_EQ("base.reboot", instance->GetName());
Vitaly Buka8d8d2192015-07-21 22:25:09 -0700133 EXPECT_JSON_EQ("{}", *instance->GetParameters());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700134}
135
136TEST_F(CommandInstanceTest, FromJson_NotObject) {
137 auto json = CreateValue("'string'");
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700138 ErrorPtr error;
Vitaly Buka0209da42015-10-08 00:07:18 -0700139 auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud,
Vitaly Buka15f59092015-07-24 16:54:32 -0700140 dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700141 EXPECT_EQ(nullptr, instance.get());
142 EXPECT_EQ("json_object_expected", error->GetCode());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700143}
144
145TEST_F(CommandInstanceTest, FromJson_NameMissing) {
146 auto json = CreateDictionaryValue("{'param': 'value'}");
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700147 ErrorPtr error;
Vitaly Buka0209da42015-10-08 00:07:18 -0700148 auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud,
Vitaly Buka15f59092015-07-24 16:54:32 -0700149 dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700150 EXPECT_EQ(nullptr, instance.get());
151 EXPECT_EQ("parameter_missing", error->GetCode());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700152}
153
154TEST_F(CommandInstanceTest, FromJson_UnknownCommand) {
155 auto json = CreateDictionaryValue("{'name': 'robot.scream'}");
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700156 ErrorPtr error;
Vitaly Buka0209da42015-10-08 00:07:18 -0700157 auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud,
Vitaly Buka15f59092015-07-24 16:54:32 -0700158 dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700159 EXPECT_EQ(nullptr, instance.get());
160 EXPECT_EQ("invalid_command_name", error->GetCode());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700161}
162
163TEST_F(CommandInstanceTest, FromJson_ParamsNotObject) {
164 auto json = CreateDictionaryValue(R"({
165 'name': 'robot.speak',
166 'parameters': 'hello'
167 })");
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700168 ErrorPtr error;
Vitaly Buka0209da42015-10-08 00:07:18 -0700169 auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud,
Vitaly Buka15f59092015-07-24 16:54:32 -0700170 dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700171 EXPECT_EQ(nullptr, instance.get());
172 auto inner = error->GetInnerError();
173 EXPECT_EQ("json_object_expected", inner->GetCode());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700174 EXPECT_EQ("command_failed", error->GetCode());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700175}
176
177TEST_F(CommandInstanceTest, FromJson_ParamError) {
178 auto json = CreateDictionaryValue(R"({
179 'name': 'robot.speak',
180 'parameters': {
181 'phrase': 'iPityDaFool',
182 'volume': 20
183 }
184 })");
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700185 ErrorPtr error;
Vitaly Buka0209da42015-10-08 00:07:18 -0700186 auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud,
Vitaly Buka15f59092015-07-24 16:54:32 -0700187 dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700188 EXPECT_EQ(nullptr, instance.get());
189 auto first = error->GetFirstError();
190 EXPECT_EQ("out_of_range", first->GetCode());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700191 auto inner = error->GetInnerError();
192 EXPECT_EQ("invalid_parameter_value", inner->GetCode());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700193 EXPECT_EQ("command_failed", error->GetCode());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700194}
Vitaly Buka906d39e2015-03-24 10:08:26 -0700195
196TEST_F(CommandInstanceTest, ToJson) {
197 auto json = CreateDictionaryValue(R"({
198 'name': 'robot.jump',
199 'parameters': {
200 'height': 53,
201 '_jumpType': '_withKick'
202 },
203 'results': {}
204 })");
Vitaly Buka0209da42015-10-08 00:07:18 -0700205 auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud,
Vitaly Buka15f59092015-07-24 16:54:32 -0700206 dict_, nullptr, nullptr);
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700207 EXPECT_TRUE(instance->SetProgress(*CreateDictionaryValue("{'progress': 15}"),
208 nullptr));
209 EXPECT_TRUE(instance->SetProgress(*CreateDictionaryValue("{'progress': 15}"),
210 nullptr));
Vitaly Buka906d39e2015-03-24 10:08:26 -0700211 instance->SetID("testId");
Vitaly Buka2f548972015-10-08 19:34:49 -0700212 EXPECT_TRUE(instance->Complete(*CreateDictionaryValue("{'testResult': 17}"),
213 nullptr));
Vitaly Buka906d39e2015-03-24 10:08:26 -0700214
215 json->MergeDictionary(CreateDictionaryValue(R"({
216 'id': 'testId',
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700217 'progress': {'progress': 15},
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700218 'state': 'done',
219 'results': {'testResult': 17}
220 })").get());
221
222 auto converted = instance->ToJson();
223 EXPECT_PRED2([](const base::Value& val1,
224 const base::Value& val2) { return val1.Equals(&val2); },
225 *json, *converted);
226}
227
228TEST_F(CommandInstanceTest, ToJsonError) {
229 auto json = CreateDictionaryValue(R"({
230 'name': 'base.reboot',
231 'parameters': {}
232 })");
Vitaly Buka0209da42015-10-08 00:07:18 -0700233 auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud,
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700234 dict_, nullptr, nullptr);
235 instance->SetID("testId");
236
237 ErrorPtr error;
238 Error::AddTo(&error, FROM_HERE, "DOMAIN", "CODE", "MESSAGE");
239 instance->Abort(error.get(), nullptr);
240
241 json->MergeDictionary(CreateDictionaryValue(R"({
242 'id': 'testId',
Vitaly Buka70f77d92015-10-07 15:42:40 -0700243 'state': 'aborted',
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700244 'progress': {},
245 'results': {},
Vitaly Buka70f77d92015-10-07 15:42:40 -0700246 'error': {'code': 'CODE', 'message': 'MESSAGE'}
Vitaly Buka906d39e2015-03-24 10:08:26 -0700247 })").get());
248
249 auto converted = instance->ToJson();
Vitaly Buka4ebd3292015-09-23 18:04:17 -0700250 EXPECT_PRED2([](const base::Value& val1,
251 const base::Value& val2) { return val1.Equals(&val2); },
252 *json, *converted);
Vitaly Buka906d39e2015-03-24 10:08:26 -0700253}
Vitaly Buka5f0d1d02015-04-29 11:39:55 -0700254
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700255} // namespace weave