Home | History | Annotate | Download | only in common
      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