Vitaly Buka | 4615e0d | 2015-10-14 15:35:12 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Weave Authors. All rights reserved. |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 5 | #include "src/commands/command_instance.h" |
Alex Deymo | f6cbe32 | 2014-11-10 19:55:35 -0800 | [diff] [blame] | 6 | |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 7 | #include <gtest/gtest.h> |
| 8 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 9 | #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 Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 13 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 14 | namespace weave { |
Vitaly Buka | 5f0d1d0 | 2015-04-29 11:39:55 -0700 | [diff] [blame] | 15 | |
Vitaly Buka | 0f6b2ec | 2015-08-20 15:35:19 -0700 | [diff] [blame] | 16 | using test::CreateDictionaryValue; |
| 17 | using test::CreateValue; |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 18 | |
| 19 | namespace { |
| 20 | |
| 21 | class CommandInstanceTest : public ::testing::Test { |
| 22 | protected: |
Alex Vakulenko | 5a9e718 | 2014-08-11 15:59:58 -0700 | [diff] [blame] | 23 | void SetUp() override { |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 24 | auto json = CreateDictionaryValue(R"({ |
| 25 | 'base': { |
| 26 | 'reboot': { |
Anton Muhin | 71fb9d5 | 2014-11-21 22:22:39 +0400 | [diff] [blame] | 27 | 'parameters': {}, |
| 28 | 'results': {} |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 29 | } |
| 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 Muhin | 71fb9d5 | 2014-11-21 22:22:39 +0400 | [diff] [blame] | 43 | }, |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 44 | 'progress': {'progress': 'integer'}, |
| 45 | 'results': {'testResult': 'integer'} |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 46 | }, |
| 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 Muhin | 71fb9d5 | 2014-11-21 22:22:39 +0400 | [diff] [blame] | 59 | }, |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 60 | 'results': {'foo': 'integer'} |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 61 | } |
| 62 | } |
| 63 | })"); |
Vitaly Buka | 453c4dd | 2015-10-04 18:01:50 -0700 | [diff] [blame] | 64 | CHECK(dict_.LoadCommands(*json, nullptr, nullptr)) |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 65 | << "Failed to parse test command dictionary"; |
| 66 | } |
Vitaly Buka | 5f0d1d0 | 2015-04-29 11:39:55 -0700 | [diff] [blame] | 67 | CommandDictionary dict_; |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 68 | }; |
| 69 | |
| 70 | } // anonymous namespace |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 71 | |
Anton Muhin | cfde869 | 2014-11-25 03:36:59 +0400 | [diff] [blame] | 72 | TEST_F(CommandInstanceTest, Test) { |
Vitaly Buka | 5f0d1d0 | 2015-04-29 11:39:55 -0700 | [diff] [blame] | 73 | StringPropType str_prop; |
| 74 | IntPropType int_prop; |
Vitaly Buka | 774cdf5 | 2015-07-21 13:55:00 -0700 | [diff] [blame] | 75 | ValueMap params; |
Vitaly Buka | c58a828 | 2015-07-29 01:25:20 -0700 | [diff] [blame] | 76 | params["phrase"] = |
| 77 | str_prop.CreateValue(base::StringValue{"iPityDaFool"}, nullptr); |
| 78 | params["volume"] = int_prop.CreateValue(base::FundamentalValue{5}, nullptr); |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 79 | CommandInstance instance{"robot.speak", Command::Origin::kCloud, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 80 | dict_.FindCommand("robot.speak"), params}; |
Anton Muhin | cfde869 | 2014-11-25 03:36:59 +0400 | [diff] [blame] | 81 | |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 82 | EXPECT_TRUE( |
Vitaly Buka | 2f54897 | 2015-10-08 19:34:49 -0700 | [diff] [blame] | 83 | instance.Complete(*CreateDictionaryValue("{'foo': 239}"), nullptr)); |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 84 | |
Alex Vakulenko | fedc487 | 2014-08-20 12:38:43 -0700 | [diff] [blame] | 85 | EXPECT_EQ("", instance.GetID()); |
Anton Muhin | cfde869 | 2014-11-25 03:36:59 +0400 | [diff] [blame] | 86 | EXPECT_EQ("robot.speak", instance.GetName()); |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 87 | EXPECT_EQ(Command::Origin::kCloud, instance.GetOrigin()); |
Vitaly Buka | 8d8d219 | 2015-07-21 22:25:09 -0700 | [diff] [blame] | 88 | EXPECT_JSON_EQ("{'phrase': 'iPityDaFool', 'volume': 5}", |
| 89 | *instance.GetParameters()); |
| 90 | EXPECT_JSON_EQ("{'foo': 239}", *instance.GetResults()); |
Alex Vakulenko | f784e21 | 2015-04-20 12:33:52 -0700 | [diff] [blame] | 91 | |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 92 | CommandInstance instance2{"base.reboot", |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 93 | Command::Origin::kLocal, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 94 | dict_.FindCommand("base.reboot"), |
| 95 | {}}; |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 96 | EXPECT_EQ(Command::Origin::kLocal, instance2.GetOrigin()); |
Alex Vakulenko | aa3a559 | 2014-08-07 07:24:06 -0700 | [diff] [blame] | 97 | } |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 98 | |
Anton Muhin | cfde869 | 2014-11-25 03:36:59 +0400 | [diff] [blame] | 99 | TEST_F(CommandInstanceTest, SetID) { |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 100 | CommandInstance instance{"base.reboot", |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 101 | Command::Origin::kLocal, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 102 | dict_.FindCommand("base.reboot"), |
| 103 | {}}; |
Alex Vakulenko | fedc487 | 2014-08-20 12:38:43 -0700 | [diff] [blame] | 104 | instance.SetID("command_id"); |
| 105 | EXPECT_EQ("command_id", instance.GetID()); |
| 106 | } |
| 107 | |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 108 | TEST_F(CommandInstanceTest, FromJson) { |
| 109 | auto json = CreateDictionaryValue(R"({ |
| 110 | 'name': 'robot.jump', |
Alex Vakulenko | d1978d3 | 2015-04-29 17:33:26 -0700 | [diff] [blame] | 111 | 'id': 'abcd', |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 112 | 'parameters': { |
| 113 | 'height': 53, |
| 114 | '_jumpType': '_withKick' |
Anton Muhin | 71fb9d5 | 2014-11-21 22:22:39 +0400 | [diff] [blame] | 115 | }, |
| 116 | 'results': {} |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 117 | })"); |
Alex Vakulenko | d1978d3 | 2015-04-29 17:33:26 -0700 | [diff] [blame] | 118 | std::string id; |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 119 | auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 120 | dict_, &id, nullptr); |
Alex Vakulenko | d1978d3 | 2015-04-29 17:33:26 -0700 | [diff] [blame] | 121 | EXPECT_EQ("abcd", id); |
| 122 | EXPECT_EQ("abcd", instance->GetID()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 123 | EXPECT_EQ("robot.jump", instance->GetName()); |
Vitaly Buka | 8d8d219 | 2015-07-21 22:25:09 -0700 | [diff] [blame] | 124 | EXPECT_JSON_EQ("{'height': 53, '_jumpType': '_withKick'}", |
| 125 | *instance->GetParameters()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | TEST_F(CommandInstanceTest, FromJson_ParamsOmitted) { |
| 129 | auto json = CreateDictionaryValue("{'name': 'base.reboot'}"); |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 130 | auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 131 | dict_, nullptr, nullptr); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 132 | EXPECT_EQ("base.reboot", instance->GetName()); |
Vitaly Buka | 8d8d219 | 2015-07-21 22:25:09 -0700 | [diff] [blame] | 133 | EXPECT_JSON_EQ("{}", *instance->GetParameters()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | TEST_F(CommandInstanceTest, FromJson_NotObject) { |
| 137 | auto json = CreateValue("'string'"); |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 138 | ErrorPtr error; |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 139 | auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 140 | dict_, nullptr, &error); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 141 | EXPECT_EQ(nullptr, instance.get()); |
| 142 | EXPECT_EQ("json_object_expected", error->GetCode()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | TEST_F(CommandInstanceTest, FromJson_NameMissing) { |
| 146 | auto json = CreateDictionaryValue("{'param': 'value'}"); |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 147 | ErrorPtr error; |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 148 | auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 149 | dict_, nullptr, &error); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 150 | EXPECT_EQ(nullptr, instance.get()); |
| 151 | EXPECT_EQ("parameter_missing", error->GetCode()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | TEST_F(CommandInstanceTest, FromJson_UnknownCommand) { |
| 155 | auto json = CreateDictionaryValue("{'name': 'robot.scream'}"); |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 156 | ErrorPtr error; |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 157 | auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 158 | dict_, nullptr, &error); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 159 | EXPECT_EQ(nullptr, instance.get()); |
| 160 | EXPECT_EQ("invalid_command_name", error->GetCode()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | TEST_F(CommandInstanceTest, FromJson_ParamsNotObject) { |
| 164 | auto json = CreateDictionaryValue(R"({ |
| 165 | 'name': 'robot.speak', |
| 166 | 'parameters': 'hello' |
| 167 | })"); |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 168 | ErrorPtr error; |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 169 | auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 170 | dict_, nullptr, &error); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 171 | EXPECT_EQ(nullptr, instance.get()); |
| 172 | auto inner = error->GetInnerError(); |
| 173 | EXPECT_EQ("json_object_expected", inner->GetCode()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 174 | EXPECT_EQ("command_failed", error->GetCode()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 175 | } |
| 176 | |
| 177 | TEST_F(CommandInstanceTest, FromJson_ParamError) { |
| 178 | auto json = CreateDictionaryValue(R"({ |
| 179 | 'name': 'robot.speak', |
| 180 | 'parameters': { |
| 181 | 'phrase': 'iPityDaFool', |
| 182 | 'volume': 20 |
| 183 | } |
| 184 | })"); |
Vitaly Buka | 0801a1f | 2015-08-14 10:03:46 -0700 | [diff] [blame] | 185 | ErrorPtr error; |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 186 | auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 187 | dict_, nullptr, &error); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 188 | EXPECT_EQ(nullptr, instance.get()); |
| 189 | auto first = error->GetFirstError(); |
| 190 | EXPECT_EQ("out_of_range", first->GetCode()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 191 | auto inner = error->GetInnerError(); |
| 192 | EXPECT_EQ("invalid_parameter_value", inner->GetCode()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 193 | EXPECT_EQ("command_failed", error->GetCode()); |
Alex Vakulenko | 8dc69af | 2014-08-07 10:29:42 -0700 | [diff] [blame] | 194 | } |
Vitaly Buka | 906d39e | 2015-03-24 10:08:26 -0700 | [diff] [blame] | 195 | |
| 196 | TEST_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 Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 205 | auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud, |
Vitaly Buka | 15f5909 | 2015-07-24 16:54:32 -0700 | [diff] [blame] | 206 | dict_, nullptr, nullptr); |
Vitaly Buka | 4f4e228 | 2015-07-23 17:50:07 -0700 | [diff] [blame] | 207 | EXPECT_TRUE(instance->SetProgress(*CreateDictionaryValue("{'progress': 15}"), |
| 208 | nullptr)); |
| 209 | EXPECT_TRUE(instance->SetProgress(*CreateDictionaryValue("{'progress': 15}"), |
| 210 | nullptr)); |
Vitaly Buka | 906d39e | 2015-03-24 10:08:26 -0700 | [diff] [blame] | 211 | instance->SetID("testId"); |
Vitaly Buka | 2f54897 | 2015-10-08 19:34:49 -0700 | [diff] [blame] | 212 | EXPECT_TRUE(instance->Complete(*CreateDictionaryValue("{'testResult': 17}"), |
| 213 | nullptr)); |
Vitaly Buka | 906d39e | 2015-03-24 10:08:26 -0700 | [diff] [blame] | 214 | |
| 215 | json->MergeDictionary(CreateDictionaryValue(R"({ |
| 216 | 'id': 'testId', |
Alex Vakulenko | 808e2d8 | 2015-04-08 15:45:56 -0700 | [diff] [blame] | 217 | 'progress': {'progress': 15}, |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 218 | '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 | |
| 228 | TEST_F(CommandInstanceTest, ToJsonError) { |
| 229 | auto json = CreateDictionaryValue(R"({ |
| 230 | 'name': 'base.reboot', |
| 231 | 'parameters': {} |
| 232 | })"); |
Vitaly Buka | 0209da4 | 2015-10-08 00:07:18 -0700 | [diff] [blame] | 233 | auto instance = CommandInstance::FromJson(json.get(), Command::Origin::kCloud, |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 234 | 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 Buka | 70f77d9 | 2015-10-07 15:42:40 -0700 | [diff] [blame] | 243 | 'state': 'aborted', |
Vitaly Buka | 47a1f6f | 2015-10-07 18:09:57 -0700 | [diff] [blame] | 244 | 'progress': {}, |
| 245 | 'results': {}, |
Vitaly Buka | 70f77d9 | 2015-10-07 15:42:40 -0700 | [diff] [blame] | 246 | 'error': {'code': 'CODE', 'message': 'MESSAGE'} |
Vitaly Buka | 906d39e | 2015-03-24 10:08:26 -0700 | [diff] [blame] | 247 | })").get()); |
| 248 | |
| 249 | auto converted = instance->ToJson(); |
Vitaly Buka | 4ebd329 | 2015-09-23 18:04:17 -0700 | [diff] [blame] | 250 | EXPECT_PRED2([](const base::Value& val1, |
| 251 | const base::Value& val2) { return val1.Equals(&val2); }, |
| 252 | *json, *converted); |
Vitaly Buka | 906d39e | 2015-03-24 10:08:26 -0700 | [diff] [blame] | 253 | } |
Vitaly Buka | 5f0d1d0 | 2015-04-29 11:39:55 -0700 | [diff] [blame] | 254 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 255 | } // namespace weave |