1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
from unittest import mock
import pytest
from cloudinit import subp
@pytest.yield_fixture(autouse=True)
def disable_subp_usage(request):
"""
Across all (pytest) tests, ensure that subp.subp is not invoked.
Note that this can only catch invocations where the util module is imported
and ``subp.subp(...)`` is called. ``from cloudinit.subp mport subp``
imports happen before the patching here (or the CiTestCase monkey-patching)
happens, so are left untouched.
To allow a particular test method or class to use subp.subp you can set the
parameter passed to this fixture to False using pytest.mark.parametrize::
@pytest.mark.parametrize("disable_subp_usage", [False], indirect=True)
def test_whoami(self):
subp.subp(["whoami"])
To instead allow subp.subp usage for a specific command, you can set the
parameter passed to this fixture to that command:
@pytest.mark.parametrize("disable_subp_usage", ["bash"], indirect=True)
def test_bash(self):
subp.subp(["bash"])
To specify multiple commands, set the parameter to a list (note the
double-layered list: we specify a single parameter that is itself a list):
@pytest.mark.parametrize(
"disable_subp_usage", ["bash", "whoami"], indirect=True)
def test_several_things(self):
subp.subp(["bash"])
subp.subp(["whoami"])
This fixture (roughly) mirrors the functionality of
CiTestCase.allowed_subp. N.B. While autouse fixtures do affect non-pytest
tests, CiTestCase's allowed_subp does take precedence (and we have
TestDisableSubpUsageInTestSubclass to confirm that).
"""
should_disable = getattr(request, "param", True)
if should_disable:
if not isinstance(should_disable, (list, str)):
def side_effect(args, *other_args, **kwargs):
raise AssertionError("Unexpectedly used subp.subp")
else:
# Look this up before our patch is in place, so we have access to
# the real implementation in side_effect
real_subp = subp.subp
if isinstance(should_disable, str):
should_disable = [should_disable]
def side_effect(args, *other_args, **kwargs):
cmd = args[0]
if cmd not in should_disable:
raise AssertionError(
"Unexpectedly used subp.subp to call {} (allowed:"
" {})".format(cmd, ",".join(should_disable))
)
return real_subp(args, *other_args, **kwargs)
with mock.patch('cloudinit.subp.subp', autospec=True) as m_subp:
m_subp.side_effect = side_effect
yield
else:
yield
|