blob: 460f0180ceca25b3397678aff38e5f54b3dbcb77 [file] [log] [blame]
mathpc3c8b0e2014-09-29 15:25:131// 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.
4
danakj501f8012016-04-22 22:49:255#include "components/suggestions/image_manager.h"
6
7#include <memory>
mathpc3c8b0e2014-09-29 15:25:138#include <string>
9
10#include "base/files/file_path.h"
danakj501f8012016-04-22 22:49:2511#include "base/memory/ptr_util.h"
mathpc3c8b0e2014-09-29 15:25:1312#include "base/run_loop.h"
fdoray0d831272017-04-06 16:50:1913#include "base/test/scoped_task_environment.h"
gab7966d312016-05-11 20:35:0114#include "base/threading/thread_task_runner_handle.h"
mastizf4d088a2017-03-21 17:41:4015#include "components/image_fetcher/core/image_fetcher.h"
16#include "components/image_fetcher/core/image_fetcher_delegate.h"
mathpc3c8b0e2014-09-29 15:25:1317#include "components/leveldb_proto/proto_database.h"
18#include "components/leveldb_proto/testing/fake_db.h"
mathp3377c6262014-10-10 21:13:0019#include "components/suggestions/image_encoder.h"
mathpc3c8b0e2014-09-29 15:25:1320#include "components/suggestions/proto/suggestions.pb.h"
21#include "testing/gmock/include/gmock/gmock.h"
22#include "testing/gtest/include/gtest/gtest.h"
tschumann30ee1082017-03-02 19:37:5323#include "ui/gfx/geometry/size.h"
markusheintz049dce32016-05-19 08:43:2724#include "ui/gfx/image/image.h"
mathpc3c8b0e2014-09-29 15:25:1325#include "ui/gfx/image/image_skia.h"
26#include "url/gurl.h"
27
28using ::testing::Return;
29using ::testing::StrictMock;
30using ::testing::_;
31
treib0a7f0202016-04-29 11:39:0832using image_fetcher::ImageFetcher;
33using image_fetcher::ImageFetcherDelegate;
34
mathpc3c8b0e2014-09-29 15:25:1335namespace suggestions {
36
37const char kTestUrl1[] = "http://go.com/";
38const char kTestUrl2[] = "http://goal.com/";
39const char kTestImagePath[] = "files/image_decoding/droids.png";
40const char kInvalidImagePath[] = "files/DOESNOTEXIST";
41
42using leveldb_proto::test::FakeDB;
mathpc3c8b0e2014-09-29 15:25:1343
brettw1ce49f62017-04-27 19:42:3244typedef std::map<std::string, ImageData> EntryMap;
mathpc3c8b0e2014-09-29 15:25:1345
46void AddEntry(const ImageData& d, EntryMap* map) { (*map)[d.url()] = d; }
47
treib0a7f0202016-04-29 11:39:0848class MockImageFetcher : public ImageFetcher {
mathpc3c8b0e2014-09-29 15:25:1349 public:
50 MockImageFetcher() {}
51 virtual ~MockImageFetcher() {}
52 MOCK_METHOD3(StartOrQueueNetworkRequest,
treib0a6cfc62017-03-20 13:10:3053 void(const std::string&,
54 const GURL&,
55 const ImageFetcherCallback&));
mathpc3c8b0e2014-09-29 15:25:1356 MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*));
treib264f6b32016-07-19 15:51:3157 MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName));
fhorschig28108022017-03-28 10:55:1358 MOCK_METHOD1(SetImageDownloadLimit,
59 void(base::Optional<int64_t> max_download_bytes));
tschumann30ee1082017-03-02 19:37:5360 MOCK_METHOD1(SetDesiredImageFrameSize, void(const gfx::Size&));
treib10fe0ac12017-03-07 13:05:5661 MOCK_METHOD0(GetImageDecoder, image_fetcher::ImageDecoder*());
mathpc3c8b0e2014-09-29 15:25:1362};
63
64class ImageManagerTest : public testing::Test {
65 public:
66 ImageManagerTest()
67 : mock_image_fetcher_(NULL),
68 num_callback_null_called_(0),
69 num_callback_valid_called_(0) {}
70
dcheng30a1b1542014-10-29 21:27:5071 void SetUp() override {
mathpc3c8b0e2014-09-29 15:25:1372 fake_db_ = new FakeDB<ImageData>(&db_model_);
mathp60143a32014-10-08 14:52:4573 image_manager_.reset(CreateImageManager(fake_db_));
mathpc3c8b0e2014-09-29 15:25:1374 }
75
dcheng30a1b1542014-10-29 21:27:5076 void TearDown() override {
mathpc3c8b0e2014-09-29 15:25:1377 fake_db_ = NULL;
78 db_model_.clear();
79 image_manager_.reset();
80 }
81
82 void InitializeDefaultImageMapAndDatabase(ImageManager* image_manager,
83 FakeDB<ImageData>* fake_db) {
84 CHECK(image_manager);
85 CHECK(fake_db);
86
87 suggestions::SuggestionsProfile suggestions_profile;
88 suggestions::ChromeSuggestion* suggestion =
89 suggestions_profile.add_suggestions();
90 suggestion->set_url(kTestUrl1);
91 suggestion->set_thumbnail(kTestImagePath);
92
93 image_manager->Initialize(suggestions_profile);
94
95 // Initialize empty database.
96 fake_db->InitCallback(true);
97 fake_db->LoadCallback(true);
98 }
99
100 ImageData GetSampleImageData(const std::string& url) {
101 // Create test bitmap.
102 SkBitmap bm;
103 // Being careful with the Bitmap. There are memory-related issue in
104 // crbug.com/101781.
105 bm.allocN32Pixels(4, 4);
106 bm.eraseColor(SK_ColorRED);
107 ImageData data;
108 data.set_url(url);
109 std::vector<unsigned char> encoded;
mathpa27b85e2014-10-10 19:19:57110 EXPECT_TRUE(EncodeSkBitmapToJPEG(bm, &encoded));
mathpc3c8b0e2014-09-29 15:25:13111 data.set_data(std::string(encoded.begin(), encoded.end()));
112 return data;
113 }
114
115 void OnImageAvailable(base::RunLoop* loop, const GURL& url,
markusheintz55ae1162016-05-25 08:20:57116 const gfx::Image& image) {
117 if (!image.IsEmpty()) {
mathpc3c8b0e2014-09-29 15:25:13118 num_callback_valid_called_++;
119 } else {
120 num_callback_null_called_++;
121 }
122 loop->Quit();
123 }
124
mathp60143a32014-10-08 14:52:45125 ImageManager* CreateImageManager(FakeDB<ImageData>* fake_db) {
mathpc3c8b0e2014-09-29 15:25:13126 mock_image_fetcher_ = new StrictMock<MockImageFetcher>();
127 EXPECT_CALL(*mock_image_fetcher_, SetImageFetcherDelegate(_));
danakj501f8012016-04-22 22:49:25128 return new ImageManager(base::WrapUnique(mock_image_fetcher_),
129 base::WrapUnique(fake_db),
130 FakeDB<ImageData>::DirectoryForTestDB(),
131 base::ThreadTaskRunnerHandle::Get());
mathpc3c8b0e2014-09-29 15:25:13132 }
133
134 EntryMap db_model_;
135 // Owned by the ImageManager under test.
136 FakeDB<ImageData>* fake_db_;
137
138 MockImageFetcher* mock_image_fetcher_;
139
140 int num_callback_null_called_;
141 int num_callback_valid_called_;
dskiba960b00e2015-06-11 22:44:46142
fdoray0d831272017-04-06 16:50:19143 base::test::ScopedTaskEnvironment scoped_task_environment_;
dskiba960b00e2015-06-11 22:44:46144
mathpc3c8b0e2014-09-29 15:25:13145 // Under test.
danakj501f8012016-04-22 22:49:25146 std::unique_ptr<ImageManager> image_manager_;
mathpc3c8b0e2014-09-29 15:25:13147};
148
149TEST_F(ImageManagerTest, InitializeTest) {
150 SuggestionsProfile suggestions_profile;
151 ChromeSuggestion* suggestion = suggestions_profile.add_suggestions();
152 suggestion->set_url(kTestUrl1);
153 suggestion->set_thumbnail(kTestImagePath);
154
155 image_manager_->Initialize(suggestions_profile);
156
157 GURL output;
158 EXPECT_TRUE(image_manager_->GetImageURL(GURL(kTestUrl1), &output));
159 EXPECT_EQ(GURL(kTestImagePath), output);
160
161 EXPECT_FALSE(image_manager_->GetImageURL(GURL("http://b.com"), &output));
162}
163
treibac5372f2015-09-09 09:08:22164TEST_F(ImageManagerTest, AddImageURL) {
165 InitializeDefaultImageMapAndDatabase(image_manager_.get(), fake_db_);
166
167 GURL output;
168 // Try a URL the ImageManager doesn't know about.
169 ASSERT_FALSE(image_manager_->GetImageURL(GURL(kTestUrl2), &output));
170
171 // Explicitly add the URL and try again.
172 image_manager_->AddImageURL(GURL(kTestUrl2), GURL(kTestImagePath));
173 EXPECT_TRUE(image_manager_->GetImageURL(GURL(kTestUrl2), &output));
174 EXPECT_EQ(GURL(kTestImagePath), output);
175}
176
mathpc3c8b0e2014-09-29 15:25:13177TEST_F(ImageManagerTest, GetImageForURLNetwork) {
178 InitializeDefaultImageMapAndDatabase(image_manager_.get(), fake_db_);
179
180 // We expect the fetcher to go to network and call the callback.
181 EXPECT_CALL(*mock_image_fetcher_, StartOrQueueNetworkRequest(_, _, _));
182
183 // Fetch existing URL.
184 base::RunLoop run_loop;
185 image_manager_->GetImageForURL(GURL(kTestUrl1),
186 base::Bind(&ImageManagerTest::OnImageAvailable,
187 base::Unretained(this), &run_loop));
188
189 // Will not go to network and use the fetcher since URL is invalid.
190 // Fetch non-existing URL.
191 image_manager_->GetImageForURL(GURL(kTestUrl2),
192 base::Bind(&ImageManagerTest::OnImageAvailable,
193 base::Unretained(this), &run_loop));
194 run_loop.Run();
195
196 EXPECT_EQ(1, num_callback_null_called_);
197}
198
199TEST_F(ImageManagerTest, GetImageForURLNetworkCacheHit) {
200 SuggestionsProfile suggestions_profile;
201 ChromeSuggestion* suggestion = suggestions_profile.add_suggestions();
202 suggestion->set_url(kTestUrl1);
203 // The URL we set is invalid, to show that it will fail from network.
204 suggestion->set_thumbnail(kInvalidImagePath);
205
206 // Create the ImageManager with an added entry in the database.
207 AddEntry(GetSampleImageData(kTestUrl1), &db_model_);
208 FakeDB<ImageData>* fake_db = new FakeDB<ImageData>(&db_model_);
mathp60143a32014-10-08 14:52:45209 image_manager_.reset(CreateImageManager(fake_db));
mathpc3c8b0e2014-09-29 15:25:13210 image_manager_->Initialize(suggestions_profile);
211 fake_db->InitCallback(true);
212 fake_db->LoadCallback(true);
213 // Expect something in the cache.
dskiba960b00e2015-06-11 22:44:46214 auto encoded_image =
215 image_manager_->GetEncodedImageFromCache(GURL(kTestUrl1));
scheib4dac7f02016-05-12 00:55:03216 EXPECT_TRUE(encoded_image);
mathpc3c8b0e2014-09-29 15:25:13217
218 base::RunLoop run_loop;
219 image_manager_->GetImageForURL(GURL(kTestUrl1),
220 base::Bind(&ImageManagerTest::OnImageAvailable,
221 base::Unretained(this), &run_loop));
222 run_loop.Run();
223
224 EXPECT_EQ(0, num_callback_null_called_);
225 EXPECT_EQ(1, num_callback_valid_called_);
226}
227
228} // namespace suggestions