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.
4
5 #include "cloud_print/virtual_driver/win/port_monitor/port_monitor.h"
6
7 #include <winspool.h>
8
9 #include "base/files/file_util.h"
10 #include "base/path_service.h"
11 #include "base/strings/string16.h"
12 #include "base/win/registry.h"
13 #include "base/win/scoped_handle.h"
14 #include "cloud_print/virtual_driver/win/port_monitor/spooler_win.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace cloud_print {
18
19 const wchar_t kChromeExePath[] = L"google\\chrome\\application\\chrometest.exe";
20 const wchar_t kChromeExePathRegValue[] = L"PathToChromeTestExe";
21 const wchar_t kChromeProfilePathRegValue[] = L"PathToChromeTestProfile";
22 const bool kIsUnittest = true;
23
24 namespace {
25
26 const wchar_t kAlternateChromeExePath[] =
27 L"google\\chrome\\application\\chrometestalternate.exe";
28
29 const wchar_t kCloudPrintRegKey[] = L"Software\\Google\\CloudPrint";
30
31 } // namespace
32
33 class PortMonitorTest : public testing::Test {
34 public:
PortMonitorTest()35 PortMonitorTest() {}
36 protected:
37 // Creates a registry entry pointing at a chrome
SetUpChromeExeRegistry()38 virtual void SetUpChromeExeRegistry() {
39 // Create a temporary chrome.exe location value.
40 base::win::RegKey key(HKEY_CURRENT_USER,
41 cloud_print::kCloudPrintRegKey,
42 KEY_ALL_ACCESS);
43
44 base::FilePath path;
45 PathService::Get(base::DIR_LOCAL_APP_DATA, &path);
46 path = path.Append(kAlternateChromeExePath);
47 ASSERT_EQ(ERROR_SUCCESS,
48 key.WriteValue(cloud_print::kChromeExePathRegValue,
49 path.value().c_str()));
50 base::FilePath temp;
51 PathService::Get(base::DIR_TEMP, &temp);
52 // Write any dir here.
53 ASSERT_EQ(ERROR_SUCCESS,
54 key.WriteValue(cloud_print::kChromeProfilePathRegValue,
55 temp.value().c_str()));
56 }
57 // Deletes the registry entry created in SetUpChromeExeRegistry
DeleteChromeExeRegistry()58 virtual void DeleteChromeExeRegistry() {
59 base::win::RegKey key(HKEY_CURRENT_USER,
60 cloud_print::kCloudPrintRegKey,
61 KEY_ALL_ACCESS);
62 key.DeleteValue(cloud_print::kChromeExePathRegValue);
63 key.DeleteValue(cloud_print::kChromeProfilePathRegValue);
64 }
65
CreateTempChromeExeFiles()66 virtual void CreateTempChromeExeFiles() {
67 base::FilePath path;
68 PathService::Get(base::DIR_LOCAL_APP_DATA, &path);
69 base::FilePath main_path = path.Append(kChromeExePath);
70 ASSERT_TRUE(base::CreateDirectory(main_path));
71 base::FilePath alternate_path = path.Append(kAlternateChromeExePath);
72 ASSERT_TRUE(base::CreateDirectory(alternate_path));
73 }
74
DeleteTempChromeExeFiles()75 virtual void DeleteTempChromeExeFiles() {
76 base::FilePath path;
77 PathService::Get(base::DIR_LOCAL_APP_DATA, &path);
78 base::FilePath main_path = path.Append(kChromeExePath);
79 ASSERT_TRUE(base::DeleteFile(main_path, true));
80 PathService::Get(base::DIR_LOCAL_APP_DATA, &path);
81 base::FilePath alternate_path = path.Append(kAlternateChromeExePath);
82 ASSERT_TRUE(base::DeleteFile(alternate_path, true));
83 }
84
85 protected:
SetUp()86 virtual void SetUp() {
87 SetUpChromeExeRegistry();
88 }
89
TearDown()90 virtual void TearDown() {
91 DeleteChromeExeRegistry();
92 }
93
94 private:
95 DISALLOW_COPY_AND_ASSIGN(PortMonitorTest);
96 };
97
TEST_F(PortMonitorTest,GetChromeExePathTest)98 TEST_F(PortMonitorTest, GetChromeExePathTest) {
99 CreateTempChromeExeFiles();
100 base::FilePath chrome_path = cloud_print::GetChromeExePath();
101 EXPECT_FALSE(chrome_path.empty());
102 EXPECT_TRUE(
103 chrome_path.value().rfind(kAlternateChromeExePath) != std::string::npos);
104 EXPECT_TRUE(base::PathExists(chrome_path));
105 DeleteChromeExeRegistry();
106 chrome_path = cloud_print::GetChromeExePath();
107 // No Chrome or regular chrome path.
108 EXPECT_TRUE(chrome_path.empty() ||
109 chrome_path.value().rfind(kChromeExePath) == std::string::npos);
110 }
111
TEST_F(PortMonitorTest,GetChromeProfilePathTest)112 TEST_F(PortMonitorTest, GetChromeProfilePathTest) {
113 base::FilePath data_path = cloud_print::GetChromeProfilePath();
114 EXPECT_FALSE(data_path.empty());
115 base::FilePath temp;
116 PathService::Get(base::DIR_TEMP, &temp);
117 EXPECT_EQ(data_path, temp);
118 EXPECT_TRUE(base::DirectoryExists(data_path));
119 DeleteChromeExeRegistry();
120 data_path = cloud_print::GetChromeProfilePath();
121 EXPECT_TRUE(data_path.empty());
122 }
123
TEST_F(PortMonitorTest,EnumPortsTest)124 TEST_F(PortMonitorTest, EnumPortsTest) {
125 DWORD needed_bytes = 0;
126 DWORD returned = 0;
127 EXPECT_FALSE(Monitor2EnumPorts(NULL,
128 NULL,
129 1,
130 NULL,
131 0,
132 &needed_bytes,
133 &returned));
134 EXPECT_EQ(ERROR_INSUFFICIENT_BUFFER, GetLastError());
135 EXPECT_NE(0u, needed_bytes);
136 EXPECT_EQ(0u, returned);
137
138 BYTE* buffer = new BYTE[needed_bytes];
139 ASSERT_TRUE(buffer != NULL);
140 EXPECT_TRUE(Monitor2EnumPorts(NULL,
141 NULL,
142 1,
143 buffer,
144 needed_bytes,
145 &needed_bytes,
146 &returned));
147 EXPECT_NE(0u, needed_bytes);
148 EXPECT_EQ(1u, returned);
149 PORT_INFO_1* port_info_1 = reinterpret_cast<PORT_INFO_1*>(buffer);
150 EXPECT_TRUE(port_info_1->pName != NULL);
151 delete[] buffer;
152
153 returned = 0;
154 needed_bytes = 0;
155 EXPECT_FALSE(Monitor2EnumPorts(NULL,
156 NULL,
157 2,
158 NULL,
159 0,
160 &needed_bytes,
161 &returned));
162 EXPECT_EQ(ERROR_INSUFFICIENT_BUFFER, GetLastError());
163 EXPECT_NE(0u, needed_bytes);
164 EXPECT_EQ(0u, returned);
165
166 buffer = new BYTE[needed_bytes];
167 ASSERT_TRUE(buffer != NULL);
168 EXPECT_TRUE(Monitor2EnumPorts(NULL,
169 NULL,
170 2,
171 buffer,
172 needed_bytes,
173 &needed_bytes,
174 &returned));
175 EXPECT_NE(0u, needed_bytes);
176 EXPECT_EQ(1u, returned);
177 PORT_INFO_2* port_info_2 = reinterpret_cast<PORT_INFO_2*>(buffer);
178 EXPECT_TRUE(port_info_2->pPortName != NULL);
179 delete[] buffer;
180 }
181
TEST_F(PortMonitorTest,FlowTest)182 TEST_F(PortMonitorTest, FlowTest) {
183 const wchar_t kXcvDataItem[] = L"MonitorUI";
184 MONITORINIT monitor_init = {0};
185 HANDLE monitor_handle = NULL;
186 HANDLE port_handle = NULL;
187 HANDLE xcv_handle = NULL;
188 DWORD bytes_processed = 0;
189 DWORD bytes_needed = 0;
190 const size_t kBufferSize = 100;
191 BYTE buffer[kBufferSize] = {0};
192
193 // Initialize the print monitor
194 MONITOR2* monitor2 = InitializePrintMonitor2(&monitor_init, &monitor_handle);
195 EXPECT_TRUE(monitor2 != NULL);
196 EXPECT_TRUE(monitor_handle != NULL);
197
198 // Test the XCV functions. Used for reporting the location of the
199 // UI portion of the port monitor.
200 EXPECT_TRUE(monitor2->pfnXcvOpenPort != NULL);
201 EXPECT_TRUE(monitor2->pfnXcvOpenPort(monitor_handle, NULL, 0, &xcv_handle));
202 EXPECT_TRUE(xcv_handle != NULL);
203 EXPECT_TRUE(monitor2->pfnXcvDataPort != NULL);
204 EXPECT_EQ(ERROR_ACCESS_DENIED,
205 monitor2->pfnXcvDataPort(xcv_handle,
206 kXcvDataItem,
207 NULL,
208 0,
209 buffer,
210 kBufferSize,
211 &bytes_needed));
212 EXPECT_TRUE(monitor2->pfnXcvClosePort != NULL);
213 EXPECT_TRUE(monitor2->pfnXcvClosePort(xcv_handle));
214 EXPECT_TRUE(monitor2->pfnXcvOpenPort(monitor_handle,
215 NULL,
216 SERVER_ACCESS_ADMINISTER,
217 &xcv_handle));
218 EXPECT_TRUE(xcv_handle != NULL);
219 EXPECT_TRUE(monitor2->pfnXcvDataPort != NULL);
220 EXPECT_EQ(ERROR_SUCCESS,
221 monitor2->pfnXcvDataPort(xcv_handle,
222 kXcvDataItem,
223 NULL,
224 0,
225 buffer,
226 kBufferSize,
227 &bytes_needed));
228 EXPECT_TRUE(monitor2->pfnXcvClosePort != NULL);
229 EXPECT_TRUE(monitor2->pfnXcvClosePort(xcv_handle));
230
231 // Test opening the port and running a print job.
232 EXPECT_TRUE(monitor2->pfnOpenPort != NULL);
233 EXPECT_TRUE(monitor2->pfnOpenPort(monitor_handle, NULL, &port_handle));
234 EXPECT_TRUE(port_handle != NULL);
235 EXPECT_TRUE(monitor2->pfnStartDocPort != NULL);
236 EXPECT_TRUE(monitor2->pfnWritePort != NULL);
237 EXPECT_TRUE(monitor2->pfnReadPort != NULL);
238 EXPECT_TRUE(monitor2->pfnEndDocPort != NULL);
239
240 // These functions should fail if we have not impersonated the user.
241 EXPECT_FALSE(monitor2->pfnStartDocPort(
242 port_handle, const_cast<wchar_t*>(L""), 0, 0, NULL));
243 EXPECT_FALSE(monitor2->pfnWritePort(port_handle,
244 buffer,
245 kBufferSize,
246 &bytes_processed));
247 EXPECT_EQ(0, bytes_processed);
248 EXPECT_FALSE(monitor2->pfnReadPort(port_handle,
249 buffer,
250 sizeof(buffer),
251 &bytes_processed));
252 EXPECT_EQ(0u, bytes_processed);
253 EXPECT_FALSE(monitor2->pfnEndDocPort(port_handle));
254
255 // Now impersonate so we can test the success case.
256 ASSERT_TRUE(ImpersonateSelf(SecurityImpersonation));
257 EXPECT_TRUE(monitor2->pfnStartDocPort(
258 port_handle, const_cast<wchar_t*>(L""), 0, 0, NULL));
259 EXPECT_TRUE(monitor2->pfnWritePort(port_handle,
260 buffer,
261 kBufferSize,
262 &bytes_processed));
263 EXPECT_EQ(kBufferSize, bytes_processed);
264 EXPECT_FALSE(monitor2->pfnReadPort(port_handle,
265 buffer,
266 sizeof(buffer),
267 &bytes_processed));
268 EXPECT_EQ(0u, bytes_processed);
269 EXPECT_TRUE(monitor2->pfnEndDocPort(port_handle));
270 RevertToSelf();
271 EXPECT_TRUE(monitor2->pfnClosePort != NULL);
272 EXPECT_TRUE(monitor2->pfnClosePort(port_handle));
273 // Shutdown the port monitor.
274 Monitor2Shutdown(monitor_handle);
275 }
276
277 } // namespace cloud_print
278
279