blob: e4a837dc27f0fa8c53fe221a1f0fc274c559ac0f [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"
mastizf4d088a2017-03-21 17:41:4014#include "components/image_fetcher/core/image_fetcher.h"
Dan Harrington343f6d9f2018-03-19 19:11:1615#include "components/image_fetcher/core/mock_image_fetcher.h"
mathpc3c8b0e2014-09-29 15:25:1316#include "components/leveldb_proto/proto_database.h"
17#include "components/leveldb_proto/testing/fake_db.h"
mathp3377c6262014-10-10 21:13:0018#include "components/suggestions/image_encoder.h"
mathpc3c8b0e2014-09-29 15:25:1319#include "components/suggestions/proto/suggestions.pb.h"
rhalavati6072a6b72017-05-19 14:52:1320#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
mathpc3c8b0e2014-09-29 15:25:1321#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 "url/gurl.h"
26
27using ::testing::Return;
28using ::testing::StrictMock;
29using ::testing::_;
30
Dan Harrington343f6d9f2018-03-19 19:11:1631using image_fetcher::MockImageFetcher;
treib0a7f0202016-04-29 11:39:0832
mathpc3c8b0e2014-09-29 15:25:1333namespace suggestions {
34
35const char kTestUrl1[] = "http://go.com/";
36const char kTestUrl2[] = "http://goal.com/";
37const char kTestImagePath[] = "files/image_decoding/droids.png";
38const char kInvalidImagePath[] = "files/DOESNOTEXIST";
39
40using leveldb_proto::test::FakeDB;
mathpc3c8b0e2014-09-29 15:25:1341
brettw1ce49f62017-04-27 19:42:3242typedef std::map<std::string, ImageData> EntryMap;
mathpc3c8b0e2014-09-29 15:25:1343
Dan Harrington343f6d9f2018-03-19 19:11:1644void AddEntry(const ImageData& d, EntryMap* map) {
45 (*map)[d.url()] = d;
46}
mathpc3c8b0e2014-09-29 15:25:1347
48class ImageManagerTest : public testing::Test {
49 public:
50 ImageManagerTest()
Ivan Kotenkov75b1c3a2017-10-24 14:47:2451 : mock_image_fetcher_(nullptr),
mathpc3c8b0e2014-09-29 15:25:1352 num_callback_null_called_(0),
53 num_callback_valid_called_(0) {}
54
dcheng30a1b1542014-10-29 21:27:5055 void SetUp() override {
mathpc3c8b0e2014-09-29 15:25:1356 fake_db_ = new FakeDB<ImageData>(&db_model_);
mathp60143a32014-10-08 14:52:4557 image_manager_.reset(CreateImageManager(fake_db_));
mathpc3c8b0e2014-09-29 15:25:1358 }
59
dcheng30a1b1542014-10-29 21:27:5060 void TearDown() override {
Ivan Kotenkov75b1c3a2017-10-24 14:47:2461 fake_db_ = nullptr;
mathpc3c8b0e2014-09-29 15:25:1362 db_model_.clear();
63 image_manager_.reset();
64 }
65
66 void InitializeDefaultImageMapAndDatabase(ImageManager* image_manager,
67 FakeDB<ImageData>* fake_db) {
68 CHECK(image_manager);
69 CHECK(fake_db);
70
71 suggestions::SuggestionsProfile suggestions_profile;
72 suggestions::ChromeSuggestion* suggestion =
73 suggestions_profile.add_suggestions();
74 suggestion->set_url(kTestUrl1);
75 suggestion->set_thumbnail(kTestImagePath);
76
77 image_manager->Initialize(suggestions_profile);
78
79 // Initialize empty database.
80 fake_db->InitCallback(true);
81 fake_db->LoadCallback(true);
82 }
83
84 ImageData GetSampleImageData(const std::string& url) {
85 // Create test bitmap.
86 SkBitmap bm;
87 // Being careful with the Bitmap. There are memory-related issue in
88 // crbug.com/101781.
89 bm.allocN32Pixels(4, 4);
90 bm.eraseColor(SK_ColorRED);
91 ImageData data;
92 data.set_url(url);
93 std::vector<unsigned char> encoded;
mathpa27b85e2014-10-10 19:19:5794 EXPECT_TRUE(EncodeSkBitmapToJPEG(bm, &encoded));
mathpc3c8b0e2014-09-29 15:25:1395 data.set_data(std::string(encoded.begin(), encoded.end()));
96 return data;
97 }
98
Dan Harrington343f6d9f2018-03-19 19:11:1699 void OnImageAvailable(base::RunLoop* loop,
100 const GURL& url,
markusheintz55ae1162016-05-25 08:20:57101 const gfx::Image& image) {
102 if (!image.IsEmpty()) {
mathpc3c8b0e2014-09-29 15:25:13103 num_callback_valid_called_++;
104 } else {
105 num_callback_null_called_++;
106 }
107 loop->Quit();
108 }
109
mathp60143a32014-10-08 14:52:45110 ImageManager* CreateImageManager(FakeDB<ImageData>* fake_db) {
mathpc3c8b0e2014-09-29 15:25:13111 mock_image_fetcher_ = new StrictMock<MockImageFetcher>();
danakj501f8012016-04-22 22:49:25112 return new ImageManager(base::WrapUnique(mock_image_fetcher_),
113 base::WrapUnique(fake_db),
Marc Treibfa8e035a2017-06-16 12:15:47114 FakeDB<ImageData>::DirectoryForTestDB());
mathpc3c8b0e2014-09-29 15:25:13115 }
116
117 EntryMap db_model_;
118 // Owned by the ImageManager under test.
119 FakeDB<ImageData>* fake_db_;
120
121 MockImageFetcher* mock_image_fetcher_;
122
123 int num_callback_null_called_;
124 int num_callback_valid_called_;
dskiba960b00e2015-06-11 22:44:46125
fdoray0d831272017-04-06 16:50:19126 base::test::ScopedTaskEnvironment scoped_task_environment_;
dskiba960b00e2015-06-11 22:44:46127
mathpc3c8b0e2014-09-29 15:25:13128 // Under test.
danakj501f8012016-04-22 22:49:25129 std::unique_ptr<ImageManager> image_manager_;
mathpc3c8b0e2014-09-29 15:25:13130};
131
132TEST_F(ImageManagerTest, InitializeTest) {
133 SuggestionsProfile suggestions_profile;
134 ChromeSuggestion* suggestion = suggestions_profile.add_suggestions();
135 suggestion->set_url(kTestUrl1);
136 suggestion->set_thumbnail(kTestImagePath);
137
138 image_manager_->Initialize(suggestions_profile);
139
140 GURL output;
141 EXPECT_TRUE(image_manager_->GetImageURL(GURL(kTestUrl1), &output));
142 EXPECT_EQ(GURL(kTestImagePath), output);
143
144 EXPECT_FALSE(image_manager_->GetImageURL(GURL("http://b.com"), &output));
145}
146
treibac5372f2015-09-09 09:08:22147TEST_F(ImageManagerTest, AddImageURL) {
148 InitializeDefaultImageMapAndDatabase(image_manager_.get(), fake_db_);
149
150 GURL output;
151 // Try a URL the ImageManager doesn't know about.
152 ASSERT_FALSE(image_manager_->GetImageURL(GURL(kTestUrl2), &output));
153
154 // Explicitly add the URL and try again.
155 image_manager_->AddImageURL(GURL(kTestUrl2), GURL(kTestImagePath));
156 EXPECT_TRUE(image_manager_->GetImageURL(GURL(kTestUrl2), &output));
157 EXPECT_EQ(GURL(kTestImagePath), output);
158}
159
mathpc3c8b0e2014-09-29 15:25:13160TEST_F(ImageManagerTest, GetImageForURLNetwork) {
161 InitializeDefaultImageMapAndDatabase(image_manager_.get(), fake_db_);
162
163 // We expect the fetcher to go to network and call the callback.
Dan Harrington343f6d9f2018-03-19 19:11:16164 EXPECT_CALL(*mock_image_fetcher_, FetchImageAndData_(_, _, _, _, _));
mathpc3c8b0e2014-09-29 15:25:13165
166 // Fetch existing URL.
167 base::RunLoop run_loop;
168 image_manager_->GetImageForURL(GURL(kTestUrl1),
169 base::Bind(&ImageManagerTest::OnImageAvailable,
170 base::Unretained(this), &run_loop));
171
172 // Will not go to network and use the fetcher since URL is invalid.
173 // Fetch non-existing URL.
174 image_manager_->GetImageForURL(GURL(kTestUrl2),
175 base::Bind(&ImageManagerTest::OnImageAvailable,
176 base::Unretained(this), &run_loop));
177 run_loop.Run();
178
179 EXPECT_EQ(1, num_callback_null_called_);
180}
181
182TEST_F(ImageManagerTest, GetImageForURLNetworkCacheHit) {
183 SuggestionsProfile suggestions_profile;
184 ChromeSuggestion* suggestion = suggestions_profile.add_suggestions();
185 suggestion->set_url(kTestUrl1);
186 // The URL we set is invalid, to show that it will fail from network.
187 suggestion->set_thumbnail(kInvalidImagePath);
188
189 // Create the ImageManager with an added entry in the database.
190 AddEntry(GetSampleImageData(kTestUrl1), &db_model_);
191 FakeDB<ImageData>* fake_db = new FakeDB<ImageData>(&db_model_);
mathp60143a32014-10-08 14:52:45192 image_manager_.reset(CreateImageManager(fake_db));
mathpc3c8b0e2014-09-29 15:25:13193 image_manager_->Initialize(suggestions_profile);
194 fake_db->InitCallback(true);
195 fake_db->LoadCallback(true);
196 // Expect something in the cache.
dskiba960b00e2015-06-11 22:44:46197 auto encoded_image =
198 image_manager_->GetEncodedImageFromCache(GURL(kTestUrl1));
scheib4dac7f02016-05-12 00:55:03199 EXPECT_TRUE(encoded_image);
mathpc3c8b0e2014-09-29 15:25:13200
201 base::RunLoop run_loop;
202 image_manager_->GetImageForURL(GURL(kTestUrl1),
203 base::Bind(&ImageManagerTest::OnImageAvailable,
204 base::Unretained(this), &run_loop));
205 run_loop.Run();
206
207 EXPECT_EQ(0, num_callback_null_called_);
208 EXPECT_EQ(1, num_callback_valid_called_);
209}
210
Siddhartha68c5d492018-02-12 21:00:10211TEST_F(ImageManagerTest, QueueImageRequest) {
212 SuggestionsProfile suggestions_profile;
213 ChromeSuggestion* suggestion = suggestions_profile.add_suggestions();
214 suggestion->set_url(kTestUrl1);
215 // The URL we set is invalid, to show that it will fail from network.
216 suggestion->set_thumbnail(kInvalidImagePath);
217
218 // Create the ImageManager with an added entry in the database.
219 AddEntry(GetSampleImageData(kTestUrl1), &db_model_);
220 FakeDB<ImageData>* fake_db = new FakeDB<ImageData>(&db_model_);
221 image_manager_.reset(CreateImageManager(fake_db));
222 image_manager_->Initialize(suggestions_profile);
223
224 base::RunLoop run_loop1;
225 base::RunLoop run_loop2;
226 image_manager_->GetImageForURL(
227 GURL(kTestUrl1), base::BindRepeating(&ImageManagerTest::OnImageAvailable,
228 base::Unretained(this), &run_loop1));
229 image_manager_->GetImageForURL(
230 GURL(kTestUrl1), base::BindRepeating(&ImageManagerTest::OnImageAvailable,
231 base::Unretained(this), &run_loop2));
232 base::RunLoop().RunUntilIdle();
233
234 EXPECT_EQ(0, num_callback_null_called_);
235 EXPECT_EQ(0, num_callback_valid_called_);
236 EXPECT_EQ(1u, image_manager_->pending_cache_requests_.size());
237 EXPECT_EQ(
238 2u,
239 image_manager_->pending_cache_requests_.begin()->second.callbacks.size());
240
241 fake_db->InitCallback(true);
242 fake_db->LoadCallback(true);
243 run_loop1.Run();
244 run_loop2.Run();
245
246 EXPECT_EQ(0, num_callback_null_called_);
247 EXPECT_EQ(2, num_callback_valid_called_);
248 EXPECT_EQ(0u, image_manager_->pending_cache_requests_.size());
249}
250
mathpc3c8b0e2014-09-29 15:25:13251} // namespace suggestions