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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
98.7%2292320.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    :  namespace kasko {
  47    :  namespace api {
  48    :  
  49    :  namespace {
  50    :  
  51    :  const char kGlobalString[] = "a global string";
  52    :  
  53    :  const char kClientProcessIdSwitch[] = "client-process-id";
  54    :  const char kExpectGlobalSwitch[] = "expect-global";
  55    :  const char kExpectRegisteredKeys[] = "expect-registered-keys";
  56    :  const char kSynthesizeException[] = "synthesize-exception";
  57    :  
  58    :  const base::char16 kExitEventNamePrefix[] = L"kasko_api_test_exit_event_";
  59    :  const base::char16 kReadyEventNamePrefix[] = L"kasko_api_test_ready_event_";
  60    :  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    :  void OnUploadProc(void* context,
  65    :                    const base::char16* report_id,
  66    :                    const base::char16* minidump_path,
  67    :                    const base::char16* const* keys,
  68  E :                    const base::char16* const* values) {
  69  E :    CHECK(report_id);
  70  E :    CHECK(report_id[0] != 0);
  71  E :    CHECK(minidump_path);
  72  E :    CHECK(minidump_path[0] != 0);
  73  E :    CHECK(keys[0]);
  74  E :    CHECK(values[0]);
  75  E :    bool found_hello_world = false;
  76  E :    for (int i = 0; keys[i] != nullptr; ++i) {
  77  E :      if (keys[i] == base::string16(L"hello")) {
  78  E :        CHECK_EQ(base::string16(L"world"), base::string16(values[i]));
  79  E :        found_hello_world = true;
  80    :      }
  81    :      // Make sure that the ""="bar" key was dropped along the way.
  82  E :      CHECK_NE(values[i], base::string16(L"bar"));
  83  E :      CHECK_NE(keys[i], base::string16());
  84  E :    }
  85  E :    CHECK(found_hello_world);
  86  E :    *reinterpret_cast<bool*>(context) = true;
  87  E :  }
  88    :  
  89    :  // Implements the setup and teardown of a child process that runs a Kasko
  90    :  // reporter.
  91    :  class ChildProcess {
  92    :   public:
  93  E :    ChildProcess() : client_process_id_(0), on_upload_invoked_(false) {
  94  E :      base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
  95    :      base::string16 client_process_id_string = base::ASCIIToUTF16(
  96  E :          cmd_line->GetSwitchValueASCII(kClientProcessIdSwitch));
  97  E :      unsigned int client_process_id_uint = 0;
  98  E :      CHECK(
  99    :          base::StringToUint(client_process_id_string, &client_process_id_uint));
 100  E :      client_process_id_ = client_process_id_uint;
 101  E :      CHECK(permanent_failure_directory_.CreateUniqueTempDir());
 102    :  
 103    :      // Set up a directory for the Reporter to generate and store crash dumps.
 104  E :      CHECK(data_directory_.CreateUniqueTempDir());
 105    :  
 106    :      // Start up a test server to receive uploads.
 107  E :      CHECK(server_.Start());
 108  E :    }
 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  E :    void Run() {
 114    :      base::string16 url =
 115  E :          L"http://127.0.0.1:" + base::UintToString16(server_.port()) + L"/crash";
 116    :      base::string16 endpoint =
 117  E :          kEndpointPrefix + base::UintToString16(client_process_id_);
 118    :  
 119    :      // Initialize the Reporter process
 120    :      InitializeReporter(endpoint.c_str(), url.c_str(),
 121    :                         data_directory_.path().value().c_str(),
 122    :                         permanent_failure_directory_.path().value().c_str(),
 123  E :                         &OnUploadProc, &on_upload_invoked_);
 124    :      observer_.reset(new testing::UploadObserver(
 125  E :          server_.incoming_directory(), permanent_failure_directory_.path()));
 126  E :      OnInitialized();
 127    :  
 128    :      // Shut down the Reporter process. This will block on upload completion.
 129  E :      ShutdownReporter();
 130    :  
 131  E :      base::FilePath minidump_path;
 132  E :      std::map<std::string, std::string> crash_keys;
 133  E :      bool success = false;
 134  E :      observer_->WaitForUpload(&minidump_path, &crash_keys, &success);
 135  E :      CHECK_EQ(success, on_upload_invoked_);
 136    :  
 137  E :      OnComplete(success, minidump_path, crash_keys);
 138  E :    }
 139    :  
 140    :   protected:
 141  E :    base::ProcessId client_process_id() { return client_process_id_; }
 142    :  
 143    :   private:
 144    :    // Invoked once the reporter is initialized. The reporter will be shut down
 145    :    // when this method returns.
 146    :    virtual void OnInitialized() = 0;
 147    :  
 148    :    // Invoked when the minidump upload has been received by the test server.
 149    :    virtual void OnComplete(
 150    :        bool success,
 151    :        const base::FilePath& minidump_path,
 152    :        const std::map<std::string, std::string>& crash_keys) = 0;
 153    :  
 154    :    base::ProcessId client_process_id_;
 155    :    base::ScopedTempDir permanent_failure_directory_;
 156    :    base::ScopedTempDir data_directory_;
 157    :    testing::TestServer server_;
 158    :    bool on_upload_invoked_;
 159    :    scoped_ptr<testing::UploadObserver> observer_;
 160    :  
 161    :    DISALLOW_COPY_AND_ASSIGN(ChildProcess);
 162    :  };
 163    :  
 164    :  // Takes a snapshot of all threads in the system and returns the first one from
 165    :  // |process|.
 166  E :  base::PlatformThreadId GetMainThreadFromProcess(const base::Process& process) {
 167    :    base::win::ScopedHandle thread_snapshot(
 168  E :        CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0));
 169  E :    if (!thread_snapshot.IsValid())
 170  i :      return 0;
 171    :  
 172  E :    THREADENTRY32 te32 = {0};
 173  E :    te32.dwSize = sizeof(THREADENTRY32);
 174    :  
 175  E :    if (!Thread32First(thread_snapshot.Get(), &te32))
 176  i :      return 0;
 177    :  
 178    :    do {
 179  E :      if (te32.th32OwnerProcessID == process.Pid())
 180  E :        return te32.th32ThreadID;
 181  E :    } while (Thread32Next(thread_snapshot.Get(), &te32));
 182    :  
 183  i :    return 0;
 184  E :  }
 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  E :  MULTIPROCESS_TEST_MAIN(WaitForClientInvocation) {
 192    :    class DoWaitForClientInvocation : public ChildProcess {
 193    :     private:
 194  E :      void OnInitialized() override {
 195    :        base::string16 client_process_id_string =
 196  E :            base::UintToString16(client_process_id());
 197    :  
 198  E :        base::Process client_process = base::Process::Open(client_process_id());
 199  E :        CHECK(client_process.IsValid());
 200    :  
 201    :        // Tell the client process that we are active.
 202    :        base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
 203    :            NULL, FALSE, FALSE,
 204  E :            (kReadyEventNamePrefix + client_process_id_string).c_str())));
 205  E :        ready_event.Signal();
 206    :  
 207    :        // The client will exit when it has finished invoking
 208    :        // SendReport.
 209  E :        int exit_code = 0;
 210  E :        CHECK(client_process.WaitForExit(&exit_code));
 211  E :      }
 212    :  
 213    :      void OnComplete(
 214    :          bool success,
 215    :          const base::FilePath& minidump_path,
 216  E :          const std::map<std::string, std::string>& crash_keys) override {
 217  E :        CHECK(success);
 218  E :        CHECK(crash_keys.end() != crash_keys.find("hello"));
 219  E :        CHECK_EQ("world", crash_keys.find("hello")->second);
 220    :        // Make sure that the ""="bar" key was dropped along the way.
 221  E :        for (auto& entry : crash_keys) {
 222  E :          CHECK_NE("", entry.first);
 223  E :          CHECK_NE("bar", entry.first);
 224    :        }
 225    :  
 226  E :        base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
 227  E :        std::string dump;
 228  E :        CHECK(base::ReadFileToString(minidump_path, &dump));
 229  E :        if (cmd_line->HasSwitch(kExpectGlobalSwitch)) {
 230  E :          CHECK_NE(std::string::npos, dump.find(kGlobalString));
 231  E :        } else {
 232  E :          CHECK_EQ(std::string::npos, dump.find(kGlobalString));
 233    :        }
 234  E :      }
 235    :    };
 236    :  
 237  E :    DoWaitForClientInvocation().Run();
 238    :  
 239  E :    return 0;
 240  E :  }
 241    :  
 242    :  // Invokes SendReportForProcess on the client (parent) process and verifies that
 243    :  // the dump is correctly taken and uploaded.
 244  E :  MULTIPROCESS_TEST_MAIN(SendReportForProcess) {
 245    :    class DoSendReportForProcess : public ChildProcess {
 246    :     private:
 247    :      static void MinidumpVisitor(IDebugClient4* client,
 248    :                                  IDebugControl* control,
 249  E :                                  IDebugSymbols* symbols) {
 250  E :        base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
 251  E :        bool synthesize_exception = cmd_line->HasSwitch(kSynthesizeException);
 252  E :        base::win::ScopedComPtr<IDebugAdvanced2> debug_advanced_2;
 253    :        HRESULT result = client->QueryInterface(__uuidof(IDebugAdvanced2),
 254  E :                                               debug_advanced_2.ReceiveVoid());
 255  E :        CHECK(SUCCEEDED(result)) << "QueryInterface(IDebugAdvanced2)";
 256  E :        EXCEPTION_RECORD64 exception_record = {0};
 257    :        result = debug_advanced_2->Request(DEBUG_REQUEST_TARGET_EXCEPTION_RECORD,
 258    :                                           nullptr, 0, &exception_record,
 259  E :                                           sizeof(exception_record), nullptr);
 260    :        // If and only if kSynthesizeException, there should be an exception
 261    :        // record.
 262  E :        CHECK(!synthesize_exception || SUCCEEDED(result))
 263    :            << "IDebugAdvanced2::Request";
 264  E :      }
 265  E :      void OnInitialized() override {
 266    :        // Request a dump of the client process.
 267  E :        base::char16* keys[] = {L"hello", L"", nullptr};
 268  E :        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    :        base::Process client_process = base::Process::OpenWithAccess(
 272  E :            client_process_id(), PROCESS_QUERY_LIMITED_INFORMATION);
 273  E :        CHECK(client_process.IsValid());
 274    :  
 275  E :        CONTEXT ctx = {};
 276  E :        EXCEPTION_RECORD exc_rec = {};
 277  E :        exc_rec.ExceptionAddress = 0;
 278  E :        exc_rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
 279  E :        EXCEPTION_POINTERS exc_ptrs = {&exc_rec, &ctx};
 280    :  
 281  E :        base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
 282  E :        bool synthesize_exception = cmd_line->HasSwitch(kSynthesizeException);
 283    :        SendReportForProcess(
 284    :            client_process.Handle(),
 285    :            synthesize_exception ? GetMainThreadFromProcess(client_process) : 0,
 286    :            synthesize_exception ? &exc_ptrs : nullptr, SMALL_DUMP_TYPE, keys,
 287  E :            values);
 288  E :      }
 289    :  
 290    :      void OnComplete(
 291    :          bool success,
 292    :          const base::FilePath& minidump_path,
 293  E :          const std::map<std::string, std::string>& crash_keys) override {
 294  E :        CHECK(success);
 295  E :        CHECK(crash_keys.end() != crash_keys.find("hello"));
 296  E :        CHECK_EQ("world", crash_keys.find("hello")->second);
 297    :        // Make sure that the ""="bar" key was dropped along the way.
 298  E :        for (auto& entry : crash_keys) {
 299  E :          CHECK_NE("", entry.first);
 300  E :          CHECK_NE("bar", entry.first);
 301    :        }
 302  E :        base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
 303  E :        if (cmd_line->HasSwitch(kExpectRegisteredKeys)) {
 304  E :          CHECK(crash_keys.end() != crash_keys.find("largest"));
 305  E :          CHECK_EQ("Jupiter", crash_keys.find("largest")->second);
 306  E :          CHECK(crash_keys.end() != crash_keys.find("inhabitable"));
 307  E :          CHECK_EQ("Earth", crash_keys.find("inhabitable")->second);
 308    :        }
 309  E :        CHECK(SUCCEEDED(
 310    :            testing::VisitMinidump(minidump_path, base::Bind(&MinidumpVisitor))));
 311  E :      }
 312    :    };
 313    :  
 314  E :    DoSendReportForProcess().Run();
 315    :  
 316  E :    return 0;
 317  E :  }
 318    :  
 319  E :  MemoryRange GetMemoryRange() {
 320    :    MemoryRange memory_range = {reinterpret_cast<const void*>(kGlobalString),
 321  E :                                sizeof(kGlobalString)};
 322  E :    return memory_range;
 323  E :  }
 324    :  
 325    :  // Waits for the reporter process to signal readiness, invokes SendReport, then
 326    :  // exits.
 327  E :  MULTIPROCESS_TEST_MAIN(ClientProcess) {
 328    :    base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
 329    :        nullptr, false, false,
 330    :        (kReadyEventNamePrefix + base::UintToString16(base::GetCurrentProcId()))
 331  E :            .c_str())));
 332  E :    ready_event.Wait();
 333    :    // Initialize the Client process.
 334    :    InitializeClient(
 335    :        (kEndpointPrefix + base::UintToString16(base::GetCurrentProcId()))
 336  E :            .c_str());
 337    :  
 338    :    // Send up a crash report.
 339  E :    CONTEXT ctx = {};
 340  E :    ::RtlCaptureContext(&ctx);
 341  E :    EXCEPTION_RECORD exc_rec = {};
 342  E :    exc_rec.ExceptionAddress = reinterpret_cast<void*>(ctx.Eip);
 343  E :    exc_rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
 344  E :    EXCEPTION_POINTERS exc_ptrs = {&exc_rec, &ctx};
 345    :  
 346  E :    CrashKey crash_keys[] = {{L"hello", L"world"}, {L"", L"bar"}};
 347    :  
 348  E :    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  E :    if (base::CommandLine::ForCurrentProcess()->HasSwitch(kExpectGlobalSwitch))
 352  E :      memory_ranges.push_back(GetMemoryRange());
 353    :  
 354    :    SendReport(&exc_ptrs, SMALL_DUMP_TYPE, NULL, 0, crash_keys,
 355  E :               arraysize(crash_keys), memory_ranges.data(), memory_ranges.size());
 356    :  
 357  E :    ShutdownClient();
 358  E :    return 0;
 359  E :  }
 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  E :  void DoInvokeSendReport(bool request_memory_range) {
 366    :    // Start building the Client process command line.
 367    :    base::CommandLine client_command_line =
 368  E :        base::GetMultiProcessTestChildBaseCommandLine();
 369    :    client_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 370  E :                                          "ClientProcess");
 371  E :    if (request_memory_range)
 372  E :      client_command_line.AppendSwitch(kExpectGlobalSwitch);
 373    :    // Launch the Client process.
 374    :    base::Process client_process =
 375  E :        base::LaunchProcess(client_command_line, base::LaunchOptions());
 376  E :    ASSERT_TRUE(client_process.IsValid());
 377    :    // Make sure that we terminate the client process, even if we ASSERT out of
 378    :    // here.
 379    :    base::ScopedClosureRunner terminate_client_process(
 380    :        base::Bind(base::IgnoreResult(&base::Process::Terminate),
 381  E :                   base::Unretained(&client_process), 0, true));
 382    :  
 383    :    // Start building the Reporter process command line.
 384    :    base::CommandLine reporter_command_line =
 385  E :        base::GetMultiProcessTestChildBaseCommandLine();
 386    :    reporter_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 387  E :                                            "WaitForClientInvocation");
 388    :  
 389    :    // Pass the client process ID, used to share event and RPC endpoint names.
 390    :    reporter_command_line.AppendSwitchASCII(
 391  E :        kClientProcessIdSwitch, base::UintToString(client_process.Pid()));
 392    :  
 393  E :    if (request_memory_range)
 394  E :      reporter_command_line.AppendSwitch(kExpectGlobalSwitch);
 395    :  
 396    :    // Launch the Reporter process and wait until it is fully initialized.
 397    :    base::Process reporter_process =
 398  E :        base::LaunchProcess(reporter_command_line, base::LaunchOptions());
 399  E :    ASSERT_TRUE(reporter_process.IsValid());
 400    :    // Make sure that we terminate the reporter process, even if we ASSERT out of
 401    :    // here.
 402    :    base::ScopedClosureRunner terminate_reporter_process(
 403    :        base::Bind(base::IgnoreResult(&base::Process::Terminate),
 404  E :                   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  E :    int exit_code = 0;
 413  E :    reporter_process.WaitForExit(&exit_code);
 414  E :    ASSERT_EQ(0, exit_code);
 415  E :  }
 416    :  
 417    :  }  // namespace
 418    :  
 419  E :  TEST(ApiTest, ExportedConstants) {
 420    :    // Verify that these constants are exported.
 421    :    base::string16 crash_keys_extension(
 422  E :        kasko::api::kPermanentFailureCrashKeysExtension);
 423    :    base::string16 minidump_extension(
 424  E :        kasko::api::kPermanentFailureMinidumpExtension);
 425  E :  }
 426    :  
 427  E :  TEST(ApiTest, SendReport) {
 428  E :    DoInvokeSendReport(false);  // Without explicit memory ranges.
 429  E :    DoInvokeSendReport(true);   // With explicit memory ranges.
 430  E :  }
 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  E :  MULTIPROCESS_TEST_MAIN(RegisterCrashKeysClient) {
 436    :    CrashKey crash_keys[] = {
 437  E :        {L"largest", L"Jupiter"}, {L"inhabitable", L"Earth"}, {L"", L""}};
 438    :  
 439  E :    RegisterCrashKeys(crash_keys, arraysize(crash_keys));
 440    :  
 441    :    base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
 442    :        nullptr, false, false,
 443    :        (kReadyEventNamePrefix + base::UintToString16(base::GetCurrentProcId()))
 444  E :            .c_str())));
 445  E :    ready_event.Signal();
 446  E :    ::Sleep(INFINITE);
 447  E :    return 0;
 448  E :  }
 449    :  
 450  E :  TEST(ApiTest, CrashKeyRegistrationTest) {
 451    :    base::CommandLine client_command_line =
 452  E :        base::GetMultiProcessTestChildBaseCommandLine();
 453    :    client_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 454  E :                                          "RegisterCrashKeysClient");
 455    :  
 456    :    // Launch the Client process.
 457    :    base::Process client_process =
 458  E :        base::LaunchProcess(client_command_line, base::LaunchOptions());
 459  E :    ASSERT_TRUE(client_process.IsValid());
 460    :    // Make sure that we terminate the client process, even if we ASSERT out of
 461    :    // here.
 462    :    base::ScopedClosureRunner terminate_client_process(
 463    :        base::Bind(base::IgnoreResult(&base::Process::Terminate),
 464  E :                   base::Unretained(&client_process), 0, true));
 465    :  
 466    :    // Wait for the child to be initialized.
 467    :    base::WaitableEvent child_ready_event(base::win::ScopedHandle(::CreateEvent(
 468    :        nullptr, false, false,
 469    :        (kReadyEventNamePrefix + base::UintToString16(client_process.Pid()))
 470  E :            .c_str())));
 471  E :    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    :    base::CommandLine reporter_command_line =
 478  E :        base::GetMultiProcessTestChildBaseCommandLine();
 479    :    reporter_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 480  E :                                            "SendReportForProcess");
 481  E :    reporter_command_line.AppendSwitch(kExpectRegisteredKeys);
 482    :  
 483    :    // Pass the client process ID, used to call SendReportForProcess.
 484    :    reporter_command_line.AppendSwitchASCII(
 485  E :        kClientProcessIdSwitch, base::UintToString(client_process.Pid()));
 486    :  
 487    :    // Launch the Reporter process.
 488    :    base::Process reporter_process =
 489  E :        base::LaunchProcess(reporter_command_line, base::LaunchOptions());
 490  E :    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  E :    int exit_code = 0;
 497  E :    reporter_process.WaitForExit(&exit_code);
 498  E :    ASSERT_EQ(0, exit_code);
 499  E :  }
 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  E :  MULTIPROCESS_TEST_MAIN(IdleChildProcess) {
 505    :    base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
 506    :        nullptr, false, false,
 507    :        (kReadyEventNamePrefix + base::UintToString16(base::GetCurrentProcId()))
 508  E :            .c_str())));
 509  E :    ready_event.Signal();
 510  E :    ::Sleep(INFINITE);
 511  E :    return 0;
 512  E :  }
 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  E :  TEST(ApiTest, SendReportForProcessTest) {
 517    :    base::CommandLine client_command_line =
 518  E :        base::GetMultiProcessTestChildBaseCommandLine();
 519    :    client_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 520  E :                                          "IdleChildProcess");
 521    :  
 522    :    // Launch the Client process.
 523    :    base::Process client_process =
 524  E :        base::LaunchProcess(client_command_line, base::LaunchOptions());
 525  E :    ASSERT_TRUE(client_process.IsValid());
 526    :    // Make sure that we terminate the client process, even if we ASSERT out of
 527    :    // here.
 528    :    base::ScopedClosureRunner terminate_client_process(
 529    :        base::Bind(base::IgnoreResult(&base::Process::Terminate),
 530  E :                   base::Unretained(&client_process), 0, true));
 531    :  
 532    :    // Wait for the child to be initialized.
 533    :    base::WaitableEvent child_ready_event(base::win::ScopedHandle(::CreateEvent(
 534    :        nullptr, false, false,
 535    :        (kReadyEventNamePrefix + base::UintToString16(client_process.Pid()))
 536  E :            .c_str())));
 537  E :    child_ready_event.Wait();
 538    :  
 539    :    // Start building the Reporter process command line.
 540    :    base::CommandLine reporter_command_line =
 541  E :        base::GetMultiProcessTestChildBaseCommandLine();
 542    :    reporter_command_line.AppendSwitchASCII(switches::kTestChildProcess,
 543  E :                                            "SendReportForProcess");
 544    :  
 545    :    // Pass the client process ID, used to call SendReportForProcess.
 546    :    reporter_command_line.AppendSwitchASCII(
 547  E :        kClientProcessIdSwitch, base::UintToString(client_process.Pid()));
 548    :  
 549    :    // Launch the Reporter process.
 550    :    base::Process reporter_process =
 551  E :        base::LaunchProcess(reporter_command_line, base::LaunchOptions());
 552  E :    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  E :    int exit_code = 0;
 559  E :    reporter_process.WaitForExit(&exit_code);
 560  E :    ASSERT_EQ(0, exit_code);
 561    :  
 562    :    // Do it again, with kSynthesizeException.
 563  E :    reporter_command_line.AppendSwitch(kSynthesizeException);
 564    :  
 565    :    // Launch the Reporter process.
 566    :    reporter_process =
 567  E :        base::LaunchProcess(reporter_command_line, base::LaunchOptions());
 568  E :    ASSERT_TRUE(reporter_process.IsValid());
 569    :  
 570    :    // Wait for the reporter process to exit and verify its status code.
 571  E :    exit_code = 0;
 572  E :    reporter_process.WaitForExit(&exit_code);
 573  E :    ASSERT_EQ(0, exit_code);
 574  E :  }
 575    :  
 576    :  }  // namespace api
 577    :  }  // namespace kasko

Coverage information generated Thu Jan 14 17:40:38 2016.