blob: f7744b026bcc50c32420ac87f3d117e471bbd828 [file] [log] [blame]
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -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
Alex Deymof6cbe322014-11-10 19:55:35 -08005#include "buffet/commands/command_instance.h"
6
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -07007#include <gtest/gtest.h>
8
Alex Vakulenko8dc69af2014-08-07 10:29:42 -07009#include "buffet/commands/command_dictionary.h"
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070010#include "buffet/commands/prop_types.h"
Anton Muhincfde8692014-11-25 03:36:59 +040011#include "buffet/commands/schema_utils.h"
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070012#include "buffet/commands/unittest_utils.h"
13
Vitaly Buka5f0d1d02015-04-29 11:39:55 -070014namespace buffet {
15
16using unittests::CreateDictionaryValue;
17using unittests::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 },
44 'results': {}
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070045 },
46 'speak': {
47 'parameters': {
48 'phrase': {
49 'type': 'string',
50 'enum': ['beamMeUpScotty', 'iDontDigOnSwine',
51 'iPityDaFool', 'dangerWillRobinson']
52 },
53 'volume': {
54 'type': 'integer',
55 'minimum': 0,
56 'maximum': 10
57 }
Anton Muhin71fb9d52014-11-21 22:22:39 +040058 },
59 'results': {}
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070060 }
61 }
62 })");
63 CHECK(dict_.LoadCommands(*json, "robotd", nullptr, nullptr))
64 << "Failed to parse test command dictionary";
65 }
Vitaly Buka5f0d1d02015-04-29 11:39:55 -070066 CommandDictionary dict_;
Alex Vakulenko8dc69af2014-08-07 10:29:42 -070067};
68
69} // anonymous namespace
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070070
Anton Muhincfde8692014-11-25 03:36:59 +040071TEST_F(CommandInstanceTest, Test) {
Vitaly Buka5f0d1d02015-04-29 11:39:55 -070072 StringPropType str_prop;
73 IntPropType int_prop;
74 native_types::Object params;
Anton Muhincfde8692014-11-25 03:36:59 +040075 params["phrase"] = str_prop.CreateValue(std::string("iPityDaFool"),
76 nullptr);
77 params["volume"] = int_prop.CreateValue(5, nullptr);
Vitaly Buka5f0d1d02015-04-29 11:39:55 -070078 CommandInstance instance{
79 "robot.speak", "cloud", dict_.FindCommand("robot.speak"), params};
Anton Muhincfde8692014-11-25 03:36:59 +040080
Vitaly Buka5f0d1d02015-04-29 11:39:55 -070081 native_types::Object results;
Anton Muhincfde8692014-11-25 03:36:59 +040082 results["foo"] = int_prop.CreateValue(239, nullptr);
83 instance.SetResults(results);
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());
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070087 EXPECT_EQ("robotd", instance.GetCategory());
Alex Vakulenkof784e212015-04-20 12:33:52 -070088 EXPECT_EQ("cloud", instance.GetOrigin());
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070089 EXPECT_EQ(params, instance.GetParameters());
Anton Muhincfde8692014-11-25 03:36:59 +040090 EXPECT_EQ("iPityDaFool",
91 instance.FindParameter("phrase")->GetString()->GetValue());
92 EXPECT_EQ(5, instance.FindParameter("volume")->GetInt()->GetValue());
Alex Vakulenko5ef75792015-03-19 15:50:44 -070093 EXPECT_EQ(nullptr, instance.FindParameter("blah"));
Anton Muhincfde8692014-11-25 03:36:59 +040094 EXPECT_EQ(results, instance.GetResults());
Alex Vakulenkof784e212015-04-20 12:33:52 -070095
Vitaly Buka5f0d1d02015-04-29 11:39:55 -070096 CommandInstance instance2{
97 "base.reboot", "local", dict_.FindCommand("base.reboot"), {}};
Alex Vakulenkof784e212015-04-20 12:33:52 -070098 EXPECT_EQ("local", instance2.GetOrigin());
Alex Vakulenkoaa3a5592014-08-07 07:24:06 -070099}
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700100
Anton Muhincfde8692014-11-25 03:36:59 +0400101TEST_F(CommandInstanceTest, SetID) {
Vitaly Buka5f0d1d02015-04-29 11:39:55 -0700102 CommandInstance instance{
103 "base.reboot", "local", dict_.FindCommand("base.reboot"), {}};
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 Buka5f0d1d02015-04-29 11:39:55 -0700119 auto instance =
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700120 CommandInstance::FromJson(json.get(), "cloud", dict_, &id, nullptr);
121 EXPECT_EQ("abcd", id);
122 EXPECT_EQ("abcd", instance->GetID());
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700123 EXPECT_EQ("robot.jump", instance->GetName());
124 EXPECT_EQ("robotd", instance->GetCategory());
125 EXPECT_EQ(53, instance->FindParameter("height")->GetInt()->GetValue());
126 EXPECT_EQ("_withKick",
127 instance->FindParameter("_jumpType")->GetString()->GetValue());
128}
129
130TEST_F(CommandInstanceTest, FromJson_ParamsOmitted) {
131 auto json = CreateDictionaryValue("{'name': 'base.reboot'}");
Vitaly Buka5f0d1d02015-04-29 11:39:55 -0700132 auto instance =
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700133 CommandInstance::FromJson(json.get(), "cloud", dict_, nullptr, nullptr);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700134 EXPECT_EQ("base.reboot", instance->GetName());
135 EXPECT_EQ("robotd", instance->GetCategory());
136 EXPECT_TRUE(instance->GetParameters().empty());
137}
138
139TEST_F(CommandInstanceTest, FromJson_NotObject) {
140 auto json = CreateValue("'string'");
Alex Vakulenko5f472062014-08-14 17:54:04 -0700141 chromeos::ErrorPtr error;
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700142 auto instance =
143 CommandInstance::FromJson(json.get(), "cloud", dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700144 EXPECT_EQ(nullptr, instance.get());
145 EXPECT_EQ("json_object_expected", error->GetCode());
146 EXPECT_EQ("Command instance is not a JSON object", error->GetMessage());
147}
148
149TEST_F(CommandInstanceTest, FromJson_NameMissing) {
150 auto json = CreateDictionaryValue("{'param': 'value'}");
Alex Vakulenko5f472062014-08-14 17:54:04 -0700151 chromeos::ErrorPtr error;
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700152 auto instance =
153 CommandInstance::FromJson(json.get(), "cloud", dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700154 EXPECT_EQ(nullptr, instance.get());
155 EXPECT_EQ("parameter_missing", error->GetCode());
156 EXPECT_EQ("Command name is missing", error->GetMessage());
157}
158
159TEST_F(CommandInstanceTest, FromJson_UnknownCommand) {
160 auto json = CreateDictionaryValue("{'name': 'robot.scream'}");
Alex Vakulenko5f472062014-08-14 17:54:04 -0700161 chromeos::ErrorPtr error;
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700162 auto instance =
163 CommandInstance::FromJson(json.get(), "cloud", dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700164 EXPECT_EQ(nullptr, instance.get());
165 EXPECT_EQ("invalid_command_name", error->GetCode());
166 EXPECT_EQ("Unknown command received: robot.scream", error->GetMessage());
167}
168
169TEST_F(CommandInstanceTest, FromJson_ParamsNotObject) {
170 auto json = CreateDictionaryValue(R"({
171 'name': 'robot.speak',
172 'parameters': 'hello'
173 })");
Alex Vakulenko5f472062014-08-14 17:54:04 -0700174 chromeos::ErrorPtr error;
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700175 auto instance =
176 CommandInstance::FromJson(json.get(), "cloud", dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700177 EXPECT_EQ(nullptr, instance.get());
178 auto inner = error->GetInnerError();
179 EXPECT_EQ("json_object_expected", inner->GetCode());
180 EXPECT_EQ("Property 'parameters' must be a JSON object", inner->GetMessage());
181 EXPECT_EQ("command_failed", error->GetCode());
182 EXPECT_EQ("Failed to validate command 'robot.speak'", error->GetMessage());
183}
184
185TEST_F(CommandInstanceTest, FromJson_ParamError) {
186 auto json = CreateDictionaryValue(R"({
187 'name': 'robot.speak',
188 'parameters': {
189 'phrase': 'iPityDaFool',
190 'volume': 20
191 }
192 })");
Alex Vakulenko5f472062014-08-14 17:54:04 -0700193 chromeos::ErrorPtr error;
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700194 auto instance =
195 CommandInstance::FromJson(json.get(), "cloud", dict_, nullptr, &error);
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700196 EXPECT_EQ(nullptr, instance.get());
197 auto first = error->GetFirstError();
198 EXPECT_EQ("out_of_range", first->GetCode());
199 EXPECT_EQ("Value 20 is out of range. It must not be greater than 10",
200 first->GetMessage());
201 auto inner = error->GetInnerError();
202 EXPECT_EQ("invalid_parameter_value", inner->GetCode());
Alex Vakulenkoa32d83a2014-09-19 15:05:24 -0700203 EXPECT_EQ("Invalid value for property 'volume'",
Alex Vakulenko8dc69af2014-08-07 10:29:42 -0700204 inner->GetMessage());
205 EXPECT_EQ("command_failed", error->GetCode());
206 EXPECT_EQ("Failed to validate command 'robot.speak'", error->GetMessage());
207}
Vitaly Buka906d39e2015-03-24 10:08:26 -0700208
209TEST_F(CommandInstanceTest, ToJson) {
210 auto json = CreateDictionaryValue(R"({
211 'name': 'robot.jump',
212 'parameters': {
213 'height': 53,
214 '_jumpType': '_withKick'
215 },
216 'results': {}
217 })");
Vitaly Buka5f0d1d02015-04-29 11:39:55 -0700218 auto instance =
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700219 CommandInstance::FromJson(json.get(), "cloud", dict_, nullptr, nullptr);
Vitaly Buka4129dfa2015-04-29 12:16:58 -0700220 instance->SetProgress(
221 native_types::Object{{"progress", unittests::make_int_prop_value(15)}});
222 instance->SetProgress(
223 native_types::Object{{"progress", unittests::make_int_prop_value(15)}});
Vitaly Buka906d39e2015-03-24 10:08:26 -0700224 instance->SetID("testId");
Vitaly Buka5f0d1d02015-04-29 11:39:55 -0700225 native_types::Object results;
Vitaly Buka4129dfa2015-04-29 12:16:58 -0700226 instance->SetResults(
227 native_types::Object{{"testResult", unittests::make_int_prop_value(17)}});
Vitaly Buka906d39e2015-03-24 10:08:26 -0700228
229 json->MergeDictionary(CreateDictionaryValue(R"({
230 'id': 'testId',
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700231 'progress': {'progress': 15},
Vitaly Buka906d39e2015-03-24 10:08:26 -0700232 'state': 'inProgress',
233 'results': {'testResult': 17}
234 })").get());
235
236 auto converted = instance->ToJson();
237 EXPECT_PRED2([](const base::Value& val1, const base::Value& val2) {
238 return val1.Equals(&val2);
239 }, *json, *converted);
240}
Vitaly Buka5f0d1d02015-04-29 11:39:55 -0700241
242} // namespace buffet