Implement yaql tests

As we already have yaql expression almost in each task, implement
basic syntax tests for these expressions.

Change-Id: Idb7768eca9be3def4783a70b2ef3b1dafc0d0510
Closes-Bug: #1588910
DocImpact
(cherry picked from commit d5891879a8)
This commit is contained in:
Stanislaw Bogatkin 2016-05-31 15:51:51 +03:00
parent e283b62750
commit 268dfb0c1e
5 changed files with 239 additions and 0 deletions

179
tests/yaql/check_yaqls.py Executable file
View File

@ -0,0 +1,179 @@
#!/usr/bin/env python
"""Tests for YAQL expressions in Fuel tasks.yaml files
Load and evaluate YAQL expressions from tasks.
Usage:
check_yaqls.py [--dir DIRPATH] [--fixtures FIXT_DIR] [--cluster CLUSTER_ID] [--node NODE_ID]
check_yaqls.py --file FILEPATH [--fixtures FIXT_DIR] [--cluster CLUSTER_ID] [--node NODE_ID]
check_yaqls.py -h
check_yaqls.py --version
Options:
-d --dir DIRPATH try to load all YAQL expressions from all tasks.yaml files found in directory and subdirectories [default: ../../deployment]
-f --file FILEPATH try to load all expressions from file
-x --fixtures FIXT_DIR use this directory to load fixtures from [default: fixtures]
-c --cluster CLUSTER_ID use this cluster ID [default: 1]
-n --node NODE_ID use this node [default: 1]
-h --help show this help
--version show version
"""
import collections
import json
import logging
import os
import sys
import traceback
import yaml
from docopt import docopt
from nailgun.fuyaql import fuyaql
TEST_FAILED = False
options = docopt(__doc__, version='0.1')
def load_tasks_from_directory(directory):
"""Loads tasks from dir and subdirs.
:param directory: directory from which tasks will be loaded
:return: dict with task names as keys and task expressions as values
"""
tasks_list = []
for root, dirs, files in os.walk(directory):
for filename in files:
if filename == 'tasks.yaml':
tasks_list.append(os.path.join(root, filename))
tasks_conditions = dict()
for tasks in tasks_list:
tasks_conditions.update(load_tasks_from_file(tasks))
return tasks_conditions
def load_tasks_from_file(tasks_file):
"""Loads tasks from file.
:param tasks_file: file from which tasks will be loaded
:return: dict with task names as keys and task expressions as values
"""
tasks_conditions = dict()
with open(tasks_file, 'rt') as f:
yml = yaml.safe_load(f)
tasks_conditions.update(
{t['id']: t.get('condition', {}).get('yaql_exp', {}) for t in yml})
return tasks_conditions
def load_tasks():
"""Load tasks from directory or file
:return: hash with tasks names and conditions
"""
if not options['--file']:
current_dir = os.path.dirname(os.path.realpath(__file__))
deployment_dir = current_dir + "/" + options['--dir']
print('deployment dir is %s' % deployment_dir)
tasks = load_tasks_from_directory(deployment_dir)
else:
tasks_file = options['--file']
tasks = load_tasks_from_file(tasks_file)
return tasks
def get_logger():
"""Get a logger and disable DEBUG state
:return: logger instance
"""
logger = logging.getLogger(__name__)
logger.propagate = False
logging.disable(logging.DEBUG)
return logger
def get_evaluator():
"""Get a YAQL evaluator
:return: FuYaqlController evaluator instance
"""
evaluator = fuyaql.FuYaqlController()
evaluator._cluster = True
evaluator._node_id = options['--node']
return evaluator
def set_evaluator_data(evaluator, old_context, new_context):
"""Set evaluator data
:param evaluator: FuYaqlController evaluator instance
:param old_context: hash to use as an old context
:param new_context: hash to use as a new context
"""
try:
with open(os.path.expanduser(old_context), 'r') as f:
current_state = json.load(f)
with open(os.path.expanduser(new_context), 'r') as f:
expected_state = json.load(f)
except IOError:
print("Cannot open context fixtures file.")
print(traceback.format_exc())
sys.exit(1)
evaluator._infos = current_state, expected_state
def load_fixtures_from_directory(directory):
"""Recursively load fixture sets from directory
:param directory: path to a directory with fixtures
:return: dictionary with fixtures name and path to context files
"""
fixtures = collections.defaultdict(dict)
for root, dirs, files in os.walk(directory):
for filename in files:
if filename.endswith('_old_context.json'):
base_name = filename.split('_old_context.json')[0]
fixtures[base_name]['old'] = os.path.join(root, filename)
elif filename.endswith('_new_context.json'):
base_name = filename.split('_new_context.json')[0]
fixtures[base_name]['new'] = os.path.join(root, filename)
return fixtures
tasks = load_tasks()
logger = get_logger()
evaluator = get_evaluator()
fixtures = load_fixtures_from_directory(options['--fixtures'])
for basename, files_hash in fixtures.items():
print("Start evaluating for {} context".format(basename))
set_evaluator_data(evaluator, files_hash['old'], files_hash['new'])
failed_tasks = dict()
for task_name, expression in tasks.items():
# There are tasks without yaql_expressions
if not expression:
continue
try:
res = evaluator.evaluate(expression)
print("Expression for %s task looks valid" % task_name)
except Exception as e:
print("Expression for %s task doesn't looks valid" % task_name)
print("%s" % expression)
print(traceback.format_exc())
failed_tasks[task_name] = 'Fail'
if failed_tasks:
print('*'*20 + ' List of failed tasks ' + '*'*20)
for name in failed_tasks:
print(name)
TEST_FAILED = True
if TEST_FAILED:
print("Some tasks failed, check the output")
sys.exit(1)
print('*'*20 + ' There is no failed tasks ' + '*'*20)

