Move parallel runner plugin to core opencafe

Change-Id: I5008807d41584923d019db2cf7c75d46a3316b3d
This commit is contained in:
Nathan Buckner 2015-05-30 19:00:32 -05:00
parent 47d0fb2023
commit da5ce3f22a
15 changed files with 32 additions and 409 deletions

View File

@ -1,13 +0,0 @@
# Copyright 2015 Rackspace
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
__import__('pkg_resources').declare_namespace(__name__)

View File

@ -1,45 +0,0 @@
# Copyright 2015 Rackspace
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from setuptools import setup, find_packages
from setuptools.command.test import test as TestCommand
class Tox(TestCommand):
"""
Tox integration
"""
def __init__(self, *args, **kwargs):
TestCommand.__init__(self, *args, **kwargs)
def finalize_options(self):
TestCommand.finalize_options(self)
def run_tests(self):
# import here, cause outside the eggs aren't loaded
import tox
tox.cmdline(self.test_args)
setup(
name='alt_unittest_runner',
version='0.0.1',
description='The Common Automation Framework Engine',
author='Rackspace Cloud QE',
author_email='cloud-cafe@lists.rackspace.com',
url='http://rackspace.com',
packages=find_packages(),
namespace_packages=['cafe'],
install_requires=[],
tests_require=['tox'],
cmdclass={'test': Tox},
zip_safe=False)

View File

@ -1,4 +0,0 @@
tox
mock
flake8
nose

View File

@ -1,167 +0,0 @@
# Copyright 2015 Rackspace
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import unittest
from cafe.configurator.managers import EngineConfigManager
from cafe.drivers.unittest.arguments import ArgumentParser
from cafe.drivers.unittest.datasets import DatasetList
from cafe.drivers.unittest.decorators import (
data_driven_test, DataDrivenFixture)
from cafe.engine.config import EngineConfig
ENGINE_CONFIG = EngineConfig(
os.environ.get("CAFE_ENGINE_CONFIG_FILE_PATH") or
EngineConfigManager.ENGINE_CONFIG_PATH)
CONFIG_NAME = "test.config"
TEST_CONFIG = "{0}{1}{2}".format(
ENGINE_CONFIG.config_directory, os.sep, CONFIG_NAME)
class PositiveDataGenerator(DatasetList):
"""Generates positive tests for ArgumentParser"""
def __init__(self):
super(PositiveDataGenerator, self).__init__()
self.append_new_dataset("Base", {"arg_update": [], "update": {}})
self.append_new_dataset("tag_no_plus", {
"arg_update": ["-t", "one", "two", "three"],
"update": {"tags": ["one", "two", "three"]}})
self.append_new_dataset("tag_plus", {
"arg_update": ["-t", "+", "two", "three"],
"update": {"tags": ["two", "three"], "all_tags": True}})
self.append_new_dataset("data_directory", {
"arg_update": ["-D", "/"],
"update": {"data_directory": "/"}})
self.append_new_dataset("result_directory", {
"arg_update": ["--result-directory", "/"],
"update": {"result_directory": "/"}})
self.append_new_dataset("regex_list", {
"arg_update": ["-d", ".*", "..."],
"update": {"regex_list": [".*", "..."]}})
self.append_new_dataset("dry_run", {
"arg_update": ["--dry-run"],
"update": {"dry_run": True}})
self.append_new_dataset("exit_on_error", {
"arg_update": ["--exit-on-error"],
"update": {"exit_on_error": True}})
self.append_new_dataset("failfast", {
"arg_update": ["--failfast"],
"update": {"failfast": True}})
self.append_new_dataset("parallel_class", {
"arg_update": ["--parallel", "class"],
"update": {"parallel": "class"}})
self.append_new_dataset("parallel_test", {
"arg_update": ["--parallel", "test"],
"update": {"parallel": "test"}})
self.append_new_dataset("result_json", {
"arg_update": ["--result", "json"],
"update": {"result": "json"}})
self.append_new_dataset("result_xml", {
"arg_update": ["--result", "xml"],
"update": {"result": "xml"}})
for i in range(1, 4):
i = str(i)
self.append_new_dataset("verbose_" + i, {
"arg_update": ["--verbose", i],
"update": {"verbose": int(i)}})
for i in range(1, 4):
i = str(i)
self.append_new_dataset("workers_" + i, {
"arg_update": ["--workers", i],
"update": {"workers": int(i)}})
self.append_new_dataset("file", {
"arg_update": ["--file", TEST_CONFIG],
"update": {"file": {"tests.repo.cafe_tests.NoDataGenerator": [
"test_fail", "test_pass"]}}})
self.append_new_dataset("list", {"arg_update": ["-l"]})
@DataDrivenFixture
class ArgumentsTests(unittest.TestCase):
"""ArgumentParser Tests"""
good_package = "tests.repo"
bad_package = "tests.fakerepo"
good_module = "tests.repo.cafe_tests"
bad_module = "tests.repo.blah"
bad_path = "tests."
good_config = CONFIG_NAME
base_arguments = [good_config, good_package]
config = TEST_CONFIG
expected_base = {
"config": good_config,
"testrepos": [good_package],
"tags": [],
"all_tags": False,
"data_directory": None,
"regex_list": [],
"dry_run": False,
"exit_on_error": False,
"failfast": False,
"parallel": None,
"result": None,
"result_directory": "./",
"verbose": 2,
"workers": 10,
"file": {},
"list": None}
@classmethod
def setUpClass(cls):
super(ArgumentsTests, cls).setUpClass()
file_ = open(cls.config, "w")
file_.write("test_fail (tests.repo.cafe_tests.NoDataGenerator)\n")
file_.write("test_pass (tests.repo.cafe_tests.NoDataGenerator)\n")
file_.close()
def get_updated_expected(self, **kwargs):
"""Creates an updated base argument dictionary for compare"""
dic = {}
dic.update(self.expected_base)
dic.update(kwargs)
return dic
@data_driven_test(PositiveDataGenerator())
def ddtest_arguments_positive(self, arg_update=None, update=None):
"""Test different argument configurations"""
arg_list = self.base_arguments + (arg_update or [])
expected = self.get_updated_expected(**(update or {}))
try:
args = ArgumentParser().parse_args(arg_list)
for key, value in expected.items():
if key == "regex_list":
self.assertEqual(
value, [i.pattern for i in getattr(args, key, [])])
else:
self.assertEqual(value, getattr(args, key, "NoValueFound"))
except SystemExit as exception:
if exception.code != 0:
self.assertEqual(exception, None)

