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

Side by Side Diff: services/native_support/process_controller_impl_unittest.cc

Issue 1321253010: Add a "native_support" service. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: fix android? Created 5 years, 2 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
OLDNEW
(Empty)
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.
4
5 #include <signal.h>
6
7 #include <string>
8 #include <vector>
9
10 #include "base/message_loop/message_loop.h"
11 #include "mojo/public/cpp/bindings/interface_request.h"
12 #include "mojo/public/cpp/bindings/type_converter.h"
13 #include "mojo/services/files/public/cpp/input_stream_file.h"
14 #include "mojo/services/files/public/cpp/output_stream_file.h"
15 #include "mojo/services/files/public/interfaces/types.mojom.h"
16 #include "services/native_support/process_test_base.h"
17
18 namespace native_support {
19 namespace {
20
21 using ProcessControllerImplTest = ProcessTestBase;
22
23 void QuitMessageLoop() {
24 base::MessageLoop::current()->QuitWhenIdle();
25 }
26
27 void RunMessageLoop() {
28 base::MessageLoop::current()->Run();
29 }
30
31 // Note: We already tested success (zero) versus failure (non-zero) exit
32 // statuses in |ProcessControllerTest.Spawn|.
33 TEST_F(ProcessControllerImplTest, Wait) {
34 mojo::files::Error error;
35
36 {
37 ProcessControllerPtr process_controller;
38 error = mojo::files::ERROR_INTERNAL;
39 const char kPath[] = "/bin/sh";
40 mojo::Array<mojo::String> argv;
41 argv.push_back(kPath);
42 argv.push_back("-c");
43 argv.push_back("exit 42");
44 process()->Spawn(kPath, argv.Pass(), mojo::Array<mojo::String>(), nullptr,
45 nullptr, nullptr, GetProxy(&process_controller),
46 Capture(&error));
47 ASSERT_TRUE(process().WaitForIncomingResponse());
48 EXPECT_EQ(mojo::files::ERROR_OK, error);
49
50 error = mojo::files::ERROR_INTERNAL;
51 int32_t exit_status = 0;
52 process_controller->Wait(Capture(&error, &exit_status));
53 ASSERT_TRUE(process_controller.WaitForIncomingResponse());
54 EXPECT_EQ(mojo::files::ERROR_OK, error);
55 EXPECT_EQ(42, exit_status);
56 }
57 }
58
59 // An output file stream that captures output and quits when "ready" is seen.
60 class QuitOnReadyFile : public files_impl::OutputStreamFile::Client {
61 public:
62 explicit QuitOnReadyFile(mojo::InterfaceRequest<mojo::files::File> request)
63 : impl_(files_impl::OutputStreamFile::Create(this, request.Pass())) {}
64 ~QuitOnReadyFile() override {}
65
66 bool got_ready() const { return got_ready_; }
67
68 private:
69 // |files_impl::OutputStreamFile::Client|:
70 void OnDataReceived(const void* bytes, size_t num_bytes) override {
71 output_.append(static_cast<const char*>(bytes), num_bytes);
72 if (output_.find("ready") != std::string::npos) {
73 got_ready_ = true;
74 QuitMessageLoop();
75 }
76 }
77 void OnClosed() override { QuitMessageLoop(); }
78
79 std::string output_;
80 bool got_ready_ = false;
81 std::unique_ptr<files_impl::OutputStreamFile> impl_;
82
83 MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnReadyFile);
84 };
85
86 // An input file stream that ignores reads (never completing them).
87 class IgnoreReadsFile : public files_impl::InputStreamFile::Client {
88 public:
89 explicit IgnoreReadsFile(mojo::InterfaceRequest<mojo::files::File> request)
90 : impl_(files_impl::InputStreamFile::Create(this, request.Pass())) {}
91 ~IgnoreReadsFile() override {}
92
93 private:
94 // |files_impl::InputStreamFile::Client|:
95 bool RequestData(size_t max_num_bytes,
96 mojo::files::Error* error,
97 mojo::Array<uint8_t>* data,
98 const RequestDataCallback& callback) override {
99 // Don't let |callback| die, because we probably have assertions "ensuring"
100 // that response callbacks get called.
101 callbacks_.push_back(callback);
102 return false;
103 }
104 void OnClosed() override { QuitMessageLoop(); }
105
106 std::vector<RequestDataCallback> callbacks_;
107 std::unique_ptr<files_impl::InputStreamFile> impl_;
108
109 MOJO_DISALLOW_COPY_AND_ASSIGN(IgnoreReadsFile);
110 };
111
112 TEST_F(ProcessControllerImplTest, Kill) {
113 // We want to run bash and have it set a trap for SIGINT, which it'll handle
114 // by quitting with code 42. We need to make sure that bash started and set
115 // the trap before we kill our child. Thus we have bash echo "ready" and wait
116 // for it to do so (and thus we need to capture/examine stdout).
117 //
118 // We want bash to pause, so that we can kill it before it quits. We can't use
119 // "sleep" since it's not a builtin (so bash would wait for it before dying).
120 // So instead we use "read" with a timeout (note that "-t" is a bash
121 // extension, and not specified by POSIX for /bin/sh). Thus we have to give
122 // something for stdin (otherwise, it'd come from /dev/null and the read would
123 // be completed immediately).
124 mojo::files::FilePtr ifile;
125 IgnoreReadsFile ifile_impl(GetProxy(&ifile));
126 mojo::files::FilePtr ofile;
127 QuitOnReadyFile ofile_impl(GetProxy(&ofile));
128
129 ProcessControllerPtr process_controller;
130 mojo::files::Error error = mojo::files::ERROR_INTERNAL;
131 const char kPath[] = "/bin/bash";
132 mojo::Array<mojo::String> argv;
133 argv.push_back(kPath);
134 argv.push_back("-c");
135 argv.push_back("trap 'exit 42' INT; echo ready; read -t30; exit 1");
136 process()->Spawn(kPath, argv.Pass(), mojo::Array<mojo::String>(),
137 ifile.Pass(), ofile.Pass(), nullptr,
138 GetProxy(&process_controller), Capture(&error));
139 ASSERT_TRUE(process().WaitForIncomingResponse());
140 EXPECT_EQ(mojo::files::ERROR_OK, error);
141
142 // |ofile_impl| will quit the message loop once it sees "ready".
143 RunMessageLoop();
144 ASSERT_TRUE(ofile_impl.got_ready());
145
146 // Send SIGINT.
147 error = mojo::files::ERROR_INTERNAL;
148 process_controller->Kill(static_cast<int32_t>(SIGINT), Capture(&error));
149 ASSERT_TRUE(process_controller.WaitForIncomingResponse());
150 EXPECT_EQ(mojo::files::ERROR_OK, error);
151
152 error = mojo::files::ERROR_INTERNAL;
153 int32_t exit_status = 0;
154 process_controller->Wait(Capture(&error, &exit_status));
155 ASSERT_TRUE(process_controller.WaitForIncomingResponse());
156 EXPECT_EQ(mojo::files::ERROR_OK, error);
157 EXPECT_EQ(42, exit_status);
158 }
159
160 TEST_F(ProcessControllerImplTest, DestroyingControllerKills) {
161 // We want to make sure that we've exec-ed before killing, so we do what we do
162 // in |ProcessControllerImplTest.Kill| (without the trap).
163 {
164 mojo::files::FilePtr ifile;
165 IgnoreReadsFile ifile_impl(GetProxy(&ifile));
166 mojo::files::FilePtr ofile;
167 QuitOnReadyFile ofile_impl(GetProxy(&ofile));
168
169 ProcessControllerPtr process_controller;
170 mojo::files::Error error = mojo::files::ERROR_INTERNAL;
171 const char kPath[] = "/bin/bash";
172 mojo::Array<mojo::String> argv;
173 argv.push_back(kPath);
174 argv.push_back("-c");
175 argv.push_back("echo ready; read -t30");
176 process()->Spawn(kPath, argv.Pass(), mojo::Array<mojo::String>(),
177 ifile.Pass(), ofile.Pass(), nullptr,
178 GetProxy(&process_controller), Capture(&error));
179 ASSERT_TRUE(process().WaitForIncomingResponse());
180 EXPECT_EQ(mojo::files::ERROR_OK, error);
181
182 // |ofile_impl| will quit the message loop once it sees "ready".
183 RunMessageLoop();
184 ASSERT_TRUE(ofile_impl.got_ready());
185 }
186
187 // The child should be killed.
188 // TODO(vtl): It's pretty hard to verify that the child process was actually
189 // killed. This could be done, e.g., by having the child trap SIGTERM and
190 // writing something to a file, and then separately checking for that file.
191 // For now now, just be happy if it doesn't crash. (I've actually verified it
192 // "manually", but automation is hard.)
193 }
194
195 } // namespace
196 } // namespace native_support
OLDNEW
« no previous file with comments | « services/native_support/process_controller_impl.cc ('k') | services/native_support/process_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698