blob: ed0818a9f257b4e31e3fea4eb644400e0531cf05 [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.h"
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/test_utils.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request_status.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/skia_util.h"
const bool kAsyncCall = true;
const bool kSyncCall = false;
const char kStartTestURL[] = "/this-should-work";
const char kOnImageDecodedTestURL[] = "/this-should-work-as-well";
const char kOnURLFetchFailureTestURL[] = "/this-should-be-fetch-failure";
using net::test_server::BasicHttpResponse;
using net::test_server::HttpRequest;
using net::test_server::HttpResponse;
// Class to catch events from the BitmapFetcher for testing.
class BitmapFetcherTestDelegate : public BitmapFetcherDelegate {
public:
explicit BitmapFetcherTestDelegate(bool async) : called_(false),
success_(false),
async_(async) {}
~BitmapFetcherTestDelegate() override { EXPECT_TRUE(called_); }
// Method inherited from BitmapFetcherDelegate.
void OnFetchComplete(const GURL& url, const SkBitmap* bitmap) override {
called_ = true;
url_ = url;
if (bitmap) {
success_ = true;
if (bitmap_.tryAllocPixels(bitmap->info())) {
bitmap->readPixels(bitmap_.info(), bitmap_.getPixels(),
bitmap_.rowBytes(), 0, 0);
}
}
// For async calls, we need to quit the run loop so the test can continue.
if (async_)
run_loop_.Quit();
}
// Waits until OnFetchComplete() is called. Should only be used for
// async tests.
void Wait() {
ASSERT_TRUE(async_);
run_loop_.Run();
}
GURL url() const { return url_; }
bool success() const { return success_; }
const SkBitmap& bitmap() const { return bitmap_; }
private:
base::RunLoop run_loop_;
bool called_;
GURL url_;
bool success_;
bool async_;
SkBitmap bitmap_;
DISALLOW_COPY_AND_ASSIGN(BitmapFetcherTestDelegate);
};
class BitmapFetcherBrowserTest : public InProcessBrowserTest {
public:
// InProcessBrowserTest overrides:
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
// Set up the test server.
embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
&BitmapFetcherBrowserTest::HandleRequest, base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
}
void TearDownOnMainThread() override {
// Tear down the test server.
EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
InProcessBrowserTest::TearDownOnMainThread();
}
protected:
SkBitmap test_bitmap() const {
// Return some realistic looking bitmap data
SkBitmap image;
// Put a real bitmap into "image". 2x2 bitmap of green 32 bit pixels.
image.allocN32Pixels(2, 2);
image.eraseColor(SK_ColorGREEN);
return image;
}
private:
std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
std::unique_ptr<BasicHttpResponse> response(new BasicHttpResponse);
if (request.relative_url == kStartTestURL) {
// Encode the bits as a PNG.
std::vector<unsigned char> compressed;
gfx::PNGCodec::EncodeBGRASkBitmap(test_bitmap(), true, &compressed);
// Copy the bits into a string and return them through the embedded
// test server
std::string image_string(compressed.begin(), compressed.end());
response->set_code(net::HTTP_OK);
response->set_content(image_string);
} else if (request.relative_url == kOnImageDecodedTestURL) {
response->set_code(net::HTTP_INTERNAL_SERVER_ERROR);
} else if (request.relative_url == kOnURLFetchFailureTestURL) {
response->set_code(net::HTTP_OK);
response->set_content(std::string("Not a real bitmap"));
}
return std::move(response);
}
};
// WARNING: These tests work with --single_process, but not
// --single-process. The reason is that the sandbox does not get created
// for us by the test process if --single-process is used.
IN_PROC_BROWSER_TEST_F(BitmapFetcherBrowserTest, StartTest) {
GURL url = embedded_test_server()->GetURL(kStartTestURL);
// Set up a delegate to wait for the callback.
BitmapFetcherTestDelegate delegate(kAsyncCall);
BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
// We expect that the image decoder will get called and return
// an image in a callback to OnImageDecoded().
fetcher.Init(
std::string(),
net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
net::LOAD_NORMAL);
fetcher.Start(
content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
->GetURLLoaderFactoryForBrowserProcess()
.get());
// Blocks until test delegate is notified via a callback.
delegate.Wait();
ASSERT_TRUE(delegate.success());
// Make sure we get back the bitmap we expect.
const SkBitmap& found_image = delegate.bitmap();
EXPECT_TRUE(gfx::BitmapsAreEqual(test_bitmap(), found_image));
}
IN_PROC_BROWSER_TEST_F(BitmapFetcherBrowserTest, OnImageDecodedTest) {
GURL url = embedded_test_server()->GetURL(kOnImageDecodedTestURL);
SkBitmap image;
// Put a real bitmap into "image". 2x2 bitmap of green 16 bit pixels.
image.allocN32Pixels(2, 2);
image.eraseColor(SK_ColorGREEN);
BitmapFetcherTestDelegate delegate(kSyncCall);
BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
fetcher.OnImageDecoded(image);
// Ensure image is marked as succeeded.
EXPECT_TRUE(delegate.success());
// Test that the image is what we expect.
EXPECT_TRUE(gfx::BitmapsAreEqual(image, delegate.bitmap()));
}
IN_PROC_BROWSER_TEST_F(BitmapFetcherBrowserTest, OnURLFetchFailureTest) {
GURL url = embedded_test_server()->GetURL(kOnURLFetchFailureTestURL);
// We intentionally put no data into the bitmap to simulate a failure.
// Set up a delegate to wait for the callback.
BitmapFetcherTestDelegate delegate(kAsyncCall);
BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
fetcher.Init(
std::string(),
net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
net::LOAD_NORMAL);
fetcher.Start(
content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
->GetURLLoaderFactoryForBrowserProcess()
.get());
// Blocks until test delegate is notified via a callback.
delegate.Wait();
EXPECT_FALSE(delegate.success());
}
IN_PROC_BROWSER_TEST_F(BitmapFetcherBrowserTest, HandleImageFailedTest) {
GURL url("http://example.com/this-should-be-a-decode-failure");
BitmapFetcherTestDelegate delegate(kAsyncCall);
BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
fetcher.Init(
std::string(),
net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
net::LOAD_NORMAL);
fetcher.Start(
content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
->GetURLLoaderFactoryForBrowserProcess()
.get());
// Blocks until test delegate is notified via a callback.
delegate.Wait();
EXPECT_FALSE(delegate.success());
}