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. 4 5#include <string> 6 7#include "base/files/file_path.h" 8#include "base/run_loop.h" 9#include "chrome/browser/profiles/profile.h" 10#include "chrome/browser/search/suggestions/image_manager_impl.h" 11#include "chrome/browser/ui/browser.h" 12#include "chrome/test/base/in_process_browser_test.h" 13#include "components/leveldb_proto/proto_database.h" 14#include "components/leveldb_proto/testing/fake_db.h" 15#include "components/suggestions/proto/suggestions.pb.h" 16#include "content/public/test/test_utils.h" 17#include "net/base/load_flags.h" 18#include "net/test/spawned_test_server/spawned_test_server.h" 19#include "testing/gtest/include/gtest/gtest.h" 20#include "ui/gfx/image/image_skia.h" 21#include "url/gurl.h" 22 23namespace suggestions { 24 25const char kTestUrl1[] = "http://go.com/"; 26const char kTestUrl2[] = "http://goal.com/"; 27const char kTestBitmapUrl[] = "http://test.com"; 28const char kTestImagePath[] = "files/image_decoding/droids.png"; 29const char kInvalidImagePath[] = "files/DOESNOTEXIST"; 30 31const base::FilePath::CharType kDocRoot[] = 32 FILE_PATH_LITERAL("chrome/test/data"); 33 34using chrome::BitmapFetcher; 35using content::BrowserThread; 36using leveldb_proto::test::FakeDB; 37using suggestions::ImageData; 38using suggestions::ImageManagerImpl; 39 40typedef base::hash_map<std::string, ImageData> EntryMap; 41 42void AddEntry(const ImageData& d, EntryMap* map) { (*map)[d.url()] = d; } 43 44class ImageManagerImplBrowserTest : public InProcessBrowserTest { 45 public: 46 ImageManagerImplBrowserTest() 47 : num_callback_null_called_(0), 48 num_callback_valid_called_(0), 49 test_server_(net::SpawnedTestServer::TYPE_HTTP, 50 net::SpawnedTestServer::kLocalhost, 51 base::FilePath(kDocRoot)) {} 52 53 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 54 ASSERT_TRUE(test_server_.Start()); 55 InProcessBrowserTest::SetUpInProcessBrowserTestFixture(); 56 } 57 58 virtual void TearDownInProcessBrowserTestFixture() OVERRIDE { 59 test_server_.Stop(); 60 } 61 62 virtual void SetUpOnMainThread() OVERRIDE { 63 fake_db_ = new FakeDB<ImageData>(&db_model_); 64 image_manager_.reset(CreateImageManagerImpl(fake_db_)); 65 } 66 67 virtual void TearDownOnMainThread() OVERRIDE { 68 fake_db_ = NULL; 69 db_model_.clear(); 70 image_manager_.reset(); 71 test_image_manager_.reset(); 72 } 73 74 void InitializeTestBitmapData() { 75 FakeDB<ImageData>* test_fake_db = new FakeDB<ImageData>(&db_model_); 76 test_image_manager_.reset(CreateImageManagerImpl(test_fake_db)); 77 78 suggestions::SuggestionsProfile suggestions_profile; 79 suggestions::ChromeSuggestion* suggestion = 80 suggestions_profile.add_suggestions(); 81 suggestion->set_url(kTestBitmapUrl); 82 suggestion->set_thumbnail(test_server_.GetURL(kTestImagePath).spec()); 83 84 test_image_manager_->Initialize(suggestions_profile); 85 86 // Initialize empty database. 87 test_fake_db->InitCallback(true); 88 test_fake_db->LoadCallback(true); 89 90 base::RunLoop run_loop; 91 // Fetch existing URL. 92 test_image_manager_->GetImageForURL( 93 GURL(kTestBitmapUrl), 94 base::Bind(&ImageManagerImplBrowserTest::OnTestImageAvailable, 95 base::Unretained(this), &run_loop)); 96 run_loop.Run(); 97 } 98 99 void OnTestImageAvailable(base::RunLoop* loop, const GURL& url, 100 const SkBitmap* bitmap) { 101 CHECK(bitmap); 102 // Copy the resource locally. 103 test_bitmap_ = *bitmap; 104 loop->Quit(); 105 } 106 107 void InitializeDefaultImageMapAndDatabase( 108 ImageManagerImpl* image_manager, FakeDB<ImageData>* fake_db) { 109 CHECK(image_manager); 110 CHECK(fake_db); 111 112 suggestions::SuggestionsProfile suggestions_profile; 113 suggestions::ChromeSuggestion* suggestion = 114 suggestions_profile.add_suggestions(); 115 suggestion->set_url(kTestUrl1); 116 suggestion->set_thumbnail(test_server_.GetURL(kTestImagePath).spec()); 117 118 image_manager->Initialize(suggestions_profile); 119 120 // Initialize empty database. 121 fake_db->InitCallback(true); 122 fake_db->LoadCallback(true); 123 } 124 125 ImageData GetSampleImageData(const std::string& url) { 126 ImageData data; 127 data.set_url(url); 128 std::vector<unsigned char> encoded; 129 EXPECT_TRUE(ImageManagerImpl::EncodeImage(test_bitmap_, &encoded)); 130 data.set_data(std::string(encoded.begin(), encoded.end())); 131 return data; 132 } 133 134 void OnImageAvailable(base::RunLoop* loop, const GURL& url, 135 const SkBitmap* bitmap) { 136 if (bitmap) { 137 num_callback_valid_called_++; 138 std::vector<unsigned char> actual; 139 std::vector<unsigned char> expected; 140 EXPECT_TRUE(ImageManagerImpl::EncodeImage(*bitmap, &actual)); 141 EXPECT_TRUE(ImageManagerImpl::EncodeImage(test_bitmap_, &expected)); 142 // Check first 100 bytes. 143 std::string actual_str(actual.begin(), actual.begin() + 100); 144 std::string expected_str(expected.begin(), expected.begin() + 100); 145 EXPECT_EQ(expected_str, actual_str); 146 } else { 147 num_callback_null_called_++; 148 } 149 loop->Quit(); 150 } 151 152 ImageManagerImpl* CreateImageManagerImpl(FakeDB<ImageData>* fake_db) { 153 return new ImageManagerImpl( 154 browser()->profile()->GetRequestContext(), 155 scoped_ptr<leveldb_proto::ProtoDatabase<ImageData> >(fake_db), 156 FakeDB<ImageData>::DirectoryForTestDB()); 157 } 158 159 EntryMap db_model_; 160 // Owned by the ImageManagerImpl under test. 161 FakeDB<ImageData>* fake_db_; 162 163 SkBitmap test_bitmap_; 164 scoped_ptr<ImageManagerImpl> test_image_manager_; 165 166 int num_callback_null_called_; 167 int num_callback_valid_called_; 168 net::SpawnedTestServer test_server_; 169 // Under test. 170 scoped_ptr<ImageManagerImpl> image_manager_; 171}; 172 173IN_PROC_BROWSER_TEST_F(ImageManagerImplBrowserTest, GetImageForURLNetwork) { 174 InitializeTestBitmapData(); 175 InitializeDefaultImageMapAndDatabase(image_manager_.get(), fake_db_); 176 177 base::RunLoop run_loop; 178 // Fetch existing URL. 179 image_manager_->GetImageForURL( 180 GURL(kTestUrl1), 181 base::Bind(&ImageManagerImplBrowserTest::OnImageAvailable, 182 base::Unretained(this), &run_loop)); 183 run_loop.Run(); 184 185 EXPECT_EQ(0, num_callback_null_called_); 186 EXPECT_EQ(1, num_callback_valid_called_); 187 188 base::RunLoop run_loop2; 189 // Fetch non-existing URL. 190 image_manager_->GetImageForURL( 191 GURL(kTestUrl2), 192 base::Bind(&ImageManagerImplBrowserTest::OnImageAvailable, 193 base::Unretained(this), &run_loop2)); 194 run_loop2.Run(); 195 196 EXPECT_EQ(1, num_callback_null_called_); 197 EXPECT_EQ(1, num_callback_valid_called_); 198} 199 200IN_PROC_BROWSER_TEST_F(ImageManagerImplBrowserTest, 201 GetImageForURLNetworkMultiple) { 202 InitializeTestBitmapData(); 203 InitializeDefaultImageMapAndDatabase(image_manager_.get(), fake_db_); 204 205 // Fetch non-existing URL, and add more while request is in flight. 206 base::RunLoop run_loop; 207 for (int i = 0; i < 5; i++) { 208 // Fetch existing URL. 209 image_manager_->GetImageForURL( 210 GURL(kTestUrl1), 211 base::Bind(&ImageManagerImplBrowserTest::OnImageAvailable, 212 base::Unretained(this), &run_loop)); 213 } 214 run_loop.Run(); 215 216 EXPECT_EQ(0, num_callback_null_called_); 217 EXPECT_EQ(5, num_callback_valid_called_); 218} 219 220IN_PROC_BROWSER_TEST_F(ImageManagerImplBrowserTest, 221 GetImageForURLNetworkInvalid) { 222 SuggestionsProfile suggestions_profile; 223 ChromeSuggestion* suggestion = suggestions_profile.add_suggestions(); 224 suggestion->set_url(kTestUrl1); 225 suggestion->set_thumbnail(test_server_.GetURL(kInvalidImagePath).spec()); 226 227 image_manager_->Initialize(suggestions_profile); 228 229 // Database will be initialized and loaded without anything in it. 230 fake_db_->InitCallback(true); 231 fake_db_->LoadCallback(true); 232 233 base::RunLoop run_loop; 234 // Fetch existing URL that has invalid image. 235 image_manager_->GetImageForURL( 236 GURL(kTestUrl1), 237 base::Bind(&ImageManagerImplBrowserTest::OnImageAvailable, 238 base::Unretained(this), &run_loop)); 239 run_loop.Run(); 240 241 EXPECT_EQ(1, num_callback_null_called_); 242 EXPECT_EQ(0, num_callback_valid_called_); 243} 244 245IN_PROC_BROWSER_TEST_F(ImageManagerImplBrowserTest, 246 GetImageForURLNetworkCacheHit) { 247 InitializeTestBitmapData(); 248 249 SuggestionsProfile suggestions_profile; 250 ChromeSuggestion* suggestion = suggestions_profile.add_suggestions(); 251 suggestion->set_url(kTestUrl1); 252 // The URL we set is invalid, to show that it will fail from network. 253 suggestion->set_thumbnail(test_server_.GetURL(kInvalidImagePath).spec()); 254 255 // Create the ImageManagerImpl with an added entry in the database. 256 AddEntry(GetSampleImageData(kTestUrl1), &db_model_); 257 FakeDB<ImageData>* fake_db = new FakeDB<ImageData>(&db_model_); 258 image_manager_.reset(CreateImageManagerImpl(fake_db)); 259 image_manager_->Initialize(suggestions_profile); 260 fake_db->InitCallback(true); 261 fake_db->LoadCallback(true); 262 // Expect something in the cache. 263 SkBitmap* bitmap = image_manager_->GetBitmapFromCache(GURL(kTestUrl1)); 264 EXPECT_FALSE(bitmap->isNull()); 265 266 base::RunLoop run_loop; 267 image_manager_->GetImageForURL( 268 GURL(kTestUrl1), 269 base::Bind(&ImageManagerImplBrowserTest::OnImageAvailable, 270 base::Unretained(this), &run_loop)); 271 run_loop.Run(); 272 273 EXPECT_EQ(0, num_callback_null_called_); 274 EXPECT_EQ(1, num_callback_valid_called_); 275} 276 277} // namespace suggestions 278