Prepare for VS2015 toolchain
[chromium-blink-merge.git] / chrome / browser / image_decoder_browsertest.cc
blobd9350dec04185956e39e6e47be7b933875b653ed
1 // Copyright 2015 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.
5 #include "chrome/browser/image_decoder.h"
7 #include "chrome/grit/generated_resources.h"
8 #include "chrome/test/base/in_process_browser_test.h"
9 #include "content/public/browser/browser_child_process_observer.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/child_process_data.h"
12 #include "content/public/test/test_utils.h"
13 #include "ui/base/l10n/l10n_util.h"
15 using content::BrowserThread;
17 namespace {
19 std::string GetValidPngString() {
20 // 1x1 PNG. Does not get much smaller than this.
21 static const char kPngData[] =
22 "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52"
23 "\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90\x77\x53"
24 "\xde\x00\x00\x00\x0c\x49\x44\x41\x54\x08\xd7\x63\xf8\xff\xff\x3f"
25 "\x00\x05\xfe\x02\xfe\xdc\xcc\x59\xe7\x00\x00\x00\x00\x49\x45\x4e"
26 "\x44\xae\x42\x60\x82";
27 // Need to specify the buffer size because it contains NULs.
28 return std::string(kPngData, sizeof(kPngData) - 1);
31 class TestImageRequest : public ImageDecoder::ImageRequest {
32 public:
33 explicit TestImageRequest(const base::Closure& quit_closure)
34 : decode_succeeded_(false),
35 quit_closure_(quit_closure),
36 quit_called_(false) {
39 ~TestImageRequest() override {
40 if (!quit_called_) {
41 quit_closure_.Run();
45 bool decode_succeeded() const { return decode_succeeded_; }
47 private:
48 void OnImageDecoded(const SkBitmap& decoded_image) override {
49 decode_succeeded_ = true;
50 Quit();
53 void OnDecodeImageFailed() override {
54 Quit();
57 void Quit() {
58 EXPECT_FALSE(quit_called_);
59 quit_called_ = true;
60 quit_closure_.Run();
63 bool decode_succeeded_;
65 base::Closure quit_closure_;
66 bool quit_called_;
68 DISALLOW_COPY_AND_ASSIGN(TestImageRequest);
71 class KillProcessObserver : public content::BrowserChildProcessObserver {
72 public:
73 KillProcessObserver()
74 : did_kill_(false),
75 utility_process_name_(
76 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_IMAGE_DECODER_NAME)) {
77 Add(this);
80 ~KillProcessObserver() override {
81 Remove(this);
84 bool did_kill() const { return did_kill_; }
86 private:
87 void BrowserChildProcessHostConnected(
88 const content::ChildProcessData& data) override {
89 DCHECK_CURRENTLY_ON(BrowserThread::UI);
90 if (data.handle == base::kNullProcessHandle ||
91 data.name != utility_process_name_) {
92 return;
95 ASSERT_FALSE(did_kill_);
96 base::ProcessHandle handle = data.handle;
98 #if defined(OS_WIN)
99 // On windows, duplicate the process handle since base::Process closes it on
100 // destruction.
101 base::ProcessHandle out_handle;
102 if (!::DuplicateHandle(GetCurrentProcess(), handle,
103 GetCurrentProcess(), &out_handle,
104 0, FALSE, DUPLICATE_SAME_ACCESS)) {
105 return;
107 handle = out_handle;
108 #endif
110 // Use a non-zero exit code so it counts as a crash.
111 // Don't wait for the process after sending the termination signal
112 // (SIGTERM). According to POSIX, doing so causes the resulting zombie to be
113 // removed from the process table. However, Chromium treats an error on
114 // |waitpid| (in this case, ECHILD) as a "normal" termination and doesn't
115 // invoke the process host delegate's OnProcessCrashed().
116 EXPECT_TRUE(base::Process(handle).Terminate(1, false));
117 did_kill_ = true;
120 bool did_kill_;
121 const base::string16 utility_process_name_;
123 DISALLOW_COPY_AND_ASSIGN(KillProcessObserver);
126 } // namespace
128 class ImageDecoderBrowserTest : public InProcessBrowserTest {
131 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, Basic) {
132 scoped_refptr<content::MessageLoopRunner> runner =
133 new content::MessageLoopRunner;
134 TestImageRequest test_request(runner->QuitClosure());
135 ImageDecoder::Start(&test_request, std::string());
136 runner->Run();
137 EXPECT_FALSE(test_request.decode_succeeded());
140 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecode) {
141 scoped_refptr<content::MessageLoopRunner> runner =
142 new content::MessageLoopRunner;
143 TestImageRequest test_request(runner->QuitClosure());
144 ImageDecoder::Start(&test_request, GetValidPngString());
145 runner->Run();
146 EXPECT_TRUE(test_request.decode_succeeded());
149 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndDestroy) {
150 scoped_refptr<content::MessageLoopRunner> runner =
151 new content::MessageLoopRunner;
152 scoped_ptr<TestImageRequest> test_request(
153 new TestImageRequest(runner->QuitClosure()));
154 ImageDecoder::Start(test_request.get(), std::string());
155 test_request.reset();
156 runner->Run();
159 // Killing the utility process counts as a crash. Thus the request fails.
160 // If ImageDecoder did not handle the crash properly, the request never finishes
161 // and this test would hang.
162 // Note: This test is inherently racy because KillProcessObserver lives on the
163 // UI thread but ImageDecoder does its work mainly on the IO thread. So the test
164 // checks for both possible valid outcomes.
165 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndKillProcess) {
166 KillProcessObserver observer;
167 scoped_refptr<content::MessageLoopRunner> runner =
168 new content::MessageLoopRunner;
169 TestImageRequest test_request(runner->QuitClosure());
170 ImageDecoder::Start(&test_request, GetValidPngString());
171 runner->Run();
172 if (!test_request.decode_succeeded()) {
173 // The UI thread won the race. Make sure the utility process did get killed.
174 EXPECT_TRUE(observer.did_kill());
176 // Else the IO thread won the race and the image got decoded. Oh well.