Retire the project
Reasons: - cloudv-ostf-adapter has been moved to another repo Changes: - retired the project Change-Id: I8104b242d774ad329a50bac71ab5fb11f9ebfe18
This commit is contained in:
parent
cf6cff8a08
commit
8c27340245
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,8 +0,0 @@
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.swp
|
||||
.idea
|
||||
*egg-info
|
||||
.tox
|
||||
.venv
|
||||
*.egg/
|
@ -1,4 +0,0 @@
|
||||
[DEFAULT]
|
||||
test_command=${PYTHON:-python} -m subunit.run discover ./cloudv_ostf_adapter/tests/unittests $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
@ -1 +0,0 @@
|
||||
recursive-include public *
|
13
README
Normal file
13
README
Normal file
@ -0,0 +1,13 @@
|
||||
This project is no longer maintained.
|
||||
|
||||
The contents of this repository are still available in the Git
|
||||
source code management system. To see the contents of this
|
||||
repository before it reached its end of life, please check out the
|
||||
previous commit with "git checkout HEAD^1".
|
||||
|
||||
For an alternative project, please see cloudv-ostf-adapter at
|
||||
https://gerrit.mirantis.com/gitweb?p=mirantis-cloud-validation/cloudv-ostf-adapter.git
|
||||
|
||||
For any further questions, please email
|
||||
openstack-dev@lists.openstack.org or join #openstack-dev on
|
||||
Freenode.
|
336
README.rst
336
README.rst
@ -1,336 +0,0 @@
|
||||
=================================
|
||||
Cloud Validation adapter for OSTF
|
||||
=================================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Existing [OSTF](http://docs.mirantis.com/fuel-dev/develop/ostf_contributors_guide.html)
|
||||
code provides a number of tests which cover a number of cases needed for cloud
|
||||
validation. The downside of existing OSTF is that it is tightly coupled with
|
||||
FUEL's nailgun. Given project aims to create standalone adapter for OSTF which
|
||||
is independent of FUEL thus making it possible to run OSTF tests on any random
|
||||
cloud (in theory).
|
||||
|
||||
High-level design
|
||||
-----------------
|
||||
|
||||
CLI tool that works with health check plugins
|
||||
Supported plugins::
|
||||
|
||||
- fuel health check
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Please note that if you're using Fuel OSTF plugin, you have to install it manually.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cloudvalidation cloud-health-check {argument} [argument_parameters]
|
||||
|
||||
Arguments::
|
||||
|
||||
list_plugins - Lists plugins
|
||||
list_plugin_suites - Lists plugin test suites
|
||||
list_plugin_tests - Lists plugin tests from all available suites
|
||||
run_suites - Runs all tests from all suites
|
||||
run_suite - Runs certain test suite
|
||||
run_test - Runs certain test
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cloudvalidation-cli cloud-health-check list_plugins
|
||||
|
||||
+----------+------------------------------------------------------------------+
|
||||
| Property | Value |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| name | fuel_health |
|
||||
| suites | fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_heat.SanityHeatTest |
|
||||
| | fuel_health.tests.smoke.test_create_flavor.FlavorsAdminTest |
|
||||
+----------+------------------------------------------------------------------+
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cloudvalidation-cli cloud-health-check list_plugin_suites --validation-plugin fuel_health
|
||||
|
||||
+----------+------------------------------------------------------------------+
|
||||
| Property | Value |
|
||||
+----------+------------------------------------------------------------------+
|
||||
| suites | fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_heat.SanityHeatTest |
|
||||
| | fuel_health.tests.smoke.test_create_flavor.FlavorsAdminTest |
|
||||
+----------+------------------------------------------------------------------+
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cloudvalidation-cli cloud-health-check list_plugin_tests --validation-plugin fuel_health
|
||||
|
||||
+----------+--------------------------------------------------------------------------------------+
|
||||
| Property | Value |
|
||||
+----------+--------------------------------------------------------------------------------------+
|
||||
| tests | fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest:test_list_services |
|
||||
| | fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest:test_list_users |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_flavors |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_images |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_instances |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_rate_limits |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_snapshots |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_volumes |
|
||||
| | fuel_health.tests.sanity.test_sanity_heat.SanityHeatTest:test_list_stacks |
|
||||
| | fuel_health.tests.smoke.test_create_flavor.FlavorsAdminTest:test_create_flavor |
|
||||
+----------+--------------------------------------------------------------------------------------+
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cloudvalidation-cli --config-dir=/etc/cloudv_ostf_adapter cloud-health-check run_suites --validation-plugin-name fuel_health
|
||||
|
||||
|
||||
Request user list ... ok
|
||||
Request flavor list ... ok
|
||||
Request image list ... ok
|
||||
Request instance list ... ok
|
||||
Request absolute limits list ... ok
|
||||
Request snapshot list ... ok
|
||||
Request volume list ... ok
|
||||
Request stack list ... ok
|
||||
Create instance flavor ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 9 tests in 5.310s
|
||||
|
||||
OK
|
||||
|
||||
.. code-block::
|
||||
|
||||
$ cloudvalidation-cli --config-dir=/etc/cloudv_ostf_adapter cloud-health-check run_suite --validation-plugin-name fuel_health --suite fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest
|
||||
|
||||
Running test suite: fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest ...
|
||||
Request user list ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 1 test in 0.938s
|
||||
|
||||
OK
|
||||
|
||||
Links
|
||||
-----
|
||||
|
||||
* OSTF contributor's guide - http://docs.mirantis.com/fuel-dev/develop/ostf_contributors_guide.html)
|
||||
* OSTF source code - https://github.com/stackforge/fuel-ostf
|
||||
|
||||
========
|
||||
REST API
|
||||
========
|
||||
|
||||
|
||||
Run server
|
||||
----------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cloudvalidation-server --config-file=path_to_config
|
||||
* Running on http://127.0.0.1:8777/ (Press CTRL+C to quit)
|
||||
|
||||
Example of config
|
||||
-----------------
|
||||
|
||||
[rest]
|
||||
server_host=127.0.0.1
|
||||
server_port=8777
|
||||
log_file=/var/log/ostf.log
|
||||
jobs_dir=/var/log/ostf
|
||||
debug=False
|
||||
|
||||
List of supported operations
|
||||
----------------------------
|
||||
- get list of supported plugins
|
||||
GET /v1/plugins?load_tests=True/False
|
||||
In load_tests=True case tests for plugin will be shown.
|
||||
|
||||
- get suites in plugin
|
||||
GET /v1/plugins/<plugin_name>/suites
|
||||
|
||||
- get tests for all suites in plugin
|
||||
GET /v1/plugins/<plugin_name>/suites/tests
|
||||
|
||||
- get tests per suite in plugin
|
||||
GET /v1/plugins/<plugin_name>/suites/<suite>/tests
|
||||
|
||||
- run suites for plugin
|
||||
POST /v1/plugins/<plugin_name>/suites
|
||||
|
||||
- run suite for plugin
|
||||
POST /v1/plugins/<plugin_name>/suites/<suite>
|
||||
|
||||
- run test for plugin
|
||||
POST /v1/plugins/<plugin_name>/suites/tests/<test>
|
||||
|
||||
- create job with user's tests set
|
||||
POST /v1/jobs/create
|
||||
Example of JSON:
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
{
|
||||
"job": {
|
||||
"name": "fake",
|
||||
"description": "description",
|
||||
"tests": [
|
||||
"fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_flavors"]
|
||||
}
|
||||
}
|
||||
|
||||
- list of all jobs
|
||||
GET /v1/jobs
|
||||
|
||||
- execute job
|
||||
GET /v1/jobs/execute/<job_id>
|
||||
|
||||
- get status with report for executed job
|
||||
GET /v1/jobs/<job_id>
|
||||
|
||||
- delete job
|
||||
DELETE /v1/jobs/<job_id>
|
||||
|
||||
|
||||
=====================
|
||||
REST API Client usage
|
||||
=====================
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from cloudv_ostf_adapter.cloudv_client import client
|
||||
|
||||
cloudvclient = client.Client(CONF.host, CONF.port, CONF.api_version)
|
||||
|
||||
plugins = cloudvclient.plugins.list()
|
||||
plugin_one = plugins[0]['name']
|
||||
|
||||
suites = cloudvalidation.suites.list_suites(plugin_one)
|
||||
|
||||
=========================
|
||||
REST API Client CLI usage
|
||||
=========================
|
||||
|
||||
To connect cloudvalidation client to ReST service you need to do next::
|
||||
|
||||
# create configuration file, that contains
|
||||
[DEFAULT]
|
||||
host = localhost
|
||||
port = 8777
|
||||
api_version = v1
|
||||
|
||||
or
|
||||
|
||||
# export next operating system variables:
|
||||
export MCLOUDV_HOST=localhost
|
||||
export MCLOUDV_PORT=8777
|
||||
export MCLOUDV_API=v1
|
||||
|
||||
|
||||
Usage examples::
|
||||
.. code-block:: bash
|
||||
|
||||
cloudvalidation cloud-health-check list_plugins
|
||||
|
||||
+----------+----------------------------------------------------------------------------------------------+
|
||||
| Property | Value |
|
||||
+----------+----------------------------------------------------------------------------------------------+
|
||||
| name | fuel_health |
|
||||
| suites | fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_heat.SanityHeatTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_networking.NetworksTest:test_list_networks_nova_network |
|
||||
| | fuel_health.tests.sanity.test_sanity_ceilometer.CeilometerApiTests |
|
||||
| | fuel_health.tests.smoke.test_create_flavor.FlavorsAdminTest |
|
||||
| | fuel_health.tests.smoke.test_create_volume.VolumesTest |
|
||||
| | fuel_health.tests.smoke.test_neutron_actions.TestNeutron |
|
||||
| | fuel_health.tests.smoke.test_nova_create_instance_with_connectivity.TestNovaNetwork |
|
||||
| | fuel_health.tests.smoke.test_nova_image_actions.TestImageAction |
|
||||
| | fuel_health.tests.smoke.test_user_create.TestUserTenantRole |
|
||||
+----------+----------------------------------------------------------------------------------------------+
|
||||
|
||||
|
||||
cloudvalidation cloud-health-check list_plugin_suites --validation-plugin-name fuel_health
|
||||
|
||||
+----------+----------------------------------------------------------------------------------------------+
|
||||
| Property | Value |
|
||||
+----------+----------------------------------------------------------------------------------------------+
|
||||
| suites | fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_heat.SanityHeatTest |
|
||||
| | fuel_health.tests.sanity.test_sanity_networking.NetworksTest:test_list_networks_nova_network |
|
||||
| | fuel_health.tests.sanity.test_sanity_ceilometer.CeilometerApiTests |
|
||||
| | fuel_health.tests.smoke.test_create_flavor.FlavorsAdminTest |
|
||||
| | fuel_health.tests.smoke.test_create_volume.VolumesTest |
|
||||
| | fuel_health.tests.smoke.test_neutron_actions.TestNeutron |
|
||||
| | fuel_health.tests.smoke.test_nova_create_instance_with_connectivity.TestNovaNetwork |
|
||||
| | fuel_health.tests.smoke.test_nova_image_actions.TestImageAction |
|
||||
| | fuel_health.tests.smoke.test_user_create.TestUserTenantRole |
|
||||
+----------+----------------------------------------------------------------------------------------------+
|
||||
|
||||
|
||||
cloudvalidation cloud-health-check list_plugin_tests --validation-plugin-name fuel_health
|
||||
|
||||
+----------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Property | Value |
|
||||
+----------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| tests | fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest:test_list_services |
|
||||
| | fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest:test_list_users |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_flavors |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_images |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_instances |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_rate_limits |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_snapshots |
|
||||
| | fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest:test_list_volumes |
|
||||
| | fuel_health.tests.sanity.test_sanity_heat.SanityHeatTest:test_list_stacks |
|
||||
| | fuel_health.tests.sanity.test_sanity_ceilometer.CeilometerApiTests:test_list_meters |
|
||||
| | fuel_health.tests.smoke.test_create_flavor.FlavorsAdminTest:test_create_flavor |
|
||||
| | fuel_health.tests.smoke.test_create_volume.VolumesTest:test_create_boot_volume |
|
||||
| | fuel_health.tests.smoke.test_create_volume.VolumesTest:test_volume_create |
|
||||
| | fuel_health.tests.smoke.test_neutron_actions.TestNeutron:test_check_neutron_objects_creation |
|
||||
| | fuel_health.tests.smoke.test_nova_create_instance_with_connectivity.TestNovaNetwork:test_001_create_keypairs |
|
||||
| | fuel_health.tests.smoke.test_nova_create_instance_with_connectivity.TestNovaNetwork:test_002_create_security_groups |
|
||||
| | fuel_health.tests.smoke.test_nova_create_instance_with_connectivity.TestNovaNetwork:test_003_check_networks |
|
||||
| | fuel_health.tests.smoke.test_nova_create_instance_with_connectivity.TestNovaNetwork:test_004_create_servers |
|
||||
| | fuel_health.tests.smoke.test_nova_create_instance_with_connectivity.TestNovaNetwork:test_006_check_internet_connectivity_instance_without_floatingIP |
|
||||
| | fuel_health.tests.smoke.test_nova_create_instance_with_connectivity.TestNovaNetwork:test_008_check_public_instance_connectivity_from_instance |
|
||||
| | fuel_health.tests.smoke.test_nova_image_actions.TestImageAction:test_snapshot |
|
||||
| | fuel_health.tests.smoke.test_user_create.TestUserTenantRole:test_create_user |
|
||||
+----------+------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
|
||||
cloudvalidation cloud-health-check run_suites --validation-plugin-name fuel_health
|
||||
|
||||
Note this command will generate big report, so it might be useful to save it into a file.
|
||||
|
||||
|
||||
cloudvalidation cloud-health-check run_suite --validation-plugin-name fuel_health --suite fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest
|
||||
|
||||
Note this command will generate big report, so it might be useful to save it into a file.
|
||||
|
||||
|
||||
cloudvalidation cloud-health-check run_test --validation-plugin-name fuel_health --test fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest:test_list_services
|
||||
|
||||
+-------------------------------------------------------------------------------------+----------+--------+------------------------------------------------------------------------+
|
||||
| Test | Duration | Result | Report |
|
||||
+-------------------------------------------------------------------------------------+----------+--------+------------------------------------------------------------------------+
|
||||
| fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest:test_list_services | 1.184s | Passed | Request active services list ... ok |
|
||||
| | | | |
|
||||
| | | | ---------------------------------------------------------------------- |
|
||||
| | | | Ran 1 test in 1.184s |
|
||||
| | | | |
|
||||
| | | | OK |
|
||||
| | | | |
|
||||
+-------------------------------------------------------------------------------------+----------+--------+------------------------------------------------------------------------+
|
||||
|
@ -1,35 +0,0 @@
|
||||
# Copyright 2015 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 cloudv_ostf_adapter.common import cfg
|
||||
|
||||
from cloudv_client import jobs
|
||||
from cloudv_client import plugins
|
||||
from cloudv_client import suites
|
||||
from cloudv_client import tests
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class Client(object):
|
||||
|
||||
def __init__(self, host, port, api_version):
|
||||
kwargs = {
|
||||
'host': host,
|
||||
'port': port,
|
||||
'api_version': api_version
|
||||
}
|
||||
self.plugins = plugins.Plugins(**kwargs)
|
||||
self.suites = suites.Suites(**kwargs)
|
||||
self.tests = tests.Tests(**kwargs)
|
||||
self.jobs = jobs.Jobs(**kwargs)
|
@ -1,77 +0,0 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
import requests
|
||||
|
||||
from cloudv_ostf_adapter.common import exception
|
||||
|
||||
|
||||
class Jobs(object):
|
||||
|
||||
_jobs_create_route = ("http://%(host)s:%(port)d/%(api_version)s"
|
||||
"/jobs/create")
|
||||
_jobs_route = ("http://%(host)s:%(port)d/%(api_version)s/jobs")
|
||||
_jobs_execute_route = ("http://%(host)s:%(port)d/%(api_version)s"
|
||||
"/jobs/execute/%(job_id)s")
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.kwargs = kwargs
|
||||
|
||||
def list(self):
|
||||
jobs_url = self._jobs_route % self.kwargs
|
||||
response = requests.get(jobs_url)
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
return json.loads(response.content)['jobs']
|
||||
|
||||
def create(self, name, description, tests):
|
||||
data = {'job': {'name': name,
|
||||
'description': description,
|
||||
'tests': tests}}
|
||||
jobs_url = self._jobs_create_route % self.kwargs
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
response = requests.post(jobs_url,
|
||||
headers=headers,
|
||||
data=json.dumps(data))
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
return json.loads(response.content)['job']
|
||||
|
||||
def get(self, job_id):
|
||||
jobs_url = self._jobs_route % self.kwargs
|
||||
jobs_url += '/%s' % job_id
|
||||
response = requests.get(jobs_url)
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
return json.loads(response.content)['job']
|
||||
|
||||
def delete(self, job_id):
|
||||
jobs_url = self._jobs_route % self.kwargs
|
||||
jobs_url += '/%s' % job_id
|
||||
response = requests.delete(jobs_url)
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
|
||||
def execute(self, job_id):
|
||||
self.kwargs.update({'job_id': job_id})
|
||||
jobs_url = self._jobs_execute_route % self.kwargs
|
||||
response = requests.post(jobs_url)
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
return json.loads(response.content)['job']
|
@ -1,38 +0,0 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
import requests
|
||||
|
||||
from cloudv_ostf_adapter.common import exception
|
||||
|
||||
|
||||
class Plugins(object):
|
||||
|
||||
route = "http://%(host)s:%(port)d/%(api_version)s/plugins"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.url = self.route % kwargs
|
||||
|
||||
def list(self, load_tests=True):
|
||||
params = {'load_tests': load_tests}
|
||||
response = requests.get(self.url, params=params)
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
resp = json.loads(response.content)
|
||||
return resp['plugins']
|
@ -1,68 +0,0 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
import requests
|
||||
|
||||
from cloudv_ostf_adapter.common import exception
|
||||
|
||||
|
||||
class Suites(object):
|
||||
|
||||
_suite_route = ("http://%(host)s:%(port)d/%(api_version)s"
|
||||
"/plugins/%(plugin)s/suites")
|
||||
_suite_test_route = ("http://%(host)s:%(port)d/%(api_version)s/"
|
||||
"plugins/%(plugin)s/suites/%(suite)s/tests")
|
||||
_test_route = ("http://%(host)s:%(port)d/%(api_version)s/"
|
||||
"plugins/%(plugin)s/suites/tests")
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.kwargs = kwargs
|
||||
|
||||
def list_suites(self, plugin):
|
||||
self.kwargs.update({"plugin": plugin})
|
||||
suite_url = self._suite_route % self.kwargs
|
||||
response = requests.get(suite_url)
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
return json.loads(response.content)['plugin']
|
||||
|
||||
def list_tests_for_suites(self, plugin):
|
||||
self.kwargs.update({"plugin": plugin})
|
||||
suite_url = self._test_route % self.kwargs
|
||||
response = requests.get(suite_url)
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
return json.loads(response.content)['plugin']
|
||||
|
||||
def run_suites(self, plugin):
|
||||
self.kwargs.update({"plugin": plugin})
|
||||
suite_url = self._suite_route % self.kwargs
|
||||
response = requests.post(suite_url, {})
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
return json.loads(response.content)['plugin']['report']
|
||||
|
||||
def run_suite_tests(self, suite, plugin):
|
||||
self.kwargs.update({"suite": suite})
|
||||
self.kwargs.update({"plugin": plugin})
|
||||
url = self._suite_test_route % self.kwargs
|
||||
response = requests.post(url, {})
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(response.status_code)()
|
||||
return json.loads(response.content)['suite']
|
@ -1,41 +0,0 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
import requests
|
||||
|
||||
from cloudv_ostf_adapter.common import exception
|
||||
|
||||
|
||||
class Tests(object):
|
||||
|
||||
route = ("http://%(host)s:%(port)d/%(api_version)s"
|
||||
"/plugins/%(plugin)s/suites/tests/%(test)s")
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.kwargs = kwargs
|
||||
|
||||
def run(self, test, plugin):
|
||||
self.kwargs.update({"test": test})
|
||||
self.kwargs.update({"plugin": plugin})
|
||||
url = self.route % self.kwargs
|
||||
response = requests.post(url, {})
|
||||
if not response.ok:
|
||||
raise exception.exception_mapping.get(
|
||||
response.status_code)()
|
||||
return json.loads(response.content)['plugin']['report']
|
@ -1,126 +0,0 @@
|
||||
# Copyright 2015 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 six
|
||||
|
||||
|
||||
def args(*args, **kwargs):
|
||||
"""
|
||||
Decorates commandline arguments for actions
|
||||
:param args: sub-category commandline arguments
|
||||
:param kwargs: sub-category commandline arguments
|
||||
:return: decorator: object attribute setter
|
||||
:rtype: callable
|
||||
"""
|
||||
def _decorator(func):
|
||||
func.__dict__.setdefault('args', []).insert(0, (args, kwargs))
|
||||
return func
|
||||
return _decorator
|
||||
|
||||
|
||||
def methods_of(obj):
|
||||
"""
|
||||
Get all callable methods of an object that don't
|
||||
start with underscore (private attributes)
|
||||
returns
|
||||
:param obj: objects to get callable attributes from
|
||||
:type obj: object
|
||||
:return result: a list of tuples of the form (method_name, method)
|
||||
:rtype: list
|
||||
"""
|
||||
result = []
|
||||
for i in dir(obj):
|
||||
if callable(getattr(obj, i)) and not i.startswith('_'):
|
||||
result.append((i, getattr(obj, i)))
|
||||
return result
|
||||
|
||||
|
||||
def add_command_parsers(categories):
|
||||
"""
|
||||
Parses actions commandline arguments from each category
|
||||
:param categories: commandline categories
|
||||
:type categories: dict
|
||||
:return: _subparser: commandline subparser
|
||||
"""
|
||||
def _subparser(subparsers):
|
||||
"""
|
||||
Iterates over categories and registers action
|
||||
commandline arguments for each category
|
||||
:param subparsers: commandline subparser
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
for category in categories:
|
||||
command_object = categories[category]()
|
||||
|
||||
desc = getattr(command_object, 'description', None)
|
||||
parser = subparsers.add_parser(category, description=desc)
|
||||
parser.set_defaults(command_object=command_object)
|
||||
|
||||
category_subparsers = parser.add_subparsers(dest='action')
|
||||
|
||||
for (action, action_fn) in methods_of(command_object):
|
||||
parser = category_subparsers.add_parser(
|
||||
action, description=desc)
|
||||
|
||||
action_kwargs = []
|
||||
for args, kwargs in getattr(action_fn, 'args', []):
|
||||
kwargs.setdefault('dest', args[0][2:])
|
||||
if kwargs['dest'].startswith('action_kwarg_'):
|
||||
action_kwargs.append(
|
||||
kwargs['dest'][len('action_kwarg_'):])
|
||||
else:
|
||||
action_kwargs.append(kwargs['dest'])
|
||||
kwargs['dest'] = 'action_kwarg_' + kwargs['dest']
|
||||
|
||||
parser.add_argument(*args, **kwargs)
|
||||
|
||||
parser.set_defaults(action_fn=action_fn)
|
||||
parser.set_defaults(action_kwargs=action_kwargs)
|
||||
|
||||
parser.add_argument('action_args', nargs='*',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
return _subparser
|
||||
|
||||
|
||||
def _main(global_conf, local_conf, category_opt, cli_args):
|
||||
"""
|
||||
|
||||
:param global_conf: staged CONF
|
||||
:param local_conf: tool conf
|
||||
:param category_opt: subparser category options
|
||||
:param cli_args: tool CLI arguments
|
||||
:return:
|
||||
"""
|
||||
global_conf.register_cli_opt(category_opt)
|
||||
local_conf.parse_args(cli_args)
|
||||
fn = global_conf.category.action_fn
|
||||
fn_args = [arg.decode('utf-8') for arg in global_conf.category.action_args]
|
||||
fn_kwargs = {}
|
||||
for k in global_conf.category.action_kwargs:
|
||||
v = getattr(global_conf.category, 'action_kwarg_' + k)
|
||||
if v is None:
|
||||
continue
|
||||
if isinstance(v, six.string_types):
|
||||
v = v.decode('utf-8')
|
||||
fn_kwargs[k] = v
|
||||
|
||||
try:
|
||||
ret = fn(*fn_args, **fn_kwargs)
|
||||
return ret
|
||||
except Exception as e:
|
||||
print(str(e))
|
@ -1,119 +0,0 @@
|
||||
# Copyright 2015 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 sys
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from cloudv_ostf_adapter.common import cfg as config
|
||||
from cloudv_ostf_adapter.common import utils
|
||||
from cloudv_ostf_adapter.cmd import _common as cmd
|
||||
|
||||
from cloudv_ostf_adapter import validation_plugin
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class OSTF(object):
|
||||
"""
|
||||
Represents CLI view for OSTF tests commands:
|
||||
- list validation plugins
|
||||
- list per-plugin test suites
|
||||
"""
|
||||
|
||||
def list_plugins(self):
|
||||
for plugin in validation_plugin.VALIDATION_PLUGINS:
|
||||
_plugin = plugin(load_tests=False)
|
||||
descriptor = _plugin.descriptor()
|
||||
del descriptor['tests']
|
||||
descriptor.update({'suites': "\n".join(descriptor['suites'])})
|
||||
utils.print_dict(descriptor)
|
||||
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
def list_plugin_suites(self, validation_plugin_name):
|
||||
for plugin in validation_plugin.VALIDATION_PLUGINS:
|
||||
_plugin = plugin(load_tests=False)
|
||||
descriptor = _plugin.descriptor()
|
||||
if descriptor['name'] == validation_plugin_name:
|
||||
utils.print_dict({'suites': "\n".join(descriptor['suites'])})
|
||||
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
def list_plugin_tests(self, validation_plugin_name):
|
||||
for plugin in validation_plugin.VALIDATION_PLUGINS:
|
||||
_plugin = plugin(load_tests=False)
|
||||
descriptor = _plugin.descriptor()
|
||||
if descriptor['name'] == validation_plugin_name:
|
||||
utils.print_dict({
|
||||
'tests': "\n".join(plugin().descriptor()['tests'])})
|
||||
|
||||
@cmd.args("--no-format", dest="no_format")
|
||||
@cmd.args("--show-full-report", dest="show_full_report")
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
def run_suites(self, validation_plugin_name):
|
||||
for plugin in validation_plugin.VALIDATION_PLUGINS:
|
||||
_plugin = plugin(load_tests=False)
|
||||
descriptor = _plugin.descriptor()
|
||||
if descriptor['name'] == validation_plugin_name:
|
||||
reports = plugin().run_suites_within_cli()
|
||||
utils.print_formatted(reports,
|
||||
CONF.no_format,
|
||||
CONF.show_full_report)
|
||||
|
||||
@cmd.args("--suite", dest="suite")
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
@cmd.args("--no-format", dest="no_format")
|
||||
@cmd.args("--show-full-report", dest="show_full_report")
|
||||
def run_suite(self, validation_plugin_name, suite):
|
||||
for plugin in validation_plugin.VALIDATION_PLUGINS:
|
||||
_plugin = plugin(load_tests=False)
|
||||
descriptor = _plugin.descriptor()
|
||||
if descriptor['name'] == validation_plugin_name:
|
||||
reports = plugin().run_suite_within_cli(suite)
|
||||
utils.print_formatted(reports,
|
||||
CONF.no_format,
|
||||
CONF.show_full_report)
|
||||
|
||||
@cmd.args("--no-format", dest="no_format")
|
||||
@cmd.args("--show-full-report", dest="show_full_report")
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
@cmd.args("--test", dest="test")
|
||||
def run_test(self, validation_plugin_name, test):
|
||||
for plugin in validation_plugin.VALIDATION_PLUGINS:
|
||||
_plugin = plugin(load_tests=False)
|
||||
descriptor = _plugin.descriptor()
|
||||
if descriptor['name'] == validation_plugin_name:
|
||||
reports = plugin().run_test(test)
|
||||
utils.print_formatted(reports,
|
||||
CONF.no_format,
|
||||
CONF.show_full_report)
|
||||
|
||||
|
||||
CATS = {
|
||||
'cloud-health-check': OSTF
|
||||
}
|
||||
|
||||
category_opt = cfg.SubCommandOpt('category',
|
||||
title='Command categories',
|
||||
help='Available categories',
|
||||
handler=cmd.add_command_parsers(CATS))
|
||||
|
||||
|
||||
def main():
|
||||
"""Parse options and call the appropriate class/method."""
|
||||
cmd._main(CONF, config, category_opt, sys.argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,136 +0,0 @@
|
||||
# Copyright 2015 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 sys
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from cloudv_ostf_adapter.common import cfg as config
|
||||
from cloudv_client import client
|
||||
from cloudv_ostf_adapter.common import utils
|
||||
from cloudv_ostf_adapter.cmd import _common as cmd
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class ClientV1Shell(object):
|
||||
"""
|
||||
Represents set of capabilities to interact with Cloudvalidation API
|
||||
"""
|
||||
|
||||
_client = client.Client(CONF.host, CONF.port, CONF.api_version)
|
||||
|
||||
def list_plugins(self):
|
||||
"""
|
||||
List plugins
|
||||
"""
|
||||
|
||||
resp = self._client.plugins.list(load_tests=False)
|
||||
for plugin in resp:
|
||||
suites = plugin['suites']
|
||||
plugin['suites'] = "\n".join(suites)
|
||||
del plugin['tests']
|
||||
utils.print_dict(plugin)
|
||||
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
def list_plugin_suites(self, validation_plugin_name):
|
||||
"""
|
||||
List plugin suites
|
||||
Required options:
|
||||
--validation-plugin
|
||||
"""
|
||||
|
||||
resp = self._client.suites.list_suites(validation_plugin_name)
|
||||
suites = resp['suites']
|
||||
resp['suites'] = "\n".join(suites)
|
||||
del resp['name']
|
||||
utils.print_dict(resp)
|
||||
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
def list_plugin_tests(self, validation_plugin_name):
|
||||
"""
|
||||
List plugin tests
|
||||
Required options:
|
||||
--validation-plugin
|
||||
"""
|
||||
|
||||
resp = self._client.suites.list_tests_for_suites(
|
||||
validation_plugin_name)
|
||||
tests = resp['tests']
|
||||
resp['tests'] = "\n".join(tests)
|
||||
del resp['name']
|
||||
utils.print_dict(resp)
|
||||
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
def run_suites(self, validation_plugin_name):
|
||||
"""
|
||||
Run plugin suites
|
||||
Required options:
|
||||
--validation-plugin
|
||||
"""
|
||||
|
||||
resp = self._client.suites.run_suites(validation_plugin_name)
|
||||
utils.print_list(resp,
|
||||
['test', 'duration', 'result', 'report'],
|
||||
obj_is_dict=True)
|
||||
|
||||
@cmd.args("--suite", dest="suite")
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
def run_suite(self, validation_plugin_name, suite):
|
||||
"""
|
||||
Run plugin suite
|
||||
Required options:
|
||||
--validation-plugin
|
||||
--suite
|
||||
"""
|
||||
|
||||
resp = self._client.suites.run_suite_tests(
|
||||
suite, validation_plugin_name)
|
||||
suite_test_reports = resp['report']
|
||||
utils.print_list(suite_test_reports,
|
||||
['test', 'duration', 'result', 'report'],
|
||||
obj_is_dict=True)
|
||||
|
||||
@cmd.args("--validation-plugin-name", dest="validation_plugin_name")
|
||||
@cmd.args("--test", dest="test")
|
||||
def run_test(self, validation_plugin_name, test):
|
||||
"""
|
||||
Run plugin test
|
||||
Required options:
|
||||
--validation-plugin
|
||||
--test
|
||||
"""
|
||||
|
||||
resp = self._client.tests.run(test, validation_plugin_name)
|
||||
utils.print_list(resp,
|
||||
['test', 'duration', 'result', 'report'],
|
||||
obj_is_dict=True)
|
||||
|
||||
|
||||
CATS = {
|
||||
'cloud-health-check': ClientV1Shell
|
||||
}
|
||||
|
||||
category_opt = cfg.SubCommandOpt('category',
|
||||
title='Command categories',
|
||||
help='Available categories',
|
||||
handler=cmd.add_command_parsers(CATS))
|
||||
|
||||
|
||||
def main():
|
||||
"""Parse options and call the appropriate class/method."""
|
||||
cmd._main(CONF, config, category_opt, sys.argv)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,74 +0,0 @@
|
||||
# Copyright 2015 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 signal
|
||||
import sys
|
||||
|
||||
import flask
|
||||
|
||||
from flask.ext import restful
|
||||
from oslo_config import cfg
|
||||
|
||||
from cloudv_ostf_adapter.common import cfg as config
|
||||
from cloudv_ostf_adapter import wsgi
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
app = flask.Flask('cloudv_ostf_adapter')
|
||||
api = restful.Api(app)
|
||||
|
||||
api.add_resource(wsgi.Plugins, '/v1/plugins')
|
||||
api.add_resource(wsgi.PluginSuite,
|
||||
'/v1/plugins/<plugin>/suites')
|
||||
api.add_resource(wsgi.PluginTests,
|
||||
'/v1/plugins/<plugin>/suites/tests')
|
||||
api.add_resource(wsgi.Suites,
|
||||
'/v1/plugins/<plugin>/suites/<suite>',
|
||||
'/v1/plugins/<plugin>/suites/<suite>/tests')
|
||||
api.add_resource(wsgi.Tests,
|
||||
'/v1/plugins/<plugin>/suites/tests/<test>')
|
||||
|
||||
|
||||
api.add_resource(wsgi.JobsCreation,
|
||||
'/v1/jobs/create')
|
||||
api.add_resource(wsgi.Jobs,
|
||||
'/v1/jobs')
|
||||
api.add_resource(wsgi.Execute,
|
||||
'/v1/jobs/execute/<job_id>')
|
||||
api.add_resource(wsgi.Job,
|
||||
'/v1/jobs/<job_id>')
|
||||
|
||||
|
||||
def main():
|
||||
config.parse_args(sys.argv)
|
||||
jobs_dir = CONF.rest.jobs_dir
|
||||
if not os.path.exists(jobs_dir):
|
||||
os.mkdir(jobs_dir)
|
||||
|
||||
host, port = CONF.rest.server_host, CONF.rest.server_port
|
||||
try:
|
||||
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
|
||||
signal.signal(signal.SIGHUP, signal.SIG_IGN)
|
||||
app.run(host=host, port=port,
|
||||
debug=CONF.rest.debug,
|
||||
use_reloader=True,
|
||||
processes=100)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,120 +0,0 @@
|
||||
# Copyright 2015 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 oslo_config import cfg
|
||||
|
||||
from cloudv_ostf_adapter import version
|
||||
|
||||
|
||||
common_opts = [
|
||||
cfg.StrOpt("health_check_config_path",
|
||||
default='etc/cloudv_ostf_adapter/health_check.conf'),
|
||||
cfg.StrOpt("enabled_validation_plugins", default=['fuel_health']),
|
||||
cfg.StrOpt("nose_verbosity", default="-v")
|
||||
]
|
||||
|
||||
cli_opts = [
|
||||
cfg.BoolOpt('no-format', short='F', default=False, required=False),
|
||||
cfg.BoolOpt('show-full-report', short='R', default=False, required=False)
|
||||
]
|
||||
|
||||
sanity_group = cfg.OptGroup("sanity", "Sanity configuration group.")
|
||||
smoke_group = cfg.OptGroup("smoke", "Smoke configuration group.")
|
||||
platform_group = cfg.OptGroup("platform",
|
||||
"Platform functional configuration group.")
|
||||
rest_group = cfg.OptGroup("rest", "Cloudvalidation ReST API service options.")
|
||||
ha_group = cfg.OptGroup("high_availability", "HA configuration group.")
|
||||
|
||||
|
||||
sanity_opts = [
|
||||
cfg.MultiStrOpt("enabled_tests", default=[
|
||||
'fuel_health.tests.sanity.test_sanity_identity.SanityIdentityTest',
|
||||
'fuel_health.tests.sanity.test_sanity_compute.SanityComputeTest',
|
||||
'fuel_health.tests.sanity.test_sanity_heat.SanityHeatTest',
|
||||
'fuel_health.tests.sanity.test_sanity_networking.NetworksTest:'
|
||||
'test_list_networks_nova_network',
|
||||
'fuel_health.tests.sanity.test_sanity_ceilometer.CeilometerApiTests',
|
||||
]),
|
||||
]
|
||||
smoke_opts = [
|
||||
cfg.MultiStrOpt("enabled_tests", default=[
|
||||
'fuel_health.tests.smoke.test_create_flavor.FlavorsAdminTest',
|
||||
'fuel_health.tests.smoke.test_create_volume.VolumesTest',
|
||||
'fuel_health.tests.smoke.test_neutron_actions.TestNeutron',
|
||||
'fuel_health.tests.smoke.test_nova_create_instance_with_connectivity.'
|
||||
'TestNovaNetwork',
|
||||
'fuel_health.tests.smoke.test_nova_image_actions.TestImageAction',
|
||||
'fuel_health.tests.smoke.test_user_create.TestUserTenantRole',
|
||||
]),
|
||||
]
|
||||
platform_opts = [
|
||||
cfg.MultiStrOpt("enabled_tests", default=[]),
|
||||
]
|
||||
ha_opts = [
|
||||
cfg.MultiStrOpt("enabled_tests", default=[]),
|
||||
]
|
||||
|
||||
rest_opts = [
|
||||
cfg.StrOpt('server_host',
|
||||
default='127.0.0.1',
|
||||
help="adapter host"),
|
||||
cfg.IntOpt('server_port',
|
||||
default=8777,
|
||||
help="Port number"),
|
||||
cfg.StrOpt('log_file',
|
||||
default='/var/log/ostf.log',
|
||||
help=""),
|
||||
cfg.StrOpt('debug',
|
||||
default=False,
|
||||
help="Debug for REST API."),
|
||||
cfg.StrOpt('jobs_dir',
|
||||
default='/var/log/ostf',
|
||||
help="Directory where jobs will be stored."),
|
||||
]
|
||||
|
||||
rest_client_opts = [
|
||||
cfg.StrOpt("host", default=os.environ.get("MCLOUDV_HOST", "localhost")),
|
||||
cfg.IntOpt("port", default=os.environ.get("MCLOUDV_PORT", 8777)),
|
||||
cfg.StrOpt("api_version", default=os.environ.get("MCLOUDV_API", "v1"))
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(common_opts)
|
||||
|
||||
CONF.register_group(sanity_group)
|
||||
CONF.register_group(smoke_group)
|
||||
CONF.register_group(platform_group)
|
||||
CONF.register_group(ha_group)
|
||||
CONF.register_group(rest_group)
|
||||
|
||||
CONF.register_opts(sanity_opts, sanity_group)
|
||||
CONF.register_opts(smoke_opts, smoke_group)
|
||||
CONF.register_opts(platform_opts, platform_group)
|
||||
CONF.register_opts(ha_opts, ha_group)
|
||||
CONF.register_opts(rest_opts, rest_group)
|
||||
|
||||
#client opts
|
||||
CONF.register_opts(rest_client_opts)
|
||||
|
||||
# CLI opts
|
||||
CONF.register_cli_opts(cli_opts)
|
||||
|
||||
|
||||
def parse_args(argv, default_config_files=None):
|
||||
cfg.CONF(args=argv[1:],
|
||||
project='cloudv_ostf_adapter',
|
||||
version=version.version,
|
||||
default_config_files=default_config_files)
|
@ -1,45 +0,0 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
|
||||
class BaseHTTPException(Exception):
|
||||
|
||||
def __init__(self, message=None,
|
||||
http_code=400, **kwargs):
|
||||
self.message = (message % kwargs
|
||||
if message else self.message)
|
||||
self.http_code = http_code
|
||||
self.reason = "HTTP Code: %d." % http_code
|
||||
super(BaseHTTPException, self).__init__(self.message + self.reason)
|
||||
|
||||
|
||||
class BadRequest(BaseHTTPException):
|
||||
http_code = 400
|
||||
message = "Bad request. "
|
||||
|
||||
|
||||
class NotFound(BaseHTTPException):
|
||||
http_code = 404
|
||||
message = "Not Found. "
|
||||
|
||||
|
||||
class ConnectionRefused(BaseHTTPException):
|
||||
http_code = 111
|
||||
message = "Server shutdowned. "
|
||||
|
||||
exception_mapping = {
|
||||
111: ConnectionRefused,
|
||||
404: NotFound,
|
||||
400: BadRequest
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
# Copyright 2015 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 oslo_utils import importutils
|
||||
|
||||
|
||||
class Test(object):
|
||||
"""
|
||||
This class represents siginificant information about test case
|
||||
such as:
|
||||
test
|
||||
its execution report
|
||||
its result
|
||||
and its duration
|
||||
|
||||
"""
|
||||
def safe_import(self):
|
||||
"""
|
||||
Performs safe import on demand of test class
|
||||
"""
|
||||
try:
|
||||
importutils.import_class(self._test_class)
|
||||
except ImportError:
|
||||
print("Can't import test's class: %s. "
|
||||
"It is not installed." % self._test_class)
|
||||
|
||||
def __init__(self, test_class):
|
||||
"""
|
||||
@param test_class: unit test case
|
||||
@type test_class: basestring
|
||||
"""
|
||||
self._test_class = test_class
|
||||
|
||||
self._test_caption = test_class
|
||||
|
||||
self._duration = None
|
||||
self._report = None
|
||||
self._result = None
|
||||
|
||||
@property
|
||||
def result(self):
|
||||
return self._result
|
||||
|
||||
@result.setter
|
||||
def result(self, result):
|
||||
self._result = result
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
"""
|
||||
Extracts docstrings from test
|
||||
:rtype: dict
|
||||
"""
|
||||
return {
|
||||
'test': self._test_caption,
|
||||
'report': self.report,
|
||||
'result': self.result,
|
||||
'duration': self.duration,
|
||||
}
|
||||
|
||||
@property
|
||||
def duration(self):
|
||||
"""
|
||||
Test execution duration
|
||||
"""
|
||||
return self._duration
|
||||
|
||||
@duration.setter
|
||||
def duration(self, duration):
|
||||
self._duration = duration
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Returns nose test name
|
||||
"""
|
||||
return self._test_caption
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
self._test_caption = name
|
||||
|
||||
@property
|
||||
def report(self):
|
||||
return self._report
|
||||
|
||||
@report.setter
|
||||
def report(self, report):
|
||||
self._report = report
|
@ -1,116 +0,0 @@
|
||||
# Copyright 2015 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 sys
|
||||
import prettytable
|
||||
import six
|
||||
|
||||
from cloudv_ostf_adapter.common import cfg
|
||||
from oslo.utils import encodeutils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def _print(pt, order):
|
||||
if sys.version_info >= (3, 0):
|
||||
print(pt.get_string(sortby=order))
|
||||
else:
|
||||
print(encodeutils.safe_encode(pt.get_string(sortby=order)))
|
||||
|
||||
|
||||
def print_raw(d, verbose):
|
||||
|
||||
fn_filter = (lambda key: 0) if verbose else lambda key: key == 'report'
|
||||
|
||||
for row in six.iteritems(d):
|
||||
if fn_filter(row[0]):
|
||||
continue
|
||||
|
||||
print('[%s]:\t%s' % (row[0].upper(), row[1]))
|
||||
print('')
|
||||
|
||||
|
||||
def print_dict(d, verbose=False, property="Property"):
|
||||
pt = prettytable.PrettyTable([property, 'Value'], caching=False)
|
||||
pt.align = 'l'
|
||||
|
||||
fn_filter = (lambda key: 0) if verbose else lambda key: key == 'report'
|
||||
|
||||
[pt.add_row(list(r)) for r in six.iteritems(d) if not fn_filter(r[0])]
|
||||
_print(pt, property)
|
||||
|
||||
|
||||
def print_formatted(reports, raw_format, verbose):
|
||||
|
||||
if raw_format:
|
||||
fn_print = print_raw
|
||||
else:
|
||||
fn_print = print_dict
|
||||
|
||||
for report in reports:
|
||||
fn_print(report.description, verbose=verbose)
|
||||
|
||||
|
||||
def print_list(objs, fields, formatters={}, order_by=None, obj_is_dict=False,
|
||||
labels={}):
|
||||
if not labels:
|
||||
labels = {}
|
||||
for field in fields:
|
||||
if field not in labels:
|
||||
# No underscores (use spaces instead) and uppercase any ID's
|
||||
label = field.replace("_", " ").replace("id", "ID")
|
||||
# Uppercase anything else that's less than 3 chars
|
||||
if len(label) < 3:
|
||||
label = label.upper()
|
||||
# Capitalize each word otherwise
|
||||
else:
|
||||
label = ' '.join(word[0].upper() + word[1:]
|
||||
for word in label.split())
|
||||
labels[field] = label
|
||||
|
||||
pt = prettytable.PrettyTable(
|
||||
[labels[field] for field in fields], caching=False)
|
||||
# set the default alignment to left-aligned
|
||||
align = dict((labels[field], 'l') for field in fields)
|
||||
set_align = True
|
||||
for obj in objs:
|
||||
row = []
|
||||
for field in fields:
|
||||
if formatters and field in formatters:
|
||||
row.append(formatters[field](obj))
|
||||
elif obj_is_dict:
|
||||
data = obj.get(field, '')
|
||||
else:
|
||||
data = getattr(obj, field, '')
|
||||
row.append(data)
|
||||
# set the alignment to right-aligned if it's a numeric
|
||||
if set_align and hasattr(data, '__int__'):
|
||||
align[labels[field]] = 'r'
|
||||
set_align = False
|
||||
pt.add_row(row)
|
||||
pt._align = align
|
||||
|
||||
if not order_by:
|
||||
order_by = fields[0]
|
||||
order_by = labels[order_by]
|
||||
_print(pt, order_by)
|
||||
|
||||
|
||||
def poll_until(pollster, expected_result=None, sleep_time=5):
|
||||
import time
|
||||
if not callable(pollster):
|
||||
raise Exception("%s is not callable" % pollster.__name__)
|
||||
while pollster() != expected_result:
|
||||
time.sleep(sleep_time)
|
@ -1,35 +0,0 @@
|
||||
# Copyright 2015 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 loader
|
||||
from oslo_utils import importutils
|
||||
|
||||
|
||||
def do_test_discovery(classes):
|
||||
"""
|
||||
Will discover test cases from suites
|
||||
"""
|
||||
_tests = []
|
||||
_loader = loader.TestLoader()
|
||||
for classname in classes:
|
||||
if ":" in classname:
|
||||
cls, method = classname.split(":")
|
||||
getattr(importutils.import_class(cls), method)
|
||||
else:
|
||||
suite_class = _loader.loadTestsFromTestClass(
|
||||
importutils.import_class(classname))
|
||||
for test_case in suite_class._precache:
|
||||
_tests.append(classname + ':' + str(
|
||||
test_case).split(' ')[0])
|
||||
return _tests
|
@ -1,52 +0,0 @@
|
||||
# Copyright 2015 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
|
||||
import testtools
|
||||
|
||||
from oslo_config import cfg as conf
|
||||
|
||||
from cloudv_ostf_adapter.common import cfg
|
||||
from cloudv_ostf_adapter.validation_plugin import base
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
_group = conf.OptGroup("fake")
|
||||
CONF.register_group(_group)
|
||||
_opts = [
|
||||
conf.MultiStrOpt("enabled_tests", default=[
|
||||
"cloudv_ostf_adapter.tests.unittests.fakes.fake_plugin."
|
||||
"fake_plugin_tests.FakePluginTests"
|
||||
])
|
||||
]
|
||||
CONF.register_opts(_opts, _group)
|
||||
|
||||
GROUP = 'fake'
|
||||
CONF = cfg.CONF
|
||||
TESTS = CONF.get(GROUP).enabled_tests
|
||||
|
||||
|
||||
class FakePluginTests(testtools.TestCase):
|
||||
|
||||
def test_a(self):
|
||||
time.sleep(5)
|
||||
self.assertEqual("A", "A")
|
||||
|
||||
def test_b(self):
|
||||
time.sleep(5)
|
||||
self.assertIn("B", "ABCD")
|
||||
|
||||
|
||||
def get_tests():
|
||||
return base.SuiteDescriptor(GROUP, TESTS)
|
@ -1,51 +0,0 @@
|
||||
# Copyright 2015 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 oslo_config import cfg
|
||||
|
||||
from cloudv_ostf_adapter.validation_plugin import base
|
||||
from cloudv_ostf_adapter.tests.unittests.fakes.fake_plugin import (
|
||||
fake_plugin_tests)
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
SUITES = [fake_plugin_tests]
|
||||
|
||||
|
||||
class FakeTest(object):
|
||||
def __init__(self):
|
||||
self.description = {
|
||||
"test": 'fake_test',
|
||||
"report": "",
|
||||
"result": "passed",
|
||||
"duration": "0.1"
|
||||
}
|
||||
|
||||
|
||||
class FakeValidationPlugin(base.ValidationPlugin):
|
||||
|
||||
def __init__(self, load_tests=True):
|
||||
name = 'fake'
|
||||
self.test = FakeTest()
|
||||
super(FakeValidationPlugin, self).__init__(
|
||||
name, SUITES, load_tests=load_tests)
|
||||
|
||||
def run_suites(self):
|
||||
return [self.test]
|
||||
|
||||
def run_suite(self, suite):
|
||||
return [self.test]
|
||||
|
||||
def run_test(self, test):
|
||||
return [self.test]
|
@ -1,323 +0,0 @@
|
||||
# Copyright 2015 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 os
|
||||
import shutil
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
import testtools
|
||||
|
||||
from cloudv_ostf_adapter.cmd import server
|
||||
from cloudv_ostf_adapter.tests.unittests.fakes.fake_plugin import health_plugin
|
||||
from cloudv_ostf_adapter import wsgi
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class TestServer(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.jobs_dir = '/tmp/ostf_tests_%s' % uuid.uuid1()
|
||||
CONF.rest.jobs_dir = self.jobs_dir
|
||||
if not os.path.exists(self.jobs_dir):
|
||||
os.mkdir(self.jobs_dir)
|
||||
self.plugin = health_plugin.FakeValidationPlugin()
|
||||
server.app.config['TESTING'] = True
|
||||
self.app = server.app.test_client()
|
||||
self.actual_plugins = wsgi.validation_plugin.VALIDATION_PLUGINS
|
||||
wsgi.validation_plugin.VALIDATION_PLUGINS = [self.plugin.__class__]
|
||||
|
||||
data = {'job': {'name': 'fake',
|
||||
'tests': self.plugin.tests,
|
||||
'description': 'description'}}
|
||||
rv = self.app.post(
|
||||
'/v1/jobs/create', content_type='application/json',
|
||||
data=json.dumps(data)).data
|
||||
self.job_id = self._resp_to_dict(rv)['job']['id']
|
||||
rv2 = self.app.post(
|
||||
'/v1/jobs/create', content_type='application/json',
|
||||
data=json.dumps(data)).data
|
||||
self.job_id2 = self._resp_to_dict(rv2)['job']['id']
|
||||
|
||||
p = mock.patch('cloudv_ostf_adapter.wsgi.uuid.uuid4')
|
||||
self.addCleanup(p.stop)
|
||||
m = p.start()
|
||||
m.return_value = 'fake_uuid'
|
||||
execute = mock.patch('cloudv_ostf_adapter.wsgi.Execute._execute_job')
|
||||
self.addCleanup(execute.stop)
|
||||
execute.start()
|
||||
super(TestServer, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
wsgi.validation_plugin.VALIDATION_PLUGINS = self.actual_plugins
|
||||
shutil.rmtree(self.jobs_dir)
|
||||
super(TestServer, self).tearDown()
|
||||
|
||||
def test_urlmap(self):
|
||||
links = []
|
||||
check_list = [
|
||||
'/v1/plugins',
|
||||
'/v1/plugins/<plugin>/suites/tests/<test>',
|
||||
'/v1/plugins/<plugin>/suites/<suite>/tests',
|
||||
'/v1/plugins/<plugin>/suites/tests',
|
||||
'/v1/plugins/<plugin>/suites/<suite>',
|
||||
'/v1/plugins/<plugin>/suites',
|
||||
'/v1/plugins/<plugin>/suites/tests/<test>',
|
||||
'/v1/jobs/create',
|
||||
'/v1/jobs',
|
||||
'/v1/jobs/execute/<job_id>',
|
||||
'/v1/jobs/<job_id>'
|
||||
]
|
||||
for rule in server.app.url_map.iter_rules():
|
||||
links.append(str(rule))
|
||||
self.assertEqual(set(check_list) & set(links), set(check_list))
|
||||
|
||||
def _resp_to_dict(self, data):
|
||||
if type(data) == bytes:
|
||||
data = data.decode('utf-8')
|
||||
return json.loads(data)
|
||||
|
||||
def test_plugins_no_load_tests(self):
|
||||
rv = self.app.get('/v1/plugins').data
|
||||
check = {
|
||||
'plugins': [{'name': self.plugin.name,
|
||||
'suites': self.plugin.suites,
|
||||
'tests': []}]
|
||||
}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_plugins_load_tests(self):
|
||||
rv = self.app.get('/v1/plugins?load_tests=True').data
|
||||
check = {
|
||||
'plugins': [{'name': self.plugin.name,
|
||||
'suites': self.plugin.suites,
|
||||
'tests': self.plugin.tests}]
|
||||
}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_plugin_not_found(self):
|
||||
rv = self.app.get('/v1/plugins/fake2/suites').data
|
||||
check = {"message": "Unsupported plugin fake2."}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_plugin_suites(self):
|
||||
rv = self.app.get('/v1/plugins/fake/suites').data
|
||||
check = {"plugin": {"name": self.plugin.name,
|
||||
"suites": self.plugin.suites}}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_suite_plugin_not_found(self):
|
||||
rv = self.app.get(
|
||||
'/v1/plugins/fake2/suites/fake/tests').data
|
||||
check = {u'message': u'Unsupported plugin fake2.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_suite_tests(self):
|
||||
suite = self.plugin.suites[0]
|
||||
url = '/v1/plugins/fake/suites/%s/tests' % suite
|
||||
rv = self.app.get(url).data
|
||||
tests = self.plugin.get_tests_by_suite(suite)
|
||||
check = {
|
||||
"plugin": {"name": self.plugin.name,
|
||||
"suite": {"name": suite,
|
||||
"tests": tests}}}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_suite_not_found(self):
|
||||
rv = self.app.get(
|
||||
'/v1/plugins/fake/suites/fake/tests').data
|
||||
check = {u'message': u'Unknown suite fake.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_plugin_tests_not_found(self):
|
||||
rv = self.app.get(
|
||||
'/v1/plugins/fake2/suites/tests').data
|
||||
check = {u'message': u'Unsupported plugin fake2.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_plugin_tests(self):
|
||||
rv = self.app.get(
|
||||
'/v1/plugins/fake/suites/tests').data
|
||||
check = {"plugin": {"name": self.plugin.name,
|
||||
"tests": self.plugin.tests}}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_run_suites(self):
|
||||
rv = self.app.post(
|
||||
'/v1/plugins/fake/suites').data
|
||||
check = {
|
||||
u'plugin': {u'name': self.plugin.name,
|
||||
u'report': [self.plugin.test.description]}}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_run_suites_plugin_not_found(self):
|
||||
rv = self.app.post(
|
||||
'/v1/plugins/fake2/suites').data
|
||||
check = {u'message': u'Unsupported plugin fake2.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_run_suite(self):
|
||||
suite = self.plugin.suites[0]
|
||||
rv = self.app.post(
|
||||
'/v1/plugins/fake/suites/%s' % suite).data
|
||||
check = {
|
||||
u'suite': {u'name': suite,
|
||||
u'report': [self.plugin.test.description]}}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_run_suite_plugin_not_found(self):
|
||||
rv = self.app.post(
|
||||
'/v1/plugins/fake2/suites/fake_suite').data
|
||||
check = {u'message': u'Unsupported plugin fake2.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_run_suite_suite_not_found(self):
|
||||
rv = self.app.post(
|
||||
'/v1/plugins/fake/suites/fake_suite').data
|
||||
check = {u'message': u'Unknown suite fake_suite.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_run_test(self):
|
||||
test = self.plugin.tests[0]
|
||||
rv = self.app.post(
|
||||
'/v1/plugins/fake/suites/tests/%s' % test).data
|
||||
check = {
|
||||
u'plugin': {u'name': self.plugin.name,
|
||||
u'test': test,
|
||||
u'report': [self.plugin.test.description]}}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_run_test_plugin_not_found(self):
|
||||
rv = self.app.post(
|
||||
'/v1/plugins/fake2/suites/tests/fake_test').data
|
||||
check = {u'message': u'Unsupported plugin fake2.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_run_test_not_found(self):
|
||||
rv = self.app.post(
|
||||
'/v1/plugins/fake/suites/tests/fake_test').data
|
||||
check = {u'message': u'Test fake_test not found.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_job_create_json_not_found(self):
|
||||
rv = self.app.post(
|
||||
'/v1/jobs/create').data
|
||||
check = {u'message': u'JSON is missing.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_job_create_job_key_found(self):
|
||||
data = {'fake': {}}
|
||||
rv = self.app.post(
|
||||
'/v1/jobs/create', content_type='application/json',
|
||||
data=json.dumps(data)).data
|
||||
check = {u'message': u"JSON doesn't have `job` key."}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_job_create_fields_not_found(self):
|
||||
data = {'job': {'name': 'fake'}}
|
||||
rv = self.app.post(
|
||||
'/v1/jobs/create', content_type='application/json',
|
||||
data=json.dumps(data)).data
|
||||
check = {u'message': u'Fields description,tests are not specified.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_job_create_tests_not_found(self):
|
||||
data = {'job': {'name': 'fake',
|
||||
'tests': ['a', 'b'],
|
||||
'description': 'description'}}
|
||||
rv = self.app.post(
|
||||
'/v1/jobs/create', content_type='application/json',
|
||||
data=json.dumps(data)).data
|
||||
check = {u'message': u'Tests not found (a,b).'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_job_create(self):
|
||||
data = {'job': {'name': 'fake',
|
||||
'tests': self.plugin.tests,
|
||||
'description': 'description'}}
|
||||
rv = self.app.post(
|
||||
'/v1/jobs/create', content_type='application/json',
|
||||
data=json.dumps(data)).data
|
||||
check = {u'job': {u'description': u'description',
|
||||
u'id': u'fake_uuid',
|
||||
u'name': u'fake',
|
||||
u'status': u'CREATED',
|
||||
u'tests': self.plugin.tests}}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_execute_job_not_found(self):
|
||||
rv = self.app.post('/v1/jobs/execute/fake').data
|
||||
check = {u'message': u'Job not found.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_execute_job(self):
|
||||
rv = self.app.post('/v1/jobs/execute/%s' % self.job_id).data
|
||||
check = {u'job': {u'description': u'description',
|
||||
u'id': self.job_id,
|
||||
u'name': u'fake',
|
||||
u'report': [],
|
||||
u'status': u'IN PROGRESS',
|
||||
u'tests': self.plugin.tests}}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_get_list_jobs(self):
|
||||
rv = self.app.get('/v1/jobs').data
|
||||
resp_dict = self._resp_to_dict(rv)['jobs']
|
||||
check = [
|
||||
{u'description': u'description',
|
||||
u'id': self.job_id,
|
||||
u'name': u'fake',
|
||||
u'status': u'CREATED',
|
||||
u'tests': self.plugin.tests},
|
||||
{u'description': u'description',
|
||||
u'id': self.job_id2,
|
||||
u'name': u'fake',
|
||||
u'status': u'CREATED',
|
||||
u'tests': self.plugin.tests}]
|
||||
for job in resp_dict:
|
||||
self.assertIn(job, check)
|
||||
|
||||
def test_get_job_not_found(self):
|
||||
rv = self.app.get('/v1/jobs/fake').data
|
||||
check = {u'message': u'Job not found.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_get_job(self):
|
||||
rv = self.app.get('/v1/jobs/%s' % self.job_id).data
|
||||
check = {'job': {u'description': u'description',
|
||||
u'id': self.job_id,
|
||||
u'name': u'fake',
|
||||
u'status': u'CREATED',
|
||||
u'tests': self.plugin.tests}}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_delete_job_not_found(self):
|
||||
rv = self.app.delete('/v1/jobs/fake').data
|
||||
check = {u'message': u'Job not found.'}
|
||||
self.assertEqual(self._resp_to_dict(rv), check)
|
||||
|
||||
def test_delete_job(self):
|
||||
before = self._resp_to_dict(
|
||||
self.app.get('/v1/jobs').data)
|
||||
jobs_id_before = [j['id'] for j in before['jobs']]
|
||||
self.assertEqual(len(jobs_id_before), 2)
|
||||
self.app.delete('/v1/jobs/%s' % self.job_id)
|
||||
after = self._resp_to_dict(
|
||||
self.app.get('/v1/jobs').data)
|
||||
jobs_id_after = [j['id'] for j in after['jobs']]
|
||||
self.assertEqual(len(jobs_id_after), 1)
|
@ -1,42 +0,0 @@
|
||||
# Copyright 2015 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 testtools
|
||||
|
||||
from cloudv_ostf_adapter import validation_plugin
|
||||
from cloudv_ostf_adapter.tests.unittests.fakes.fake_plugin import health_plugin
|
||||
|
||||
|
||||
class TestWorkflow(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.plugin = health_plugin.FakeValidationPlugin()
|
||||
validation_plugin.VALIDATION_PLUGINS.append(self.plugin.__class__)
|
||||
super(TestWorkflow, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
validation_plugin.VALIDATION_PLUGINS.pop(
|
||||
validation_plugin.VALIDATION_PLUGINS.index(
|
||||
self.plugin.__class__))
|
||||
super(TestWorkflow, self).tearDown()
|
||||
|
||||
def test_verify_plugins(self):
|
||||
self.assertEqual(2, len(validation_plugin.VALIDATION_PLUGINS))
|
||||
self.assertIn(self.plugin.__class__,
|
||||
validation_plugin.VALIDATION_PLUGINS)
|
||||
|
||||
def test_verify_fake_plugin(self):
|
||||
test_patsh = self.plugin._collect_test(self.plugin.tests)
|
||||
self.assertEqual(2, len(test_patsh))
|
||||
self.assertEqual(2, len(self.plugin.tests))
|
@ -1,19 +0,0 @@
|
||||
# Copyright 2015 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 cloudv_ostf_adapter.validation_plugin import fuel_health
|
||||
|
||||
|
||||
VALIDATION_PLUGINS = [
|
||||
fuel_health.FuelHealthPlugin,
|
||||
]
|
@ -1,151 +0,0 @@
|
||||
# Copyright 2015 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 sys
|
||||
|
||||
from oslo_utils import importutils
|
||||
|
||||
from cloudv_ostf_adapter.common import cfg
|
||||
from cloudv_ostf_adapter.common import utils
|
||||
from cloudv_ostf_adapter.nose_plugin import discovery
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class SuiteDescriptor(object):
|
||||
|
||||
suite_attrs = ['test_group', 'tests']
|
||||
test_attrs = ['tests']
|
||||
|
||||
def __init__(self, test_group_definition, tests):
|
||||
"""
|
||||
Describes test specific test group
|
||||
@param test_group_definition: Test group definition
|
||||
(i.e. sanity, smoke, HA, platform)
|
||||
@type test_group_definition: basestring
|
||||
@param tests: list of tests per test group
|
||||
@type tests: list
|
||||
"""
|
||||
self.test_group = test_group_definition
|
||||
self.tests = tests
|
||||
|
||||
def print_tests_description(self):
|
||||
utils.print_list(self, self.test_attrs)
|
||||
|
||||
def print_description(self):
|
||||
utils.print_dict(self)
|
||||
|
||||
|
||||
class ValidationPlugin(object):
|
||||
|
||||
test_executor = "%(test_module_path)s:%(class)s.%(test)s"
|
||||
|
||||
def __init__(self, name, suites, load_tests=True):
|
||||
__suites = []
|
||||
for suite in suites:
|
||||
__suites.extend(suite.TESTS)
|
||||
|
||||
self.name = name
|
||||
self.suites = __suites
|
||||
self._suites = suites
|
||||
self.tests = (self.get_tests()
|
||||
if load_tests else [])
|
||||
|
||||
def get_tests(self):
|
||||
"""
|
||||
Test collector
|
||||
"""
|
||||
tests = []
|
||||
for suite in self._suites:
|
||||
_tests = discovery.do_test_discovery(
|
||||
suite.TESTS)
|
||||
tests.extend(_tests)
|
||||
return tests
|
||||
|
||||
def _collect_test(self, tests):
|
||||
test_suites_paths = []
|
||||
for test in tests:
|
||||
classpath, test_method = test.split(":")
|
||||
classname = classpath.split(".")[-1]
|
||||
module = importutils.import_class(
|
||||
classpath).__module__
|
||||
test_module_path = os.path.abspath(
|
||||
sys.modules[module].__file__)
|
||||
if test_module_path.endswith("pyc"):
|
||||
test_module_path = test_module_path[:-1]
|
||||
test_suites_paths.append(
|
||||
self.test_executor %
|
||||
{
|
||||
'test_module_path': test_module_path,
|
||||
'class': classname,
|
||||
'test': test_method
|
||||
})
|
||||
return test_suites_paths
|
||||
|
||||
def get_tests_by_suite(self, suite):
|
||||
tests = []
|
||||
for test in self.tests:
|
||||
if suite in test:
|
||||
tests.append(test)
|
||||
return tests
|
||||
|
||||
def descriptor(self):
|
||||
"""
|
||||
Returns Plugin descriptor that contains:
|
||||
- plugin name
|
||||
- plugin suites
|
||||
- plugin tests
|
||||
"""
|
||||
return {
|
||||
"name": self.name,
|
||||
"suites": self.suites,
|
||||
"tests": self.tests,
|
||||
}
|
||||
|
||||
def run_suites(self):
|
||||
"""
|
||||
Runs all tests from all suites
|
||||
"""
|
||||
raise Exception("Plugin doesn't support suites execution.")
|
||||
|
||||
def run_suite(self, suite):
|
||||
"""
|
||||
Runs specific suite
|
||||
"""
|
||||
raise Exception("Plugin doesn't support suite execution.")
|
||||
|
||||
def run_test(self, test):
|
||||
"""
|
||||
Runs specific test
|
||||
"""
|
||||
raise Exception("Plugin doesn't support test execution.")
|
||||
|
||||
def run_suite_within_cli(self, suite):
|
||||
"""
|
||||
Runs test suite with view for CLI
|
||||
"""
|
||||
raise Exception("CLI execution is not supported.")
|
||||
|
||||
def run_suites_within_cli(self):
|
||||
"""
|
||||
Runs test suites with view for CLI
|
||||
"""
|
||||
raise Exception("CLI execution is not supported.")
|
||||
|
||||
def run_test_within_cli(self, test):
|
||||
"""
|
||||
Runs test suites with view for CLI
|
||||
"""
|
||||
raise Exception("CLI execution is not supported.")
|
@ -1,178 +0,0 @@
|
||||
# Copyright 2015 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 sys
|
||||
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
|
||||
from nose import core
|
||||
from oslo_utils import importutils
|
||||
|
||||
from cloudv_ostf_adapter.common import cfg
|
||||
from cloudv_ostf_adapter.common import object_descriptors
|
||||
from cloudv_ostf_adapter.validation_plugin import base
|
||||
from cloudv_ostf_adapter.validation_plugin.fuel_health import sanity
|
||||
from cloudv_ostf_adapter.validation_plugin.fuel_health import smoke
|
||||
from cloudv_ostf_adapter.validation_plugin.fuel_health import high_availability
|
||||
from cloudv_ostf_adapter.validation_plugin.fuel_health import platform
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
SUITES = [
|
||||
sanity,
|
||||
smoke,
|
||||
high_availability,
|
||||
platform,
|
||||
]
|
||||
|
||||
|
||||
class FuelHealthPlugin(base.ValidationPlugin):
|
||||
|
||||
def setup_fuel_health_on_need(self):
|
||||
FUEL_HEALTH_CONF = importutils.import_module("fuel_health.config")
|
||||
|
||||
@FUEL_HEALTH_CONF.process_singleton
|
||||
class MonkeyPatchFuelHealthConf(object):
|
||||
|
||||
def __init__(self):
|
||||
self.register_opts()
|
||||
self.compute = cfg.CONF.compute
|
||||
self.identity = cfg.CONF.identity
|
||||
self.network = cfg.CONF.network
|
||||
self.volume = cfg.CONF.volume
|
||||
self.murano = cfg.CONF.murano
|
||||
self.heat = cfg.CONF.heat
|
||||
self.sahara = cfg.CONF.sahara
|
||||
|
||||
def register_opts(self):
|
||||
FUEL_HEALTH_CONF.register_compute_opts(CONF)
|
||||
FUEL_HEALTH_CONF.register_identity_opts(CONF)
|
||||
FUEL_HEALTH_CONF.register_network_opts(CONF)
|
||||
FUEL_HEALTH_CONF.register_volume_opts(CONF)
|
||||
FUEL_HEALTH_CONF.register_murano_opts(CONF)
|
||||
FUEL_HEALTH_CONF.register_heat_opts(CONF)
|
||||
FUEL_HEALTH_CONF.register_sahara_opts(CONF)
|
||||
|
||||
FUEL_HEALTH_CONF.FileConfig = MonkeyPatchFuelHealthConf
|
||||
|
||||
MonkeyPatchFuelHealthConf()
|
||||
|
||||
def __init__(self, load_tests=True):
|
||||
self.setup_fuel_health_on_need()
|
||||
super(FuelHealthPlugin, self).__init__(
|
||||
'fuel_health', SUITES, load_tests=load_tests)
|
||||
|
||||
def get_tests(self):
|
||||
try:
|
||||
return super(FuelHealthPlugin, self).get_tests()
|
||||
except Exception:
|
||||
print("fuel_health is not installed.")
|
||||
|
||||
def _get_duration_from_report(self, report):
|
||||
for line in report:
|
||||
if line.startswith("Ran"):
|
||||
return line.split(" ")[-1]
|
||||
|
||||
def _get_test_name_from_report(self, report):
|
||||
if len(report) and not report[0].startswith('ERROR'):
|
||||
return report[0]
|
||||
return ''
|
||||
|
||||
def _get_test_name_from_class(self, cls_name):
|
||||
return cls_name.split(':')[1]
|
||||
|
||||
def _execute_and_report(self, test_suite_paths):
|
||||
"""
|
||||
Executes and assembles report right after each test execution
|
||||
@param test_suite_paths: FS-based path to python module
|
||||
@type test_suite_paths: list of basestring
|
||||
@rtype: list of object_descriptors.Test
|
||||
"""
|
||||
reports = []
|
||||
for test in test_suite_paths:
|
||||
suites_report = StringIO()
|
||||
sys.stderr = suites_report
|
||||
result = core.TestProgram(
|
||||
argv=["--tests", test, CONF.nose_verbosity],
|
||||
exit=False).success
|
||||
|
||||
test_descr = object_descriptors.Test(test)
|
||||
test_descr.report = "".join(suites_report.buflist)
|
||||
|
||||
# @TODO(okyrylchuk): there's no way to extract test
|
||||
# description from report when test fails, so it should
|
||||
# be implemented in a rather different way
|
||||
|
||||
_name = self._get_test_name_from_report(suites_report.buflist)
|
||||
_name = _name or self._get_test_name_from_class(test_descr.name)
|
||||
|
||||
test_descr.name = _name
|
||||
|
||||
test_descr.duration = self._get_duration_from_report(
|
||||
suites_report.buflist)
|
||||
test_descr.result = "Passed" if result else "Failed"
|
||||
|
||||
reports.append(test_descr)
|
||||
|
||||
return reports
|
||||
|
||||
def run_suites(self):
|
||||
safe_stderr = sys.stderr
|
||||
test_suites_paths = self.setup_execution(self.tests)
|
||||
reports = self._execute_and_report(test_suites_paths)
|
||||
sys.stderr = safe_stderr
|
||||
return reports
|
||||
|
||||
def setup_execution(self, tests):
|
||||
test_suites_paths = self._collect_test(tests)
|
||||
os.environ.update(
|
||||
{"CUSTOM_FUEL_CONFIG": CONF.health_check_config_path})
|
||||
return test_suites_paths
|
||||
|
||||
def run_suite(self, suite):
|
||||
safe_stderr = sys.stderr
|
||||
if ":" in suite:
|
||||
raise Exception(
|
||||
"%s is a test case, but not test suite." % suite)
|
||||
else:
|
||||
tests = self.get_tests_by_suite(suite)
|
||||
test_suites_paths = self.setup_execution(tests)
|
||||
reports = self._execute_and_report(test_suites_paths)
|
||||
sys.stderr = safe_stderr
|
||||
return reports
|
||||
|
||||
def run_suites_within_cli(self):
|
||||
return self.run_suites()
|
||||
|
||||
def run_suite_within_cli(self, suite):
|
||||
return self.run_suite(suite)
|
||||
|
||||
def run_test(self, test):
|
||||
safe_stderr = sys.stderr
|
||||
if ":" not in test:
|
||||
raise Exception(
|
||||
"%s is a test suite, but not test case." % test)
|
||||
else:
|
||||
test_suites_paths = self.setup_execution([test])
|
||||
reports = self._execute_and_report(test_suites_paths)
|
||||
sys.stderr = safe_stderr
|
||||
return reports
|
||||
|
||||
def run_test_within_cli(self, test):
|
||||
return self.run_test(test)
|
@ -1,24 +0,0 @@
|
||||
# Copyright 2015 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 cloudv_ostf_adapter.common import cfg
|
||||
from cloudv_ostf_adapter.validation_plugin import base
|
||||
|
||||
GROUP = 'high_availability'
|
||||
CONF = cfg.CONF
|
||||
TESTS = CONF.get(GROUP).enabled_tests
|
||||
|
||||
|
||||
def get_tests():
|
||||
return base.SuiteDescriptor(GROUP, TESTS)
|
@ -1,24 +0,0 @@
|
||||
# Copyright 2015 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 cloudv_ostf_adapter.common import cfg
|
||||
from cloudv_ostf_adapter.validation_plugin import base
|
||||
|
||||
GROUP = 'platform'
|
||||
CONF = cfg.CONF
|
||||
TESTS = CONF.get(GROUP).enabled_tests
|
||||
|
||||
|
||||
def get_tests():
|
||||
return base.SuiteDescriptor(GROUP, TESTS)
|
@ -1,24 +0,0 @@
|
||||
# Copyright 2015 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 cloudv_ostf_adapter.common import cfg
|
||||
from cloudv_ostf_adapter.validation_plugin import base
|
||||
|
||||
GROUP = 'sanity'
|
||||
CONF = cfg.CONF
|
||||
TESTS = CONF.get(GROUP).enabled_tests
|
||||
|
||||
|
||||
def get_tests():
|
||||
return base.SuiteDescriptor(GROUP, TESTS)
|
@ -1,24 +0,0 @@
|
||||
# Copyright 2015 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 cloudv_ostf_adapter.common import cfg
|
||||
from cloudv_ostf_adapter.validation_plugin import base
|
||||
|
||||
GROUP = 'smoke'
|
||||
CONF = cfg.CONF
|
||||
TESTS = CONF.get(GROUP).enabled_tests
|
||||
|
||||
|
||||
def get_tests():
|
||||
return base.SuiteDescriptor(GROUP, TESTS)
|
@ -1,16 +0,0 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
release = "cloudv-ostf-adapter"
|
||||
version = "2015.1"
|
@ -1,272 +0,0 @@
|
||||
# Copyright 2015 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 multiprocessing
|
||||
import os
|
||||
import os.path
|
||||
import uuid
|
||||
|
||||
from flask.ext import restful
|
||||
from flask.ext.restful import abort
|
||||
from flask.ext.restful import reqparse
|
||||
from flask import request
|
||||
from oslo_config import cfg
|
||||
|
||||
from cloudv_ostf_adapter import validation_plugin
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
CREATED = 'CREATED'
|
||||
IN_PROGRESS = 'IN PROGRESS'
|
||||
COMPLETED = 'COMPLETED'
|
||||
|
||||
|
||||
class BaseTests(restful.Resource):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BaseTests, self).__init__(*args, **kwargs)
|
||||
self.plugins = {}
|
||||
for plugin in validation_plugin.VALIDATION_PLUGINS:
|
||||
_plugin = plugin(load_tests=False)
|
||||
self.plugins[_plugin.name] = _plugin
|
||||
|
||||
def load_tests(self):
|
||||
for plugin in self.plugins.values():
|
||||
plugin.tests = plugin.get_tests()
|
||||
|
||||
def get_plugin(self, **kwargs):
|
||||
plugin = kwargs.pop('plugin', None)
|
||||
if plugin is None or plugin not in self.plugins:
|
||||
abort(404,
|
||||
message='Unsupported plugin %s.' % plugin)
|
||||
return self.plugins[plugin]
|
||||
|
||||
def get_suite(self, plugin, suite=None):
|
||||
if suite not in plugin.suites:
|
||||
abort(404,
|
||||
message='Unknown suite %s.' % suite)
|
||||
return suite
|
||||
|
||||
def path_from_job_name(self, job_id):
|
||||
return '/'.join((CONF.rest.jobs_dir, job_id))
|
||||
|
||||
def get_job(self, **kwargs):
|
||||
job_id = kwargs.pop('job_id', None)
|
||||
if job_id is None:
|
||||
abort(400,
|
||||
message="Job id is missing.")
|
||||
file_name = self.path_from_job_name(job_id)
|
||||
if not os.path.exists(file_name):
|
||||
abort(404,
|
||||
message="Job not found.")
|
||||
return (job_id, file_name)
|
||||
|
||||
|
||||
class Plugins(BaseTests):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Plugins, self).__init__(*args, **kwargs)
|
||||
self.parser = reqparse.RequestParser()
|
||||
self.parser.add_argument('load_tests',
|
||||
type=str,
|
||||
location='args',
|
||||
required=False)
|
||||
|
||||
def get(self, **kwargs):
|
||||
args = self.parser.parse_args()
|
||||
load_tests = args.pop('load_tests', False)
|
||||
if load_tests in ['True', 'true', '1']:
|
||||
self.load_tests()
|
||||
plugins = [
|
||||
{'name': p.name,
|
||||
'suites': p.suites,
|
||||
'tests': p.tests}
|
||||
for p in self.plugins.values()
|
||||
]
|
||||
return {'plugins': plugins}
|
||||
|
||||
|
||||
class PluginSuite(BaseTests):
|
||||
|
||||
def get(self, **kwargs):
|
||||
plugin = self.get_plugin(**kwargs)
|
||||
return {'plugin': {'name': plugin.name,
|
||||
'suites': plugin.suites}}
|
||||
|
||||
def post(self, **kwargs):
|
||||
plugin = self.get_plugin(**kwargs)
|
||||
self.load_tests()
|
||||
reports = plugin.run_suites()
|
||||
report = [r.description for r in reports]
|
||||
return {"plugin": {"name": plugin.name,
|
||||
"report": report}}
|
||||
|
||||
|
||||
class PluginTests(BaseTests):
|
||||
|
||||
def get(self, **kwargs):
|
||||
plugin = self.get_plugin(**kwargs)
|
||||
self.load_tests()
|
||||
return {'plugin': {'name': plugin.name,
|
||||
'tests': plugin.tests}}
|
||||
|
||||
|
||||
class Suites(BaseTests):
|
||||
|
||||
def get(self, **kwargs):
|
||||
plugin = self.get_plugin(**kwargs)
|
||||
_suite = kwargs.pop('suite', None)
|
||||
suite = self.get_suite(plugin, suite=_suite)
|
||||
self.load_tests()
|
||||
tests = plugin.get_tests_by_suite(suite)
|
||||
return {'plugin': {'name': plugin.name,
|
||||
'suite': {'name': suite,
|
||||
'tests': tests}}}
|
||||
|
||||
def post(self, **kwargs):
|
||||
plugin = self.get_plugin(**kwargs)
|
||||
_suite = kwargs.pop('suite', None)
|
||||
suite = self.get_suite(plugin, suite=_suite)
|
||||
self.load_tests()
|
||||
reports = plugin.run_suite(suite)
|
||||
report = [r.description for r in reports]
|
||||
return {"suite": {"name": suite,
|
||||
"report": report}}
|
||||
|
||||
|
||||
class Tests(BaseTests):
|
||||
|
||||
def post(self, **kwargs):
|
||||
plugin = self.get_plugin(**kwargs)
|
||||
self.load_tests()
|
||||
test = kwargs.pop('test', None)
|
||||
if test is None or test not in plugin.tests:
|
||||
abort(404,
|
||||
message="Test %s not found." % test)
|
||||
reports = plugin.run_test(test)
|
||||
report = [r.description for r in reports]
|
||||
return {"plugin": {"name": plugin.name,
|
||||
"test": test,
|
||||
"report": report}}
|
||||
|
||||
|
||||
class JobsCreation(BaseTests):
|
||||
|
||||
def post(self, **kwargs):
|
||||
try:
|
||||
data = request.json
|
||||
except Exception:
|
||||
abort(400,
|
||||
message="JSON is missing.")
|
||||
if data is None:
|
||||
abort(400,
|
||||
message="JSON is missing.")
|
||||
job = data.get('job', None)
|
||||
if job is None:
|
||||
abort(400,
|
||||
message="JSON doesn't have `job` key.")
|
||||
mandatory = ['name',
|
||||
'tests',
|
||||
'description']
|
||||
missing = set(mandatory) - set(job.keys())
|
||||
missing = list(missing)
|
||||
missing.sort()
|
||||
if missing:
|
||||
abort(400,
|
||||
message="Fields %s are not specified." % ','.join(missing))
|
||||
self.load_tests()
|
||||
filtered_tests = []
|
||||
for p in self.plugins.values():
|
||||
tests_in_plugin = set(p.tests) & set(job['tests'])
|
||||
filtered_tests.extend(tests_in_plugin)
|
||||
not_found = set(job['tests']) - set(filtered_tests)
|
||||
not_found = list(not_found)
|
||||
not_found.sort()
|
||||
if not_found:
|
||||
abort(400,
|
||||
message="Tests not found (%s)." % ','.join(not_found))
|
||||
job_uuid = str(uuid.uuid4())
|
||||
file_name = self.path_from_job_name(job_uuid)
|
||||
job['status'] = CREATED
|
||||
with open(file_name, 'w') as f:
|
||||
f.write(json.dumps(job))
|
||||
job['id'] = job_uuid
|
||||
return {'job': job}
|
||||
|
||||
|
||||
class Execute(BaseTests):
|
||||
|
||||
def post(self, **kwargs):
|
||||
job_id, file_name = self.get_job(**kwargs)
|
||||
data = {}
|
||||
with open(file_name, 'r') as f:
|
||||
data = json.loads(f.read())
|
||||
with open(file_name, 'w') as f:
|
||||
data['status'] = IN_PROGRESS
|
||||
data['report'] = []
|
||||
f.write(json.dumps(data))
|
||||
p = multiprocessing.Process(target=self._execute_job,
|
||||
args=(data, job_id))
|
||||
p.start()
|
||||
job = data.copy()
|
||||
job['id'] = job_id
|
||||
return {'job': job}
|
||||
|
||||
def _execute_job(self, data, job_id):
|
||||
tests = data['tests']
|
||||
self.load_tests()
|
||||
reports = []
|
||||
for name, plugin in self.plugins.iteritems():
|
||||
tests_in_plugin = set(plugin.tests) & set(tests)
|
||||
for test in tests_in_plugin:
|
||||
results = plugin.run_test(test)
|
||||
report = [r.description for r in results].pop()
|
||||
report['test'] = test
|
||||
reports.append(report)
|
||||
data['status'] = COMPLETED
|
||||
data['report'] = reports
|
||||
file_name = self.path_from_job_name(job_id)
|
||||
with open(file_name, 'w') as f:
|
||||
f.write(json.dumps(data))
|
||||
|
||||
|
||||
class Job(BaseTests):
|
||||
|
||||
def get(self, **kwargs):
|
||||
job_id, file_name = self.get_job(**kwargs)
|
||||
data = {}
|
||||
with open(file_name, 'r') as f:
|
||||
data = json.loads(f.read())
|
||||
job = data.copy()
|
||||
job['id'] = job_id
|
||||
return {'job': job}
|
||||
|
||||
def delete(self, **kwargs):
|
||||
job_id, file_name = self.get_job(**kwargs)
|
||||
os.remove(file_name)
|
||||
return {}
|
||||
|
||||
|
||||
class Jobs(BaseTests):
|
||||
|
||||
def get(self):
|
||||
res = []
|
||||
jobs = [f for (dp, dn, f) in os.walk(CONF.rest.jobs_dir)][0]
|
||||
for job in jobs:
|
||||
file_name = self.path_from_job_name(job)
|
||||
with open(file_name, 'r') as f:
|
||||
data = json.loads(f.read())
|
||||
data['id'] = job
|
||||
res.append(data)
|
||||
return {'jobs': res}
|
@ -1,316 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration ----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.todo',
|
||||
'sphinx.ext.viewcode',
|
||||
'oslosphinx']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'cloudv-ostf-adapter'
|
||||
copyright = u'2013, OpenStack Foundation'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
from cloudv_ostf_adapter import version
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = version.release
|
||||
# The short X.Y version.
|
||||
version = version.release
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
modindex_common_prefix = ['cloudv_ostf_adapter.']
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
# html_theme_path = ["."]
|
||||
# html_theme = '_theme'
|
||||
# html_static_path = ['_static']
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
# html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
|
||||
|
||||
# -- Options for LaTeX output -------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual])
|
||||
latex_documents = [
|
||||
(
|
||||
'index',
|
||||
'%s.tex' % project,
|
||||
u'%s Documentation' % project,
|
||||
u'OpenStack Foundation',
|
||||
'manual'
|
||||
),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output -------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
# man_pages = [
|
||||
# (
|
||||
# 'index',
|
||||
# '%s' % project,
|
||||
# u'%s Documentation' % project,
|
||||
# u'OpenStack Foundation',
|
||||
# 1
|
||||
# ),
|
||||
# ]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -----------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(
|
||||
'index',
|
||||
'%s' % project,
|
||||
u'%s Documentation' % project,
|
||||
u'OpenStack Foundation',
|
||||
'%s' % project,
|
||||
'Database as a service.',
|
||||
'Miscellaneous'
|
||||
'manual'
|
||||
),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
|
||||
|
||||
# -- Options for Epub output --------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = u'%s' % project
|
||||
epub_author = u'OpenStack Foundation'
|
||||
epub_publisher = u'OpenStack Foundation'
|
||||
epub_copyright = u'2013, OpenStack Foundation'
|
||||
|
||||
# The language of the text. It defaults to the language option
|
||||
# or en if the language is not set.
|
||||
#epub_language = ''
|
||||
|
||||
# The scheme of the identifier. Typical schemes are ISBN or URL.
|
||||
#epub_scheme = ''
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#epub_uid = ''
|
||||
|
||||
# A tuple containing the cover image and cover page html template filenames.
|
||||
#epub_cover = ()
|
||||
|
||||
# A sequence of (type, uri, title) tuples for the guide element of content.opf.
|
||||
#epub_guide = ()
|
||||
|
||||
# HTML files that should be inserted before the pages created by sphinx.
|
||||
# The format is a list of tuples containing the path and title.
|
||||
#epub_pre_files = []
|
||||
|
||||
# HTML files shat should be inserted after the pages created by sphinx.
|
||||
# The format is a list of tuples containing the path and title.
|
||||
#epub_post_files = []
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
#epub_exclude_files = []
|
||||
|
||||
# The depth of the table of contents in toc.ncx.
|
||||
#epub_tocdepth = 3
|
||||
|
||||
# Allow duplicate toc entries.
|
||||
#epub_tocdup = True
|
||||
|
||||
# Fix unsupported image types using the PIL.
|
||||
#epub_fix_images = False
|
||||
|
||||
# Scale large images.
|
||||
#epub_max_image_width = 0
|
||||
|
||||
# If 'no', URL addresses will not be shown.
|
||||
#epub_show_urls = 'inline'
|
||||
|
||||
# If false, no index is generated.
|
||||
#epub_use_index = True
|
@ -1,4 +0,0 @@
|
||||
====================
|
||||
Cloudvalidation tool
|
||||
====================
|
||||
|
@ -1,17 +0,0 @@
|
||||
[DEFAULT]
|
||||
health_check_config_path = /etc/cloudv-ostf-adapter/test.conf
|
||||
|
||||
[rest]
|
||||
server_host=127.0.0.1
|
||||
server_port=8777
|
||||
log_file=/var/log/ostf.log
|
||||
debug=False
|
||||
jobs_dir=/var/log/ostf
|
||||
|
||||
[sanity]
|
||||
|
||||
[smoke]
|
||||
|
||||
[platform]
|
||||
|
||||
[high_availability]
|
@ -1,41 +0,0 @@
|
||||
[identity]
|
||||
disable_ssl_certificate_validatio = True
|
||||
uri = http://172.18.196.219:5000/v2.0/
|
||||
url = http://172.18.196.219:5000/v2.0/
|
||||
ubuntu_url = http://172.18.196.219:5000/v2.0/
|
||||
strategy = keystone
|
||||
admin_username = admin
|
||||
admin_tenant_name = admin
|
||||
admin_password = 3de4922d8b6ac5a1aad9
|
||||
|
||||
[compute]
|
||||
flavor_ref = 2
|
||||
compute_nodes = 172.18.196.219
|
||||
online_computes = 172.18.196.219
|
||||
deployment_os = Ubuntu
|
||||
libvirt_type = qemu
|
||||
image_name = mysql
|
||||
online_controllers = 172.18.196.219
|
||||
controller_node_ssh_key_path = /home/ubuntu/.ssh/id_rsa
|
||||
controller_node_ssh_user = ubuntu
|
||||
ssh_timeout = 700
|
||||
controller_node_ssh_password = ''
|
||||
image_ssh_user = ubuntu
|
||||
image_alt_ssh_user = ubuntu
|
||||
ssh_user = ubuntu
|
||||
path_to_private_key = /home/ubuntu/.ssh/id_rsa
|
||||
|
||||
[network]
|
||||
# tenant_network_cidr = ?
|
||||
|
||||
[volume]
|
||||
backend1_name = lvmdriver-1
|
||||
backend2_name = lvmdriver-1
|
||||
|
||||
[heat]
|
||||
endpoint = http://172.18.196.219:8004/v1
|
||||
|
||||
[murano]
|
||||
# Please note that this URLs are fake, the are needed to instantiate unnecessary/redundant muranoclient
|
||||
api_url = http://172.18.196.219:8082/v1
|
||||
api_url_management = http://172.18.196.219:8082/v1
|
@ -1,171 +0,0 @@
|
||||
[identity]
|
||||
# This section contains configuration options that a variety of
|
||||
# test clients use when authenticating with different user/tenant
|
||||
# combinations
|
||||
url = http://localhost/
|
||||
# The type of endpoint for a Identity service. Unless you have a
|
||||
# custom Keystone service catalog implementation, you probably want to leave
|
||||
# this value as "identity"
|
||||
catalog_type = identity
|
||||
# Ignore SSL certificate validation failures? Use when in testing
|
||||
# environments that have self-signed SSL certs.
|
||||
disable_ssl_certificate_validation = False
|
||||
# URL for where to find the OpenStack Identity API endpoint (Keystone)
|
||||
uri = http://localhost:5000/v2.0/
|
||||
# URL for where to find the OpenStack V3 Identity API endpoint (Keystone)
|
||||
#uri_v3 = http://127.0.0.1:5000/v3/
|
||||
# Should typically be left as keystone unless you have a non-Keystone
|
||||
# authentication API service
|
||||
strategy = keystone
|
||||
# The identity region
|
||||
region = RegionOne
|
||||
|
||||
# This should be the username of a user WITH administrative privileges
|
||||
admin_username = nova
|
||||
# The above administrative user's password
|
||||
admin_password = nova
|
||||
# The above administrative user's tenant name
|
||||
admin_tenant_name = service
|
||||
|
||||
[compute]
|
||||
# This section contains configuration options used when executing tests
|
||||
# against the OpenStack Compute API.
|
||||
|
||||
#One of the controller nodes
|
||||
controller_nodes = localhost
|
||||
controller_nodes_name = controller
|
||||
|
||||
#Controller node user who able connect via ssh
|
||||
controller_node_ssh_user = root
|
||||
|
||||
#Controller node ssh user's password
|
||||
controller_node_ssh_password = r00tme
|
||||
controller_node_ssh_key_path = /root/.ssh/id_rsa
|
||||
|
||||
#The list of the services should be enabled
|
||||
enabled_services=nova-cert, nova-consoleauth, nova-scheduler, nova-conductor, nova-compute, nova-network, nova-compute, nova-network
|
||||
|
||||
# Allows test cases to create/destroy tenants and users. This option
|
||||
# enables isolated test cases and better parallel execution,
|
||||
# but also requires that OpenStack Identity API admin credentials
|
||||
# are known.
|
||||
allow_tenant_isolation = True
|
||||
|
||||
# Allows test cases to create/destroy tenants and users. This option
|
||||
# enables isolated test cases and better parallel execution,
|
||||
# but also requires that OpenStack Identity API admin credentials
|
||||
# are known.
|
||||
allow_tenant_reuse = true
|
||||
|
||||
# Reference data for tests. The ref and ref_alt should be
|
||||
# distinct images/flavors.
|
||||
image_name = TestVM
|
||||
flavor_ref = 1
|
||||
|
||||
# User names used to authenticate to an instance for a given image.
|
||||
image_ssh_user = cirros
|
||||
image_alt_ssh_user = cirros
|
||||
|
||||
# Number of seconds to wait while looping to check the status of an
|
||||
# instance that is building.
|
||||
build_interval = 3
|
||||
|
||||
# Number of seconds to time out on waiting for an instance
|
||||
# to build or reach an expected status
|
||||
build_timeout = 300
|
||||
|
||||
# Run additional tests that use SSH for instance validation?
|
||||
# This requires the instances be routable from the host
|
||||
# executing the tests
|
||||
run_ssh = false
|
||||
|
||||
# Number of seconds to wait to authenticate to an instance
|
||||
ssh_timeout = 300
|
||||
|
||||
# Number of seconds to wait for output from ssh channel
|
||||
ssh_channel_timeout = 60
|
||||
|
||||
# The type of endpoint for a Compute API service. Unless you have a
|
||||
# custom Keystone service catalog implementation, you probably want to leave
|
||||
# this value as "compute"
|
||||
catalog_type = compute
|
||||
|
||||
# Does the Compute API support creation of images?
|
||||
create_image_enabled = true
|
||||
|
||||
[image]
|
||||
# This section contains configuration options used when executing tests
|
||||
# against the OpenStack Images API
|
||||
|
||||
# The type of endpoint for an Image API service. Unless you have a
|
||||
# custom Keystone service catalog implementation, you probably want to leave
|
||||
# this value as "image"
|
||||
catalog_type = image
|
||||
|
||||
# The version of the OpenStack Images API to use
|
||||
api_version = 1
|
||||
|
||||
# HTTP image to use for glance http image testing
|
||||
http_image = http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz
|
||||
|
||||
[network]
|
||||
# This section contains configuration options used when executing tests
|
||||
# against the OpenStack Network API.
|
||||
|
||||
# Version of the Quantum API
|
||||
api_version = 2.0
|
||||
# Catalog type of the Quantum Service
|
||||
catalog_type = network
|
||||
|
||||
# A large private cidr block from which to allocate smaller blocks for
|
||||
# tenant networks.
|
||||
tenant_network_cidr = 10.13.0.0/16
|
||||
|
||||
# The mask bits used to partition the tenant block.
|
||||
tenant_network_mask_bits = 28
|
||||
|
||||
# If tenant networks are reachable, connectivity checks will be
|
||||
# performed directly against addresses on those networks.
|
||||
tenant_networks_reachable = true
|
||||
|
||||
# Whether or not quantum is expected to be available
|
||||
quantum_available = false
|
||||
|
||||
[volume]
|
||||
# This section contains the configuration options used when executing tests
|
||||
# against the OpenStack Block Storage API service
|
||||
|
||||
# The type of endpoint for a Cinder or Block Storage API service.
|
||||
# Unless you have a custom Keystone service catalog implementation, you
|
||||
# probably want to leave this value as "volume"
|
||||
catalog_type = volume
|
||||
# Number of seconds to wait while looping to check the status of a
|
||||
# volume that is being made available
|
||||
build_interval = 3
|
||||
# Number of seconds to time out on waiting for a volume
|
||||
# to be available or reach an expected status
|
||||
build_timeout = 300
|
||||
# Runs Cinder multi-backend tests (requires 2 backends declared in cinder.conf)
|
||||
# They must have different volume_backend_name (backend1_name and backend2_name
|
||||
# have to be different)
|
||||
multi_backend_enabled = false
|
||||
backend1_name = BACKEND_1
|
||||
backend2_name = BACKEND_2
|
||||
|
||||
[object-storage]
|
||||
# This section contains configuration options used when executing tests
|
||||
# against the OpenStack Object Storage API.
|
||||
|
||||
# You can configure the credentials in the compute section
|
||||
|
||||
# The type of endpoint for an Object Storage API service. Unless you have a
|
||||
# custom Keystone service catalog implementation, you probably want to leave
|
||||
# this value as "object-store"
|
||||
catalog_type = object-store
|
||||
|
||||
# Number of seconds to time on waiting for a container to container
|
||||
# synchronization complete
|
||||
container_sync_timeout = 120
|
||||
# Number of seconds to wait while looping to check the status of a
|
||||
# container to container synchronization
|
||||
container_sync_interval = 5
|
@ -1,16 +0,0 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
flask
|
||||
flask-restful
|
||||
nose
|
||||
oslo.config>=1.6.0 # Apache-2.0
|
||||
pbr>=0.6,!=0.7,<1.0
|
||||
oslo.utils
|
||||
PrettyTable>=0.7,<0.8
|
||||
requests>=2.2.0,!=2.4.0
|
||||
simplejson>=2.2.0
|
||||
|
||||
#TODO(???): move this fix into fuel-ostf
|
||||
python-muranoclient
|
50
setup.cfg
50
setup.cfg
@ -1,50 +0,0 @@
|
||||
[metadata]
|
||||
name = cloudv-ostf-adapter
|
||||
version = 2015.1
|
||||
summary = CloudValidation OSTF adapter
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
classifier =
|
||||
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
|
||||
|
||||
[files]
|
||||
packages =
|
||||
cloudv_ostf_adapter
|
||||
cloudv_client
|
||||
|
||||
[compile_catalog]
|
||||
domain = cloudv_ostf_adapter
|
||||
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
cloudvalidation-cli = cloudv_ostf_adapter.cmd.cli:main
|
||||
cloudvalidation-server = cloudv_ostf_adapter.cmd.server:main
|
||||
cloudvalidation = cloudv_ostf_adapter.cmd.client:main
|
||||
|
||||
[global]
|
||||
setup-hooks =
|
||||
pbr.hooks.setup_hook
|
||||
|
||||
[build_sphinx]
|
||||
all_files = 1
|
||||
build-dir = doc/build
|
||||
source-dir = doc/source
|
||||
|
||||
[nosetests]
|
||||
match=^test
|
||||
where=cloudv_ostf_adapter
|
||||
nocapture=1
|
||||
cover-package=cloudv_ostf_adapter
|
||||
cover-erase=1
|
||||
|
||||
[wheel]
|
||||
universal = 1
|
31
setup.py
31
setup.py
@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
||||
# In python < 2.7.4, a lazy loading of package `pbr` will break
|
||||
# setuptools if some other modules registered functions in `atexit`.
|
||||
# solution from: http://bugs.python.org/issue15881#msg170215
|
||||
try:
|
||||
import multiprocessing # noqa
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True
|
||||
)
|
@ -1,11 +0,0 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
# Hacking already pins down pep8, pyflakes and flake8
|
||||
hacking>=0.8.0,<0.9
|
||||
mock>=1.0
|
||||
testtools>=0.9.36,!=1.2.0
|
||||
testrepository>=0.0.18
|
||||
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
||||
oslosphinx>=2.2.0 # Apache-2.0
|
33
tox.ini
33
tox.ini
@ -1,33 +0,0 @@
|
||||
[tox]
|
||||
envlist = py27
|
||||
minversion = 1.6
|
||||
skipsdist = True
|
||||
|
||||
[tox:jenkins]
|
||||
sitepackages = True
|
||||
|
||||
[testenv]
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
usedevelop = True
|
||||
install_command = pip install -U {opts} {packages}
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
# https://github.com/stackforge/fuel-ostf/archive/6.0.tar.gz#egg=fuel-ostf==6.0
|
||||
commands =
|
||||
python setup.py testr --slowest
|
||||
whitelist_externals = bash
|
||||
|
||||
[testenv:pep8]
|
||||
commands =
|
||||
flake8
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[flake8]
|
||||
show-source = True
|
||||
ignore = F821,H301,H306,H404
|
||||
builtins = _
|
||||
exclude=.venv,.tox,dist,doc,openstack,*egg,rsdns,tools,etc,build,*.po,*.pot
|
||||
filename=*.py
|
Loading…
Reference in New Issue
Block a user