Merge "Remove V2 API version of coverage extensions"
This commit is contained in:
commit
7402a0ba78
|
@ -240,14 +240,6 @@
|
|||
"namespace": "http://docs.openstack.org/compute/ext/os-consoles/api/v2",
|
||||
"updated": "2011-12-23T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-coverage",
|
||||
"description": "Enable Nova Coverage.",
|
||||
"links": [],
|
||||
"name": "Coverage",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/coverage/api/v2",
|
||||
"updated": "2012-10-15T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"alias": "os-create-server-ext",
|
||||
"description": "Extended support to the Create Server v1.1 API.",
|
||||
|
@ -625,4 +617,4 @@
|
|||
"updated": "2011-03-25T00:00:00+00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,9 +106,6 @@
|
|||
<extension alias="os-consoles" updated="2011-12-23T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/os-consoles/api/v2" name="Consoles">
|
||||
<description>Interactive Console support.</description>
|
||||
</extension>
|
||||
<extension alias="os-coverage" updated="2012-10-15T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/coverage/api/v2" name="Coverage">
|
||||
<description>Enable Nova Coverage.</description>
|
||||
</extension>
|
||||
<extension alias="os-create-server-ext" updated="2011-07-19T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/createserverext/api/v1.1" name="Createserverext">
|
||||
<description>Extended support to the Create Server v1.1 API.</description>
|
||||
</extension>
|
||||
|
@ -254,4 +251,4 @@
|
|||
<extension alias="os-volumes" updated="2011-03-25T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/volumes/api/v1.1" name="Volumes">
|
||||
<description>Volumes support.</description>
|
||||
</extension>
|
||||
</extensions>
|
||||
</extensions>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"report" : {
|
||||
"file" : "report"
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report>
|
||||
<file>report</file>
|
||||
</report>
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"path": "/tmp/tmpV0Pno7/nova-coverage_D8L8SB/report"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<path>/tmp/tmpAqRtz5/nova-coverage_Iqja9E/report</path>
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"reset" : {
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<reset></reset>
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"start" : {
|
||||
"combine": true
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<start>
|
||||
<combine>True</combine>
|
||||
</start>
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"start" : {
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<start></start>
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"stop" : {
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stop></stop>
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"path": "/tmp/tmpua9HvB/nova-coverage_rs2CaS"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<path>/tmp/tmpCLve38/nova-coverage_GJ4BZ_</path>
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"report": {
|
||||
"xml": true,
|
||||
"file": "report"
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report>
|
||||
<file>report</file>
|
||||
<xml>True</xml>
|
||||
</report>
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"path": "/tmp/tmp6kdYaa/nova-coverage_TOTUbz/report"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<path>/tmp/tmp4j87bp/nova-coverage_7ViTA7/report</path>
|
|
@ -78,7 +78,6 @@
|
|||
"compute_extension:consoles": "",
|
||||
"compute_extension:v3:os-remote-consoles": "",
|
||||
"compute_extension:v3:os-remote-consoles:discoverable": "",
|
||||
"compute_extension:coverage_ext": "rule:admin_api",
|
||||
"compute_extension:createserverext": "",
|
||||
"compute_extension:deferred_delete": "",
|
||||
"compute_extension:v3:os-deferred-delete": "",
|
||||
|
|
|
@ -1,305 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 IBM Corp.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# See: http://wiki.openstack.org/Nova/CoverageExtension for more information
|
||||
# and usage explanation for this API extension
|
||||
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import telnetlib
|
||||
import tempfile
|
||||
|
||||
from oslo.config import cfg
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import extensions
|
||||
from nova import baserpc
|
||||
from nova import db
|
||||
from nova.openstack.common.gettextutils import _
|
||||
from nova.openstack.common import log as logging
|
||||
from nova.openstack.common.rpc import common as rpc_common
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
authorize = extensions.extension_authorizer('compute', 'coverage_ext')
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class CoverageController(object):
|
||||
"""The Coverage report API controller for the OpenStack API."""
|
||||
def __init__(self):
|
||||
self.data_path = None
|
||||
self.services = []
|
||||
self.combine = False
|
||||
self._cover_inst = None
|
||||
self.host = CONF.host
|
||||
super(CoverageController, self).__init__()
|
||||
|
||||
@property
|
||||
def coverInst(self):
|
||||
if not self._cover_inst:
|
||||
try:
|
||||
import coverage
|
||||
if self.data_path is None:
|
||||
self.data_path = tempfile.mkdtemp(prefix='nova-coverage_')
|
||||
data_out = os.path.join(self.data_path, '.nova-coverage.api')
|
||||
self._cover_inst = coverage.coverage(data_file=data_out)
|
||||
except ImportError:
|
||||
pass
|
||||
return self._cover_inst
|
||||
|
||||
def _find_services(self, req):
|
||||
"""Returns a list of services."""
|
||||
context = req.environ['nova.context']
|
||||
services = db.service_get_all(context)
|
||||
hosts = []
|
||||
for serv in services:
|
||||
hosts.append({"service": serv["topic"], "host": serv["host"]})
|
||||
return hosts
|
||||
|
||||
def _find_ports(self, req, hosts):
|
||||
"""Return a list of backdoor ports for all services in the list."""
|
||||
context = req.environ['nova.context']
|
||||
ports = []
|
||||
#TODO(mtreinish): Figure out how to bind the backdoor socket to 0.0.0.0
|
||||
# Currently this will only work if the host is resolved as loopback on
|
||||
# the same host as api-server
|
||||
for host in hosts:
|
||||
base = baserpc.BaseAPI(host['service'])
|
||||
_host = host
|
||||
try:
|
||||
_host['port'] = base.get_backdoor_port(context, host['host'])
|
||||
except rpc_common.UnsupportedRpcVersion:
|
||||
_host['port'] = None
|
||||
|
||||
#NOTE(mtreinish): if the port is None then it wasn't set in
|
||||
# the configuration file for this service. However, that
|
||||
# doesn't necessarily mean that we don't have backdoor ports
|
||||
# for all the services. So, skip the telnet connection for
|
||||
# this service.
|
||||
if _host['port']:
|
||||
ports.append(_host)
|
||||
else:
|
||||
LOG.warning(_("Can't connect to service: %s, no port"
|
||||
"specified\n"), host['service'])
|
||||
return ports
|
||||
|
||||
def _start_coverage_telnet(self, tn, service):
|
||||
data_file = os.path.join(self.data_path,
|
||||
'.nova-coverage.%s' % str(service))
|
||||
tn.write('from __future__ import print_function\n')
|
||||
tn.write('import sys\n')
|
||||
tn.write('from coverage import coverage\n')
|
||||
tn.write("coverInst = coverage(data_file='%s') "
|
||||
"if 'coverInst' not in locals() "
|
||||
"else coverInst\n" % data_file)
|
||||
tn.write('coverInst.skipModules = sys.modules.keys()\n')
|
||||
tn.write("coverInst.start()\n")
|
||||
tn.write("print('finished')\n")
|
||||
tn.expect([re.compile('finished')])
|
||||
|
||||
def _start_coverage(self, req, body):
|
||||
'''Begin recording coverage information.'''
|
||||
LOG.debug(_("Coverage begin"))
|
||||
body = body['start']
|
||||
self.combine = False
|
||||
if 'combine' in body.keys():
|
||||
self.combine = bool(body['combine'])
|
||||
self.coverInst.skipModules = sys.modules.keys()
|
||||
self.coverInst.start()
|
||||
hosts = self._find_services(req)
|
||||
ports = self._find_ports(req, hosts)
|
||||
self.services = []
|
||||
for service in ports:
|
||||
try:
|
||||
service['telnet'] = telnetlib.Telnet(service['host'],
|
||||
service['port'])
|
||||
# NOTE(mtreinish): Fallback to try connecting to lo if
|
||||
# ECONNREFUSED is raised. If using the hostname that is returned
|
||||
# for the service from the service_get_all() DB query raises
|
||||
# ECONNREFUSED it most likely means that the hostname in the DB
|
||||
# doesn't resolve to 127.0.0.1. Currently backdoors only open on
|
||||
# loopback so this is for covering the common single host use case
|
||||
except socket.error as e:
|
||||
exc_info = sys.exc_info()
|
||||
if 'ECONNREFUSED' in e and service['host'] == self.host:
|
||||
service['telnet'] = telnetlib.Telnet('127.0.0.1',
|
||||
service['port'])
|
||||
else:
|
||||
raise exc_info[0], exc_info[1], exc_info[2]
|
||||
self.services.append(service)
|
||||
self._start_coverage_telnet(service['telnet'], service['service'])
|
||||
|
||||
def _stop_coverage_telnet(self, tn):
|
||||
tn.write("coverInst.stop()\n")
|
||||
tn.write("coverInst.save()\n")
|
||||
tn.write("print('finished')\n")
|
||||
tn.expect([re.compile('finished')])
|
||||
|
||||
def _check_coverage(self):
|
||||
try:
|
||||
self.coverInst.stop()
|
||||
self.coverInst.save()
|
||||
except AssertionError:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _stop_coverage(self, req):
|
||||
for service in self.services:
|
||||
self._stop_coverage_telnet(service['telnet'])
|
||||
if self._check_coverage():
|
||||
msg = _("Coverage not running")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
return {'path': self.data_path}
|
||||
|
||||
def _report_coverage_telnet(self, tn, path, xml=False):
|
||||
if xml:
|
||||
execute = str("coverInst.xml_report(outfile='%s')\n" % path)
|
||||
tn.write(execute)
|
||||
tn.write("print('finished')\n")
|
||||
tn.expect([re.compile('finished')])
|
||||
else:
|
||||
execute = str("output = open('%s', 'w')\n" % path)
|
||||
tn.write(execute)
|
||||
tn.write("coverInst.report(file=output)\n")
|
||||
tn.write("output.close()\n")
|
||||
tn.write("print('finished')\n")
|
||||
tn.expect([re.compile('finished')])
|
||||
tn.close()
|
||||
|
||||
def _report_coverage(self, req, body):
|
||||
self._stop_coverage(req)
|
||||
xml = False
|
||||
html = False
|
||||
path = None
|
||||
|
||||
body = body['report']
|
||||
if 'file' in body.keys():
|
||||
path = body['file']
|
||||
if path != os.path.basename(path):
|
||||
msg = _("Invalid path")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
path = os.path.join(self.data_path, path)
|
||||
else:
|
||||
msg = _("No path given for report file")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
if 'xml' in body.keys():
|
||||
xml = body['xml']
|
||||
elif 'html' in body.keys():
|
||||
if not self.combine:
|
||||
msg = _("You can't use html reports without combining")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
html = body['html']
|
||||
|
||||
if self.combine:
|
||||
data_out = os.path.join(self.data_path, '.nova-coverage')
|
||||
import coverage
|
||||
coverInst = coverage.coverage(data_file=data_out)
|
||||
coverInst.combine()
|
||||
if xml:
|
||||
coverInst.xml_report(outfile=path)
|
||||
elif html:
|
||||
if os.path.isdir(path):
|
||||
msg = _("Directory conflict: %s already exists") % path
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
coverInst.html_report(directory=path)
|
||||
else:
|
||||
output = open(path, 'w')
|
||||
coverInst.report(file=output)
|
||||
output.close()
|
||||
for service in self.services:
|
||||
service['telnet'].close()
|
||||
else:
|
||||
if xml:
|
||||
apipath = path + '.api'
|
||||
self.coverInst.xml_report(outfile=apipath)
|
||||
for service in self.services:
|
||||
self._report_coverage_telnet(service['telnet'],
|
||||
path + '.%s'
|
||||
% service['service'],
|
||||
xml=True)
|
||||
else:
|
||||
output = open(path + '.api', 'w')
|
||||
self.coverInst.report(file=output)
|
||||
for service in self.services:
|
||||
self._report_coverage_telnet(service['telnet'],
|
||||
path + '.%s' % service['service'])
|
||||
output.close()
|
||||
return {'path': path}
|
||||
|
||||
def _reset_coverage_telnet(self, tn):
|
||||
tn.write("coverInst.erase()\n")
|
||||
tn.write("print('finished')\n")
|
||||
tn.expect([re.compile('finished')])
|
||||
|
||||
def _reset_coverage(self, req):
|
||||
# Reopen telnet connections if they are closed.
|
||||
for service in self.services:
|
||||
if not service['telnet'].get_socket():
|
||||
service['telnet'].open(service['host'], service['port'])
|
||||
|
||||
# Stop coverage if it is started.
|
||||
try:
|
||||
self._stop_coverage(req)
|
||||
except exc.HTTPNotFound:
|
||||
pass
|
||||
|
||||
for service in self.services:
|
||||
self._reset_coverage_telnet(service['telnet'])
|
||||
service['telnet'].close()
|
||||
self.coverInst.erase()
|
||||
|
||||
def action(self, req, body):
|
||||
_actions = {
|
||||
'start': self._start_coverage,
|
||||
'stop': self._stop_coverage,
|
||||
'report': self._report_coverage,
|
||||
'reset': self._reset_coverage,
|
||||
}
|
||||
authorize(req.environ['nova.context'])
|
||||
if not self.coverInst:
|
||||
msg = _("Python coverage module is not installed.")
|
||||
raise exc.HTTPServiceUnavailable(explanation=msg)
|
||||
for action, data in body.iteritems():
|
||||
if action == 'stop' or action == 'reset':
|
||||
return _actions[action](req)
|
||||
elif action == 'report' or action == 'start':
|
||||
return _actions[action](req, body)
|
||||
else:
|
||||
msg = _("Coverage doesn't have %s action") % action
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
raise exc.HTTPBadRequest(explanation=_("Invalid request body"))
|
||||
|
||||
|
||||
class Coverage_ext(extensions.ExtensionDescriptor):
|
||||
"""Enable Nova Coverage."""
|
||||
|
||||
name = "Coverage"
|
||||
alias = "os-coverage"
|
||||
namespace = ("http://docs.openstack.org/compute/ext/"
|
||||
"coverage/api/v2")
|
||||
updated = "2012-10-15T00:00:00+00:00"
|
||||
|
||||
def get_resources(self):
|
||||
resources = []
|
||||
res = extensions.ResourceExtension('os-coverage',
|
||||
controller=CoverageController(),
|
||||
collection_actions={"action": "POST"})
|
||||
resources.append(res)
|
||||
return resources
|
|
@ -1,229 +0,0 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 IBM Corp.
|
||||
#
|
||||
# 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 telnetlib
|
||||
|
||||
import coverage
|
||||
import webob
|
||||
|
||||
from nova.api.openstack.compute.contrib import coverage_ext
|
||||
from nova import context
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova import test
|
||||
from nova.tests.api.openstack import fakes
|
||||
|
||||
|
||||
def fake_telnet(self, data):
|
||||
return
|
||||
|
||||
|
||||
def fake_check_coverage(self):
|
||||
return False
|
||||
|
||||
|
||||
class FakeCoverage(object):
|
||||
def __init__(self, data_file=None):
|
||||
self.started = False
|
||||
return super(FakeCoverage, self).__init__()
|
||||
|
||||
def save(self):
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
self.started = True
|
||||
|
||||
def stop(self):
|
||||
if not self.started:
|
||||
raise AssertionError()
|
||||
self.started = False
|
||||
|
||||
def report(self, file):
|
||||
pass
|
||||
|
||||
def xml_report(self, outfile):
|
||||
pass
|
||||
|
||||
def erase(self):
|
||||
pass
|
||||
|
||||
|
||||
class CoverageExtensionTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CoverageExtensionTest, self).setUp()
|
||||
self.stubs.Set(telnetlib.Telnet, 'write', fake_telnet)
|
||||
self.stubs.Set(telnetlib.Telnet, 'expect', fake_telnet)
|
||||
self.stubs.Set(coverage, 'coverage', FakeCoverage)
|
||||
self.admin_context = context.RequestContext('fakeadmin_0',
|
||||
'fake',
|
||||
is_admin=True)
|
||||
self.user_context = context.RequestContext('fakeadmin_0',
|
||||
'fake',
|
||||
is_admin=False)
|
||||
|
||||
def test_not_admin(self):
|
||||
body = {'start': {}}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.user_context))
|
||||
self.assertEqual(res.status_int, 403)
|
||||
|
||||
def test_start_coverage_action(self):
|
||||
body = {'start': {}}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 200)
|
||||
|
||||
def test_stop_coverage_action(self):
|
||||
self.stubs.Set(coverage_ext.CoverageController,
|
||||
'_check_coverage', fake_check_coverage)
|
||||
body = {'stop': {}}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 200)
|
||||
resp_dict = jsonutils.loads(res.body)
|
||||
self.assertIn('path', resp_dict)
|
||||
|
||||
def test_report_coverage_action_file(self):
|
||||
self.stubs.Set(coverage_ext.CoverageController,
|
||||
'_check_coverage', fake_check_coverage)
|
||||
self.test_start_coverage_action()
|
||||
body = {
|
||||
'report': {
|
||||
'file': 'coverage-unit-test.report',
|
||||
},
|
||||
}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 200)
|
||||
resp_dict = jsonutils.loads(res.body)
|
||||
self.assertIn('path', resp_dict)
|
||||
self.assertIn('coverage-unit-test.report', resp_dict['path'])
|
||||
|
||||
def test_report_coverage_action_xml_file(self):
|
||||
self.stubs.Set(coverage_ext.CoverageController,
|
||||
'_check_coverage', fake_check_coverage)
|
||||
body = {
|
||||
'report': {
|
||||
'file': 'coverage-xml-unit-test.report',
|
||||
'xml': 'True',
|
||||
},
|
||||
}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 200)
|
||||
resp_dict = jsonutils.loads(res.body)
|
||||
self.assertIn('path', resp_dict)
|
||||
self.assertIn('coverage-xml-unit-test.report', resp_dict['path'])
|
||||
|
||||
def test_report_coverage_action_nofile(self):
|
||||
self.stubs.Set(coverage_ext.CoverageController,
|
||||
'_check_coverage', fake_check_coverage)
|
||||
body = {'report': {}}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_coverage_bad_body(self):
|
||||
body = {}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_coverage_report_bad_path(self):
|
||||
self.stubs.Set(coverage_ext.CoverageController,
|
||||
'_check_coverage', fake_check_coverage)
|
||||
body = {
|
||||
'report': {
|
||||
'file': '/tmp/coverage-xml-unit-test.report',
|
||||
}
|
||||
}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_stop_coverage_action_nostart(self):
|
||||
body = {'stop': {}}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 404)
|
||||
|
||||
def test_report_coverage_action_nostart(self):
|
||||
body = {'report': {}}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 404)
|
||||
|
||||
def test_reset_coverage_action_while_coverage_running(self):
|
||||
self.stubs.Set(coverage_ext.CoverageController,
|
||||
'_check_coverage', fake_check_coverage)
|
||||
body = {'reset': {}}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 200)
|
||||
|
||||
def test_reset_coverage_action_while_coverage_stopped(self):
|
||||
body = {'reset': {}}
|
||||
req = webob.Request.blank('/v2/fake/os-coverage/action')
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.admin_context))
|
||||
self.assertEqual(res.status_int, 200)
|
|
@ -148,7 +148,6 @@ policy_data = """
|
|||
"compute_extension:v3:console-output": "",
|
||||
"compute_extension:consoles": "",
|
||||
"compute_extension:v3:os-remote-consoles": "",
|
||||
"compute_extension:coverage_ext": "is_admin:True",
|
||||
"compute_extension:createserverext": "",
|
||||
"compute_extension:deferred_delete": "",
|
||||
"compute_extension:v3:os-deferred-delete": "",
|
||||
|
|
|
@ -240,14 +240,6 @@
|
|||
"namespace": "http://docs.openstack.org/compute/ext/os-consoles/api/v2",
|
||||
"updated": "%(timestamp)s"
|
||||
},
|
||||
{
|
||||
"alias": "os-coverage",
|
||||
"description": "%(text)s",
|
||||
"links": [],
|
||||
"name": "Coverage",
|
||||
"namespace": "http://docs.openstack.org/compute/ext/coverage/api/v2",
|
||||
"updated": "%(timestamp)s"
|
||||
},
|
||||
{
|
||||
"alias": "os-create-server-ext",
|
||||
"description": "%(text)s",
|
||||
|
|
|
@ -87,9 +87,6 @@
|
|||
<extension alias="os-consoles" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/os-consoles/api/v2" name="Consoles">
|
||||
<description>%(text)s</description>
|
||||
</extension>
|
||||
<extension alias="os-coverage" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/coverage/api/v2" name="Coverage">
|
||||
<description>%(text)s</description>
|
||||
</extension>
|
||||
<extension alias="os-create-server-ext" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/createserverext/api/v1.1" name="Createserverext">
|
||||
<description>%(text)s</description>
|
||||
</extension>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"report" : {
|
||||
"file" : "%(filename)s"
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report>
|
||||
<file>%(filename)s</file>
|
||||
</report>
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"path" : "%(path)s"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<path>%(path)s</path>
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"start" : {
|
||||
"combine": true
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<start>
|
||||
<combine>True</combine>
|
||||
</start>
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"start" : {
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<start></start>
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"stop" : {
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stop></stop>
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"path" : "%(path)s"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<path>%(path)s</path>
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"report": {
|
||||
"xml": true,
|
||||
"file": "%(filename)s"
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report>
|
||||
<file>%(filename)s</file>
|
||||
<xml>True</xml>
|
||||
</report>
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"path" : "%(path)s"
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<path>%(path)s</path>
|
|
@ -23,12 +23,10 @@ import os
|
|||
import urllib
|
||||
import uuid as uuid_lib
|
||||
|
||||
import coverage
|
||||
from lxml import etree
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.api.metadata import password
|
||||
from nova.api.openstack.compute.contrib import coverage_ext
|
||||
from nova.api.openstack.compute.contrib import fping
|
||||
from nova.api.openstack.compute import extensions
|
||||
# Import extensions to pull in osapi_compute_extension CONF option used below.
|
||||
|
@ -51,7 +49,6 @@ from nova.openstack.common import timeutils
|
|||
import nova.quota
|
||||
from nova.servicegroup import api as service_group_api
|
||||
from nova import test
|
||||
from nova.tests.api.openstack.compute.contrib import test_coverage_ext
|
||||
from nova.tests.api.openstack.compute.contrib import test_fping
|
||||
from nova.tests.api.openstack.compute.contrib import test_networks
|
||||
from nova.tests.api.openstack.compute.contrib import test_services
|
||||
|
@ -474,74 +471,6 @@ class LimitsSampleXmlTest(LimitsSampleJsonTest):
|
|||
ctype = 'xml'
|
||||
|
||||
|
||||
class CoverageExtJsonTests(ApiSampleTestBaseV2):
|
||||
extension_name = ("nova.api.openstack.compute.contrib.coverage_ext."
|
||||
"Coverage_ext")
|
||||
|
||||
def setUp(self):
|
||||
super(CoverageExtJsonTests, self).setUp()
|
||||
|
||||
def _fake_check_coverage(self):
|
||||
return False
|
||||
|
||||
def _fake_xml_report(self, outfile=None):
|
||||
return
|
||||
|
||||
self.stubs.Set(coverage_ext.CoverageController, '_check_coverage',
|
||||
_fake_check_coverage)
|
||||
self.stubs.Set(coverage, 'coverage', test_coverage_ext.FakeCoverage)
|
||||
|
||||
def test_start_coverage(self):
|
||||
# Start coverage data collection.
|
||||
subs = {}
|
||||
response = self._do_post('os-coverage/action',
|
||||
'coverage-start-post-req', subs)
|
||||
self.assertEqual(response.status, 200)
|
||||
|
||||
def test_start_coverage_combine(self):
|
||||
# Start coverage data collection.
|
||||
subs = {}
|
||||
response = self._do_post('os-coverage/action',
|
||||
'coverage-start-combine-post-req', subs)
|
||||
self.assertEqual(response.status, 200)
|
||||
|
||||
def test_stop_coverage(self):
|
||||
# Stop coverage data collection.
|
||||
subs = {
|
||||
'path': '/.*',
|
||||
}
|
||||
response = self._do_post('os-coverage/action',
|
||||
'coverage-stop-post-req', subs)
|
||||
subs.update(self._get_regexes())
|
||||
self._verify_response('coverage-stop-post-resp', subs, response, 200)
|
||||
|
||||
def test_report_coverage(self):
|
||||
# Generate a coverage report.
|
||||
subs = {
|
||||
'filename': 'report',
|
||||
'path': '/.*/report',
|
||||
}
|
||||
response = self._do_post('os-coverage/action',
|
||||
'coverage-report-post-req', subs)
|
||||
subs.update(self._get_regexes())
|
||||
self._verify_response('coverage-report-post-resp', subs, response, 200)
|
||||
|
||||
def test_xml_report_coverage(self):
|
||||
subs = {
|
||||
'filename': 'report',
|
||||
'path': '/.*/report',
|
||||
}
|
||||
response = self._do_post('os-coverage/action',
|
||||
'coverage-xml-report-post-req', subs)
|
||||
subs.update(self._get_regexes())
|
||||
self._verify_response('coverage-xml-report-post-resp',
|
||||
subs, response, 200)
|
||||
|
||||
|
||||
class CoverageExtXmlTests(CoverageExtJsonTests):
|
||||
ctype = "xml"
|
||||
|
||||
|
||||
class ServersActionsJsonTest(ServersSampleBase):
|
||||
def _test_server_action(self, uuid, action,
|
||||
subs={}, resp_tpl=None, code=202):
|
||||
|
|
Loading…
Reference in New Issue