github.com/elastic/gosigar@v0.14.3/sys/windows/syscall_windows_test.go (about) 1 package windows 2 3 import ( 4 "encoding/binary" 5 "os" 6 "runtime" 7 "syscall" 8 "testing" 9 "unsafe" 10 11 "github.com/pkg/errors" 12 "github.com/stretchr/testify/assert" 13 ) 14 15 func TestGetProcessImageFileName(t *testing.T) { 16 h, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(syscall.Getpid())) 17 if err != nil { 18 t.Fatal(err) 19 } 20 21 filename, err := GetProcessImageFileName(h) 22 if err != nil { 23 t.Fatal(err) 24 } 25 26 t.Logf("GetProcessImageFileName: %v", filename) 27 } 28 29 func TestGetProcessMemoryInfo(t *testing.T) { 30 h, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(syscall.Getpid())) 31 if err != nil { 32 t.Fatal(err) 33 } 34 counters, err := GetProcessMemoryInfo(h) 35 if err != nil { 36 t.Fatal(err) 37 } 38 39 t.Logf("GetProcessMemoryInfo: ProcessMemoryCountersEx=%+v", counters) 40 } 41 42 func TestGetLogicalDriveStrings(t *testing.T) { 43 drives, err := GetLogicalDriveStrings() 44 if err != nil { 45 t.Fatal(err) 46 } 47 48 t.Logf("GetLogicalDriveStrings: %v", drives) 49 } 50 51 func TestGetDriveType(t *testing.T) { 52 drives, err := GetLogicalDriveStrings() 53 if err != nil { 54 t.Fatal(err) 55 } 56 57 for _, drive := range drives { 58 dt, err := GetDriveType(drive) 59 if err != nil { 60 t.Fatal(err) 61 } 62 63 t.Logf("GetDriveType: drive=%v, type=%v", drive, dt) 64 } 65 } 66 67 func TestGetSystemTimes(t *testing.T) { 68 idle, kernel, user, err := GetSystemTimes() 69 if err != nil { 70 t.Fatal(err) 71 } 72 73 t.Logf("GetSystemTimes: idle=%v, kernel=%v, user=%v", idle, kernel, user) 74 } 75 76 func TestGlobalMemoryStatusEx(t *testing.T) { 77 mem, err := GlobalMemoryStatusEx() 78 if err != nil { 79 t.Fatal(err) 80 } 81 82 t.Logf("GlobalMemoryStatusEx: %+v", mem) 83 } 84 85 func TestEnumProcesses(t *testing.T) { 86 pids, err := EnumProcesses() 87 if err != nil { 88 t.Fatal(err) 89 } 90 91 t.Logf("EnumProcesses: %v", pids) 92 } 93 94 func TestGetDiskFreeSpaceEx(t *testing.T) { 95 if runtime.GOOS == "windows" { 96 t.Skip("test is not running on latest windows versions. See https://github.com/elastic/gosigar/issues/172") 97 return 98 } 99 drives, err := GetLogicalDriveStrings() 100 if err != nil { 101 t.Fatal(err) 102 } 103 104 for _, drive := range drives { 105 dt, err := GetDriveType(drive) 106 if err != nil { 107 t.Fatal(err) 108 } 109 110 // Ignore CDROM drives. They return an error if the drive is emtpy. 111 if dt != DRIVE_CDROM { 112 free, total, totalFree, err := GetDiskFreeSpaceEx(drive) 113 if err != nil { 114 t.Fatal(err) 115 } 116 t.Logf("GetDiskFreeSpaceEx: %v, %v, %v", free, total, totalFree) 117 } 118 } 119 } 120 121 func TestGetFilesystemType(t *testing.T) { 122 drives, err := GetLogicalDriveStrings() 123 if err != nil { 124 t.Fatal(err) 125 } 126 127 for _, drive := range drives { 128 volumeType, err := GetFilesystemType(drive) 129 if err != nil { 130 t.Fatal(err) 131 } 132 t.Logf("GetFilesystemType: %v - %v", drive, volumeType) 133 } 134 } 135 136 func TestGetWindowsVersion(t *testing.T) { 137 ver := GetWindowsVersion() 138 assert.True(t, ver.Major >= 5) 139 t.Logf("GetWindowsVersion: %+v", ver) 140 } 141 142 func TestCreateToolhelp32Snapshot(t *testing.T) { 143 handle, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 144 if err != nil { 145 t.Fatal(err) 146 } 147 defer syscall.CloseHandle(syscall.Handle(handle)) 148 149 // Iterate over the snapshots until our PID is found. 150 pid := uint32(syscall.Getpid()) 151 for { 152 process, err := Process32Next(handle) 153 if errors.Cause(err) == syscall.ERROR_NO_MORE_FILES { 154 break 155 } 156 if err != nil { 157 t.Fatal(err) 158 } 159 160 t.Logf("CreateToolhelp32Snapshot: ProcessEntry32=%v", process) 161 162 if process.ProcessID == pid { 163 assert.EqualValues(t, syscall.Getppid(), process.ParentProcessID) 164 return 165 } 166 } 167 168 assert.Fail(t, "Snapshot not found for PID=%v", pid) 169 } 170 171 func TestNtQuerySystemProcessorPerformanceInformation(t *testing.T) { 172 cpus, err := NtQuerySystemProcessorPerformanceInformation() 173 if err != nil { 174 t.Fatal(err) 175 } 176 177 assert.Len(t, cpus, runtime.NumCPU()) 178 179 for i, cpu := range cpus { 180 assert.NotZero(t, cpu.IdleTime) 181 assert.NotZero(t, cpu.KernelTime) 182 assert.NotZero(t, cpu.UserTime) 183 184 t.Logf("CPU=%v SystemProcessorPerformanceInformation=%v", i, cpu) 185 } 186 } 187 188 func TestNtQueryProcessBasicInformation(t *testing.T) { 189 h, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(syscall.Getpid())) 190 if err != nil { 191 t.Fatal(err) 192 } 193 194 info, err := NtQueryProcessBasicInformation(h) 195 if err != nil { 196 t.Fatal(err) 197 } 198 defer syscall.CloseHandle(h) 199 assert.EqualValues(t, os.Getpid(), info.UniqueProcessID) 200 assert.EqualValues(t, os.Getppid(), info.InheritedFromUniqueProcessID) 201 202 t.Logf("NtQueryProcessBasicInformation: %+v", info) 203 } 204 205 func TestGetTickCount64(t *testing.T) { 206 uptime, err := GetTickCount64() 207 if err != nil { 208 t.Fatal(err) 209 } 210 assert.NotZero(t, uptime) 211 } 212 213 func TestGetUserProcessParams(t *testing.T) { 214 h, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, false, uint32(syscall.Getpid())) 215 if err != nil { 216 t.Fatal(err) 217 } 218 info, err := NtQueryProcessBasicInformation(h) 219 if err != nil { 220 t.Fatal(err) 221 } 222 userProc, err := GetUserProcessParams(h, info) 223 if err != nil { 224 t.Fatal(err) 225 } 226 defer syscall.CloseHandle(h) 227 assert.NoError(t, err) 228 assert.EqualValues(t, os.Getpid(), info.UniqueProcessID) 229 assert.EqualValues(t, os.Getppid(), info.InheritedFromUniqueProcessID) 230 assert.NotEmpty(t, userProc.CommandLine) 231 } 232 233 func TestGetUserProcessParamsInvalidHandle(t *testing.T) { 234 var handle syscall.Handle 235 var info = ProcessBasicInformation{PebBaseAddress: uintptr(0)} 236 userProc, err := GetUserProcessParams(handle, info) 237 assert.EqualValues(t, err.Error(), "The handle is invalid.") 238 assert.Empty(t, userProc) 239 } 240 241 func TestReadProcessUnicodeString(t *testing.T) { 242 h, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, false, uint32(syscall.Getpid())) 243 if err != nil { 244 t.Fatal(err) 245 } 246 defer syscall.CloseHandle(h) 247 info, err := NtQueryProcessBasicInformation(h) 248 if err != nil { 249 t.Fatal(err) 250 } 251 userProc, err := GetUserProcessParams(h, info) 252 if err != nil { 253 t.Fatal(err) 254 } 255 read, err := ReadProcessUnicodeString(h, &userProc.CommandLine) 256 if err != nil { 257 t.Fatal(err) 258 } 259 assert.NoError(t, err) 260 assert.NotEmpty(t, read) 261 } 262 263 const currentProcessHandle = syscall.Handle(^uintptr(0)) 264 265 func TestReadProcessUnicodeStringTerminator(t *testing.T) { 266 data := []byte{'H', 0, 'E', 0, 'L', 0, 'L', 0, 'O', 0, 0, 0} 267 for n := len(data); n >= 0; n-- { 268 us := UnicodeString{ 269 Buffer: uintptr(unsafe.Pointer(&data[0])), 270 Size: uint16(n), 271 } 272 read, err := ReadProcessUnicodeString(currentProcessHandle, &us) 273 if err != nil { 274 t.Fatal(err) 275 } 276 nRead := len(read) 277 // Strings must match 278 assert.True(t, nRead >= n) 279 assert.Equal(t, data[:n], read[:n]) 280 // result is an array of uint16, can't have odd length. 281 assert.True(t, nRead&1 == 0) 282 // Must include a zero terminator at the end. 283 assert.True(t, nRead >= 2) 284 assert.Zero(t, read[nRead-1]) 285 assert.Zero(t, read[nRead-2]) 286 } 287 } 288 289 func TestReadProcessUnicodeStringInvalidHandle(t *testing.T) { 290 var handle syscall.Handle 291 var cmd = UnicodeString{Size: 5, MaximumLength: 400, Buffer: 400} 292 read, err := ReadProcessUnicodeString(handle, &cmd) 293 assert.EqualValues(t, err.Error(), "The handle is invalid.") 294 assert.Empty(t, read) 295 } 296 297 func TestByteSliceToStringSlice(t *testing.T) { 298 cmd := syscall.GetCommandLine() 299 b := make([]byte, unsafe.Sizeof(cmd)) 300 binary.LittleEndian.PutUint16(b, *cmd) 301 hes, err := ByteSliceToStringSlice(b) 302 assert.NoError(t, err) 303 assert.NotEmpty(t, hes) 304 } 305 306 func TestByteSliceToStringSliceEmptyBytes(t *testing.T) { 307 b := make([]byte, 0) 308 cmd, err := ByteSliceToStringSlice(b) 309 assert.NoError(t, err) 310 assert.Empty(t, cmd) 311 } 312 313 func mkUtf16bytes(s string) []byte { 314 n := len(s) 315 b := make([]byte, n*2) 316 for idx, val := range s { 317 *(*uint16)(unsafe.Pointer(&b[idx*2])) = uint16(val) 318 } 319 return b 320 } 321 322 func TestByteSliceToStringSliceNotTerminated(t *testing.T) { 323 b := mkUtf16bytes("Hello World") 324 cmd, err := ByteSliceToStringSlice(b) 325 assert.NoError(t, err) 326 assert.Len(t, cmd, 2) 327 assert.Equal(t, "Hello", cmd[0]) 328 assert.Equal(t, "World", cmd[1]) 329 } 330 331 func TestByteSliceToStringSliceNotOddSize(t *testing.T) { 332 b := mkUtf16bytes("BAD")[:5] 333 cmd, err := ByteSliceToStringSlice(b) 334 assert.NoError(t, err) 335 assert.Len(t, cmd, 1) 336 // Odd character is dropped 337 assert.Equal(t, "BA", cmd[0]) 338 } 339 340 func TestReadProcessMemory(t *testing.T) { 341 h, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, false, uint32(syscall.Getpid())) 342 if err != nil { 343 t.Fatal(err) 344 } 345 info, err := NtQueryProcessBasicInformation(h) 346 if err != nil { 347 t.Fatal(err) 348 } 349 pebSize := 0x20 + 8 350 if unsafe.Sizeof(uintptr(0)) == 4 { 351 pebSize = 0x10 + 8 352 } 353 defer syscall.CloseHandle(h) 354 peb := make([]byte, pebSize) 355 nRead, err := ReadProcessMemory(h, info.PebBaseAddress, peb) 356 assert.NoError(t, err) 357 assert.NotEmpty(t, nRead) 358 assert.EqualValues(t, nRead, uintptr(pebSize)) 359 } 360 361 // A zero-byte read is a no-op, no error is returned. 362 func TestReadProcessMemoryZeroByteRead(t *testing.T) { 363 peb := make([]byte, 0) 364 var h syscall.Handle 365 var address uintptr 366 nRead, err := ReadProcessMemory(h, address, peb) 367 assert.NoError(t, err) 368 assert.Empty(t, nRead) 369 } 370 371 func TestReadProcessMemoryInvalidHandler(t *testing.T) { 372 peb := make([]byte, 10) 373 var h syscall.Handle 374 var address uintptr 375 nRead, err := ReadProcessMemory(h, address, peb) 376 assert.Error(t, err) 377 assert.EqualValues(t, err.Error(), "The handle is invalid.") 378 assert.Empty(t, nRead) 379 } 380 381 func TestGetAccessPaths(t *testing.T) { 382 paths, err := GetAccessPaths() 383 if err != nil { 384 t.Fatal(err) 385 } 386 assert.NotEmpty(t, paths) 387 assert.True(t, len(paths) >= 1) 388 } 389 390 func TestGetVolumes(t *testing.T) { 391 paths, err := GetVolumes() 392 if err != nil { 393 t.Fatal(err) 394 } 395 assert.NotEmpty(t, paths) 396 assert.True(t, len(paths) >= 1) 397 } 398 399 func TestGetVolumePathsForVolume(t *testing.T) { 400 if runtime.GOOS == "windows" { 401 t.Skip("test is not running on latest windows versions. See https://github.com/elastic/gosigar/issues/172") 402 return 403 } 404 volumes, err := GetVolumes() 405 if err != nil { 406 t.Fatal(err) 407 } 408 assert.NotNil(t, volumes) 409 assert.True(t, len(volumes) >= 1) 410 volumePath, err := GetVolumePathsForVolume(volumes[0]) 411 if err != nil { 412 t.Fatal(err) 413 } 414 assert.NotNil(t, volumePath) 415 assert.True(t, len(volumePath) >= 1) 416 }