Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use local project functional test template #263

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions openstack/tools/charmed_openstack_functest_runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,11 @@ which yq &>/dev/null || sudo snap install yq
get_and_update_repo https://github.com/openstack-charmers/zosci-config

TOOLS_PATH=$(realpath $(dirname $0))/func_test_tools
CHARM_PATH=$PWD
# This is used generally to identify the charm root.
export CHARM_ROOT_PATH=$PWD

# Get commit we are running tests against.
COMMIT_ID=$(git -C $CHARM_PATH rev-parse --short HEAD)
COMMIT_ID=$(git -C $CHARM_ROOT_PATH rev-parse --short HEAD)
CHARM_NAME=$(awk '/^name: .+/{print $2}' metadata.yaml)

echo "Running functional tests for charm $CHARM_NAME commit $COMMIT_ID"
Expand Down
40 changes: 17 additions & 23 deletions openstack/tools/func_test_tools/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,11 @@ def get_branch_jobs(self, branch, project_templates):
class OSCIConfig():
""" Extract information from osci.yaml """
def __init__(self):
if not os.path.exists('osci.yaml'):
self._osci_config = {}
else:
with open('osci.yaml', encoding='utf-8') as fd:
self._osci_config = yaml.safe_load(fd)
path = os.path.join(os.environ.get('CHARM_ROOT_PATH', ''), 'osci.yaml')
with open(path, encoding='utf-8') as fd:
Copy link
Collaborator

@dnegreira dnegreira Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When opening a file we should have in an exception catcher so that we can handle it properly

Something like:

try:
    with open(path, encoding='utf-8') as fd:
        self._osci_config = yaml.safe_load(fd)
except Exception as e:
    print(f"Error opening {path}: {e}")


Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no i actually want it to fail hard since if it cant find this information it cant do its job properly (which is what happened before)

self._osci_config = yaml.safe_load(fd)

@property
@cached_property
def project_templates(self):
""" Returns all project templates. """
for item in self._osci_config:
Expand All @@ -73,7 +71,7 @@ def project_templates(self):

return []

@property
@cached_property
def project_check_jobs(self):
""" Generator returning all project check jobs defined. """
for item in self._osci_config:
Expand Down Expand Up @@ -103,21 +101,17 @@ def get_job(self, name):

return None

def get_project_check_job(self, name):
""" Get job by name from project.check.jobs. Return can be string name
or dict.

class ProjectTemplatesConfig():
""" Extract information from project_templates.yaml """
def __init__(self, path):
if not os.path.exists(path):
self._config = {}
else:
with open(path, encoding='utf-8') as fd:
self._config = yaml.safe_load(fd)

@property
def project_templates(self):
""" Generator returning all project check jobs defined. """
for item in self._config:
if 'project-template' not in item:
continue
@param name: string name
"""
for job in self.project_check_jobs:
if isinstance(job, dict):
if name in job:
return job
elif job == name:
return job

yield item['project-template']
return None
65 changes: 40 additions & 25 deletions openstack/tools/func_test_tools/test_is_voting.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,57 @@

from common import ( # pylint: disable=import-error
OSCIConfig,
ProjectTemplatesConfig,
ZOSCIConfig,
)


if __name__ == "__main__":
test_job = sys.argv[1]
zosci_path = os.path.join(os.environ['HOME'], "zosci-config")
project_templates = os.path.join(zosci_path,
"zuul.d/project-templates.yaml")
def is_job_voting(job, name):
"""
Jobs are voting by default so only return False if there is a match and it
is a dict with voting=False.
"""
if isinstance(job, dict):
if name in job:
return job[name].get('voting', True)

return True


def is_test_voting():
"""
First look for the func-target in osci
Exit with 1 if test is non-voting otherwise 0.
"""
test_job = sys.argv[1]
# First look for the func-target in osci
if os.path.exists('osci.yaml'):
osci_config = OSCIConfig()
try:
jobs = osci_config.project_check_jobs
for job in jobs:
if isinstance(job, dict) and test_job in job:
if not job[test_job]['voting']:
sys.exit(1)
else:
# default is true
sys.exit(0)
job = osci_config.get_project_check_job(test_job)
if not is_job_voting(job, test_job):
sys.exit(1)

# default is true
except KeyError as exc:
sys.stderr.write(f"ERROR: failed to process osci.yaml - assuming "
f"{test_job} is voting (key {exc} not found)."
"\n")

# If the target was not found in osci.yaml then osci will fallback to
# looking at https://github.com/openstack-charmers/zosci-config/blob/master/zuul.d/project-templates.yaml # noqa, pylint: disable=line-too-long
if os.path.exists(project_templates):
config = ProjectTemplatesConfig(project_templates)
for project in config.project_templates:
if project['name'] == "charm-functional-jobs":
for job in project['check']['jobs']:
if test_job in job:
if not job[test_job].get('voting', True):
sys.exit(1)
# If the target was not found in osci.yaml then osci will fallback to zosci
project_template = 'charm-functional-jobs'
for template in osci_config.project_templates:
if 'functional' in template:
project_template = template

path = os.path.join(os.environ['HOME'], 'zosci-config')
for project in ZOSCIConfig(path).project_templates:
t = project['project-template']
if ('functional' not in t['name'] or t['name'] != project_template):
continue

for job in t['check']['jobs']:
if not is_job_voting(job, test_job):
sys.exit(1)


if __name__ == "__main__":
is_test_voting()