Skip to content

Commit

Permalink
Backport more meaningful tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lkubb committed Dec 11, 2022
1 parent 04ffddb commit 8d70e42
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 94 deletions.
150 changes: 150 additions & 0 deletions tests/pytests/functional/states/test_gpg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import shutil
import subprocess

import psutil
import pytest

try:
import gnupg as gnupglib

HAS_GNUPG = True
except ImportError:
HAS_GNUPG = False


pytestmark = [
pytest.mark.skipif(HAS_GNUPG is False, reason="Needs python-gnupg library"),
pytest.mark.skip_if_binaries_missing("gpg", reason="Needs gpg binary"),
]


@pytest.fixture
def gpghome(tmp_path):
root = tmp_path / "gpghome"
root.mkdir(mode=0o0700)
try:
yield root
finally:
# Make sure we don't leave any gpg-agents running behind
gpg_connect_agent = shutil.which("gpg-connect-agent")
if gpg_connect_agent:
gnupghome = root / ".gnupg"
if not gnupghome.is_dir():
gnupghome = root
try:
subprocess.run(
[gpg_connect_agent, "killagent", "/bye"],
env={"GNUPGHOME": str(gnupghome)},
shell=False,
check=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
except subprocess.CalledProcessError:
# This is likely CentOS 7 or Amazon Linux 2
pass

# If the above errored or was not enough, as a last resort, let's check
# the running processes.
for proc in psutil.process_iter():
try:
if "gpg-agent" in proc.name():
for arg in proc.cmdline():
if str(root) in arg:
proc.terminate()
except Exception: # pylint: disable=broad-except
pass


@pytest.fixture
def gpg(loaders, states, gpghome):
try:
yield states.gpg
finally:
pass


@pytest.fixture
def key_a_fp():
return "EF03765F59EE904930C8A781553A82A058C0C795"


@pytest.fixture
def key_a_pub():
return """\
-----BEGIN PGP PUBLIC KEY BLOCK-----
mI0EY4fxHQEEAJvXEaaw+o/yZCwMOJbt5FQHbVMMDX/0YI8UdzsE5YCC4iKnoC3x
FwFdkevKj3qp+45iBGLLnalfXIcVGXJGACB+tPHgsfHaXSDQPSfmX6jbZ6pHosSm
v1tTixY+NTJzGL7hDLz2sAXTbYmTbXeE9ifWWk6NcIwZivUbhNRBM+KxABEBAAG0
LUtleSBBIChHZW5lcmF0ZWQgYnkgU2FsdFN0YWNrKSA8a2V5YUBleGFtcGxlPojR
BBMBCAA7FiEE7wN2X1nukEkwyKeBVTqCoFjAx5UFAmOH8R0CGy8FCwkIBwICIgIG
FQoJCAsCBBYCAwECHgcCF4AACgkQVTqCoFjAx5XURAQAguOwI+49lG0Kby+Bsyv3
of3GgxvhS1Qa7+ysj088az5GVt0pqVe3SbRVvn/jyC6yZvWuv94KdL3R7hCeEz2/
JakCRJ4wxEsdeASE8t9H/oTqD0I5asMa9EMvn5ICEGeLsTeQb7OYYihTQj7HJLG6
pDEmK8EhJDvV/9o0lnhm/9w=
=Wc0O
-----END PGP PUBLIC KEY BLOCK-----"""


@pytest.fixture
def gnupg(gpghome):
return gnupglib.GPG(gnupghome=str(gpghome))


@pytest.fixture
def gnupg_keyring(gpghome, keyring):
return gnupglib.GPG(gnupghome=str(gpghome), keyring=keyring)


@pytest.fixture(params=["a"])
def pubkeys_present(gnupg, request):
pubkeys = [request.getfixturevalue(f"key_{x}_pub") for x in request.param]
fingerprints = [request.getfixturevalue(f"key_{x}_fp") for x in request.param]
gnupg.import_keys("\n".join(pubkeys))
present_keys = gnupg.list_keys()
for fp in fingerprints:
assert any(x["fingerprint"] == fp for x in present_keys)
yield
# cleanup is taken care of by gpghome and tmp_path


@pytest.mark.usefixtures("pubkeys_present")
def test_gpg_present_no_changes(gpghome, gpg, gnupg, key_a_fp):
assert gnupg.list_keys(keys=key_a_fp)
ret = gpg.present(
key_a_fp[-16:], trust="unknown", gnupghome=str(gpghome), keyserver="nonexistent"
)
assert ret.result
assert not ret.changes


@pytest.mark.skip_unless_on_linux(
reason="Complains about deleting private keys first when they are absent"
)
@pytest.mark.usefixtures("pubkeys_present")
def test_gpg_absent(gpghome, gpg, gnupg, key_a_fp):
assert gnupg.list_keys(keys=key_a_fp)
ret = gpg.absent(key_a_fp[-16:], gnupghome=str(gpghome))
assert ret.result
assert ret.changes
assert "deleted" in ret.changes
assert ret.changes["deleted"]


def test_gpg_absent_no_changes(gpghome, gpg, gnupg, key_a_fp):
assert not gnupg.list_keys(keys=key_a_fp)
ret = gpg.absent(key_a_fp[-16:], gnupghome=str(gpghome))
assert ret.result
assert not ret.changes


@pytest.mark.usefixtures("pubkeys_present")
def test_gpg_absent_test_mode_no_changes(gpghome, gpg, gnupg, key_a_fp):
assert gnupg.list_keys(keys=key_a_fp)
ret = gpg.absent(key_a_fp[-16:], gnupghome=str(gpghome), test=True)
assert ret.result is None
assert ret.changes
assert "deleted" in ret.changes
assert ret.changes["deleted"]
assert gnupg.list_keys(keys=key_a_fp)
12 changes: 0 additions & 12 deletions tests/pytests/unit/modules/test_gpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -1058,15 +1058,3 @@ def test_gpg_receive_keys_no_user_id():
res = gpg.receive_keys(keys="abc", user="abc")
assert res["res"] is False
assert "no user ID" in res["message"][0]


def test_gpg_delete_key_honors_gnupghome():
with patch("salt.modules.gpg._create_gpg") as create:
with patch("salt.modules.gpg.get_key") as get_key:
gnupghome = "/pls_respect_me"
get_key.return_value = None
gpg.delete_key("foo", gnupghome=gnupghome)
create.assert_called_with(None, gnupghome)
get_key.assert_called_with(
keyid="foo", fingerprint=None, user=None, gnupghome=gnupghome
)
89 changes: 7 additions & 82 deletions tests/pytests/unit/states/test_gpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,25 +92,6 @@ def gpg_receive(request):
yield recv


@pytest.fixture()
def gpg_delete(request):
delete = Mock(spec="salt.modules.gpg.delete_key")
delete.return_value = getattr(
request, "param", {"res": True, "message": "Public key for A deleted"}
)
with patch.dict(gpg.__salt__, {"gpg.delete_key": delete}):
yield delete


@pytest.mark.usefixtures("gpg_list_keys")
def test_gpg_present_no_changes(gpg_receive, gpg_trust):
ret = gpg.present("A")
assert ret["result"]
assert not ret["changes"]
gpg_receive.assert_not_called()
gpg_trust.assert_not_called()


@pytest.mark.usefixtures("gpg_list_keys")
@pytest.mark.parametrize(
"gpg_trust,expected",
Expand All @@ -122,8 +103,8 @@ def test_gpg_present_no_changes(gpg_receive, gpg_trust):
)
def test_gpg_present_trust_change(gpg_receive, gpg_trust, expected):
ret = gpg.present("A", trust="marginally")
assert ret["result"] == expected
assert bool(ret["changes"]) == expected
assert ret["result"] is expected
assert bool(ret["changes"]) is expected
gpg_trust.assert_called_once()
gpg_receive.assert_not_called()

Expand All @@ -147,8 +128,8 @@ def test_gpg_present_trust_change(gpg_receive, gpg_trust, expected):
)
def test_gpg_present_new_key(gpg_receive, gpg_trust, expected):
ret = gpg.present("new")
assert ret["result"] == expected
assert bool(ret["changes"]) == expected
assert ret["result"] is expected
assert bool(ret["changes"]) is expected
gpg_receive.assert_called_once()
gpg_trust.assert_not_called()

