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

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: Fix kill 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 #if defined(OS_POSIX)
8 #include <sys/types.h> 8 #include <sys/types.h>
9 #include <signal.h> 9 #include <signal.h>
10 #endif 10 #endif
11 11
12 #include "chrome/grit/generated_resources.h"
12 #include "chrome/test/base/in_process_browser_test.h" 13 #include "chrome/test/base/in_process_browser_test.h"
13 #include "content/public/browser/browser_child_process_observer.h" 14 #include "content/public/browser/browser_child_process_observer.h"
14 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/child_process_data.h" 16 #include "content/public/browser/child_process_data.h"
16 #include "content/public/test/test_utils.h" 17 #include "content/public/test/test_utils.h"
18 #include "ui/base/l10n/l10n_util.h"
17 19
18 using content::BrowserThread; 20 using content::BrowserThread;
19 21
20 namespace { 22 namespace {
21 23
24 std::string GetValidPngString() {
25 // 1x1 PNG. Does not get much smaller than this.
26 static const char kPngData[] =
27 "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52"
28 "\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90\x77\x53"
29 "\xde\x00\x00\x00\x0c\x49\x44\x41\x54\x08\xd7\x63\xf8\xff\xff\x3f"
30 "\x00\x05\xfe\x02\xfe\xdc\xcc\x59\xe7\x00\x00\x00\x00\x49\x45\x4e"
31 "\x44\xae\x42\x60\x82";
32 // Need to specify the buffer size because it contains NULs.
33 return std::string(kPngData, sizeof(kPngData) - 1);
34 }
35
22 class TestImageRequest : public ImageDecoder::ImageRequest { 36 class TestImageRequest : public ImageDecoder::ImageRequest {
23 public: 37 public:
24 explicit TestImageRequest(const base::Closure& quit_closure) 38 explicit TestImageRequest(const base::Closure& quit_closure)
25 : quit_closure_(quit_closure), 39 : decode_succeeded_(false),
40 quit_closure_(quit_closure),
26 quit_called_(false) { 41 quit_called_(false) {
27 } 42 }
28 43
29 ~TestImageRequest() override { 44 ~TestImageRequest() override {
30 if (!quit_called_) { 45 if (!quit_called_) {
31 quit_closure_.Run(); 46 quit_closure_.Run();
32 } 47 }
33 } 48 }
34 49
50 const bool decode_succeeded() const { return decode_succeeded_; }
51
35 private: 52 private:
36 void OnImageDecoded(const SkBitmap& decoded_image) override { 53 void OnImageDecoded(const SkBitmap& decoded_image) override {
54 decode_succeeded_ = true;
37 Quit(); 55 Quit();
38 } 56 }
39 57
40 void OnDecodeImageFailed() override { 58 void OnDecodeImageFailed() override {
41 Quit(); 59 Quit();
42 } 60 }
43 61
44 void Quit() { 62 void Quit() {
45 EXPECT_FALSE(quit_called_); 63 EXPECT_FALSE(quit_called_);
46 quit_called_ = true; 64 quit_called_ = true;
47 quit_closure_.Run(); 65 quit_closure_.Run();
48 } 66 }
49 67
68 bool decode_succeeded_;
69
50 base::Closure quit_closure_; 70 base::Closure quit_closure_;
51 bool quit_called_; 71 bool quit_called_;
52 72
53 DISALLOW_COPY_AND_ASSIGN(TestImageRequest); 73 DISALLOW_COPY_AND_ASSIGN(TestImageRequest);
54 }; 74 };
55 75
56 class KillProcessObserver : public content::BrowserChildProcessObserver { 76 class KillProcessObserver : public content::BrowserChildProcessObserver {
57 public: 77 public:
58 KillProcessObserver() { 78 KillProcessObserver()
79 : did_kill_(false),
80 utility_process_name_(
81 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_IMAGE_DECODER_NAME)) {
59 Add(this); 82 Add(this);
60 } 83 }
61 84
62 ~KillProcessObserver() override { 85 ~KillProcessObserver() override {
63 Remove(this); 86 Remove(this);
64 } 87 }
65 88
89 bool did_kill() const { return did_kill_; }
90
66 private: 91 private:
67 void BrowserChildProcessHostConnected( 92 void BrowserChildProcessHostConnected(
68 const content::ChildProcessData& data) override { 93 const content::ChildProcessData& data) override {
94 DCHECK_CURRENTLY_ON(BrowserThread::UI);
95 if (data.handle == base::kNullProcessHandle ||
96 data.name != utility_process_name_) {
97 return;
98 }
99
100 ASSERT_FALSE(did_kill_);
69 base::ProcessHandle handle = data.handle; 101 base::ProcessHandle handle = data.handle;
70 102
71 if (handle == base::kNullProcessHandle)
72 return;
73
74 #if defined(OS_WIN) 103 #if defined(OS_WIN)
75 // On windows, duplicate the process handle since base::Process closes it on 104 // On windows, duplicate the process handle since base::Process closes it on
76 // destruction. 105 // destruction.
77 base::ProcessHandle out_handle; 106 base::ProcessHandle out_handle;
78 if (!::DuplicateHandle(GetCurrentProcess(), handle, 107 if (!::DuplicateHandle(GetCurrentProcess(), handle,
79 GetCurrentProcess(), &out_handle, 108 GetCurrentProcess(), &out_handle,
80 0, FALSE, DUPLICATE_SAME_ACCESS)) 109 0, FALSE, DUPLICATE_SAME_ACCESS)) {
81 return; 110 return;
111 }
82 handle = out_handle; 112 handle = out_handle;
83 #endif 113 #endif
84 114
85 EXPECT_TRUE(base::Process(handle).Terminate(0, true)); 115 // Use a non-zero exit code so it counts as a crash.
Lei Zhang 2015/05/07 00:24:13 0 is "exit normally" on Windows -> OnProcessCrashe
116 EXPECT_TRUE(base::Process(handle).Terminate(1, true));
117 did_kill_ = true;
86 } 118 }
119
120 bool did_kill_;
121 const base::string16 utility_process_name_;
122
123 DISALLOW_COPY_AND_ASSIGN(KillProcessObserver);
87 }; 124 };
88 125
89 #if defined(OS_POSIX) 126 #if defined(OS_POSIX)
90 class FreezeProcessObserver : public content::BrowserChildProcessObserver { 127 class FreezeProcessObserver : public content::BrowserChildProcessObserver {
91 public: 128 public:
92 FreezeProcessObserver() { 129 FreezeProcessObserver()
130 : did_freeze_(false),
131 utility_process_name_(
132 l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_IMAGE_DECODER_NAME)) {
93 Add(this); 133 Add(this);
94 } 134 }
95 135
96 ~FreezeProcessObserver() override { 136 ~FreezeProcessObserver() override {
97 Remove(this); 137 Remove(this);
98 } 138 }
99 139
140 bool did_freeze() const { return did_freeze_; }
141
100 private: 142 private:
143 static void ResumeFrozenProcess(const base::ProcessHandle& handle) {
144 DCHECK_NE(handle, base::kNullProcessHandle);
145 EXPECT_EQ(0, kill(handle, SIGCONT));
Anand Mistry (off Chromium) 2015/05/07 05:35:22 I'm not 100% sure, but I suspect there's a race he
Lei Zhang 2015/05/07 22:31:05 How do you feel if I just removed this test? It no
Anand Mistry (off Chromium) 2015/05/08 00:02:10 That sounds fine.
146 }
147
101 void BrowserChildProcessHostConnected( 148 void BrowserChildProcessHostConnected(
102 const content::ChildProcessData& data) override { 149 const content::ChildProcessData& data) override {
103 if (data.handle != base::kNullProcessHandle) 150 DCHECK_CURRENTLY_ON(BrowserThread::UI);
104 EXPECT_EQ(0, kill(data.handle, SIGSTOP)); 151 if (data.handle == base::kNullProcessHandle ||
152 data.name != utility_process_name_) {
153 return;
154 }
155
156 ASSERT_FALSE(did_freeze_);
157 did_freeze_ = true;
158 EXPECT_EQ(0, kill(data.handle, SIGSTOP));
159 BrowserThread::PostDelayedTask(
160 BrowserThread::UI,
161 FROM_HERE,
162 base::Bind(&FreezeProcessObserver::ResumeFrozenProcess, data.handle),
163 base::TimeDelta::FromSeconds(7));
105 } 164 }
165
166 bool did_freeze_;
167 const base::string16 utility_process_name_;
168
169 DISALLOW_COPY_AND_ASSIGN(FreezeProcessObserver);
106 }; 170 };
107 #endif // defined(OS_POSIX) 171 #endif // defined(OS_POSIX)
108 172
109 } // namespace 173 } // namespace
110 174
111 class ImageDecoderBrowserTest : public InProcessBrowserTest { 175 class ImageDecoderBrowserTest : public InProcessBrowserTest {
112 }; 176 };
113 177
114 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, Basic) { 178 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, Basic) {
115 scoped_refptr<content::MessageLoopRunner> runner = 179 scoped_refptr<content::MessageLoopRunner> runner =
116 new content::MessageLoopRunner; 180 new content::MessageLoopRunner;
117 TestImageRequest test_request(runner->QuitClosure()); 181 TestImageRequest test_request(runner->QuitClosure());
118 ImageDecoder::Start(&test_request, std::string()); 182 ImageDecoder::Start(&test_request, std::string());
119 runner->Run(); 183 runner->Run();
184 EXPECT_FALSE(test_request.decode_succeeded());
185 }
186
187 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecode) {
188 scoped_refptr<content::MessageLoopRunner> runner =
189 new content::MessageLoopRunner;
190 TestImageRequest test_request(runner->QuitClosure());
191 ImageDecoder::Start(&test_request, GetValidPngString());
192 runner->Run();
193 EXPECT_TRUE(test_request.decode_succeeded());
120 } 194 }
121 195
122 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndDestroy) { 196 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndDestroy) {
123 scoped_refptr<content::MessageLoopRunner> runner = 197 scoped_refptr<content::MessageLoopRunner> runner =
124 new content::MessageLoopRunner; 198 new content::MessageLoopRunner;
125 scoped_ptr<TestImageRequest> test_request( 199 scoped_ptr<TestImageRequest> test_request(
126 new TestImageRequest(runner->QuitClosure())); 200 new TestImageRequest(runner->QuitClosure()));
127 ImageDecoder::Start(test_request.get(), std::string()); 201 ImageDecoder::Start(test_request.get(), std::string());
128 test_request.reset(); 202 test_request.reset();
129 runner->Run(); 203 runner->Run();
130 } 204 }
131 205
206 // Killing the utility process counts as a crash. Thus the request fails.
207 // This test is inherently racy because KillProcessObserver lives on the UI
208 // thread but ImageDecoder does its work mainly on the IO thread. So the test
209 // checks for both possible valid outcomes.
Anand Mistry (off Chromium) 2015/05/07 05:35:22 I should have commented this when I wrote this tes
Lei Zhang 2015/05/07 22:36:22 Done.
132 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndKillProcess) { 210 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndKillProcess) {
133 KillProcessObserver observer; 211 KillProcessObserver observer;
134 scoped_refptr<content::MessageLoopRunner> runner = 212 scoped_refptr<content::MessageLoopRunner> runner =
135 new content::MessageLoopRunner; 213 new content::MessageLoopRunner;
136 scoped_ptr<TestImageRequest> test_request( 214 TestImageRequest test_request(runner->QuitClosure());
137 new TestImageRequest(runner->QuitClosure())); 215 ImageDecoder::Start(&test_request, GetValidPngString());
138 ImageDecoder::Start(test_request.get(), std::string());
139 runner->Run(); 216 runner->Run();
217 if (!test_request.decode_succeeded()) {
218 // The UI thread won the race. Make sure the utility process did get killed.
219 EXPECT_TRUE(observer.did_kill());
220 }
221 // Else the IO thread won the race and the image got decoded. Oh well.
140 } 222 }
141 223
142 #if defined(OS_POSIX) 224 #if defined(OS_POSIX)
225 // Freezing the utility process just long enough that it would try to end batch
226 // mode. However, the outstanding request prevents that. The request should
227 // eventually finish.
143 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndFreezeProcess) { 228 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndFreezeProcess) {
144 FreezeProcessObserver observer; 229 FreezeProcessObserver observer;
145 scoped_refptr<content::MessageLoopRunner> runner = 230 scoped_refptr<content::MessageLoopRunner> runner =
146 new content::MessageLoopRunner; 231 new content::MessageLoopRunner;
147 scoped_ptr<TestImageRequest> test_request( 232 TestImageRequest test_request(runner->QuitClosure());
148 new TestImageRequest(runner->QuitClosure())); 233 ImageDecoder::Start(&test_request, GetValidPngString());
149 ImageDecoder::Start(test_request.get(), std::string());
150 runner->Run(); 234 runner->Run();
235 EXPECT_TRUE(observer.did_freeze());
236 EXPECT_TRUE(test_request.decode_succeeded());
151 } 237 }
152 #endif // defined(OS_POSIX) 238 #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