mirror of
https://pagure.io/fedora-qa/os-autoinst-distri-fedora.git
synced 2025-08-22 07:15:44 +00:00
Add ProfileGroups
This is another new convenience feature. Groups of profiles let us avoid repeating commonly-used sets. A test suite can specify a group of profiles, with a base priority. The priority value for each profile within the ProfileGroup is added to the base priority in the test suite. Signed-off-by: Adam Williamson <awilliam@redhat.com>
This commit is contained in:
parent
046d9df432
commit
bdf74e74b4
47
fifloader.py
47
fifloader.py
@ -136,6 +136,7 @@ def merge_inputs(inputs, validate=False, clean=False):
|
|||||||
flavors = {}
|
flavors = {}
|
||||||
products = {}
|
products = {}
|
||||||
profiles = {}
|
profiles = {}
|
||||||
|
pgroups = {}
|
||||||
testsuites = {}
|
testsuites = {}
|
||||||
jobtemplates = []
|
jobtemplates = []
|
||||||
|
|
||||||
@ -165,6 +166,7 @@ def merge_inputs(inputs, validate=False, clean=False):
|
|||||||
('Flavors', flavors),
|
('Flavors', flavors),
|
||||||
('Products', products),
|
('Products', products),
|
||||||
('Profiles', profiles),
|
('Profiles', profiles),
|
||||||
|
('ProfileGroups', pgroups),
|
||||||
('JobTemplates', jobtemplates),
|
('JobTemplates', jobtemplates),
|
||||||
):
|
):
|
||||||
if datatype in data:
|
if datatype in data:
|
||||||
@ -177,14 +179,22 @@ def merge_inputs(inputs, validate=False, clean=False):
|
|||||||
for (name, newsuite) in data['TestSuites'].items():
|
for (name, newsuite) in data['TestSuites'].items():
|
||||||
try:
|
try:
|
||||||
existing = testsuites[name]
|
existing = testsuites[name]
|
||||||
# combine and stash the profiles
|
# combine and stash the profiles and groups
|
||||||
|
combinedprofiles = {}
|
||||||
|
if 'profiles' in existing:
|
||||||
existing['profiles'].update(newsuite['profiles'])
|
existing['profiles'].update(newsuite['profiles'])
|
||||||
combinedprofiles = existing['profiles']
|
combinedprofiles = existing['profiles']
|
||||||
|
combinedpgroups = {}
|
||||||
|
if 'profile_groups' in existing:
|
||||||
|
existing['profile_groups'].update(newsuite.get('profile_groups', {}))
|
||||||
|
combinedpgroups = existing['profile_groups']
|
||||||
# now update the existing suite with the new one, this
|
# now update the existing suite with the new one, this
|
||||||
# will overwrite the profiles
|
# will overwrite the profiles and groups
|
||||||
existing.update(newsuite)
|
existing.update(newsuite)
|
||||||
# now restore the combined profiles
|
# now restore the combined profiles and groups
|
||||||
existing['profiles'] = combinedprofiles
|
existing['profiles'] = combinedprofiles
|
||||||
|
if combinedpgroups:
|
||||||
|
existing['profile_groups'] = combinedpgroups
|
||||||
except KeyError:
|
except KeyError:
|
||||||
testsuites[name] = newsuite
|
testsuites[name] = newsuite
|
||||||
|
|
||||||
@ -201,6 +211,8 @@ def merge_inputs(inputs, validate=False, clean=False):
|
|||||||
merged['Products'] = products
|
merged['Products'] = products
|
||||||
if profiles:
|
if profiles:
|
||||||
merged['Profiles'] = profiles
|
merged['Profiles'] = profiles
|
||||||
|
if pgroups:
|
||||||
|
merged['ProfileGroups'] = pgroups
|
||||||
if testsuites:
|
if testsuites:
|
||||||
merged['TestSuites'] = testsuites
|
merged['TestSuites'] = testsuites
|
||||||
if jobtemplates:
|
if jobtemplates:
|
||||||
@ -211,19 +223,26 @@ def merge_inputs(inputs, validate=False, clean=False):
|
|||||||
schema_validate(merged, fif=True, state=state)
|
schema_validate(merged, fif=True, state=state)
|
||||||
print("Input template data is valid")
|
print("Input template data is valid")
|
||||||
|
|
||||||
return (machines, flavors, products, profiles, testsuites, jobtemplates)
|
return (machines, flavors, products, profiles, pgroups, testsuites, jobtemplates)
|
||||||
|
|
||||||
def generate_job_templates(products, profiles, testsuites):
|
def generate_job_templates(products, profiles, pgroups, testsuites):
|
||||||
"""Given machines, products, profiles and testsuites (after
|
"""Given machines, products, profiles and testsuites (after
|
||||||
merging and handling of flavors, but still in intermediate format),
|
merging and handling of flavors, but still in intermediate format),
|
||||||
generates job templates and returns them as a list.
|
generates job templates and returns them as a list.
|
||||||
"""
|
"""
|
||||||
jobtemplates = []
|
jobtemplates = []
|
||||||
for (name, suite) in testsuites.items():
|
for (name, suite) in testsuites.items():
|
||||||
if 'profiles' not in suite:
|
suiteprofs = {}
|
||||||
|
for (pgroup, baseprio) in suite.get('profile_groups', {}).items():
|
||||||
|
if pgroup not in pgroups:
|
||||||
|
sys.exit(f"Error: profile group {pgroup} does not exist!")
|
||||||
|
for (gotprof, pprio) in pgroups[pgroup].items():
|
||||||
|
suiteprofs[gotprof] = pprio+baseprio
|
||||||
|
suiteprofs.update(suite.get('profiles', {}))
|
||||||
|
if not suiteprofs:
|
||||||
print("Warning: no profiles for test suite {}".format(name))
|
print("Warning: no profiles for test suite {}".format(name))
|
||||||
continue
|
continue
|
||||||
for (profile, prio) in suite['profiles'].items():
|
for (profile, prio) in suiteprofs.items():
|
||||||
jobtemplate = {'test_suite_name': name, 'prio': prio}
|
jobtemplate = {'test_suite_name': name, 'prio': prio}
|
||||||
# x86_64 compose
|
# x86_64 compose
|
||||||
jobtemplate['group_name'] = 'fedora'
|
jobtemplate['group_name'] = 'fedora'
|
||||||
@ -285,11 +304,13 @@ def reverse_qol(machines, flavors, products, testsuites):
|
|||||||
temp.update(product.get("settings", {}))
|
temp.update(product.get("settings", {}))
|
||||||
product["settings"] = temp
|
product["settings"] = temp
|
||||||
|
|
||||||
# drop profiles from test suites - these are only used for job
|
# drop profiles and groups from test suites - these are only used
|
||||||
# template generation and should not be in final output. if suite
|
# for job template generation and should not be in final output.
|
||||||
# *only* contained profiles, drop it
|
# if suite *only* contained profiles/groups, drop it
|
||||||
for suite in testsuites.values():
|
for suite in testsuites.values():
|
||||||
del suite['profiles']
|
for prop in ('profiles', 'profile_groups'):
|
||||||
|
if prop in suite:
|
||||||
|
del suite[prop]
|
||||||
testsuites = {name: suite for (name, suite) in testsuites.items() if suite}
|
testsuites = {name: suite for (name, suite) in testsuites.items() if suite}
|
||||||
|
|
||||||
machines = to_list_of_dicts(machines)
|
machines = to_list_of_dicts(machines)
|
||||||
@ -343,9 +364,9 @@ def run(args):
|
|||||||
args = parse_args(args)
|
args = parse_args(args)
|
||||||
if not args.validate and not args.write and not args.load:
|
if not args.validate and not args.write and not args.load:
|
||||||
sys.exit("--no-validate specified and neither --write nor --load specified! Doing nothing.")
|
sys.exit("--no-validate specified and neither --write nor --load specified! Doing nothing.")
|
||||||
(machines, flavors, products, profiles, testsuites, jobtemplates) = merge_inputs(
|
(machines, flavors, products, profiles, pgroups, testsuites, jobtemplates) = merge_inputs(
|
||||||
args.files, validate=args.validate, clean=args.clean)
|
args.files, validate=args.validate, clean=args.clean)
|
||||||
jobtemplates.extend(generate_job_templates(products, profiles, testsuites))
|
jobtemplates.extend(generate_job_templates(products, profiles, pgroups, testsuites))
|
||||||
(machines, products, testsuites) = reverse_qol(machines, flavors, products, testsuites)
|
(machines, products, testsuites) = reverse_qol(machines, flavors, products, testsuites)
|
||||||
# now produce the output in upstream-compatible format
|
# now produce the output in upstream-compatible format
|
||||||
out = {}
|
out = {}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"Flavors": { "$ref": "fif-flavors.json" },
|
"Flavors": { "$ref": "fif-flavors.json" },
|
||||||
"ProductDefaults": { "$ref": "fif-productdefaults.json" },
|
"ProductDefaults": { "$ref": "fif-productdefaults.json" },
|
||||||
"Products": { "$ref": "fif-products.json" },
|
"Products": { "$ref": "fif-products.json" },
|
||||||
|
"ProfileGroups": { "$ref": "fif-profilegroups.json" },
|
||||||
"Profiles": { "$ref": "fif-profiles.json" },
|
"Profiles": { "$ref": "fif-profiles.json" },
|
||||||
"TestSuites": { "$ref": "fif-testsuites.json" },
|
"TestSuites": { "$ref": "fif-testsuites.json" },
|
||||||
"JobTemplates": { "$ref": "openqa-jobtemplates.json" }
|
"JobTemplates": { "$ref": "openqa-jobtemplates.json" }
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"Flavors": { "$ref": "fif-flavors.json" },
|
"Flavors": { "$ref": "fif-flavors.json" },
|
||||||
"ProductDefaults": { "$ref": "fif-productdefaults.json" },
|
"ProductDefaults": { "$ref": "fif-productdefaults.json" },
|
||||||
"Products": { "$ref": "fif-products.json" },
|
"Products": { "$ref": "fif-products.json" },
|
||||||
|
"ProfileGroups": { "$ref": "fif-profilegroups.json" },
|
||||||
"Profiles": { "$ref": "fif-profiles.json" },
|
"Profiles": { "$ref": "fif-profiles.json" },
|
||||||
"TestSuites": { "$ref": "fif-testsuites.json" },
|
"TestSuites": { "$ref": "fif-testsuites.json" },
|
||||||
"JobTemplates": { "$ref": "openqa-jobtemplates.json" }
|
"JobTemplates": { "$ref": "openqa-jobtemplates.json" }
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"Flavors": { "$ref": "fif-flavors.json" },
|
"Flavors": { "$ref": "fif-flavors.json" },
|
||||||
"ProductDefaults": { "$ref": "fif-productdefaults.json" },
|
"ProductDefaults": { "$ref": "fif-productdefaults.json" },
|
||||||
"Products": { "$ref": "fif-products-predefault.json" },
|
"Products": { "$ref": "fif-products-predefault.json" },
|
||||||
|
"ProfileGroups": { "$ref": "fif-profilegroups.json" },
|
||||||
"Profiles": { "$ref": "fif-profiles.json" },
|
"Profiles": { "$ref": "fif-profiles.json" },
|
||||||
"TestSuites": { "$ref": "fif-testsuites.json" },
|
"TestSuites": { "$ref": "fif-testsuites.json" },
|
||||||
"JobTemplates": { "$ref": "openqa-jobtemplates.json" }
|
"JobTemplates": { "$ref": "openqa-jobtemplates.json" }
|
||||||
|
8
schemas/fif-profilegroup.json
Normal file
8
schemas/fif-profilegroup.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "fif-profilegroup.json",
|
||||||
|
"title": "FIF single profile group schema",
|
||||||
|
"type": "object",
|
||||||
|
"minProperties": 1,
|
||||||
|
"additionalProperties": { "type": "number" }
|
||||||
|
}
|
8
schemas/fif-profilegroups.json
Normal file
8
schemas/fif-profilegroups.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "fif-profilegroups.json",
|
||||||
|
"title": "FIF ProfileGroups object schema",
|
||||||
|
"type": "object",
|
||||||
|
"minProperties": 1,
|
||||||
|
"additionalProperties": { "$ref": "fif-profilegroup.json" }
|
||||||
|
}
|
@ -2,8 +2,9 @@
|
|||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"$id": "fif-testsuite.json",
|
"$id": "fif-testsuite.json",
|
||||||
"title": "FIF single test suite schema",
|
"title": "FIF single test suite schema",
|
||||||
"required": [
|
"anyOf": [
|
||||||
"profiles"
|
{"required": ["profiles"]},
|
||||||
|
{"required": ["profile_groups"]}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"profiles": {
|
"profiles": {
|
||||||
@ -11,6 +12,11 @@
|
|||||||
"title": "A testsuite profile entry schema",
|
"title": "A testsuite profile entry schema",
|
||||||
"additionalProperties": { "type": "number" }
|
"additionalProperties": { "type": "number" }
|
||||||
},
|
},
|
||||||
|
"profile_groups": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "A profile group entry schema",
|
||||||
|
"additionalProperties": { "type": "number" }
|
||||||
|
},
|
||||||
"settings": { "$ref": "fif-settingshash.json" }
|
"settings": { "$ref": "fif-settingshash.json" }
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -25,6 +25,11 @@
|
|||||||
"product": "fedora-updates-server-x86_64-*"
|
"product": "fedora-updates-server-x86_64-*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ProfileGroups": {
|
||||||
|
"fedora-updates-server-1arch": {
|
||||||
|
"fedora-updates-server-ppc64le-*-ppc64le": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
"TestSuites": {
|
"TestSuites": {
|
||||||
"advisory_boot": {
|
"advisory_boot": {
|
||||||
"profiles": {
|
"profiles": {
|
||||||
@ -39,8 +44,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"base_selinux": {
|
"base_selinux": {
|
||||||
|
"profile_groups": {
|
||||||
|
"fedora-updates-server-1arch": 40
|
||||||
|
},
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"fedora-updates-server-ppc64le-*-ppc64le": 40,
|
|
||||||
"fedora-updates-server-x86_64-*-64bit": 40
|
"fedora-updates-server-x86_64-*-64bit": 40
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,10 +65,21 @@
|
|||||||
"product": "fedora-Server-dvd-iso-x86_64-*"
|
"product": "fedora-Server-dvd-iso-x86_64-*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ProfileGroups": {
|
||||||
|
"fedora-server-2arch": {
|
||||||
|
"fedora-Server-dvd-iso-ppc64le-*-ppc64le": 0,
|
||||||
|
"fedora-Server-dvd-iso-x86_64-*-64bit": 1
|
||||||
|
},
|
||||||
|
"fedora-server-1arch": {
|
||||||
|
"fedora-Server-dvd-iso-ppc64le-*-ppc64le": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
"TestSuites": {
|
"TestSuites": {
|
||||||
"base_selinux": {
|
"base_selinux": {
|
||||||
|
"profile_groups": {
|
||||||
|
"fedora-server-1arch": 40
|
||||||
|
},
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"fedora-Server-dvd-iso-ppc64le-*-ppc64le": 40,
|
|
||||||
"fedora-Server-dvd-iso-x86_64-*-64bit": 40
|
"fedora-Server-dvd-iso-x86_64-*-64bit": 40
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -81,9 +92,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"install_default_upload": {
|
"install_default_upload": {
|
||||||
"profiles": {
|
"profile_groups": {
|
||||||
"fedora-Server-dvd-iso-ppc64le-*-ppc64le": 10,
|
"fedora-server-2arch": 10
|
||||||
"fedora-Server-dvd-iso-x86_64-*-64bit": 10
|
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"PACKAGE_SET": "default",
|
"PACKAGE_SET": "default",
|
||||||
|
@ -73,20 +73,26 @@ def test_schema_validate():
|
|||||||
)
|
)
|
||||||
def test_merge_inputs(input1, input2):
|
def test_merge_inputs(input1, input2):
|
||||||
"""Test for merge_inputs."""
|
"""Test for merge_inputs."""
|
||||||
(machines, flavors, products, profiles, testsuites, jobtemplates) = _get_merged(input1, input2)
|
(machines, flavors, products, profiles, pgroups, testsuites, jobtemplates) = _get_merged(
|
||||||
|
input1,
|
||||||
|
input2
|
||||||
|
)
|
||||||
# a few known attributes of the test data to ensure the merge worked
|
# a few known attributes of the test data to ensure the merge worked
|
||||||
assert len(machines) == 2
|
assert len(machines) == 2
|
||||||
assert len(flavors) == 1
|
assert len(flavors) == 1
|
||||||
assert len(products) == 4
|
assert len(products) == 4
|
||||||
assert len(profiles) == 4
|
assert len(profiles) == 4
|
||||||
|
assert len(pgroups) == 3
|
||||||
assert not jobtemplates
|
assert not jobtemplates
|
||||||
# testsuite merging is the most complex feature
|
# testsuite merging is the most complex feature
|
||||||
# len should be 3 as there is 1 unique suite in each input file,
|
# len should be 3 as there is 1 unique suite in each input file,
|
||||||
# and one defined in both which should be merged
|
# and one defined in both which should be merged
|
||||||
assert len(testsuites) == 3
|
assert len(testsuites) == 3
|
||||||
# check the merged suite was merged correctly
|
# check the merged suite was merged correctly
|
||||||
# we should have the profiles from *both* input files...
|
# we should have the profiles and profile groups from *both*
|
||||||
assert len(testsuites['base_selinux']['profiles']) == 4
|
# input files...
|
||||||
|
assert len(testsuites['base_selinux']['profiles']) == 2
|
||||||
|
assert len(testsuites['base_selinux']['profile_groups']) == 2
|
||||||
# and we should still have the settings (note, combining settings
|
# and we should still have the settings (note, combining settings
|
||||||
# is not supported, the last-read settings dict is always used)
|
# is not supported, the last-read settings dict is always used)
|
||||||
assert len(testsuites['base_selinux']['settings']) == 6
|
assert len(testsuites['base_selinux']['settings']) == 6
|
||||||
@ -98,8 +104,8 @@ def test_merge_inputs(input1, input2):
|
|||||||
|
|
||||||
def test_generate_job_templates():
|
def test_generate_job_templates():
|
||||||
"""Test for generate_job_templates."""
|
"""Test for generate_job_templates."""
|
||||||
(machines, _, products, profiles, testsuites, _) = _get_merged()
|
(machines, _, products, profiles, pgroups, testsuites, _) = _get_merged()
|
||||||
templates = fifloader.generate_job_templates(products, profiles, testsuites)
|
templates = fifloader.generate_job_templates(products, profiles, pgroups, testsuites)
|
||||||
# we should get one template per profile in merged input
|
# we should get one template per profile in merged input
|
||||||
assert len(templates) == 8
|
assert len(templates) == 8
|
||||||
for template in templates:
|
for template in templates:
|
||||||
@ -112,9 +118,17 @@ def test_generate_job_templates():
|
|||||||
assert item in template
|
assert item in template
|
||||||
assert template['test_suite_name'] in list(testsuites.keys())
|
assert template['test_suite_name'] in list(testsuites.keys())
|
||||||
|
|
||||||
|
# check profile group expansion
|
||||||
|
idus = [t for t in templates if t['test_suite_name'] == 'install_default_upload']
|
||||||
|
assert len(idus) == 2
|
||||||
|
assert {t['machine_name'] for t in idus} == {'ppc64le', '64bit'}
|
||||||
|
aboots = [t for t in templates if t['test_suite_name'] == 'base_selinux']
|
||||||
|
assert len(aboots) == 4
|
||||||
|
assert {t['machine_name'] for t in aboots} == {'ppc64le', '64bit'}
|
||||||
|
|
||||||
def test_reverse_qol():
|
def test_reverse_qol():
|
||||||
"""Test for reverse_qol."""
|
"""Test for reverse_qol."""
|
||||||
(machines, flavors, products, _, testsuites, _) = _get_merged()
|
(machines, flavors, products, _, _, testsuites, _) = _get_merged()
|
||||||
(machines, products, testsuites) = fifloader.reverse_qol(machines, flavors, products, testsuites)
|
(machines, products, testsuites) = fifloader.reverse_qol(machines, flavors, products, testsuites)
|
||||||
assert isinstance(machines, list)
|
assert isinstance(machines, list)
|
||||||
assert isinstance(products, list)
|
assert isinstance(products, list)
|
||||||
@ -127,8 +141,9 @@ def test_reverse_qol():
|
|||||||
for item in datatype:
|
for item in datatype:
|
||||||
# all items should have one of these
|
# all items should have one of these
|
||||||
settlists.append(item['settings'])
|
settlists.append(item['settings'])
|
||||||
# no items should have one of these
|
# no items should have these
|
||||||
assert 'profiles' not in item
|
assert 'profiles' not in item
|
||||||
|
assert 'profile_groups' not in item
|
||||||
for settlist in settlists:
|
for settlist in settlists:
|
||||||
assert isinstance(settlist, list)
|
assert isinstance(settlist, list)
|
||||||
for setting in settlist:
|
for setting in settlist:
|
||||||
|
Loading…
Reference in New Issue
Block a user