1 // Copyright (c) 2012 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.
5 // This file contains unit tests for the job object.
7 #include "base/win/scoped_process_information.h"
8 #include "sandbox/win/src/job.h"
9 #include "testing/gtest/include/gtest/gtest.h"
13 // Tests the creation and destruction of the job.
14 TEST(JobTest
, TestCreation
) {
15 // Scope the creation of Job.
19 ASSERT_EQ(ERROR_SUCCESS
, job
.Init(JOB_LOCKDOWN
, L
"my_test_job_name", 0, 0));
21 // check if the job exists.
22 HANDLE job_handle
= ::OpenJobObjectW(GENERIC_ALL
, FALSE
,
24 ASSERT_TRUE(job_handle
!= NULL
);
27 CloseHandle(job_handle
);
30 // Check if the job is destroyed when the object goes out of scope.
31 HANDLE job_handle
= ::OpenJobObjectW(GENERIC_ALL
, FALSE
, L
"my_test_job_name");
32 ASSERT_TRUE(job_handle
== NULL
);
33 ASSERT_EQ(ERROR_FILE_NOT_FOUND
, ::GetLastError());
36 // Tests the method "Detach".
37 TEST(JobTest
, TestDetach
) {
39 // Scope the creation of Job.
43 ASSERT_EQ(ERROR_SUCCESS
, job
.Init(JOB_LOCKDOWN
, L
"my_test_job_name", 0, 0));
45 job_handle
= job
.Detach();
46 ASSERT_TRUE(job_handle
!= NULL
);
49 // Check to be sure that the job is still alive even after the object is gone
51 HANDLE job_handle_dup
= ::OpenJobObjectW(GENERIC_ALL
, FALSE
,
53 ASSERT_TRUE(job_handle_dup
!= NULL
);
55 // Remove all references.
57 ::CloseHandle(job_handle_dup
);
60 ::CloseHandle(job_handle
);
62 // Check if the jbo is really dead.
63 job_handle
= ::OpenJobObjectW(GENERIC_ALL
, FALSE
, L
"my_test_job_name");
64 ASSERT_TRUE(job_handle
== NULL
);
65 ASSERT_EQ(ERROR_FILE_NOT_FOUND
, ::GetLastError());
68 // Tests the ui exceptions
69 TEST(JobTest
, TestExceptions
) {
71 // Scope the creation of Job.
75 ASSERT_EQ(ERROR_SUCCESS
, job
.Init(JOB_LOCKDOWN
, L
"my_test_job_name",
76 JOB_OBJECT_UILIMIT_READCLIPBOARD
, 0));
78 job_handle
= job
.Detach();
79 ASSERT_TRUE(job_handle
!= NULL
);
81 JOBOBJECT_BASIC_UI_RESTRICTIONS jbur
= {0};
82 DWORD size
= sizeof(jbur
);
83 BOOL result
= ::QueryInformationJobObject(job_handle
,
84 JobObjectBasicUIRestrictions
,
88 ASSERT_EQ(jbur
.UIRestrictionsClass
& JOB_OBJECT_UILIMIT_READCLIPBOARD
, 0);
89 ::CloseHandle(job_handle
);
92 // Scope the creation of Job.
96 ASSERT_EQ(ERROR_SUCCESS
, job
.Init(JOB_LOCKDOWN
, L
"my_test_job_name", 0, 0));
98 job_handle
= job
.Detach();
99 ASSERT_TRUE(job_handle
!= NULL
);
101 JOBOBJECT_BASIC_UI_RESTRICTIONS jbur
= {0};
102 DWORD size
= sizeof(jbur
);
103 BOOL result
= ::QueryInformationJobObject(job_handle
,
104 JobObjectBasicUIRestrictions
,
108 ASSERT_EQ(jbur
.UIRestrictionsClass
& JOB_OBJECT_UILIMIT_READCLIPBOARD
,
109 JOB_OBJECT_UILIMIT_READCLIPBOARD
);
110 ::CloseHandle(job_handle
);
114 // Tests the error case when the job is initialized twice.
115 TEST(JobTest
, DoubleInit
) {
118 ASSERT_EQ(ERROR_SUCCESS
, job
.Init(JOB_LOCKDOWN
, L
"my_test_job_name", 0, 0));
119 ASSERT_EQ(ERROR_ALREADY_INITIALIZED
, job
.Init(JOB_LOCKDOWN
, L
"test", 0, 0));
122 // Tests the error case when we use a method and the object is not yet
124 TEST(JobTest
, NoInit
) {
126 ASSERT_EQ(ERROR_NO_DATA
, job
.UserHandleGrantAccess(NULL
));
127 ASSERT_EQ(ERROR_NO_DATA
, job
.AssignProcessToJob(NULL
));
128 ASSERT_TRUE(job
.Detach() == NULL
);
131 // Tests the initialization of the job with different security level.
132 TEST(JobTest
, SecurityLevel
) {
134 ASSERT_EQ(ERROR_SUCCESS
, job1
.Init(JOB_LOCKDOWN
, L
"job1", 0, 0));
137 ASSERT_EQ(ERROR_SUCCESS
, job2
.Init(JOB_RESTRICTED
, L
"job2", 0, 0));
140 ASSERT_EQ(ERROR_SUCCESS
, job3
.Init(JOB_LIMITED_USER
, L
"job3", 0, 0));
143 ASSERT_EQ(ERROR_SUCCESS
, job4
.Init(JOB_INTERACTIVE
, L
"job4", 0, 0));
146 ASSERT_EQ(ERROR_SUCCESS
, job5
.Init(JOB_UNPROTECTED
, L
"job5", 0, 0));
148 // JOB_NONE means we run without a job object so Init should fail.
150 ASSERT_EQ(ERROR_BAD_ARGUMENTS
, job6
.Init(JOB_NONE
, L
"job6", 0, 0));
153 ASSERT_EQ(ERROR_BAD_ARGUMENTS
, job7
.Init(
154 static_cast<JobLevel
>(JOB_NONE
+1), L
"job7", 0, 0));
157 // Tests the method "AssignProcessToJob".
158 TEST(JobTest
, ProcessInJob
) {
161 ASSERT_EQ(ERROR_SUCCESS
, job
.Init(JOB_UNPROTECTED
, L
"job_test_process", 0,
166 wchar_t notepad
[] = L
"notepad";
167 STARTUPINFO si
= { sizeof(si
) };
168 PROCESS_INFORMATION temp_process_info
= {};
169 result
= ::CreateProcess(NULL
, notepad
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
,
172 base::win::ScopedProcessInformation
pi(temp_process_info
);
173 ASSERT_EQ(ERROR_SUCCESS
, job
.AssignProcessToJob(pi
.process_handle()));
175 // Get the job handle.
176 HANDLE job_handle
= job
.Detach();
178 // Check if the process is in the job.
179 JOBOBJECT_BASIC_PROCESS_ID_LIST jbpidl
= {0};
180 DWORD size
= sizeof(jbpidl
);
181 result
= ::QueryInformationJobObject(job_handle
,
182 JobObjectBasicProcessIdList
,
183 &jbpidl
, size
, &size
);
186 EXPECT_EQ(1, jbpidl
.NumberOfAssignedProcesses
);
187 EXPECT_EQ(1, jbpidl
.NumberOfProcessIdsInList
);
188 EXPECT_EQ(pi
.process_id(), jbpidl
.ProcessIdList
[0]);
190 EXPECT_TRUE(::TerminateProcess(pi
.process_handle(), 0));
192 EXPECT_TRUE(::CloseHandle(job_handle
));
195 } // namespace sandbox