Web MIDI: running status should be reset on receiving a system message
[chromium-blink-merge.git] / components / search_provider_logos / logo_tracker_unittest.cc
blobc5c1f35a9208fd6ac8c62b859263ec67ea42befa
1 // Copyright 2014 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.
5 #include "components/search_provider_logos/logo_tracker.h"
7 #include <vector>
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/file_path.h"
13 #include "base/json/json_writer.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_vector.h"
16 #include "base/run_loop.h"
17 #include "base/strings/string_piece.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/test/simple_test_clock.h"
20 #include "base/time/time.h"
21 #include "base/values.h"
22 #include "components/search_provider_logos/google_logo_api.h"
23 #include "net/base/url_util.h"
24 #include "net/http/http_response_headers.h"
25 #include "net/http/http_status_code.h"
26 #include "net/url_request/test_url_fetcher_factory.h"
27 #include "net/url_request/url_request_status.h"
28 #include "net/url_request/url_request_test_util.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "ui/gfx/image/image.h"
33 using ::testing::_;
34 using ::testing::AnyNumber;
35 using ::testing::AtMost;
36 using ::testing::InSequence;
37 using ::testing::Invoke;
38 using ::testing::Mock;
39 using ::testing::NiceMock;
40 using ::testing::Return;
42 namespace search_provider_logos {
44 namespace {
46 bool AreImagesSameSize(const SkBitmap& bitmap1, const SkBitmap& bitmap2) {
47 return bitmap1.width() == bitmap2.width() &&
48 bitmap1.height() == bitmap2.height();
51 scoped_refptr<base::RefCountedString> EncodeBitmapAsPNG(
52 const SkBitmap& bitmap) {
53 scoped_refptr<base::RefCountedMemory> png_bytes =
54 gfx::Image::CreateFrom1xBitmap(bitmap).As1xPNGBytes();
55 scoped_refptr<base::RefCountedString> str = new base::RefCountedString();
56 str->data().assign(png_bytes->front_as<char>(), png_bytes->size());
57 return str;
60 std::string EncodeBitmapAsPNGBase64(const SkBitmap& bitmap) {
61 scoped_refptr<base::RefCountedString> png_bytes = EncodeBitmapAsPNG(bitmap);
62 std::string encoded_image_base64;
63 base::Base64Encode(png_bytes->data(), &encoded_image_base64);
64 return encoded_image_base64;
67 SkBitmap MakeBitmap(int width, int height) {
68 SkBitmap bitmap;
69 bitmap.allocN32Pixels(width, height);
70 bitmap.eraseColor(SK_ColorBLUE);
71 return bitmap;
74 EncodedLogo EncodeLogo(const Logo& logo) {
75 EncodedLogo encoded_logo;
76 encoded_logo.encoded_image = EncodeBitmapAsPNG(logo.image);
77 encoded_logo.metadata = logo.metadata;
78 return encoded_logo;
81 Logo DecodeLogo(const EncodedLogo& encoded_logo) {
82 Logo logo;
83 logo.image = gfx::Image::CreateFrom1xPNGBytes(
84 encoded_logo.encoded_image->front(),
85 encoded_logo.encoded_image->size()).AsBitmap();
86 logo.metadata = encoded_logo.metadata;
87 return logo;
90 Logo GetSampleLogo(const GURL& logo_url, base::Time response_time) {
91 Logo logo;
92 logo.image = MakeBitmap(2, 5);
93 logo.metadata.can_show_after_expiration = false;
94 logo.metadata.expiration_time =
95 response_time + base::TimeDelta::FromHours(19);
96 logo.metadata.fingerprint = "8bc33a80";
97 logo.metadata.source_url = logo_url.spec();
98 logo.metadata.on_click_url = "http://www.google.com/search?q=potato";
99 logo.metadata.alt_text = "A logo about potatoes";
100 logo.metadata.mime_type = "image/png";
101 return logo;
104 Logo GetSampleLogo2(const GURL& logo_url, base::Time response_time) {
105 Logo logo;
106 logo.image = MakeBitmap(4, 3);
107 logo.metadata.can_show_after_expiration = true;
108 logo.metadata.expiration_time = base::Time();
109 logo.metadata.fingerprint = "71082741021409127";
110 logo.metadata.source_url = logo_url.spec();
111 logo.metadata.on_click_url = "http://example.com/page25";
112 logo.metadata.alt_text = "The logo for example.com";
113 logo.metadata.mime_type = "image/png";
114 return logo;
117 std::string MakeServerResponse(
118 const SkBitmap& image,
119 const std::string& on_click_url,
120 const std::string& alt_text,
121 const std::string& mime_type,
122 const std::string& fingerprint,
123 base::TimeDelta time_to_live) {
124 base::DictionaryValue dict;
125 if (!image.isNull()) {
126 dict.SetString("update.logo.data", EncodeBitmapAsPNGBase64(image));
129 dict.SetString("update.logo.target", on_click_url);
130 dict.SetString("update.logo.alt", alt_text);
131 dict.SetString("update.logo.mime_type", mime_type);
132 dict.SetString("update.logo.fingerprint", fingerprint);
133 if (time_to_live.ToInternalValue() != 0)
134 dict.SetInteger("update.logo.time_to_live",
135 static_cast<int>(time_to_live.InMilliseconds()));
137 std::string output;
138 base::JSONWriter::Write(&dict, &output);
139 return output;
142 std::string MakeServerResponse(const Logo& logo, base::TimeDelta time_to_live) {
143 return MakeServerResponse(logo.image,
144 logo.metadata.on_click_url,
145 logo.metadata.alt_text,
146 logo.metadata.mime_type,
147 logo.metadata.fingerprint,
148 time_to_live);
151 void ExpectLogosEqual(const Logo* expected_logo,
152 const Logo* actual_logo) {
153 if (!expected_logo) {
154 ASSERT_FALSE(actual_logo);
155 return;
157 ASSERT_TRUE(actual_logo);
158 EXPECT_TRUE(AreImagesSameSize(expected_logo->image, actual_logo->image));
159 EXPECT_EQ(expected_logo->metadata.on_click_url,
160 actual_logo->metadata.on_click_url);
161 EXPECT_EQ(expected_logo->metadata.source_url,
162 actual_logo->metadata.source_url);
163 EXPECT_EQ(expected_logo->metadata.fingerprint,
164 actual_logo->metadata.fingerprint);
165 EXPECT_EQ(expected_logo->metadata.can_show_after_expiration,
166 actual_logo->metadata.can_show_after_expiration);
169 void ExpectLogosEqual(const Logo* expected_logo,
170 const EncodedLogo* actual_encoded_logo) {
171 Logo actual_logo;
172 if (actual_encoded_logo)
173 actual_logo = DecodeLogo(*actual_encoded_logo);
174 ExpectLogosEqual(expected_logo, actual_encoded_logo ? &actual_logo : NULL);
177 ACTION_P(ExpectLogosEqualAction, expected_logo) {
178 ExpectLogosEqual(expected_logo, arg0);
181 class MockLogoCache : public LogoCache {
182 public:
183 MockLogoCache() : LogoCache(base::FilePath()) {
184 // Delegate actions to the *Internal() methods by default.
185 ON_CALL(*this, UpdateCachedLogoMetadata(_)).WillByDefault(
186 Invoke(this, &MockLogoCache::UpdateCachedLogoMetadataInternal));
187 ON_CALL(*this, GetCachedLogoMetadata()).WillByDefault(
188 Invoke(this, &MockLogoCache::GetCachedLogoMetadataInternal));
189 ON_CALL(*this, SetCachedLogo(_))
190 .WillByDefault(Invoke(this, &MockLogoCache::SetCachedLogoInternal));
193 MOCK_METHOD1(UpdateCachedLogoMetadata, void(const LogoMetadata& metadata));
194 MOCK_METHOD0(GetCachedLogoMetadata, const LogoMetadata*());
195 MOCK_METHOD1(SetCachedLogo, void(const EncodedLogo* logo));
196 // GetCachedLogo() can't be mocked since it returns a scoped_ptr, which is
197 // non-copyable. Instead create a method that's pinged when GetCachedLogo() is
198 // called.
199 MOCK_METHOD0(OnGetCachedLogo, void());
201 void EncodeAndSetCachedLogo(const Logo& logo) {
202 EncodedLogo encoded_logo = EncodeLogo(logo);
203 SetCachedLogo(&encoded_logo);
206 void ExpectSetCachedLogo(const Logo* expected_logo) {
207 Mock::VerifyAndClearExpectations(this);
208 EXPECT_CALL(*this, SetCachedLogo(_))
209 .WillOnce(ExpectLogosEqualAction(expected_logo));
212 void UpdateCachedLogoMetadataInternal(const LogoMetadata& metadata) {
213 metadata_.reset(new LogoMetadata(metadata));
216 virtual const LogoMetadata* GetCachedLogoMetadataInternal() {
217 return metadata_.get();
220 virtual void SetCachedLogoInternal(const EncodedLogo* logo) {
221 logo_.reset(logo ? new EncodedLogo(*logo) : NULL);
222 metadata_.reset(logo ? new LogoMetadata(logo->metadata) : NULL);
225 virtual scoped_ptr<EncodedLogo> GetCachedLogo() override {
226 OnGetCachedLogo();
227 return make_scoped_ptr(logo_ ? new EncodedLogo(*logo_) : NULL);
230 private:
231 scoped_ptr<LogoMetadata> metadata_;
232 scoped_ptr<EncodedLogo> logo_;
235 class MockLogoObserver : public LogoObserver {
236 public:
237 virtual ~MockLogoObserver() {}
239 void ExpectNoLogo() {
240 Mock::VerifyAndClearExpectations(this);
241 EXPECT_CALL(*this, OnLogoAvailable(_, _)).Times(0);
242 EXPECT_CALL(*this, OnObserverRemoved()).Times(1);
245 void ExpectCachedLogo(const Logo* expected_cached_logo) {
246 Mock::VerifyAndClearExpectations(this);
247 EXPECT_CALL(*this, OnLogoAvailable(_, true))
248 .WillOnce(ExpectLogosEqualAction(expected_cached_logo));
249 EXPECT_CALL(*this, OnLogoAvailable(_, false)).Times(0);
250 EXPECT_CALL(*this, OnObserverRemoved()).Times(1);
253 void ExpectFreshLogo(const Logo* expected_fresh_logo) {
254 Mock::VerifyAndClearExpectations(this);
255 EXPECT_CALL(*this, OnLogoAvailable(_, true)).Times(0);
256 EXPECT_CALL(*this, OnLogoAvailable(NULL, true));
257 EXPECT_CALL(*this, OnLogoAvailable(_, false))
258 .WillOnce(ExpectLogosEqualAction(expected_fresh_logo));
259 EXPECT_CALL(*this, OnObserverRemoved()).Times(1);
262 void ExpectCachedAndFreshLogos(const Logo* expected_cached_logo,
263 const Logo* expected_fresh_logo) {
264 Mock::VerifyAndClearExpectations(this);
265 InSequence dummy;
266 EXPECT_CALL(*this, OnLogoAvailable(_, true))
267 .WillOnce(ExpectLogosEqualAction(expected_cached_logo));
268 EXPECT_CALL(*this, OnLogoAvailable(_, false))
269 .WillOnce(ExpectLogosEqualAction(expected_fresh_logo));
270 EXPECT_CALL(*this, OnObserverRemoved()).Times(1);
273 MOCK_METHOD2(OnLogoAvailable, void(const Logo*, bool));
274 MOCK_METHOD0(OnObserverRemoved, void());
277 class TestLogoDelegate : public LogoDelegate {
278 public:
279 TestLogoDelegate() {}
280 ~TestLogoDelegate() override {}
282 void DecodeUntrustedImage(
283 const scoped_refptr<base::RefCountedString>& encoded_image,
284 base::Callback<void(const SkBitmap&)> image_decoded_callback) override {
285 SkBitmap bitmap =
286 gfx::Image::CreateFrom1xPNGBytes(encoded_image->front(),
287 encoded_image->size()).AsBitmap();
288 base::MessageLoopProxy::current()->PostTask(
289 FROM_HERE, base::Bind(image_decoded_callback, bitmap));
293 class LogoTrackerTest : public ::testing::Test {
294 protected:
295 LogoTrackerTest()
296 : message_loop_(new base::MessageLoop()),
297 logo_url_("https://google.com/doodleoftheday?size=hp"),
298 test_clock_(new base::SimpleTestClock()),
299 logo_cache_(new NiceMock<MockLogoCache>()),
300 fake_url_fetcher_factory_(NULL) {
301 test_clock_->SetNow(base::Time::FromJsTime(GG_INT64_C(1388686828000)));
302 logo_tracker_ = new LogoTracker(
303 base::FilePath(),
304 base::MessageLoopProxy::current(),
305 base::MessageLoopProxy::current(),
306 new net::TestURLRequestContextGetter(base::MessageLoopProxy::current()),
307 scoped_ptr<LogoDelegate>(new TestLogoDelegate()));
308 logo_tracker_->SetServerAPI(logo_url_,
309 base::Bind(&GoogleParseLogoResponse),
310 base::Bind(&GoogleAppendFingerprintToLogoURL));
311 logo_tracker_->SetClockForTests(scoped_ptr<base::Clock>(test_clock_));
312 logo_tracker_->SetLogoCacheForTests(scoped_ptr<LogoCache>(logo_cache_));
315 virtual void TearDown() {
316 // logo_tracker_ owns logo_cache_, which gets destructed on the file thread
317 // after logo_tracker_'s destruction. Ensure that logo_cache_ is actually
318 // destructed before the test ends to make gmock happy.
319 delete logo_tracker_;
320 message_loop_->RunUntilIdle();
323 // Returns the response that the server would send for the given logo.
324 std::string ServerResponse(const Logo& logo) const;
326 // Sets the response to be returned when the LogoTracker fetches the logo.
327 void SetServerResponse(const std::string& response,
328 net::URLRequestStatus::Status request_status =
329 net::URLRequestStatus::SUCCESS,
330 net::HttpStatusCode response_code = net::HTTP_OK);
332 // Sets the response to be returned when the LogoTracker fetches the logo and
333 // provides the given fingerprint.
334 void SetServerResponseWhenFingerprint(
335 const std::string& fingerprint,
336 const std::string& response_when_fingerprint,
337 net::URLRequestStatus::Status request_status =
338 net::URLRequestStatus::SUCCESS,
339 net::HttpStatusCode response_code = net::HTTP_OK);
341 // Calls logo_tracker_->GetLogo() with listener_ and waits for the
342 // asynchronous response(s).
343 void GetLogo();
345 scoped_ptr<base::MessageLoop> message_loop_;
346 GURL logo_url_;
347 base::SimpleTestClock* test_clock_;
348 NiceMock<MockLogoCache>* logo_cache_;
349 net::FakeURLFetcherFactory fake_url_fetcher_factory_;
350 LogoTracker* logo_tracker_;
351 NiceMock<MockLogoObserver> observer_;
354 std::string LogoTrackerTest::ServerResponse(const Logo& logo) const {
355 base::TimeDelta time_to_live;
356 if (!logo.metadata.expiration_time.is_null())
357 time_to_live = logo.metadata.expiration_time - test_clock_->Now();
358 return MakeServerResponse(logo, time_to_live);
361 void LogoTrackerTest::SetServerResponse(
362 const std::string& response,
363 net::URLRequestStatus::Status request_status,
364 net::HttpStatusCode response_code) {
365 fake_url_fetcher_factory_.SetFakeResponse(
366 logo_url_, response, response_code, request_status);
369 void LogoTrackerTest::SetServerResponseWhenFingerprint(
370 const std::string& fingerprint,
371 const std::string& response_when_fingerprint,
372 net::URLRequestStatus::Status request_status,
373 net::HttpStatusCode response_code) {
374 GURL url_with_fp = GoogleAppendFingerprintToLogoURL(logo_url_, fingerprint);
375 fake_url_fetcher_factory_.SetFakeResponse(
376 url_with_fp, response_when_fingerprint, response_code, request_status);
379 void LogoTrackerTest::GetLogo() {
380 logo_tracker_->GetLogo(&observer_);
381 base::RunLoop().RunUntilIdle();
384 // Tests -----------------------------------------------------------------------
386 TEST_F(LogoTrackerTest, FingerprintURLHasColon) {
387 GURL url_with_fp = GoogleAppendFingerprintToLogoURL(
388 GURL("http://logourl.com/path"), "abc123");
389 EXPECT_EQ("http://logourl.com/path?async=es_dfp:abc123", url_with_fp.spec());
391 url_with_fp = GoogleAppendFingerprintToLogoURL(
392 GURL("http://logourl.com/?a=b"), "cafe0");
393 EXPECT_EQ("http://logourl.com/?a=b&async=es_dfp:cafe0", url_with_fp.spec());
396 TEST_F(LogoTrackerTest, DownloadAndCacheLogo) {
397 Logo logo = GetSampleLogo(logo_url_, test_clock_->Now());
398 SetServerResponse(ServerResponse(logo));
399 logo_cache_->ExpectSetCachedLogo(&logo);
400 observer_.ExpectFreshLogo(&logo);
401 GetLogo();
404 TEST_F(LogoTrackerTest, EmptyCacheAndFailedDownload) {
405 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
406 EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
407 EXPECT_CALL(*logo_cache_, SetCachedLogo(NULL)).Times(AnyNumber());
409 SetServerResponse("server is borked");
410 observer_.ExpectCachedLogo(NULL);
411 GetLogo();
413 SetServerResponse("", net::URLRequestStatus::FAILED, net::HTTP_OK);
414 observer_.ExpectCachedLogo(NULL);
415 GetLogo();
417 SetServerResponse("", net::URLRequestStatus::SUCCESS, net::HTTP_BAD_GATEWAY);
418 observer_.ExpectCachedLogo(NULL);
419 GetLogo();
422 TEST_F(LogoTrackerTest, AcceptMinimalLogoResponse) {
423 Logo logo;
424 logo.image = MakeBitmap(1, 2);
425 logo.metadata.source_url = logo_url_.spec();
426 logo.metadata.can_show_after_expiration = true;
428 std::string response = ")]}' {\"update\":{\"logo\":{\"data\":\"" +
429 EncodeBitmapAsPNGBase64(logo.image) +
430 "\",\"mime_type\":\"image/png\"}}}";
432 SetServerResponse(response);
433 observer_.ExpectFreshLogo(&logo);
434 GetLogo();
437 TEST_F(LogoTrackerTest, ReturnCachedLogo) {
438 Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
439 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
440 SetServerResponseWhenFingerprint(cached_logo.metadata.fingerprint,
442 net::URLRequestStatus::FAILED,
443 net::HTTP_OK);
445 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
446 EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
447 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
448 observer_.ExpectCachedLogo(&cached_logo);
449 GetLogo();
452 TEST_F(LogoTrackerTest, ValidateCachedLogoFingerprint) {
453 Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
454 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
456 Logo fresh_logo = cached_logo;
457 fresh_logo.image.reset();
458 fresh_logo.metadata.expiration_time =
459 test_clock_->Now() + base::TimeDelta::FromDays(8);
460 SetServerResponseWhenFingerprint(fresh_logo.metadata.fingerprint,
461 ServerResponse(fresh_logo));
463 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(1);
464 EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
465 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
466 observer_.ExpectCachedLogo(&cached_logo);
468 GetLogo();
470 EXPECT_TRUE(logo_cache_->GetCachedLogoMetadata() != NULL);
471 EXPECT_EQ(logo_cache_->GetCachedLogoMetadata()->expiration_time,
472 fresh_logo.metadata.expiration_time);
475 TEST_F(LogoTrackerTest, UpdateCachedLogo) {
476 Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
477 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
479 Logo fresh_logo = GetSampleLogo2(logo_url_, test_clock_->Now());
480 SetServerResponseWhenFingerprint(cached_logo.metadata.fingerprint,
481 ServerResponse(fresh_logo));
483 logo_cache_->ExpectSetCachedLogo(&fresh_logo);
484 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
485 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
486 observer_.ExpectCachedAndFreshLogos(&cached_logo, &fresh_logo);
488 GetLogo();
491 TEST_F(LogoTrackerTest, InvalidateCachedLogo) {
492 Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
493 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
495 // This response means there's no current logo.
496 SetServerResponseWhenFingerprint(cached_logo.metadata.fingerprint,
497 ")]}' {\"update\":{}}");
499 logo_cache_->ExpectSetCachedLogo(NULL);
500 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
501 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
502 observer_.ExpectCachedAndFreshLogos(&cached_logo, NULL);
504 GetLogo();
507 TEST_F(LogoTrackerTest, DeleteCachedLogoFromOldUrl) {
508 SetServerResponse("", net::URLRequestStatus::FAILED, net::HTTP_OK);
509 Logo cached_logo =
510 GetSampleLogo(GURL("http://oldsearchprovider.com"), test_clock_->Now());
511 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
513 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
514 EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
515 EXPECT_CALL(*logo_cache_, SetCachedLogo(NULL)).Times(AnyNumber());
516 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
517 observer_.ExpectCachedLogo(NULL);
518 GetLogo();
521 TEST_F(LogoTrackerTest, LogoWithTTLCannotBeShownAfterExpiration) {
522 Logo logo = GetSampleLogo(logo_url_, test_clock_->Now());
523 base::TimeDelta time_to_live = base::TimeDelta::FromDays(3);
524 logo.metadata.expiration_time = test_clock_->Now() + time_to_live;
525 SetServerResponse(ServerResponse(logo));
526 GetLogo();
528 const LogoMetadata* cached_metadata =
529 logo_cache_->GetCachedLogoMetadata();
530 EXPECT_TRUE(cached_metadata != NULL);
531 EXPECT_FALSE(cached_metadata->can_show_after_expiration);
532 EXPECT_EQ(test_clock_->Now() + time_to_live,
533 cached_metadata->expiration_time);
536 TEST_F(LogoTrackerTest, LogoWithoutTTLCanBeShownAfterExpiration) {
537 Logo logo = GetSampleLogo(logo_url_, test_clock_->Now());
538 base::TimeDelta time_to_live = base::TimeDelta();
539 SetServerResponse(MakeServerResponse(logo, time_to_live));
540 GetLogo();
542 const LogoMetadata* cached_metadata =
543 logo_cache_->GetCachedLogoMetadata();
544 EXPECT_TRUE(cached_metadata != NULL);
545 EXPECT_TRUE(cached_metadata->can_show_after_expiration);
546 EXPECT_EQ(test_clock_->Now() + base::TimeDelta::FromDays(30),
547 cached_metadata->expiration_time);
550 TEST_F(LogoTrackerTest, UseSoftExpiredCachedLogo) {
551 SetServerResponse("", net::URLRequestStatus::FAILED, net::HTTP_OK);
552 Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
553 cached_logo.metadata.expiration_time =
554 test_clock_->Now() - base::TimeDelta::FromSeconds(1);
555 cached_logo.metadata.can_show_after_expiration = true;
556 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
558 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
559 EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
560 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
561 observer_.ExpectCachedLogo(&cached_logo);
562 GetLogo();
565 TEST_F(LogoTrackerTest, RerequestSoftExpiredCachedLogo) {
566 Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
567 cached_logo.metadata.expiration_time =
568 test_clock_->Now() - base::TimeDelta::FromDays(5);
569 cached_logo.metadata.can_show_after_expiration = true;
570 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
572 Logo fresh_logo = GetSampleLogo2(logo_url_, test_clock_->Now());
573 SetServerResponse(ServerResponse(fresh_logo));
575 logo_cache_->ExpectSetCachedLogo(&fresh_logo);
576 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
577 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
578 observer_.ExpectCachedAndFreshLogos(&cached_logo, &fresh_logo);
580 GetLogo();
583 TEST_F(LogoTrackerTest, DeleteAncientCachedLogo) {
584 SetServerResponse("", net::URLRequestStatus::FAILED, net::HTTP_OK);
585 Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
586 cached_logo.metadata.expiration_time =
587 test_clock_->Now() - base::TimeDelta::FromDays(200);
588 cached_logo.metadata.can_show_after_expiration = true;
589 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
591 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
592 EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
593 EXPECT_CALL(*logo_cache_, SetCachedLogo(NULL)).Times(AnyNumber());
594 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
595 observer_.ExpectCachedLogo(NULL);
596 GetLogo();
599 TEST_F(LogoTrackerTest, DeleteExpiredCachedLogo) {
600 SetServerResponse("", net::URLRequestStatus::FAILED, net::HTTP_OK);
601 Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
602 cached_logo.metadata.expiration_time =
603 test_clock_->Now() - base::TimeDelta::FromSeconds(1);
604 cached_logo.metadata.can_show_after_expiration = false;
605 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
607 EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
608 EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
609 EXPECT_CALL(*logo_cache_, SetCachedLogo(NULL)).Times(AnyNumber());
610 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
611 observer_.ExpectCachedLogo(NULL);
612 GetLogo();
615 // Tests that deal with multiple listeners.
617 void EnqueueObservers(LogoTracker* logo_tracker,
618 const ScopedVector<MockLogoObserver>& observers,
619 size_t start_index) {
620 if (start_index >= observers.size())
621 return;
623 logo_tracker->GetLogo(observers[start_index]);
624 base::MessageLoop::current()->PostTask(FROM_HERE,
625 base::Bind(&EnqueueObservers,
626 logo_tracker,
627 base::ConstRef(observers),
628 start_index + 1));
631 TEST_F(LogoTrackerTest, SupportOverlappingLogoRequests) {
632 Logo cached_logo = GetSampleLogo(logo_url_, test_clock_->Now());
633 logo_cache_->EncodeAndSetCachedLogo(cached_logo);
634 ON_CALL(*logo_cache_, SetCachedLogo(_)).WillByDefault(Return());
636 Logo fresh_logo = GetSampleLogo2(logo_url_, test_clock_->Now());
637 std::string response = ServerResponse(fresh_logo);
638 SetServerResponse(response);
639 SetServerResponseWhenFingerprint(cached_logo.metadata.fingerprint, response);
641 const int kNumListeners = 10;
642 ScopedVector<MockLogoObserver> listeners;
643 for (int i = 0; i < kNumListeners; ++i) {
644 MockLogoObserver* listener = new MockLogoObserver();
645 listener->ExpectCachedAndFreshLogos(&cached_logo, &fresh_logo);
646 listeners.push_back(listener);
648 EnqueueObservers(logo_tracker_, listeners, 0);
650 EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(AtMost(3));
651 EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(3));
653 base::RunLoop().RunUntilIdle();
656 TEST_F(LogoTrackerTest, DeleteObserversWhenLogoURLChanged) {
657 MockLogoObserver listener1;
658 listener1.ExpectNoLogo();
659 logo_tracker_->GetLogo(&listener1);
661 logo_url_ = GURL("http://example.com/new-logo-url");
662 logo_tracker_->SetServerAPI(logo_url_,
663 base::Bind(&GoogleParseLogoResponse),
664 base::Bind(&GoogleAppendFingerprintToLogoURL));
665 Logo logo = GetSampleLogo(logo_url_, test_clock_->Now());
666 SetServerResponse(ServerResponse(logo));
668 MockLogoObserver listener2;
669 listener2.ExpectFreshLogo(&logo);
670 logo_tracker_->GetLogo(&listener2);
672 base::RunLoop().RunUntilIdle();
675 } // namespace
677 } // namespace search_provider_logos