summaryrefslogtreecommitdiff
path: root/base/test/launcher/test_launcher_ios.cc
blob: ecd31aedf5d00cb3754b0c1d4220b65e1dce3e51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#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/strings/string_util.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_switches.h"
#include "base/test/test_timeouts.h"

namespace {

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 IOSUnitTestPlatformDelegate : public base::UnitTestPlatformDelegate {
 public:
  IOSUnitTestPlatformDelegate() {
  }

  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);
  }

  bool CreateTemporaryFile(base::FilePath* path) override {
    if (!CreateTemporaryDirInDir(writable_path_, std::string(), path))
      return false;
    *path = path->AppendASCII("test_results.xml");
    return true;
  }

  base::CommandLine GetCommandLineForChildGTestProcess(
      const std::vector<std::string>& test_names,
      const base::FilePath& output_file) override {
    base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
    cmd_line.AppendSwitchPath(switches::kTestLauncherOutput, output_file);
    cmd_line.AppendSwitchASCII(base::kGTestFilterFlag,
                               JoinString(test_names, ":"));
    return cmd_line;
  }

  std::string GetWrapperForChildGTestProcess() override {
    return dir_exe_.AppendASCII("iossim").value();
  }

  void RelaunchTests(base::TestLauncher* test_launcher,
                     const std::vector<std::string>& test_names,
                     int launch_flags) override {
    // Relaunch all tests in one big batch, since overhead of smaller batches
    // is too big for serialized runs inside ios simulator.
    RunUnitTestsBatch(test_launcher, this, test_names, launch_flags);
  }

 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(IOSUnitTestPlatformDelegate);
};

}  // namespace

int main(int argc, char** argv) {
  base::AtExitManager at_exit;

  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;

  IOSUnitTestPlatformDelegate platform_delegate;
  if (!platform_delegate.Init()) {
    fprintf(stderr, "Failed to intialize test launcher platform delegate.\n");
    fflush(stderr);
    return 1;
  }
  base::UnitTestLauncherDelegate delegate(&platform_delegate, 0, false);
  // 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);
}