Merge "Remove flavor API"

This commit is contained in:
Zuul 2020-04-28 03:52:57 +00:00 committed by Gerrit Code Review
commit fa1843be0a
21 changed files with 77 additions and 1881 deletions

View File

@ -6,17 +6,7 @@
"version": "5.7"
},
"flavor": {
"id": "6",
"links": [
{
"href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6",
"rel": "self"
},
{
"href": "https://127.0.0.1:8779/flavors/6",
"rel": "bookmark"
}
]
"id": "6"
},
"id": "b76a6a76-748b-4064-adec-4c9e6c9abd68",
"links": [

View File

@ -17,17 +17,7 @@
"version": "5.7"
},
"flavor": {
"id": "6",
"links": [
{
"href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6",
"rel": "self"
},
{
"href": "https://127.0.0.1:8779/flavors/6",
"rel": "bookmark"
}
]
"id": "6"
},
"id": "7de1bed8-6983-4d46-9a52-0abfbb0d27a2",
"ip": [
@ -65,17 +55,7 @@
"message": "Failed to create User port for instance b76a6a76-748b-4064-adec-4c9e6c9abd68"
},
"flavor": {
"id": "6",
"links": [
{
"href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6",
"rel": "self"
},
{
"href": "https://127.0.0.1:8779/flavors/6",
"rel": "bookmark"
}
]
"id": "6"
},
"id": "b76a6a76-748b-4064-adec-4c9e6c9abd68",
"links": [

View File

@ -6,17 +6,7 @@
"version": "5.7"
},
"flavor": {
"id": "6",
"links": [
{
"href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6",
"rel": "self"
},
{
"href": "https://127.0.0.1:8779/flavors/6",
"rel": "bookmark"
}
]
"id": "6"
},
"id": "7de1bed8-6983-4d46-9a52-0abfbb0d27a2",
"ip": [

View File

@ -20,17 +20,7 @@
"deleted_at": null,
"encrypted_rpc_messaging": true,
"flavor": {
"id": "d2",
"links": [
{
"href": "https://127.0.0.1:8779/v1.0/2afa58fd5db34fd8b7b659d997a5341f/flavors/d2",
"rel": "self"
},
{
"href": "https://127.0.0.1:8779/flavors/d2",
"rel": "bookmark"
}
]
"id": "d2"
},
"id": "7de1bed8-6983-4d46-9a52-0abfbb0d27a2",
"ip": [
@ -82,17 +72,7 @@
"message": "Failed to create User port for instance b76a6a76-748b-4064-adec-4c9e6c9abd68"
},
"flavor": {
"id": "6",
"links": [
{
"href": "https://127.0.0.1:8779/v1.0/2afa58fd5db34fd8b7b659d997a5341f/flavors/6",
"rel": "self"
},
{
"href": "https://127.0.0.1:8779/flavors/6",
"rel": "bookmark"
}
]
"id": "6"
},
"id": "b76a6a76-748b-4064-adec-4c9e6c9abd68",
"links": [

View File

@ -19,17 +19,7 @@
"deleted_at": null,
"encrypted_rpc_messaging": true,
"flavor": {
"id": "d2",
"links": [
{
"href": "https://127.0.0.1:8779/v1.0/2afa58fd5db34fd8b7b659d997a5341f/flavors/d2",
"rel": "self"
},
{
"href": "https://127.0.0.1:8779/flavors/d2",
"rel": "bookmark"
}
]
"id": "d2"
},
"guest_status": {
"state_description": "healthy"

View File

@ -16,17 +16,7 @@
"version": "5.7"
},
"flavor": {
"id": "6",
"links": [
{
"href": "https://127.0.0.1:8779/v1.0/9f8dd5eacb074c9f87d2d822c9092aa5/flavors/6",
"rel": "self"
},
{
"href": "https://127.0.0.1:8779/flavors/6",
"rel": "bookmark"
}
]
"id": "6"
},
"id": "7de1bed8-6983-4d46-9a52-0abfbb0d27a2",
"ip": [

View File

@ -658,4 +658,4 @@ In the API response, note that the additional key
::
RESP BODY: {"instance": {"status": "ACTIVE", "updated": "2017-01-09T18:29:00", "name": "m10", "links": [{"href": "https://192.168.126.130:8779/v1.0/56cca8484d3e48869126ada4f355c284/instances/514ef051-0bf7-48a5-adcf-071d4a6625fb", "rel": "self"}, {"href": "https://192.168.126.130:8779/instances/514ef051-0bf7-48a5-adcf-071d4a6625fb", "rel": "bookmark"}], "created": "2017-01-09T18:28:56", "region": "RegionOne", "server_id": "2452263e-3d33-48ec-8f24-2851fe74db28", "id": "514ef051-0bf7-48a5-adcf-071d4a6625fb", "volume": {"used": 0.11, "size": 3}, "volume_id": "cee2e17b-80fa-48e5-a488-da8b7809373a", "flavor": {"id": "25", "links": [{"href": "https://192.168.126.130:8779/v1.0/56cca8484d3e48869126ada4f355c284/flavors/25", "rel": "self"}, {"href": "https://192.168.126.130:8779/flavors/25", "rel": "bookmark"}]}, "datastore": {"version": "5.6", "type": "mysql"}, "encrypted_rpc_messaging": false}}
RESP BODY: {"instance": {"status": "ACTIVE", "updated": "2017-01-09T18:29:00", "name": "m10", "links": [{"href": "https://192.168.126.130:8779/v1.0/56cca8484d3e48869126ada4f355c284/instances/514ef051-0bf7-48a5-adcf-071d4a6625fb", "rel": "self"}, {"href": "https://192.168.126.130:8779/instances/514ef051-0bf7-48a5-adcf-071d4a6625fb", "rel": "bookmark"}], "created": "2017-01-09T18:28:56", "region": "RegionOne", "server_id": "2452263e-3d33-48ec-8f24-2851fe74db28", "id": "514ef051-0bf7-48a5-adcf-071d4a6625fb", "volume": {"used": 0.11, "size": 3}, "volume_id": "cee2e17b-80fa-48e5-a488-da8b7809373a", "flavor": {"id": "25"}, "datastore": {"version": "5.6", "type": "mysql"}, "encrypted_rpc_messaging": false}}

View File

@ -113,11 +113,7 @@ Create and use incremental backups
| created | 2014-03-19T14:10:56 |
| datastore | {u'version': u'mysql-5.5', u'type': u'mysql'} |
| datastore_version | mysql-5.5 |
| flavor | {u'id': u'10', u'links': |
| | [{u'href': u'https://10.125.1.135:8779/v1.0/ |
| | 626734041baa4254ae316de52a20b390/flavors/10', u'rel': |
| | u'self'}, {u'href': u'https://10.125.1.135:8779/ |
| | flavors/10', u'rel': u'bookmark'}]} |
| flavor | {u'id': u'10'} |
| id | a3680953-eea9-4cf2-918b-5b8e49d7e1b3 |
| name | guest2 |
| status | BUILD |

View File

@ -102,10 +102,7 @@ class ClusterView(object):
return None
def _build_flavor_info(self, flavor_id):
return {
"id": flavor_id,
"links": create_links("flavors", self.req, flavor_id)
}
return {"id": flavor_id}
class ClusterInstanceDetailView(InstanceDetailView):

View File

@ -20,7 +20,6 @@ from trove.common import wsgi
from trove.configuration.service import ConfigurationsController
from trove.configuration.service import ParametersController
from trove.datastore.service import DatastoreController
from trove.flavor.service import FlavorController
from trove.instance.service import InstanceController
from trove.limits.service import LimitsController
from trove.module.service import ModuleController
@ -35,7 +34,6 @@ class API(wsgi.Router):
self._instance_router(mapper)
self._cluster_router(mapper)
self._datastore_router(mapper)
self._flavor_router(mapper)
self._versions_router(mapper)
self._limits_router(mapper)
self._backups_router(mapper)
@ -168,17 +166,6 @@ class API(wsgi.Router):
action="delete",
conditions={'method': ['DELETE']})
def _flavor_router(self, mapper):
flavor_resource = FlavorController().create_resource()
mapper.connect("/{tenant_id}/flavors",
controller=flavor_resource,
action="index",
conditions={'method': ['GET']})
mapper.connect("/{tenant_id}/flavors/{id}",
controller=flavor_resource,
action="show",
conditions={'method': ['GET']})
def _limits_router(self, mapper):
limits_resource = LimitsController().create_resource()
mapper.connect("/{tenant_id}/limits",

View File

@ -1,54 +0,0 @@
# Copyright 2010-2012 OpenStack Foundation
# All Rights Reserved.
#
# 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 six
from trove.common import exception
from trove.common import policy
from trove.common import wsgi
from trove.flavor import models
from trove.flavor import views
class FlavorController(wsgi.Controller):
"""Controller for flavor functionality."""
def show(self, req, tenant_id, id):
"""Return a single flavor."""
context = req.environ[wsgi.CONTEXT_KEY]
self._validate_flavor_id(id)
flavor = models.Flavor(context=context, flavor_id=id)
# Flavors do not bind to a particular tenant.
# Only authorize the current tenant.
policy.authorize_on_tenant(context, 'flavor:show')
# Pass in the request to build accurate links.
return wsgi.Result(views.FlavorView(flavor, req).data(), 200)
def index(self, req, tenant_id):
"""Return all flavors."""
context = req.environ[wsgi.CONTEXT_KEY]
policy.authorize_on_tenant(context, 'flavor:index')
flavors = models.Flavors(context=context)
return wsgi.Result(views.FlavorsView(flavors, req).data(), 200)
def _validate_flavor_id(self, id):
if isinstance(id, six.string_types):
return
try:
if int(id) != float(id):
raise exception.NotFound(uuid=id)
except ValueError:
raise exception.NotFound(uuid=id)

View File

@ -72,13 +72,8 @@ class InstanceView(object):
def _build_flavor_info(self):
return {
"id": self.instance.flavor_id,
"links": self._build_flavor_links()
}
def _build_flavor_links(self):
return create_links("flavors", self.req,
self.instance.flavor_id)
def _build_master_info(self):
return {
"id": self.instance.slave_of_id,

View File

@ -36,6 +36,7 @@ from trove.common.utils import poll_until
from trove.datastore import models as datastore_models
from trove import tests
from trove.tests.config import CONFIG
from trove.tests import util
from trove.tests.util.check import AttrCheck
from trove.tests.util import create_dbaas_client
from trove.tests.util import test_config
@ -88,6 +89,7 @@ class InstanceTestInfo(object):
self.user_context = None # A regular user context
self.users = None # The users created on the instance.
self.consumer = create_usage_verifier()
self.flavors = None # The cache of Nova flavors.
def find_default_flavor(self):
if EPHEMERAL_SUPPORT:
@ -96,15 +98,17 @@ class InstanceTestInfo(object):
else:
flavor_name = CONFIG.values.get('instance_flavor_name', 'm1.tiny')
flavors = self.dbaas.find_flavors_by_name(flavor_name)
assert_equal(len(flavors), 1,
"Number of flavors with name '%s' "
"found was '%d'." % (flavor_name, len(flavors)))
flavor = None
flavor_href = None
flavor = flavors[0]
flavor_href = self.dbaas.find_flavor_self_href(flavor)
assert_true(flavor_href is not None,
"Flavor href '%s' not found!" % flavor_name)
for item in self.flavors:
if item.name == flavor_name:
flavor = item
flavor_href = item.id
break
asserts.assert_is_not_none(flavor)
asserts.assert_is_not_none(flavor_href)
return flavor, flavor_href
@ -190,11 +194,10 @@ class CheckInstance(AttrCheck):
if 'flavor' not in self.instance:
self.fail("'flavor' not found in instance.")
else:
allowed_attrs = ['id', 'links']
allowed_attrs = ['id']
self.contains_allowed_attrs(
self.instance['flavor'], allowed_attrs,
msg="Flavor")
self.links(self.instance['flavor']['links'])
def datastore(self):
if 'datastore' not in self.instance:
@ -315,6 +318,10 @@ class TestInstanceSetup(object):
instance_info.user = CONFIG.users.find_user(reqs)
instance_info.dbaas = create_dbaas_client(instance_info.user)
instance_info.nova_client = util.create_nova_client(instance_info.user)
instance_info.flavors = instance_info.nova_client.flavors.list()
global dbaas
dbaas = instance_info.dbaas
@ -563,10 +570,16 @@ class CreateInstanceFail(object):
instance_name = "instance-failure-with-no-ephemeral-flavor"
databases = []
flavor_name = CONFIG.values.get('instance_flavor_name', 'm1.tiny')
flavors = dbaas.find_flavors_by_name(flavor_name)
flavor_id = None
for item in instance_info.flavors:
if item.name == flavor_name:
flavor_id = item.id
asserts.assert_is_not_none(flavor_id)
assert_raises(exceptions.BadRequest, dbaas.instances.create,
instance_name, flavors[0].id, None, databases,
instance_name, flavor_id, None, databases,
nics=instance_info.nics)
assert_equal(400, dbaas.last_http_code)

View File

@ -367,11 +367,6 @@ class ResizeInstanceTest(ActionTestBase):
def flavor_id(self):
return instance_info.dbaas_flavor_href
def get_flavor_href(self, flavor_id=2):
res = instance_info.dbaas.find_flavor_and_self_href(flavor_id)
_, dbaas_flavor_href = res
return dbaas_flavor_href
def wait_for_resize(self):
def is_finished_resizing():
instance = self.instance
@ -399,7 +394,12 @@ class ResizeInstanceTest(ActionTestBase):
def test_instance_resize_to_ephemeral_in_volume_support_should_fail(self):
flavor_name = CONFIG.values.get('instance_bigger_eph_flavor_name',
'eph.rd-smaller')
flavors = self.dbaas.find_flavors_by_name(flavor_name)
flavor_id = None
for item in instance_info.flavors:
if item.name == flavor_name:
flavor_id = item.id
asserts.assert_is_not_none(flavor_id)
def is_active():
return self.instance.status in CONFIG.running_status
@ -409,36 +409,42 @@ class ResizeInstanceTest(ActionTestBase):
asserts.assert_raises(HTTPNotImplemented,
self.dbaas.instances.resize_instance,
self.instance_id, flavors[0].id)
self.instance_id, flavor_id)
@test(enabled=EPHEMERAL_SUPPORT)
def test_instance_resize_to_non_ephemeral_flavor_should_fail(self):
flavor_name = CONFIG.values.get('instance_bigger_flavor_name',
'm1-small')
flavors = self.dbaas.find_flavors_by_name(flavor_name)
flavor_id = None
for item in instance_info.flavors:
if item.name == flavor_name:
flavor_id = item.id
asserts.assert_is_not_none(flavor_id)
asserts.assert_raises(BadRequest, self.dbaas.instances.resize_instance,
self.instance_id, flavors[0].id)
self.instance_id, flavor_id)
def obtain_flavor_ids(self):
old_id = self.instance.flavor['id']
self.expected_old_flavor_id = old_id
res = instance_info.dbaas.find_flavor_and_self_href(old_id)
self.expected_dbaas_flavor, _ = res
if EPHEMERAL_SUPPORT:
flavor_name = CONFIG.values.get('instance_bigger_eph_flavor_name',
'eph.rd-smaller')
else:
flavor_name = CONFIG.values.get('instance_bigger_flavor_name',
'm1.small')
flavors = self.dbaas.find_flavors_by_name(flavor_name)
asserts.assert_equal(len(flavors), 1,
"Number of flavors with name '%s' "
"found was '%d'." % (flavor_name,
len(flavors)))
flavor = flavors[0]
new_flavor = None
for item in instance_info.flavors:
if item.name == flavor_name:
new_flavor = item
break
asserts.assert_is_not_none(new_flavor)
self.old_dbaas_flavor = instance_info.dbaas_flavor
instance_info.dbaas_flavor = flavor
self.expected_new_flavor_id = flavor.id
instance_info.dbaas_flavor = new_flavor
self.expected_new_flavor_id = new_flavor.id
@test(depends_on=[test_instance_resize_same_size_should_fail])
def test_status_changed_to_resize(self):
@ -447,14 +453,14 @@ class ResizeInstanceTest(ActionTestBase):
self.obtain_flavor_ids()
self.dbaas.instances.resize_instance(
self.instance_id,
self.get_flavor_href(flavor_id=self.expected_new_flavor_id))
self.expected_new_flavor_id)
asserts.assert_equal(202, self.dbaas.last_http_code)
# (WARNING) IF THE RESIZE IS WAY TOO FAST THIS WILL FAIL
assert_unprocessable(
self.dbaas.instances.resize_instance,
self.instance_id,
self.get_flavor_href(flavor_id=self.expected_new_flavor_id))
self.expected_new_flavor_id)
@test(depends_on=[test_status_changed_to_resize])
@time_out(TIME_OUT_TIME)
@ -493,9 +499,8 @@ class ResizeInstanceTest(ActionTestBase):
@test(depends_on=[test_make_sure_mysql_is_running_after_resize])
def test_instance_has_new_flavor_after_resize(self):
actual = self.get_flavor_href(self.instance.flavor['id'])
expected = self.get_flavor_href(flavor_id=self.expected_new_flavor_id)
asserts.assert_equal(actual, expected)
actual = self.instance.flavor['id']
asserts.assert_equal(actual, self.expected_new_flavor_id)
@test(depends_on_classes=[ResizeInstanceTest],

View File

@ -1,293 +0,0 @@
# Copyright 2014 Rackspace
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import os
import re
import time
from proboscis.asserts import fail
from six.moves.urllib.parse import urlparse
from troveclient.compat.client import TroveHTTPClient
from trove.tests.config import CONFIG
print_req = True
def shorten_url(url):
parsed = urlparse(url)
if parsed.query:
method_url = parsed.path + '?' + parsed.query
else:
method_url = parsed.path
return method_url
class SnippetWriter(object):
def __init__(self, conf, get_replace_list):
self.conf = conf
self.get_replace_list = get_replace_list
def output_request(self, user_details, name, url, output_headers, body,
content_type, method, static_auth_token=True):
headers = []
parsed = urlparse(url)
method_url = shorten_url(url)
headers.append("%s %s HTTP/1.1" % (method, method_url))
headers.append("User-Agent: %s" % output_headers['User-Agent'])
headers.append("Host: %s" % parsed.netloc)
# static_auth_token option for documentation purposes
if static_auth_token:
output_token = '87c6033c-9ff6-405f-943e-2deb73f278b7'
else:
output_token = output_headers['X-Auth-Token']
headers.append("X-Auth-Token: %s" % output_token)
headers.append("Accept: %s" % output_headers['Accept'])
print("OUTPUT HEADERS: %s" % output_headers)
headers.append("Content-Type: %s" % output_headers['Content-Type'])
self.write_file(user_details, name, "-%s-http.txt" % content_type, url,
method, "request", output='\n'.join(headers))
pretty_body = self.format_body(body, content_type)
self.write_file(user_details, name, ".%s" % content_type, url,
method, "request", output=pretty_body)
def output_response(self, user_details, name, content_type, url, method,
resp, body):
version = "1.1" # if resp.version == 11 else "1.0"
lines = [
["HTTP/%s %s %s" % (version, resp.status, resp.reason)],
["Content-Type: %s" % resp['content-type']],
]
if 'via' in resp:
lines.append(["Via: %s" % resp['via']])
lines.append(["Content-Length: %s" % resp['content-length']])
lines.append(["Date: Mon, 18 Mar 2013 19:09:17 GMT"])
if 'server' in resp:
lines.append(["Server: %s" % resp["server"]])
new_lines = [x[0] for x in lines]
joined_lines = '\n'.join(new_lines)
self.write_file(user_details, name, "-%s-http.txt" % content_type, url,
method, "response", output=joined_lines)
if body:
pretty_body = self.format_body(body, content_type)
self.write_file(user_details, name, ".%s" % content_type, url,
method, "response", output=pretty_body)
def format_body(self, body, content_type):
assert content_type == 'json'
try:
if self.conf['replace_dns_hostname']:
before = r'\"hostname\": \"[a-zA-Z0-9-_\.]*\"'
after = '\"hostname\": \"%s\"' % self.conf[
'replace_dns_hostname']
body = re.sub(before, after, body)
return json.dumps(json.loads(body), sort_keys=True, indent=4)
except Exception:
return body or ''
def write_request_file(self, user_details, name, content_type, url, method,
req_headers, request_body):
if print_req:
print("\t%s req url:%s" % (content_type, url))
print("\t%s req method:%s" % (content_type, method))
print("\t%s req headers:%s" % (content_type, req_headers))
print("\t%s req body:%s" % (content_type, request_body))
self.output_request(user_details, name, url, req_headers, request_body,
content_type, method)
def write_response_file(self, user_details, name, content_type, url,
method, resp, resp_content):
if print_req:
print("\t%s resp:%s" % (content_type, resp))
print("\t%s resp content:%s" % (content_type, resp_content))
self.output_response(user_details, name, content_type, url, method,
resp, resp_content)
def write_file(self, user_details, name, content_type, url, method,
in_or_out, output):
output = output.replace(user_details['tenant'], '1234')
if self.conf['replace_host']:
output = output.replace(user_details['api_url'],
self.conf['replace_host'])
pre_host_port = urlparse(user_details['service_url']).netloc
post_host = urlparse(self.conf['replace_host']).netloc
output = output.replace(pre_host_port, post_host)
output = output.replace("fake_host", "hostname")
output = output.replace("FAKE_", "")
for resource in self.get_replace_list():
output = output.replace(str(resource[0]), str(resource[1]))
filename = "%s/db-%s-%s%s" % (self.conf['directory'],
name.replace('_', '-'), in_or_out,
content_type)
self._write_file(filename, output)
def _write_file(self, filename, output):
empty = len(output.strip()) == 0
# Manipulate actual data to appease doc niceness checks
actual = [line.rstrip() for line in output.split("\n")]
if not empty and actual[len(actual) - 1] != '':
actual.append("")
def goofy_diff(a, b):
diff = []
for i in range(len(a)):
if i < len(b):
if a[i].rstrip() != b[i].rstrip():
diff.append('Expected line %d :%s\n'
' Actual line %d :%s'
% (i + 1, a[i], i + 1, b[i]))
else:
diff.append("Expected line %d :%s" % (i + 1, a[i]))
for j in range(len(b) - len(a)):
i2 = len(a) + j
diff.append(" Actual line %d :%s" % (i2 + 1, b[i2]))
return diff
def write_actual_file():
# Always write the file.
with open(filename, "w") as file:
for line in actual:
file.write("%s\n" % line)
def assert_output_matches():
if os.path.isfile(filename):
with open(filename, 'r') as original_file:
original = original_file.read()
if empty:
fail('Error: output missing in new snippet generation '
'for %s. Old content follows:\n"""%s"""'
% (filename, original))
elif filename.endswith('.json'):
assert_json_matches(original)
else:
assert_file_matches(original)
elif not empty:
fail('Error: new file necessary where there was no file '
'before. Filename=%s\nContent follows:\n"""%s"""'
% (filename, output))
def assert_file_matches(original):
expected = original.split('\n')
# Remove the last item which will look like a duplicated
# file ending newline
expected.pop()
diff = '\n'.join(goofy_diff(expected, actual))
if diff:
fail('Error: output files differ for %s:\n%s'
% (filename, diff))
def order_json(json_obj):
"""Sort the json object so that it can be compared properly."""
if isinstance(json_obj, list):
return sorted(order_json(elem) for elem in json_obj)
if isinstance(json_obj, dict):
return sorted(
(key, order_json(value))
for key, value in json_obj.items())
else:
return json_obj
def assert_json_matches(original):
try:
expected_json = json.loads(original)
actual_json = json.loads(output)
except ValueError:
fail('Invalid json!\nExpected: %s\nActual: %s'
% (original, output))
if order_json(expected_json) != order_json(actual_json):
# Re-Use the same failure output if the json is different
assert_file_matches(original)
if not os.environ.get('TESTS_FIX_EXAMPLES'):
assert_output_matches()
elif not empty:
write_actual_file()
# This method is mixed into the client class.
# It requires the following fields: snippet_writer, content_type, and
# "name," the last of which must be set before each call.
def write_to_snippet(self, args, kwargs, resp, body):
if self.name is None:
raise RuntimeError("'name' not set before call.")
url = args[0]
method = args[1]
request_headers = kwargs['headers']
request_body = kwargs.get('body', None)
response_headers = resp
response_body = body
# Log request
user_details = {
'api_url': self.service_url,
'service_url': self.service_url,
'tenant': self.tenant,
}
self.snippet_writer.write_request_file(user_details, self.name,
self.content_type, url, method,
request_headers, request_body)
self.snippet_writer.write_response_file(user_details, self.name,
self.content_type, url, method,
response_headers, response_body)
# Create a short url to assert against.
short_url = url
base_url = self.service_url
for prefix in (base_url):
if short_url.startswith(prefix):
short_url = short_url[len(prefix):]
self.old_info = {
'url': shorten_url(short_url),
'method': method,
'request_headers': request_headers,
'request_body': request_body,
'response_headers': response_headers,
'response_body': response_body
}
def add_fake_response_headers(headers):
"""
Fakes other items that would appear if you were using, just to make up
an example, a proxy.
"""
conf = CONFIG.examples
if 'via' in conf and 'via' not in headers:
headers['via'] = conf['via']
if 'server' in conf and 'server' not in headers:
headers['server'] = conf['server']
if 'date' not in headers:
date_string = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
headers['date'] = date_string
class JsonClient(TroveHTTPClient):
content_type = 'json'
def http_log(self, args, kwargs, resp, body):
add_fake_response_headers(resp)
self.pretty_log(args, kwargs, resp, body)
def write_snippet():
return write_to_snippet(self, args, kwargs, resp, body.decode())
self.write_snippet = write_snippet

File diff suppressed because it is too large Load Diff

View File

@ -183,6 +183,7 @@ class InstanceTestInfo(object):
self.helper_user = None # Test helper user if exists.
self.helper_database = None # Test helper database if exists.
self.admin_user = None
self.flavors = None
class LogOnFail(type):
@ -368,6 +369,8 @@ class TestRunner(object):
inst_ids = [self.instance_info.id]
self.register_debug_inst_ids(inst_ids)
self.instance_info.flavors = self.nova_client.flavors.list()
@classmethod
def fail(cls, message):
asserts.fail(message)
@ -817,12 +820,14 @@ class TestRunner(object):
return {"flavorRef": flavor_id, "volume": {"size": volume_size}}
def get_flavor(self, flavor_name):
flavors = self.auth_client.find_flavors_by_name(flavor_name)
self.assert_equal(
1, len(flavors),
"Unexpected number of flavors with name '%s' found." % flavor_name)
flavor = None
for item in self.instance_info.flavors:
if item.name == flavor_name:
flavor = item
return flavors[0]
asserts.assert_is_not_none(flavor)
return flavor
def get_instance_flavor(self, fault_num=None):
name_format = 'instance%s%s_flavor_name'
@ -841,7 +846,7 @@ class TestRunner(object):
return self.get_flavor(flavor_name)
def get_flavor_href(self, flavor):
return self.auth_client.find_flavor_self_href(flavor)
return flavor.id
def copy_dict(self, d, ignored_keys=None):
return {k: v for k, v in d.items()
@ -980,11 +985,10 @@ class CheckInstance(AttrCheck):
if 'flavor' not in self.instance:
self.fail("'flavor' not found in instance.")
else:
allowed_attrs = ['id', 'links']
allowed_attrs = ['id']
self.contains_allowed_attrs(
self.instance['flavor'], allowed_attrs,
msg="Flavor")
self.links(self.instance['flavor']['links'])
def datastore(self):
if 'datastore' not in self.instance:

View File

@ -140,7 +140,6 @@ class ClusterInstanceDetailViewTest(trove_testtools.TestCase):
super(ClusterInstanceDetailViewTest, self).tearDown()
@patch.object(ClusterInstanceDetailView, '_build_links')
@patch.object(ClusterInstanceDetailView, '_build_flavor_links')
@patch.object(ClusterInstanceDetailView, '_build_configuration_info')
def test_data(self, *args):
view = ClusterInstanceDetailView(self.instance, self.req)
@ -154,7 +153,6 @@ class ClusterInstanceDetailViewTest(trove_testtools.TestCase):
self.assertNotIn('ip', result['instance'])
@patch.object(ClusterInstanceDetailView, '_build_links')
@patch.object(ClusterInstanceDetailView, '_build_flavor_links')
@patch.object(ClusterInstanceDetailView, '_build_configuration_info')
def test_data_ip(self, *args):
self.instance.hostname = None

View File

@ -41,10 +41,8 @@ class InstanceDetailViewTest(trove_testtools.TestCase):
def setUp(self):
super(InstanceDetailViewTest, self).setUp()
self.build_links_method = InstanceView._build_links
self.build_flavor_links_method = InstanceView._build_flavor_links
self.build_config_method = InstanceDetailView._build_configuration_info
InstanceView._build_links = Mock()
InstanceView._build_flavor_links = Mock()
InstanceDetailView._build_configuration_info = Mock()
self.instance = Mock()
self.instance.created = 'Yesterday'
@ -79,7 +77,6 @@ class InstanceDetailViewTest(trove_testtools.TestCase):
def tearDown(self):
super(InstanceDetailViewTest, self).tearDown()
InstanceView._build_links = self.build_links_method
InstanceView._build_flavor_links = self.build_flavor_links_method
InstanceDetailView._build_configuration_info = self.build_config_method
def test_data_hostname(self):

View File

@ -67,37 +67,6 @@ class TestClient(object):
resp, body = self.real_client.client.last_response
return resp.status
@staticmethod
def find_flavor_self_href(flavor):
self_links = [link for link in flavor.links if link['rel'] == 'self']
asserts.assert_true(len(self_links) > 0, "Flavor had no self href!")
flavor_href = self_links[0]['href']
asserts.assert_false(flavor_href is None,
"Flavor link self href missing.")
return flavor_href
def find_flavors_by(self, condition, flavor_manager=None):
flavor_manager = flavor_manager or self.flavors
flavors = flavor_manager.list()
return [flavor for flavor in flavors if condition(flavor)]
def find_flavors_by_name(self, name, flavor_manager=None):
return self.find_flavors_by(lambda flavor: flavor.name == name,
flavor_manager)
def find_flavors_by_ram(self, ram, flavor_manager=None):
return self.find_flavors_by(lambda flavor: flavor.ram == ram,
flavor_manager)
def find_flavor_and_self_href(self, flavor_id, flavor_manager=None):
"""Given an ID, returns flavor and its self href."""
flavor_manager = flavor_manager or self.flavors
asserts.assert_false(flavor_id is None)
flavor = flavor_manager.get(flavor_id)
asserts.assert_false(flavor is None)
flavor_href = self.find_flavor_self_href(flavor)
return flavor, flavor_href
def __getattr__(self, item):
if item == "__setstate__":
raise AttributeError(item)