11
11
from molecule .config import molecule_drivers
12
12
13
13
14
+ def pytest_addoption (parser ):
15
+ group = parser .getgroup ("molecule" )
16
+ help_msg = (
17
+ "What marker to add to molecule scenarios when driver is "
18
+ "unavailable. (ex: skip, xfail)"
19
+ )
20
+ default = "skip"
21
+ dest = "molecule_unavailable_driver"
22
+
23
+ group .addoption (
24
+ "--molecule-unavailable-driver" ,
25
+ action = "store" ,
26
+ dest = dest ,
27
+ default = default ,
28
+ help = help_msg ,
29
+ )
30
+
31
+ parser .addini (dest , help_msg , default = default )
32
+
33
+
14
34
def pytest_configure (config ):
15
35
36
+ config .option .molecule = {}
16
37
for driver in molecule_drivers ():
17
38
config .addinivalue_line (
18
39
"markers" , "{0}: mark test to run only when {0} is available" .format (driver )
19
40
)
41
+ config .option .molecule [driver ] = {"available" : True }
42
+ # TODO(ssbarnea): extend molecule itself to allow it to report usable drivers
43
+ if driver == "docker" :
44
+ try :
45
+ import docker
46
+
47
+ # validate docker connectivity
48
+ # Default docker value is 60s but we want to fail faster
49
+ # With parallel execution 5s proved to give errors.
50
+ c = docker .from_env (timeout = 10 , version = "auto" )
51
+ if not c .ping ():
52
+ raise Exception ("Failed to ping docker server." )
53
+
54
+ except Exception as e :
55
+ msg = "Molecule {} driver is not available due to: {}." .format (
56
+ driver , e
57
+ )
58
+ if config .option .molecule_unavailable_driver :
59
+ msg += " We will tag scenarios using it with '{}' marker." .format (
60
+ config .option .molecule_unavailable_driver
61
+ )
62
+ logging .getLogger ().warning (msg )
63
+ config .option .molecule [driver ]["available" ] = False
64
+
65
+ if driver == "delegated" :
66
+ # To protect ourselves from case where a molecule scenario using
67
+ # `delegated` is accidentally altering the localhost on a developer
68
+ # machine, we verify run delegated tests only when ansible `zuul`
69
+ # or `use_for_testing` vars are defined.
70
+ cmd = [
71
+ "ansible" ,
72
+ "localhost" ,
73
+ "-e" ,
74
+ "ansible_connection=local" "-o" ,
75
+ "-m" ,
76
+ "shell" ,
77
+ "-a" ,
78
+ "exit {% if zuul is defined or use_for_testing is defined %}0{% else %}1{% endif %}" ,
79
+ ]
80
+ try :
81
+ p = subprocess .Popen (
82
+ cmd ,
83
+ stdout = subprocess .DEVNULL ,
84
+ stderr = subprocess .DEVNULL ,
85
+ universal_newlines = True ,
86
+ )
87
+ p .wait ()
88
+ if p .returncode != 0 :
89
+ raise Exception (
90
+ "Error code %s returned by: %s" % (p .returncode , " " .join (cmd ))
91
+ )
92
+ except Exception :
93
+ msg = "Molecule {} driver was not enabled because missing zuul.build variable in current inventory." .format (
94
+ driver
95
+ )
96
+ if config .option .molecule_unavailable_driver :
97
+ msg += " We will tag scenarios using it with '{}' marker." .format (
98
+ config .option .molecule_unavailable_driver
99
+ )
100
+ logging .getLogger ().warning (msg )
101
+ config .option .molecule [driver ]["available" ] = False
102
+
20
103
config .addinivalue_line ("markers" , "molecule: mark used by all molecule scenarios" )
21
104
22
105
# validate selinux availability
@@ -65,6 +148,11 @@ def __init__(self, name, parent):
65
148
)
66
149
self .add_marker (p )
67
150
self .add_marker ("molecule" )
151
+ if (
152
+ self .config .option .molecule_unavailable_driver
153
+ and not self .config .option .molecule [self .molecule_driver ]["available" ]
154
+ ):
155
+ self .add_marker (self .config .option .molecule_unavailable_driver )
68
156
69
157
def runtest (self ):
70
158
folders = self .fspath .dirname .split (os .sep )
@@ -80,7 +168,6 @@ def runtest(self):
80
168
cmd .extend (shlex .split (opts ))
81
169
82
170
print ("running: %s (from %s)" % (" " .join (quote (arg ) for arg in cmd ), cwd ))
83
-
84
171
try :
85
172
# Workaround for STDOUT/STDERR line ordering issue:
86
173
# https://github.com/pytest-dev/pytest/issues/5449
0 commit comments