Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(595)

Side by Side Diff: chrome/browser/image_decoder_browsertest.cc

Issue 1129653002: Wait for pending requests to finish in ImageDecoder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: remove freeze test Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/image_decoder.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/image_decoder.h" 5 #include "chrome/browser/image_decoder.h"
6 6
7 #if defined(OS_POSIX) 7 #include "chrome/grit/generated_resources.h"
8 #include <sys/types.h>
9 #include <signal.h>
10 #endif
11
12 #include "chrome/test/base/in_process_browser_test.h" 8 #include "chrome/test/base/in_process_browser_test.h"
13 #include "content/public/browser/browser_child_process_observer.h" 9 #include "content/public/browser/browser_child_process_observer.h"
14 #include "content/public/browser/browser_thread.h" 10 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/child_process_data.h" 11 #include "content/public/browser/child_process_data.h"
16 #include "content/public/test/test_utils.h" 12 #include "content/public/test/test_utils.h"
13 #include "ui/base/l10n/l10n_util.h"
17 14
18 using content::BrowserThread; 15 using content::BrowserThread;
19 16
20 namespace { 17 namespace {
21 18
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);
29 }
30
22 class TestImageRequest : public ImageDecoder::ImageRequest { 31 class TestImageRequest : public ImageDecoder::ImageRequest {
23 public: 32 public:
24 explicit TestImageRequest(const base::Closure& quit_closure) 33 explicit TestImageRequest(const base::Closure& quit_closure)
25 : quit_closure_(quit_closure), 34 : decode_succeeded_(false),
35 quit_closure_(quit_closure),
26 quit_called_(false) { 36 quit_called_(false) {
27 } 37 }
28 38
29 ~TestImageRequest() override { 39 ~TestImageRequest() override {
30 if (!quit_called_) { 40 if (!quit_called_) {
31 quit_closure_.Run(); 41 quit_closure_.Run();
32 } 42 }
33 } 43 }
34 44
45 bool decode_succeeded() const { return decode_succeeded_; }
46
35 private: 47 private:
36 void OnImageDecoded(const SkBitmap& decoded_image) override { 48 void OnImageDecoded(const SkBitmap& decoded_image) override {
49 decode_succeeded_ = true;
37 Quit(); 50 Quit();
38 } 51 }
39 52
40 void OnDecodeImageFailed() override { 53 void OnDecodeImageFailed() override {
41 Quit(); 54 Quit();
42 } 55 }
43 56
44 void Quit() { 57 void Quit() {
45 EXPECT_FALSE(quit_called_); 58 EXPECT_FALSE(quit_called_);
46 quit_called_ = true; 59 quit_called_ = true;
47 quit_closure_.Run(); 60 quit_closure_.Run();
48 } 61 }
49 62
63 bool decode_succeeded_;
64
50 base::Closure quit_closure_; 65 base::Closure quit_closure_;
51 bool quit_called_; 66 bool quit_called_;
52 67
53 DISALLOW_COPY_AND_ASSIGN(TestImageRequest); 68 DISALLOW_COPY_AND_ASSIGN(TestImageRequest);
54 }; 69 };
55 70
56 class KillProcessObserver : public content::BrowserChildProcessObserver { 71 class KillProcessObserver : public content::BrowserChildProcessObserver {
57 public: 72 public:
58 KillProcessObserver() { 73 KillProcessObserver()
74 : did_kill_(false),
75 utility_process_name_(
76 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_IMAGE_DECODER_NAME)) {
59 Add(this); 77 Add(this);
60 } 78 }
61 79
62 ~KillProcessObserver() override { 80 ~KillProcessObserver() override {
63 Remove(this); 81 Remove(this);
64 } 82 }
65 83
84 bool did_kill() const { return did_kill_; }
85
66 private: 86 private:
67 void BrowserChildProcessHostConnected( 87 void BrowserChildProcessHostConnected(
68 const content::ChildProcessData& data) override { 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;
93 }
94
95 ASSERT_FALSE(did_kill_);
69 base::ProcessHandle handle = data.handle; 96 base::ProcessHandle handle = data.handle;
70 97
71 if (handle == base::kNullProcessHandle)
72 return;
73
74 #if defined(OS_WIN) 98 #if defined(OS_WIN)
75 // On windows, duplicate the process handle since base::Process closes it on 99 // On windows, duplicate the process handle since base::Process closes it on
76 // destruction. 100 // destruction.
77 base::ProcessHandle out_handle; 101 base::ProcessHandle out_handle;
78 if (!::DuplicateHandle(GetCurrentProcess(), handle, 102 if (!::DuplicateHandle(GetCurrentProcess(), handle,
79 GetCurrentProcess(), &out_handle, 103 GetCurrentProcess(), &out_handle,
80 0, FALSE, DUPLICATE_SAME_ACCESS)) 104 0, FALSE, DUPLICATE_SAME_ACCESS)) {
81 return; 105 return;
106 }
82 handle = out_handle; 107 handle = out_handle;
83 #endif 108 #endif
84 109
85 EXPECT_TRUE(base::Process(handle).Terminate(0, true)); 110 // Use a non-zero exit code so it counts as a crash.
86 } 111 EXPECT_TRUE(base::Process(handle).Terminate(1, true));
87 }; 112 did_kill_ = true;
88
89 #if defined(OS_POSIX)
90 class FreezeProcessObserver : public content::BrowserChildProcessObserver {
91 public:
92 FreezeProcessObserver() {
93 Add(this);
94 } 113 }
95 114
96 ~FreezeProcessObserver() override { 115 bool did_kill_;
97 Remove(this); 116 const base::string16 utility_process_name_;
98 }
99 117
100 private: 118 DISALLOW_COPY_AND_ASSIGN(KillProcessObserver);
101 void BrowserChildProcessHostConnected(
102 const content::ChildProcessData& data) override {
103 if (data.handle != base::kNullProcessHandle)
104 EXPECT_EQ(0, kill(data.handle, SIGSTOP));
105 }
106 }; 119 };
107 #endif // defined(OS_POSIX)
108 120
109 } // namespace 121 } // namespace
110 122
111 class ImageDecoderBrowserTest : public InProcessBrowserTest { 123 class ImageDecoderBrowserTest : public InProcessBrowserTest {
112 }; 124 };
113 125
114 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, Basic) { 126 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, Basic) {
115 scoped_refptr<content::MessageLoopRunner> runner = 127 scoped_refptr<content::MessageLoopRunner> runner =
116 new content::MessageLoopRunner; 128 new content::MessageLoopRunner;
117 TestImageRequest test_request(runner->QuitClosure()); 129 TestImageRequest test_request(runner->QuitClosure());
118 ImageDecoder::Start(&test_request, std::string()); 130 ImageDecoder::Start(&test_request, std::string());
119 runner->Run(); 131 runner->Run();
132 EXPECT_FALSE(test_request.decode_succeeded());
133 }
134
135 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecode) {
136 scoped_refptr<content::MessageLoopRunner> runner =
137 new content::MessageLoopRunner;
138 TestImageRequest test_request(runner->QuitClosure());
139 ImageDecoder::Start(&test_request, GetValidPngString());
140 runner->Run();
141 EXPECT_TRUE(test_request.decode_succeeded());
120 } 142 }
121 143
122 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndDestroy) { 144 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndDestroy) {
123 scoped_refptr<content::MessageLoopRunner> runner = 145 scoped_refptr<content::MessageLoopRunner> runner =
124 new content::MessageLoopRunner; 146 new content::MessageLoopRunner;
125 scoped_ptr<TestImageRequest> test_request( 147 scoped_ptr<TestImageRequest> test_request(
126 new TestImageRequest(runner->QuitClosure())); 148 new TestImageRequest(runner->QuitClosure()));
127 ImageDecoder::Start(test_request.get(), std::string()); 149 ImageDecoder::Start(test_request.get(), std::string());
128 test_request.reset(); 150 test_request.reset();
129 runner->Run(); 151 runner->Run();
130 } 152 }
131 153
154 // Killing the utility process counts as a crash. Thus the request fails.
155 // If ImageDecoder did not handle the crash properly, the request never finishes
156 // and this test would hang.
157 // Note: This test is inherently racy because KillProcessObserver lives on the
158 // UI thread but ImageDecoder does its work mainly on the IO thread. So the test
159 // checks for both possible valid outcomes.
132 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndKillProcess) { 160 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndKillProcess) {
133 KillProcessObserver observer; 161 KillProcessObserver observer;
134 scoped_refptr<content::MessageLoopRunner> runner = 162 scoped_refptr<content::MessageLoopRunner> runner =
135 new content::MessageLoopRunner; 163 new content::MessageLoopRunner;
136 scoped_ptr<TestImageRequest> test_request( 164 TestImageRequest test_request(runner->QuitClosure());
137 new TestImageRequest(runner->QuitClosure())); 165 ImageDecoder::Start(&test_request, GetValidPngString());
138 ImageDecoder::Start(test_request.get(), std::string());
139 runner->Run(); 166 runner->Run();
167 if (!test_request.decode_succeeded()) {
168 // The UI thread won the race. Make sure the utility process did get killed.
169 EXPECT_TRUE(observer.did_kill());
170 }
171 // Else the IO thread won the race and the image got decoded. Oh well.
140 } 172 }
141
142 #if defined(OS_POSIX)
143 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndFreezeProcess) {
144 FreezeProcessObserver observer;
145 scoped_refptr<content::MessageLoopRunner> runner =
146 new content::MessageLoopRunner;
147 scoped_ptr<TestImageRequest> test_request(
148 new TestImageRequest(runner->QuitClosure()));
149 ImageDecoder::Start(test_request.get(), std::string());
150 runner->Run();
151 }
152 #endif // defined(OS_POSIX)
OLDNEW
« no previous file with comments | « chrome/browser/image_decoder.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698