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

Side by Side Diff: components/nacl/loader/nonsfi/test_launcher_nacl_nonsfi.cc

Issue 1154313003: Non-SFI mode: Implement test launcher for nacl_helper_nonsfi_unittests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Small clean up for code review. Created 5 years, 6 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
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "base/test/launcher/test_launcher.h" 5 #include <inttypes.h>
6 #include <stdio.h>
7
8 #include <string>
6 9
7 #include "base/at_exit.h" 10 #include "base/at_exit.h"
8 #include "base/base_paths.h"
9 #include "base/bind.h"
10 #include "base/command_line.h" 11 #include "base/command_line.h"
11 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
12 #include "base/files/file_util.h" 13 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/format_macros.h"
15 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop.h"
16 #include "base/path_service.h" 15 #include "base/path_service.h"
17 #include "base/process/launch.h" 16 #include "base/process/launch.h"
17 #include "base/strings/string_piece.h"
18 #include "base/strings/string_tokenizer.h"
18 #include "base/strings/string_util.h" 19 #include "base/strings/string_util.h"
20 #include "base/sys_info.h"
21 #include "base/test/launcher/test_launcher.h"
19 #include "base/test/launcher/unit_test_launcher.h" 22 #include "base/test/launcher/unit_test_launcher.h"
20 #include "base/test/test_switches.h"
21 #include "base/test/test_timeouts.h" 23 #include "base/test/test_timeouts.h"
22 24
23 namespace { 25 namespace {
24 26
25 const char kHelpFlag[] = "help"; 27 const char kHelpFlag[] = "help";
26 28
27 void PrintUsage() { 29 void PrintUsage() {
28 fprintf(stdout, 30 fprintf(stdout,
29 "Runs tests using the gtest framework, each batch of tests being\n" 31 "Runs tests using the gtest framework, each batch of tests being\n"
30 "run in their own process. Supported command-line flags:\n" 32 "run in their own process. Supported command-line flags:\n"
(...skipping 17 matching lines...) Expand all
48 " auto means to print it when the test failed.\n" 50 " auto means to print it when the test failed.\n"
49 "\n" 51 "\n"
50 " --test-launcher-total-shards=N\n" 52 " --test-launcher-total-shards=N\n"
51 " Sets the total number of shards to N.\n" 53 " Sets the total number of shards to N.\n"
52 "\n" 54 "\n"
53 " --test-launcher-shard-index=N\n" 55 " --test-launcher-shard-index=N\n"
54 " Sets the shard index to run to N (from 0 to TOTAL - 1).\n"); 56 " Sets the shard index to run to N (from 0 to TOTAL - 1).\n");
55 fflush(stdout); 57 fflush(stdout);
56 } 58 }
57 59
58 class IOSUnitTestPlatformDelegate : public base::UnitTestPlatformDelegate { 60 // gtest's --gtest_list_tests option outputs a list of test cases and test
59 public: 61 // methods in a following format.
60 IOSUnitTestPlatformDelegate() { 62 //
63 // test_case1.
64 // test_method1
65 // test_method2
66 // test_case2.
67 // test_method3
68 // test_method4
69 //
70 // This function parses it.
71 bool ParseGTestList(const std::string& text,
Paweł Hajdan Jr. 2015/05/29 13:48:20 Why not output structured list of tests like on io
hidehiko 2015/05/29 14:00:47 Because vanilla gtest does not support it.
Paweł Hajdan Jr. 2015/06/01 10:56:59 That's right. However, we have small utility funct
hidehiko 2015/06/02 08:12:17 Done.
72 std::vector<base::SplitTestName>* output) {
73 std::string test_case_name;
74 base::StringTokenizer tokenizer(text, "\n");
75 // As nacl_helper_nonsfi_unittests_main uses vanilla gtest_main, so it
76 // outputs a line at first. Check and skip it.
77 tokenizer.GetNext();
78 if (tokenizer.token_piece() != "Running main() from gtest_main.cc") {
79 return false;
61 } 80 }
62 81
63 bool Init() WARN_UNUSED_RESULT { 82 while (tokenizer.GetNext()) {
64 if (!PathService::Get(base::DIR_EXE, &dir_exe_)) { 83 base::StringPiece token = tokenizer.token_piece();
65 LOG(ERROR) << "Failed to get directory of current executable."; 84 if (token.ends_with(".")) {
85 // This is test case name.
86 token.remove_suffix(1); // Drop the trailing '.'
87 token.CopyToString(&test_case_name);
88 continue;
89 }
90
91 if (token.starts_with(" ")) {
92 // This is test method name.
93 token.remove_prefix(2); // Drop the leading " ".
94 output->push_back(base::SplitTestName(test_case_name, token.as_string()));
95 continue;
96 }
97
98 // Unknown token.
99 output->clear();
100 return false;
101 }
102 return true;
103 }
104
105 class NonSfiUnitTestPlatformDelegate : public base::UnitTestPlatformDelegate {
106 public:
107 NonSfiUnitTestPlatformDelegate() {
108 }
109
110 bool Init() {
111 base::FilePath dir_exe;
112 if (!PathService::Get(base::DIR_EXE, &dir_exe)) {
113 LOG(ERROR) << "Failed to get directory of the current executable.";
66 return false; 114 return false;
67 } 115 }
68 116
69 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); 117 test_path_ = dir_exe.AppendASCII("nacl_helper_nonsfi_unittests_main");
70 std::vector<std::string> args(command_line->GetArgs());
71 if (args.size() < 1) {
72 LOG(ERROR) << "Arguments expected.";
73 return false;
74 }
75 test_name_ = args[0];
76
77 base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
78 cmd_line.AppendSwitch(switches::kTestLauncherPrintWritablePath);
79 cmd_line.PrependWrapper(dir_exe_.AppendASCII("iossim").value());
80
81 std::string raw_output;
82 if (!base::GetAppOutput(cmd_line, &raw_output)) {
83 LOG(ERROR) << "GetAppOutput failed.";
84 return false;
85 }
86 writable_path_ = base::FilePath(raw_output);
87
88 return true; 118 return true;
89 } 119 }
90 120
91 bool GetTests(std::vector<base::SplitTestName>* output) override { 121 private:
92 base::ScopedTempDir temp_dir;
93 if (!temp_dir.CreateUniqueTempDirUnderPath(writable_path_))
94 return false;
95 base::FilePath test_list_path(
96 temp_dir.path().AppendASCII("test_list.json"));
97
98 base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
99 cmd_line.AppendSwitchPath(switches::kTestLauncherListTests, test_list_path);
100 cmd_line.PrependWrapper(dir_exe_.AppendASCII("iossim").value());
101
102 base::LaunchOptions launch_options;
103 launch_options.wait = true;
104
105 if (!base::LaunchProcess(cmd_line, launch_options).IsValid())
106 return false;
107
108 return base::ReadTestNamesFromFile(test_list_path, output);
109 }
110
111 bool CreateTemporaryFile(base::FilePath* path) override { 122 bool CreateTemporaryFile(base::FilePath* path) override {
112 if (!CreateTemporaryDirInDir(writable_path_, std::string(), path)) 123 if (!base::CreateNewTempDirectory(base::FilePath::StringType(), path))
113 return false; 124 return false;
114 *path = path->AppendASCII("test_results.xml"); 125 *path = path->AppendASCII("test_results.xml");
115 return true; 126 return true;
116 } 127 }
117 128
129 bool GetTests(std::vector<base::SplitTestName>* output) override {
130 base::CommandLine cmd_line(test_path_);
131 cmd_line.AppendSwitch(base::kGTestListTestsFlag);
132
133 std::string raw_output;
134 if (!base::GetAppOutput(cmd_line, &raw_output)) {
135 LOG(ERROR) << "Failed to run test with --gtest_list";
136 return false;
137 }
138
139 return ParseGTestList(raw_output, output);
140 }
141
142 std::string GetWrapperForChildGTestProcess() override {
143 return std::string();
144 }
145
118 base::CommandLine GetCommandLineForChildGTestProcess( 146 base::CommandLine GetCommandLineForChildGTestProcess(
119 const std::vector<std::string>& test_names, 147 const std::vector<std::string>& test_names,
120 const base::FilePath& output_file) override { 148 const base::FilePath& output_file) override {
121 base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app")); 149 base::CommandLine cmd_line(test_path_);
122 cmd_line.AppendSwitchPath(switches::kTestLauncherOutput, output_file); 150 cmd_line.AppendSwitchASCII(
123 cmd_line.AppendSwitchASCII(base::kGTestFilterFlag, 151 base::kGTestOutputFlag, "xml:" + output_file.value());
124 JoinString(test_names, ":")); 152 cmd_line.AppendSwitchASCII(
153 base::kGTestFilterFlag, JoinString(test_names, ":"));
154
125 return cmd_line; 155 return cmd_line;
126 } 156 }
127 157
128 std::string GetWrapperForChildGTestProcess() override {
129 return dir_exe_.AppendASCII("iossim").value();
130 }
131
132 void RelaunchTests(base::TestLauncher* test_launcher, 158 void RelaunchTests(base::TestLauncher* test_launcher,
133 const std::vector<std::string>& test_names, 159 const std::vector<std::string>& test_names,
134 int launch_flags) override { 160 int launch_flags) override {
135 // Relaunch all tests in one big batch, since overhead of smaller batches
136 // is too big for serialized runs inside ios simulator.
137 RunUnitTestsBatch(test_launcher, this, test_names, launch_flags); 161 RunUnitTestsBatch(test_launcher, this, test_names, launch_flags);
138 } 162 }
139 163
140 private: 164 base::FilePath test_path_;
141 // Directory containing test launcher's executable.
142 base::FilePath dir_exe_;
143
144 // Name of the test executable to run.
145 std::string test_name_;
146
147 // Path that launched test binary can write to.
148 base::FilePath writable_path_;
149
150 DISALLOW_COPY_AND_ASSIGN(IOSUnitTestPlatformDelegate);
151 }; 165 };
152 166
153 } // namespace 167 } // namespace
154 168
155 int main(int argc, char** argv) { 169 int main(int argc, char** argv) {
156 base::AtExitManager at_exit; 170 base::AtExitManager at_exit;
157 171
158 base::CommandLine::Init(argc, argv); 172 base::CommandLine::Init(argc, argv);
159 173
160 if (base::CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) { 174 if (base::CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) {
161 PrintUsage(); 175 PrintUsage();
162 return 0; 176 return 0;
163 } 177 }
164 178
165 base::TimeTicks start_time(base::TimeTicks::Now()); 179 base::TimeTicks start_time(base::TimeTicks::Now());
166 180
167 TestTimeouts::Initialize(); 181 TestTimeouts::Initialize();
168 182
169 base::MessageLoopForIO message_loop; 183 base::MessageLoopForIO message_loop;
170 184
171 IOSUnitTestPlatformDelegate platform_delegate; 185 NonSfiUnitTestPlatformDelegate platform_delegate;
172 if (!platform_delegate.Init()) { 186 if (!platform_delegate.Init()) {
173 fprintf(stderr, "Failed to intialize test launcher platform delegate.\n"); 187 fprintf(stderr, "Failed to initialize test launcher.\n");
174 fflush(stderr); 188 fflush(stderr);
175 return 1; 189 return 1;
176 } 190 }
177 base::UnitTestLauncherDelegate delegate(&platform_delegate, 0, false); 191
178 // Force one job since we can't run multiple simulators in parallel. 192 base::UnitTestLauncherDelegate delegate(&platform_delegate, 10, true);
179 base::TestLauncher launcher(&delegate, 1); 193 base::TestLauncher launcher(&delegate, base::SysInfo::NumberOfProcessors());
194 // Allow --gtest_output option of the vanilla gtest library.
195 launcher.set_use_child_gtest_output(true);
180 bool success = launcher.Run(); 196 bool success = launcher.Run();
181 197
182 fprintf(stdout, "Tests took %" PRId64 " seconds.\n", 198 fprintf(stdout, "Tests took %" PRId64 " seconds.\n",
183 (base::TimeTicks::Now() - start_time).InSeconds()); 199 (base::TimeTicks::Now() - start_time).InSeconds());
184 fflush(stdout); 200 fflush(stdout);
185 201 return success ? 0 : 1;
186 return (success ? 0 : 1);
187 } 202 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698