Skip to content

Commit f1e830c

Browse files
authored
Merge pull request #185 from lachmanfrantisek/better-tests
Run tests for all target types
2 parents af6cb90 + 642ba40 commit f1e830c

10 files changed

Lines changed: 217 additions & 104 deletions

File tree

Dockerfile.tests

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ FROM registry.fedoraproject.org/fedora:29
33
ENV PYTHONDONTWRITEBYTECODE=yes-please
44

55
# atomic in F28 can't mount: can't find the image
6-
RUN dnf install -y make python3-pytest python3-pyxattr \
6+
RUN dnf install -y make python3-pytest python3-pyxattr python3-pytest-cov \
77
skopeo \
88
https://kojipkgs.fedoraproject.org/packages/podman/0.9.1/3.gitaba58d1.fc29/x86_64/podman-0.9.1-3.gitaba58d1.fc29.x86_64.rpm \
99
https://kojipkgs.fedoraproject.org/packages/containernetworking-plugins/0.7.3/2.fc29/x86_64/containernetworking-plugins-0.7.3-2.fc29.x86_64.rpm \

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ test-in-container-now:
1515
docker run --rm --privileged --security-opt label=disable --cap-add SYS_ADMIN -ti -v $(CURDIR):/src $(TEST_IMAGE_NAME) make exec-test TEST_TARGET="$(TEST_TARGET)"
1616

1717
test-in-ci: setup-ci
18-
PYTHONPATH=$(CURDIR) py.test $(TEST_TARGET)
18+
PYTHONPATH=$(CURDIR) py.test --cov=colin $(TEST_TARGET)
1919

2020
exec-test:
21-
PYTHONPATH=$(CURDIR) py.test-3 $(TEST_TARGET)
21+
PYTHONPATH=$(CURDIR) py.test-3 --cov=colin $(TEST_TARGET)
2222

2323
setup-ci:
2424
./setup-ci.sh

colin/core/target.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class Target(object):
7070

7171
def __init__(self):
7272
self._labels = None
73+
self.target_name = None
7374

7475
@property
7576
def labels(self):
@@ -115,9 +116,11 @@ def get_instance(target_type, **kwargs):
115116

116117

117118
class DockerfileTarget(Target):
119+
target_type = "dockerfile"
118120

119121
def __init__(self, target, **_):
120122
super().__init__()
123+
self.target_name = target
121124
logger.debug("Target is a dockerfile.")
122125
if isinstance(target, io.IOBase):
123126
logger.debug("Target is a dockerfile loaded from the file-like object.")
@@ -224,13 +227,15 @@ class ImageTarget(AbstractImageTarget):
224227
"""
225228
Represents the podman image as a target.
226229
"""
230+
target_type = "image"
227231

228232
def __init__(self, target, pull, insecure=False, **_):
229233
super().__init__()
230234
logger.debug("Target is an image.")
231235
self.pull = pull
232236
self.insecure = insecure
233-
self.image_name = ImageName.parse(target)
237+
self.image_name_obj = ImageName.parse(target)
238+
self.target_name = self.image_name_obj.name
234239

235240
self._config_metadata = None
236241
self._mount_point = None
@@ -242,7 +247,7 @@ def __init__(self, target, pull, insecure=False, **_):
242247
@property
243248
def config_metadata(self):
244249
if not self._config_metadata:
245-
cmd = ["podman", "inspect", self.image_name.name]
250+
cmd = ["podman", "inspect", self.target_name]
246251
loaded_config = json.loads(subprocess.check_output(cmd))
247252
if loaded_config and isinstance(loaded_config, list):
248253
self._config_metadata = loaded_config[0]
@@ -260,15 +265,15 @@ def labels(self):
260265
def mount_point(self):
261266
""" podman mount -- real filesystem """
262267
if self._mount_point is None:
263-
cmd_create = ["podman", "create", self.image_name.name, "some-cmd"]
268+
cmd_create = ["podman", "create", self.target_name, "some-cmd"]
264269
self._mounted_container_id = subprocess.check_output(cmd_create).decode().rstrip()
265270
cmd_mount = ["podman", "mount", self._mounted_container_id]
266271
self._mount_point = subprocess.check_output(cmd_mount).decode().rstrip()
267272
return self._mount_point
268273

