Skip to content

Commit

Permalink
Fix Checkbox configuration value resolution and add Metabox scenarios…
Browse files Browse the repository at this point in the history
… to test it (#439)

* Process config from launcher last to have precedence

Launcher should always take precedence over anything else (config file
from /etc/xdg/ or ~/.config/). In order to achieve this, it has to be
added last in the configs list to be processed.

* Update documentation to reflect actual value resolution

* Refactor config [environment] metabox scenarios

Checkbox configuration covers many different sections. In order to
accomodate testing all the different sections inside the same "tag"
("config"), refactoring the existing tests (covering the [environment]
section) into its own scenario module.

* Add Metabox scenarios to test [test selection] section
  • Loading branch information
pieqq committed May 9, 2023
1 parent 526cb6d commit d7c7100
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 24 deletions.
8 changes: 5 additions & 3 deletions checkbox-ng/checkbox_ng/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,12 @@ def expand_all(path):
return os.path.expandvars(os.path.expanduser(path))

def load_configs(launcher_file=None):
# launcher can override the default name of config files to look for
# so first we need to establish the filename to look for
configs = []
config_filename = 'checkbox.conf'
launcher = DefaultLauncherDefinition()
# launcher can override the default name of config files to look for
# so first we need to establish the filename to look for
if launcher_file:
configs.append(launcher_file)
generic_launcher = LauncherDefinition()
if not os.path.exists(launcher_file):
_logger.error(_(
Expand All @@ -68,6 +67,9 @@ def load_configs(launcher_file=None):
config = expand_all(os.path.join(d, config_filename))
if os.path.exists(config):
configs.append(config)
# Add config from launcher last so it gets precedence over others
if launcher_file:
configs.append(launcher_file)
launcher.read(configs)
if launcher.problem_list:
_logger.error(_("Unable to start launcher because of errors:"))
Expand Down
5 changes: 3 additions & 2 deletions checkbox-ng/docs/configs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ is used.
Note that if same configuration variable is defined in more than one place, the
value resolution is as follows:

1. config file from ``~/.config``
2. launcher being invoked (only the new syntax launchers)
1. launcher being invoked
2. config file from ``~/.config``
3. config file from ``/etc/xdg``
4. config file from ``$SNAP_DATA``

Configs with Checkbox Remote
============================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ source = HOME
# The following variables are defined to test value resolution when defining
# configuration from different places (config files, launcher, etc.)
var1 = HOME
var2 = HOME
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[test selection]
forced = yes
exclude = .*config-environ-source
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[test selection]
forced = yes
exclude = .*config-environ-source
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@
from metabox.core.actions import Put
from metabox.core.scenario import Scenario

from . import config_files
from .config_files import environment


class CheckboxConfXDG(Scenario):
"""
Check that environment variables are read from the XDG directory when
nothing else is available.
"""
checkbox_conf = read_text(config_files, "checkbox_etc_xdg.conf")
checkbox_conf = read_text(environment, "checkbox_etc_xdg.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
Expand All @@ -56,7 +56,7 @@ class CheckboxConfLocalHome(Scenario):
nothing else is available.
"""
modes = ["local"]
checkbox_conf = read_text(config_files, "checkbox_home_dir.conf")
checkbox_conf = read_text(environment, "checkbox_home_dir.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
Expand All @@ -80,7 +80,7 @@ class CheckboxConfRemoteHome(Scenario):
nothing else is available.
"""
modes = ["remote"]
checkbox_conf = read_text(config_files, "checkbox_home_dir.conf")
checkbox_conf = read_text(environment, "checkbox_home_dir.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
Expand All @@ -104,7 +104,7 @@ class CheckboxConfSnap(Scenario):
nothing else is available.
"""
origins = ["snap", "classic-snap"]
checkbox_conf = read_text(config_files, "checkbox_snap_dir.conf")
checkbox_conf = read_text(environment, "checkbox_snap_dir.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
Expand Down Expand Up @@ -150,8 +150,8 @@ class CheckboxConfLocalHomePrecedence(Scenario):
take precedence over the ones defined in /etc/xdg/.
"""
modes = ["local"]
checkbox_conf_xdg = read_text(config_files, "checkbox_etc_xdg.conf")
checkbox_conf_home = read_text(config_files, "checkbox_home_dir.conf")
checkbox_conf_xdg = read_text(environment, "checkbox_etc_xdg.conf")
checkbox_conf_home = read_text(environment, "checkbox_home_dir.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
Expand All @@ -176,7 +176,7 @@ class CheckboxConfLauncherPrecedence(Scenario):
over the ones defined in /etc/xdg/.
"""
modes = ["remote"]
checkbox_conf_xdg = read_text(config_files, "checkbox_etc_xdg.conf")
checkbox_conf_xdg = read_text(environment, "checkbox_etc_xdg.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
Expand All @@ -200,16 +200,21 @@ class CheckboxConfLocalResolutionOrder(Scenario):
"""
According to the documentation, resolution order should be:
1. config file from ~/.config
2. launcher being invoked (only the new syntax launchers)
3. config file from /etc/xdg
1. launcher being invoked
2. config file from ``~/.config``
3. config file from ``/etc/xdg``
This scenario sets 3 environment variables in different config locations
and checks the resolution order is as defined.
and checks the resolution order is as defined:
var1 XDG HOME LAUNCHER
var2 XDG HOME
var3 XDG
--------------------->
"""
modes = ["local"]
checkbox_conf_xdg = read_text(config_files, "checkbox_etc_xdg.conf")
checkbox_conf_home = read_text(config_files, "checkbox_home_dir.conf")
checkbox_conf_xdg = read_text(environment, "checkbox_etc_xdg.conf")
checkbox_conf_home = read_text(environment, "checkbox_home_dir.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
Expand All @@ -221,13 +226,12 @@ class CheckboxConfLocalResolutionOrder(Scenario):
forced = yes
[environment]
var1 = LAUNCHER
var2 = LAUNCHER
""")
steps = [
Put("/etc/xdg/checkbox.conf", checkbox_conf_xdg),
Put("/home/ubuntu/.config/checkbox.conf", checkbox_conf_home),
Start(),
AssertPrinted("variables: HOME LAUNCHER XDG"),
AssertPrinted("variables: LAUNCHER HOME XDG"),
]


Expand All @@ -243,8 +247,8 @@ class CheckboxConfRemoteServiceResolutionOrder(Scenario):
and checks the resolution order is as defined.
"""
modes = ["remote"]
checkbox_conf_xdg = read_text(config_files, "checkbox_etc_xdg.conf")
checkbox_conf_home = read_text(config_files, "checkbox_home_dir.conf")
checkbox_conf_xdg = read_text(environment, "checkbox_etc_xdg.conf")
checkbox_conf_home = read_text(environment, "checkbox_home_dir.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
Expand All @@ -263,4 +267,4 @@ class CheckboxConfRemoteServiceResolutionOrder(Scenario):
target="service"),
Start(),
AssertPrinted("variables: HOME LAUNCHER XDG"),
]
]
163 changes: 163 additions & 0 deletions metabox/metabox/scenarios/config/test_selection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# This file is part of Checkbox.
#
# Copyright 2023 Canonical Ltd.
# Written by:
# Pierre Equoy <pierre.equoy@canonical.com>
#
# Checkbox is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3,
# as published by the Free Software Foundation.

#
# Checkbox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
import textwrap
from importlib.resources import read_text

from metabox.core.actions import AssertPrinted
from metabox.core.actions import AssertNotPrinted
from metabox.core.actions import Expect
from metabox.core.actions import Start
from metabox.core.actions import Put
from metabox.core.scenario import Scenario

from .config_files import test_selection


class TestSelectionDefault(Scenario):
"""
Check that by default, the list of tests to run is displayed.
"""
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
stock_reports = text
[test plan]
unit = com.canonical.certification::smoke
forced = yes
""")
steps = [
Start(),
Expect("Choose tests to run on your system:"),
]


class TestSelectionForced(Scenario):
"""
If test selection is forced, Checkbox should start testing right away.
"""
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
stock_reports = text
[test plan]
#unit = 2021.com.canonical.certification::config-automated
unit = com.canonical.certification::smoke
forced = yes
[test selection]
forced = yes
""")
steps = [
Start(),
# Jobs are started right away without test selection screen, e.g.
# --------------[ Running job 1 / 20. Estimated time left: unknown ]--------------
Expect("Running job"),
]


class TestSelectionExcludedJob(Scenario):
"""
If some jobs are excluded from the launcher, they should not be run.
"""
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
stock_reports = text
[test plan]
unit = 2021.com.canonical.certification::config-automated
forced = yes
[test selection]
forced = yes
exclude = .*config-environ-source
""")
steps = [
Start(),
AssertNotPrinted(".*config-environ-source.*"),
]


class LocalTestSelectionResolution(Scenario):
"""
According to Checkbox documentation, the resolution order is:
1. launcher being invoked
2. config file from ~/.config
3. config file from /etc/xdg
If a test is excluded from 2 and 3, but the exclusion list is cleaned in 1,
the test should be run.
This scenario tests this in local mode.
"""
modes = ["local"]
checkbox_conf_etc = read_text(test_selection, "checkbox_etc_xdg.conf")
checkbox_conf_home = read_text(test_selection, "checkbox_home_dir.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
stock_reports = text
[test plan]
unit = 2021.com.canonical.certification::config-automated
forced = yes
[test selection]
exclude =
forced = yes
""")
steps = [
Put("/home/ubuntu/.config/checkbox.conf", checkbox_conf_home),
Put("/etc/xdg/checkbox.conf", checkbox_conf_etc),
Start(),
AssertPrinted(".*config-environ-source.*"),
]


class RemoteTestSelectionResolution(Scenario):
"""
According to Checkbox documentation, the resolution order is:
1. launcher being invoked
2. config file from ~/.config
3. config file from /etc/xdg
If a test is excluded from 2 and 3, but the exclusion list is cleaned in 1,
the test should be run.
This scenario tests this in remote mode.
"""
modes = ["remote"]
checkbox_conf_etc = read_text(test_selection, "checkbox_etc_xdg.conf")
checkbox_conf_home = read_text(test_selection, "checkbox_home_dir.conf")
launcher = textwrap.dedent("""
[launcher]
launcher_version = 1
stock_reports = text
[test plan]
unit = 2021.com.canonical.certification::config-automated
forced = yes
[test selection]
exclude =
forced = yes
""")
steps = [
Put("/home/ubuntu/.config/checkbox.conf", checkbox_conf_home,
target="service"),
Put("/etc/xdg/checkbox.conf", checkbox_conf_etc,
target="service"),
Start(),
AssertPrinted(".*config-environ-source.*"),
]

0 comments on commit d7c7100

Please sign in to comment.