View File

@ -1,136 +0,0 @@
# Copyright 2015 Rackspace
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from time import sleep
from cafe.drivers.unittest.decorators import (
tags, DataDrivenFixture, data_driven_test, DataDrivenClass)
from cafe.drivers.unittest.datasets import DatasetList
from cafe.drivers.unittest.fixtures import BaseTestFixture
DATASET = [1, 2]
SLEEP_TIME = 0
class TestDataGenerator(DatasetList):
"""Data generator"""
def __init__(self):
super(TestDataGenerator, self).__init__()
for num in DATASET:
self.append_new_dataset(
name=str(num),
data_dict={'num': num})
class TestFixture(BaseTestFixture):
"""Test Fixture for tests"""
@classmethod
def setUpClass(cls):
super(TestFixture, cls).setUpClass()
sleep(SLEEP_TIME)
cls.fixture_log.error(cls.__name__)
class NoDataGenerator(TestFixture):
"""Testing Non Data Generated class/test"""
def test_pass(self):
"""Testing pass case"""
sleep(SLEEP_TIME)
self.assertIn(1, DATASET)
self.fixture_log.error("%s Pass", self.__class__.__name__)
def test_fail(self):
"""Testing failure case"""
sleep(SLEEP_TIME)
self.fixture_log.error("%s Fail", self.__class__.__name__)
self.assertIn(9, DATASET)
def test_error(self):
"""Testing error case"""
sleep(SLEEP_TIME)
self.fixture_log.error("%s Error", self.__class__.__name__)
raise Exception
@DataDrivenFixture
class DataGeneratedTests(TestFixture):
"""Testing Data Driven Tests"""
@tags("value", "value1", key='value')
@data_driven_test(TestDataGenerator())
def ddtest_pass(self, num):
"""Testing pass case"""
sleep(SLEEP_TIME)
self.assertIn(num, DATASET)
self.fixture_log.error("%s Pass", self.__class__.__name__)
@tags("value", "value1", key='value')
@data_driven_test(TestDataGenerator())
def ddtest_fail(self, num):
"""Testing failure case"""
sleep(SLEEP_TIME)
self.fixture_log.error("%s Fail", self.__class__.__name__)
self.assertNotIn(num, DATASET)
@tags("value", "value1", key='value')
@data_driven_test(TestDataGenerator())
def ddtest_error(self, num):
"""Testing error case"""
sleep(SLEEP_TIME)
self.fixture_log.error("%s Error", self.__class__.__name__)
raise Exception(num)
@DataDrivenClass(TestDataGenerator())
class DataGeneratedClasses(NoDataGenerator):
"""Testing Data Driven Classes"""
pass
@DataDrivenClass(TestDataGenerator())
class DataGeneratedClassesAndTests(DataGeneratedTests):
"""Testing Data Driven Classes with Data Driven Tests"""
pass
class SetupFailNoDataGenerator(NoDataGenerator):
"""Testing setUpClass failure for SetupFailNoDataGenerator"""
@classmethod
def setUpClass(cls):
super(SetupFailNoDataGenerator, cls).setUpClass()
raise Exception
class SetupFailDataGeneratedTests(DataGeneratedTests):
"""Testing setUpClass failure for SetupFailDataGeneratedTests"""
@classmethod
def setUpClass(cls):
super(SetupFailDataGeneratedTests, cls).setUpClass()
raise Exception
@DataDrivenClass(TestDataGenerator())
class SetupFailDataGeneratedClasses(DataGeneratedClasses):
"""Testing setUpClass failure for SetupFailDataGeneratedClasses"""
@classmethod
def setUpClass(cls):
super(SetupFailDataGeneratedClasses, cls).setUpClass()
raise Exception
@DataDrivenClass(TestDataGenerator())
class SetupFailDataGeneratedClassesAndTests(DataGeneratedClassesAndTests):
"""Testing setUpClass failure for SetupFailDataGeneratedClassesAndTests"""
@classmethod
def setUpClass(cls):
super(SetupFailDataGeneratedClassesAndTests, cls).setUpClass()
raise Exception

