Coverage for /Syzygy/kasko/api/api_tests.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%00361.C++test

Line-by-line coverage:

   1    :  // Copyright 2015 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include <windows.h>  // NOLINT
  16    :  #include <tlhelp32.h>
  17    :  
  18    :  #include "base/base_switches.h"
  19    :  #include "base/bind.h"
  20    :  #include "base/bind_helpers.h"
  21    :  #include "base/callback_helpers.h"
  22    :  #include "base/command_line.h"
  23    :  #include "base/logging.h"
  24    :  #include "base/macros.h"
  25    :  #include "base/files/file_path.h"
  26    :  #include "base/files/file_util.h"
  27    :  #include "base/files/scoped_temp_dir.h"
  28    :  #include "base/process/kill.h"
  29    :  #include "base/process/launch.h"
  30    :  #include "base/process/process_handle.h"
  31    :  #include "base/strings/string16.h"
  32    :  #include "base/strings/string_number_conversions.h"
  33    :  #include "base/strings/utf_string_conversions.h"
  34    :  #include "base/synchronization/waitable_event.h"
  35    :  #include "base/test/multiprocess_test.h"
  36    :  #include "base/win/scoped_comptr.h"
  37    :  #include "base/win/scoped_handle.h"
  38    :  #include "syzygy/kasko/api/client.h"
  39    :  #include "syzygy/kasko/api/reporter.h"
  40    :  #include "syzygy/kasko/testing/minidump_unittest_helpers.h"
  41    :  #include "syzygy/kasko/testing/test_server.h"
  42    :  #include "syzygy/kasko/testing/upload_observer.h"
  43    :  #include "testing/multiprocess_func_list.h"
  44    :  #include "testing/gtest/include/gtest/gtest.h"
  45    :  
  46  m :  namespace kasko {
  47  m :  namespace api {
  48    :  
  49  m :  namespace {
  50    :  
  51  m :  const char kGlobalString[] = "a global string";
  52    :  
  53  m :  const char kClientProcessIdSwitch[] = "client-process-id";
  54  m :  const char kExpectGlobalSwitch[] = "expect-global";
  55  m :  const char kExpectRegisteredKeys[] = "expect-registered-keys";
  56  m :  const char kSynthesizeException[] = "synthesize-exception";
  57    :  
  58  m :  const base::char16 kExitEventNamePrefix[] = L"kasko_api_test_exit_event_";
  59  m :  const base::char16 kReadyEventNamePrefix[] = L"kasko_api_test_ready_event_";
  60  m :  const base::char16 kEndpointPrefix[] = L"kasko_api_test_endpoint_";
  61    :  
  62    :  // Verifies the minidump contents and sets the bool pointed to by |context| to
  63    :  // true.
  64  m :  void OnUploadProc(void* context,
  65  m :                    const base::char16* report_id,
  66  m :                    const base::char16* minidump_path,
  67  m :                    const base::char16* const* keys,
  68  m :                    const base::char16* const* values) {
  69  m :    CHECK(report_id);
  70  m :    CHECK(report_id[0] != 0);
  71  m :    CHECK(minidump_path);
  72  m :    CHECK(minidump_path[0] != 0);
  73  m :    CHECK(keys[0]);
  74  m :    CHECK(values[0]);
  75  m :    bool found_hello_world = false;
  76  m :    for (int i = 0; keys[i] != nullptr; ++i) {
  77  m :      if (keys[i] == base::string16(L"hello")) {
  78  m :        CHECK_EQ(base::string16(L"world"), base::string16(values[i]));
  79  m :        found_hello_world = true;
  80  m :      }
  81    :      // Make sure that the ""="bar" key was dropped along the way.
  82  m :      CHECK_NE(values[i], base::string16(L"bar"));
  83  m :      CHECK_NE(keys[i], base::string16());
  84  m :    }
  85  m :    CHECK(found_hello_world);
  86  m :    *reinterpret_cast<bool*>(context) = true;
  87  m :  }
  88    :  
  89    :  // Implements the setup and teardown of a child process that runs a Kasko
  90    :  // reporter.
  91  m :  class ChildProcess {
  92  m :   public:
  93  m :    ChildProcess() : client_process_id_(0), on_upload_invoked_(false) {
  94  m :      base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
  95  m :      base::string16 client_process_id_string = base::ASCIIToUTF16(
  96  m :          cmd_line->GetSwitchValueASCII(kClientProcessIdSwitch));
  97  m :      unsigned int client_process_id_uint = 0;
  98  m :      CHECK(
  99  m :          base::StringToUint(client_process_id_string, &client_process_id_uint));
 100  m :      client_process_id_ = client_process_id_uint;
 101  m :      CHECK(permanent_failure_directory_.CreateUniqueTempDir());
 102    :  
 103    :      // Set up a directory for the Reporter to generate and store crash dumps.
 104  m :      CHECK(data_directory_.CreateUniqueTempDir());
 105    :  
 106    :      // Start up a test server to receive uploads.
 107  m :      CHECK(server_.Start());
 108  m :    }
 109    :  
 110    :    // Initializes the reporter, invokes the subclass-implemented OnInitialized,
 111    :    // shuts down the reporter (waiting for an upload to complete), then invokes
 112    :    // the subclass-implemented OnComplete().
 113  m :    void Run() {
 114  m :      base::string16 url =
 115  m :          L"http://127.0.0.1:" + base::UintToString16(server_.port()) + L"/crash";
 116  m :      base::string16 endpoint =
 117  m :          kEndpointPrefix + base::UintToString16(client_process_id_);
 118    :  
 119    :      // Initialize the Reporter process
 120  m :      InitializeReporter(endpoint.c_str(), url.c_str(),
 121  m :                         data_directory_.path().value().c_str(),
 122  m :                         permanent_failure_directory_.path().value().c_str(),
 123  m :                         &OnUploadProc, &on_upload_invoked_);
 124  m :      observer_.reset(new testing::UploadObserver(
 125  m :          server_.incoming_directory(), permanent_failure_directory_.path()));
 126  m :      OnInitialized();
 127    :  
 128    :      // Shut down the Reporter process. This will block on upload completion.
 129  m :      ShutdownReporter();
 130    :  
 131  m :      base::FilePath minidump_path;
 132  m :      std::map<std::string, std::string> crash_keys;
 133  m :      bool success = false;
 134  m :      observer_->WaitForUpload(&minidump_path, &crash_keys, &success);
 135  m :      CHECK_EQ(success, on_upload_invoked_);
 136    :  
 137  m :      OnComplete(success, minidump_path, crash_keys);
 138  m :    }
 139    :  
 140  m :   protected:
 141  m :    base::ProcessId client_process_id() { return client_process_id_; }
 142    :  
 143  m :   private:
 144    :    // Invoked once the reporter is initialized. The reporter will be shut down
 145    :    // when this method returns.
 146  m :    virtual void OnInitialized() = 0;
 147    :  
 148    :    // Invoked when the minidump upload has been received by the test server.
 149  m :    virtual void OnComplete(
 150  m :        bool success,
 151  m :        const base::FilePath& minidump_path,
 152  m :        const std::map<std::string, std::string>& crash_keys) = 0;
 153    :  
 154  m :    base::ProcessId client_process_id_;
 155  m :    base::ScopedTempDir permanent_failure_directory_;
 156  m :    base::ScopedTempDir data_directory_;
 157  m :    testing::TestServer server_;
 158  m :    bool on_upload_invoked_;
 159  m :    std::unique_ptr<testing::UploadObserver> observer_;
 160    :  
 161  m :    DISALLOW_COPY_AND_ASSIGN(ChildProcess);
 162  m :  };
 163    :  
 164    :  // Takes a snapshot of all threads in the system and returns the first one from
 165    :  // |process|.
 166  m :  base::PlatformThreadId GetMainThreadFromProcess(const base::Process& process) {
 167  m :    base::win::ScopedHandle thread_snapshot(
 168  m :        CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0));
 169  m :    if (!thread_snapshot.IsValid())
 170  m :      return 0;
 171    :  
 172  m :    THREADENTRY32 te32 = {0};
 173  m :    te32.dwSize = sizeof(THREADENTRY32);
 174    :  
 175  m :    if (!Thread32First(thread_snapshot.Get(), &te32))
 176  m :      return 0;
 177    :  
 178  m :    do {
 179  m :      if (te32.th32OwnerProcessID == process.Pid())
 180  m :        return te32.th32ThreadID;
 181  m :    } while (Thread32Next(thread_snapshot.Get(), &te32));
 182    :  
 183  m :    return 0;
 184  m :  }
 185    :  
 186    :  // Use an event to tell the client process that it is ready to serve requests.
 187    :  // Expects to receive a single invocation of SendReport followed by
 188    :  // the exit of the client process.
 189    :  // Verifies that kGlobalString is in the dump if and only if kExpectGlobalSwitch
 190    :  // is used.
 191  m :  MULTIPROCESS_TEST_MAIN(WaitForClientInvocation) {
 192  m :    class DoWaitForClientInvocation : public ChildProcess {
 193  m :     private:
 194  m :      void OnInitialized() override {
 195  m :        base::string16 client_process_id_string =
 196  m :            base::UintToString16(client_process_id());
 197    :  
 198  m :        base::Process client_process = base::Process::Open(client_process_id());
 199  m :        CHECK(client_process.IsValid());
 200    :  
 201    :        // Tell the client process that we are active.
 202  m :        base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
 203  m :            NULL, FALSE, FALSE,
 204  m :            (kReadyEventNamePrefix + client_process_id_string).c_str())));
 205  m :        ready_event.Signal();
 206    :  
 207    :        // The client will exit when it has finished invoking
 208    :        // SendReport.
 209  m :        int exit_code = 0;
 210  m :        CHECK(client_process.WaitForExit(&exit_code));
 211  m :      }
 212    :  
 213  m :      void OnComplete(
 214  m :          bool success,
 215  m :          const base::FilePath& minidump_path,
 216  m :          const std::map<std::string, std::string>& crash_keys) override {
 217  m :        CHECK(success);
 218  m :        CHECK(crash_keys.end() != crash_keys.find("hello"));
 219  m :        CHECK_EQ("world", crash_keys.find("hello")->second);
 220    :        // Make sure that the ""="bar" key was dropped along the way.
 221  m :        for (auto& entry : crash_keys) {
 222  m :          CHECK_NE("", entry.first);
 223  m :          CHECK_NE("bar", entry.first);
 224  m :        }
 225    :  
 226  m :        base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
 227  m :        std::string dump;
 228  m :        CHECK(base::ReadFileToString(minidump_path, &dump));
 229  m :        if (cmd_line->HasSwitch(kExpectGlobalSwitch)) {
 230  m :          CHECK_NE(std::string::npos, dump.find(kGlobalString));
 231  m :        } else {
 232  m :          CHECK_EQ(std::string::npos, dump.find(kGlobalString));
 233  m :        }
 234  m :      }
 235  m :    };
 236    :  
 237  m :    DoWaitForClientInvocation().Run();
 238    :  
 239  m :    return 0;
 240  m :  }
 241    :  
 242    :  // Invokes SendReportForProcess on the client (parent) process and verifies that
 243    :  // the dump is correctly taken and uploaded.
 244  m :  MULTIPROCESS_TEST_MAIN(SendReportForProcess) {
 245  m :    class DoSendReportForProcess : public ChildProcess {
 246  m :     private:
 247  m :      static void MinidumpVisitor(IDebugClient4* client,
 248  m :                                  IDebugControl* control,
 249  m :                                  IDebugSymbols* symbols) {
 250  m :        base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
 251  m :        bool synthesize_exception = cmd_line->HasSwitch(kSynthesizeException);
 252  m :        base::win::ScopedComPtr<IDebugAdvanced2> debug_advanced_2;
 253  m :        HRESULT result = client->QueryInterface(__uuidof(IDebugAdvanced2),
 254  m :                                               debug_advanced_2.ReceiveVoid());
 255  m :        CHECK(SUCCEEDED(result)) << "QueryInterface(IDebugAdvanced2)";
 256  m :        EXCEPTION_RECORD64 exception_record = {0};
 257  m :        result = debug_advanced_2->Request(DEBUG_REQUEST_TARGET_EXCEPTION_RECORD,
 258  m :                                           nullptr, 0, &exception_record,
 259  m :                                           sizeof(exception_record), nullptr);
 260    :        // If and only if kSynthesizeException, there should be an exception
 261    :        // record.
 262  m :        CHECK(!synthesize_exception || SUCCEEDED(result))
 263  m :            << "IDebugAdvanced2::Request";
 264  m :      }
 265  m :      void OnInitialized() override {
 266    :        // Request a dump of the client process.
 267  m :        base::char16* keys[] = {L"hello", L"", nullptr};
 268  m :        base::char16* values[] = {L"world", L"bar", nullptr};
 269    :        // Open with minimal access as SendReportForProcess() will reopen the
 270    :        // process with the access it needs.
 271  m :        base::Process client_process = base::Process::OpenWithAccess(
 272  m :            client_process_id(), PROCESS_QUERY_LIMITED_INFORMATION);
 273  m :        CHECK(client_process.IsValid());
 274    :  
 275  m :        CONTEXT ctx = {};
 276  m :        EXCEPTION_RECORD exc_rec = {};
 277  m :        exc_rec.ExceptionAddress = 0;
 278  m :        exc_rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
 279  m :        EXCEPTION_POINTERS exc_ptrs = {&exc_rec, &ctx};
 280    :  
 281  m :        base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
 282  m :        bool synthesize_exception = cmd_line->HasSwitch(kSynthesizeException);
 283  m :        SendReportForProcess(
 284  m :            client_process.Handle(),
 285  m :            synthesize_exception ? GetMainThreadFromProcess(client_process) : 0,
 286  m :            synthesize_exception ? &exc_ptrs : nullptr, SMALL_DUMP_TYPE, keys,
 287  m :            values);
 288  m :      }
 289    :  
 290  m :      void OnComplete(
 291  m :          bool success,
 292  m :          const base::FilePath& minidump_path,
 293  m :          const std::map<std::string, std::string>& crash_keys) override {
 294  m :        CHECK(success);
 295  m :        CHECK(crash_keys.end() != crash_keys.find("hello"));
 296  m :        CHECK_EQ("world", crash_keys.find("hello")->second);
 297    :        // Make sure that the ""="bar" key was dropped along the way.
 298  m :        for (auto& entry : crash_keys) {
 299  m :          CHECK_NE("", entry.first);
 300  m :          CHECK_NE("bar", entry.first);
 301  m :        }
 302  m :        base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
 303  m :        if (cmd_line->HasSwitch(kExpectRegisteredKeys)) {
 304  m :          CHECK(crash_keys.end() != crash_keys.find("largest"));
 305  m :          CHECK_EQ("Jupiter", crash_keys.find("largest")->second);
 306  m :          CHECK(crash_keys.end() != crash_keys.find("inhabitable"));
 307  m :          CHECK_EQ("Earth", crash_keys.find("inhabitable")->second);
 308  m :        }
 309  m :        CHECK(SUCCEEDED(
 310  m :            testing::VisitMinidump(minidump_path, base::Bind(&MinidumpVisitor))));
 311  m :      }
 312  m :    };
 313    :  
 314  m :    DoSendReportForProcess().Run();
 315    :  
 316  m :    return 0;
 317  m :  }
 318    :  
 319  m :  MemoryRange GetMemoryRange() {
 320  m :    MemoryRange memory_range = {reinterpret_cast<const void*>(kGlobalString),
 321  m :                                sizeof(kGlobalString)};
 322  m :    return memory_range;
 323  m :  }
 324    :  
 325    :  // Waits for the reporter process to signal readiness, invokes SendReport, then
 326    :  // exits.
 327  m :  MULTIPROCESS_TEST_MAIN(ClientProcess) {
 328  m :    base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
 329  m :        nullptr, false, false,
 330  m :        (kReadyEventNamePrefix + base::UintToString16(base::GetCurrentProcId()))
 331  m :            .c_str())));
 332  m :    ready_event.Wait();
 333    :    // Initialize the Client process.
 334  m :    InitializeClient(
 335  m :        (kEndpointPrefix + base::UintToString16(base::GetCurrentProcId()))
 336  m :            .c_str());
 337    :  
 338    :    // Send up a crash report.
 339  m :    CONTEXT ctx = {};
 340  m :    ::RtlCaptureContext(&ctx);
 341  m :    EXCEPTION_RECORD exc_rec = {};
 342  m :    exc_rec.ExceptionAddress = reinterpret_cast<void*>(ctx.Eip);
 343  m :    exc_rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
 344  m :    EXCEPTION_POINTERS exc_ptrs = {&exc_rec, &ctx};
 345    :  
 346  m :    CrashKey crash_keys[] = {{L"hello", L"world"}, {L"", L"bar"}};
 347    :  
 348  m :    std::vector<MemoryRange> memory_ranges;
 349    :    // GetMemoryRange is extracted to prevent kGlobalString from unintentionally
 350    :    // being on the stack and potentially being included for that reason.
 351  m :    if (base::CommandLine::ForCurrentProcess()->HasSwitch(kExpectGlobalSwitch))
 352  m :      memory_ranges.push_back(GetMemoryRange());
 353    :  
 354  m :    SendReport(&exc_ptrs, SMALL_DUMP_TYPE, NULL, 0, crash_keys,
 355  m :               arraysize(crash_keys), memory_ranges.data(), memory_ranges.size());
 356    :  
 357  m :    ShutdownClient();
 358  m :    return 0;
 359  m :  }
 360    :  
 361    :  // Starts up child client and reporter processes. The client will request a
 362    :  // report, and the reporter will generate, upload, and then verify the report.
 363    :  // If |request_memory_range| is true, inclusion of kGlobalString will be
 364    :  // requested (and verified).
 365  m :  void DoInvokeSendReport(bool request_memory_range) {
 366    :    // Start building the Client process command line.
 367  m :    base::CommandLine client_command_line =
 368  m :        base::GetMultiProcessTestChildBaseCommandLine();
 369  m :    client_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 370  m :                                          "ClientProcess");
 371  m :    if (request_memory_range)
 372  m :      client_command_line.AppendSwitch(kExpectGlobalSwitch);
 373    :    // Launch the Client process.
 374  m :    base::Process client_process =
 375  m :        base::LaunchProcess(client_command_line, base::LaunchOptions());
 376  m :    ASSERT_TRUE(client_process.IsValid());
 377    :    // Make sure that we terminate the client process, even if we ASSERT out of
 378    :    // here.
 379  m :    base::ScopedClosureRunner terminate_client_process(
 380  m :        base::Bind(base::IgnoreResult(&base::Process::Terminate),
 381  m :                   base::Unretained(&client_process), 0, true));
 382    :  
 383    :    // Start building the Reporter process command line.
 384  m :    base::CommandLine reporter_command_line =
 385  m :        base::GetMultiProcessTestChildBaseCommandLine();
 386  m :    reporter_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 387  m :                                            "WaitForClientInvocation");
 388    :  
 389    :    // Pass the client process ID, used to share event and RPC endpoint names.
 390  m :    reporter_command_line.AppendSwitchASCII(
 391  m :        kClientProcessIdSwitch, base::UintToString(client_process.Pid()));
 392    :  
 393  m :    if (request_memory_range)
 394  m :      reporter_command_line.AppendSwitch(kExpectGlobalSwitch);
 395    :  
 396    :    // Launch the Reporter process and wait until it is fully initialized.
 397  m :    base::Process reporter_process =
 398  m :        base::LaunchProcess(reporter_command_line, base::LaunchOptions());
 399  m :    ASSERT_TRUE(reporter_process.IsValid());
 400    :    // Make sure that we terminate the reporter process, even if we ASSERT out of
 401    :    // here.
 402  m :    base::ScopedClosureRunner terminate_reporter_process(
 403  m :        base::Bind(base::IgnoreResult(&base::Process::Terminate),
 404  m :                   base::Unretained(&reporter_process), 0, true));
 405    :  
 406    :    // The client will wait for the reporter to signal a "ready" event.
 407    :    // The client will then invoke SendReport and exit.
 408    :    // The reporter process will exit after the generated report has been uploaded
 409    :    // and its contents verified.
 410    :  
 411    :    // Wait for the reporter process to exit and verify its status code.
 412  m :    int exit_code = 0;
 413  m :    reporter_process.WaitForExit(&exit_code);
 414  m :    ASSERT_EQ(0, exit_code);
 415  m :  }
 416    :  
 417  m :  }  // namespace
 418    :  
 419  m :  TEST(ApiTest, ExportedConstants) {
 420    :    // Verify that these constants are exported.
 421  m :    base::string16 crash_keys_extension(
 422  m :        kasko::api::kPermanentFailureCrashKeysExtension);
 423  m :    base::string16 minidump_extension(
 424  m :        kasko::api::kPermanentFailureMinidumpExtension);
 425  m :  }
 426    :  
 427  m :  TEST(ApiTest, SendReport) {
 428  m :    DoInvokeSendReport(false);  // Without explicit memory ranges.
 429  m :    DoInvokeSendReport(true);   // With explicit memory ranges.
 430  m :  }
 431    :  
 432    :  // Signals when it is done registering crash keys and then sleeps indefinitely.
 433    :  // The parent process is responsible for terminating this child after
 434    :  // SendReportForProcess has successfully been invoked on it.
 435  m :  MULTIPROCESS_TEST_MAIN(RegisterCrashKeysClient) {
 436  m :    CrashKey crash_keys[] = {
 437  m :        {L"largest", L"Jupiter"}, {L"inhabitable", L"Earth"}, {L"", L""}};
 438    :  
 439  m :    RegisterCrashKeys(crash_keys, arraysize(crash_keys));
 440    :  
 441  m :    base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
 442  m :        nullptr, false, false,
 443  m :        (kReadyEventNamePrefix + base::UintToString16(base::GetCurrentProcId()))
 444  m :            .c_str())));
 445  m :    ready_event.Signal();
 446  m :    ::Sleep(INFINITE);
 447  m :    return 0;
 448  m :  }
 449    :  
 450  m :  TEST(ApiTest, CrashKeyRegistrationTest) {
 451  m :    base::CommandLine client_command_line =
 452  m :        base::GetMultiProcessTestChildBaseCommandLine();
 453  m :    client_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 454  m :                                          "RegisterCrashKeysClient");
 455    :  
 456    :    // Launch the Client process.
 457  m :    base::Process client_process =
 458  m :        base::LaunchProcess(client_command_line, base::LaunchOptions());
 459  m :    ASSERT_TRUE(client_process.IsValid());
 460    :    // Make sure that we terminate the client process, even if we ASSERT out of
 461    :    // here.
 462  m :    base::ScopedClosureRunner terminate_client_process(
 463  m :        base::Bind(base::IgnoreResult(&base::Process::Terminate),
 464  m :                   base::Unretained(&client_process), 0, true));
 465    :  
 466    :    // Wait for the child to be initialized.
 467  m :    base::WaitableEvent child_ready_event(base::win::ScopedHandle(::CreateEvent(
 468  m :        nullptr, false, false,
 469  m :        (kReadyEventNamePrefix + base::UintToString16(client_process.Pid()))
 470  m :            .c_str())));
 471  m :    child_ready_event.Wait();
 472    :  
 473    :    // Launch a Reporter process that will call SendReportForProcess and then
 474    :    // verify that the registered keys are included.
 475    :  
 476    :    // Start building the Reporter process command line.
 477  m :    base::CommandLine reporter_command_line =
 478  m :        base::GetMultiProcessTestChildBaseCommandLine();
 479  m :    reporter_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 480  m :                                            "SendReportForProcess");
 481  m :    reporter_command_line.AppendSwitch(kExpectRegisteredKeys);
 482    :  
 483    :    // Pass the client process ID, used to call SendReportForProcess.
 484  m :    reporter_command_line.AppendSwitchASCII(
 485  m :        kClientProcessIdSwitch, base::UintToString(client_process.Pid()));
 486    :  
 487    :    // Launch the Reporter process.
 488  m :    base::Process reporter_process =
 489  m :        base::LaunchProcess(reporter_command_line, base::LaunchOptions());
 490  m :    ASSERT_TRUE(reporter_process.IsValid());
 491    :  
 492    :    // The Reporter process will exit after taking a dump of us and verifying its
 493    :    // contents.
 494    :  
 495    :    // Wait for the reporter process to exit and verify its status code.
 496  m :    int exit_code = 0;
 497  m :    reporter_process.WaitForExit(&exit_code);
 498  m :    ASSERT_EQ(0, exit_code);
 499  m :  }
 500    :  
 501    :  // Signals when it is executing and then sleeps indefinitely. The parent process
 502    :  // is responsible for terminating this child after SendReportForProcess has
 503    :  // successfully been invoked on it.
 504  m :  MULTIPROCESS_TEST_MAIN(IdleChildProcess) {
 505  m :    base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
 506  m :        nullptr, false, false,
 507  m :        (kReadyEventNamePrefix + base::UintToString16(base::GetCurrentProcId()))
 508  m :            .c_str())));
 509  m :    ready_event.Signal();
 510  m :    ::Sleep(INFINITE);
 511  m :    return 0;
 512  m :  }
 513    :  
 514    :  // Starts up a child process to be reported on, and then instantiates a reporter
 515    :  // process that generates and verifies the report.
 516  m :  TEST(ApiTest, SendReportForProcessTest) {
 517  m :    base::CommandLine client_command_line =
 518  m :        base::GetMultiProcessTestChildBaseCommandLine();
 519  m :    client_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 520  m :                                          "IdleChildProcess");
 521    :  
 522    :    // Launch the Client process.
 523  m :    base::Process client_process =
 524  m :        base::LaunchProcess(client_command_line, base::LaunchOptions());
 525  m :    ASSERT_TRUE(client_process.IsValid());
 526    :    // Make sure that we terminate the client process, even if we ASSERT out of
 527    :    // here.
 528  m :    base::ScopedClosureRunner terminate_client_process(
 529  m :        base::Bind(base::IgnoreResult(&base::Process::Terminate),
 530  m :                   base::Unretained(&client_process), 0, true));
 531    :  
 532    :    // Wait for the child to be initialized.
 533  m :    base::WaitableEvent child_ready_event(base::win::ScopedHandle(::CreateEvent(
 534  m :        nullptr, false, false,
 535  m :        (kReadyEventNamePrefix + base::UintToString16(client_process.Pid()))
 536  m :            .c_str())));
 537  m :    child_ready_event.Wait();
 538    :  
 539    :    // Start building the Reporter process command line.
 540  m :    base::CommandLine reporter_command_line =
 541  m :        base::GetMultiProcessTestChildBaseCommandLine();
 542  m :    reporter_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 543  m :                                            "SendReportForProcess");
 544    :  
 545    :    // Pass the client process ID, used to call SendReportForProcess.
 546  m :    reporter_command_line.AppendSwitchASCII(
 547  m :        kClientProcessIdSwitch, base::UintToString(client_process.Pid()));
 548    :  
 549    :    // Launch the Reporter process.
 550  m :    base::Process reporter_process =
 551  m :        base::LaunchProcess(reporter_command_line, base::LaunchOptions());
 552  m :    ASSERT_TRUE(reporter_process.IsValid());
 553    :  
 554    :    // The Reporter process will exit after taking a dump of the client and
 555    :    // verifying its contents.
 556    :  
 557    :    // Wait for the reporter process to exit and verify its status code.
 558  m :    int exit_code = 0;
 559  m :    reporter_process.WaitForExit(&exit_code);
 560  m :    ASSERT_EQ(0, exit_code);
 561    :  
 562    :    // Do it again, with kSynthesizeException.
 563  m :    reporter_command_line.AppendSwitch(kSynthesizeException);
 564    :  
 565    :    // Launch the Reporter process.
 566  m :    reporter_process =
 567  m :        base::LaunchProcess(reporter_command_line, base::LaunchOptions());
 568  m :    ASSERT_TRUE(reporter_process.IsValid());
 569    :  
 570    :    // Wait for the reporter process to exit and verify its status code.
 571  m :    exit_code = 0;
 572  m :    reporter_process.WaitForExit(&exit_code);
 573  m :    ASSERT_EQ(0, exit_code);
 574  m :  }
 575    :  
 576  m :  }  // namespace api
 577  m :  }  // namespace kasko

Coverage information generated Fri Jul 29 11:00:21 2016.