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

base / test / multiprocess_test.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_TEST_MULTIPROCESS_TEST_H_
#define BASE_TEST_MULTIPROCESS_TEST_H_

#include <string>

#include "base/process/launch.h"
#include "base/process/process.h"
#include "build/build_config.h"
#include "testing/platform_test.h"

namespace base {

class CommandLine;

// Helpers to spawn a child for a multiprocess test and execute a designated
// function. Use these when you already have another base class for your test
// fixture, but you want (some) of your tests to be multiprocess (otherwise you
// may just want to derive your fixture from |MultiProcessTest|, below).
//
// Use these helpers as follows:
//
//   TEST_F(MyTest, ATest) {
//     CommandLine command_line(
//         base::GetMultiProcessTestChildBaseCommandLine());
//     // Maybe add our own switches to |command_line|....
//
//     LaunchOptions options;
//     // Maybe set some options (e.g., |start_hidden| on Windows)....
//
//     // Start a child process and run |a_test_func|.
//     base::Process test_child_process =
//         base::SpawnMultiProcessTestChild("a_test_func", command_line,
//                                          options);
//
//     // Do stuff involving |test_child_process| and the child process....
//
//     int rv = -1;
//     ASSERT_TRUE(base::WaitForMultiprocessTestChildExit(test_child_process,
//         TestTimeouts::action_timeout(), &rv));
//     EXPECT_EQ(0, rv);
//   }
//
//   // Note: |MULTIPROCESS_TEST_MAIN()| is defined in
//   // testing/multiprocess_func_list.h.
//   MULTIPROCESS_TEST_MAIN(a_test_func) {
//     // Code here runs in a child process....
//     return 0;
//   }
//
// If you need to terminate the child process, use the
// TerminateMultiProcessTestChild method to ensure that test will work on
// Android.

// Spawns a child process and executes the function |procname| declared using
// |MULTIPROCESS_TEST_MAIN()| or |MULTIPROCESS_TEST_MAIN_WITH_SETUP()|.
// |command_line| should be as provided by
// |GetMultiProcessTestChildBaseCommandLine()| (below), possibly with arguments
// added. Note: On Windows, you probably want to set |options.start_hidden|.
Process SpawnMultiProcessTestChild(const std::string& procname,
                                   const CommandLine& command_line,
                                   const LaunchOptions& options);

// Gets the base command line for |SpawnMultiProcessTestChild()|. To this, you
// may add any flags needed for your child process.
CommandLine GetMultiProcessTestChildBaseCommandLine();

// Waits for the child process to exit. Returns true if the process exited
// within |timeout| and sets |exit_code| if non null.
bool WaitForMultiprocessTestChildExit(const Process& process,
                                      TimeDelta timeout,
                                      int* exit_code);

// Terminates |process| with |exit_code|. If |wait| is true, this call blocks
// until the process actually terminates.
bool TerminateMultiProcessTestChild(const Process& process,
                                    int exit_code,
                                    bool wait);

#if BUILDFLAG(IS_ANDROID)
// Returns whether the child process exited cleanly from the main runloop.
bool MultiProcessTestChildHasCleanExit(const Process& process);
#endif

// MultiProcessTest ------------------------------------------------------------

// A MultiProcessTest is a test class which makes it easier to
// write a test which requires code running out of process.
//
// To create a multiprocess test simply follow these steps:
//
// 1) Derive your test from MultiProcessTest. Example:
//
//    class MyTest : public MultiProcessTest {
//    };
//
//    TEST_F(MyTest, TestCaseName) {
//      ...
//    }
//
// 2) Create a mainline function for the child processes and include
//    testing/multiprocess_func_list.h.
//    See the declaration of the MULTIPROCESS_TEST_MAIN macro
//    in that file for an example.
// 3) Call SpawnChild("foo"), where "foo" is the name of
//    the function you wish to run in the child processes.
// That's it!
class MultiProcessTest : public PlatformTest {
 public:
  MultiProcessTest();

  MultiProcessTest(const MultiProcessTest&) = delete;
  MultiProcessTest& operator=(const MultiProcessTest&) = delete;

 protected:
  // Run a child process.
  // 'procname' is the name of a function which the child will
  // execute.  It must be exported from this library in order to
  // run.
  //
  // Example signature:
  //    extern "C" int __declspec(dllexport) FooBar() {
  //         // do client work here
  //    }
  //
  // Returns the child process.
  Process SpawnChild(const std::string& procname);

  // Run a child process using the given launch options.
  //
  // Note: On Windows, you probably want to set |options.start_hidden|.
  Process SpawnChildWithOptions(const std::string& procname,
                                const LaunchOptions& options);

  // Set up the command line used to spawn the child process.
  // Override this to add things to the command line (calling this first in the
  // override).
  // Note that currently some tests rely on this providing a full command line,
  // which they then use directly with |LaunchProcess()|.
  // TODO(viettrungluu): Remove this and add a virtual
  // |ModifyChildCommandLine()|; make the two divergent uses more sane.
  virtual CommandLine MakeCmdLine(const std::string& procname);
};

}  // namespace base

#endif  // BASE_TEST_MULTIPROCESS_TEST_H_