| // Copyright 2014 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 "test/multiprocess_exec.h" |
| |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "build/build_config.h" |
| #include "gtest/gtest.h" |
| #include "test/test_paths.h" |
| #include "util/file/file_io.h" |
| |
| namespace crashpad { |
| namespace test { |
| namespace { |
| |
| class TestMultiprocessExec final : public MultiprocessExec { |
| public: |
| TestMultiprocessExec() : MultiprocessExec() {} |
| |
| ~TestMultiprocessExec() {} |
| |
| private: |
| void MultiprocessParent() override { |
| // Use Logging*File() instead of Checked*File() so that the test can fail |
| // gracefully with a gtest assertion if the child does not execute properly. |
| |
| char c = 'z'; |
| ASSERT_TRUE(LoggingWriteFile(WritePipeHandle(), &c, 1)); |
| |
| ASSERT_TRUE(LoggingReadFileExactly(ReadPipeHandle(), &c, 1)); |
| EXPECT_EQ(c, 'Z'); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(TestMultiprocessExec); |
| }; |
| |
| TEST(MultiprocessExec, MultiprocessExec) { |
| TestMultiprocessExec multiprocess_exec; |
| base::FilePath child_test_executable = TestPaths::BuildArtifact( |
| FILE_PATH_LITERAL("test"), |
| FILE_PATH_LITERAL("multiprocess_exec_test_child"), |
| TestPaths::FileType::kExecutable); |
| multiprocess_exec.SetChildCommand(child_test_executable, nullptr); |
| multiprocess_exec.Run(); |
| } |
| |
| |
| CRASHPAD_CHILD_TEST_MAIN(SimpleMultiprocess) { |
| char c; |
| CheckedReadFileExactly(StdioFileHandle(StdioStream::kStandardInput), &c, 1); |
| LOG_IF(FATAL, c != 'z'); |
| |
| c = 'Z'; |
| CheckedWriteFile(StdioFileHandle(StdioStream::kStandardOutput), &c, 1); |
| return 0; |
| } |
| |
| TEST(MultiprocessExec, MultiprocessExecSimpleChild) { |
| TestMultiprocessExec exec; |
| exec.SetChildTestMainFunction("SimpleMultiprocess"); |
| exec.Run(); |
| } |
| |
| CRASHPAD_CHILD_TEST_MAIN(SimpleMultiprocessReturnsNonZero) { |
| return 123; |
| } |
| |
| class TestMultiprocessExecEmpty final : public MultiprocessExec { |
| public: |
| TestMultiprocessExecEmpty() = default; |
| ~TestMultiprocessExecEmpty() = default; |
| |
| private: |
| void MultiprocessParent() override {} |
| |
| DISALLOW_COPY_AND_ASSIGN(TestMultiprocessExecEmpty); |
| }; |
| |
| TEST(MultiprocessExec, MultiprocessExecSimpleChildReturnsNonZero) { |
| TestMultiprocessExecEmpty exec; |
| exec.SetChildTestMainFunction("SimpleMultiprocessReturnsNonZero"); |
| exec.SetExpectedChildTermination( |
| Multiprocess::TerminationReason::kTerminationNormal, 123); |
| exec.Run(); |
| } |
| |
| #if !defined(OS_WIN) |
| |
| CRASHPAD_CHILD_TEST_MAIN(BuiltinTrapChild) { |
| __builtin_trap(); |
| return EXIT_SUCCESS; |
| } |
| |
| class TestBuiltinTrapTermination final : public MultiprocessExec { |
| public: |
| TestBuiltinTrapTermination() { |
| SetChildTestMainFunction("BuiltinTrapChild"); |
| SetExpectedChildTerminationBuiltinTrap(); |
| } |
| |
| ~TestBuiltinTrapTermination() = default; |
| |
| private: |
| void MultiprocessParent() override {} |
| |
| DISALLOW_COPY_AND_ASSIGN(TestBuiltinTrapTermination); |
| }; |
| |
| TEST(MultiprocessExec, BuiltinTrapTermination) { |
| TestBuiltinTrapTermination test; |
| test.Run(); |
| } |
| |
| #endif // !OS_WIN |
| |
| } // namespace |
| } // namespace test |
| } // namespace crashpad |