OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium 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 "chrome/browser/media/router/discovery/dial/device_description_service.
h" |
| 6 |
| 7 #include "base/strings/stringprintf.h" |
| 8 #include "base/test/mock_callback.h" |
| 9 #include "chrome/browser/media/router/discovery/dial/device_description_fetcher.
h" |
| 10 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h" |
| 11 #include "chrome/browser/media/router/discovery/dial/parsed_dial_device_descript
ion.h" |
| 12 #include "chrome/browser/media/router/discovery/dial/safe_dial_device_descriptio
n_parser.h" |
| 13 #include "chrome/test/base/testing_profile.h" |
| 14 #include "content/public/test/test_browser_thread_bundle.h" |
| 15 #include "testing/gmock/include/gmock/gmock.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" |
| 17 |
| 18 using ::testing::_; |
| 19 using ::testing::Return; |
| 20 using ::testing::SaveArg; |
| 21 |
| 22 // Create Test Data |
| 23 namespace { |
| 24 |
| 25 media_router::DialDeviceData CreateDialDeviceData(int num) { |
| 26 media_router::DialDeviceData device_data( |
| 27 base::StringPrintf("Device id %d", num), |
| 28 GURL(base::StringPrintf("http://192.168.1.%d/dd.xml", num)), |
| 29 base::Time::Now()); |
| 30 device_data.set_label(base::StringPrintf("Device label %d", num)); |
| 31 return device_data; |
| 32 } |
| 33 |
| 34 media_router::DialDeviceDescriptionData CreateDialDeviceDescriptionData( |
| 35 int num) { |
| 36 return media_router::DialDeviceDescriptionData( |
| 37 "", GURL(base::StringPrintf("http://192.168.1.%d/apps", num))); |
| 38 } |
| 39 |
| 40 chrome::mojom::DialDeviceDescriptionPtr CreateDialDeviceDescriptionPtr( |
| 41 int num) { |
| 42 chrome::mojom::DialDeviceDescriptionPtr description_ptr = |
| 43 chrome::mojom::DialDeviceDescription::New(); |
| 44 description_ptr->friendly_name = base::StringPrintf("Friendly name %d", num); |
| 45 description_ptr->model_name = base::StringPrintf("Model name %d", num); |
| 46 description_ptr->unique_id = base::StringPrintf("Unique ID %d", num); |
| 47 return description_ptr; |
| 48 } |
| 49 |
| 50 media_router::ParsedDialDeviceDescription CreateParsedDialDeviceDescription( |
| 51 int num) { |
| 52 media_router::ParsedDialDeviceDescription description_data; |
| 53 description_data.app_url = |
| 54 GURL(base::StringPrintf("http://192.168.1.%d/apps", num)); |
| 55 description_data.friendly_name = base::StringPrintf("Friendly name %d", num); |
| 56 description_data.model_name = base::StringPrintf("Model name %d", num); |
| 57 description_data.unique_id = base::StringPrintf("Unique ID %d", num); |
| 58 return description_data; |
| 59 } |
| 60 |
| 61 } // namespace |
| 62 |
| 63 namespace media_router { |
| 64 |
| 65 class TestSafeDialDeviceDescriptionParser |
| 66 : public SafeDialDeviceDescriptionParser { |
| 67 public: |
| 68 ~TestSafeDialDeviceDescriptionParser() override {} |
| 69 |
| 70 MOCK_METHOD2(Start, |
| 71 void(const std::string& xml_text, |
| 72 const DeviceDescriptionCallback& callback)); |
| 73 }; |
| 74 |
| 75 class TestDeviceDescriptionService : public DeviceDescriptionService { |
| 76 public: |
| 77 TestDeviceDescriptionService( |
| 78 const DeviceDescriptionParseSuccessCallback& success_cb, |
| 79 const DeviceDescriptionParseErrorCallback& error_cb) |
| 80 : DeviceDescriptionService(success_cb, error_cb) {} |
| 81 |
| 82 MOCK_METHOD0(CreateSafeParser, SafeDialDeviceDescriptionParser*()); |
| 83 }; |
| 84 |
| 85 class DeviceDescriptionServiceTest : public ::testing::Test { |
| 86 public: |
| 87 DeviceDescriptionServiceTest() |
| 88 : device_description_service_(mock_success_cb_.Get(), |
| 89 mock_error_cb_.Get()), |
| 90 fetcher_map_( |
| 91 device_description_service_.device_description_fetcher_map_), |
| 92 description_cache_(device_description_service_.description_cache_), |
| 93 thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {} |
| 94 |
| 95 TestDeviceDescriptionService* device_description_service() { |
| 96 return &device_description_service_; |
| 97 } |
| 98 |
| 99 void AddToCache(const std::string& device_label, |
| 100 const ParsedDialDeviceDescription& description_data, |
| 101 bool expired) { |
| 102 DeviceDescriptionService::CacheEntry cache_entry; |
| 103 cache_entry.expire_time = base::Time::Now(); |
| 104 if (!expired) |
| 105 cache_entry.expire_time += base::TimeDelta::FromHours(12); |
| 106 cache_entry.description_data = description_data; |
| 107 description_cache_[device_label] = cache_entry; |
| 108 } |
| 109 |
| 110 void SetTestParser( |
| 111 std::unique_ptr<TestSafeDialDeviceDescriptionParser> test_parser) { |
| 112 if (device_description_service_.parser_) |
| 113 return; |
| 114 device_description_service_.parser_ = std::move(test_parser); |
| 115 } |
| 116 |
| 117 void OnDeviceDescriptionFetchComplete(int num) { |
| 118 auto device_data = CreateDialDeviceData(num); |
| 119 auto description_response_data = CreateDialDeviceDescriptionData(num); |
| 120 auto parsed_description_data = CreateParsedDialDeviceDescription(num); |
| 121 |
| 122 EXPECT_CALL(mock_success_cb_, Run(device_data, parsed_description_data)); |
| 123 |
| 124 device_description_service_.OnDeviceDescriptionFetchComplete( |
| 125 device_data, description_response_data); |
| 126 device_description_service_.OnParsedDeviceDescription( |
| 127 device_data, description_response_data.app_url, |
| 128 CreateDialDeviceDescriptionPtr(num)); |
| 129 } |
| 130 |
| 131 void TestOnParsedDeviceDescription( |
| 132 chrome::mojom::DialDeviceDescriptionPtr description_ptr, |
| 133 const std::string& error_message) { |
| 134 GURL app_url("http://192.168.1.1/apps"); |
| 135 auto device_data = CreateDialDeviceData(1); |
| 136 auto description_data = CreateParsedDialDeviceDescription(1); |
| 137 |
| 138 if (!error_message.empty()) { |
| 139 EXPECT_CALL(mock_error_cb_, Run(device_data, error_message)); |
| 140 } else { |
| 141 EXPECT_CALL(mock_success_cb_, Run(device_data, description_data)); |
| 142 } |
| 143 device_description_service()->OnParsedDeviceDescription( |
| 144 device_data, app_url, std::move(description_ptr)); |
| 145 } |
| 146 |
| 147 protected: |
| 148 base::MockCallback< |
| 149 DeviceDescriptionService::DeviceDescriptionParseSuccessCallback> |
| 150 mock_success_cb_; |
| 151 base::MockCallback< |
| 152 DeviceDescriptionService::DeviceDescriptionParseErrorCallback> |
| 153 mock_error_cb_; |
| 154 |
| 155 TestDeviceDescriptionService device_description_service_; |
| 156 std::map<std::string, std::unique_ptr<DeviceDescriptionFetcher>>& |
| 157 fetcher_map_; |
| 158 std::map<std::string, DeviceDescriptionService::CacheEntry>& |
| 159 description_cache_; |
| 160 |
| 161 const content::TestBrowserThreadBundle thread_bundle_; |
| 162 TestingProfile profile_; |
| 163 }; |
| 164 |
| 165 TEST_F(DeviceDescriptionServiceTest, TestGetDeviceDescriptionFromCache) { |
| 166 auto device_data = CreateDialDeviceData(1); |
| 167 auto description_data = CreateParsedDialDeviceDescription(1); |
| 168 EXPECT_CALL(mock_success_cb_, Run(device_data, description_data)); |
| 169 |
| 170 AddToCache(device_data.label(), description_data, false /* expired */); |
| 171 |
| 172 std::vector<DialDeviceData> devices = {device_data}; |
| 173 device_description_service()->GetDeviceDescriptions(devices, nullptr); |
| 174 } |
| 175 |
| 176 TEST_F(DeviceDescriptionServiceTest, TestGetDeviceDescriptionFetchURL) { |
| 177 DialDeviceData device_data = CreateDialDeviceData(1); |
| 178 std::vector<DialDeviceData> devices = {device_data}; |
| 179 |
| 180 // Create Fetcher |
| 181 EXPECT_TRUE(fetcher_map_.empty()); |
| 182 device_description_service()->GetDeviceDescriptions( |
| 183 devices, profile_.GetRequestContext()); |
| 184 EXPECT_EQ(size_t(1), fetcher_map_.size()); |
| 185 |
| 186 // Remove fetcher and create safe parser |
| 187 auto test_parser = base::MakeUnique<TestSafeDialDeviceDescriptionParser>(); |
| 188 EXPECT_CALL(*test_parser, Start(_, _)); |
| 189 |
| 190 SetTestParser(std::move(test_parser)); |
| 191 OnDeviceDescriptionFetchComplete(1); |
| 192 } |
| 193 |
| 194 TEST_F(DeviceDescriptionServiceTest, TestGetDeviceDescriptionFetchURLError) { |
| 195 DialDeviceData device_data = CreateDialDeviceData(1); |
| 196 std::vector<DialDeviceData> devices; |
| 197 devices.push_back(device_data); |
| 198 |
| 199 // Create Fetcher |
| 200 EXPECT_TRUE(fetcher_map_.empty()); |
| 201 device_description_service()->GetDeviceDescriptions( |
| 202 devices, profile_.GetRequestContext()); |
| 203 EXPECT_EQ(size_t(1), fetcher_map_.size()); |
| 204 |
| 205 EXPECT_CALL(mock_error_cb_, Run(device_data, "")); |
| 206 |
| 207 device_description_service()->OnDeviceDescriptionFetchError(device_data, ""); |
| 208 EXPECT_TRUE(fetcher_map_.empty()); |
| 209 } |
| 210 |
| 211 TEST_F(DeviceDescriptionServiceTest, |
| 212 TestGetDeviceDescriptionRemoveOutDatedFetchers) { |
| 213 DialDeviceData device_data_1 = CreateDialDeviceData(1); |
| 214 DialDeviceData device_data_2 = CreateDialDeviceData(2); |
| 215 DialDeviceData device_data_3 = CreateDialDeviceData(3); |
| 216 |
| 217 std::vector<DialDeviceData> devices; |
| 218 devices.push_back(device_data_1); |
| 219 devices.push_back(device_data_2); |
| 220 |
| 221 // insert fetchers |
| 222 device_description_service()->GetDeviceDescriptions( |
| 223 devices, profile_.GetRequestContext()); |
| 224 |
| 225 // Keep fetchers non exist in current device list and remove fetchers with |
| 226 // different description url. |
| 227 GURL new_url_2 = GURL("http://example.com"); |
| 228 device_data_2.set_device_description_url(new_url_2); |
| 229 |
| 230 devices.clear(); |
| 231 devices.push_back(device_data_2); |
| 232 devices.push_back(device_data_3); |
| 233 device_description_service()->GetDeviceDescriptions( |
| 234 devices, profile_.GetRequestContext()); |
| 235 |
| 236 EXPECT_EQ(size_t(3), fetcher_map_.size()); |
| 237 |
| 238 auto* description_fetcher = fetcher_map_[device_data_2.label()].get(); |
| 239 EXPECT_EQ(new_url_2, description_fetcher->device_description_url()); |
| 240 |
| 241 EXPECT_CALL(mock_error_cb_, Run(_, _)).Times(3); |
| 242 device_description_service()->OnDeviceDescriptionFetchError(device_data_1, |
| 243 ""); |
| 244 device_description_service()->OnDeviceDescriptionFetchError(device_data_2, |
| 245 ""); |
| 246 device_description_service()->OnDeviceDescriptionFetchError(device_data_3, |
| 247 ""); |
| 248 } |
| 249 |
| 250 TEST_F(DeviceDescriptionServiceTest, TestCleanUpCacheEntries) { |
| 251 DialDeviceData device_data_1 = CreateDialDeviceData(1); |
| 252 DialDeviceData device_data_2 = CreateDialDeviceData(2); |
| 253 DialDeviceData device_data_3 = CreateDialDeviceData(3); |
| 254 |
| 255 AddToCache(device_data_1.label(), ParsedDialDeviceDescription(), |
| 256 true /* expired */); |
| 257 AddToCache(device_data_2.label(), ParsedDialDeviceDescription(), |
| 258 true /* expired */); |
| 259 AddToCache(device_data_3.label(), ParsedDialDeviceDescription(), |
| 260 false /* expired */); |
| 261 |
| 262 device_description_service_.CleanUpCacheEntries(); |
| 263 EXPECT_EQ(size_t(1), description_cache_.size()); |
| 264 EXPECT_TRUE(base::ContainsKey(description_cache_, device_data_3.label())); |
| 265 |
| 266 AddToCache(device_data_3.label(), ParsedDialDeviceDescription(), |
| 267 true /* expired*/); |
| 268 device_description_service_.CleanUpCacheEntries(); |
| 269 EXPECT_TRUE(description_cache_.empty()); |
| 270 } |
| 271 |
| 272 TEST_F(DeviceDescriptionServiceTest, TestOnParsedDeviceDescription) { |
| 273 GURL app_url("http://192.168.1.1/apps"); |
| 274 DialDeviceData device_data = CreateDialDeviceData(1); |
| 275 |
| 276 // null_ptr |
| 277 std::string error_message = "Failed to parse device description XML"; |
| 278 TestOnParsedDeviceDescription(nullptr, error_message); |
| 279 |
| 280 // Empty field |
| 281 error_message = "Failed to process fetch result"; |
| 282 TestOnParsedDeviceDescription(chrome::mojom::DialDeviceDescription::New(), |
| 283 error_message); |
| 284 |
| 285 // Valid device description ptr and put in cache |
| 286 auto description_ptr = CreateDialDeviceDescriptionPtr(1); |
| 287 TestOnParsedDeviceDescription(std::move(description_ptr), ""); |
| 288 EXPECT_EQ(size_t(1), description_cache_.size()); |
| 289 |
| 290 // Valid device description ptr and skip cache. |
| 291 size_t cache_num = 256; |
| 292 for (size_t i = 0; i < cache_num; i++) { |
| 293 AddToCache(std::to_string(i), ParsedDialDeviceDescription(), |
| 294 false /* expired */); |
| 295 } |
| 296 |
| 297 EXPECT_EQ(size_t(cache_num + 1), description_cache_.size()); |
| 298 description_ptr = CreateDialDeviceDescriptionPtr(1); |
| 299 TestOnParsedDeviceDescription(std::move(description_ptr), ""); |
| 300 EXPECT_EQ(size_t(cache_num + 1), description_cache_.size()); |
| 301 } |
| 302 |
| 303 TEST_F(DeviceDescriptionServiceTest, TestSafeParserProperlyCreated) { |
| 304 DialDeviceData device_data_1 = CreateDialDeviceData(1); |
| 305 DialDeviceData device_data_2 = CreateDialDeviceData(2); |
| 306 DialDeviceData device_data_3 = CreateDialDeviceData(3); |
| 307 |
| 308 std::vector<DialDeviceData> devices = {device_data_1, device_data_2, |
| 309 device_data_3}; |
| 310 |
| 311 // insert fetchers |
| 312 device_description_service()->GetDeviceDescriptions( |
| 313 devices, profile_.GetRequestContext()); |
| 314 auto test_parser = base::MakeUnique<TestSafeDialDeviceDescriptionParser>(); |
| 315 EXPECT_CALL(*test_parser, Start(_, _)).Times(3); |
| 316 |
| 317 EXPECT_FALSE(device_description_service()->parser_); |
| 318 SetTestParser(std::move(test_parser)); |
| 319 OnDeviceDescriptionFetchComplete(1); |
| 320 |
| 321 EXPECT_TRUE(device_description_service()->parser_); |
| 322 OnDeviceDescriptionFetchComplete(2); |
| 323 OnDeviceDescriptionFetchComplete(3); |
| 324 |
| 325 EXPECT_FALSE(device_description_service()->parser_); |
| 326 } |
| 327 |
| 328 } // namespace media_router |
OLD | NEW |