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

Side by Side Diff: content/shell/browser/layout_test/layout_test_android.cc

Issue 2540603004: [Android] Redirect std{in,out,err} to sockets for layout tests. (Closed)
Patch Set: qyearsley comments Created 4 years 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "content/shell/browser/layout_test/layout_test_android.h" 5 #include "content/shell/browser/layout_test/layout_test_android.h"
6 6
7 #include <fcntl.h>
8 #include <iostream>
7 #include <memory> 9 #include <memory>
8 10
9 #include "base/android/context_utils.h" 11 #include "base/android/context_utils.h"
10 #include "base/android/fifo_utils.h" 12 #include "base/android/fifo_utils.h"
Peter Beverloo 2016/12/06 19:24:06 The entirety of fifo_utils (and implementation) ar
jbudorick 2016/12/08 02:04:13 Done.
11 #include "base/android/jni_android.h" 13 #include "base/android/jni_android.h"
12 #include "base/android/jni_string.h" 14 #include "base/android/jni_string.h"
13 #include "base/command_line.h" 15 #include "base/command_line.h"
14 #include "base/files/file_path.h" 16 #include "base/files/file_path.h"
15 #include "base/message_loop/message_loop.h" 17 #include "base/message_loop/message_loop.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/test/test_support_android.h"
21 #include "content/public/browser/browser_thread.h"
16 #include "content/public/test/nested_message_pump_android.h" 22 #include "content/public/test/nested_message_pump_android.h"
23 #include "content/shell/browser/layout_test/blink_test_controller.h"
24 #include "content/shell/common/layout_test/layout_test_switches.h"
17 #include "content/shell/common/shell_switches.h" 25 #include "content/shell/common/shell_switches.h"
18 #include "jni/ShellLayoutTestUtils_jni.h" 26 #include "jni/ShellLayoutTestUtils_jni.h"
27 #include "net/base/ip_address.h"
28 #include "net/base/ip_endpoint.h"
29 #include "net/base/net_errors.h"
30 #include "net/base/sockaddr_storage.h"
31 #include "net/socket/socket_posix.h"
19 #include "url/gurl.h" 32 #include "url/gurl.h"
20 33
21 using base::android::ScopedJavaLocalRef; 34 using base::android::ScopedJavaLocalRef;
22 35
23 namespace { 36 namespace {
24 37
25 base::FilePath GetTestFilesDirectory(JNIEnv* env) {
26 ScopedJavaLocalRef<jstring> directory =
27 content::Java_ShellLayoutTestUtils_getApplicationFilesDirectory(
28 env, base::android::GetApplicationContext());
29 return base::FilePath(ConvertJavaStringToUTF8(directory));
30 }
31
32 void EnsureCreateFIFO(const base::FilePath& path) {
33 unlink(path.value().c_str());
34 CHECK(base::android::CreateFIFO(path, 0666))
35 << "Unable to create the Android's FIFO: " << path.value().c_str();
36 }
37
38 std::unique_ptr<base::MessagePump> CreateMessagePumpForUI() { 38 std::unique_ptr<base::MessagePump> CreateMessagePumpForUI() {
39 return std::unique_ptr<base::MessagePump>( 39 return std::unique_ptr<base::MessagePump>(
40 new content::NestedMessagePumpAndroid()); 40 new content::NestedMessagePumpAndroid());
41 } 41 }
42 42
43 } // namespace 43 } // namespace
44 44
45 namespace content { 45 namespace content {
46 46
47 void EnsureInitializeForAndroidLayoutTests() { 47 ScopedAndroidConfiguration::ScopedAndroidConfiguration() : sockets_() {}
Peter Beverloo 2016/12/06 19:24:06 nit - no need to explicitly construct |sockets_|.
jbudorick 2016/12/08 02:04:13 Done.
48
49 void ConnectCompleted(base::Closure socket_connected, int rv) {
Peter Beverloo 2016/12/06 19:24:06 nit: please keep the functions that aren't declare
jbudorick 2016/12/08 02:04:13 Done.
50 CHECK_EQ(net::OK, rv) << " Failed to redirect to socket: "
51 << net::ErrorToString(rv);
52 socket_connected.Run();
53 }
54
55 void CreateAndConnectSocket(
56 uint16_t port,
57 base::Callback<void(std::unique_ptr<net::SocketPosix>)> socket_open,
58 base::Callback<void(int)> socket_connected) {
Peter Beverloo 2016/12/06 19:24:06 nit - avoid the base::Callback refcount churn by m
jbudorick 2016/12/08 02:04:13 Done.
59 net::SockaddrStorage storage;
60 net::IPAddress address;
61 CHECK(address.AssignFromIPLiteral("127.0.0.1"))
62 << "Failed to create IPAddress from IP literal 127.0.0.1.";
63 net::IPEndPoint endpoint(address, port);
64 CHECK(endpoint.ToSockAddr(storage.addr, &storage.addr_len))
65 << "Failed to convert " << endpoint.ToString() << " to sockaddr.";
66
67 std::unique_ptr<net::SocketPosix> socket(new net::SocketPosix);
68
69 int result = net::OK;
70 result = socket->Open(AF_INET);
Peter Beverloo 2016/12/06 19:24:06 nit - you can combine these lines: int result =
jbudorick 2016/12/08 02:04:13 I imagine there was some reason I had them split a
71 CHECK_EQ(net::OK, result) << "Failed to open socket for "
72 << endpoint.ToString() << ": "
73 << net::ErrorToString(result);
74
75 // Set the socket as blocking.
76 const int flags = fcntl(socket->socket_fd(), F_GETFL);
Peter Beverloo 2016/12/06 19:24:06 nit - check for the error condition for the fcntl
jbudorick 2016/12/08 02:04:13 Done.
77 if (flags & O_NONBLOCK) {
78 fcntl(socket->socket_fd(), F_SETFL, flags & ~O_NONBLOCK);
79 }
80
81 net::CompletionCallback connect_completed = base::Bind(
82 &ConnectCompleted, base::Bind(socket_connected, socket->socket_fd()));
83 result = socket->Connect(storage, connect_completed);
84 if (result != net::ERR_IO_PENDING) {
Peter Beverloo 2016/12/06 19:24:06 nit - what about other values for |result|? Should
jbudorick 2016/12/08 02:04:13 These currently get checked in the callback s.t. t
85 connect_completed.Run(result);
86 }
87 socket_open.Run(std::move(socket));
88 }
89
90 void RedirectStdout(int fd) {
91 CHECK_NE(dup2(fd, STDOUT_FILENO), -1) << "Failed to dup2 stdout: "
92 << strerror(errno);
93 }
94
95 void RedirectStdin(int fd) {
96 CHECK_NE(dup2(fd, STDIN_FILENO), -1) << "Failed to dup2 stdin: "
97 << strerror(errno);
98 }
99
100 void RedirectStderr(int fd) {
101 CHECK_NE(dup2(fd, STDERR_FILENO), -1) << "Failed to dup2 stderr: "
102 << strerror(errno);
103 }
104
105 void FinishRedirection(base::Callback<void(int)> redirect,
106 base::WaitableEvent* event,
107 int fd) {
108 redirect.Run(fd);
109 event->Signal();
110 }
111
112 void RedirectStream(
113 uint16_t port,
114 base::Callback<void(std::unique_ptr<net::SocketPosix>)> socket_open,
115 base::Callback<void(base::WaitableEvent*, int)> finish_redirection) {
116 base::WaitableEvent redirected(
117 base::WaitableEvent::ResetPolicy::MANUAL,
118 base::WaitableEvent::InitialState::NOT_SIGNALED);
119 content::BrowserThread::PostTask(
120 content::BrowserThread::IO, FROM_HERE,
121 base::Bind(&CreateAndConnectSocket, port, socket_open,
122 base::Bind(finish_redirection, &redirected)));
123 content::ScopedAllowWaitForAndroidLayoutTests allow_wait;
Peter Beverloo 2016/12/06 19:24:06 micro nit (4x in this file) - you're in content::,
jbudorick 2016/12/08 02:04:13 Done.
124 while (!redirected.IsSignaled())
125 redirected.Wait();
126 }
127
128 void ScopedAndroidConfiguration::RedirectStreams() {
129 base::Callback<void(std::unique_ptr<net::SocketPosix>)> add_socket =
130 base::Bind(&ScopedAndroidConfiguration::AddSocket,
131 base::Unretained(this));
Peter Beverloo 2016/12/06 19:24:06 nit: add a comment explaining that it's safe to us
jbudorick 2016/12/08 02:04:12 Done.
132
133 std::string stdout_port_str =
134 base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
135 switches::kAndroidStdoutPort);
136 unsigned stdout_port = 0;
137 if (base::StringToUint(stdout_port_str, &stdout_port)) {
138 RedirectStream(base::checked_cast<uint16_t>(stdout_port), add_socket,
139 base::Bind(&FinishRedirection, base::Bind(&RedirectStdout)));
140 }
141
142 std::string stdin_port_str =
143 base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
144 switches::kAndroidStdinPort);
145 unsigned stdin_port = 0;
146 if (base::StringToUint(stdin_port_str, &stdin_port)) {
147 RedirectStream(base::checked_cast<uint16_t>(stdin_port), add_socket,
148 base::Bind(&FinishRedirection, base::Bind(&RedirectStdin)));
149 }
150
151 std::string stderr_port_str =
152 base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
153 switches::kAndroidStderrPort);
154 unsigned stderr_port = 0;
155 if (base::StringToUint(stderr_port_str, &stderr_port)) {
156 RedirectStream(base::checked_cast<uint16_t>(stderr_port), add_socket,
157 base::Bind(&FinishRedirection, base::Bind(&RedirectStderr)));
158 }
159 }
160
161 void ScopedAndroidConfiguration::AddSocket(
162 std::unique_ptr<net::SocketPosix> socket) {
163 sockets_.push_back(std::move(socket));
164 }
165
166 ScopedAndroidConfiguration::~ScopedAndroidConfiguration() {}
167
168 void ScopedAndroidConfiguration::Initialize() {
48 JNIEnv* env = base::android::AttachCurrentThread(); 169 JNIEnv* env = base::android::AttachCurrentThread();
170 ScopedJavaLocalRef<jstring> jtest_data_dir =
171 content::Java_ShellLayoutTestUtils_getIsolatedTestRoot(env);
172 base::FilePath test_data_dir(
173 base::android::ConvertJavaStringToUTF8(env, jtest_data_dir));
174 base::InitAndroidTestPaths(test_data_dir);
49 175
50 bool success = base::MessageLoop::InitMessagePumpForUIFactory( 176 bool success =
51 &CreateMessagePumpForUI); 177 base::MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUI);
52 CHECK(success) << "Unable to initialize the message pump for Android."; 178 CHECK(success) << "Unable to initialize the message pump for Android.";
53
54 // Android will need three FIFOs to communicate with the Blink test runner,
55 // one for each of [stdout, stderr, stdin].
56 base::FilePath files_dir(GetTestFilesDirectory(env));
57
58 base::FilePath stdout_fifo(files_dir.Append(FILE_PATH_LITERAL("test.fifo")));
59 EnsureCreateFIFO(stdout_fifo);
60
61 base::FilePath stderr_fifo(
62 files_dir.Append(FILE_PATH_LITERAL("stderr.fifo")));
63 EnsureCreateFIFO(stderr_fifo);
64
65 base::FilePath stdin_fifo(files_dir.Append(FILE_PATH_LITERAL("stdin.fifo")));
66 EnsureCreateFIFO(stdin_fifo);
67
68 // Redirecting stdout needs to happen before redirecting stdin, which needs
69 // to happen before redirecting stderr.
70 success = base::android::RedirectStream(stdout, stdout_fifo, "w") &&
71 base::android::RedirectStream(stdin, stdin_fifo, "r") &&
72 base::android::RedirectStream(stderr, stderr_fifo, "w");
73
74 CHECK(success) << "Unable to initialize the Android FIFOs.";
75 } 179 }
76 180
77 } // namespace content 181 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698