Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(404)

Unified Diff: handler/win/registrar_test.cc

Issue 1213723004: Implement a Windows crash client registrar. (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@child_process
Patch Set: More self-review. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« handler/win/registrar.cc ('K') | « handler/win/registrar.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: handler/win/registrar_test.cc
diff --git a/handler/win/registrar_test.cc b/handler/win/registrar_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f509977da5dcf62ad8c26919812dcf86eb0ee5a0
--- /dev/null
+++ b/handler/win/registrar_test.cc
@@ -0,0 +1,188 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "handler/win/registrar.h"
+
+#include <windows.h>
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "gtest/gtest.h"
+#include "test/win/win_child_process.h"
+#include "util/win/scoped_handle.h"
+
+namespace crashpad {
+namespace test {
+namespace {
+
+// Reads a `HANDLE` value from |handle|. Assume sender has same bitness as
+// reader. CHECKs upon failure.
+ScopedKernelHANDLE ReadHandle(HANDLE handle) {
+ HANDLE value = nullptr;
+ DWORD bytes_read = 0;
scottmg 2015/06/29 20:29:05 Replace 36-38 with CheckReadFile() from util/file/
+ CHECK(::ReadFile(handle, &value, sizeof(value), &bytes_read, nullptr));
+ CHECK_EQ(sizeof(value), bytes_read);
+ return ScopedKernelHANDLE(value);
+}
+
+// Writes |value| to |handle|. Logs a GTest failure upon failure.
+void WriteHandle(HANDLE handle, HANDLE value) {
+ DWORD bytes_written = 0;
scottmg 2015/06/29 20:29:05 And CheckedWriteFile here.
+ EXPECT_TRUE(
+ ::WriteFile(handle, &value, sizeof(value), &bytes_written, nullptr));
+ EXPECT_EQ(sizeof(value), bytes_written);
+}
+
+// Implements a client process that may be registered. Reads the handle pair
+// from its parent and proceeds to request a dump. After receiving notice that
+// the dump completed, exits with 0.
+class ClientProcess : public test::WinChildProcess {
+ public:
+ ClientProcess() {}
+
+ private:
+ int Run() override {
+ // In the worst case, this process will exit due to a broken pipe if the
+ // parent process disappears.
+ ScopedKernelHANDLE request_report_event = ReadHandle(ReadPipeHandle());
+ ScopedKernelHANDLE report_complete_event = ReadHandle(ReadPipeHandle());
+ PCHECK(SetEvent(request_report_event.get()));
+ CHECK_EQ(WAIT_OBJECT_0,
+ WaitForSingleObject(report_complete_event.get(), INFINITE));
+ return 0;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ClientProcess);
+};
+
+// Handles crash dump requests, logging the requesting client's PID.
+class MockDelegate : Registrar::Delegate {
+ public:
+ // Instantiates a Registrar::Delegate that logs requesting clients' PIDs to
+ // |process_ids|.
+ explicit MockDelegate(std::vector<DWORD>* process_ids)
+ : process_ids_(process_ids) {}
+
+ // Registrar::Delegate:
+ void GenerateReportForClient(HANDLE client_process) override {
+ process_ids_->push_back(GetProcessId(client_process));
+ }
+
+ private:
+ std::vector<DWORD>* process_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDelegate);
+};
+
+// Duplicates |handle| with PROCESS_ALL_ACCESS. Logs a GTest failure upon
+// failure.
+ScopedKernelHANDLE DuplicateProcessHandleWithAllAccess(HANDLE handle) {
+ HANDLE result = nullptr;
+ if (!DuplicateHandle(GetCurrentProcess(),
+ handle,
+ GetCurrentProcess(),
+ &result,
+ PROCESS_ALL_ACCESS,
+ false,
+ 0)) {
+ PLOG(ERROR) << "DuplicateHandle";
+ ADD_FAILURE() << "DuplicateHandle";
+ return ScopedKernelHANDLE();
+ }
+ return ScopedKernelHANDLE(result);
+}
+
+class RegistrarTest : public testing::Test {
+ public:
+ RegistrarTest()
+ : registrar_(
+ scoped_ptr<Registrar::Delegate>(new MockDelegate(&process_ids_))) {}
+
+ protected:
+ Registrar& registrar() { return registrar_; }
+ std::vector<DWORD>& triggered_process_ids() { return process_ids_; }
+
+ private:
+ std::vector<DWORD> process_ids_;
+ Registrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegistrarTest);
+};
+
+// Exercises registration, report request handling, and process termination.
+TEST_F(RegistrarTest, RegisterProcess) {
+ test::WinChildProcess::EntryPoint<ClientProcess>();
+
+ struct ProcessState {
+ scoped_ptr<test::WinChildProcess::Handles> child_handles;
+ HANDLE request_handle;
+ HANDLE done_handle;
+ } process_states[3];
+
+ for (int i = 0; i < arraysize(process_states); ++i) {
+ process_states[i].child_handles = test::WinChildProcess::Launch();
+ ASSERT_TRUE(registrar().RegisterProcess(
+ DuplicateProcessHandleWithAllAccess(
+ process_states[i].child_handles->process.get()),
+ &process_states[i].request_handle,
+ &process_states[i].done_handle));
+ }
+
+ // Kill a process. This should not cause any hiccups for the Registrar.
+ ASSERT_TRUE(
+ TerminateProcess(process_states[0].child_handles->process.get(), 0));
+
+ // Send the event pairs over to each of the child processes, and verify that
+ // they are able to trigger a report request, that the request is handed to
+ // our delegate, and that the "report complete" event is triggered and may be
+ // detected by the client.
+ for (int i = 1; i < arraysize(process_states); ++i) {
+ triggered_process_ids().clear();
+
+ // Verify that the child process is still running.
+ ASSERT_EQ(
+ WAIT_TIMEOUT,
+ WaitForSingleObject(process_states[i].child_handles->process.get(), 0));
+
+ // Send the handle pair along to the child, which will proceed to request a
+ // dump and wait for the "dump complete" signal.
+ WriteHandle(process_states[i].child_handles->write.get(),
+ process_states[i].request_handle);
+ WriteHandle(process_states[i].child_handles->write.get(),
+ process_states[i].done_handle);
+
+ // Wait for the process to exit with code 0 (which indicates that the "dump
+ // complete" signal was received).
+ ASSERT_EQ(WAIT_OBJECT_0,
+ WaitForSingleObject(
+ process_states[i].child_handles->process.get(), INFINITE));
+ DWORD exit_code = 0;
+ ASSERT_TRUE(GetExitCodeProcess(
+ process_states[i].child_handles->process.get(), &exit_code));
+ ASSERT_EQ(0, exit_code);
+
+ // Verify that our delegate was invoked, with the correct process handle.
+ ASSERT_EQ(1, triggered_process_ids().size());
+ ASSERT_EQ(GetProcessId(process_states[i].child_handles->process.get()),
+ triggered_process_ids()[0]);
+ }
+}
+
+} // namespace
+} // namespace test
+} // namespace crashpad
+
« handler/win/registrar.cc ('K') | « handler/win/registrar.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698