These tests (will) test more than just image-info: they'll take a blueprint, verify that `osbuild-pipeline` generates the correct pipeline, run osbuild with that pipeline and verify that the resulting image has the expected image-info output. This change only includes the latter half (i.e., only moves the already existing tests). Also drop python's unittest. It was hard to control output (important for quickly spotting failures and to make travis happy). This introduces test/run, which runs all test cases in test/cases or the ones given on the command line. When a failure occurs, it prints a diff of the actual and the expected image info.
89 lines
2.4 KiB
Python
Executable file
89 lines
2.4 KiB
Python
Executable file
#!/usr/bin/python3
|
|
|
|
import contextlib
|
|
import glob
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
import urllib.request
|
|
|
|
|
|
TEST_DIR = os.path.dirname(__file__)
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def osbuild_test_store():
|
|
store = os.getenv("OSBUILD_TEST_STORE")
|
|
if store:
|
|
yield store
|
|
else:
|
|
with tempfile.TemporaryDirectory(dir="/var/tmp", prefix="osbuild-composer-test-") as store:
|
|
yield store
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def temporary_json_file(obj):
|
|
f = tempfile.NamedTemporaryFile("w", delete=False)
|
|
json.dump(obj, f, indent=2)
|
|
f.close()
|
|
try:
|
|
yield f.name
|
|
finally:
|
|
os.unlink(f.name)
|
|
|
|
|
|
def run_osbuild(pipeline, store):
|
|
osbuild_cmd = ["python3", "-m", "osbuild", "--json", "--libdir", ".", "--store", store, "-"]
|
|
|
|
build_pipeline = os.getenv("OSBUILD_TEST_BUILD_PIPELINE", None)
|
|
if build_pipeline:
|
|
osbuild_cmd.append("--build-pipeline")
|
|
osbuild_cmd.append(os.path.abspath(build_pipeline))
|
|
|
|
try:
|
|
result = json.loads(subprocess.check_output(osbuild_cmd, cwd="./osbuild", encoding="utf-8", input=json.dumps(pipeline)))
|
|
except subprocess.CalledProcessError as err:
|
|
print(err.output)
|
|
|
|
return result["tree_id"], result["output_id"]
|
|
|
|
|
|
def run_test(case, store):
|
|
if "pipeline" in case:
|
|
_, output_id = run_osbuild(case["pipeline"], store)
|
|
filename = os.path.join(store, "refs", output_id, case["compose"]["filename"])
|
|
else:
|
|
filename, _ = urllib.request.urlretrieve(case["url"])
|
|
|
|
info = json.loads(subprocess.check_output(["tools/image-info", filename]))
|
|
if info != case["expected"]:
|
|
with temporary_json_file(case["expected"]) as a, temporary_json_file(info) as b:
|
|
subprocess.run(["diff", "--unified", "--color", "--label", "expected", a, "--label", "got", b], check=False)
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def main(args):
|
|
failed = False
|
|
with osbuild_test_store() as store:
|
|
for filename in args or glob.glob(f"{TEST_DIR}/cases/*.json"):
|
|
name = os.path.basename(filename)[:-5]
|
|
with open(filename) as f:
|
|
case = json.load(f)
|
|
|
|
print(f"{name}")
|
|
if not run_test(case, store):
|
|
print(f"FAIL")
|
|
print()
|
|
failed = True
|
|
|
|
return 1 if failed else 0
|
|
|
|
r = main(sys.argv[1:])
|
|
if r:
|
|
sys.exit(r)
|