1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/common/sandbox_mac_unittest_helper.h" 6 7 extern "C" { 8 #include <sandbox.h> 9 } 10 11 #include <map> 12 13 #include "base/files/file_path.h" 14 #include "base/logging.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/process/kill.h" 17 #include "content/common/sandbox_mac.h" 18 #include "content/test/test_content_client.h" 19 #include "testing/multiprocess_func_list.h" 20 21 namespace content { 22 namespace { 23 24 const char* kSandboxTypeKey = "CHROMIUM_SANDBOX_SANDBOX_TYPE"; 25 const char* kSandboxTestNameKey = "CHROMIUM_SANDBOX_TEST_NAME"; 26 const char* kTestDataKey = "CHROMIUM_SANDBOX_USER_DATA"; 27 28 } // namespace 29 30 // Support infrastructure for REGISTER_SANDBOX_TEST_CASE macro. 31 namespace internal { 32 33 typedef std::map<std::string,MacSandboxTestCase*> SandboxTestMap; 34 35 // A function that returns a common map from string -> test case class. 36 SandboxTestMap& GetSandboxTestMap() { 37 static SandboxTestMap test_map; 38 return test_map; 39 } 40 41 void AddSandboxTestCase(const char* test_name, MacSandboxTestCase* test_class) { 42 SandboxTestMap& test_map = GetSandboxTestMap(); 43 if (test_map.find(test_name) != test_map.end()) { 44 LOG(ERROR) << "Trying to register duplicate test" << test_name; 45 NOTREACHED(); 46 } 47 test_map[test_name] = test_class; 48 } 49 50 } // namespace internal 51 52 bool MacSandboxTest::RunTestInAllSandboxTypes(const char* test_name, 53 const char* test_data) { 54 // Go through all the sandbox types, and run the test case in each of them 55 // if one fails, abort. 56 for(int i = static_cast<int>(SANDBOX_TYPE_FIRST_TYPE); 57 i < SANDBOX_TYPE_AFTER_LAST_TYPE; 58 ++i) { 59 60 if (!RunTestInSandbox(static_cast<SandboxType>(i), 61 test_name, test_data)) { 62 LOG(ERROR) << "Sandboxed test (" << test_name << ")" << 63 "Failed in sandbox type " << i << 64 "user data: (" << test_data << ")"; 65 return false; 66 } 67 } 68 return true; 69 } 70 71 bool MacSandboxTest::RunTestInSandbox(SandboxType sandbox_type, 72 const char* test_name, 73 const char* test_data) { 74 std::stringstream s; 75 s << static_cast<int>(static_cast<int>(sandbox_type)); 76 setenv(kSandboxTypeKey, s.str().c_str(), 1); 77 setenv(kSandboxTestNameKey, test_name, 1); 78 if (test_data) 79 setenv(kTestDataKey, test_data, 1); 80 81 base::ProcessHandle child_process = SpawnChild("mac_sandbox_test_runner", 82 false); 83 if (child_process == base::kNullProcessHandle) { 84 LOG(WARNING) << "SpawnChild failed"; 85 return false; 86 } 87 int code = -1; 88 if (!base::WaitForExitCode(child_process, &code)) { 89 LOG(WARNING) << "base::WaitForExitCode failed"; 90 return false; 91 } 92 return code == 0; 93 } 94 95 bool MacSandboxTestCase::BeforeSandboxInit() { 96 return true; 97 } 98 99 void MacSandboxTestCase::SetTestData(const char* test_data) { 100 test_data_ = test_data; 101 } 102 103 // Given a test name specified by |name| return that test case. 104 // If no test case is found for the given name, return NULL. 105 MacSandboxTestCase *SandboxTestForName(const char* name) { 106 using internal::SandboxTestMap; 107 using internal::GetSandboxTestMap; 108 109 SandboxTestMap all_tests = GetSandboxTestMap(); 110 111 SandboxTestMap::iterator it = all_tests.find(name); 112 if (it == all_tests.end()) { 113 LOG(ERROR) << "Couldn't find sandbox test case(" << name << ")"; 114 return NULL; 115 } 116 117 return it->second; 118 } 119 120 // Main function for driver process that enables the sandbox and runs test 121 // code. 122 MULTIPROCESS_TEST_MAIN(mac_sandbox_test_runner) { 123 TestContentClient content_client; 124 SetContentClient(&content_client); 125 // Extract parameters. 126 char* sandbox_type_str = getenv(kSandboxTypeKey); 127 if (!sandbox_type_str) { 128 LOG(ERROR) << "Sandbox type not specified"; 129 return -1; 130 } 131 SandboxType sandbox_type = static_cast<SandboxType>(atoi(sandbox_type_str)); 132 char* sandbox_test_name = getenv(kSandboxTestNameKey); 133 if (!sandbox_test_name) { 134 LOG(ERROR) << "Sandbox test name not specified"; 135 return -1; 136 } 137 138 const char* test_data = getenv(kTestDataKey); 139 140 // Find Test Function to run; 141 scoped_ptr<MacSandboxTestCase> 142 test_case(SandboxTestForName(sandbox_test_name)); 143 if (!test_case) { 144 LOG(ERROR) << "Invalid sandbox test name (" << sandbox_test_name << ")"; 145 return -1; 146 } 147 if (test_data) 148 test_case->SetTestData(test_data); 149 150 // Run Test. 151 if (!test_case->BeforeSandboxInit()) { 152 LOG(ERROR) << sandbox_test_name << "Failed test before sandbox init"; 153 return -1; 154 } 155 156 Sandbox::SandboxWarmup(sandbox_type); 157 158 if (!Sandbox::EnableSandbox(sandbox_type, base::FilePath())) { 159 LOG(ERROR) << "Failed to initialize sandbox " << sandbox_type; 160 return -1; 161 } 162 163 if (!test_case->SandboxedTest()) { 164 LOG(ERROR) << sandbox_test_name << "Failed sandboxed test"; 165 return -1; 166 } 167 168 return 0; 169 } 170 171 } // namespace content 172