269274
def _try_image(self):
270275
logger.debug("Trying to find an image.")
271-
cmd = ["podman", "images", "--quiet", self.image_name.name]
276+
cmd = ["podman", "images", "--quiet", self.target_name]
272277
result = subprocess.run(cmd,
273278
stdout=subprocess.PIPE,
274279
stderr=subprocess.PIPE)
@@ -279,7 +284,7 @@ def _try_image(self):
279284
if "unable to find" in result.stderr.decode():
280285
if self.pull:
281286
logger.debug("Pulling an image.")
282-
cmd_pull = ["podman", "pull", "--quiet", self.image_name.name]
287+
cmd_pull = ["podman", "pull", "--quiet", self.target_name]
283288
result_pull = subprocess.run(cmd_pull,
284289
stdout=subprocess.PIPE,
285290
stderr=subprocess.PIPE)
@@ -288,10 +293,10 @@ def _try_image(self):
288293
logger.debug("Image pulled with id: '{}'.".format(self.image_id))
289294
else:
290295
raise ColinException(
291-
"Cannot pull an image: '{}'.".format(self.image_name.name))
296+
"Cannot pull an image: '{}'.".format(self.target_name))
292297

293298
else:
294-
raise ColinException("Image '{}' not found.".format(self.image_name.name))
299+
raise ColinException("Image '{}' not found.".format(self.target_name))
295300
else:
296301
raise ColinException("Podman error: {}".format(result.stderr))
297302

@@ -313,17 +318,18 @@ class OstreeTarget(AbstractImageTarget):
313318
"""
314319
Represents the ostree repository as an image target.
315320
"""
321+
target_type = "ostree"
316322

317323
def __init__(self, target, **_):
318324
super().__init__()
319325
logger.debug("Target is an ostree repository.")
320326

321-
self.image_name = target
322-
if self.image_name.startswith("ostree:"):
323-
self.image_name = self.image_name[7:]
327+
self.target_name = target
328+
if self.target_name.startswith("ostree:"):
329+
self.target_name = self.target_name[7:]
324330

325331
try:
326-
self.ref_image_name, self._ostree_path = self.image_name.split("@", 1)
332+
self.ref_image_name, self._ostree_path = self.target_name.split("@", 1)
327333
except ValueError:
328334
raise RuntimeError("Invalid ostree target: should be 'image@path'.")
329335

setup-ci.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ echo "yum -y install make gcc python36 python36-devel python36-setuptools python
1010
yum -y install make gcc python36 python36-devel python36-setuptools python36-pip python36-cffi python36-pycparser
1111

1212
echo "pip3 install pytest xattr"
13-
pip3.6 install pytest xattr
13+
pip3.6 install pytest pytest-cov xattr
1414

1515
echo "yum copr enable -y baude/Upstream_CRIO_Family"
1616
yum copr enable -y baude/Upstream_CRIO_Family

tests/integration/conftest.py

Lines changed: 138 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import logging
22
import os
3+
import shutil
34
import subprocess
5+
import tempfile
46

57
import pytest
68

79
from colin.core.colin import _set_logging
10+
from colin.core.target import ImageTarget, OstreeTarget, DockerfileTarget
811

912
_set_logging(level=logging.DEBUG)
1013

