Skip to content

Commit 8520850

Browse files
authored
Add Windows support for File and Service modules (#683)
1 parent 7e36cff commit 8520850

File tree

2 files changed

+196
-0
lines changed

2 files changed

+196
-0
lines changed

testinfra/modules/file.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ def get_module_class(cls, host):
215215
return BSDFile
216216
if host.system_info.type == "darwin":
217217
return DarwinFile
218+
if host.system_info.type == "windows":
219+
return WindowsFile
218220
raise NotImplementedError
219221

220222

@@ -330,3 +332,173 @@ class NetBSDFile(BSDFile):
330332
@property
331333
def sha256sum(self):
332334
return self.check_output("cksum -a sha256 < %s", self.path)
335+
336+
337+
class WindowsFile(File):
338+
@property
339+
def exists(self):
340+
"""Test if file exists
341+
342+
>>> host.file(r"C:/Users").exists
343+
True
344+
>>> host.file(r"C:/nonexistent").exists
345+
False
346+
"""
347+
348+
return (
349+
self.check_output(r"powershell -command \"Test-Path '%s'\"", self.path)
350+
== "True"
351+
)
352+
353+
@property
354+
def is_file(self):
355+
return (
356+
self.check_output(
357+
r"powershell -command \"(Get-Item '%s') -is [System.IO.FileInfo]\"",
358+
self.path,
359+
)
360+
== "True"
361+
)
362+
363+
@property
364+
def is_directory(self):
365+
return (
366+
self.check_output(
367+
r"powershell -command \"(Get-Item '%s') -is [System.IO.DirectoryInfo]\"",
368+
self.path,
369+
)
370+
== "True"
371+
)
372+
373+
@property
374+
def is_pipe(self):
375+
raise NotImplementedError
376+
377+
@property
378+
def is_socket(self):
379+
raise NotImplementedError
380+
381+
@property
382+
def is_symlink(self):
383+
return (
384+
self.check_output(
385+
r"powershell -command \"(Get-Item -Path '%s').Attributes -band [System.IO.FileAttributes]::ReparsePoint\"",
386+
self.path,
387+
)
388+
== "True"
389+
)
390+
391+
@property
392+
def linked_to(self):
393+
"""Resolve symlink
394+
395+
>>> host.file("C:/Users/lock").linked_to
396+
'C:/Program Files/lock'
397+
"""
398+
return self.check_output(
399+
r"powershell -command \"(Get-Item -Path '%s' -ReadOnly).FullName\"",
400+
self.path,
401+
)
402+
403+
@property
404+
def user(self):
405+
raise NotImplementedError
406+
407+
@property
408+
def uid(self):
409+
raise NotImplementedError
410+
411+
@property
412+
def group(self):
413+
raise NotImplementedError
414+
415+
@property
416+
def gid(self):
417+
raise NotImplementedError
418+
419+
@property
420+
def mode(self):
421+
raise NotImplementedError
422+
423+
def contains(self, pattern):
424+
"""Checks content of file for pattern
425+
426+
This follows the regex syntax.
427+
"""
428+
return (
429+
self.run_test(
430+
r"powershell -command \"Select-String -Path '%s' -Pattern '%s'\"",
431+
self.path,
432+
pattern,
433+
).stdout
434+
!= ""
435+
)
436+
437+
@property
438+
def md5sum(self):
439+
raise NotImplementedError
440+
441+
@property
442+
def sha256sum(self):
443+
raise NotImplementedError
444+
445+
def _get_content(self, decode):
446+
out = self.run_expect([0], r"powershell -command \"cat -- '%s'\"", self.path)
447+
if decode:
448+
return out.stdout
449+
return out.stdout_bytes
450+
451+
@property
452+
def content(self):
453+
"""Return file content as bytes
454+
455+
>>> host.file("C:/Windows/Temp/foo").content
456+
b'caf\\xc3\\xa9'
457+
"""
458+
return self._get_content(False)
459+
460+
@property
461+
def content_string(self):
462+
"""Return file content as string
463+
464+
>>> host.file("C:/Windows/Temp/foo").content_string
465+
'café'
466+
"""
467+
return self._get_content(True)
468+
469+
@property
470+
def mtime(self):
471+
"""Return time of last modification as datetime.datetime object
472+
473+
>>> host.file("C:/Windows/passwd").mtime
474+
datetime.datetime(2015, 3, 15, 20, 25, 40)
475+
"""
476+
date_time_str = self.check_output(
477+
r"powershell -command \"Get-ChildItem -Path '%s' | Select-Object -ExpandProperty LastWriteTime\"",
478+
self.path,
479+
)
480+
return datetime.datetime.strptime(
481+
date_time_str.strip(), "%A, %B %d, %Y %I:%M:%S %p"
482+
)
483+
484+
@property
485+
def size(self):
486+
"""Return size of file in bytes"""
487+
return int(
488+
self.check_output(
489+
r"powershell -command \"Get-Item -Path '%s' | Select-Object -ExpandProperty Length\"",
490+
self.path,
491+
)
492+
)
493+
494+
def listdir(self):
495+
"""Return list of items under the directory
496+
497+
>>> host.file("C:/Windows/Temp").listdir()
498+
['foo_file', 'bar_dir']
499+
"""
500+
out = self.check_output(
501+
r"powershell -command \"Get-ChildItem -Path '%s' | Select-Object -ExpandProperty Name\"",
502+
self.path,
503+
)
504+
return [item.strip() for item in out.strip().split("\n")]

testinfra/modules/service.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ def get_module_class(cls, host):
103103
return OpenBSDService
104104
if host.system_info.type == "netbsd":
105105
return NetBSDService
106+
if host.system_info.type == "windows":
107+
return WindowsService
106108
raise NotImplementedError
107109

108110
def __repr__(self):
@@ -275,3 +277,25 @@ def is_running(self):
275277
@property
276278
def is_enabled(self):
277279
raise NotImplementedError
280+
281+
282+
class WindowsService(Service):
283+
@property
284+
def is_running(self):
285+
return (
286+
self.check_output(
287+
"Get-Service '%s' | Select -ExpandProperty Status",
288+
self.name,
289+
)
290+
== "Running"
291+
)
292+
293+
@property
294+
def is_enabled(self):
295+
return (
296+
self.check_output(
297+
"Get-Service '%s' | Select -ExpandProperty StartType",
298+
self.name,
299+
)
300+
== "Automatic"
301+
)

0 commit comments

Comments
 (0)