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 if (!RunTestInSandbox(static_cast<SandboxType>(i), 60 test_name, test_data)) { 61 LOG(ERROR) << "Sandboxed test (" << test_name << ")" << 62 "Failed in sandbox type " << i << 63 "user data: (" << test_data << ")"; 64 return false; 65 } 66 } 67 return true; 68 } 69 70 bool MacSandboxTest::RunTestInSandbox(SandboxType sandbox_type, 71 const char* test_name, 72 const char* test_data) { 73 std::stringstream s; 74 s << static_cast<int>(static_cast<int>(sandbox_type)); 75 setenv(kSandboxTypeKey, s.str().c_str(), 1); 76 setenv(kSandboxTestNameKey, test_name, 1); 77 if (test_data) 78 setenv(kTestDataKey, test_data, 1); 79 80 base::ProcessHandle child_process = SpawnChild("mac_sandbox_test_runner"); 81 if (child_process == base::kNullProcessHandle) { 82 LOG(WARNING) << "SpawnChild failed"; 83 return false; 84 } 85 int code = -1; 86 if (!base::WaitForExitCode(child_process, &code)) { 87 LOG(WARNING) << "base::WaitForExitCode failed"; 88 return false; 89 } 90 return code == 0; 91 } 92 93 bool MacSandboxTestCase::BeforeSandboxInit() { 94 return true; 95 } 96 97 void MacSandboxTestCase::SetTestData(const char* test_data) { 98 test_data_ = test_data; 99 } 100 101 // Given a test name specified by |name| return that test case. 102 // If no test case is found for the given name, return NULL. 103 MacSandboxTestCase *SandboxTestForName(const char* name) { 104 using internal::SandboxTestMap; 105 using internal::GetSandboxTestMap; 106 107 SandboxTestMap all_tests = GetSandboxTestMap(); 108 109 SandboxTestMap::iterator it = all_tests.find(name); 110 if (it == all_tests.end()) { 111 LOG(ERROR) << "Couldn't find sandbox test case(" << name << ")"; 112 return NULL; 113 } 114 115 return it->second; 116 } 117 118 // Main function for driver process that enables the sandbox and runs test 119 // code. 120 MULTIPROCESS_TEST_MAIN(mac_sandbox_test_runner) { 121 TestContentClient content_client; 122 SetContentClient(&content_client); 123 // Extract parameters. 124 char* sandbox_type_str = getenv(kSandboxTypeKey); 125 if (!sandbox_type_str) { 126 LOG(ERROR) << "Sandbox type not specified"; 127 return -1; 128 } 129 SandboxType sandbox_type = static_cast<SandboxType>(atoi(sandbox_type_str)); 130 char* sandbox_test_name = getenv(kSandboxTestNameKey); 131 if (!sandbox_test_name) { 132 LOG(ERROR) << "Sandbox test name not specified"; 133 return -1; 134 } 135 136 const char* test_data = getenv(kTestDataKey); 137 138 // Find Test Function to run; 139 scoped_ptr<MacSandboxTestCase> 140 test_case(SandboxTestForName(sandbox_test_name)); 141 if (!test_case) { 142 LOG(ERROR) << "Invalid sandbox test name (" << sandbox_test_name << ")"; 143 return -1; 144 } 145 if (test_data) 146 test_case->SetTestData(test_data); 147 148 // Run Test. 149 if (!test_case->BeforeSandboxInit()) { 150 LOG(ERROR) << sandbox_test_name << "Failed test before sandbox init"; 151 return -1; 152 } 153 154 Sandbox::SandboxWarmup(sandbox_type); 155 156 if (!Sandbox::EnableSandbox(sandbox_type, base::FilePath())) { 157 LOG(ERROR) << "Failed to initialize sandbox " << sandbox_type; 158 return -1; 159 } 160 161 if (!test_case->SandboxedTest()) { 162 LOG(ERROR) << sandbox_test_name << "Failed sandboxed test"; 163 return -1; 164 } 165 166 return 0; 167 } 168 169 } // namespace content 170