1114
BASH_IMAGE = "colin-test-bash"
1215
LS_IMAGE = "colin-test-ls"
13-
BUSYBOX_IMAGE = "docker.io/library/busybox"
14-
LABELS_IMAGE = "colin-labels:latest"
16+
BUSYBOX_IMAGE = "busybox"
17+
LABELS_IMAGE = "colin-labels"
1518
IMAGES = {
1619
BASH_IMAGE: {
1720
"dockerfile_path": "Dockerfile-bash"
@@ -25,29 +28,140 @@
2528
}
2629

2730

28-
def build_images():
29-
""" build container images we need for testing """
30-
this_dir = os.path.abspath(os.path.dirname(__file__))
31-
data_dir = os.path.join(this_dir, os.path.pardir, "data")
32-
for image_name, image_data in IMAGES.items():
33-
cmd_create = ["podman", "build", "-t", image_name, "-f",
34-
image_data["dockerfile_path"], data_dir]
31+
def build_image_if_not_exists(image_name):
32+
try:
33+
subprocess.check_call(["podman", "image", "inspect", image_name],
34+
stdout=subprocess.PIPE)
35+
except subprocess.CalledProcessError:
36+
this_dir = os.path.abspath(os.path.dirname(__file__))
37+
data_dir = os.path.join(this_dir, os.path.pardir, "data")
38+
39+
dockerfile_path = IMAGES[image_name]["dockerfile_path"]
40+
cmd_create = ["podman", "build", "-t", image_name, "-f", dockerfile_path, data_dir]
3541
output = subprocess.check_output(cmd_create)
3642
assert output
3743

3844

39-
@pytest.fixture(autouse=True, scope='session')
40-
def setup_test_session():
41-
""" set up environment before testing """
42-
for image_name in IMAGES:
43-
try:
44-
subprocess.check_call(["podman", "image", "inspect", image_name],
45-
stdout=subprocess.PIPE)
46-
except subprocess.CalledProcessError:
47-
break
48-
# executed if break was not reached
49-
else:
50-
# all images were found, we're good
51-
return
52-
# the loop ended with break, create images
53-
build_images()
45+
def pull_image_if_not_exists(image_name):
46+
try:
47+
subprocess.check_call(["podman", "image", "inspect", image_name],
48+
stdout=subprocess.PIPE)
49+
except subprocess.CalledProcessError:
50+
subprocess.check_call(["podman", "pull", image_name],
51+
stdout=subprocess.PIPE)
52+
53+
54+
def convert_image_to_ostree(image_name):
55+
# /tmp is tmpfs and ostree can't do its magic there
56+
tmpdir_path = tempfile.mkdtemp(prefix="pytest-", dir="/var/tmp")
57+
ostree_path = os.path.join(tmpdir_path, "os3")
58+
os.makedirs(ostree_path)
59+
skopeo_target = get_skopeo_path(image_name=image_name, ostree_path=ostree_path)
60+
61+
subprocess.check_call(["ostree", "init", "--mode", "bare-user-only",
62+
"--repo", ostree_path])
63+
64+
cmd = ["podman", "push", image_name, skopeo_target]
65+
subprocess.check_call(cmd)
66+
return ostree_path
67+
68+
69+
def get_target(name, type):
70+
if type == "image":
71+
72+
target = ImageTarget(target=name,
73+
pull=False)
74+
yield target
75+
target.clean_up()
76+
77+
elif type == "ostree":
78+
79+
ostree_path = convert_image_to_ostree(name)
80+
skopeo_target = get_skopeo_path(image_name=name,
81+
ostree_path=ostree_path)
82+
83+
ostree_target = OstreeTarget(target=skopeo_target)
84+
yield ostree_target
85+
ostree_target.clean_up()
86+
shutil.rmtree(ostree_path)
87+
88+
elif type == "dockerfile":
89+
90+
this_dir = os.path.abspath(os.path.dirname(__file__))
91+
data_dir = os.path.join(this_dir, os.path.pardir, "data")
92+
dockerfile_path = os.path.join(data_dir, IMAGES[name]["dockerfile_path"])
93+
94+
yield DockerfileTarget(target=dockerfile_path)
95+
96+
97+
def get_skopeo_path(image_name, ostree_path):
98+
return "ostree:%s@%s" % (image_name, ostree_path)
99+
100+
101+
@pytest.fixture(scope="session")
102+
def label_image():
103+
build_image_if_not_exists(LABELS_IMAGE)
104+
105+
106+
@pytest.fixture(scope="session",
107+
params=["image", "ostree", "dockerfile"])
108+
def target_label(request, label_image):
109+
for t in get_target(name=LABELS_IMAGE,
110+
type=request.param):
111+
yield t
112+
113+
114+
@pytest.fixture(scope="session",
115+
params=["image", "ostree", "dockerfile"])
116+
def target_label_image_and_dockerfile(request, label_image):
117+
for t in get_target(name=LABELS_IMAGE,
118+
type=request.param):
119+
yield t
120+
121+
122+
@pytest.fixture(scope="session")
123+
def target_bash_image():
124+
build_image_if_not_exists(BASH_IMAGE)
125+
126+
127+
@pytest.fixture(scope="session",
128+
params=["image", "ostree"])
129+
def target_bash(request, target_bash_image):
130+
for t in get_target(name=BASH_IMAGE,
131+
type=request.param):
132+
yield t
133+
134+
135+
@pytest.fixture(scope="session")
136+
def target_ls_image():
137+
build_image_if_not_exists(LS_IMAGE)
138+
139+
140+
@pytest.fixture(scope="session",
141+
params=["image", "ostree"])
142+
def target_ls(request, target_ls_image):
143+
for t in get_target(name=LS_IMAGE,
144+
type=request.param):
145+
yield t
146+
147+
148+
@pytest.fixture(scope="session",
149+
params=[LS_IMAGE, BASH_IMAGE])
150+
def target_help_file(request, target_ls, target_bash):
151+
if request.param == LS_IMAGE:
152+
return target_ls, False
153+
if request.param == BASH_IMAGE:
154+
return target_bash, True
155+
156+
157+
@pytest.fixture(scope="session")
158+
def target_busybox_image():
159+
pull_image_if_not_exists(image_name=BUSYBOX_IMAGE)
160+
161+
162+
@pytest.fixture(scope="session",
163+
params=["image", "ostree"])
164+
def target_busybox(request, target_busybox_image):
165+
for t in get_target(name=BUSYBOX_IMAGE,
166+
type=request.param):
167+
yield t

tests/integration/test_cont.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,13 @@
33
"""
44
import pytest
55

6-
from colin.core.target import ImageTarget
7-
from tests.integration.conftest import BUSYBOX_IMAGE, LABELS_IMAGE
86

9-
10-
def test_file_is_present():
11-
image = ImageTarget(target=BUSYBOX_IMAGE, pull=True)
12-
assert image.file_is_present("/etc/passwd")
13-
assert not image.file_is_present("/oglogoblogologlo")
7+
def test_file_is_present(target_busybox):
8+
assert target_busybox.file_is_present("/etc/passwd")
9+
assert not target_busybox.file_is_present("/oglogoblogologlo")
1410
with pytest.raises(IOError):
15-
image.file_is_present("/etc")
11+
target_busybox.file_is_present("/etc")
1612

1713

18-
def test_labels_are_present():
19-
image = ImageTarget(target=LABELS_IMAGE, pull=False)
20-
assert isinstance(image.labels, dict)
14+
def test_labels_are_present(target_label):
15+
assert isinstance(target_label.labels, dict)

tests/integration/test_fs_checks.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@
1313
# You should have received a copy of the GNU General Public License
1414
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
#
16-
import colin
1716
import pytest
1817

19-
from tests.integration.conftest import BASH_IMAGE, LS_IMAGE
18+
import colin
2019

2120

2221
@pytest.fixture()
@@ -35,13 +34,22 @@ def ruleset():
3534
}
3635

3736

38-
@pytest.mark.parametrize("image_name,should_pass", [
39-
(LS_IMAGE, False),
40-
(BASH_IMAGE, True),
41-
])
42-
def test_help_file_or_readme(ruleset, image_name, should_pass):
37+
def test_help_file_or_readme_bash(ruleset, target_bash):
38+
help_file_or_readme_test(ruleset=ruleset,
39+
image=target_bash,
40+
should_pass=True)
41+
42+
43+
def test_help_file_or_readme_ls(ruleset, target_ls):
44+
help_file_or_readme_test(ruleset=ruleset,
45+
image=target_ls,
46+
should_pass=False)
47+
48+
49+
def help_file_or_readme_test(ruleset, image, should_pass):
4350
""" verify that help_file_or_readme check works well """
44-
results = colin.run(image_name, "image", ruleset=ruleset, logging_level=10, pull=False)
51+
results = colin.run(target=image.target_name,
52+
target_type=image.target_type,
53+
ruleset=ruleset, logging_level=10, pull=False)
4554
assert results.ok
4655
assert results.fail is not should_pass
47-

0 commit comments

Comments
 (0)