|
Packit |
a20ca0 |
#
|
|
Packit |
a20ca0 |
# Basic tests for a collection of osbuild modules.
|
|
Packit |
a20ca0 |
#
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
import json
|
|
Packit |
a20ca0 |
import os
|
|
Packit |
a20ca0 |
import unittest
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
import osbuild
|
|
Packit |
a20ca0 |
import osbuild.meta
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
class TestDescriptions(unittest.TestCase):
|
|
Packit |
a20ca0 |
def test_canonical(self):
|
|
Packit |
a20ca0 |
"""Degenerate case. Make sure we always return the same canonical
|
|
Packit |
a20ca0 |
description when passing empty or null values."""
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
cases = [
|
|
Packit |
a20ca0 |
{},
|
|
Packit |
a20ca0 |
{"assembler": None},
|
|
Packit |
a20ca0 |
{"stages": []},
|
|
Packit |
a20ca0 |
{"build": {}},
|
|
Packit |
a20ca0 |
{"build": None}
|
|
Packit |
a20ca0 |
]
|
|
Packit |
a20ca0 |
for pipeline in cases:
|
|
Packit |
a20ca0 |
with self.subTest(pipeline):
|
|
Packit |
a20ca0 |
self.assertEqual(osbuild.load(pipeline, {}).description(), {})
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
def test_stage(self):
|
|
Packit |
a20ca0 |
name = "org.osbuild.test"
|
|
Packit |
a20ca0 |
options = {"one": 1}
|
|
Packit |
a20ca0 |
cases = [
|
|
Packit |
a20ca0 |
(osbuild.Stage(name, {}, None, None, {}), {"name": name}),
|
|
Packit |
a20ca0 |
(osbuild.Stage(name, {}, None, None, None), {"name": name}),
|
|
Packit |
a20ca0 |
(osbuild.Stage(name, {}, None, None, options), {"name": name, "options": options}),
|
|
Packit |
a20ca0 |
]
|
|
Packit |
a20ca0 |
for stage, description in cases:
|
|
Packit |
a20ca0 |
with self.subTest(description):
|
|
Packit |
a20ca0 |
self.assertEqual(stage.description(), description)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
def test_assembler(self):
|
|
Packit |
a20ca0 |
name = "org.osbuild.test"
|
|
Packit |
a20ca0 |
options = {"one": 1}
|
|
Packit |
a20ca0 |
cases = [
|
|
Packit |
a20ca0 |
(osbuild.Assembler(name, None, None, {}), {"name": name}),
|
|
Packit |
a20ca0 |
(osbuild.Assembler(name, None, None, None), {"name": name}),
|
|
Packit |
a20ca0 |
(osbuild.Assembler(name, None, None, options), {"name": name, "options": options}),
|
|
Packit |
a20ca0 |
]
|
|
Packit |
a20ca0 |
for assembler, description in cases:
|
|
Packit |
a20ca0 |
with self.subTest(description):
|
|
Packit |
a20ca0 |
self.assertEqual(assembler.description(), description)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
def test_pipeline(self):
|
|
Packit |
a20ca0 |
build = osbuild.Pipeline("org.osbuild.test")
|
|
Packit |
a20ca0 |
build.add_stage("org.osbuild.test", {}, {"one": 1})
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
pipeline = osbuild.Pipeline("org.osbuild.test", build)
|
|
Packit |
a20ca0 |
pipeline.add_stage("org.osbuild.test", {}, {"one": 2})
|
|
Packit |
a20ca0 |
pipeline.set_assembler("org.osbuild.test")
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
self.assertEqual(pipeline.description(), {
|
|
Packit |
a20ca0 |
"build": {
|
|
Packit |
a20ca0 |
"pipeline": {
|
|
Packit |
a20ca0 |
"stages": [
|
|
Packit |
a20ca0 |
{
|
|
Packit |
a20ca0 |
"name": "org.osbuild.test",
|
|
Packit |
a20ca0 |
"options": {"one": 1}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
]
|
|
Packit |
a20ca0 |
},
|
|
Packit |
a20ca0 |
"runner": "org.osbuild.test"
|
|
Packit |
a20ca0 |
},
|
|
Packit |
a20ca0 |
"stages": [
|
|
Packit |
a20ca0 |
{
|
|
Packit |
a20ca0 |
"name": "org.osbuild.test",
|
|
Packit |
a20ca0 |
"options": {"one": 2}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
],
|
|
Packit |
a20ca0 |
"assembler": {
|
|
Packit |
a20ca0 |
"name": "org.osbuild.test"
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
})
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
def test_moduleinfo(self):
|
|
Packit |
a20ca0 |
index = osbuild.meta.Index(os.curdir)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
modules = []
|
|
Packit |
a20ca0 |
for klass in ("Stage", "Assembler", "Source"):
|
|
Packit |
a20ca0 |
mods = index.list_modules_for_class(klass)
|
|
Packit |
a20ca0 |
modules += [(klass, module) for module in mods]
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
self.assertTrue(modules)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
for module in modules:
|
|
Packit |
a20ca0 |
klass, name = module
|
|
Packit |
a20ca0 |
try:
|
|
Packit |
a20ca0 |
info = osbuild.meta.ModuleInfo.load(os.curdir, klass, name)
|
|
Packit |
a20ca0 |
schema = osbuild.meta.Schema(info.schema, name)
|
|
Packit |
a20ca0 |
res = schema.check()
|
|
Packit |
a20ca0 |
if not res:
|
|
Packit |
a20ca0 |
err = "\n ".join(str(e) for e in res)
|
|
Packit |
a20ca0 |
self.fail(str(res) + "\n " + err)
|
|
Packit |
a20ca0 |
except json.decoder.JSONDecodeError as e:
|
|
Packit |
a20ca0 |
msg = f"{klass} '{name}' has invalid STAGE_OPTS\n\t" + str(e)
|
|
Packit |
a20ca0 |
self.fail(msg)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
def test_schema(self):
|
|
Packit |
a20ca0 |
schema = osbuild.meta.Schema(None)
|
|
Packit |
a20ca0 |
self.assertFalse(schema)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
schema = osbuild.meta.Schema({"type": "bool"}) # should be 'boolean'
|
|
Packit |
a20ca0 |
self.assertFalse(schema.check().valid)
|
|
Packit |
a20ca0 |
self.assertFalse(schema)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
schema = osbuild.meta.Schema({"type": "array", "minItems": 3})
|
|
Packit |
a20ca0 |
self.assertTrue(schema.check().valid)
|
|
Packit |
a20ca0 |
self.assertTrue(schema)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
res = schema.validate([1, 2])
|
|
Packit |
a20ca0 |
self.assertFalse(res)
|
|
Packit |
a20ca0 |
res = schema.validate([1, 2, 3])
|
|
Packit |
a20ca0 |
self.assertTrue(res)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
def test_validation(self):
|
|
Packit |
a20ca0 |
index = osbuild.meta.Index(os.curdir)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
# an empty manifest is OK
|
|
Packit |
a20ca0 |
res = osbuild.meta.validate({}, index)
|
|
Packit |
a20ca0 |
self.assertEqual(res.valid, True)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
# something totally invalid (by Ondřej Budai)
|
|
Packit |
a20ca0 |
totally_invalid = {
|
|
Packit |
a20ca0 |
"osbuild": {
|
|
Packit |
a20ca0 |
"state": "awesome",
|
|
Packit |
a20ca0 |
"but": {
|
|
Packit |
a20ca0 |
"input-validation": 1
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
res = osbuild.meta.validate(totally_invalid, index)
|
|
Packit |
a20ca0 |
self.assertEqual(res.valid, False)
|
|
Packit |
a20ca0 |
# The top-level 'osbuild' is an additional property
|
|
Packit |
a20ca0 |
self.assertEqual(len(res), 1)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
# This is missing the runner
|
|
Packit |
a20ca0 |
no_runner = {
|
|
Packit |
a20ca0 |
"pipeline": {
|
|
Packit |
a20ca0 |
"build": {
|
|
Packit |
a20ca0 |
"pipeline": {}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
res = osbuild.meta.validate(no_runner, index)
|
|
Packit |
a20ca0 |
self.assertEqual(res.valid, False)
|
|
Packit |
a20ca0 |
self.assertEqual(len(res), 1) # missing runner
|
|
Packit |
a20ca0 |
lst = res[".pipeline.build"]
|
|
Packit |
a20ca0 |
self.assertEqual(len(lst), 1)
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
# de-dup issues: the manifest checking will report
|
|
Packit |
a20ca0 |
# the extra element and the recursive build pipeline
|
|
Packit |
a20ca0 |
# check will also report that same error; make sure
|
|
Packit |
a20ca0 |
# they get properly de-duplicated
|
|
Packit |
a20ca0 |
no_runner_extra = {
|
|
Packit |
a20ca0 |
"pipeline": {
|
|
Packit |
a20ca0 |
"build": { # missing runner
|
|
Packit |
a20ca0 |
"pipeline": {
|
|
Packit |
a20ca0 |
"extra": True, # should not be there
|
|
Packit |
a20ca0 |
"stages": [{
|
|
Packit |
a20ca0 |
"name": "org.osbuild.chrony",
|
|
Packit |
a20ca0 |
"options": {
|
|
Packit |
a20ca0 |
"timeservers": "string" # should be an array
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}]
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
res = osbuild.meta.validate(no_runner_extra, index)
|
|
Packit |
a20ca0 |
self.assertEqual(res.valid, False)
|
|
Packit |
a20ca0 |
self.assertEqual(len(res), 3)
|
|
Packit |
a20ca0 |
lst = res[".pipeline.build.pipeline"]
|
|
Packit |
a20ca0 |
self.assertEqual(len(lst), 1) # should only have one
|
|
Packit |
a20ca0 |
lst = res[".pipeline.build.pipeline.stages[0].options.timeservers"]
|
|
Packit |
a20ca0 |
self.assertEqual(len(lst), 1) # should only have one
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
# stage issues
|
|
Packit |
a20ca0 |
stage_check = {
|
|
Packit |
a20ca0 |
"pipeline": {
|
|
Packit |
a20ca0 |
"stages": [{
|
|
Packit |
a20ca0 |
"name": "org.osbuild.grub2",
|
|
Packit |
a20ca0 |
"options": {
|
|
Packit |
a20ca0 |
"uefi": {
|
|
Packit |
a20ca0 |
"install": False,
|
|
Packit |
a20ca0 |
# missing "vendor"
|
|
Packit |
a20ca0 |
},
|
|
Packit |
a20ca0 |
# missing rootfs or root_fs_uuid
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}]
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
res = osbuild.meta.validate(stage_check, index)
|
|
Packit |
a20ca0 |
self.assertEqual(res.valid, False)
|
|
Packit |
a20ca0 |
self.assertEqual(len(res), 2)
|
|
Packit |
a20ca0 |
lst = res[".pipeline.stages[0].options"]
|
|
Packit |
a20ca0 |
self.assertEqual(len(lst), 1) # missing rootfs
|
|
Packit |
a20ca0 |
lst = res[".pipeline.stages[0].options.uefi"]
|
|
Packit |
a20ca0 |
self.assertEqual(len(lst), 1) # missing "osname"
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
assembler_check = {
|
|
Packit |
a20ca0 |
"pipeline": {
|
|
Packit |
a20ca0 |
"assembler": {
|
|
Packit |
a20ca0 |
"name": "org.osbuild.tar",
|
|
Packit |
a20ca0 |
"options": {
|
|
Packit |
a20ca0 |
"compression": "foobar"
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
}
|
|
Packit |
a20ca0 |
|
|
Packit |
a20ca0 |
res = osbuild.meta.validate(assembler_check, index)
|
|
Packit |
a20ca0 |
self.assertEqual(res.valid, False)
|
|
Packit |
a20ca0 |
self.assertEqual(len(res), 2)
|
|
Packit |
a20ca0 |
lst = res[".pipeline.assembler.options"]
|
|
Packit |
a20ca0 |
self.assertEqual(len(lst), 1) # missing "filename"
|
|
Packit |
a20ca0 |
lst = res[".pipeline.assembler.options.compression"]
|
|
Packit |
a20ca0 |
self.assertEqual(len(lst), 1) # wrong compression method
|