Skip to content

Commit

Permalink
PoC of profiles support
Browse files Browse the repository at this point in the history
  • Loading branch information
jscotka committed Jul 26, 2023
1 parent 1971d30 commit f21e136
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 0 deletions.
5 changes: 5 additions & 0 deletions fmf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import fmf.context
import fmf.utils as utils
from fmf.utils import dict_to_yaml, log
from fmf.profile import Profile

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Constants
Expand Down Expand Up @@ -794,3 +795,7 @@ def __getitem__(self, key):
return self.children[key[1:]]
else:
return self.data[key]

def apply_profile(self, profile: Profile) -> None:
profile.apply_rule(self)

74 changes: 74 additions & 0 deletions fmf/profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from copy import deepcopy
from fmf.context import Context
#from fmf.base import Tree
"""
generic _definition/:
where: a is defined and b is defined
key1: value1 # override
key2+: value2 # append
key3-: value3 # remove
key4?: value4 # define if not defined
plan_definition/:
where: execute is defined and discovery is defined
# append to prepare phase
prepare+:
name: some name
how: shell
script: systemctl start httpd
# create reporting if not defined
report?:
how: html
open: true
# override provision by own definition
provision:
how: virtual
image: fedora-37
"""


class ProfileError(Exception):
pass


class ProfileWithoutWhereStatement(ProfileError):
pass


class Profile:

def __init__(self, rule: dict, name = None):
self._raw_rule = rule
self.name = name
if "where" not in self._raw_rule.keys():
raise ProfileWithoutWhereStatement
self.where = self._raw_rule.pop("where")
self.rules = deepcopy(self._raw_rule)

def _check_if_fmf_node_match(self, node):
context = Context(**node.data)
return context.matches(self.where)

def _apply_rule(self, node):

if not self._check_if_fmf_node_match(node):
return
for rule in self.rules:
if isinstance(rule, str) and rule.endswith("?"):
rule_clear = rule[:-1]
data = {rule_clear : self.rules[rule]}
if rule_clear in node.data:
# do not override if defined
continue
else:
data = {rule: self.rules[rule]}
node._merge_special(node.data, data)

def apply_rule(self, node):
for item in node.climb():
self._apply_rule(item)
23 changes: 23 additions & 0 deletions tests/unit/data/profile/profile_file.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plan1_definition:
where: execute is defined cc and discover is defined
# append to prepare phase
prepare+:
name: some name
how: shell
script: systemctl start httpd
# create reporting if not defined
report?:
how: html
open: true

# override provision by own definition
provision:
how: virtual
image: fedora-37


test1_definition:
where: summary is defined and discovery is defined
new_attribute: hello world
test+: appended

1 change: 1 addition & 0 deletions tests/unit/data/profile/tree/.fmf/version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
Empty file.
17 changes: 17 additions & 0 deletions tests/unit/data/profile/tree/plan.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/base:
summary: test plans
execute:
how: tmt
provision:
how: minute
/plan0:
discover:
how: fmf
/plan1:
discover:
how: shell
report:
how: polarion
prepare:
name: some name
how: shell
2 changes: 2 additions & 0 deletions tests/unit/data/profile/tree/test.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test: test1.sh
summary: hello
36 changes: 36 additions & 0 deletions tests/unit/test_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from unittest import TestCase
from pathlib import Path

import yaml

from fmf import Tree
from fmf.profile import Profile

PROFILE_PATH = Path(__file__).parent / "data" / "profile"
PROFILE = PROFILE_PATH / "profile_file.yaml"

class ProfileLoad(TestCase):
def setUp(self) -> None:
with PROFILE.open("r") as profile_file:
self.profile_data = yaml.safe_load(profile_file)

def test_load(self):
profiles = []
for k, v in self.profile_data.items():
profiles.append(Profile(v, name=k))


class ProfileApply(TestCase):
def setUp(self) -> None:
with PROFILE.open("r") as profile_file:
self.profile_data = yaml.safe_load(profile_file)
self.profiles = []
for k, v in self.profile_data.items():
self.profiles.append(Profile(v, name=k))
self.fmf_tree = Tree(PROFILE_PATH / "tree")

def test_apply_to_test(self):
for profile in self.profiles:
self.fmf_tree.apply_profile(profile)
for item in self.fmf_tree.climb():
print(item.data)

0 comments on commit f21e136

Please sign in to comment.