Expand All @@ -165,9 +146,9 @@ def test_gpg_present_new_key(gpg_receive, gpg_trust, expected):
@pytest.mark.usefixtures("gpg_list_keys")
def test_gpg_present_new_key_and_trust(gpg_receive, gpg_trust, expected):
ret = gpg.present("new", trust="marginally")
assert ret["result"] == expected
assert ret["result"] is expected
# the key is always marked as added
assert bool(ret["changes"])
assert ret["changes"]
gpg_receive.assert_called_once()
gpg_trust.assert_called_once()

Expand All @@ -180,60 +161,4 @@ def test_gpg_present_test_mode_no_changes(gpg_receive, gpg_trust, key, trust):
gpg_receive.assert_not_called()
gpg_trust.assert_not_called()
assert ret["result"] is None
assert bool(ret["changes"])


@pytest.mark.usefixtures("gpg_list_keys")
def test_gpg_absent_no_changes(gpg_delete):
ret = gpg.absent("nonexistent")
assert ret["result"]
assert not ret["changes"]
gpg_delete.assert_not_called()


@pytest.mark.usefixtures("gpg_list_keys")
@pytest.mark.parametrize(
"gpg_delete,expected",
[
({"res": True, "message": "Public key for A deleted"}, True),
(
{
"res": False,
"message": "Secret key exists, delete first or pass delete_secret=True.",
},
False,
),
],
indirect=["gpg_delete"],
)
@pytest.mark.usefixtures("gpg_list_keys")
def test_gpg_absent_delete_key(gpg_delete, expected):
ret = gpg.absent("A")
assert ret["result"] == expected
assert bool(ret["changes"]) == expected
gpg_delete.assert_called_once()


@pytest.mark.usefixtures("gpg_list_keys")
def test_gpg_absent_test_mode_no_changes(gpg_delete):
with patch.dict(gpg.__opts__, {"test": True}):
ret = gpg.absent("A")
gpg_delete.assert_not_called()
assert ret["result"] is None
assert bool(ret["changes"])


def test_gpg_absent_list_keys_with_gnupghome_and_user(gpg_list_keys):
gnupghome = "/pls_respect_me"
user = "imthereaswell"
gpg.absent("nonexistent", gnupghome=gnupghome, user=user)
gpg_list_keys.assert_called_with(gnupghome=gnupghome, user=user)


@pytest.mark.usefixtures("gpg_list_keys")
def test_gpg_absent_delete_key_called_with_correct_kwargs(gpg_delete):
key = "A"
user = "hellothere"
gnupghome = "/pls_sir"
gpg.absent(key, user=user, gnupghome=gnupghome)
gpg_delete.assert_called_with(keyid=key, gnupghome=gnupghome, user=user)
assert ret["changes"]

0 comments on commit 8d70e42

Please sign in to comment.