blob: e6cb33a069a9dddc8fb2c3db531ebc1f9895acbf [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h"
#include <stddef.h>
#include "base/macros.h"
#include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace {
class TestNotificationInterface {
public:
virtual ~TestNotificationInterface() {}
virtual void OnImageChanged() = 0;
virtual void OnRequestFinished() = 0;
};
class TestObserver : public BitmapFetcherService::Observer {
public:
explicit TestObserver(TestNotificationInterface* target) : target_(target) {}
~TestObserver() override { target_->OnRequestFinished(); }
void OnImageChanged(BitmapFetcherService::RequestId request_id,
const SkBitmap& answers_image) override {
target_->OnImageChanged();
}
private:
TestNotificationInterface* target_;
DISALLOW_COPY_AND_ASSIGN(TestObserver);
};
class TestService : public BitmapFetcherService {
public:
explicit TestService(content::BrowserContext* context)
: BitmapFetcherService(context) {}
~TestService() override {}
// Create a fetcher, but don't start downloading. That allows side-stepping
// the decode step, which requires a utility process.
std::unique_ptr<BitmapFetcher> CreateFetcher(
const GURL& url,
const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
return std::make_unique<BitmapFetcher>(url, this, traffic_annotation);
}
};
} // namespace
class BitmapFetcherServiceTest : public testing::Test,
public TestNotificationInterface {
public:
BitmapFetcherServiceTest()
: url1_(GURL("http://example.org/sample-image-1.png")),
url2_(GURL("http://example.org/sample-image-2.png")) {
}
void SetUp() override {
service_.reset(new TestService(&profile_));
requests_finished_ = 0;
images_changed_ = 0;
}
const std::vector<std::unique_ptr<BitmapFetcherRequest>>& requests() const {
return service_->requests_;
}
const std::vector<std::unique_ptr<BitmapFetcher>>& active_fetchers() const {
return service_->active_fetchers_;
}
size_t cache_size() const { return service_->cache_.size(); }
void OnImageChanged() override { images_changed_++; }
void OnRequestFinished() override { requests_finished_++; }
// Simulate finishing a URL fetch and decode for the given fetcher.
void CompleteFetch(const GURL& url) {
const BitmapFetcher* fetcher = service_->FindFetcherForUrl(url);
ASSERT_TRUE(fetcher);
// Create a non-empty bitmap.
SkBitmap image;
image.allocN32Pixels(2, 2);
image.eraseColor(SK_ColorGREEN);
const_cast<BitmapFetcher*>(fetcher)->OnImageDecoded(image);
}
void FailFetch(const GURL& url) {
const BitmapFetcher* fetcher = service_->FindFetcherForUrl(url);
ASSERT_TRUE(fetcher);
const_cast<BitmapFetcher*>(fetcher)->OnImageDecoded(SkBitmap());
}
// A failed decode results in a nullptr image.
void FailDecode(const GURL& url) {
const BitmapFetcher* fetcher = service_->FindFetcherForUrl(url);
ASSERT_TRUE(fetcher);
const_cast<BitmapFetcher*>(fetcher)->OnDecodeImageFailed();
}
protected:
std::unique_ptr<BitmapFetcherService> service_;
int images_changed_;
int requests_finished_;
const GURL url1_;
const GURL url2_;
private:
content::TestBrowserThreadBundle thread_bundle_;
TestingProfile profile_;
};
TEST_F(BitmapFetcherServiceTest, RequestInvalidUrl) {
const BitmapFetcherService::RequestId invalid_request_id =
BitmapFetcherService::REQUEST_ID_INVALID;
GURL invalid_url;
ASSERT_FALSE(invalid_url.is_valid());
BitmapFetcherService::RequestId request_id = service_->RequestImage(
invalid_url, new TestObserver(this), TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(invalid_request_id, request_id);
}
TEST_F(BitmapFetcherServiceTest, CancelInvalidRequest) {
service_->CancelRequest(BitmapFetcherService::REQUEST_ID_INVALID);
service_->CancelRequest(23);
}
TEST_F(BitmapFetcherServiceTest, OnlyFirstRequestCreatesFetcher) {
EXPECT_EQ(0U, active_fetchers().size());
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(1U, active_fetchers().size());
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(1U, active_fetchers().size());
}
TEST_F(BitmapFetcherServiceTest, CompletedFetchNotifiesAllObservers) {
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(1U, active_fetchers().size());
EXPECT_EQ(4U, requests().size());
CompleteFetch(url1_);
EXPECT_EQ(4, images_changed_);
EXPECT_EQ(4, requests_finished_);
}
TEST_F(BitmapFetcherServiceTest, CancelRequest) {
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
BitmapFetcherService::RequestId requestId = service_->RequestImage(
url2_, new TestObserver(this), TRAFFIC_ANNOTATION_FOR_TESTS);
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(5U, requests().size());
service_->CancelRequest(requestId);
EXPECT_EQ(4U, requests().size());
CompleteFetch(url2_);
EXPECT_EQ(0, images_changed_);
CompleteFetch(url1_);
EXPECT_EQ(4, images_changed_);
}
TEST_F(BitmapFetcherServiceTest, FailedNullRequestsAreHandled) {
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
service_->RequestImage(url2_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(0U, cache_size());
CompleteFetch(url1_);
EXPECT_EQ(1U, cache_size());
FailDecode(url2_);
EXPECT_EQ(1U, cache_size());
}
TEST_F(BitmapFetcherServiceTest, FailedRequestsDontEnterCache) {
service_->RequestImage(url1_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
service_->RequestImage(url2_, new TestObserver(this),
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(0U, cache_size());
CompleteFetch(url1_);
EXPECT_EQ(1U, cache_size());
FailFetch(url2_);
EXPECT_EQ(1U, cache_size());
}