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: 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 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 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 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 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