diff options
author | Paweł Hajdan <phajdan.jr@chromium.org> | 2015-01-15 14:32:01 +0100 |
---|---|---|
committer | Paweł Hajdan <phajdan.jr@chromium.org> | 2015-01-15 13:33:12 +0000 |
commit | 26bc4153eac79795de3539ed053dbf61d6504095 (patch) | |
tree | 29558b4b97619ad321e90b648124affd1086b305 /base/test | |
parent | 9af9ccd01bb33f591fa6dcdc94393ff0377c4a3a (diff) | |
download | chromium_src-26bc4153eac79795de3539ed053dbf61d6504095.zip chromium_src-26bc4153eac79795de3539ed053dbf61d6504095.tar.gz chromium_src-26bc4153eac79795de3539ed053dbf61d6504095.tar.bz2 |
iOS gtest launcher: get list of tests from executable running in simulator
BUG=426870
R=lliabraa@google.com, sky@chromium.org
Review URL: https://codereview.chromium.org/838603004
Cr-Commit-Position: refs/heads/master@{#311652}
Diffstat (limited to 'base/test')
-rw-r--r-- | base/test/gtest_util.cc | 35 | ||||
-rw-r--r-- | base/test/gtest_util.h | 6 | ||||
-rw-r--r-- | base/test/launcher/test_launcher.cc | 15 | ||||
-rw-r--r-- | base/test/launcher/test_launcher.h | 8 | ||||
-rw-r--r-- | base/test/launcher/test_launcher_ios.cc | 140 | ||||
-rw-r--r-- | base/test/launcher/unit_test_launcher.cc | 6 | ||||
-rw-r--r-- | base/test/launcher/unit_test_launcher.h | 1 | ||||
-rw-r--r-- | base/test/launcher/unit_test_launcher_ios.cc | 7 | ||||
-rw-r--r-- | base/test/test_switches.cc | 4 | ||||
-rw-r--r-- | base/test/test_switches.h | 1 |
10 files changed, 214 insertions, 9 deletions
diff --git a/base/test/gtest_util.cc b/base/test/gtest_util.cc index 47fd639..f98320c 100644 --- a/base/test/gtest_util.cc +++ b/base/test/gtest_util.cc @@ -40,4 +40,39 @@ bool WriteCompiledInTestsToFile(const FilePath& path) { return serializer.Serialize(root); } +bool ReadTestNamesFromFile(const FilePath& path, + std::vector<SplitTestName>* output) { + JSONFileValueSerializer deserializer(path); + int error_code = 0; + std::string error_message; + scoped_ptr<base::Value> value( + deserializer.Deserialize(&error_code, &error_message)); + if (!value.get()) + return false; + + base::ListValue* tests = nullptr; + if (!value->GetAsList(&tests)) + return false; + + std::vector<base::SplitTestName> result; + for (base::ListValue::iterator i = tests->begin(); i != tests->end(); ++i) { + base::DictionaryValue* test = nullptr; + if (!(*i)->GetAsDictionary(&test)) + return false; + + std::string test_case_name; + if (!test->GetStringASCII("test_case_name", &test_case_name)) + return false; + + std::string test_name; + if (!test->GetStringASCII("test_name", &test_name)) + return false; + + result.push_back(std::make_pair(test_case_name, test_name)); + } + + output->swap(result); + return true; +} + } // namespace diff --git a/base/test/gtest_util.h b/base/test/gtest_util.h index 93382f8..d10c72f 100644 --- a/base/test/gtest_util.h +++ b/base/test/gtest_util.h @@ -26,6 +26,12 @@ std::vector<SplitTestName> GetCompiledInTests(); // current executable as a JSON file. Returns true on success. bool WriteCompiledInTestsToFile(const FilePath& path) WARN_UNUSED_RESULT; +// Reads the list of gtest-based tests from |path| into |output|. +// Returns true on success. +bool ReadTestNamesFromFile( + const FilePath& path, + std::vector<SplitTestName>* output) WARN_UNUSED_RESULT; + } // namespace base #endif // BASE_TEST_GTEST_UTIL_H_ diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc index af2e461..b5316ad 100644 --- a/base/test/launcher/test_launcher.cc +++ b/base/test/launcher/test_launcher.cc @@ -829,6 +829,11 @@ bool TestLauncher::Init() { } } + if (!launcher_delegate_->GetTests(&tests_)) { + LOG(ERROR) << "Failed to get list of tests."; + return false; + } + if (!results_tracker_.Init(*command_line)) { LOG(ERROR) << "Failed to initialize test results tracker."; return 1; @@ -900,12 +905,10 @@ bool TestLauncher::Init() { } void TestLauncher::RunTests() { - std::vector<SplitTestName> tests(GetCompiledInTests()); - std::vector<std::string> test_names; - - for (size_t i = 0; i < tests.size(); i++) { - std::string test_name = FormatFullTestName(tests[i].first, tests[i].second); + for (size_t i = 0; i < tests_.size(); i++) { + std::string test_name = FormatFullTestName( + tests_[i].first, tests_[i].second); results_tracker_.AddTest(test_name); @@ -918,7 +921,7 @@ void TestLauncher::RunTests() { continue; } - if (!launcher_delegate_->ShouldRunTest(tests[i].first, tests[i].second)) + if (!launcher_delegate_->ShouldRunTest(tests_[i].first, tests_[i].second)) continue; // Skip the test that doesn't match the filter (if given). diff --git a/base/test/launcher/test_launcher.h b/base/test/launcher/test_launcher.h index 78a854b..27909d4 100644 --- a/base/test/launcher/test_launcher.h +++ b/base/test/launcher/test_launcher.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/callback_forward.h" #include "base/compiler_specific.h" +#include "base/test/gtest_util.h" #include "base/test/launcher/test_result.h" #include "base/test/launcher/test_results_tracker.h" #include "base/time/time.h" @@ -40,6 +41,10 @@ extern const char kGTestOutputFlag[]; // which tests and how are run. class TestLauncherDelegate { public: + // Called to get names of tests available for running. The delegate + // must put the result in |output| and return true on success. + virtual bool GetTests(std::vector<SplitTestName>* output) = 0; + // Called before a test is considered for running. If it returns false, // the test is not run. If it returns true, the test will be run provided // it is part of the current shard. @@ -158,6 +163,9 @@ class TestLauncher { std::vector<std::string> positive_test_filter_; std::vector<std::string> negative_test_filter_; + // Tests to use (cached result of TestLauncherDelegate::GetTests). + std::vector<SplitTestName> tests_; + // Number of tests started in this iteration. size_t test_started_count_; diff --git a/base/test/launcher/test_launcher_ios.cc b/base/test/launcher/test_launcher_ios.cc index 39051ca..82353cc 100644 --- a/base/test/launcher/test_launcher_ios.cc +++ b/base/test/launcher/test_launcher_ios.cc @@ -5,18 +5,152 @@ #include "base/test/launcher/test_launcher.h" #include "base/at_exit.h" +#include "base/base_paths.h" #include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/format_macros.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "base/process/launch.h" #include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_switches.h" +#include "base/test/test_timeouts.h" namespace { -int DummyRunTestSuite(void) { - return -1; +const char kHelpFlag[] = "help"; + +void PrintUsage() { + fprintf(stdout, + "Runs tests using the gtest framework, each batch of tests being\n" + "run in their own process. Supported command-line flags:\n" + "\n" + " Common flags:\n" + " --gtest_filter=...\n" + " Runs a subset of tests (see --gtest_help for more info).\n" + "\n" + " --help\n" + " Shows this message.\n" + "\n" + " Other flags:\n" + " --test-launcher-retry-limit=N\n" + " Sets the limit of test retries on failures to N.\n" + "\n" + " --test-launcher-summary-output=PATH\n" + " Saves a JSON machine-readable summary of the run.\n" + "\n" + " --test-launcher-print-test-stdio=auto|always|never\n" + " Controls when full test output is printed.\n" + " auto means to print it when the test failed.\n" + "\n" + " --test-launcher-total-shards=N\n" + " Sets the total number of shards to N.\n" + "\n" + " --test-launcher-shard-index=N\n" + " Sets the shard index to run to N (from 0 to TOTAL - 1).\n"); + fflush(stdout); } +class IOSUnitTestLauncherDelegate : public base::UnitTestLauncherDelegate { + public: + IOSUnitTestLauncherDelegate() : base::UnitTestLauncherDelegate(0, false) { + } + + bool Init() WARN_UNUSED_RESULT { + if (!PathService::Get(base::DIR_EXE, &dir_exe_)) { + LOG(ERROR) << "Failed to get directory of current executable."; + return false; + } + + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + std::vector<std::string> args(command_line->GetArgs()); + if (args.size() < 1) { + LOG(ERROR) << "Arguments expected."; + return false; + } + test_name_ = args[0]; + + base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app")); + cmd_line.AppendSwitch(switches::kTestLauncherPrintWritablePath); + cmd_line.PrependWrapper(dir_exe_.AppendASCII("iossim").value()); + + std::string raw_output; + if (!base::GetAppOutput(cmd_line, &raw_output)) { + LOG(ERROR) << "GetAppOutput failed."; + return false; + } + writable_path_ = base::FilePath(raw_output); + + return true; + } + + bool GetTests(std::vector<base::SplitTestName>* output) override { + base::ScopedTempDir temp_dir; + if (!temp_dir.CreateUniqueTempDirUnderPath(writable_path_)) + return false; + base::FilePath test_list_path( + temp_dir.path().AppendASCII("test_list.json")); + + base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app")); + cmd_line.AppendSwitchPath(switches::kTestLauncherListTests, test_list_path); + cmd_line.PrependWrapper(dir_exe_.AppendASCII("iossim").value()); + + base::LaunchOptions launch_options; + launch_options.wait = true; + + if (!base::LaunchProcess(cmd_line, launch_options).IsValid()) + return false; + + return base::ReadTestNamesFromFile(test_list_path, output); + } + + private: + // Directory containing test launcher's executable. + base::FilePath dir_exe_; + + // Name of the test executable to run. + std::string test_name_; + + // Path that launched test binary can write to. + base::FilePath writable_path_; + + DISALLOW_COPY_AND_ASSIGN(IOSUnitTestLauncherDelegate); +}; + } // namespace int main(int argc, char** argv) { base::AtExitManager at_exit; - return base::LaunchUnitTests(argc, argv, base::Bind(&DummyRunTestSuite)); + + base::CommandLine::Init(argc, argv); + + if (base::CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) { + PrintUsage(); + return 0; + } + + base::TimeTicks start_time(base::TimeTicks::Now()); + + TestTimeouts::Initialize(); + + base::MessageLoopForIO message_loop; + + IOSUnitTestLauncherDelegate delegate; + if (!delegate.Init()) { + fprintf(stderr, "Failed to intialize test launcher delegate.\n"); + fflush(stderr); + return 1; + } + // Force one job since we can't run multiple simulators in parallel. + base::TestLauncher launcher(&delegate, 1); + bool success = launcher.Run(); + + fprintf(stdout, "Tests took %" PRId64 " seconds.\n", + (base::TimeTicks::Now() - start_time).InSeconds()); + fflush(stdout); + + return (success ? 0 : 1); } diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc index 719c498..9a8b41f 100644 --- a/base/test/launcher/unit_test_launcher.cc +++ b/base/test/launcher/unit_test_launcher.cc @@ -236,6 +236,12 @@ UnitTestLauncherDelegate::GTestCallbackState::GTestCallbackState() { UnitTestLauncherDelegate::GTestCallbackState::~GTestCallbackState() { } +bool UnitTestLauncherDelegate::GetTests(std::vector<SplitTestName>* output) { + DCHECK(thread_checker_.CalledOnValidThread()); + *output = GetCompiledInTests(); + return true; +} + bool UnitTestLauncherDelegate::ShouldRunTest(const std::string& test_case_name, const std::string& test_name) { DCHECK(thread_checker_.CalledOnValidThread()); diff --git a/base/test/launcher/unit_test_launcher.h b/base/test/launcher/unit_test_launcher.h index 7264e41..0f661db 100644 --- a/base/test/launcher/unit_test_launcher.h +++ b/base/test/launcher/unit_test_launcher.h @@ -50,6 +50,7 @@ class UnitTestLauncherDelegate : public TestLauncherDelegate { }; // TestLauncherDelegate: + bool GetTests(std::vector<SplitTestName>* output) override; bool ShouldRunTest(const std::string& test_case_name, const std::string& test_name) override; size_t RunTests(TestLauncher* test_launcher, diff --git a/base/test/launcher/unit_test_launcher_ios.cc b/base/test/launcher/unit_test_launcher_ios.cc index d4276c8..acb6c71 100644 --- a/base/test/launcher/unit_test_launcher_ios.cc +++ b/base/test/launcher/unit_test_launcher_ios.cc @@ -6,7 +6,9 @@ #include "base/command_line.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/logging.h" +#include "base/mac/foundation_util.h" #include "base/test/gtest_util.h" #include "base/test/test_switches.h" @@ -27,6 +29,11 @@ int LaunchUnitTests(int argc, LOG(ERROR) << "Failed to write list of tests."; return 1; } + } else if (command_line->HasSwitch( + switches::kTestLauncherPrintWritablePath)) { + fprintf(stdout, "%s", mac::GetUserLibraryPath().value().c_str()); + fflush(stdout); + return 0; } return run_test_suite.Run(); diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc index 4d8331d..84aa53c 100644 --- a/base/test/test_switches.cc +++ b/base/test/test_switches.cc @@ -42,6 +42,10 @@ const char switches::kTestLauncherSummaryOutput[] = const char switches::kTestLauncherPrintTestStdio[] = "test-launcher-print-test-stdio"; +// Print a writable path and exit (for internal use). +const char switches::kTestLauncherPrintWritablePath[] = + "test-launcher-print-writable-path"; + // Index of the test shard to run, starting from 0 (first shard) to total shards // minus one (last shard). const char switches::kTestLauncherShardIndex[] = diff --git a/base/test/test_switches.h b/base/test/test_switches.h index 336d036..f145f1e 100644 --- a/base/test/test_switches.h +++ b/base/test/test_switches.h @@ -19,6 +19,7 @@ extern const char kTestLauncherOutput[]; extern const char kTestLauncherRetryLimit[]; extern const char kTestLauncherSummaryOutput[]; extern const char kTestLauncherPrintTestStdio[]; +extern const char kTestLauncherPrintWritablePath[]; extern const char kTestLauncherShardIndex[]; extern const char kTestLauncherTotalShards[]; extern const char kTestLauncherTimeout[]; |