Skip to content

Commit

Permalink
Implement a directive for disabling inheritance
Browse files Browse the repository at this point in the history
As the first step for the special `fmf` directives let's allow to
completely disable inheriting data from parent which is currently
the most desired use case.

Fix #14.
  • Loading branch information
psss committed Jun 8, 2022
1 parent fa20450 commit ed4d296
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 0 deletions.
7 changes: 7 additions & 0 deletions docs/features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ This nicely prevents unnecessary duplication. Redefining an
attribute in a child object will by default overwrite value
inherited from the parent.

If inheriting data from parent is not desired in particular node
of the tree it is possible to disable it using the following
directive::

/:
inherit: false


Merging
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
42 changes: 42 additions & 0 deletions fmf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ def __init__(self, data, name=None, parent=None):
# (needed to prevent removing nodes with an empty dict).
self._updated = False

# Special directives
self._directives = dict()

# Store symlinks in while walking tree in grow() to detect
# symlink loops
if parent is None:
Expand Down Expand Up @@ -208,6 +211,33 @@ def _merge_special(self, data, source):
else:
data[key] = value

def _process_directives(self, directives):
""" Check and process special fmf directives """

def check(value, type_, name=None):
""" Check for correct type """
if not isinstance(value, type_):
name = f" '{name}'" if name else ""
raise fmf.utils.FormatError(
f"Invalid fmf directive{name} in '{self.name}': "
f"Should be a '{type_.__name__}', "
f"got a '{type(value).__name__}' instead.")

# Directives should be a directory
check(directives, dict)

# Check for proper values
for key, value in directives.items():
if key == "inherit":
check(value, bool, name="inherit")
continue
# No other directive supported
raise fmf.utils.FormatError(
f"Unknown fmf directive '{key}' in '{self.name}'.")

# Everything ok, store the directives
self._directives.update(directives)

@staticmethod
def init(path):
""" Create metadata tree root under given path """
Expand All @@ -231,6 +261,9 @@ def merge(self, parent=None):
parent = self.parent
if parent is None:
return
# Do not inherit when disabled
if self._directives.get("inherit") == False:
return
self.sources = parent.sources + self.sources
# Merge child data with parent data
data = copy.deepcopy(parent.data)
Expand All @@ -257,6 +290,15 @@ def update(self, data):
# Nothing to do if no data
if data is None:
return

# Handle fmf directives first
try:
directives = data.pop("/")
self._process_directives(directives)
except KeyError:
pass

# Process the metadata
for key, value in sorted(data.items()):
# Ensure there are no 'None' keys
if key is None:
Expand Down
1 change: 1 addition & 0 deletions tests/core/inherit/data/.fmf/version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
5 changes: 5 additions & 0 deletions tests/core/inherit/data/ci.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Do not inherit common test metadata into CI configuration
/:
inherit: false

resultsdb-testcase: separate
1 change: 1 addition & 0 deletions tests/core/inherit/data/full/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
summary: Full test
2 changes: 2 additions & 0 deletions tests/core/inherit/data/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test: echo fine
contact: somebody
1 change: 1 addition & 0 deletions tests/core/inherit/data/mini/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
summary: Minimal test
8 changes: 8 additions & 0 deletions tests/core/inherit/data/plans/features.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
summary: This plan should inherit nothing

provision:
how: local
discover:
how: fmf
execute:
how: tmt
3 changes: 3 additions & 0 deletions tests/core/inherit/data/plans/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Do not inherit common test metadata into plans
/:
inherit: false
1 change: 1 addition & 0 deletions tests/core/inherit/invalid/.fmf/version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
1 change: 1 addition & 0 deletions tests/core/inherit/invalid/directive.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/: An invalid fmf directive
7 changes: 7 additions & 0 deletions tests/core/inherit/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
summary: Verify functionality of the `inherit` directive
description:
Make sure that the inheritance from parent can be turned off
using the `inherit` directive both when defined in the same
file or separately. Test on a real-life scenario when plans
and the CI config are defined in the test namespace.
require: [tmt]
72 changes: 72 additions & 0 deletions tests/core/inherit/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/bin/bash
. /usr/share/beakerlib/beakerlib.sh || exit 1

rlJournalStart
rlPhaseStartTest "Valid"
rlRun "pushd data"

# Check test
rlRun -s "fmf show --name /mini"
rlAssertGrep "Minimal test" $rlRun_LOG
rlAssertGrep "contact" $rlRun_LOG
rlAssertGrep "fine" $rlRun_LOG

# Check plan
rlRun -s "fmf show --name /plans/features"
rlAssertGrep "This plan should inherit nothing" $rlRun_LOG
rlAssertNotGrep "contact" $rlRun_LOG
rlAssertNotGrep "fine" $rlRun_LOG

# Check ci
rlRun -s "fmf show --name /ci"
rlAssertGrep "resultsdb-testcase: separate" $rlRun_LOG
rlAssertNotGrep "contact" $rlRun_LOG
rlAssertNotGrep "fine" $rlRun_LOG

rlRun "popd"
rlPhaseEnd

rlPhaseStartTest "Invalid"
rlRun "pushd $(mktemp -d)"
rlRun "fmf init"

# Directives should be dictionary
rlRun "echo '/: weird' > file.fmf"
rlRun -s "fmf show" 1
rlAssertGrep "Invalid fmf directive in '/file" $rlRun_LOG
rlAssertGrep "Should be a 'dict', got a 'str' instead." $rlRun_LOG

# Inherit should be a bool
rlRun "echo -e '/: \n inherit: hmmm' > file.fmf"
rlRun -s "fmf show" 1
rlAssertGrep "Invalid fmf directive 'inherit'" $rlRun_LOG

# Unknown directive
rlRun "echo -e '/: \n weird: hmmm' > file.fmf"
rlRun -s "fmf show" 1
rlAssertGrep "Unknown fmf directive 'weird' in '/file'" $rlRun_LOG

rlRun "popd"
rlPhaseEnd

rlPhaseStartTest "Integration with tmt"
rlRun "pushd data"

# Show tests
rlRun -s "tmt tests show"
rlAssertGrep "/mini" $rlRun_LOG
rlAssertGrep "Minimal test" $rlRun_LOG
rlAssertGrep "echo fine" $rlRun_LOG
rlAssertNotGrep "/plan" $rlRun_LOG
rlAssertNotGrep "/ci" $rlRun_LOG

# Check plan
rlRun -s "tmt plans show"
rlAssertGrep "/plan" $rlRun_LOG
rlAssertGrep "This plan should inherit nothing" $rlRun_LOG
rlAssertNotGrep "/test" $rlRun_LOG
rlAssertNotGrep "/ci" $rlRun_LOG

rlRun "popd"
rlPhaseEnd
rlJournalEnd

0 comments on commit ed4d296

Please sign in to comment.