diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 120a4cd..0000000 --- a/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -.idea -*.pyc -*.log -nosetests.xml -*.egg-info -/*.egg -.tox -build -dist -*.out -.coverage diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 60b9b4a..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -recursive-include ostf_adapter *.ini -recursive-include ostf_adapter * \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 1bdd076..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -fuel-ostf-plugin -================ diff --git a/README.rst b/README.rst index 6cc3eab..a031980 100644 --- a/README.rst +++ b/README.rst @@ -1,78 +1,2 @@ -SETUP: - - -1. System packages: - 1.1. Postgres server - 1.2. libpq-dev -2. Install pip-requirements - 2.1. python setup.py develop - Will install python dependencies, and two scripts - ostf-server - ostf-db -3. Migrate postgres database - ostf-db --config-file /etc/testing_adapter.conf upgrade head - TO REMOVE APPLIED MIGRATION USE: - ostf-db --config-file /etc/testing_adapter.conf downgrade -1 -4. ostf-server --config-file /etc/testing_adapter.conf - config-file should be in format of ./etc/testing_adapter.conf.sample - where database_connection just usual sqlalchemy url - - -BY DEFAULT database connection will be: -postgresql+psycopg2://adapter:demo@localhost/testing_adapter - -If you want logging to file : -ostf-server --log_file testing.log - -After installation hook -ostf-server --after-initialization-environment-hook --dbpath=postgresql+psycopg2://postgres:demo@localhost/testing_adapter -------------------------------------------------------------------------------------------------------------------------------------- - -USE: - -Design of OSTF REST API entities, urls and output format -Testset -GET /v1/testsets -Response: -[ - {id: "testset-nova-1", name: "Tests for nova"}, - {id: "testset-keystone-222", name: "Tests for keystone"}, - ... -] -Test -GET /v1/tests -Response: -[ - {id: "test_for_adapter.TestSimple.test_first_without_sleep_1", name: "Some test #1", testset: "testset-nova-1"}, - {id: "test_for_adapter.TestSimple.test_first_without_sleep_2", name: "Some test #2", testset: "testset-nova-1"}, - {id: "test_for_keystone.TestSimple.fgsfds", name: "Another test", testset: "testset-keystone-222"}, - ... -] -Testrun (history entry) -GET /v1/testruns -Response: -[ - {id: , testset: "testset-keystone-222", metadata: {...}, tests: [ - {id: "test_for_adapter.TestSimple.test_first_without_sleep_1", status: "running/success/error", message: "error message if error"}, - ... - ]}, - ... -] - -GET /v1/testruns/last/ -Response format is the same, but response contains only last entries filtered by cluster_id - -POST /v1/testruns (run the tests) -Request: -[ - {testset: "testset-keystone-222", metadata: {...}}, - ... -] -Response format is like GET reponse format (i.e. with status and id) - -PUT /v1/testruns (stop the tests) -Request: -[ - {id: , status: "stopped"}, - ... -] +Obsolete repo, please, take a look at fuel-ostf +=============================================== diff --git a/bin/__init__.py b/bin/__init__.py deleted file mode 100644 index 141ca6a..0000000 --- a/bin/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. diff --git a/bin/adapter_api.py b/bin/adapter_api.py deleted file mode 100644 index 10c59e3..0000000 --- a/bin/adapter_api.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Copyright 2013 Mirantis, Inc. -# -# 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 -from ostf_adapter import cli_config -from ostf_adapter import nailgun_hooks -from ostf_adapter import logger -from gevent import pywsgi -from ostf_adapter.wsgi import app -import logging -import signal -import pecan - - -def main(): - - cli_args = cli_config.parse_cli() - - config = { - 'server': { - 'host': cli_args.host, - 'port': cli_args.port - }, - 'dbpath': cli_args.dbpath, - 'debug': cli_args.debug, - 'debug_tests': cli_args.debug_tests - } - - logger.setup(log_file=cli_args.log_file) - - log = logging.getLogger(__name__) - - root = app.setup_app(config=config) - nailgun_hooks.nose_discovery.discovery(cli_args.debug_tests) - if getattr(cli_args, 'after_init_hook'): - return nailgun_hooks.after_initialization_environment_hook() - - host, port = pecan.conf.server.host, pecan.conf.server.port - srv = pywsgi.WSGIServer((host, int(port)), root) - - log.info('Starting server in PID %s', os.getpid()) - log.info("serving on http://%s:%s", host, port) - - try: - signal.signal(signal.SIGCHLD, signal.SIG_IGN) - srv.serve_forever() - except KeyboardInterrupt: - pass - - -if __name__ == '__main__': - main() diff --git a/functional/__init__.py b/functional/__init__.py deleted file mode 100644 index 53d87b0..0000000 --- a/functional/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -__author__ = 'ekonstantinov' - diff --git a/functional/base.py b/functional/base.py deleted file mode 100644 index b893773..0000000 --- a/functional/base.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 functools import wraps -from unittest import TestCase - -from ostf_client.client import TestingAdapterClient - - -class EmptyResponseError(Exception): - pass - - -class Response(object): - """This is testing_adapter response object""" - test_name_mapping = {} - - def __init__(self, response): - self.is_empty = False - if isinstance(response, list): - self._parse_json(response) - self.request = None - else: - self._parse_json(response.json()) - self.request = '{0} {1} \n with {2}'\ - .format(response.request.method, response.request.url, response.request.body) - - def __getattr__(self, item): - if item in self.test_sets or item in self._tests: - return self.test_sets.get(item) or self._tests.get(item) - else: - return super(type(self), self).__delattr__(item) - - def __str__(self): - if self.is_empty: - return "Empty" - return self.test_sets.__str__() - - @classmethod - def set_test_name_mapping(cls, mapping): - cls.test_name_mapping = mapping - - def _parse_json(self, json): - if json == [{}]: - self.is_empty = True - return - else: - self.is_empty = False - - self.test_sets = {} - self._tests = {} - for testset in json: - self.test_sets[testset.pop('testset')] = testset - self._tests = dict((self._friendly_name(item.get('id')), item) for item in testset['tests']) - - def _friendly_name(self, name): - return self.test_name_mapping.get(name, name) - - -class AdapterClientProxy(object): - - def __init__(self, url): - self.client = TestingAdapterClient(url) - - def __getattr__(self, item): - if item in TestingAdapterClient.__dict__: - call = getattr(self.client, item) - return self._decorate_call(call) - def _friendly_map(self, mapping): - Response.set_test_name_mapping(mapping) - - def _decorate_call(self, call): - @wraps(call) - def inner(*args, **kwargs): - r = call(*args, **kwargs) - return Response(r) - return inner - - - - -class SubsetException(Exception): - pass - - -class BaseAdapterTest(TestCase): - def compare(self, response, comparable): - if response.is_empty: - msg = '{0} is empty'.format(response.request) - raise AssertionError(msg) - if not isinstance(comparable, Response): - comparable = Response(comparable) - test_set = comparable.test_sets.keys()[0] - test_set_data = comparable.test_sets[test_set] - tests = comparable._tests - diff = [] - - for item in test_set_data: - if item == 'tests': - continue - if response.test_sets[test_set][item] != test_set_data[item]: - msg = 'Actual "{0}" != expected "{1}" in {2}.{3}'.format(response.test_sets[test_set][item], - test_set_data[item], test_set, item) - diff.append(msg) - - for test_name, test in tests.iteritems(): - for t in test: - if t == 'id': - continue - if response._tests[test_name][t] != test[t]: - msg = 'Actual "{0}" != expected"{1}" in {2}.{3}.{4}'.format(response._tests[test_name][t], - test[t], test_set, test_name, t) - diff.append(msg) - if diff: - raise AssertionError(diff) - - @staticmethod - def init_client(url, mapping): - ac = AdapterClientProxy(url) - ac._friendly_map(mapping) - return ac - - diff --git a/functional/config.py b/functional/config.py deleted file mode 100644 index 12d36f0..0000000 --- a/functional/config.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -__author__ = 'ekonstantinov' -CONFIG = {'compute-admin_password': 'nova', - 'compute-admin_tenant_name': '', - 'compute-admin_username': '', - 'compute_allow_tenant_isolation': 'True', - 'compute_allow_tenant_reuse': 'true', - 'compute_block_migrate_supports_cinder_iscsi': 'false', - 'compute_build_interval': '3', - 'compute_build_timeout': '300', - 'compute_catalog_type': 'compute', - 'compute_change_password_available': 'False', - 'compute_controller_node': '10.30.1.101', - 'compute_controller_node_name': 'fuel-controller-01.localdomain.', - 'compute_controller_node_ssh_password': 'r00tme', - 'compute_controller_node_ssh_user': 'root', - 'compute_create_image_enabled': 'true', - 'compute_disk_config_enabled_override': 'true', - 'compute_enabled_services': 'nova-cert, nova-consoleauth, nova-scheduler, nova-conductor, nova-cert, nova-consoleauth, nova-scheduler, nova-conductor, nova-cert, nova-consoleauth, nova-scheduler, nova-conductor, nova-compute', - 'compute_fixed_network_name': 'private', - 'compute_flavor_ref': '1', - 'compute_flavor_ref_alt': '2', - 'compute_image_alt_ssh_user': 'cirros', - 'compute_image_ref': '53734a0d-60a8-4689-b7c8-3c14917a7197', - 'compute_image_ref_alt': '53734a0d-60a8-4689-b7c8-3c14917a7197', - 'compute_image_ssh_user': 'cirros', - 'compute_ip_version_for_ssh': '4', - 'compute_live_migration_available': 'False', - 'compute_network_for_ssh': 'private', - 'compute_resize_available': 'true', - 'compute_run_ssh': 'false', - 'compute_ssh_channel_timeout': '60', - 'compute_ssh_timeout': '300', - 'compute_ssh_user': 'cirros', - 'compute_use_block_migration_for_live_migration': 'False', - 'identity_admin_password': 'nova', - 'identity_admin_tenant_name': 'admin', - 'identity_admin_username': 'admin', - 'identity_alt_password': 'nova', - 'identity_alt_tenant_name': 'alt_demo', - 'identity_alt_username': 'alt_demo', - 'identity_catalog_type': 'identity', - 'identity_disable_ssl_certificate_validation': 'False', - 'identity_password': 'nova', - 'identity_region': 'RegionOne', - 'identity_strategy': 'keystone', - 'identity_tenant_name': 'admin', - 'identity_uri': 'http://172.18.164.70:5000/v2.0/', - 'identity_url': 'http://172.18.164.70/', - 'identity_username': 'admin', - 'image_api_version': '1', - 'image_catalog_type': 'image', - 'image_http_image': 'http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz', - 'network_api_version': '2.0', - 'network_catalog_type': 'network', - 'network_public_network_id': 'cdb94175-2002-449f-be41-6b8afce8de13', - 'network_public_router_id': '2a6bf65b-01f7-4c91-840a-2b5f676e7016', - 'network_quantum_available': 'true', - 'network_tenant_network_cidr': '10.13.0.0/16', - 'network_tenant_network_mask_bits': '28', - 'network_tenant_networks_reachable': 'true', - 'object-storage_catalog_type': 'object-store', - 'object-storage_container_sync_interval': '5', - 'object-storage_container_sync_timeout': '120', - 'smoke_allow_tenant_isolation': 'True', - 'smoke_allow_tenant_reuse': 'true', - 'smoke_block_migrate_supports_cinder_iscsi': 'false', - 'smoke_build_interval': '3', - 'smoke_build_timeout': '300', - 'smoke_catalog_type': 'compute', - 'smoke_change_password_available': 'False', - 'smoke_create_image_enabled': 'true', - 'smoke_disk_config_enabled_override': 'true', - 'smoke_fixed_network_name': 'net04', - 'smoke_flavor_ref': '1', - 'smoke_flavor_ref_alt': '2', - 'smoke_image_alt_ssh_user': 'cirros', - 'smoke_image_ref': '53734a0d-60a8-4689-b7c8-3c14917a7197', - 'smoke_image_ref_alt': '53734a0d-60a8-4689-b7c8-3c14917a7197', - 'smoke_image_ssh_user': 'cirros', - 'smoke_ip_version_for_ssh': '4', - 'smoke_live_migration_available': 'False', - 'smoke_network_for_ssh': 'net04', - 'smoke_resize_available': 'true', - 'smoke_run_ssh': 'false', - 'smoke_ssh_channel_timeout': '60', - 'smoke_ssh_timeout': '320', - 'smoke_ssh_user': 'cirros', - 'smoke_use_block_migration_for_live_migration': 'False', - 'volume_backend1_name': 'BACKEND_1', - 'volume_backend2_name': 'BACKEND_2', - 'volume_build_interval': '3', - 'volume_build_timeout': '300', - 'volume_catalog_type': 'volume', - 'volume_multi_backend_enabled': 'false'} \ No newline at end of file diff --git a/functional/dummy_tests/__init__.py b/functional/dummy_tests/__init__.py deleted file mode 100644 index bc8f0be..0000000 --- a/functional/dummy_tests/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. \ No newline at end of file diff --git a/functional/dummy_tests/config_test.py b/functional/dummy_tests/config_test.py deleted file mode 100644 index 59d6193..0000000 --- a/functional/dummy_tests/config_test.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -__author__ = 'ekonstantinov' -from os import environ as env -from unittest import TestCase -from oslo.config import cfg - -opts = [ - cfg.StrOpt('quantum', default='ALALALALA') -] - -class Config(TestCase): - def test_config(self): - file_path = env['OSTF_CONF_PATH'] - cfg.CONF - - - - - - diff --git a/functional/dummy_tests/general_test.py b/functional/dummy_tests/general_test.py deleted file mode 100644 index 7a9ffe7..0000000 --- a/functional/dummy_tests/general_test.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -__profile__ = { - "id": "general_test", - "driver": "nose", - "test_path": "functional/dummy_tests/general_test.py", - "description": "General fake tests" -} - -import time -import httplib -import unittest - - -class Dummy_test(unittest.TestCase): - """Class docstring is required? - """ - - def test_fast_pass(self): - """fast pass test - This is a simple always pass test - Duration: 1sec - """ - self.assertTrue(True) - - def test_long_pass(self): - """Will sleep 5 sec - This is a simple test - it will run for 5 sec - Duration: 5sec - """ - time.sleep(5) - self.assertTrue(True) - - def test_fast_fail(self): - """Fast fail - """ - self.assertTrue(False, msg='Something goes wroooong') - - def test_fast_error(self): - """And fast error - """ - conn = httplib.HTTPSConnection('random.random/random') - conn.request("GET", "/random.aspx") - - def test_fail_with_step(self): - self.fail('Step 3 Failed: MEssaasasas') diff --git a/functional/dummy_tests/stopped_test.py b/functional/dummy_tests/stopped_test.py deleted file mode 100644 index 5e0f274..0000000 --- a/functional/dummy_tests/stopped_test.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -__profile__ = { - "id": "stopped_test", - "driver": "nose", - "test_path": "functional/dummy_tests/stopped_test.py", - "description": "Long running 25 secs fake tests" -} - -import time -import unittest - - -class dummy_tests_stopped(unittest.TestCase): - - def test_really_long(self): - """This is long running tests - Duration: 25sec - """ - time.sleep(25) - self.assertTrue(True) - - def test_one_no_so_long(self): - """What i am doing here? You ask me???? - """ - time.sleep(5) - self.assertFalse(1 == 2) - - def test_not_long_at_all(self): - """You know.. for testing - Duration: 1sec - """ - self.assertTrue(True) - diff --git a/functional/manual/create_and_kill.py b/functional/manual/create_and_kill.py deleted file mode 100644 index ea33cda..0000000 --- a/functional/manual/create_and_kill.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 requests -import json -import time -import pprint - -def make_requests(claster_id, test_set): - body = [{'testset': test_set, - 'metadata': {'config': {'identity_uri': 'hommeee'}, - 'cluster_id': claster_id} - } - ] - headers = {'Content-Type': 'application/json'} - response = requests.post('http://172.18.164.37:8777/v1/testruns', data=json.dumps(body), headers=headers) - pprint.pprint(response.json()) - _id = response.json()[0]['id'] - time.sleep(1) - body = [{'id': _id, 'status': 'stopped'}] - update = requests.put('http://172.18.164.37:8777/v1/testruns', data=json.dumps(body), headers=headers) - get_resp = requests.get('http://172.18.164.37:8777/v1/testruns/last/%s' % claster_id) - data = get_resp.json() - pprint.pprint(data) - -if __name__ == '__main__': - make_requests(11, 'fuel_health') \ No newline at end of file diff --git a/functional/manual/post_test_run_with_tests.py b/functional/manual/post_test_run_with_tests.py deleted file mode 100644 index b16ebb1..0000000 --- a/functional/manual/post_test_run_with_tests.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 requests -import json -import time - -import pprint - -def make_requests(claster_id, test_set): - tests = ['functional.dummy_tests.general_test.Dummy_test.test_fast_pass', - 'functional.dummy_tests.general_test.Dummy_test.test_fast_error'] - body = [{'testset': test_set, - 'tests': tests, - 'metadata': { - 'cluster_id': claster_id}}] - headers = {'Content-Type': 'application/json'} - response = requests.post('http://127.0.0.1:8989/v1/testruns', - data=json.dumps(body), headers=headers) - pprint.pprint(response.json()) - - -if __name__ == '__main__': - make_requests('101', 'plugin_general') \ No newline at end of file diff --git a/functional/manual/post_testrun.py b/functional/manual/post_testrun.py deleted file mode 100644 index c93b574..0000000 --- a/functional/manual/post_testrun.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 gevent -from gevent import monkey -monkey.patch_all() -import requests -import json -import time - -import pprint - -def make_requests(claster_id, test_set): - body = [{'testset': test_set, - 'metadata': {'config': {}, - 'cluster_id': claster_id}}] - headers = {'Content-Type': 'application/json'} - response = requests.post('http://127.0.0.1:8989/v1/testruns', - data=json.dumps(body), headers=headers) - pprint.pprint(response.json()) - - -if __name__ == '__main__': - make_requests('308', 'general_test') \ No newline at end of file diff --git a/functional/manual/put_test_run_with_tests.py b/functional/manual/put_test_run_with_tests.py deleted file mode 100644 index fe506c8..0000000 --- a/functional/manual/put_test_run_with_tests.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 requests -import json -import time - -import pprint - -def make_requests(claster_id, test_set): - tests = ['functional.dummy_tests.general_test.Dummy_test.test_long_pass'] - body = [{'id': claster_id, - 'tests': tests, - 'status': 'restarted', - }] - headers = {'Content-Type': 'application/json'} - response = requests.put('http://127.0.0.1:8989/v1/testruns', - data=json.dumps(body), headers=headers) - pprint.pprint(response.json()) - - -if __name__ == '__main__': - make_requests(370, 'plugin_general') \ No newline at end of file diff --git a/functional/manual/update_testrun.py b/functional/manual/update_testrun.py deleted file mode 100644 index 12dd40c..0000000 --- a/functional/manual/update_testrun.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 requests -import json -import time -import pprint - -def make_requests(claster_id, test_set): - body = [{'id': claster_id, 'status': 'stopped'}] - headers = {'Content-Type': 'application/json'} - update = requests.put( - 'http://localhost:8989/v1/testruns', - data=json.dumps(body), headers=headers) - data = update.json() - pprint.pprint(data) - -if __name__ == '__main__': - make_requests(378, 'plugin_stopped') \ No newline at end of file diff --git a/functional/scenario.py b/functional/scenario.py deleted file mode 100644 index bbe2f1c..0000000 --- a/functional/scenario.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 functional.base import BaseAdapterTest, Response - -import time - - -class ScenarioTests(BaseAdapterTest): - @classmethod - def setUpClass(cls): - - url = 'http://0.0.0.0:8989/v1' - mapping = {} - - cls.client = cls.init_client(url, mapping) - - def test_random_scenario(self): - testset = "fuel_sanity" - cluster_id = 3 - tests = [] - timeout = 60 - - from pprint import pprint - - for i in range(1): - r = self.client.run_with_timeout(testset, tests, cluster_id, timeout) - pprint([item for item in r.test_sets[testset]['tests']]) - if r.fuel_sanity['status'] == 'stopped': - running_tests = [test for test in r._tests - if r._tests[test]['status'] is 'stopped'] - print "restarting: ", running_tests - result = self.client.restart_with_timeout(testset, running_tests, cluster_id, timeout) - print 'Restart', result - - def test_run_fuel_sanity(self): - testset = "fuel_sanity" - cluster_id = 3 - tests = [] - - timeout = 240 - - r = self.client.run_with_timeout(testset, tests, cluster_id, timeout) - for item in r.fuel_sanity['tests']: - print item['id'].split('.').pop(), item - self.assertEqual(r.fuel_sanity['status'], 'finished') - - def test_run_fuel_smoke(self): - testset = "fuel_smoke" - cluster_id = 3 - tests = [] - timeout = 900 - - r = self.client.run_with_timeout(testset, tests, cluster_id, timeout) - for item in r.fuel_sanity['tests']: - print item['id'].split('.').pop(), item - self.assertEqual(r.fuel_smoke['status'], 'finished') diff --git a/functional/tests.py b/functional/tests.py deleted file mode 100644 index 00a57be..0000000 --- a/functional/tests.py +++ /dev/null @@ -1,254 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 time - -from functional.base import BaseAdapterTest, Response -from ostf_client.client import TestingAdapterClient as adapter - - -class AdapterTests(BaseAdapterTest): - - @classmethod - def setUpClass(cls): - - url = 'http://0.0.0.0:8989/v1' - - cls.mapping = { - 'functional.dummy_tests.general_test.Dummy_test.test_fast_pass': 'fast_pass', - 'functional.dummy_tests.general_test.Dummy_test.test_fast_error': 'fast_error', - 'functional.dummy_tests.general_test.Dummy_test.test_fast_fail': 'fast_fail', - 'functional.dummy_tests.general_test.Dummy_test.test_long_pass': 'long_pass', - 'functional.dummy_tests.general_test.Dummy_test.test_fail_with_step': 'fail_step', - 'functional.dummy_tests.stopped_test.dummy_tests_stopped.test_really_long': 'really_long', - 'functional.dummy_tests.stopped_test.dummy_tests_stopped.test_not_long_at_all': 'not_long', - 'functional.dummy_tests.stopped_test.dummy_tests_stopped.test_one_no_so_long': 'so_long' - } - cls.testsets = { - # "fuel_smoke": None, - # "fuel_sanity": None, - "general_test": ['fast_pass', 'fast_error', 'fast_fail', 'long_pass'], - "stopped_test": ['really_long', 'not_long', 'so_long'] - } - - cls.adapter = adapter(url) - cls.client = cls.init_client(url, cls.mapping) - - def test_list_testsets(self): - """Verify that self.testsets are in json response - """ - json = self.adapter.testsets().json() - response_testsets = [item['id'] for item in json] - for testset in self.testsets: - msg = '"{test}" not in "{response}"'.format(test=testset, response=response_testsets) - self.assertTrue(testset in response_testsets, msg) - - def test_list_tests(self): - """Verify that self.tests are in json response - """ - json = self.adapter.tests().json() - response_tests = [item['id'] for item in json] - - for test in self.mapping: - msg = '"{test}" not in "{response}"'.format(test=test.capitalize(), response=response_tests) - self.assertTrue(test in response_tests, msg) - - def test_run_testset(self): - """Verify that test status changes in time from running to success - """ - testset = "general_test" - cluster_id = 1 - - self.client.start_testrun(testset, cluster_id) - time.sleep(3) - - r = self.client.testruns_last(cluster_id) - - assertions = Response([{'status': 'running', - 'testset': 'general_test', - 'tests': [ - {'id': 'fast_pass', 'status': 'success', 'name': 'fast pass test', - 'description': """ This is a simple always pass test - """,}, - {'id': 'long_pass', 'status': 'running'}, - {'id': 'fail_step', 'message': 'MEssaasasas', 'status': 'failure'}, - {'id': 'fast_error', 'message': '', 'status': 'error'}, - {'id': 'fast_fail', 'message': 'Something goes wroooong', 'status': 'failure'}]}]) - - print r - print assertions - - self.compare(r, assertions) - time.sleep(10) - - r = self.client.testruns_last(cluster_id) - - assertions.general_test['status'] = 'finished' - assertions.long_pass['status'] = 'success' - - self.compare(r, assertions) - - def test_stop_testset(self): - """Verify that long running testrun can be stopped - """ - testset = "stopped_test" - cluster_id = 2 - - self.client.start_testrun(testset, cluster_id) - time.sleep(10) - r = self.client.testruns_last(cluster_id) - assertions = Response([ - {'status': 'running', - 'testset': 'stopped_test', - 'tests': [ - {'id': 'not_long', 'status': 'success'}, - {'id': 'so_long', 'status': 'success'}, - {'id': 'really_long', 'status': 'running'}]}]) - - self.compare(r, assertions) - - self.client.stop_testrun_last(testset, cluster_id) - r = self.client.testruns_last(cluster_id) - - assertions.stopped_test['status'] = 'finished' - assertions.really_long['status'] = 'stopped' - self.compare(r, assertions) - - def test_cant_start_while_running(self): - """Verify that you can't start new testrun for the same cluster_id while previous run is running""" - testsets = {"stopped_test": None, - "general_test": None} - cluster_id = 3 - - for testset in testsets: - self.client.start_testrun(testset, cluster_id) - self.client.testruns_last(cluster_id) - - for testset in testsets: - r = self.client.start_testrun(testset, cluster_id) - - msg = "Response {0} is not empty when you try to start testrun" \ - " with testset and cluster_id that are already running".format(r) - - self.assertTrue(r.is_empty, msg) - - def test_start_many_runs(self): - """Verify that you can start 20 testruns in a row with different cluster_id""" - testset = "general_test" - - for cluster_id in range(100, 105): - r = self.client.start_testrun(testset, cluster_id) - msg = '{0} was empty'.format(r.request) - self.assertFalse(r.is_empty, msg) - - '''TODO: Rewrite assertions to verity that all 5 testruns ended with appropriate status''' - - def test_run_single_test(self): - """Verify that you can run individual tests from given testset""" - testset = "general_test" - tests = ['functional.dummy_tests.general_test.Dummy_test.test_fast_pass', - 'functional.dummy_tests.general_test.Dummy_test.test_fast_fail'] - cluster_id = 50 - - r = self.client.start_testrun_tests(testset, tests, cluster_id) - assertions = Response([ - {'status': 'running', - 'testset': 'general_test', - 'tests': [ - {'status': 'disabled', 'id': 'fast_error'}, - {'status': 'wait_running', 'id': 'fast_fail'}, - {'status': 'wait_running', 'id': 'fast_pass'}, - {'status': 'disabled', 'id': 'long_pass'}]}]) - - self.compare(r, assertions) - time.sleep(2) - - r = self.client.testruns_last(cluster_id) - assertions.general_test['status'] = 'finished' - assertions.fast_fail['status'] = 'failure' - assertions.fast_pass['status'] = 'success' - self.compare(r, assertions) - - def test_single_test_restart(self): - """Verify that you restart individual tests for given testrun""" - testset = "general_test" - tests = ['functional.dummy_tests.general_test.Dummy_test.test_fast_pass', - 'functional.dummy_tests.general_test.Dummy_test.test_fast_fail'] - cluster_id = 60 - - self.client.run_testset_with_timeout(testset, cluster_id, 10) - - r = self.client.restart_tests_last(testset, tests, cluster_id) - assertions = Response([ - {'status': 'running', - 'testset': 'general_test', - 'tests': [ - {'id': 'fast_pass', 'status': 'wait_running'}, - {'id': 'long_pass', 'status': 'success'}, - {'id': 'fast_error', 'status': 'error'}, - {'id': 'fast_fail', 'status': 'wait_running'}]}]) - - self.compare(r, assertions) - time.sleep(5) - - r = self.client.testruns_last(cluster_id) - assertions.general_test['status'] = 'finished' - assertions.fast_pass['status'] = 'success' - assertions.fast_fail['status'] = 'failure' - - self.compare(r, assertions) - - def test_restart_combinations(self): - """Verify that you can restart both tests that ran and did not run during single test start""" - testset = "general_test" - tests = ['functional.dummy_tests.general_test.Dummy_test.test_fast_pass', - 'functional.dummy_tests.general_test.Dummy_test.test_fast_fail'] - disabled_test = ['functional.dummy_tests.general_test.Dummy_test.test_fast_error', ] - cluster_id = 70 - - self.client.run_with_timeout(testset, tests, cluster_id, 70) - self.client.restart_with_timeout(testset, tests, cluster_id, 10) - - r = self.client.restart_tests_last(testset, disabled_test, cluster_id) - assertions = Response([ - {'status': 'running', - 'testset': 'general_test', - 'tests': [ - {'status': 'wait_running', 'id': 'fast_error'}, - {'status': 'failure', 'id': 'fast_fail'}, - {'status': 'success', 'id': 'fast_pass'}, - {'status': 'disabled', 'id': 'long_pass'}]}]) - print r - self.compare(r, assertions) - time.sleep(5) - - r = self.client.testruns_last(cluster_id) - assertions.general_test['status'] = 'finished' - assertions.fast_error['status'] = 'error' - self.compare(r, assertions) - - def test_cant_restart_during_run(self): - testset = 'general_test' - tests = ['functional.dummy_tests.general_test.Dummy_test.test_fast_pass', - 'functional.dummy_tests.general_test.Dummy_test.test_fast_fail', - 'functional.dummy_tests.general_test.Dummy_test.test_fast_pass'] - cluster_id = 999 - - self.client.start_testrun(testset, cluster_id) - time.sleep(2) - - r = self.client.restart_tests_last(testset, tests, cluster_id) - msg = 'Response was not empty after trying to restart running testset:\n {0}'.format(r.request) - self.assertTrue(r.is_empty, msg) - diff --git a/ostf_adapter/__init__.py b/ostf_adapter/__init__.py deleted file mode 100644 index 141ca6a..0000000 --- a/ostf_adapter/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. diff --git a/ostf_adapter/cli_config.py b/ostf_adapter/cli_config.py deleted file mode 100644 index a49f6f9..0000000 --- a/ostf_adapter/cli_config.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 argparse -import sys - - -def parse_cli(): - parser = argparse.ArgumentParser() - parser.add_argument('--after-initialization-environment-hook', - action='store_true', dest='after_init_hook') - parser.add_argument('--debug', - action='store_true', dest='debug') - parser.add_argument( - '--dbpath', metavar='DB_PATH', - default='postgresql+psycopg2://adapter:demo@localhost/testing_adapter') - parser.add_argument('--host', default='127.0.0.1') - parser.add_argument('--port', default='8989') - parser.add_argument('--log_file', default=None, metavar='PATH') - parser.add_argument('--nailgun-host', default='127.0.0.1') - parser.add_argument('--nailgun-port', default='3232') - parser.add_argument('--debug_tests', default=None) - return parser.parse_args(sys.argv[1:]) diff --git a/ostf_adapter/logger.py b/ostf_adapter/logger.py deleted file mode 100644 index 96f0e1f..0000000 --- a/ostf_adapter/logger.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 logging -import logging.handlers - - -def setup(log_file=None): - formatter = logging.Formatter( - '[%(asctime)s] %(levelname)-8s %(message)s') - log = logging.getLogger(None) - stream_handler = logging.StreamHandler() - stream_handler.setLevel(logging.INFO) - stream_handler.setFormatter(formatter) - log.addHandler(stream_handler) - - if log_file: - log_file = os.path.abspath(log_file) - file_handler = logging.handlers.WatchedFileHandler(log_file) - file_handler.setLevel(logging.DEBUG) - mode = int('0644', 8) - os.chmod(log_file, mode) - file_handler.setFormatter(formatter) - log.addHandler(file_handler) - - log.setLevel(logging.INFO) diff --git a/ostf_adapter/nailgun_hooks.py b/ostf_adapter/nailgun_hooks.py deleted file mode 100644 index dc82f77..0000000 --- a/ostf_adapter/nailgun_hooks.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 logging -from ostf_adapter.storage import alembic_cli -from ostf_adapter.nose_plugin import nose_discovery -from pecan import conf - -LOG = logging.getLogger(__name__) - - -def after_initialization_environment_hook(): - """Expect 0 on success by nailgun - Exception is good enough signal that something goes wrong - """ - alembic_cli.do_apply_migrations() - nose_discovery.discovery(conf.debug_tests) - return 0 diff --git a/ostf_adapter/nose_plugin/__init__.py b/ostf_adapter/nose_plugin/__init__.py deleted file mode 100644 index 518f830..0000000 --- a/ostf_adapter/nose_plugin/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 stevedore import extension - - -_PLUGIN_MANAGER = None - - -def get_plugin(plugin): - global _PLUGIN_MANAGER - plugin_manager = _PLUGIN_MANAGER - - if plugin_manager is None: - PLUGINS_NAMESPACE = 'plugins' - plugin_manager = extension.ExtensionManager(PLUGINS_NAMESPACE, - invoke_on_load=True) - - _PLUGIN_MANAGER = plugin_manager - return _PLUGIN_MANAGER[plugin].obj \ No newline at end of file diff --git a/ostf_adapter/nose_plugin/nose_adapter.py b/ostf_adapter/nose_plugin/nose_adapter.py deleted file mode 100644 index 96b418e..0000000 --- a/ostf_adapter/nose_plugin/nose_adapter.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 logging - -from pecan import conf - -from ostf_adapter import storage -from ostf_adapter.nose_plugin import nose_utils -from ostf_adapter.nose_plugin import nose_storage_plugin -from ostf_adapter.nose_plugin import nose_test_runner -from ostf_adapter.storage import engine, models -from ostf_adapter.storage import storage_utils - - -LOG = logging.getLogger(__name__) - - -class NoseDriver(object): - def __init__(self): - LOG.warning('WTF') - self._named_threads = {} - session = engine.get_session() - with session.begin(subtransactions=True): - storage_utils.update_all_running_test_runs(session) - - def check_current_running(self, unique_id): - return unique_id in self._named_threads - - def run(self, test_run, test_set, tests=None): - """ - remove unneceserry arguments - spawn processes and send them tasks as to workers - """ - tests = tests or test_run.enabled_tests - if tests: - argv_add = [nose_utils.modify_test_name_for_nose(test) for test in - tests] - else: - argv_add = [test_set.test_path] + test_set.additional_arguments - - self._named_threads[test_run.id] = nose_utils.run_proc( - self._run_tests, test_run.id, test_run.cluster_id, argv_add) - - def _run_tests(self, test_run_id, cluster_id, argv_add): - session = engine.get_session() - try: - nose_test_runner.SilentTestProgram( - addplugins=[nose_storage_plugin.StoragePlugin( - test_run_id, str(cluster_id))], - exit=False, - argv=['ostf_tests'] + argv_add) - self._named_threads.pop(int(test_run_id), None) - except Exception, e: - LOG.exception('Test run: %s\n', test_run_id) - finally: - models.TestRun.update_test_run( - session, test_run_id, status='finished') - - def kill(self, test_run_id, cluster_id, cleanup=None): - session = engine.get_session() - if test_run_id in self._named_threads: - - self._named_threads[test_run_id].terminate() - self._named_threads.pop(test_run_id, None) - - if cleanup: - nose_utils.run_proc( - self._clean_up, - test_run_id, - cluster_id, - cleanup) - else: - models.TestRun.update_test_run( - session, test_run_id, status='finished') - - return True - return False - - def _clean_up(self, test_run_id, external_id, cleanup): - session = engine.get_session() - try: - module_obj = __import__(cleanup, -1) - - os.environ['NAILGUN_HOST'] = str(conf.nailgun.host) - os.environ['NAILGUN_PORT'] = str(conf.nailgun.port) - os.environ['CLUSTER_ID'] = str(external_id) - - module_obj.cleanup.cleanup() - - except Exception: - LOG.exception('EXCEPTION IN CLEANUP') - - finally: - models.TestRun.update_test_run( - session, test_run_id, status='finished') diff --git a/ostf_adapter/nose_plugin/nose_discovery.py b/ostf_adapter/nose_plugin/nose_discovery.py deleted file mode 100644 index 9cacf95..0000000 --- a/ostf_adapter/nose_plugin/nose_discovery.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 nose import plugins -import logging -import os - -from ostf_adapter.nose_plugin import nose_test_runner -from ostf_adapter.nose_plugin import nose_utils -from ostf_adapter.storage import engine, models - - -CORE_PATH = 'fuel_health' - -LOG = logging.getLogger(__name__) - - -class DiscoveryPlugin(plugins.Plugin): - - enabled = True - name = 'discovery' - score = 15000 - - def __init__(self): - self.test_sets = {} - super(DiscoveryPlugin, self).__init__() - - def options(self, parser, env=os.environ): - pass - - def configure(self, options, conf): - pass - - def afterImport(self, filename, module): - module = __import__(module, fromlist=[module]) - LOG.info('Inspecting %s', filename) - if hasattr(module, '__profile__'): - session = engine.get_session() - with session.begin(subtransactions=True): - LOG.info('%s discovered.', module.__name__) - test_set = models.TestSet(**module.__profile__) - test_set = session.merge(test_set) - session.add(test_set) - self.test_sets[test_set.id] = test_set - - def addSuccess(self, test): - test_id = test.id() - for test_set_id in self.test_sets.keys(): - if test_set_id in test_id: - session = engine.get_session() - with session.begin(subtransactions=True): - LOG.info('%s added for %s', test_id, test_set_id) - data = dict() - data['title'], data['description'], data['duration'] = \ - nose_utils.get_description(test) - old_test_obj = session.query(models.Test).filter_by( - name=test_id, test_set_id=test_set_id, - test_run_id=None).\ - update(data, synchronize_session=False) - if not old_test_obj: - data.update({'test_set_id': test_set_id, - 'name': test_id}) - test_obj = models.Test(**data) - session.add(test_obj) - - -def discovery(path=None): - """ - function to automaticly discover any test packages - """ - - tests = [CORE_PATH, path] if path else [CORE_PATH] - LOG.info('Starting discovery for %r.', tests) - nose_test_runner.SilentTestProgram( - addplugins=[DiscoveryPlugin()], - exit=False, - argv=['tests_discovery', '--collect-only'] + tests) diff --git a/ostf_adapter/nose_plugin/nose_storage_plugin.py b/ostf_adapter/nose_plugin/nose_storage_plugin.py deleted file mode 100644 index 9ad4e74..0000000 --- a/ostf_adapter/nose_plugin/nose_storage_plugin.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 time -import logging -import os - -from nose import plugins -from nose.suite import ContextSuite -from pecan import conf - -from ostf_adapter.nose_plugin import nose_utils -from ostf_adapter.storage import models -from ostf_adapter.storage import engine - - -LOG = logging.getLogger(__name__) - - -class StoragePlugin(plugins.Plugin): - enabled = True - name = 'storage' - score = 15000 - - def __init__( - self, test_run_id, cluster_id): - self.test_run_id = test_run_id - self.cluster_id = cluster_id - super(StoragePlugin, self).__init__() - self._start_time = None - - def options(self, parser, env=os.environ): - env['NAILGUN_HOST'] = str(conf.nailgun.host) - env['NAILGUN_PORT'] = str(conf.nailgun.port) - if self.cluster_id: - env['CLUSTER_ID'] = str(self.cluster_id) - - def configure(self, options, conf): - self.conf = conf - - def _add_message( - self, test, err=None, status=None): - data = { - 'status': status, - 'time_taken': self.taken - } - data['title'], data['description'], data['duration'] = \ - nose_utils.get_description(test) - if err: - exc_type, exc_value, exc_traceback = err - data['step'], data['message'] = None, u'' - if not status == 'error': - data['step'], data['message'] = \ - nose_utils.format_failure_message(exc_value) - data['traceback'] = u'' - else: - data['step'], data['message'] = None, u'' - data['traceback'] = u'' - - session = engine.get_session() - - with session.begin(subtransactions=True): - - if isinstance(test, ContextSuite): - for sub_test in test._tests: - data['title'], data['description'], data['duration'] = \ - nose_utils.get_description(test) - models.Test.add_result( - session, self.test_run_id, sub_test.id(), data) - else: - models.Test.add_result( - session, self.test_run_id, test.id(), data) - - def addSuccess(self, test, capt=None): - self._add_message(test, status='success') - - def addFailure(self, test, err): - LOG.error('%s', test.id(), exc_info=err) - self._add_message(test, err=err, status='failure') - - def addError(self, test, err): - if err[0] == AssertionError: - LOG.error('%s', test.id(), exc_info=err) - self._add_message( - test, err=err, status='failure') - else: - LOG.error('%s', test.id(), exc_info=err) - self._add_message(test, err=err, status='error') - - def beforeTest(self, test): - self._start_time = time() - self._add_message(test, status='running') - - def describeTest(self, test): - return test.test._testMethodDoc - - @property - def taken(self): - if self._start_time: - return time() - self._start_time - return 0 diff --git a/ostf_adapter/nose_plugin/nose_test_runner.py b/ostf_adapter/nose_plugin/nose_test_runner.py deleted file mode 100644 index c2ba0f7..0000000 --- a/ostf_adapter/nose_plugin/nose_test_runner.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 nose import core - - -class SilentTestRunner(core.TextTestRunner): - def run(self, test): - """Overrides to provide plugin hooks and defer all output to - the test result class. - """ - result = self._makeResult() - test(result) - return result - - -class SilentTestProgram(core.TestProgram): - def runTests(self): - """Run Tests. Returns true on success, false on failure, and sets - self.success to the same value. - """ - self.testRunner = SilentTestRunner(stream=self.config.stream, - verbosity=0, - config=self.config) - return self.testRunner.run(self.test).wasSuccessful() diff --git a/ostf_adapter/nose_plugin/nose_utils.py b/ostf_adapter/nose_plugin/nose_utils.py deleted file mode 100644 index 1b87e75..0000000 --- a/ostf_adapter/nose_plugin/nose_utils.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 traceback -import re -import json -import os -import multiprocessing - -from nose import case - - -def parse_json_file(file_path): - current_directory = os.path.dirname(os.path.realpath(__file__)) - commands_path = os.path.join( - current_directory, file_path) - with open(commands_path, 'r') as f: - return json.load(f) - - -def get_exc_message(exception_value): - """ - @exception_value - Exception type object - """ - _exc_long = str(exception_value) - if isinstance(_exc_long, basestring): - return _exc_long.split('\n')[0] - return u"" - - -def get_description(test_obj): - if isinstance(test_obj, case.Test): - docstring = test_obj.shortDescription() - - if docstring: - duration_pattern = r'Duration:.?(?P.+)' - duration_matcher = re.search(duration_pattern, docstring) - if duration_matcher: - duration = duration_matcher.group(1) - docstring = docstring[:duration_matcher.start()] - else: - duration = None - docstring = docstring.split('\n') - name = docstring.pop(0) - description = u'\n'.join(docstring) if docstring else u"" - - return name, description, duration - return u"", u"", u"" - - -def modify_test_name_for_nose(test_path): - test_module, test_class, test_method = test_path.rsplit('.', 2) - return '{0}:{1}.{2}'.format(test_module, test_class, test_method) - - -def format_exception(exc_info): - ec, ev, tb = exc_info - - # formatError() may have turned our exception object into a string, and - # Python 3's traceback.format_exception() doesn't take kindly to that (it - # expects an actual exception object). So we work around it, by doing the - # work ourselves if ev is a string. - if isinstance(ev, basestring): - tb_data = ''.join(traceback.format_tb(tb)) - return tb_data + ev - else: - return ''.join(traceback.format_exception(*exc_info)) - - -def format_failure_message(message): - message = get_exc_message(message) - matcher = re.search( - r'^[a-zA-Z]+\s?(\d+)\s?[a-zA-Z]+\s?[\.:]\s?(.+)', - message) - if matcher: - step, msg = matcher.groups() - return int(step), msg - return None, message - - -def run_proc(func, *args): - proc = multiprocessing.Process( - target=func, - args=args) - proc.daemon = True - proc.start() - return proc - - -def get_module(module_path): - pass diff --git a/ostf_adapter/storage/__init__.py b/ostf_adapter/storage/__init__.py deleted file mode 100644 index 141ca6a..0000000 --- a/ostf_adapter/storage/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. diff --git a/ostf_adapter/storage/alembic.ini b/ostf_adapter/storage/alembic.ini deleted file mode 100644 index 3139d9c..0000000 --- a/ostf_adapter/storage/alembic.ini +++ /dev/null @@ -1,49 +0,0 @@ -# A generic, single database configuration. - -[alembic] -# path to migration scripts -script_location = migrations - -# template used to generate migration files -# file_template = %%(rev)s_%%(slug)s - -# set to 'true' to run the environment during -# the 'revision' command, regardless of autogenerate -# revision_environment = false - -sqlalchemy.url = postgresql+psycopg2://ostf:ostf@localhost/ostf - -# Logging configuration -[loggers] -keys = root,sqlalchemy,alembic - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = WARN -handlers = console -qualname = - -[logger_sqlalchemy] -level = WARN -handlers = -qualname = sqlalchemy.engine - -[logger_alembic] -level = INFO -handlers = -qualname = alembic - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(levelname)-5.5s [%(name)s] %(message)s -datefmt = %H:%M:%S diff --git a/ostf_adapter/storage/alembic_cli.py b/ostf_adapter/storage/alembic_cli.py deleted file mode 100644 index c731cd9..0000000 --- a/ostf_adapter/storage/alembic_cli.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 logging - -from alembic import command, config -from pecan import conf - - -log = logging.getLogger(__name__) - - -def do_apply_migrations(): - alembic_conf = config.Config( - os.path.join(os.path.dirname(__file__), 'alembic.ini') - ) - alembic_conf.set_main_option('script_location', - 'ostf_adapter.storage:migrations') - alembic_conf.set_main_option('sqlalchemy.url', conf.dbpath) - command.upgrade(alembic_conf, 'head') diff --git a/ostf_adapter/storage/engine.py b/ostf_adapter/storage/engine.py deleted file mode 100644 index bd53473..0000000 --- a/ostf_adapter/storage/engine.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 pecan import conf -from sqlalchemy import create_engine, orm, pool - - -_ENGINE = None -_MAKER = None - - -def get_session(autocommit=True, expire_on_commit=False): - """Return a SQLAlchemy session.""" - global _MAKER - global _SLAVE_MAKER - maker = _MAKER - - if maker is None: - engine = get_engine() - maker = get_maker(engine, autocommit, expire_on_commit) - - else: - _MAKER = maker - - session = maker() - return session - - -def get_engine(pool_type=None): - """Return a SQLAlchemy engine.""" - global _ENGINE - engine = _ENGINE - - if engine is None: - engine = create_engine(conf.dbpath, - poolclass=pool_type or pool.NullPool) - _ENGINE = engine - return engine - - -def get_maker(engine, autocommit=True, expire_on_commit=False): - """Return a SQLAlchemy sessionmaker using the given engine.""" - return orm.sessionmaker( - bind=engine, - autocommit=autocommit, - expire_on_commit=expire_on_commit) diff --git a/ostf_adapter/storage/fields.py b/ostf_adapter/storage/fields.py deleted file mode 100644 index 68f271d..0000000 --- a/ostf_adapter/storage/fields.py +++ /dev/null @@ -1,28 +0,0 @@ -import json - -from sqlalchemy.types import TypeDecorator, VARCHAR - - -class JsonField(TypeDecorator): - impl = VARCHAR - - def process_bind_param(self, value, dialect): - if value is not None: - value = json.dumps(value) - - return value - - def process_result_value(self, value, dialect): - if value is not None: - value = json.loads(value) - return value - - -class ListField(JsonField): - def process_bind_param(self, value, dialect): - value = list(value) if value else [] - super(ListField, self).process_bind_param(value, dialect) - - def process_result_value(self, value, dialect): - value = super(ListField, self).process_bind_param(value, dialect) - return list(value) if value else [] diff --git a/ostf_adapter/storage/migrations/README b/ostf_adapter/storage/migrations/README deleted file mode 100644 index 98e4f9c..0000000 --- a/ostf_adapter/storage/migrations/README +++ /dev/null @@ -1 +0,0 @@ -Generic single-database configuration. \ No newline at end of file diff --git a/ostf_adapter/storage/migrations/__init__.py b/ostf_adapter/storage/migrations/__init__.py deleted file mode 100644 index 141ca6a..0000000 --- a/ostf_adapter/storage/migrations/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. diff --git a/ostf_adapter/storage/migrations/env.py b/ostf_adapter/storage/migrations/env.py deleted file mode 100644 index f798633..0000000 --- a/ostf_adapter/storage/migrations/env.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 __future__ import with_statement -from logging.config import fileConfig - -from alembic import context -from sqlalchemy import engine_from_config, pool - -from ostf_adapter.storage import models - - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -fileConfig(config.config_file_name) - -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata -target_metadata = models.BASE.metadata - -# other values from the config, defined by the needs of env.py, -# can be acquired: -# my_important_option = config.get_main_option("my_important_option") -# ... etc. - - -def run_migrations_offline(): - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = config.get_main_option("sqlalchemy.url") - context.configure(url=url) - - with context.begin_transaction(): - context.run_migrations() - - -def run_migrations_online(): - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - engine = engine_from_config( - config.get_section(config.config_ini_section), - prefix='sqlalchemy.', - poolclass=pool.NullPool) - - connection = engine.connect() - context.configure( - connection=connection, - target_metadata=target_metadata - ) - - try: - with context.begin_transaction(): - context.run_migrations() - finally: - connection.close() - - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() diff --git a/ostf_adapter/storage/migrations/script.py.mako b/ostf_adapter/storage/migrations/script.py.mako deleted file mode 100644 index 04cd370..0000000 --- a/ostf_adapter/storage/migrations/script.py.mako +++ /dev/null @@ -1,22 +0,0 @@ -"""${message} - -Revision ID: ${up_revision} -Revises: ${down_revision} -Create Date: ${create_date} - -""" - -# revision identifiers, used by Alembic. -revision = ${repr(up_revision)} -down_revision = ${repr(down_revision)} - -from alembic import op -import sqlalchemy as sa -${imports if imports else ""} - -def upgrade(): -${upgrades if upgrades else "pass"} - - -def downgrade(): -${downgrades if downgrades else "pass"} diff --git a/ostf_adapter/storage/migrations/versions/12340edd992d_add_status_field_to_.py b/ostf_adapter/storage/migrations/versions/12340edd992d_add_status_field_to_.py deleted file mode 100644 index 0fbd4a1..0000000 --- a/ostf_adapter/storage/migrations/versions/12340edd992d_add_status_field_to_.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -"""Add status field to test run model - -Revision ID: 12340edd992d -Revises: 1e2c38f575fb -Create Date: 2013-07-03 17:38:42.632146 - -""" - -# revision identifiers, used by Alembic. -revision = '12340edd992d' -down_revision = '1e2c38f575fb' - -from alembic import op -import sqlalchemy as sa - - -def upgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.add_column( - 'test_runs', - sa.Column('status', sa.String(length=128), nullable=True)) - ### end Alembic commands ### - - -def downgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.drop_column('test_runs', 'status') - ### end Alembic commands ### diff --git a/ostf_adapter/storage/migrations/versions/1b28f7bc6476_database_refactoring.py b/ostf_adapter/storage/migrations/versions/1b28f7bc6476_database_refactoring.py deleted file mode 100644 index d9c6802..0000000 --- a/ostf_adapter/storage/migrations/versions/1b28f7bc6476_database_refactoring.py +++ /dev/null @@ -1,93 +0,0 @@ -"""Database refactoring - -Revision ID: 1b28f7bc6476 -Revises: 4e9905279776 -Create Date: 2013-08-07 13:20:06.373200 - -""" - -# revision identifiers, used by Alembic. -revision = '1b28f7bc6476' -down_revision = '4e9905279776' - -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import postgresql -from ostf_adapter.storage import fields - - -def upgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.add_column('test_runs', sa.Column('test_set_id', sa.String(length=128), - nullable=True)) - op.add_column('test_runs', - sa.Column('meta', fields.JsonField(), nullable=True)) - op.add_column('test_runs', - sa.Column('cluster_id', sa.Integer(), nullable=False)) - op.drop_column('test_runs', u'type') - op.drop_column('test_runs', u'stats') - op.drop_column('test_runs', u'external_id') - op.drop_column('test_runs', u'data') - op.alter_column('test_runs', 'status', - existing_type=sa.VARCHAR(length=128), - nullable=False) - op.add_column('test_sets', sa.Column('cleanup_path', sa.String(length=128), - nullable=True)) - op.add_column('test_sets', - sa.Column('meta', fields.JsonField(), nullable=True)) - op.add_column('test_sets', - sa.Column('driver', sa.String(length=128), nullable=True)) - op.add_column('test_sets', - sa.Column('additional_arguments', fields.ListField(), - nullable=True)) - op.add_column('test_sets', - sa.Column('test_path', sa.String(length=256), nullable=True)) - op.drop_column('test_sets', u'data') - op.add_column('tests', sa.Column('description', sa.Text(), nullable=True)) - op.add_column('tests', sa.Column('traceback', sa.Text(), nullable=True)) - op.add_column('tests', sa.Column('step', sa.Integer(), nullable=True)) - op.add_column('tests', sa.Column('meta', fields.JsonField(), - nullable=True)) - op.add_column('tests', - sa.Column('duration', sa.String(length=512), nullable=True)) - op.add_column('tests', sa.Column('message', sa.Text(), nullable=True)) - op.add_column('tests', - sa.Column('time_taken', sa.Float(), nullable=True)) - op.drop_column('tests', u'taken') - op.drop_column('tests', u'data') - ### end Alembic commands ### - - -def downgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.add_column('tests', sa.Column(u'data', sa.TEXT(), nullable=True)) - op.add_column('tests', sa.Column(u'taken', - postgresql.DOUBLE_PRECISION(precision=53), - nullable=True)) - op.drop_column('tests', 'time_taken') - op.drop_column('tests', 'message') - op.drop_column('tests', 'duration') - op.drop_column('tests', 'meta') - op.drop_column('tests', 'step') - op.drop_column('tests', 'traceback') - op.drop_column('tests', 'description') - op.add_column('test_sets', sa.Column(u'data', sa.TEXT(), nullable=True)) - op.drop_column('test_sets', 'test_path') - op.drop_column('test_sets', 'additional_arguments') - op.drop_column('test_sets', 'driver') - op.drop_column('test_sets', 'meta') - op.drop_column('test_sets', 'cleanup_path') - op.alter_column('test_runs', 'status', - existing_type=sa.VARCHAR(length=128), - nullable=True) - op.add_column('test_runs', sa.Column(u'data', sa.TEXT(), nullable=True)) - op.add_column('test_runs', - sa.Column(u'external_id', sa.VARCHAR(length=128), - nullable=True)) - op.add_column('test_runs', sa.Column(u'stats', sa.TEXT(), nullable=True)) - op.add_column('test_runs', - sa.Column(u'type', sa.VARCHAR(length=128), nullable=True)) - op.drop_column('test_runs', 'cluster_id') - op.drop_column('test_runs', 'meta') - op.drop_column('test_runs', 'test_set_id') - ### end Alembic commands ### diff --git a/ostf_adapter/storage/migrations/versions/1e2c38f575fb_storage_refactor.py b/ostf_adapter/storage/migrations/versions/1e2c38f575fb_storage_refactor.py deleted file mode 100644 index 2befb72..0000000 --- a/ostf_adapter/storage/migrations/versions/1e2c38f575fb_storage_refactor.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -"""Storage refactor - -Revision ID: 1e2c38f575fb -Revises: 1fcb29d29e03 -Create Date: 2013-07-02 22:43:00.844574 - -""" - -# revision identifiers, used by Alembic. -revision = '1e2c38f575fb' -down_revision = '1fcb29d29e03' - -from alembic import op -import sqlalchemy as sa - - -def upgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.create_table( - 'test_sets', - sa.Column('id', sa.String(length=128), nullable=False), - sa.Column('description', sa.String(length=128), nullable=True), - sa.Column('data', sa.Text(), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.add_column(u'test_runs', sa.Column('external_id', sa.String(length=128), - nullable=True)) - op.add_column(u'test_runs', sa.Column('stats', sa.Text(), nullable=True)) - op.add_column(u'tests', sa.Column('test_set_id', sa.String(length=128), - nullable=True)) - ### end Alembic commands ### - - -def downgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.drop_column(u'tests', 'test_set_id') - op.drop_column(u'test_runs', 'stats') - op.drop_column(u'test_runs', 'external_id') - op.drop_table('test_sets') - ### end Alembic commands ### diff --git a/ostf_adapter/storage/migrations/versions/1fcb29d29e03_initial_migration.py b/ostf_adapter/storage/migrations/versions/1fcb29d29e03_initial_migration.py deleted file mode 100644 index b7b30c7..0000000 --- a/ostf_adapter/storage/migrations/versions/1fcb29d29e03_initial_migration.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -"""initial migration - -Revision ID: 1fcb29d29e03 -Revises: None -Create Date: 2013-06-26 17:40:23.908062 - -""" - -# revision identifiers, used by Alembic. -revision = '1fcb29d29e03' -down_revision = None - -from alembic import op -import sqlalchemy as sa - - -def upgrade(): - ### commands auto generated by Alembic - please adjust! ### - - op.create_table( - 'test_runs', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('type', sa.String(length=128), nullable=True), - sa.Column('data', sa.Text(), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - - op.create_table( - 'tests', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(length=512), nullable=True), - sa.Column('status', sa.String(length=128), nullable=True), - sa.Column('taken', sa.Float(), nullable=True), - sa.Column('data', sa.Text(), nullable=True), - sa.Column('test_run_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['test_run_id'], ['test_runs.id'], ), - sa.PrimaryKeyConstraint('id') - ) - ### end Alembic commands ### - - -def downgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.drop_table('tests') - op.drop_table('test_runs') - ### end Alembic commands ### diff --git a/ostf_adapter/storage/migrations/versions/3e45add6471_add_title_column.py b/ostf_adapter/storage/migrations/versions/3e45add6471_add_title_column.py deleted file mode 100644 index c25c9c9..0000000 --- a/ostf_adapter/storage/migrations/versions/3e45add6471_add_title_column.py +++ /dev/null @@ -1,27 +0,0 @@ -"""add title column - -Revision ID: 3e45add6471 -Revises: 1b28f7bc6476 -Create Date: 2013-08-07 17:01:59.306413 - -""" - -# revision identifiers, used by Alembic. -revision = '3e45add6471' -down_revision = '1b28f7bc6476' - -from alembic import op -import sqlalchemy as sa - - -def upgrade(): -### commands auto generated by Alembic - please adjust! ### - op.add_column('tests', sa.Column('title', sa.String(length=512), - nullable=True)) - ### end Alembic commands ### - - -def downgrade(): -### commands auto generated by Alembic - please adjust! ### - op.drop_column('tests', 'title') - ### end Alembic commands ### diff --git a/ostf_adapter/storage/migrations/versions/4e9905279776_add_started_at_ended.py b/ostf_adapter/storage/migrations/versions/4e9905279776_add_started_at_ended.py deleted file mode 100644 index c40d79b..0000000 --- a/ostf_adapter/storage/migrations/versions/4e9905279776_add_started_at_ended.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -"""Add started_at , ended_at on TestRun model - -Revision ID: 4e9905279776 -Revises: 12340edd992d -Create Date: 2013-07-04 12:10:49.219213 - -""" - -# revision identifiers, used by Alembic. -revision = '4e9905279776' -down_revision = '12340edd992d' - -from alembic import op -import sqlalchemy as sa - - -def upgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.add_column('test_runs', - sa.Column('started_at', sa.DateTime(), nullable=True)) - op.add_column('test_runs', - sa.Column('ended_at', sa.DateTime(), nullable=True)) - ### end Alembic commands ### - - -def downgrade(): - ### commands auto generated by Alembic - please adjust! ### - op.drop_column('test_runs', 'ended_at') - op.drop_column('test_runs', 'started_at') - ### end Alembic commands ### diff --git a/ostf_adapter/storage/models.py b/ostf_adapter/storage/models.py deleted file mode 100644 index 9c5abb0..0000000 --- a/ostf_adapter/storage/models.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 datetime import datetime - -import sqlalchemy as sa -from sqlalchemy import desc -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import joinedload, relationship, object_mapper - -from ostf_adapter.storage import fields, engine -from ostf_adapter import nose_plugin - - -BASE = declarative_base() - - -class TestRun(BASE): - - __tablename__ = 'test_runs' - - STATES = ( - 'running', - 'finished' - ) - - id = sa.Column(sa.Integer(), primary_key=True) - cluster_id = sa.Column(sa.Integer(), nullable=False) - status = sa.Column(sa.Enum(*STATES, name='test_run_states'), - nullable=False) - meta = sa.Column(fields.JsonField()) - started_at = sa.Column(sa.DateTime, default=datetime.utcnow) - ended_at = sa.Column(sa.DateTime) - test_set_id = sa.Column(sa.String(128), sa.ForeignKey('test_sets.id')) - - test_set = relationship('TestSet', backref='test_runs') - tests = relationship('Test', backref='test_run', order_by='Test.name') - - def update(self, session, status): - self.status = status - if status == 'finished': - self.ended_at = datetime.utcnow() - session.add(self) - - @property - def enabled_tests(self): - return [test.name for test in self.tests if test.status != 'disabled'] - - def is_finished(self): - return self.status == 'finished' - - @property - def frontend(self): - test_run_data = { - 'id': self.id, - 'testset': self.test_set_id, - 'meta': self.meta, - 'cluster_id': self.cluster_id, - 'status': self.status, - 'started_at': self.started_at, - 'ended_at': self.ended_at, - 'tests': [] - } - if self.tests: - test_run_data['tests'] = [test.frontend for test in self.tests] - return test_run_data - - @classmethod - def add_test_run(cls, session, test_set, cluster_id, status='running', - tests=None): - predefined_tests = tests or [] - tests = session.query(Test).filter_by( - test_set_id=test_set, test_run_id=None) - test_run = cls(test_set_id=test_set, cluster_id=cluster_id, - status=status) - session.add(test_run) - for test in tests: - session.add(test.copy_test(test_run, predefined_tests)) - return test_run - - @classmethod - def get_last_test_run(cls, session, test_set, cluster_id): - test_run = session.query(cls). \ - filter_by(cluster_id=cluster_id, test_set_id=test_set). \ - order_by(desc(cls.id)).first() - return test_run - - @classmethod - def get_test_results(cls): - session = engine.get_session() - test_runs = session.query(cls). \ - options(joinedload('tests')). \ - order_by(desc(cls.id)) - session.commit() - session.close() - return test_runs - - @classmethod - def get_test_run(cls, session, test_run_id, joined=False): - if not joined: - test_run = session.query(cls). \ - filter_by(id=test_run_id).first() - else: - test_run = session.query(cls). \ - options(joinedload('tests')). \ - filter_by(id=test_run_id).first() - return test_run - - @classmethod - def update_test_run(cls, session, test_run_id, status=None): - updated_data = {} - if status: - updated_data['status'] = status - if status in ['finished']: - updated_data['ended_at'] = datetime.utcnow() - session.query(cls). \ - filter(cls.id == test_run_id). \ - update(updated_data, synchronize_session=False) - - @classmethod - def is_last_running(cls, session, test_set, cluster_id): - test_run = cls.get_last_test_run(session, test_set, cluster_id) - return not bool(test_run) or test_run.is_finished() - - @classmethod - def start(cls, session, test_set, metadata, tests): - plugin = nose_plugin.get_plugin(test_set.driver) - if cls.is_last_running(session, test_set.id, - metadata['cluster_id']): - test_run = cls.add_test_run( - session, test_set.id, - metadata['cluster_id'], tests=tests) - plugin.run(test_run, test_set) - return test_run.frontend - return {} - - def restart(self, session, tests=None): - """Restart test run with - if tests given they will be enabled - """ - if TestRun.is_last_running(session, - self.test_set_id, - self.cluster_id): - plugin = nose_plugin.get_plugin(self.test_set.driver) - self.update(session, 'running') - if tests: - Test.update_test_run_tests( - session, self.id, tests) - plugin.run(self, self.test_set, tests) - return self.frontend - return {} - - def stop(self, session): - """Stop test run if running - """ - plugin = nose_plugin.get_plugin(self.test_set.driver) - killed = plugin.kill( - self.id, self.cluster_id, - cleanup=self.test_set.cleanup_path) - if killed: - Test.update_running_tests( - session, self.id, status='stopped') - return self.frontend - - - -class TestSet(BASE): - - __tablename__ = 'test_sets' - - id = sa.Column(sa.String(128), primary_key=True) - description = sa.Column(sa.String(256)) - test_path = sa.Column(sa.String(256)) - driver = sa.Column(sa.String(128)) - additional_arguments = sa.Column(fields.ListField()) - cleanup_path = sa.Column(sa.String(128)) - meta = sa.Column(fields.JsonField()) - - tests = relationship('Test', - backref='test_set', order_by='Test.name') - - @property - def frontend(self): - return {'id': self.id, 'name': self.description} - - @classmethod - def get_test_set(cls, session, test_set): - return session.query(cls).filter_by(id=test_set).first() - - -class Test(BASE): - - __tablename__ = 'tests' - - STATES = ( - 'wait_running', - 'running', - 'failure', - 'success', - 'error', - 'stopped' - ) - - id = sa.Column(sa.Integer(), primary_key=True) - name = sa.Column(sa.String(512)) - title = sa.Column(sa.String(512)) - description = sa.Column(sa.Text()) - duration = sa.Column(sa.String(512)) - message = sa.Column(sa.Text()) - traceback = sa.Column(sa.Text()) - status = sa.Column(sa.Enum(*STATES, name='test_states')) - step = sa.Column(sa.Integer()) - time_taken = sa.Column(sa.Float()) - meta = sa.Column(fields.JsonField()) - - test_set_id = sa.Column(sa.String(128), sa.ForeignKey('test_sets.id')) - test_run_id = sa.Column(sa.Integer(), sa.ForeignKey('test_runs.id')) - - @property - def frontend(self): - return { - 'id': self.name, - 'testset': self.test_set_id, - 'name': self.title, - 'description': self.description, - 'duration': self.duration, - 'message': self.message, - 'step': self.step, - 'status': self.status, - 'taken': self.time_taken - } - - @classmethod - def add_result(cls, session, test_run_id, test_name, data): - session.query(cls).\ - filter_by(name=test_name, test_run_id=test_run_id).\ - update(data, synchronize_session=False) - - @classmethod - def update_running_tests(cls, session, test_run_id, status='stopped'): - session.query(cls). \ - filter(cls.test_run_id == test_run_id, - cls.status.in_(('running', 'wait_running'))). \ - update({'status': status}, synchronize_session=False) - - @classmethod - def update_test_run_tests(cls, session, test_run_id, - tests_names, status='wait_running'): - session.query(cls). \ - filter(cls.name.in_(tests_names), - cls.test_run_id == test_run_id). \ - update({'status': status}, synchronize_session=False) - - def copy_test(self, test_run, predefined_tests): - new_test = self.__class__() - mapper = object_mapper(self) - primary_keys = set([col.key for col in mapper.primary_key]) - for column in mapper.iterate_properties: - if column.key not in primary_keys: - setattr(new_test, column.key, getattr(self, column.key)) - new_test.test_run_id = test_run.id - if predefined_tests and new_test.name not in predefined_tests: - new_test.status = 'disabled' - else: - new_test.status = 'wait_running' - return new_test diff --git a/ostf_adapter/storage/storage_utils.py b/ostf_adapter/storage/storage_utils.py deleted file mode 100644 index d2ad7d6..0000000 --- a/ostf_adapter/storage/storage_utils.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 ostf_adapter.storage import models - - -def update_all_running_test_runs(session): - session.query(models.TestRun). \ - filter_by(status='running'). \ - update({'status': 'finished'}, synchronize_session=False) - session.query(models.Test). \ - filter(models.Test.status.in_(('running', 'wait_running'))). \ - update({'status': 'stopped'}, synchronize_session=False) diff --git a/ostf_adapter/wsgi/__init__.py b/ostf_adapter/wsgi/__init__.py deleted file mode 100644 index 141ca6a..0000000 --- a/ostf_adapter/wsgi/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. diff --git a/ostf_adapter/wsgi/app.py b/ostf_adapter/wsgi/app.py deleted file mode 100644 index c11c0b0..0000000 --- a/ostf_adapter/wsgi/app.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 pecan -from ostf_adapter.wsgi import hooks - - -PECAN_DEFAULT = { - 'server': { - 'host': '0.0.0.0', - 'port': 8989 - }, - 'app': { - 'root': 'ostf_adapter.wsgi.root.RootController', - 'modules': ['ostf_adapter.wsgi'] - }, - 'nailgun': { - 'host': '127.0.0.1', - 'port': 8000 - }, - 'dbpath': 'postgresql+psycopg2://ostf:ostf@localhost/ostf', - 'debug': False, - 'debug_tests': 'functional/dummy_tests' -} - - -def setup_config(pecan_config): - pecan_config.update(PECAN_DEFAULT) - pecan.conf.update(pecan_config) - - -def setup_app(config=None): - setup_config(config or {}) - app_hooks = [hooks.SessionHook()] - app = pecan.make_app( - pecan.conf.app.root, - debug=pecan.conf.debug, - force_canonical=True, - hooks=app_hooks - ) - return app diff --git a/ostf_adapter/wsgi/controllers.py b/ostf_adapter/wsgi/controllers.py deleted file mode 100644 index a4fd5e1..0000000 --- a/ostf_adapter/wsgi/controllers.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 json -import logging - -from pecan import rest, expose, request -from ostf_adapter.storage import models - -from sqlalchemy import desc, func, asc -from sqlalchemy.orm import joinedload - -LOG = logging.getLogger(__name__) - - -class BaseRestController(rest.RestController): - def _handle_get(self, method, remainder): - if len(remainder): - method_name = remainder[0] - if method.upper() in self._custom_actions.get(method_name, []): - controller = self._find_controller( - 'get_%s' % method_name, - method_name - ) - if controller: - return controller, remainder[1:] - return super(BaseRestController, self)._handle_get(method, remainder) - - -class TestsController(BaseRestController): - - @expose('json') - def get_one(self, test_name): - raise NotImplementedError() - - @expose('json') - def get_all(self): - with request.session.begin(subtransactions=True): - return [item.frontend for item - in request.session.query(models.Test).all()] - - -class TestsetsController(BaseRestController): - - @expose('json') - def get_one(self, test_set): - with request.session.begin(subtransactions=True): - test_set = request.session.query(models.TestSet)\ - .filter_by(id=test_set).first() - if test_set and isinstance(test_set, models.TestSet): - return test_set.frontend - return {} - - @expose('json') - def get_all(self): - with request.session.begin(subtransactions=True): - return [item.frontend for item - in request.session.query(models.TestSet).all()] - - -class TestrunsController(BaseRestController): - - _custom_actions = { - 'last': ['GET'], - } - - @expose('json') - def get_all(self): - with request.session.begin(subtransactions=True): - return [item.frontend for item - in request.session.query(models.TestRun).all()] - - @expose('json') - def get_one(self, test_run_id): - with request.session.begin(subtransactions=True): - test_run = request.session.query(models.TestRun)\ - .filter_by(id=test_run_id).first() - if test_run and isinstance(test_run, models.TestRun): - return test_run.frontend - return {} - - @expose('json') - def get_last(self, cluster_id): - with request.session.begin(subtransactions=True): - test_run_ids = request.session.query(func.max(models.TestRun.id)) \ - .group_by(models.TestRun.test_set_id).\ - filter_by(cluster_id=cluster_id) - test_runs = request.session.query(models.TestRun). \ - options(joinedload('tests')). \ - filter(models.TestRun.id.in_(test_run_ids)) - return [item.frontend for item in test_runs] - - @expose('json') - def post(self): - test_runs = json.loads(request.body) - res = [] - with request.session.begin(subtransactions=True): - for test_run in test_runs: - test_set = test_run['testset'] - metadata = test_run['metadata'] - tests = test_run.get('tests', []) - - test_set = models.TestSet.get_test_set( - request.session, test_set) - test_run = models.TestRun.start( - request.session, test_set, metadata, tests) - res.append(test_run) - return res - - @expose('json') - def put(self): - test_runs = json.loads(request.body) - data = [] - with request.session.begin(subtransactions=True): - for test_run in test_runs: - status = test_run.get('status') - tests=test_run.get('tests', []) - test_run = models.TestRun.get_test_run(request.session, - test_run['id']) - if status == 'stopped': - data.append(test_run.stop(request.session)) - elif status == 'restarted': - data.append(test_run.restart(request.session, tests=tests)) - return data diff --git a/ostf_adapter/wsgi/hooks.py b/ostf_adapter/wsgi/hooks.py deleted file mode 100644 index 688fe81..0000000 --- a/ostf_adapter/wsgi/hooks.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 logging - -from pecan import hooks -from stevedore import extension - -from ostf_adapter.storage import engine - - -LOG = logging.getLogger(__name__) - - -class ExceptionHandlingHook(hooks.PecanHook): - def on_error(self, state, e): - LOG.exception('Pecan state %s', state) - - -# class StorageHook(hooks.PecanHook): -# def __init__(self): -# super(StorageHook, self).__init__() -# self.storage = storage.get_storage() -# -# def before(self, state): -# state.request.storage = self.storage - - -class PluginsHook(hooks.PecanHook): - PLUGINS_NAMESPACE = 'plugins' - - def __init__(self): - super(PluginsHook, self).__init__() - self.plugin_manager = extension.ExtensionManager( - self.PLUGINS_NAMESPACE, invoke_on_load=True) - - def before(self, state): - state.request.plugin_manager = self.plugin_manager - - -class SessionHook(hooks.PecanHook): - - def before(self, state): - state.request.session = engine.get_session() diff --git a/ostf_adapter/wsgi/root.py b/ostf_adapter/wsgi/root.py deleted file mode 100644 index 706fd84..0000000 --- a/ostf_adapter/wsgi/root.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 pecan import expose -from ostf_adapter.wsgi import controllers - - -class V1Controller(object): - """ - TODO Rewrite it with wsme expose - """ - - tests = controllers.TestsController() - testsets = controllers.TestsetsController() - testruns = controllers.TestrunsController() - - -class RootController(object): - v1 = V1Controller() - - @expose('json', generic=True) - def index(self): - return {} diff --git a/ostf_client/__init__.py b/ostf_client/__init__.py deleted file mode 100644 index bc8f0be..0000000 --- a/ostf_client/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. \ No newline at end of file diff --git a/ostf_client/client.py b/ostf_client/client.py deleted file mode 100644 index 5fdafb0..0000000 --- a/ostf_client/client.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 requests -from json import dumps -import time - - -class TestingAdapterClient(object): - def __init__(self, url): - self.url = url - - def _request(self, method, url, data=None): - headers = {'content-type': 'application/json'} - - r = requests.request(method, url, data=data, headers=headers, timeout=30.0) - if 2 != r.status_code/100: - raise AssertionError('{method} "{url}" responded with ' - '"{code}" status code'.format( - method=method.upper(), - url=url, code=r.status_code)) - return r - - def __getattr__(self, item): - getters = ['testsets', 'tests', 'testruns'] - if item in getters: - url = ''.join([self.url, '/', item]) - return lambda: self._request('GET', url) - - def testruns_last(self, cluster_id): - url = ''.join([self.url, '/testruns/last/', - str(cluster_id)]) - return self._request('GET', url) - - def start_testrun(self, testset, cluster_id): - return self.start_testrun_tests(testset, [], cluster_id) - - def start_testrun_tests(self, testset, tests, cluster_id): - url = ''.join([self.url, '/testruns']) - data = [{'testset': testset, - 'tests': tests, - 'metadata': {'cluster_id': str(cluster_id)}}] - return self._request('POST', url, data=dumps(data)) - - def stop_testrun(self, testrun_id): - url = ''.join([self.url, '/testruns']) - data = [{"id": testrun_id, - "status": "stopped"}] - return self._request("PUT", url, data=dumps(data)) - - def stop_testrun_last(self, testset, cluster_id): - latest = self.testruns_last(cluster_id).json() - testrun_id = [item['id'] for item in latest - if item['testset'] == testset][0] - return self.stop_testrun(testrun_id) - - def restart_tests(self, tests, testrun_id): - url = ''.join([self.url, '/testruns']) - body = [{'id': str(testrun_id), - 'tests': tests, - 'status': 'restarted'}] - return self._request('PUT', url, data=dumps(body)) - - def restart_tests_last(self, testset, tests, cluster_id): - latest = self.testruns_last(cluster_id).json() - testrun_id = [item['id'] for item in latest - if item['testset'] == testset][0] - return self.restart_tests(tests, testrun_id) - - def _with_timeout(self, action, testset, cluster_id, - timeout, polling=5, polling_hook=None): - start_time = time.time() - json = action().json() - - if json == [{}]: - self.stop_testrun_last(testset, cluster_id) - time.sleep(1) - action() - - while time.time() - start_time <= timeout: - time.sleep(polling) - - current_response = self.testruns_last(cluster_id) - if polling_hook: - polling_hook(current_response) - current_status, current_tests = \ - [(item['status'], item['tests']) for item - in current_response.json() if item['testset'] == testset][0] - - if current_status == 'finished': - break - else: - stopped_response = self.stop_testrun_last(testset, cluster_id) - if polling_hook: - polling_hook(stopped_response) - stopped_response = self.testruns_last(cluster_id) - stopped_status = [item['status'] for item in stopped_response.json() - if item['testset'] == testset][0] - - msg = '{0} is still in {1} state. Now the state is {2}'.format( - testset, current_status, stopped_status) - msg_tests = '\n'.join(['{0} -> {1}, {2}'.format( - item['id'], item['status'], item['taken']) - for item in current_tests]) - raise AssertionError('\n'.join([msg, msg_tests])) - return current_response - - def run_with_timeout(self, testset, tests, cluster_id, timeout, polling=5, - polling_hook=None): - action = lambda: self.start_testrun_tests(testset, tests, cluster_id) - return self._with_timeout(action, testset, cluster_id, timeout, - polling, polling_hook) - - def run_testset_with_timeout(self, testset, cluster_id, timeout, - polling=5, polling_hook=None): - return self.run_with_timeout(testset, [], cluster_id, timeout, - polling, polling_hook) - - def restart_with_timeout(self, testset, tests, cluster_id, timeout): - action = lambda: self.restart_tests_last(testset, tests, cluster_id) - return self._with_timeout(action, testset, cluster_id, timeout) - - - diff --git a/ostf_client/ostf.py b/ostf_client/ostf.py deleted file mode 100755 index 83b4b5d..0000000 --- a/ostf_client/ostf.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python -"""Openstack testing framework client - -Usage: ostf.py run [-q] [--id=] [--tests=] [--url=] [--timeout=] - ostf.py list [] - - -q Show test run result only after finish - -h --help Show this screen - --tests= Tests to run - --id= Cluster id to use, default: OSTF_CLUSTER_ID or "1" - --url= Ostf url, default: OSTF_URL or http://0.0.0.0:8989/v1 - --timeout= Amount of time after which test_run will be stopped [default: 60] - -""" -import os -import sys - -from docopt import docopt -from clint.textui import puts, colored, columns, indent -from blessings import Terminal -from requests import get -from client import TestingAdapterClient - - -def get_cluster_id(): - try: - r = get('http://localhost:8000/api/clusters').json() - except: - return 0 - return next(item['id'] for item in r) - - -def main(): - t = Terminal() - args = docopt(__doc__, version='0.1') - test_set = args[''] - cluster_id = args['--id'] or os.environ.get('OSTF_CLUSTER_ID') \ - or get_cluster_id() or '1' - tests = args['--tests'] or [] - timeout = args['--timeout'] - quite = args['-q'] - url = args['--url'] or os.environ.get('OSTF_URL') \ - or 'http://0.0.0.0:8989/v1' - - client = TestingAdapterClient(url) - - def run(): - col = 60 - - statused = dict( - running='running', - wait_running='wait_running', - success=colored.green('success'), - finished=colored.blue('finished'), - failure=colored.red('failure'), - error=colored.red('error'), - stopped=colored.red('stopped') - ) - - tests = [test['id'].split('.')[-1] - for test in client.tests().json() - if test['testset'] == test_set] - - def print_results(item): - if isinstance(item, dict): - puts(columns([item['id'].split('.')[-1], col], - [statused[item['status']], col])) - else: - puts(columns([item[0], col], - [statused.get(item[1], item[1]), col])) - - def move_up(lines): - for _ in range(lines): - print t.move_up + t.move_left, - - def polling_hook(response): - current_status, current_tests = next( - (item['status'], item['tests']) for item in response.json() - if item['testset'] == test_set) - - move_up(len(current_tests) + 1) - - for test in current_tests: - print_results(test) - print_results(['General', current_status]) - - def quite_polling_hook(response): - if not quite_polling_hook.__dict__.get('published_tests'): - quite_polling_hook.__dict__['published_tests'] = [] - - current_status, current_tests = next( - (item['status'], item['tests']) for item in response.json() - if item['testset'] == test_set) - - finished_statuses = ['success', 'failure', 'stopped', 'error'] - - finished_tests = [item for item in current_tests - if item['status'] in finished_statuses - and item - not in quite_polling_hook.__dict__['published_tests']] - - for test in finished_tests: - print_results(test) - quite_polling_hook.__dict__['published_tests'].append(test) - - if current_status == 'finished': - print_results(['General', current_status]) - - if quite: - polling_hook = quite_polling_hook - else: - for test in tests: - print_results([test, 'wait_running']) - print_results(['General', 'running']) - - try: - r = client.run_testset_with_timeout(test_set, cluster_id, - timeout, 2, polling_hook) - except AssertionError as e: - return 1 - except KeyboardInterrupt as e: - r = client.stop_testrun_last(test_set, cluster_id) - print t.move_left + t.move_left, - polling_hook(r) - - tests = next(item['tests'] for item in r.json()) - return any(item['status'] != 'success' for item in tests) - - def list_tests(): - result = client.tests().json() - tests = (test for test in result if test['testset'] == test_set) - - col = 60 - puts(columns([(colored.red("ID")), col], - [(colored.red("NAME")), None])) - - for test in tests: - test_id = test['id'].split('.')[-1] - puts(columns([test_id, col], [test['name'], None])) - - return 0 - - def list_test_sets(): - result = client.testsets().json() - - col = 60 - puts(columns([(colored.red("ID")), col], - [(colored.red("NAME")), None])) - - for test_set in result: - puts(columns([test_set['id'], col], [test_set['name'], None])) - return 0 - - if args['run']: - return run() - if test_set: - return list_tests() - return list_test_sets() - -if __name__ == '__main__': - sys.exit(main()) - - - - - diff --git a/setup.py b/setup.py deleted file mode 100644 index 5e36e11..0000000 --- a/setup.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 multiprocessing -import setuptools - -requirements = [ - 'Mako==0.8.1', - 'MarkupSafe==0.18', - 'SQLAlchemy==0.8.2', - 'WebOb==1.2.3', - 'WebTest==2.0.6', - 'alembic==0.5.0', - 'argparse==1.2.1', - 'beautifulsoup4==4.2.1', - 'distribute==0.7.3', - 'gevent==0.13.8', - 'greenlet==0.4.1', - 'nose==1.3.0', - 'pecan==0.3.0', - 'psycogreen==1.0', - 'psycopg2==2.5.1', - 'simplegeneric==0.8.1', - 'six==1.3.0', - 'stevedore==0.10', - 'waitress==0.8.5', - 'wsgiref==0.1.2', - 'WSME==0.5b2' -] - -test_requires = [ - 'mock==1.0.1', - 'pep8==1.4.6', - 'py==1.4.15', - 'six==1.3.0', - 'tox==1.5.0', - 'unittest2', - 'nose', - 'requests' -] - -setuptools.setup( - - name='testing_adapter', - version='0.2', - - description='cloud computing testing', - - zip_safe=False, - - test_suite='tests', - - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Framework :: Setuptools Plugin', - 'Environment :: OpenStack', - 'Intended Audience :: Information Technology', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: POSIX :: Linux', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Topic :: System :: Testing', - ], - - packages=setuptools.find_packages( - exclude=['tests', 'utils', '*_tests']), - - include_package_data=True, - - install_requires=requirements, - - test_requires=test_requires, - - entry_points={ - 'plugins': [ - 'nose = ostf_adapter.nose_plugin.nose_adapter:NoseDriver' - ], - 'console_scripts': [ - 'ostf-server = bin.adapter_api:main', - 'update-commands = test_utils.update_commands:main' - ] - }, -) diff --git a/test_utils/__init__.py b/test_utils/__init__.py deleted file mode 100644 index bc8f0be..0000000 --- a/test_utils/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. \ No newline at end of file diff --git a/test_utils/cluster_id.py b/test_utils/cluster_id.py deleted file mode 100644 index 382b748..0000000 --- a/test_utils/cluster_id.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from requests import get -import sys - - -def main(): - try: - r = get('http://localhost:8000/api/clusters').json() - except IOError or ValueError as e: - print e.message - return 1 - - cluster_id = next(item['id'] for item in r) - print cluster_id - return 0 - -if __name__ == '__main__': - sys.exit(main()) - - diff --git a/test_utils/commands b/test_utils/commands deleted file mode 100755 index 30efa62..0000000 --- a/test_utils/commands +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash - -function killapp { - netstat -nplt | grep 8989 | grep -o [0-9]*/python | grep -o [0-9]* &> /dev/null || { echo "Not running" && return 1; } - while netstat -nplt | grep 8989 &> /dev/null; do - declare app_pid=$(netstat -nplt | grep 8989 | grep -o [0-9]*/python | grep -o [0-9]*) - echo "Ostf-adapter pid is: $app_pid" - kill -9 $app_pid; done -} - -function stopapp { - if netstat -nplt | grep 8989 &> /dev/null; then - supervisorctl stop ostf && killapp - else - echo "OSTF-server is not running" - fi -} - -function startapp { - if netstat -nplt | grep 8989 | grep -o [0-9]*/python | grep -o [0-9]* &> /dev/null; then - echo "Server is already running" && return 1; fi - - supervisorctl start ostf - touch testing.log - sleep 5 - count=1 - while ! tail -1 testing.log | grep "serving on" &> /dev/null || ((count != 20)) ; do sleep 3; ((count+=1)) ; done - nc -xvw 2 0.0.0.0 8989 &> /dev/null && echo "Working like a charm" || echo "Not working" -} - -function update_tests { - if [[ -z $1 && -z $OSTF_TESTS_BRANCH ]] ; then echo "Please specify a branch"; return 1; fi - if [[ ! -z $1 ]] ; then - git ls-remote --heads git@github.com:Mirantis/fuel-ostf-tests.git $1 | grep $1 &> /dev/null || { echo "No branch" && return 1; } - export OSTF_TESTS_BRANCH=$1 - fi - ! pip freeze | grep ostf-tests &> /dev/null || pip uninstall -y ostf-tests - pip install -e git+ssh://git@github.com/Mirantis/fuel-ostf-tests.git@"$OSTF_TESTS_BRANCH"#egg=ostf-tests -} - -function update_adapter { - if [[ -z $1 && -z $OSTF_ADAPTER_BRANCH ]] ; then echo "Please specify a branch"; return 1; fi - if [[ ! -z $1 ]] ; then - git ls-remote --heads git@github.com:Mirantis/fuel-ostf-plugin.git $1 | grep $1 &> /dev/null || { echo "No branch" && return 1; } - export OSTF_ADAPTER_BRANCH=$1 - fi - ! pip freeze | grep testing_adapter &> /dev/null || pip uninstall -y testing_adapter - pip install -e git+ssh://git@github.com/Mirantis/fuel-ostf-plugin.git@"$OSTF_ADAPTER_BRANCH"#egg=ostf-plugin -} - -function migrate_db { - service postgresql restart - while ! service postgresql status | grep running &> /dev/null; do sleep 1; done - sleep 30 - export PGPASSWORD='ostf' - psql -U postgres -h localhost -c "drop database if exists testing_adapter" - psql -U postgres -h localhost -c "drop user adapter" - psql -U postgres -h localhost -c "create role adapter with nosuperuser createdb password 'demo' login" - psql -U postgres -h localhost -c "create database testing_adapter" - - ostf-server --after-initialization-environment-hook --dbpath=postgresql+psycopg2://adapter:demo@localhost/testing_adapter - } - -function run_functional_tests { - [[ ! -z $WORKSPACE ]] || export WORKSPACE=$(pwd) - nosetests -q functional/tests.py:AdapterTests --with-xunit --xunit-file=$WORKSPACE/reports/functional.xml -} \ No newline at end of file diff --git a/test_utils/db_manage.sh b/test_utils/db_manage.sh deleted file mode 100644 index 3cbbca3..0000000 --- a/test_utils/db_manage.sh +++ /dev/null @@ -1,5 +0,0 @@ -export PGPASSWORD='ostf' -psql -U postgres -h localhost -c "drop user adapter" -psql -U postgres -h localhost -c "create role adapter with nosuperuser createdb password 'demo' login" -psql -U postgres -h localhost -c "drop database if exists testing_adapter" -psql -U postgres -h localhost -c "create database testing_adapter" \ No newline at end of file diff --git a/test_utils/pylintrc b/test_utils/pylintrc deleted file mode 100644 index 3f8e00b..0000000 --- a/test_utils/pylintrc +++ /dev/null @@ -1,236 +0,0 @@ -[MASTER] - -# Specify a configuration file. -#rcfile= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Profiled execution. -profile=no - -# Add to the black list. It should be a base name, not a -# path. You may set this option multiple times. -ignore=CVS - -# Pickle collected data for later comparisons. -persistent=yes - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - - -[MESSAGES CONTROL] - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifier separated by comma (,) or put this option -# multiple time. -disable=F0401,R0201,W0311,C0111 - - -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html -output-format=parseable - -# Include message's id in output -include-ids=yes - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no - -# Tells whether to display a full report or only the messages -reports=yes - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (R0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Add a comment according to your evaluation note. This is used by the global -# evaluation report (R0004). -comment=no - - -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=120 - -# Maximum number of lines in a module -max-module-lines=1000 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - - -[VARIABLES] - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching names used for dummy variables (i.e. not used). -dummy-variables-rgx=_|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - - -[TYPECHECK] - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# List of classes names for which member attributes should not be checked -# (useful for classes with attributes dynamically set). -ignored-classes=SQLObject - -# When zope mode is activated, add a predefined set of Zope acquired attributes -# to generated-members. -zope=no - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E0201 when accessed. -generated-members=REQUEST,acl_users,aq_parent - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[BASIC] - -# Required attributes for module, separated by a comma -required-attributes= - -# List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter,apply,input - -# Regular expression which should only match correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression which should only match correct module level names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression which should only match correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression which should only match correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct method names -method-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct instance attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct list comprehension / -# generator expression variable names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Good variable names which should always be accepted, separated by a comma -good-names=app,uwsgi,e,i,j,k,ex,Run,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Regular expression which should only match functions or classes name which do -# not require a docstring -no-docstring-rgx=__.*__|[Tt]est.* - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.* - -# Maximum number of locals for function / method body -max-locals=20 - -# Maximum number of return / yield for function / method body -max-returns=10 - -# Maximum number of branch for function / method body -max-branchs=12 - -# Maximum number of statements in function / method body -max-statements=50 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=10 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=0 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - - -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,string,TERMIOS,Bastion,rexec - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - - -[CLASSES] - -# List of interface methods to ignore, separated by a comma. This is used for -# instance to not check methods defines in Zope's Interface base class. -ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp \ No newline at end of file diff --git a/test_utils/update_commands.py b/test_utils/update_commands.py deleted file mode 100644 index 01a4e61..0000000 --- a/test_utils/update_commands.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. - -__author__ = 'ekonstantinov' -from json import loads, dumps - - -def main(): - with open('ostf_adapter/commands.json', 'rw+') as commands: - data = loads(commands.read()) - for item in data: - if 'argv' in data[item] and item in ['fuel_sanity', 'fuel_smoke']: - if "--with-xunit" not in data[item]['argv']: - data[item]['argv'].extend(["--with-xunit", '--xunit-file={0}.xml'.format(item)]) - elif item in ['fuel_sanity', 'fuel_smoke']: - data[item]['argv'] = ["--with-xunit", ] - test_apps = {"plugin_general": {"test_path": "tests/functional/dummy_tests/general_test.py", "driver": "nose"}, - "plugin_stopped": {"test_path": "tests/functional/dummy_tests/stopped_test.py", "driver": "nose"}} - if 'plugin_general' not in data or 'plugin_stopped' not in data: - data.update(test_apps) - commands.seek(0) - commands.write(dumps(data)) - commands.truncate() - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index bc8f0be..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. \ No newline at end of file diff --git a/tests/test_nose_discovery.py b/tests/test_nose_discovery.py deleted file mode 100644 index ba08b86..0000000 --- a/tests/test_nose_discovery.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 unittest2 -from ostf_adapter.nose_plugin import nose_discovery -from mock import patch -from ostf_adapter.storage import models - - -stopped__profile__ = { - "id": "stopped_test", - "driver": "nose", - "test_path": "functional/dummy_tests/stopped_test.py", - "description": "Long running 25 secs fake tests" -} -general__profile__ = { - "id": "general_test", - "driver": "nose", - "test_path": "functional/dummy_tests/general_test.py", - "description": "General fake tests" -} - - -@patch('ostf_adapter.nose_plugin.nose_discovery.engine') -class TestNoseDiscovery(unittest2.TestCase): - - def setUp(self): - self.fixtures = [models.TestSet(**stopped__profile__), - models.TestSet(**general__profile__)] - self.fixtures_iter = iter(self.fixtures) - - def test_discovery(self, engine): - engine.get_session().merge.return_value = \ - lambda *args, **kwargs: self.fixtures_iter.next() - nose_discovery.discovery(path='functional/dummy_tests') - self.assertEqual(engine.get_session().merge.call_count, 2) - diff --git a/tests/test_nose_storage_plugin.py b/tests/test_nose_storage_plugin.py deleted file mode 100644 index bc8f0be..0000000 --- a/tests/test_nose_storage_plugin.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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. \ No newline at end of file diff --git a/tests/test_sql_storage.py b/tests/test_sql_storage.py deleted file mode 100644 index 34240ba..0000000 --- a/tests/test_sql_storage.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 unittest2 - - -class TestSqlStorage(unittest2.TestCase): - - def test_add_test_run(self): - pass \ No newline at end of file diff --git a/tests/test_wsgi_controllers.py b/tests/test_wsgi_controllers.py deleted file mode 100644 index 73943ff..0000000 --- a/tests/test_wsgi_controllers.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 ostf_adapter.wsgi import controllers -from ostf_adapter.storage import models -import unittest2 -from mock import patch, MagicMock -import json - - -@patch('ostf_adapter.wsgi.controllers.request') -class TestTestsController(unittest2.TestCase): - - def setUp(self): - self.fixtures = [models.Test(), models.Test()] - self.controller = controllers.TestsController() - - def test_get_all(self, request): - request.session.query().all.return_value =\ - self.fixtures - res = self.controller.get_all() - self.assertEqual(res, [f.frontend for f in self.fixtures]) - - def test_get_one(self, request): - pass - - -@patch('ostf_adapter.wsgi.controllers.request') -class TestTestSetsController(unittest2.TestCase): - - def setUp(self): - self.fixtures = [models.TestSet(), models.TestSet()] - self.controller = controllers.TestsetsController() - - def test_get_all(self, request): - request.session.query().all.return_value =\ - self.fixtures - res = self.controller.get_all() - self.assertEqual(res, [f.frontend for f in self.fixtures]) - - def test_get_one(self, request): - pass - -@patch('ostf_adapter.wsgi.controllers.request') -class TestTestRunsController(unittest2.TestCase): - - def setUp(self): - self.fixtures = [models.TestRun(status='finished'), - models.TestRun(status='running')] - self.fixtures[0].test_set = models.TestSet(driver='nose') - self.storage = MagicMock() - self.plugin = MagicMock() - self.session = MagicMock() - self.controller = controllers.TestrunsController() - - def test_get_all(self, request): - request.session.query().all.return_value =\ - self.fixtures - res = self.controller.get_all() - self.assertEqual(res, [f.frontend for f in self.fixtures]) - - def test_get_one(self, request): - request.session.query().filter_by().first.return_value =\ - self.fixtures[0] - res = self.controller.get_one(1) - self.assertEqual(res, self.fixtures[0].frontend) - - @patch('ostf_adapter.wsgi.controllers.models') - def test_post(self, models, request): - request.storage = self.storage - testruns = [ - {'testset': 'test_simple', - 'metadata': {'cluster_id': 3} - }, - {'testset': 'test_simple', - 'metadata': {'cluster_id': 4} - }] - request.body = json.dumps(testruns) - fixtures_iterable = (f.frontend for f in self.fixtures) - - models.TestRun.start.side_effect = \ - lambda *args, **kwargs: fixtures_iterable.next() - res = self.controller.post() - self.assertEqual(res, [f.frontend for f in self.fixtures]) - - @patch('ostf_adapter.wsgi.controllers.models') - def test_put_stopped(self, models, request): - request.storage = self.storage - testruns = [ - {'id': 1, - 'metadata': {'cluster_id': 4}, - 'status': 'stopped' - }] - request.body = json.dumps(testruns) - - models.TestRun.get_test_run().stop.side_effect = \ - lambda *args, **kwargs: self.fixtures[0].frontend - res = self.controller.put() - self.assertEqual(res, [self.fixtures[0].frontend]) - - @patch('ostf_adapter.wsgi.controllers.models') - def test_put_restarted(self, models, request): - request.storage = self.storage - testruns = [ - {'id': 1, - 'metadata': {'cluster_id': 4}, - 'status': 'restarted' - }] - request.body = json.dumps(testruns) - - models.TestRun.get_test_run().restart.side_effect = \ - lambda *args, **kwargs: self.fixtures[0].frontend - res = self.controller.put() - self.assertEqual(res, [self.fixtures[0].frontend]) - - def test_get_last(self, request): - cluster_id = 1 - request.session.query().group_by().filter_by.return_value = [10, 11] - request.session.query().options().filter.return_value = self.fixtures - res = self.controller.get_last(cluster_id) - self.assertEqual(res, [f.frontend for f in self.fixtures]) diff --git a/tests/tests_wsgi_interface.py b/tests/tests_wsgi_interface.py deleted file mode 100644 index 56dbbf2..0000000 --- a/tests/tests_wsgi_interface.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2013 Mirantis, Inc. -# -# 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 unittest2 -from mock import patch, MagicMock -from webtest import TestApp -from ostf_adapter.wsgi import app -import json - - -@patch('ostf_adapter.wsgi.controllers.request') -class WsgiInterfaceTests(unittest2.TestCase): - - def setUp(self): - self.app = TestApp(app.setup_app()) - - def test_get_all_tests(self, request): - self.app.get('/v1/tests') - - def test_get_one_test(self, request): - self.assertRaises(NotImplementedError, - self.app.get, - '/v1/tests/1') - - def test_get_all_testsets(self, request): - self.app.get('/v1/testsets') - - def test_get_one_testset(self, request): - self.app.get('/v1/testsets/plugin_test') - - def test_get_one_testruns(self, request): - self.app.get('/v1/testruns/1') - - def test_get_all_testruns(self, request): - self.app.get('/v1/testruns') - - @patch('ostf_adapter.wsgi.controllers.models') - def test_post_testruns(self, models, request): - testruns = [ - {'testset': 'test_simple', - 'metadata': {'cluster_id': 3} - }, - {'testset': 'test_simple', - 'metadata': {'cluster_id': 4} - }] - request.body = json.dumps(testruns) - models.TestRun.start.return_value = {} - self.app.post_json('/v1/testruns', testruns) - - def test_put_testruns(self, request): - testruns = [ - {'id': 2, - 'metadata': {'cluster_id': 3}, - 'status': 'non_exist' - }, - {'id': 1, - 'metadata': {'cluster_id': 4}, - 'status': 'non_exist' - }] - request.body = json.dumps(testruns) - request.storage.get_test_run.return_value = MagicMock(frontend={}) - self.app.put_json('/v1/testruns', testruns) - - def test_get_last_testruns(self, request): - self.app.get('/v1/testruns/last/101') \ No newline at end of file diff --git a/tools/commands-requires b/tools/commands-requires deleted file mode 100644 index 40e888b..0000000 --- a/tools/commands-requires +++ /dev/null @@ -1 +0,0 @@ -git+ssh://git@github.com/Mirantis/fuel-ostf-tests.git@stable#egg=ostf-tests==0.1 \ No newline at end of file diff --git a/tools/pip-requires b/tools/pip-requires deleted file mode 100644 index f2c4a48..0000000 --- a/tools/pip-requires +++ /dev/null @@ -1,20 +0,0 @@ -'Mako==0.8.1' -'MarkupSafe==0.18' -'SQLAlchemy==0.8.2' -'WebOb==1.2.3' -'WebTest==2.0.6' -'alembic==0.5.0' -'argparse==1.2.1' -'beautifulsoup4==4.2.1' -'distribute==0.7.3' -'gevent==0.13.8' -'greenlet==0.4.1' -'nose==1.3.0' -'pecan==0.3.0' -'psycogreen==1.0' -'psycopg2==2.5.1' -'simplegeneric==0.8.1' -'six==1.3.0' -'stevedore==0.10' -'waitress==0.8.5' -'wsgiref==0.1.2' \ No newline at end of file diff --git a/tools/test-requires b/tools/test-requires deleted file mode 100644 index cafb8ad..0000000 --- a/tools/test-requires +++ /dev/null @@ -1,9 +0,0 @@ -WebTest==2.0.6 -mock==1.0.1 -pep8==1.4.6 -py==1.4.15 -six==1.3.0 -tox==1.5.0 -unittest2==0.5.1 -coverage==3.6 -requests==1.2.3 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 25dc62a..0000000 --- a/tox.ini +++ /dev/null @@ -1,21 +0,0 @@ -# Tox (http://tox.testrun.org/) is a tool for running tests -# in multiple virtualenvs. This configuration file will run the -# test suite on all supported python versions. To use it, "pip install tox" -# and then run "tox" from this directory. - -[tox] -envlist = py26, py27, pep8, cover - -[testenv] -commands = nosetests tests -deps = -r{toxinidir}/tools/test-requires - -[testenv:pep8] -commands = pep8 --repeat --show-source --exclude=.venv,.tox,dist,doc,*egg,tests,functional,test_utils,ostf_client . - -[testenv:cover] -commands = nosetests tests --no-path-adjustment --with-coverage --cover-erase --cover-package=ostf_adapter - -[testenv:funct] -deps = requests -commands = nosetests functional/tests.py:AdapterTests