9
tests/yaql/install_nailgun.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
# It is a workaround for old pip and tox versions. CI uses tox 1.6 and it
# can't manage hash symbols right way (look at
# https://bitbucket.org/hpk42/tox/issues/181/hash-number-sign-cannot-be-escaped-in)
# We can use deps field for tox but at the same time CI uses pip 1.5.4 and it
# can't properly install package from a vcs subdirectory. Also we can't just
# update pip from tox deps as dependencies doesn't managed in a consequent way in tox.
# TODO(sbog): move this into tox configuration when CI will use newer versions of tox and pip (tested for pip 7.1.2 and tox 2.3.1)
pip install -e "git+https://github.com/openstack/fuel-web.git#egg=nailgun&subdirectory=nailgun"

35
tests/yaql/run_tests.sh Executable file
View File

@ -0,0 +1,35 @@
#!/bin/bash
set -eux
DIR=`dirname $0`
cd "${DIR}" || exit 1
REPO_URL=${NOOP_FIXTURES_REPO_URL:-'https://github.com/openstack/fuel-noop-fixtures.git'}
clone_fixtures_repo() {
if ! [ -d 'fuel-noop-fixtures' ]; then
echo "Cloning the repository..."
git clone "${REPO_URL}" 'fuel-noop-fixtures'
fi
}
link_yaql_fixtures() {
if ! [ -L 'fixtures' ]; then
echo "Linking repo fixtures to the local FS..."
ln -sf 'fuel-noop-fixtures/yaql' 'fixtures'
fi
}
check_tox() {
type tox >/dev/null 2>&1 || { echo >&2 "Tox is required to be installed to run tests."; exit 1; }
}
run_tox() {
echo "Run tests..."
tox
}
check_tox
clone_fixtures_repo
link_yaql_fixtures
run_tox

11
tests/yaql/tox.ini Normal file
View File

@ -0,0 +1,11 @@
[tox]
minversion = 1.6
envlist = py27
skipsdist = True
[testenv]
deps = docopt
commands =
pip install pip --upgrade
./install_nailgun.sh
python check_yaqls.py

View File

@ -0,0 +1,5 @@
#!/bin/sh
DIR=`dirname $0`
cd $DIR || exit 1
../../tests/yaql/run_tests.sh