View File

@ -1,17 +0,0 @@
[tox]
envlist=pep8,py27
[testenv]
setenv=VIRTUAL_ENV={envdir}
deps=-r{toxinidir}/test-requirements.txt
[testenv:py27]
commands=nosetests {toxinidir}
[testenv:pep8]
commands=flake8
[flake8]
ignore=F401
exclude=.git,.idea,docs,.tox,bin,dist,tools,*.egg-info

View File

@ -6,39 +6,43 @@ _cafe_runner()
#get current word. sed for windows backslash
cur=$(echo "${COMP_WORDS[COMP_CWORD]}"|sed 's/\\/\\\\/g')
#Consumer only exists in the parallel runner
python -c "from cafe.drivers.unittest.runner import Consumer" 2>/dev/null
#if status is == 0 then we are running parallel runner
status=$?
if [[ ${cur} == -* ]]; then
options='--help --test-repo --verbose --fail-fast --supress-load-tests --packages --module-regex --module --method-regex --tags --result --result-directory --parallel --dry-run --data-directory --data --list'
elif [[ ${COMP_CWORD} < 2 ]]; then
options=$(python -c "from cafe.drivers.unittest.autocomplete import print_products;print_products()" 2>/dev/null)
else
options=$(python -c "from cafe.drivers.unittest.autocomplete import print_configs_by_product;print_configs_by_product(\"${COMP_WORDS[1]}\")" 2>/dev/null)
fi
#parallel runner
if [ $status -eq 0 ]; then
if [[ ${cur} == -* ]]; then
options='--help --dry-run --exit-on-error --list --data-directory --regex-list --file --parallel --result --result-directory --tags --verbose --workers'
elif [[ ${COMP_CWORD} < 2 ]]; then
options=$(python -c "from cafe.drivers.unittest.autocomplete import print_configs;print_configs()")
else
options=$(python -c "from cafe.drivers.unittest.autocomplete import print_imports;print_imports(\"${cur}\")")
fi
else #normal runner
if [[ ${cur} == -* ]]; then
options='--help --test-repo --verbose --fail-fast --supress-load-tests --packages --module-regex --module --method-regex --tags --result --result-directory --parallel --dry-run --data-directory --data --list'
elif [[ ${COMP_CWORD} < 2 ]]; then
options=$(python -c "from cafe.drivers.unittest.autocomplete import print_products;print_products()")
else
options=$(python -c "from cafe.drivers.unittest.autocomplete import print_configs_by_product;print_configs_by_product(\"${COMP_WORDS[1]}\")")
fi
options=$(echo $options|sed 's/\\/\\\\/g')
COMPREPLY=( $(compgen -W '${options}' -- ${cur}) )
return 0
}
_cafe_parallel()
{
local cur options
COMPREPLY=()
#get current word. sed for windows backslash
cur=$(echo "${COMP_WORDS[COMP_CWORD]}"|sed 's/\\/\\\\/g')
if [[ ${cur} == -* ]]; then
options='--help --dry-run --exit-on-error --list --data-directory --regex-list --file --parallel --result --result-directory --tags --verbose --workers'
COMPREPLY="${COMPREPLY} "
elif [[ ${COMP_CWORD} < 2 ]]; then
options=$(python -c "from cafe.drivers.unittest.autocomplete import print_configs;print_configs()" 2>/dev/null)
COMPREPLY="${COMPREPLY} "
else
options=$(python -c "from cafe.drivers.unittest.autocomplete import print_imports;print_imports(\"${cur}\")" 2>/dev/null)
fi
#sed for windows backslash
options=$(echo $options|sed 's/\\/\\\\/g')
COMPREPLY=( $(compgen -W '${options}' -- ${cur}) )
if [[ ${cur} == -* || ${COMP_CWORD} < 2 ]]; then
COMPREPLY="${COMPREPLY} "
elif [ $status -ne 0 ]; then
COMPREPLY="${COMPREPLY} "
fi
return 0
}
complete -o nospace -F _cafe_runner cafe-runner
complete -F _cafe_runner cafe-runner
complete -o nospace -F _cafe_parallel cafe-parallel

View File

@ -109,6 +109,7 @@ setup(
entry_points={
'console_scripts':
['cafe-runner = cafe.drivers.unittest.runner:entry_point',
'cafe-parallel = cafe.drivers.unittest.runner_parallel:entry_point',
'behave-runner = cafe.drivers.behave.runner:entry_point',
'vows-runner = cafe.drivers.pyvows.runner:entry_point',
'specter-runner = cafe.drivers.specter.runner:entry_point',