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