summaryrefslogtreecommitdiff
path: root/chromium/content/common/sandbox_mac_unittest_helper.mm
blob: 0a8d3c1965ef285a5c20f6451a8df9bedd80216c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/common/sandbox_mac_unittest_helper.h"

extern "C" {
#include <sandbox.h>
}

#include <map>

#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/kill.h"
#include "content/common/sandbox_mac.h"
#include "content/test/test_content_client.h"
#include "testing/multiprocess_func_list.h"

namespace content {
namespace {

const char* kSandboxTypeKey = "CHROMIUM_SANDBOX_SANDBOX_TYPE";
const char* kSandboxTestNameKey = "CHROMIUM_SANDBOX_TEST_NAME";
const char* kTestDataKey = "CHROMIUM_SANDBOX_USER_DATA";

}  // namespace

// Support infrastructure for REGISTER_SANDBOX_TEST_CASE macro.
namespace internal {

typedef std::map<std::string,MacSandboxTestCase*> SandboxTestMap;

// A function that returns a common map from string -> test case class.
SandboxTestMap& GetSandboxTestMap() {
  static SandboxTestMap test_map;
  return test_map;
}

void AddSandboxTestCase(const char* test_name, MacSandboxTestCase* test_class) {
  SandboxTestMap& test_map = GetSandboxTestMap();
  if (test_map.find(test_name) != test_map.end()) {
    LOG(ERROR) << "Trying to register duplicate test" << test_name;
    NOTREACHED();
  }
  test_map[test_name] = test_class;
}

}  // namespace internal

bool MacSandboxTest::RunTestInAllSandboxTypes(const char* test_name,
                                              const char* test_data) {
  // Go through all the sandbox types, and run the test case in each of them
  // if one fails, abort.
  for(int i = static_cast<int>(SANDBOX_TYPE_FIRST_TYPE);
      i < SANDBOX_TYPE_AFTER_LAST_TYPE;
      ++i) {

    if (!RunTestInSandbox(static_cast<SandboxType>(i),
            test_name, test_data)) {
      LOG(ERROR) << "Sandboxed test (" << test_name << ")" <<
          "Failed in sandbox type " << i <<
          "user data: (" << test_data << ")";
      return false;
    }
  }
 return true;
}

bool MacSandboxTest::RunTestInSandbox(SandboxType sandbox_type,
                                      const char* test_name,
                                      const char* test_data) {
  std::stringstream s;
  s << static_cast<int>(static_cast<int>(sandbox_type));
  setenv(kSandboxTypeKey, s.str().c_str(), 1);
  setenv(kSandboxTestNameKey, test_name, 1);
  if (test_data)
    setenv(kTestDataKey, test_data, 1);

  base::ProcessHandle child_process = SpawnChild("mac_sandbox_test_runner",
                                                 false);
  if (child_process == base::kNullProcessHandle) {
    LOG(WARNING) << "SpawnChild failed";
    return false;
  }
  int code = -1;
  if (!base::WaitForExitCode(child_process, &code)) {
    LOG(WARNING) << "base::WaitForExitCode failed";
    return false;
  }
  return code == 0;
}

bool MacSandboxTestCase::BeforeSandboxInit() {
  return true;
}

void MacSandboxTestCase::SetTestData(const char* test_data) {
  test_data_ = test_data;
}

// Given a test name specified by |name| return that test case.
// If no test case is found for the given name, return NULL.
MacSandboxTestCase *SandboxTestForName(const char* name) {
  using internal::SandboxTestMap;
  using internal::GetSandboxTestMap;

  SandboxTestMap all_tests = GetSandboxTestMap();

  SandboxTestMap::iterator it = all_tests.find(name);
  if (it == all_tests.end()) {
    LOG(ERROR) << "Couldn't find sandbox test case(" << name << ")";
    return NULL;
  }

  return it->second;
}

// Main function for driver process that enables the sandbox and runs test
// code.
MULTIPROCESS_TEST_MAIN(mac_sandbox_test_runner) {
  TestContentClient content_client;
  SetContentClient(&content_client);
  // Extract parameters.
  char* sandbox_type_str = getenv(kSandboxTypeKey);
  if (!sandbox_type_str) {
    LOG(ERROR) << "Sandbox type not specified";
    return -1;
  }
  SandboxType sandbox_type = static_cast<SandboxType>(atoi(sandbox_type_str));
  char* sandbox_test_name = getenv(kSandboxTestNameKey);
  if (!sandbox_test_name) {
    LOG(ERROR) << "Sandbox test name not specified";
    return -1;
  }

  const char* test_data = getenv(kTestDataKey);

  // Find Test Function to run;
  scoped_ptr<MacSandboxTestCase>
      test_case(SandboxTestForName(sandbox_test_name));
  if (!test_case) {
    LOG(ERROR) << "Invalid sandbox test name (" << sandbox_test_name << ")";
    return -1;
  }
  if (test_data)
    test_case->SetTestData(test_data);

  // Run Test.
  if (!test_case->BeforeSandboxInit()) {
    LOG(ERROR) << sandbox_test_name << "Failed test before sandbox init";
    return -1;
  }

  Sandbox::SandboxWarmup(sandbox_type);

  if (!Sandbox::EnableSandbox(sandbox_type, base::FilePath())) {
    LOG(ERROR) << "Failed to initialize sandbox " << sandbox_type;
    return -1;
  }

  if (!test_case->SandboxedTest()) {
    LOG(ERROR) << sandbox_test_name << "Failed sandboxed test";
    return -1;
  }

  return 0;
}

}  // namespace content