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
17namespace cloud_print {
18
19const wchar_t kChromeExePath[] = L"google\\chrome\\application\\chrometest.exe";
20const wchar_t kChromeExePathRegValue[] = L"PathToChromeTestExe";
21const wchar_t kChromeProfilePathRegValue[] = L"PathToChromeTestProfile";
22const bool kIsUnittest = true;
23
24namespace {
25
26const wchar_t kAlternateChromeExePath[] =
27    L"google\\chrome\\application\\chrometestalternate.exe";
28
29const wchar_t kCloudPrintRegKey[] = L"Software\\Google\\CloudPrint";
30
31}  // namespace
32
33class PortMonitorTest : public testing::Test  {
34 public:
35  PortMonitorTest() {}
36 protected:
37  // Creates a registry entry pointing at a chrome
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
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
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
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:
86  virtual void SetUp() {
87    SetUpChromeExeRegistry();
88  }
89
90  virtual void TearDown() {
91    DeleteChromeExeRegistry();
92  }
93
94 private:
95  DISALLOW_COPY_AND_ASSIGN(PortMonitorTest);
96};
97
98TEST_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
112TEST_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
124TEST_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
182TEST_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