Vitaly Buka | 4615e0d | 2015-10-14 15:35:12 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Weave Authors. All rights reserved. |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -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 | |
| 5 | #include <weave/device.h> |
| 6 | |
| 7 | #include <gmock/gmock.h> |
| 8 | #include <gtest/gtest.h> |
Vitaly Buka | 727f3e6 | 2015-09-25 17:33:43 -0700 | [diff] [blame] | 9 | #include <weave/provider/test/fake_task_runner.h> |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 10 | #include <weave/provider/test/mock_bluetooth.h> |
| 11 | #include <weave/provider/test/mock_config_store.h> |
| 12 | #include <weave/provider/test/mock_dns_service_discovery.h> |
| 13 | #include <weave/provider/test/mock_http_client.h> |
| 14 | #include <weave/provider/test/mock_http_server.h> |
| 15 | #include <weave/provider/test/mock_network.h> |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 16 | #include <weave/provider/test/mock_wifi.h> |
Vitaly Buka | ef213d7 | 2015-10-07 15:54:58 -0700 | [diff] [blame] | 17 | #include <weave/test/mock_command.h> |
Vitaly Buka | a8ece8f | 2015-10-05 13:30:23 -0700 | [diff] [blame] | 18 | #include <weave/test/mock_device.h> |
Vitaly Buka | 0f6b2ec | 2015-08-20 15:35:19 -0700 | [diff] [blame] | 19 | #include <weave/test/unittest_utils.h> |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 20 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 21 | #include "src/bind_lambda.h" |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 22 | |
| 23 | using testing::_; |
Vitaly Buka | 65e1f21 | 2015-11-05 15:54:05 -0800 | [diff] [blame] | 24 | using testing::AtLeast; |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 25 | using testing::AtMost; |
| 26 | using testing::HasSubstr; |
Vitaly Buka | 65e1f21 | 2015-11-05 15:54:05 -0800 | [diff] [blame] | 27 | using testing::InSequence; |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 28 | using testing::Invoke; |
| 29 | using testing::InvokeWithoutArgs; |
| 30 | using testing::MatchesRegex; |
| 31 | using testing::Mock; |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 32 | using testing::Return; |
| 33 | using testing::ReturnRefOfCopy; |
| 34 | using testing::StartsWith; |
| 35 | using testing::StrictMock; |
| 36 | using testing::WithArgs; |
| 37 | |
| 38 | namespace weave { |
| 39 | |
Vitaly Buka | e69e4ee | 2015-10-26 18:30:14 -0700 | [diff] [blame] | 40 | namespace { |
| 41 | |
Vitaly Buka | 1a42e14 | 2015-10-10 18:15:15 -0700 | [diff] [blame] | 42 | using provider::HttpClient; |
| 43 | using provider::Network; |
| 44 | using provider::test::MockHttpClientResponse; |
Vitaly Buka | 0f6b2ec | 2015-08-20 15:35:19 -0700 | [diff] [blame] | 45 | using test::CreateDictionaryValue; |
| 46 | using test::ValueToString; |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 47 | |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 48 | const char kCommandDefs[] = R"({ |
| 49 | "base": { |
Alex Vakulenko | 2c7740a | 2015-11-30 08:51:29 -0800 | [diff] [blame] | 50 | "reboot": { |
| 51 | "minimalRole": "user" |
| 52 | }, |
Vitaly Buka | e5b2041 | 2015-09-30 15:41:28 -0700 | [diff] [blame] | 53 | "_shutdown": { |
Alex Vakulenko | 2c7740a | 2015-11-30 08:51:29 -0800 | [diff] [blame] | 54 | "minimalRole": "user", |
Vitaly Buka | e5b2041 | 2015-09-30 15:41:28 -0700 | [diff] [blame] | 55 | "parameters": {}, |
| 56 | "results": {} |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 57 | } |
| 58 | } |
| 59 | })"; |
| 60 | |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 61 | const char kDeviceResource[] = R"({ |
Vitaly Buka | 88272d5 | 2015-11-17 17:04:01 -0800 | [diff] [blame] | 62 | "kind": "weave#device", |
Johan Euphrosine | 0b7bb9f | 2015-09-29 01:11:21 -0700 | [diff] [blame] | 63 | "id": "CLOUD_ID", |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 64 | "channel": { |
| 65 | "supportedType": "pull" |
| 66 | }, |
| 67 | "deviceKind": "vendor", |
| 68 | "modelManifestId": "ABCDE", |
| 69 | "systemName": "", |
Vitaly Buka | a05eadb | 2015-09-29 16:38:24 -0700 | [diff] [blame] | 70 | "name": "TEST_NAME", |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 71 | "displayName": "", |
| 72 | "description": "Developer device", |
| 73 | "stateValidationEnabled": true, |
| 74 | "commandDefs":{ |
| 75 | "base": { |
| 76 | "reboot": { |
| 77 | "minimalRole": "user", |
Alex Vakulenko | 7e894da | 2015-11-23 11:47:49 -0800 | [diff] [blame] | 78 | "parameters": {"delay": {"type": "integer"}}, |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 79 | "results": {} |
| 80 | }, |
| 81 | "shutdown": { |
| 82 | "minimalRole": "user", |
| 83 | "parameters": {}, |
| 84 | "results": {} |
| 85 | } |
| 86 | } |
| 87 | }, |
| 88 | "state":{ |
| 89 | "base":{ |
| 90 | "firmwareVersion":"FIRMWARE_VERSION", |
| 91 | "localAnonymousAccessMaxRole":"viewer", |
| 92 | "localDiscoveryEnabled":true, |
| 93 | "localPairingEnabled":true, |
| 94 | "network":{ |
| 95 | } |
| 96 | }, |
| 97 | "power": {"battery_level":44} |
| 98 | } |
| 99 | })"; |
| 100 | |
| 101 | const char kRegistrationResponse[] = R"({ |
Vitaly Buka | 88272d5 | 2015-11-17 17:04:01 -0800 | [diff] [blame] | 102 | "kind": "weave#registrationTicket", |
Johan Euphrosine | 0b7bb9f | 2015-09-29 01:11:21 -0700 | [diff] [blame] | 103 | "id": "TICKET_ID", |
| 104 | "deviceId": "CLOUD_ID", |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 105 | "oauthClientId": "CLIENT_ID", |
| 106 | "userEmail": "USER@gmail.com", |
| 107 | "creationTimeMs": "1440087183738", |
| 108 | "expirationTimeMs": "1440087423738" |
| 109 | })"; |
| 110 | |
| 111 | const char kRegistrationFinalResponse[] = R"({ |
Vitaly Buka | 88272d5 | 2015-11-17 17:04:01 -0800 | [diff] [blame] | 112 | "kind": "weave#registrationTicket", |
Johan Euphrosine | 0b7bb9f | 2015-09-29 01:11:21 -0700 | [diff] [blame] | 113 | "id": "TICKET_ID", |
| 114 | "deviceId": "CLOUD_ID", |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 115 | "oauthClientId": "CLIENT_ID", |
| 116 | "userEmail": "USER@gmail.com", |
| 117 | "robotAccountEmail": "ROBO@gmail.com", |
| 118 | "robotAccountAuthorizationCode": "AUTH_CODE", |
| 119 | "creationTimeMs": "1440087183738", |
| 120 | "expirationTimeMs": "1440087423738" |
| 121 | })"; |
| 122 | |
| 123 | const char kAuthTokenResponse[] = R"({ |
| 124 | "access_token" : "ACCESS_TOKEN", |
| 125 | "token_type" : "Bearer", |
| 126 | "expires_in" : 3599, |
| 127 | "refresh_token" : "REFRESH_TOKEN" |
| 128 | })"; |
| 129 | |
| 130 | const char kStateDefs[] = R"({"power": {"battery_level":"integer"}})"; |
| 131 | |
| 132 | const char kStateDefaults[] = R"({"power": {"battery_level":44}})"; |
| 133 | |
Vitaly Buka | 3dc2f53 | 2015-09-08 18:01:32 -0700 | [diff] [blame] | 134 | MATCHER_P(MatchTxt, txt, "") { |
| 135 | std::vector<std::string> txt_copy = txt; |
| 136 | std::sort(txt_copy.begin(), txt_copy.end()); |
| 137 | std::vector<std::string> arg_copy = arg; |
| 138 | std::sort(arg_copy.begin(), arg_copy.end()); |
| 139 | return (arg_copy == txt_copy); |
| 140 | } |
| 141 | |
Vitaly Buka | e69e4ee | 2015-10-26 18:30:14 -0700 | [diff] [blame] | 142 | template <class Map> |
| 143 | std::set<typename Map::key_type> GetKeys(const Map& map) { |
| 144 | std::set<typename Map::key_type> result; |
| 145 | for (const auto& pair : map) |
| 146 | result.insert(pair.first); |
| 147 | return result; |
| 148 | } |
| 149 | |
| 150 | } // namespace |
| 151 | |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 152 | class WeaveTest : public ::testing::Test { |
| 153 | protected: |
Vitaly Buka | c5bdd17 | 2015-10-01 19:48:51 -0700 | [diff] [blame] | 154 | void SetUp() override {} |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 155 | |
Vitaly Buka | 1a42e14 | 2015-10-10 18:15:15 -0700 | [diff] [blame] | 156 | void ExpectRequest(HttpClient::Method method, |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 157 | const std::string& url, |
| 158 | const std::string& json_response) { |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 159 | EXPECT_CALL(http_client_, SendRequest(method, url, _, _, _)) |
Vitaly Buka | 1728037 | 2015-10-10 17:11:47 -0700 | [diff] [blame] | 160 | .WillOnce(WithArgs<4>(Invoke([json_response]( |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 161 | const HttpClient::SendRequestCallback& callback) { |
Vitaly Buka | 1728037 | 2015-10-10 17:11:47 -0700 | [diff] [blame] | 162 | std::unique_ptr<provider::test::MockHttpClientResponse> response{ |
| 163 | new StrictMock<provider::test::MockHttpClientResponse>}; |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 164 | EXPECT_CALL(*response, GetStatusCode()) |
| 165 | .Times(AtLeast(1)) |
| 166 | .WillRepeatedly(Return(200)); |
| 167 | EXPECT_CALL(*response, GetContentType()) |
| 168 | .Times(AtLeast(1)) |
| 169 | .WillRepeatedly(Return("application/json; charset=utf-8")); |
| 170 | EXPECT_CALL(*response, GetData()) |
| 171 | .Times(AtLeast(1)) |
Vitaly Buka | 4774df2 | 2015-10-09 12:36:22 -0700 | [diff] [blame] | 172 | .WillRepeatedly(Return(json_response)); |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 173 | callback.Run(std::move(response), nullptr); |
Vitaly Buka | 1728037 | 2015-10-10 17:11:47 -0700 | [diff] [blame] | 174 | }))); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 175 | } |
| 176 | |
| 177 | void InitConfigStore() { |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 178 | EXPECT_CALL(config_store_, SaveSettings("")).WillRepeatedly(Return()); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | void InitNetwork() { |
Vitaly Buka | 3ab6f6e | 2015-09-24 13:16:16 -0700 | [diff] [blame] | 182 | EXPECT_CALL(network_, AddConnectionChangedCallback(_)) |
| 183 | .WillRepeatedly(Invoke( |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 184 | [this](const provider::Network::ConnectionChangedCallback& cb) { |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 185 | network_callbacks_.push_back(cb); |
| 186 | })); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 187 | EXPECT_CALL(network_, GetConnectionState()) |
Vitaly Buka | 35f317d | 2015-09-27 22:54:39 -0700 | [diff] [blame] | 188 | .WillRepeatedly(Return(Network::State::kOffline)); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 189 | } |
| 190 | |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 191 | void InitDnsSd() { |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 192 | EXPECT_CALL(dns_sd_, PublishService(_, _, _)).WillRepeatedly(Return()); |
| 193 | EXPECT_CALL(dns_sd_, StopPublishing("_privet._tcp")).WillOnce(Return()); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 194 | } |
| 195 | |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 196 | void InitDnsSdPublishing(bool registered, const std::string& flags) { |
Vitaly Buka | 87eb788 | 2015-10-27 22:23:49 -0700 | [diff] [blame] | 197 | std::vector<std::string> txt{ |
| 198 | {"id=TEST_DEVICE_ID"}, {"flags=" + flags}, {"mmid=ABCDE"}, |
| 199 | {"services=developmentBoard"}, {"txtvers=3"}, {"ty=TEST_NAME"}}; |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 200 | if (registered) { |
Johan Euphrosine | 0b7bb9f | 2015-09-29 01:11:21 -0700 | [diff] [blame] | 201 | txt.push_back("gcd_id=CLOUD_ID"); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 202 | |
| 203 | // During registration device may announce itself twice: |
| 204 | // 1. with GCD ID but not connected (DB) |
| 205 | // 2. with GCD ID and connected (BB) |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 206 | EXPECT_CALL(dns_sd_, PublishService("_privet._tcp", 11, MatchTxt(txt))) |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 207 | .Times(AtMost(1)) |
| 208 | .WillOnce(Return()); |
| 209 | |
Vitaly Buka | 3dc2f53 | 2015-09-08 18:01:32 -0700 | [diff] [blame] | 210 | txt[1] = "flags=BB"; |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 211 | } |
| 212 | |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 213 | EXPECT_CALL(dns_sd_, PublishService("_privet._tcp", 11, MatchTxt(txt))) |
Vitaly Buka | bced5af | 2015-10-12 17:42:30 -0700 | [diff] [blame] | 214 | .Times(AtMost(1)) |
Vitaly Buka | 3dc2f53 | 2015-09-08 18:01:32 -0700 | [diff] [blame] | 215 | .WillOnce(Return()); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 216 | } |
| 217 | |
| 218 | void InitHttpServer() { |
| 219 | EXPECT_CALL(http_server_, GetHttpPort()).WillRepeatedly(Return(11)); |
| 220 | EXPECT_CALL(http_server_, GetHttpsPort()).WillRepeatedly(Return(12)); |
Alex Vakulenko | efee3a2 | 2015-11-17 15:08:38 -0800 | [diff] [blame] | 221 | EXPECT_CALL(http_server_, GetRequestTimeout()) |
| 222 | .WillRepeatedly(Return(base::TimeDelta::Max())); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 223 | EXPECT_CALL(http_server_, GetHttpsCertificateFingerprint()) |
Vitaly Buka | 138aec4 | 2015-10-08 10:17:48 -0700 | [diff] [blame] | 224 | .WillRepeatedly(Return(std::vector<uint8_t>{1, 2, 3})); |
Vitaly Buka | 1a39c81 | 2015-10-08 21:20:58 -0700 | [diff] [blame] | 225 | EXPECT_CALL(http_server_, AddHttpRequestHandler(_, _)) |
| 226 | .WillRepeatedly(Invoke( |
| 227 | [this](const std::string& path_prefix, |
| 228 | const provider::HttpServer::RequestHandlerCallback& cb) { |
Vitaly Buka | e69e4ee | 2015-10-26 18:30:14 -0700 | [diff] [blame] | 229 | http_handlers_[path_prefix] = cb; |
Vitaly Buka | 1a39c81 | 2015-10-08 21:20:58 -0700 | [diff] [blame] | 230 | })); |
| 231 | EXPECT_CALL(http_server_, AddHttpsRequestHandler(_, _)) |
Vitaly Buka | 01893cc | 2015-10-08 19:58:00 -0700 | [diff] [blame] | 232 | .WillRepeatedly(Invoke( |
| 233 | [this](const std::string& path_prefix, |
| 234 | const provider::HttpServer::RequestHandlerCallback& cb) { |
Vitaly Buka | e69e4ee | 2015-10-26 18:30:14 -0700 | [diff] [blame] | 235 | https_handlers_[path_prefix] = cb; |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 236 | })); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 237 | } |
| 238 | |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 239 | void InitDefaultExpectations() { |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 240 | InitConfigStore(); |
| 241 | InitNetwork(); |
Vitaly Buka | a05eadb | 2015-09-29 16:38:24 -0700 | [diff] [blame] | 242 | EXPECT_CALL(wifi_, StartAccessPoint(MatchesRegex("TEST_NAME.*prv"))) |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 243 | .WillOnce(Return()); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 244 | InitHttpServer(); |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 245 | InitDnsSd(); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 246 | } |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 247 | |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 248 | void StartDevice() { |
Vitaly Buka | c5bdd17 | 2015-10-01 19:48:51 -0700 | [diff] [blame] | 249 | device_ = weave::Device::Create(&config_store_, &task_runner_, |
| 250 | &http_client_, &network_, &dns_sd_, |
| 251 | &http_server_, &wifi_, &bluetooth_); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 252 | |
Vitaly Buka | e69e4ee | 2015-10-26 18:30:14 -0700 | [diff] [blame] | 253 | EXPECT_EQ((std::set<std::string>{ |
| 254 | "/privet/info", "/privet/v3/pairing/cancel", |
| 255 | "/privet/v3/pairing/confirm", "/privet/v3/pairing/start"}), |
| 256 | GetKeys(http_handlers_)); |
| 257 | EXPECT_EQ((std::set<std::string>{ |
Alex Vakulenko | efee3a2 | 2015-11-17 15:08:38 -0800 | [diff] [blame] | 258 | "/privet/info", "/privet/v3/auth", |
| 259 | "/privet/v3/checkForUpdates", "/privet/v3/commandDefs", |
Vitaly Buka | e69e4ee | 2015-10-26 18:30:14 -0700 | [diff] [blame] | 260 | "/privet/v3/commands/cancel", "/privet/v3/commands/execute", |
| 261 | "/privet/v3/commands/list", "/privet/v3/commands/status", |
| 262 | "/privet/v3/pairing/cancel", "/privet/v3/pairing/confirm", |
| 263 | "/privet/v3/pairing/start", "/privet/v3/setup/start", |
| 264 | "/privet/v3/setup/status", "/privet/v3/state"}), |
| 265 | GetKeys(https_handlers_)); |
| 266 | |
Vitaly Buka | 3110deb | 2015-10-06 19:54:09 -0700 | [diff] [blame] | 267 | device_->AddCommandDefinitionsFromJson(kCommandDefs); |
| 268 | device_->AddStateDefinitionsFromJson(kStateDefs); |
Vitaly Buka | 216e86d | 2015-10-06 20:23:02 -0700 | [diff] [blame] | 269 | device_->SetStatePropertiesFromJson(kStateDefaults, nullptr); |
Vitaly Buka | 0ac6ca6 | 2015-10-06 19:16:29 -0700 | [diff] [blame] | 270 | |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 271 | task_runner_.Run(); |
| 272 | } |
| 273 | |
Vitaly Buka | 35f317d | 2015-09-27 22:54:39 -0700 | [diff] [blame] | 274 | void NotifyNetworkChanged(provider::Network::State state, |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 275 | base::TimeDelta delay) { |
Vitaly Buka | 65e1f21 | 2015-11-05 15:54:05 -0800 | [diff] [blame] | 276 | auto task = [this, state] { |
| 277 | EXPECT_CALL(network_, GetConnectionState()).WillRepeatedly(Return(state)); |
| 278 | for (const auto& cb : network_callbacks_) |
| 279 | cb.Run(); |
| 280 | }; |
| 281 | |
| 282 | task_runner_.PostDelayedTask(FROM_HERE, base::Bind(task), delay); |
Vitaly Buka | 3884ce1 | 2015-09-21 13:48:48 -0700 | [diff] [blame] | 283 | } |
| 284 | |
Vitaly Buka | e69e4ee | 2015-10-26 18:30:14 -0700 | [diff] [blame] | 285 | std::map<std::string, provider::HttpServer::RequestHandlerCallback> |
| 286 | http_handlers_; |
| 287 | std::map<std::string, provider::HttpServer::RequestHandlerCallback> |
| 288 | https_handlers_; |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 289 | |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 290 | StrictMock<provider::test::MockConfigStore> config_store_; |
Vitaly Buka | 727f3e6 | 2015-09-25 17:33:43 -0700 | [diff] [blame] | 291 | StrictMock<provider::test::FakeTaskRunner> task_runner_; |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 292 | StrictMock<provider::test::MockHttpClient> http_client_; |
| 293 | StrictMock<provider::test::MockNetwork> network_; |
| 294 | StrictMock<provider::test::MockDnsServiceDiscovery> dns_sd_; |
| 295 | StrictMock<provider::test::MockHttpServer> http_server_; |
| 296 | StrictMock<provider::test::MockWifi> wifi_; |
| 297 | StrictMock<provider::test::MockBluetooth> bluetooth_; |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 298 | |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 299 | std::vector<provider::Network::ConnectionChangedCallback> network_callbacks_; |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 300 | |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 301 | std::unique_ptr<weave::Device> device_; |
| 302 | }; |
| 303 | |
Vitaly Buka | ef213d7 | 2015-10-07 15:54:58 -0700 | [diff] [blame] | 304 | TEST_F(WeaveTest, Mocks) { |
Vitaly Buka | a8ece8f | 2015-10-05 13:30:23 -0700 | [diff] [blame] | 305 | // Test checks if mock implements entire interface and mock can be |
| 306 | // instantiated. |
| 307 | test::MockDevice device; |
Vitaly Buka | ef213d7 | 2015-10-07 15:54:58 -0700 | [diff] [blame] | 308 | test::MockCommand command; |
Vitaly Buka | a8ece8f | 2015-10-05 13:30:23 -0700 | [diff] [blame] | 309 | } |
| 310 | |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 311 | TEST_F(WeaveTest, StartMinimal) { |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 312 | InitConfigStore(); |
Vitaly Buka | c5bdd17 | 2015-10-01 19:48:51 -0700 | [diff] [blame] | 313 | device_ = weave::Device::Create(&config_store_, &task_runner_, &http_client_, |
| 314 | &network_, nullptr, nullptr, &wifi_, nullptr); |
Vitaly Buka | b1041e7 | 2015-09-21 15:26:51 -0700 | [diff] [blame] | 315 | } |
| 316 | |
| 317 | TEST_F(WeaveTest, StartNoWifi) { |
| 318 | InitConfigStore(); |
| 319 | InitNetwork(); |
| 320 | InitHttpServer(); |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 321 | InitDnsSd(); |
| 322 | InitDnsSdPublishing(false, "CB"); |
Vitaly Buka | b1041e7 | 2015-09-21 15:26:51 -0700 | [diff] [blame] | 323 | |
Vitaly Buka | c5bdd17 | 2015-10-01 19:48:51 -0700 | [diff] [blame] | 324 | device_ = weave::Device::Create(&config_store_, &task_runner_, &http_client_, |
| 325 | &network_, &dns_sd_, &http_server_, nullptr, |
| 326 | &bluetooth_); |
Vitaly Buka | 3110deb | 2015-10-06 19:54:09 -0700 | [diff] [blame] | 327 | device_->AddCommandDefinitionsFromJson(kCommandDefs); |
Vitaly Buka | b1041e7 | 2015-09-21 15:26:51 -0700 | [diff] [blame] | 328 | |
Vitaly Buka | b1041e7 | 2015-09-21 15:26:51 -0700 | [diff] [blame] | 329 | task_runner_.Run(); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 330 | } |
| 331 | |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 332 | class WeaveBasicTest : public WeaveTest { |
| 333 | public: |
| 334 | void SetUp() override { |
| 335 | WeaveTest::SetUp(); |
Vitaly Buka | 3884ce1 | 2015-09-21 13:48:48 -0700 | [diff] [blame] | 336 | |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 337 | InitDefaultExpectations(); |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 338 | InitDnsSdPublishing(false, "DB"); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 339 | } |
| 340 | }; |
| 341 | |
| 342 | TEST_F(WeaveBasicTest, Start) { |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 343 | StartDevice(); |
| 344 | } |
| 345 | |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 346 | TEST_F(WeaveBasicTest, Register) { |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 347 | EXPECT_CALL(network_, OpenSslSocket(_, _, _)).WillRepeatedly(Return()); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 348 | StartDevice(); |
| 349 | |
| 350 | auto draft = CreateDictionaryValue(kDeviceResource); |
| 351 | auto response = CreateDictionaryValue(kRegistrationResponse); |
| 352 | response->Set("deviceDraft", draft->DeepCopy()); |
Vitaly Buka | 0d7aac8 | 2015-11-16 23:02:24 -0800 | [diff] [blame] | 353 | ExpectRequest(HttpClient::Method::kPatch, |
| 354 | "https://www.googleapis.com/weave/v1/registrationTickets/" |
| 355 | "TICKET_ID?key=TEST_API_KEY", |
| 356 | ValueToString(*response)); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 357 | |
| 358 | response = CreateDictionaryValue(kRegistrationFinalResponse); |
| 359 | response->Set("deviceDraft", draft->DeepCopy()); |
Vitaly Buka | 0d7aac8 | 2015-11-16 23:02:24 -0800 | [diff] [blame] | 360 | ExpectRequest(HttpClient::Method::kPost, |
| 361 | "https://www.googleapis.com/weave/v1/registrationTickets/" |
| 362 | "TICKET_ID/finalize?key=TEST_API_KEY", |
| 363 | ValueToString(*response)); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 364 | |
Vitaly Buka | 1a42e14 | 2015-10-10 18:15:15 -0700 | [diff] [blame] | 365 | ExpectRequest(HttpClient::Method::kPost, |
| 366 | "https://accounts.google.com/o/oauth2/token", |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 367 | kAuthTokenResponse); |
| 368 | |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 369 | InitDnsSdPublishing(true, "DB"); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 370 | |
Vitaly Buka | 12870bd | 2015-10-08 23:49:39 -0700 | [diff] [blame] | 371 | bool done = false; |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 372 | device_->Register("TICKET_ID", base::Bind([this, &done](ErrorPtr error) { |
| 373 | EXPECT_FALSE(error); |
Vitaly Buka | 12870bd | 2015-10-08 23:49:39 -0700 | [diff] [blame] | 374 | done = true; |
| 375 | task_runner_.Break(); |
| 376 | EXPECT_EQ("CLOUD_ID", device_->GetSettings().cloud_id); |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 377 | })); |
Vitaly Buka | 12870bd | 2015-10-08 23:49:39 -0700 | [diff] [blame] | 378 | task_runner_.Run(); |
| 379 | EXPECT_TRUE(done); |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 380 | } |
| 381 | |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 382 | class WeaveWiFiSetupTest : public WeaveTest { |
| 383 | public: |
| 384 | void SetUp() override { |
| 385 | WeaveTest::SetUp(); |
| 386 | |
| 387 | InitConfigStore(); |
| 388 | InitHttpServer(); |
| 389 | InitNetwork(); |
Vitaly Buka | beddc60 | 2015-09-24 15:28:03 -0700 | [diff] [blame] | 390 | InitDnsSd(); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 391 | |
| 392 | EXPECT_CALL(network_, GetConnectionState()) |
Vitaly Buka | efad5b2 | 2015-10-08 10:02:14 -0700 | [diff] [blame] | 393 | .WillRepeatedly(Return(provider::Network::State::kOnline)); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 394 | } |
| 395 | }; |
| 396 | |
| 397 | TEST_F(WeaveWiFiSetupTest, StartOnlineNoPrevSsid) { |
| 398 | StartDevice(); |
| 399 | |
| 400 | // Short disconnect. |
Vitaly Buka | 35f317d | 2015-09-27 22:54:39 -0700 | [diff] [blame] | 401 | NotifyNetworkChanged(provider::Network::State::kOffline, {}); |
Vitaly Buka | efad5b2 | 2015-10-08 10:02:14 -0700 | [diff] [blame] | 402 | NotifyNetworkChanged(provider::Network::State::kOnline, |
Vitaly Buka | 3884ce1 | 2015-09-21 13:48:48 -0700 | [diff] [blame] | 403 | base::TimeDelta::FromSeconds(10)); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 404 | task_runner_.Run(); |
| 405 | |
| 406 | // Long disconnect. |
Vitaly Buka | 35f317d | 2015-09-27 22:54:39 -0700 | [diff] [blame] | 407 | NotifyNetworkChanged(Network::State::kOffline, {}); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 408 | auto offline_from = task_runner_.GetClock()->Now(); |
Vitaly Buka | a05eadb | 2015-09-29 16:38:24 -0700 | [diff] [blame] | 409 | EXPECT_CALL(wifi_, StartAccessPoint(MatchesRegex("TEST_NAME.*prv"))) |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 410 | .WillOnce(InvokeWithoutArgs([this, offline_from]() { |
| 411 | EXPECT_GT(task_runner_.GetClock()->Now() - offline_from, |
| 412 | base::TimeDelta::FromMinutes(1)); |
Vitaly Buka | caf42bd | 2015-09-16 11:23:23 -0700 | [diff] [blame] | 413 | task_runner_.Break(); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 414 | })); |
| 415 | task_runner_.Run(); |
| 416 | } |
| 417 | |
| 418 | // If device has previously configured WiFi it will run AP for limited time |
| 419 | // after which it will try to re-connect. |
| 420 | TEST_F(WeaveWiFiSetupTest, StartOnlineWithPrevSsid) { |
| 421 | EXPECT_CALL(config_store_, LoadSettings()) |
| 422 | .WillRepeatedly(Return(R"({"last_configured_ssid": "TEST_ssid"})")); |
| 423 | StartDevice(); |
| 424 | |
| 425 | // Long disconnect. |
Vitaly Buka | 35f317d | 2015-09-27 22:54:39 -0700 | [diff] [blame] | 426 | NotifyNetworkChanged(Network::State::kOffline, {}); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 427 | |
| 428 | for (int i = 0; i < 5; ++i) { |
| 429 | auto offline_from = task_runner_.GetClock()->Now(); |
| 430 | // Temporarily offline mode. |
Vitaly Buka | a05eadb | 2015-09-29 16:38:24 -0700 | [diff] [blame] | 431 | EXPECT_CALL(wifi_, StartAccessPoint(MatchesRegex("TEST_NAME.*prv"))) |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 432 | .WillOnce(InvokeWithoutArgs([this, &offline_from]() { |
| 433 | EXPECT_GT(task_runner_.GetClock()->Now() - offline_from, |
| 434 | base::TimeDelta::FromMinutes(1)); |
| 435 | task_runner_.Break(); |
| 436 | })); |
| 437 | task_runner_.Run(); |
| 438 | |
| 439 | // Try to reconnect again. |
| 440 | offline_from = task_runner_.GetClock()->Now(); |
Vitaly Buka | 1fd619a | 2015-09-24 11:46:05 -0700 | [diff] [blame] | 441 | EXPECT_CALL(wifi_, StopAccessPoint()) |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 442 | .WillOnce(InvokeWithoutArgs([this, offline_from]() { |
| 443 | EXPECT_GT(task_runner_.GetClock()->Now() - offline_from, |
| 444 | base::TimeDelta::FromMinutes(5)); |
| 445 | task_runner_.Break(); |
| 446 | })); |
| 447 | task_runner_.Run(); |
| 448 | } |
| 449 | |
Vitaly Buka | efad5b2 | 2015-10-08 10:02:14 -0700 | [diff] [blame] | 450 | NotifyNetworkChanged(Network::State::kOnline, {}); |
Vitaly Buka | ca365fb | 2015-09-15 17:38:41 -0700 | [diff] [blame] | 451 | task_runner_.Run(); |
| 452 | } |
| 453 | |
Vitaly Buka | caf42bd | 2015-09-16 11:23:23 -0700 | [diff] [blame] | 454 | TEST_F(WeaveWiFiSetupTest, StartOfflineWithSsid) { |
| 455 | EXPECT_CALL(config_store_, LoadSettings()) |
| 456 | .WillRepeatedly(Return(R"({"last_configured_ssid": "TEST_ssid"})")); |
| 457 | EXPECT_CALL(network_, GetConnectionState()) |
Vitaly Buka | 35f317d | 2015-09-27 22:54:39 -0700 | [diff] [blame] | 458 | .WillRepeatedly(Return(Network::State::kOffline)); |
Vitaly Buka | caf42bd | 2015-09-16 11:23:23 -0700 | [diff] [blame] | 459 | |
| 460 | auto offline_from = task_runner_.GetClock()->Now(); |
Vitaly Buka | a05eadb | 2015-09-29 16:38:24 -0700 | [diff] [blame] | 461 | EXPECT_CALL(wifi_, StartAccessPoint(MatchesRegex("TEST_NAME.*prv"))) |
Vitaly Buka | caf42bd | 2015-09-16 11:23:23 -0700 | [diff] [blame] | 462 | .WillOnce(InvokeWithoutArgs([this, &offline_from]() { |
| 463 | EXPECT_GT(task_runner_.GetClock()->Now() - offline_from, |
| 464 | base::TimeDelta::FromMinutes(1)); |
| 465 | task_runner_.Break(); |
| 466 | })); |
| 467 | |
| 468 | StartDevice(); |
| 469 | } |
| 470 | |
Vitaly Buka | 65e1f21 | 2015-11-05 15:54:05 -0800 | [diff] [blame] | 471 | TEST_F(WeaveWiFiSetupTest, OfflineLongTimeWithNoSsid) { |
| 472 | EXPECT_CALL(network_, GetConnectionState()) |
| 473 | .WillRepeatedly(Return(Network::State::kOffline)); |
| 474 | NotifyNetworkChanged(provider::Network::State::kOnline, |
| 475 | base::TimeDelta::FromHours(15)); |
| 476 | |
| 477 | { |
| 478 | InSequence s; |
| 479 | auto time_stamp = task_runner_.GetClock()->Now(); |
| 480 | |
| 481 | EXPECT_CALL(wifi_, StartAccessPoint(MatchesRegex("TEST_NAME.*prv"))) |
| 482 | .WillOnce(InvokeWithoutArgs([this, &time_stamp]() { |
| 483 | EXPECT_LE(task_runner_.GetClock()->Now() - time_stamp, |
| 484 | base::TimeDelta::FromMinutes(1)); |
| 485 | time_stamp = task_runner_.GetClock()->Now(); |
| 486 | })); |
| 487 | |
| 488 | EXPECT_CALL(wifi_, StopAccessPoint()) |
| 489 | .WillOnce(InvokeWithoutArgs([this, &time_stamp]() { |
| 490 | EXPECT_GT(task_runner_.GetClock()->Now() - time_stamp, |
| 491 | base::TimeDelta::FromMinutes(5)); |
| 492 | time_stamp = task_runner_.GetClock()->Now(); |
| 493 | task_runner_.Break(); |
| 494 | })); |
| 495 | } |
| 496 | |
| 497 | StartDevice(); |
| 498 | } |
| 499 | |
| 500 | TEST_F(WeaveWiFiSetupTest, OfflineLongTimeWithSsid) { |
| 501 | EXPECT_CALL(config_store_, LoadSettings()) |
| 502 | .WillRepeatedly(Return(R"({"last_configured_ssid": "TEST_ssid"})")); |
| 503 | EXPECT_CALL(network_, GetConnectionState()) |
| 504 | .WillRepeatedly(Return(Network::State::kOffline)); |
| 505 | NotifyNetworkChanged(provider::Network::State::kOnline, |
| 506 | base::TimeDelta::FromHours(15)); |
| 507 | |
| 508 | { |
| 509 | InSequence s; |
| 510 | auto time_stamp = task_runner_.GetClock()->Now(); |
| 511 | for (size_t i = 0; i < 10; ++i) { |
| 512 | EXPECT_CALL(wifi_, StartAccessPoint(MatchesRegex("TEST_NAME.*prv"))) |
| 513 | .WillOnce(InvokeWithoutArgs([this, &time_stamp]() { |
| 514 | EXPECT_GT(task_runner_.GetClock()->Now() - time_stamp, |
| 515 | base::TimeDelta::FromMinutes(1)); |
| 516 | time_stamp = task_runner_.GetClock()->Now(); |
| 517 | })); |
| 518 | |
| 519 | EXPECT_CALL(wifi_, StopAccessPoint()) |
| 520 | .WillOnce(InvokeWithoutArgs([this, &time_stamp]() { |
| 521 | EXPECT_GT(task_runner_.GetClock()->Now() - time_stamp, |
| 522 | base::TimeDelta::FromMinutes(5)); |
| 523 | time_stamp = task_runner_.GetClock()->Now(); |
| 524 | })); |
| 525 | } |
| 526 | |
| 527 | EXPECT_CALL(wifi_, StartAccessPoint(MatchesRegex("TEST_NAME.*prv"))) |
| 528 | .WillOnce(InvokeWithoutArgs([this]() { task_runner_.Break(); })); |
| 529 | } |
| 530 | |
| 531 | StartDevice(); |
| 532 | } |
| 533 | |
Vitaly Buka | 11b2f23 | 2015-08-20 13:55:41 -0700 | [diff] [blame] | 534 | } // namespace weave |