diff options
Diffstat (limited to 'tests')
37 files changed, 0 insertions, 4576 deletions
diff --git a/tests/examples/README b/tests/examples/README deleted file mode 100644 index f7ebb0b..0000000 --- a/tests/examples/README +++ /dev/null @@ -1,13 +0,0 @@ -Example Generator - -Settings for the example generator are in examples/local.conf - -After customizing examples/local.conf, run: -./example_gen.sh - -2012-06-12 - - Updated to work with trove - - All XML calls are commented out - - Management calls are also commented out -2012-06-14 - - Renabled XML calls diff --git a/tests/examples/example_gen.sh b/tests/examples/example_gen.sh deleted file mode 100755 index cbbe153..0000000 --- a/tests/examples/example_gen.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -python ./examples/example_generation.py ./examples/local.conf - diff --git a/tests/examples/examples/client.py b/tests/examples/examples/client.py deleted file mode 100644 index e52d183..0000000 --- a/tests/examples/examples/client.py +++ /dev/null @@ -1,235 +0,0 @@ -import httplib2
-import json
-import os
-import re
-import sys
-import time
-from urlparse import urlparse
-import xml.dom.minidom
-
-from proboscis.asserts import *
-from troveclient.compat.client import TroveHTTPClient
-from troveclient.compat.xml import TroveXmlClient
-
-
-print_req = True
-
-
-class ConfigFile(object):
-
- def __init__(self, config_file):
- if not os.path.exists(config_file):
- raise RuntimeError("Could not find Example CONF at %s." %
- config_file)
- file_contents = open(config_file, "r").read()
- try:
- config = json.loads(file_contents)
- except Exception as exception:
- msg = 'Error loading config file "%s".' % config_file
- raise RuntimeError(msg, exception)
-
- self.directory = config.get("directory", None)
- if not self.directory.endswith('/'):
- self.directory += '/'
- self.api_url = config.get("api_url", None)
- self.auth_url = config.get("auth_url", None)
- self.username = config.get("username", None)
- self.password = config.get("password", None)
- self.tenant = config.get("tenant", None)
- self.replace_host = config.get("replace_host", None)
- self.replace_dns_hostname = config.get("replace_dns_hostname", None)
- if self.auth_url:
- auth_id, tenant_id = self.get_auth_token_id_tenant_id(self.auth_url,
- self.username,
- self.password)
- else:
- auth_id = self.tenant
- tenant_id = self.tenant
-
- print "id = %s" % auth_id
- self.headers = {
- 'X-Auth-Token': str(auth_id)
- }
- print "tenantID = %s" % tenant_id
- self.tenantID = tenant_id
- self.dbaas_url = "%s/v1.0/%s" % (self.api_url, self.tenantID)
-
-
-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):
- self.conf = conf
-
- def _indent_xml(self, my_string):
- my_string = my_string.encode("utf-8")
- # convert to plain string without indents and spaces
- my_re = re.compile('>\s+([^\s])', re.DOTALL)
- my_string = myre.sub('>\g<1>', my_string)
- my_string = xml.dom.minidom.parseString(my_string).toprettyxml()
- # remove line breaks
- my_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
- my_string = my_re.sub('>\g<1></', my_string)
- return my_string
-
- def output_request(self, url, output_headers, body, content_type, method,
- static_auth_token=True):
- output_list = []
- parsed = urlparse(url)
- method_url = shorten_url(url)
- output_list.append("%s %s HTTP/1.1" % (method, method_url))
- output_list.append("User-Agent: %s" % output_headers['User-Agent'])
- output_list.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']
- output_list.append("X-Auth-Token: %s" % output_token)
- output_list.append("Accept: %s" % output_headers['Accept'])
- print("OUTPUT HEADERS: %s" % output_headers)
- output_list.append("Content-Type: %s" % output_headers['Content-Type'])
- output_list.append("")
- pretty_body = self.format_body(body, content_type)
- output_list.append("%s" % pretty_body)
- output_list.append("")
- return '\n'.join(output_list)
-
- def output_response(self, resp, body, content_type):
- output_list = []
- 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']],
- ["Content-Length: %s" % resp['content-length']],
- ["Date: %s" % resp['date']]]
- new_lines = [x[0] for x in lines]
- joined_lines = '\n'.join(new_lines)
- output_list.append(joined_lines)
- if body:
- output_list.append("")
- pretty_body = self.format_body(body, content_type)
- output_list.append("%s" % pretty_body)
- output_list.append("")
- return '\n'.join(output_list)
-
- def format_body(self, body, content_type):
- if 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 ''
- else:
- # expected type of body is xml
- try:
- if self.conf.replace_dns_hostname:
- hostname = 'hostname=\"%s\"' % self.conf.replace_dns_hostname,
- body = re.sub(r'hostname=\"[a-zA-Z0-9-_\.]*\"',
- hostname, body)
- return self._indent_xml(body)
- except Exception as ex:
- return body if body else ''
-
-
- def write_request_file(self, name, content_type, url, method,
- req_headers, request_body):
- def write_request():
- return self.output_request(url, req_headers, request_body,
- content_type, method)
- 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.write_file(name, content_type, url, method, "request",
- write_request)
-
- def write_response_file(self, name, content_type, url, method,
- resp, resp_content):
- def write_response():
- return self.output_response(resp, resp_content, content_type)
- self.write_file(name, content_type, url, method, "response",
- write_response)
- if print_req:
- print("\t%s resp:%s" % (content_type, resp))
- print("\t%s resp content:%s" % (content_type, resp_content))
-
- def write_file(self, name, content_type, url, method, in_or_out, func):
- filename = "%sdb-%s-%s.%s" % (self.conf.directory,
- name.replace('_', '-'), in_or_out,
- content_type)
- with open(filename, "w") as file:
- output = func()
- output = output.replace(self.conf.tenantID, '1234')
- if self.conf.replace_host:
- output = output.replace(self.conf.api_url, self.conf.replace_host)
- pre_host_port = urlparse(self.conf.api_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_", "")
-
- file.write(output)
-
-
-# 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
- self.snippet_writer.write_request_file(self.name, self.content_type,
- url, method, request_headers, request_body)
- self.snippet_writer.write_response_file(self.name, self.content_type,
- url, method, response_headers, response_body)
-
- # Create a short url to assert against.
- short_url = url
- for prefix in (self.snippet_writer.conf.dbaas_url,
- self.snippet_writer.conf.api_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
- }
-
-
-class JsonClient(TroveHTTPClient):
-
- content_type = 'json'
-
- def http_log(self, *args, **kwargs):
- return write_to_snippet(self, *args, **kwargs)
-
-
-class XmlClient(TroveXmlClient):
-
- content_type = 'xml'
-
- def http_log(self, *args, **kwargs):
- return write_to_snippet(self, *args, **kwargs)
diff --git a/tests/examples/examples/example_generation.py b/tests/examples/examples/example_generation.py deleted file mode 100644 index 7ca8a02..0000000 --- a/tests/examples/examples/example_generation.py +++ /dev/null @@ -1,1042 +0,0 @@ -import httplib2 -import json -import os -import re -import sys -import time -from urlparse import urlparse -import xml.dom.minidom - -from proboscis import before_class -from proboscis import test -from proboscis import TestProgram -from proboscis.asserts import * -from proboscis.asserts import Check - -from troveclient.compat import Dbaas -from troveclient.compat import TroveHTTPClient - - -from client import ConfigFile -from client import SnippetWriter -from client import JsonClient -from client import XmlClient - - -print_req = True - - -class ExampleClient(object): - - def __init__(self, config_file): - if not os.path.exists(config_file): - raise RuntimeError("Could not find Example CONF at %s." % - config_file) - file_contents = open(config_file, "r").read() - try: - config = json.loads(file_contents) - except Exception as exception: - msg = 'Error loading config file "%s".' % config_file - raise RuntimeError(msg, exception) - - self.directory = config.get("directory", None) - if not self.directory.endswith('/'): - self.directory += '/' - print "directory = %s" % self.directory - self.api_url = config.get("api_url", None) - print "api_url = %s" % self.api_url - #auth - auth_url = config.get("auth_url", None) - print "auth_url = %s" % auth_url - username = config.get("username", None) - print "username = %s" % username - password = config.get("password", None) - print "password = %s" % password - self.tenant = config.get("tenant", None) - self.replace_host = config.get("replace_host", None) - print "tenant = %s" % self.tenant - self.replace_dns_hostname = config.get("replace_dns_hostname", None) - if auth_url: - auth_id, tenant_id = self.get_auth_token_id_tenant_id(auth_url, - username, - password) - else: - auth_id = self.tenant - tenant_id = self.tenant - - print "id = %s" % auth_id - self.headers = { - 'X-Auth-Token': str(auth_id) - } - print "tenantID = %s" % tenant_id - self.tenantID = tenant_id - self.dbaas_url = "%s/v1.0/%s" % (self.api_url, self.tenantID) - - def write_request_file(self, name, content_type, url, method, - req_headers, request_body): - def write_request(): - return self.output_request(url, req_headers, request_body, - content_type, method) - 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.write_file(name, content_type, url, method, write_request) - - def write_response_file(self, name, content_type, url, method, - resp, resp_content): - def write_response(): - return self.output_response(resp, resp_content, content_type) - self.write_file(name, content_type, url, method, write_response) - if print_req: - print("\t%s resp:%s" % (content_type, resp)) - print("\t%s resp content:%s" % (content_type, resp_content)) - - def write_file(self, name, content_type, url, method, func): - filename = "%sdb-%s-request.%s" % (self.directory, name, content_type) - with open(filename, "w") as file: - output = func() - output = output.replace(self.tenantID, '1234') - if self.replace_host: - output = output.replace(self.api_url, self.replace_host) - pre_host_port = urlparse(self.api_url).netloc - post_host = urlparse(self.replace_host).netloc - output = output.replace(pre_host_port, post_host) - - file.write(output) - - def version_http_call(self, name, method, json, xml, - output=True, print_resp=False): - json['url'] = "%s/%s" % (self.api_url, json['url']) - xml['url'] = "%s/%s" % (self.api_url, xml['url']) - return self.make_request(name, method, json, xml, output, print_resp) - - def http_call(self, name, method, url, json, xml, - output=True, print_resp=False): - json['url'] = "%s/%s" % (self.dbaas_url, json['url']) - xml['url'] = "%s/%s" % (self.dbaas_url, xml['url']) - return self.make_request(name, method, json, xml, output, print_resp) - - # print_req and print_resp for debugging purposes - def make_request(self, name, method, json, xml, - output=True, print_resp=False): - name = name.replace('_', '-') - print "http call for %s" % name - http = httplib2.Http(disable_ssl_certificate_validation=True) - req_headers = {'User-Agent': "python-example-client", - 'Content-Type': "application/json", - 'Accept': "application/json" - } - req_headers.update(self.headers) - - - content_type = 'json' - request_body = json.get('body', None) - url = json.get('url') - if output: - self.write_request_file(name, 'json', url, method, req_headers, - request_body) - - resp, resp_content = http.request(url, method, body=request_body, - headers=req_headers) - json_resp = resp, resp_content - if output: - filename = "%sdb-%s-response.%s" % (self.directory, name, - content_type) - self.write_response_file(name, 'json', url, method, resp, - resp_content) - - - content_type = 'xml' - req_headers['Accept'] = 'application/xml' - req_headers['Content-Type'] = 'application/xml' - request_body = xml.get('body', None) - url = xml.get('url') - if output: - filename = "%sdb-%s-request.%s" % (self.directory, name, - content_type) - output = self.write_request_file(name, 'xml', url, method, - req_headers, request_body) - resp, resp_content = http.request(url, method, body=request_body, - headers=req_headers) - xml_resp = resp, resp_content - if output: - filename = "%sdb-%s-response.%s" % (self.directory, name, - content_type) - self.write_response_file(name, 'xml', url, method, resp, - resp_content) - - - return json_resp, xml_resp - - def _indent_xml(self, my_string): - my_string = my_string.encode("utf-8") - # convert to plain string without indents and spaces - my_re = re.compile('>\s+([^\s])', re.DOTALL) - my_string = myre.sub('>\g<1>', my_string) - my_string = xml.dom.minidom.parseString(my_string).toprettyxml() - # remove line breaks - my_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL) - my_string = my_re.sub('>\g<1></', my_string) - return my_string - - def output_request(self, url, output_headers, body, content_type, method, - static_auth_token=True): - output_list = [] - parsed = urlparse(url) - if parsed.query: - method_url = parsed.path + '?' + parsed.query - else: - method_url = parsed.path - output_list.append("%s %s HTTP/1.1" % (method, method_url)) - output_list.append("User-Agent: %s" % output_headers['User-Agent']) - output_list.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'] - output_list.append("X-Auth-Token: %s" % output_token) - output_list.append("Accept: %s" % output_headers['Accept']) - output_list.append("Content-Type: %s" % output_headers['Content-Type']) - output_list.append("") - pretty_body = self.format_body(body, content_type) - output_list.append("%s" % pretty_body) - output_list.append("") - return '\n'.join(output_list) - - def output_response(self, resp, body, content_type): - output_list = [] - 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']], - ["Content-Length: %s" % resp['content-length']], - ["Date: %s" % resp['date']]] - new_lines = [x[0] for x in lines] - joined_lines = '\n'.join(new_lines) - output_list.append(joined_lines) - if body: - output_list.append("") - pretty_body = self.format_body(body, content_type) - output_list.append("%s" % pretty_body) - output_list.append("") - return '\n'.join(output_list) - - def format_body(self, body, content_type): - if content_type == 'json': - try: - if self.replace_dns_hostname: - before = r'\"hostname\": \"[a-zA-Z0-9-_\.]*\"' - after = '\"hostname\": \"%s\"' % self.replace_dns_hostname - body = re.sub(before, after, body) - return json.dumps(json.loads(body), sort_keys=True, indent=4) - except Exception: - return body if body else '' - else: - # expected type of body is xml - try: - if self.replace_dns_hostname: - hostname = 'hostname=\"%s\"' % self.replace_dns_hostname, - body = re.sub(r'hostname=\"[a-zA-Z0-9-_\.]*\"', - hostname, body) - return self._indent_xml(body) - except Exception as ex: - return body if body else '' - - def get_auth_token_id_tenant_id(self, url, username, password): - body = ('{"auth":{"tenantName": "%s", "passwordCredentials": ' - '{"username": "%s", "password": "%s"}}}') - body = body % (self.tenant, username, password) - http = httplib2.Http(disable_ssl_certificate_validation=True) - req_headers = {'User-Agent': "python-example-client", - 'Content-Type': "application/json", - 'Accept': "application/json", - } - resp, body = http.request(url, 'POST', body=body, headers=req_headers) - auth = json.loads(body) - auth_id = auth['access']['token']['id'] - tenant_id = auth['access']['token']['tenant']['id'] - return auth_id, tenant_id - - -@test -def load_config_file(): - global conf - print("RUNNING ARGS : " + str(sys.argv)) - conf = None - for arg in sys.argv[1:]: - conf_file_path = os.path.expanduser(arg) - conf = ConfigFile(conf_file_path) - return - if not conf: - fail("Missing conf file.") - -def create_client(cls=TroveHTTPClient): - client = Dbaas(conf.username, conf.password, tenant=conf.tenant, - auth_url="blah/", auth_strategy='fake', - insecure=True, service_type='trove', - service_url=conf.dbaas_url, client_cls=cls) - return client - -class ClientPair(object): - """ - Combines a Json and XML version of the Dbaas client. - """ - - def __init__(self): - snippet_writer = SnippetWriter(conf) - def make_client(cls): - client = create_client(cls) - client.client.name = "auth" - client.client.snippet_writer = snippet_writer - client.authenticate() - return client - self.json = make_client(JsonClient) - self.xml = make_client(XmlClient) - self.clients = [self.json, self.xml] - - def do(self, name, url, method, status, reason, func, func_args=None): - """ - Performs the given function twice, first for the JSON client, then for - the XML one, and writes both to their respective files. - 'name' is the name of the file, while 'url,' 'method,' 'status,' - and 'reason' are expected values that are asserted against. - If func_args is present, it is a list of lists, each one of which - is passed as the *args to the two invocations of "func". - """ - func_args = func_args or [[], []] - snippet_writer = SnippetWriter(conf) - results = [] - for index, client in enumerate(self.clients): - client.client.snippet_writer = snippet_writer - client.client.name = name - args = func_args[index] - result = func(client, *args) - with Check() as check: - if isinstance(url, (list, tuple)): - check.equal(client.client.old_info['url'], url[index]) - else: - check.equal(client.client.old_info['url'], url) - check.equal(client.client.old_info['method'], method) - check.equal(client.client.old_info['response_headers'].status, - status) - check.equal(client.client.old_info['response_headers'].reason, - reason) - results.append(result) - # To prevent this from writing a snippet somewhere else... - client.client.name = "junk" - - return results - - -JSON_INDEX = 0 -XML_INDEX = 1 - -@test(depends_on=[load_config_file]) -class Versions(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def get_versions(self): - self.clients.do("versions", - "", "GET", 200, "OK", - lambda client : client.versions.index(conf.api_url)) - - - @test - def get_version(self): - self.clients.do("versions", - "/v1.0", "GET", 200, "OK", - lambda client : client.versions.index(conf.api_url + "/v1.0/")) - - -@test(depends_on=[load_config_file]) -class Flavors(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def get_flavors(self): - self.clients.do("flavors", - "/flavors", "GET", 200, "OK", - lambda client : client.flavors.list()) - - @test - def get_flavor_by_id(self): - self.clients.do("flavors_by_id", - "/flavors/1", "GET", 200, "OK", - lambda client : client.flavors.get(1)) - - -@test(depends_on=[load_config_file]) -def clean_slate(): - client = create_client() - client.client.name = "list" - instances = client.instances.list() - assert_equal(0, len(instances), "Instance count must be zero.") - - -@test(depends_on=[clean_slate]) -class CreateInstance(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def post_create_instance(self): - def create_instance(client, name): - instance = client.instances.create(name, 1, volume={'size':2}, - databases=[{ - "name": "sampledb", - "character_set": "utf8", - "collate": "utf8_general_ci" - },{ - "name": "nextround" - } - ], - users =[{ - "databases":[{ "name":"sampledb"}], - "name":"demouser", - "password": "demopassword" - } - ]) - assert_equal(instance.status, "BUILD") - return instance - self.instances = self.clients.do("create_instance", - "/instances", "POST", 200, "OK", - create_instance, - (["json_rack_instance"], ["xml_rack_instance"])) - #self.instance_j = create_instance(self.clients.json, - # "json_rack_instance") - #self.instance_x = create_instance(self.clients.xml, - # "xml_rack_instance") - - @test(depends_on=[post_create_instance]) - def wait_for_instances(self): - for instance in self.instances: - while instance.status != "ACTIVE": - assert_equal(instance.status, "BUILD") - instance.get() - time.sleep(0.1) - global json_instance - json_instance = self.instances[0] - global xml_instance - xml_instance = self.instances[1] - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Databases(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def post_create_databases(self): - self.clients.do("create_databases", - ("/instances/%s/databases" % json_instance.id, - "/instances/%s/databases" % xml_instance.id), - "POST", 202, "Accepted", - lambda client, id : client.databases.create(id, databases=[ - { - "name": "testingdb", - "character_set": "utf8", - "collate": "utf8_general_ci" - }, - { - "name": "anotherdb" - }, - { - "name": "oneMoreDB" - } - ]), ([json_instance.id], [xml_instance.id])) - - @test(depends_on=[post_create_databases]) - def get_list_databases(self): - results = self.clients.do("list_databases", - ("/instances/%s/databases" % json_instance.id, - "/instances/%s/databases" % xml_instance.id), - "GET", 200, "OK", - lambda client, id : client.databases.list(id), - ([json_instance.id], [xml_instance.id])) - - @test(depends_on=[post_create_databases]) - def get_list_databases_limit_two(self): - results = self.clients.do("list_databases_pagination", - ("/instances/%s/databases?limit=1" % json_instance.id, - "/instances/%s/databases?limit=2" % xml_instance.id), - "GET", 200, "OK", - lambda client, id, limit : client.databases.list(id, limit=limit), - ([json_instance.id, 1], [xml_instance.id, 2])) - assert_equal(1, len(results[JSON_INDEX])) - assert_equal(2, len(results[XML_INDEX])) - assert_equal("anotherdb", results[JSON_INDEX].next) - assert_equal("nextround", results[XML_INDEX].next) - - @test(depends_on=[post_create_databases], - runs_after=[get_list_databases, get_list_databases_limit_two]) - def delete_databases(self): - results = self.clients.do("delete_databases", - ("/instances/%s/databases/testingdb" % json_instance.id, - "/instances/%s/databases/oneMoreDB" % xml_instance.id), - "DELETE", 202, "Accepted", - lambda client, id, name : client.databases.delete(id, name), - ([json_instance.id, 'testingdb'], [xml_instance.id, 'oneMoreDB'])) - - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Users(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def post_create_users(self): - results = self.clients.do("create_users", - ("/instances/%s/users" % json_instance.id, - "/instances/%s/users" % xml_instance.id), - "POST", 202, "Accepted", - lambda client, id : client.users.create(id, [ - { - "name": "dbuser1", - "password": "password", - "database": "databaseA" - }, - { - "name": "dbuser2", - "password": "password", - "databases": [ - { - "name": "databaseB" - }, - { - "name": "databaseC" - } - ] - }, - { - "name": "dbuser3", - "password": "password", - "database": "databaseD" - } - ]), - ([json_instance.id], [xml_instance.id])) - - @test(depends_on=[post_create_users]) - def get_list_users(self): - results = self.clients.do("list_users", - ("/instances/%s/users" % json_instance.id, - "/instances/%s/users" % xml_instance.id), - "GET", 200, "OK", - lambda client, id : client.users.list(id), - ([json_instance.id], [xml_instance.id])) - - @test(depends_on=[post_create_users]) - def get_list_users_limit_two(self): - results = self.clients.do("list_users_pagination", - ("/instances/%s/users?limit=2" % json_instance.id, - "/instances/%s/users?limit=2" % xml_instance.id), - "GET", 200, "OK", - lambda client, id : client.users.list(id, limit=2), - ([json_instance.id], [xml_instance.id])) - - @test(depends_on=[post_create_users], - runs_after=[get_list_users, get_list_users_limit_two]) - def delete_users(self): - user_name = "testuser" - results = self.clients.do("delete_users", - ("/instances/%s/users/%s" % (json_instance.id, user_name), - "/instances/%s/users/%s" % (xml_instance.id, user_name)), - "DELETE", 202, "Accepted", - lambda client, id : client.users.delete(id, user=user_name), - ([json_instance.id], [xml_instance.id])) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Root(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def post_enable_root_access(self): - results = self.clients.do("enable_root_user", - ("/instances/%s/root" % json_instance.id, - "/instances/%s/root" % xml_instance.id), - "POST", 200, "OK", - lambda client, id : client.root.create(id), - ([json_instance.id], [xml_instance.id])) - - @test(depends_on=[post_enable_root_access]) - def get_check_root_access(self): - results = self.clients.do("check_root_user", - ("/instances/%s/root" % json_instance.id, - "/instances/%s/root" % xml_instance.id), - "GET", 200, "OK", - lambda client, id : client.root.is_root_enabled(id), - ([json_instance.id], [xml_instance.id])) - assert_equal(results[JSON_INDEX], True) - assert_equal(results[XML_INDEX], True) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class InstanceList(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def get_list_instance_index(self): - results = self.clients.do("instances_index", - "/instances", "GET", 200, "OK", - lambda client : client.instances.list()) - for result in results: - assert_equal(2, len(result)) - - @test - def get_instance_details(self): - results = self.clients.do("instance_status_detail", - ("/instances/%s" % json_instance.id, - "/instances/%s" % xml_instance.id), - "GET", 200, "OK", - lambda client, id : client.instances.get(id), - ([json_instance.id], [xml_instance.id])) - assert_equal(results[JSON_INDEX].id, json_instance.id) - assert_equal(results[XML_INDEX].id, xml_instance.id) - - @test - def get_list_instance_index_limit_two(self): - third_instance = self.clients.json.instances.create( - "The Third Instance", 1, volume={'size':2}) - while third_instance.status != "ACTIVE": - third_instance.get() - time.sleep(0.1) - - results = self.clients.do("instances_index_pagination", - "/instances?limit=2", "GET", 200, "OK", - lambda client : client.instances.list(limit=2)) - for result in results: - assert_equal(2, len(result)) - - self.clients.json.instances.delete(third_instance.id) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class Actions(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - def _wait_for_active(self, *acceptable_states): - for instance in (json_instance, xml_instance): - instance.get() - print('instance.status=%s' % instance.status) - while instance.status != "ACTIVE": - assert_true(instance.status in acceptable_states, - "Instance status == %s; expected it to be one of these: %s" - % (instance.status, acceptable_states)) - instance.get() - time.sleep(0.1) - - @test - def instance_restart(self): - results = self.clients.do("instance_restart", - ("/instances/%s/action" % json_instance.id, - "/instances/%s/action" % xml_instance.id), - "POST", 202, "Accepted", - lambda client, id : client.instances.restart(id), - ([json_instance.id], [xml_instance.id])) - self._wait_for_active("RESTART") - - @test - def instance_resize_volume(self): - results = self.clients.do("instance_resize_volume", - ("/instances/%s/action" % json_instance.id, - "/instances/%s/action" % xml_instance.id), - "POST", 202, "Accepted", - lambda client, id : client.instances.resize_volume(id, 4), - ([json_instance.id], [xml_instance.id])) - self._wait_for_active("RESIZE") - assert_equal(json_instance.volume['size'], 4) - assert_equal(xml_instance.volume['size'], '4') - - @test - def instance_resize_flavor(self): - results = self.clients.do("instance_resize_flavor", - ("/instances/%s/action" % json_instance.id, - "/instances/%s/action" % xml_instance.id), - "POST", 202, "Accepted", - lambda client, id : client.instances.resize_flavor(id, 3), - ([json_instance.id], [xml_instance.id])) - self._wait_for_active("RESIZE") - assert_equal(json_instance.flavor['id'], '3') - assert_equal(xml_instance.flavor['id'], '3') - - -@test(depends_on=[CreateInstance], groups=['uses_instances', "MgmtHosts"]) -class MgmtHosts(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def mgmt_list_hosts(self): - results = self.clients.do("mgmt_list_hosts", - "/mgmt/hosts", "GET", 200, "OK", - lambda client : client.mgmt.hosts.index()) - with Check() as check: - for hosts in results: - check.equal(1, len(hosts)) - check.equal("fake_host", hosts[0].name) - check.equal(2, results[0][0].instanceCount) - # In XML land this is a string. :'( - check.equal("2", results[1][0].instanceCount) - - @test - def mgmt_get_host_detail(self): - results = self.clients.do("mgmt_get_host_detail", - "/mgmt/hosts/fake_host", "GET", 200, "OK", - lambda client : client.mgmt.hosts.get("fake_host")) - with Check() as check: - for host in results: - check.equal(results[0].name, "fake_host") - check.equal(results[1].name, "fake_host") - # XML entries won't come back as these types. :( - check.true(isinstance(results[0].percentUsed, int)), - check.true(isinstance(results[0].totalRAM, int)), - check.true(isinstance(results[0].usedRAM, int)), - with Check() as check: - for host in results: - check.equal(2, len(host.instances)) - for instance in host.instances: - check.equal(instance['status'], 'ACTIVE') - check.true(instance['name'] == 'json_rack_instance' or - instance['name'] == 'xml_rack_instance') - #TODO: Check with GUID regex. - check.true(isinstance(instance['id'], basestring)) - check.true(isinstance(instance['server_id'], basestring)) - check.true(isinstance(instance['tenant_id'], basestring)) - - @test - def mgmt_host_update_all(self): - results = self.clients.do("mgmt_host_update", - "/mgmt/hosts/fake_host/instances/action", - "POST", 202, "Accepted", - lambda client : client.mgmt.hosts.update_all("fake_host")) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtStorage(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def mgmt_get_storage(self): - results = self.clients.do("mgmt_get_storage", - "/mgmt/storage", "GET", 200, "OK", - lambda client : client.mgmt.storage.index()) - for index, devices in enumerate(results): - with Check() as check: - check.equal(1, len(devices)) - device = devices[0] - check.equal(int(device.capacity['available']), 90) - check.equal(int(device.capacity['total']), 100) - check.equal(device.name, "fake_storage") - check.equal(int(device.provision['available']), 40) - check.equal(int(device.provision['percent']), 10) - check.equal(int(device.provision['total']), 50) - check.equal(device.type, "test_type") - check.equal(int(device.used), 10) - if index == JSON_INDEX: - check.true(isinstance(device.capacity['available'], int)) - check.true(isinstance(device.capacity['total'], int)) - check.true(isinstance(device.provision['available'], int)) - check.true(isinstance(device.provision['percent'], int)) - check.true(isinstance(device.provision['total'], int)) - check.true(isinstance(device.used, int)) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtAccount(object): - - @before_class - def setup(self): - self.clients = ClientPair() - - @test - def mgmt_get_account_details(self): - results = self.clients.do("mgmt_get_account_details", - "/mgmt/accounts/admin", "GET", 200, "OK", - lambda client : client.mgmt.accounts.show("admin")) - with Check() as check: - for account_info in results: - check.equal(2, len(account_info.instances)) - check.equal('admin', account_info.id) - - @test - def mgmt_get_account_list(self): - results = self.clients.do("mgmt_list_accounts", - "/mgmt/accounts", "GET", 200, "OK", - lambda client : client.mgmt.accounts.index()) - for index, result in enumerate(results): - for account in result.accounts: - assert_equal('admin', account['id']) - if index == JSON_INDEX: - assert_equal(2, account['num_instances']) - else: - assert_equal("2", account['num_instances']) - - -def for_both(func): - def both(self): - for result in self.results: - func(self, result) - return both - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtInstance(object): - - @before_class - def mgmt_get_instance_details(self): - self.clients = ClientPair() - self.results = self.clients.do("mgmt_get_instance_details", - ("/mgmt/instances/%s" % json_instance.id, - "/mgmt/instances/%s" % xml_instance.id), - "GET", 200, "OK", - lambda client, id : client.mgmt.instances.show(id), - ([json_instance.id], [xml_instance.id])) - - @test - @for_both - def created(self, result): - #TODO: use regex - assert_true(isinstance(result.created, basestring)) - - @test - def deleted(self): - assert_equal(self.results[JSON_INDEX].deleted, False) - assert_equal(self.results[XML_INDEX].deleted, "False") - - @test - @for_both - def flavor(self, result): - assert_true(result.flavor['id'] == "1" or result.flavor['id'] == "3") - assert_equal(len(result.flavor['links']), 2) - #TODO: validate the flavors format. - - @test - @for_both - def guest_status(self, result): - assert_equal(result.guest_status['state_description'], 'running') - - @test - @for_both - def host(self, result): - assert_equal(result.host, 'fake_host') - - @test - def id(self): - assert_equal(self.results[JSON_INDEX].id, json_instance.id) - assert_equal(self.results[XML_INDEX].id, xml_instance.id) - - @test - @for_both - def links(self, result): - assert_true(isinstance(result.links, list)) - for link in result.links: - assert_true(isinstance(link, dict)) - assert_true(isinstance(link['href'], basestring)) - assert_true(isinstance(link['rel'], basestring)) - - @test - def local_id(self): - #TODO: regex - assert_true(isinstance(self.results[JSON_INDEX].local_id, int)) - assert_true(isinstance(self.results[XML_INDEX].local_id, basestring)) - - @test - @for_both - def name(self, result): - #TODO: regex - assert_true(isinstance(result.name, basestring)) - - @test - @for_both - def server_id(self, result): - #TODO: regex - assert_true(isinstance(result.server_id, basestring)) - - @test - @for_both - def status(self, result): - #TODO: regex - assert_equal("ACTIVE", result.status) - - @test - @for_both - def task_description(self, result): - assert_equal(result.task_description, "No tasks for the instance.") - - @test - @for_both - def tenant_id(self, result): - assert_equal(result.tenant_id, "admin") - - @test - @for_both - def updated(self, result): - #TODO: regex - assert_true(isinstance(result.updated, basestring)) - - @test - @for_both - def volume(self, result): - #TODO: regex - assert_true(isinstance(result.volume, dict)) - assert_true('id' in result.volume) - assert_true('size' in result.volume) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtInstanceIndex(object): - - @before_class - def mgmt_get_instance_details(self): - self.clients = ClientPair() - - @test - def mgmt_instance_index(self, deleted=False): - url = "/mgmt/instances?deleted=false" - results = self.clients.do("mgmt_instance_index", - "/mgmt/instances?deleted=false", "GET", 200, "OK", - lambda client : client.mgmt.instances.index(deleted=False)) - #TODO: Valdiate everything... *sigh* - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtInstanceDiagnostics(object): - - @before_class - def mgmt_get_instance_details(self): - self.clients = ClientPair() - - @test - def mgmt_get_instance_diagnostics(self): - results = self.clients.do("mgmt_instance_diagnostics", - ("/mgmt/instances/%s/diagnostics" % json_instance.id, - "/mgmt/instances/%s/diagnostics" % xml_instance.id), - "GET", 200, "OK", - lambda client, id: client.diagnostics.get(id), - ([json_instance.id], [xml_instance.id])) - #TODO: validate the actual stuff that comes back (booorring!). - - -@test(depends_on=[CreateInstance]) -class MgmtInstanceRoot(object): - - @before_class - def mgmt_get_instance_details(self): - self.clients = ClientPair() - - @test - def mgmt_get_root_details(self): - results = self.clients.do("mgmt_get_root_details", - ("/mgmt/instances/%s/root" % json_instance.id, - "/mgmt/instances/%s/root" % xml_instance.id), - "GET", 200, "OK", - lambda client, id: client.mgmt.instances.root_enabled_history(id), - ([json_instance.id], [xml_instance.id])) - #TODO: validate the actual stuff that comes back (booorring!). - - -@test(depends_on=[CreateInstance]) -class MgmtInstanceHWInfo(object): - - @before_class - def mgmt_get_instance_details(self): - self.clients = ClientPair() - - @test - def mgmt_get_hw_info(self): - results = self.clients.do("mgmt_get_hw_info", - ("/mgmt/instances/%s/hwinfo" % json_instance.id, - "/mgmt/instances/%s/hwinfo" % xml_instance.id), - "GET", 200, "OK", - lambda client, id: client.hw_info.get(id), - ([json_instance.id], [xml_instance.id])) - - -@test(depends_on=[CreateInstance], groups=['uses_instances']) -class MgmtInstanceReboot(object): - - @before_class - def mgmt_get_instance_details(self): - self.clients = ClientPair() - - @test - def mgmt_instance_reboot(self): - results = self.clients.do("instance_reboot", - ("/mgmt/instances/%s/action" % json_instance.id, - "/mgmt/instances/%s/action" % xml_instance.id), - "POST", 202, "Accepted", - lambda client, id: client.mgmt.instances.reboot(id), - ([json_instance.id], [xml_instance.id])) - - -@test(depends_on=[CreateInstance], - groups=['uses_instances'], enabled=False) -class MgmtInstanceGuestUpdate(object): - - @before_class - def mgmt_get_instance_details(self): - self.clients = ClientPair() - - @test - def mgmt_instance_guest_update(self): - results = self.clients.do("guest_update", - ("/mgmt/instances/%s/action" % json_instance.id, - "/mgmt/instances/%s/action" % xml_instance.id), - "POST", 202, "Accepted", - lambda client, id: client.mgmt.instances.update(id), - ([json_instance.id], [xml_instance.id])) - - -@test(depends_on=[CreateInstance], runs_after_groups=['uses_instances']) -class ZzzDeleteInstance(object): - - @before_class - def mgmt_get_instance_details(self): - self.clients = ClientPair() - - @test - def zzz_delete_instance(self): - results = self.clients.do("delete_instance", - ("/instances/%s" % json_instance.id, - "/instances/%s" % xml_instance.id), - "DELETE", 202, "Accepted", - lambda client, id: client.instances.delete(id), - ([json_instance.id], [xml_instance.id])) - for result in json_instance, xml_instance: - result.get() - assert_equal(result.status, "SHUTDOWN") - - -if __name__ == "__main__": - TestProgram().run_and_exit() diff --git a/tests/examples/examples/local.conf b/tests/examples/examples/local.conf deleted file mode 100644 index 682200d..0000000 --- a/tests/examples/examples/local.conf +++ /dev/null @@ -1,10 +0,0 @@ -{ - "directory": "/src/apidocs/src/resources/samples/", - "auth_url":"http://localhost:35357/v2.0/tokens", - "api_url":"http://localhost:8779", - "replace_host":"https://ord.databases.api.rackspacecloud.com", - "replace_dns_hostname": "e09ad9a3f73309469cf1f43d11e79549caf9acf2.rackspaceclouddb.com", - "username":"examples", - "password":"examples", - "tenant":"trove" -} diff --git a/tests/examples/gendoc.sh b/tests/examples/gendoc.sh deleted file mode 100755 index 01b2327..0000000 --- a/tests/examples/gendoc.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -pushd ../../apidocs -mvn clean -mvn generate-sources - -popd - diff --git a/tests/examples/local.conf b/tests/examples/local.conf deleted file mode 100644 index adaaecd..0000000 --- a/tests/examples/local.conf +++ /dev/null @@ -1,10 +0,0 @@ -{ - "directory": "output", - "auth_url":null, - "api_url":"http://localhost:8779", - "replace_host":"https://ord.databases.api.rackspacecloud.com", - "replace_dns_hostname": "e09ad9a3f73309469cf1f43d11e79549caf9acf2.rackspaceclouddb.com", - "username":"examples", - "password":"examples", - "tenant":"admin" -} diff --git a/tests/examples/setup.py b/tests/examples/setup.py deleted file mode 100644 index a722150..0000000 --- a/tests/examples/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -# 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 setuptools import setup - - -def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read() - - -setup( - name="Trove Example Generator", - version="0.0.9.9", - author='OpenStack', - description="Generates documentation examples.", - license='Apache', - py_modules=[], - packages=['examples'], - scripts=[] -) diff --git a/tests/examples/tox.ini b/tests/examples/tox.ini deleted file mode 100644 index 1995342..0000000 --- a/tests/examples/tox.ini +++ /dev/null @@ -1,16 +0,0 @@ -# Examples: -# Run tests against Trove running locally in fake mode: -# tox -e local -- --group=blackbox -[tox] -envlist = py27 - -[testenv] -deps = - lxml==2.3 - nose - proboscis - {env:TROVE_CLIENT_PATH} - -[testenv:py27] -commands = - {envpython} {toxinidir}/examples/example_generation.py {toxinidir}/local.conf {posargs:DEFAULTS} diff --git a/tests/integration/core.test.conf b/tests/integration/core.test.conf deleted file mode 100644 index 2ba05be..0000000 --- a/tests/integration/core.test.conf +++ /dev/null @@ -1,48 +0,0 @@ -{ - "report_directory":"rdli-test-report", - "start_services": false, - - - "white_box":false, - "test_mgmt":false, - "use_local_ovz":false, - "use_venv":false, - "glance_code_root":"/opt/stack/glance", - "glance_api_conf":"/vagrant/conf/glance-api.conf", - "glance_reg_conf":"/vagrant/conf/glance-reg.conf", - "glance_images_directory": "/glance_images", - "glance_image": "fakey_fakerson.tar.gz", - "instance_flavor_name":"m1.rd-tiny", - "instance_bigger_flavor_name":"m1.rd-smaller", - "nova_code_root":"/opt/stack/nova", - "nova_conf":"/home/vagrant/nova.conf", - "keystone_code_root":"/opt/stack/keystone", - "keystone_conf":"/etc/keystone/keystone.conf", - "keystone_use_combined":true, - "trove_code_root":"/opt/stack/trove", - "trove_conf":"/tmp/trove.conf", - "trove_version":"v1.0", - "trove_api_updated":"2012-08-01T00:00:00Z", - "trove_must_have_volume":false, - "trove_can_have_volume":true, - "trove_main_instance_has_volume": true, - "trove_max_accepted_volume_size": 1000, - "trove_max_instances_per_user": 55, - "trove_max_volumes_per_user": 100, - "use_nova_volume": false, - "use_reaper":false, -"root_removed_from_instance_api": true, - "root_timestamp_disabled": false, - "openvz_disabled": false, - "management_api_disabled": true, - "dbaas_image": 1, - "dns_driver":"trove.dns.rsdns.driver.RsDnsDriver", - "dns_instance_entry_factory":"trove.dns.rsdns.driver.RsDnsInstanceEntryFactory", - "databases_page_size": 20, - "instances_page_size": 20, - "users_page_size": 20, - "rabbit_runs_locally":false, - -"dns_instance_entry_factory":"trove.dns.rsdns.driver.RsDnsInstanceEntryFactory", - "sentinel": null -} diff --git a/tests/integration/int_tests.py b/tests/integration/int_tests.py deleted file mode 100644 index e8f00fc..0000000 --- a/tests/integration/int_tests.py +++ /dev/null @@ -1,263 +0,0 @@ -#!/usr/bin/env python -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# # Copyright (c) 2011 OpenStack, LLC. -# 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. - - -"""Runs the tests. - -There are a few initialization issues to deal with. -The first is flags, which must be initialized before any imports. The test -configuration has the same problem (it was based on flags back when the tests -resided outside of the Nova code). - -The command line is picked apart so that Nose won't see commands it isn't -compatible with, such as "--flagfile" or "--group". - -This script imports all other tests to make them known to Proboscis before -passing control to proboscis.TestProgram which itself calls nose, which then -call unittest.TestProgram and exits. - -If "repl" is a command line argument, then the original stdout and stderr is -saved and sys.exit is neutralized so that unittest.TestProgram will not exit -and instead sys.stdout and stderr are restored so that interactive mode can -be used. - -""" - - -from __future__ import absolute_import -import atexit -import gettext -import logging -import os -import time -import unittest -import sys -import proboscis - -from nose import config -from nose import core - -from tests.colorizer import NovaTestRunner - - -if os.environ.get("PYDEV_DEBUG", "False") == 'True': - from pydev import pydevd - pydevd.settrace('10.0.2.2', port=7864, stdoutToServer=True, - stderrToServer=True) - - -def add_support_for_localization(): - """Adds support for localization in the logging. - - If ../nova/__init__.py exists, add ../ to Python search path, so that - it will override what happens to be installed in - /usr/(local/)lib/python... - - """ - path = os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir) - possible_topdir = os.path.normpath(path) - if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): - sys.path.insert(0, possible_topdir) - - gettext.install('nova', unicode=1) - - -MAIN_RUNNER = None - - -def initialize_rdl_config(config_file): - from trove.common import cfg - from oslo_log import log - from trove.db import get_db_api - conf = cfg.CONF - cfg.parse_args(['int_tests'], default_config_files=[config_file]) - log.setup(conf, None) - try: - get_db_api().configure_db(conf) - conf_file = conf.find_file(conf.api_paste_config) - except RuntimeError as error: - import traceback - print(traceback.format_exc()) - sys.exit("ERROR: %s" % error) - - -def _clean_up(): - """Shuts down any services this program has started and shows results.""" - from tests.util import report - report.update() - if MAIN_RUNNER is not None: - MAIN_RUNNER.on_exit() - from tests.util.services import get_running_services - for service in get_running_services(): - sys.stderr.write("Stopping service ") - for c in service.cmd: - sys.stderr.write(c + " ") - sys.stderr.write("...\n\r") - service.stop() - - -def import_tests(): - - # TODO(tim.simpson): Import these again once white box test functionality - # is restored. - # from tests.dns import check_domain - # from tests.dns import concurrency - # from tests.dns import conversion - - # The DNS stuff is problematic. Not loading the other tests allow us to - # run its functional tests only. - ADD_DOMAINS = os.environ.get("ADD_DOMAINS", "False") == 'True' - if not ADD_DOMAINS: - from tests.api import delete_all - from tests.api import instances_pagination - from tests.api import instances_quotas - from tests.api import instances_states - from tests.dns import dns - from tests import initialize - from tests.smoke import instance - from tests.volumes import driver - - # Groups that exist as core int-tests are registered from the - # trove.tests.int_tests module - from trove.tests import int_tests - - # Groups defined in trove-integration, or any other externally - # defined groups can be registered here - heavy_black_box_groups = [ - "dbaas.api.instances.pagination", - "dbaas.api.instances.delete", - "dbaas.api.instances.status", - "dbaas.api.instances.down", - "dbaas.api.mgmt.hosts.update", - "fake.dbaas.api.mgmt.instances", - "fake.dbaas.api.mgmt.accounts.broken", - "fake.dbaas.api.mgmt.allaccounts" - ] - proboscis.register(groups=["heavy_blackbox"], - depends_on_groups=heavy_black_box_groups) - - -def run_main(test_importer): - - add_support_for_localization() - - # Strip non-nose arguments out before passing this to nosetests - - repl = False - nose_args = [] - conf_file = "~/test.conf" - show_elapsed = True - groups = [] - print("RUNNING TEST ARGS : " + str(sys.argv)) - extra_test_conf_lines = [] - rdl_config_file = None - nova_flag_file = None - index = 0 - while index < len(sys.argv): - arg = sys.argv[index] - if arg[:2] == "-i" or arg == '--repl': - repl = True - elif arg[:7] == "--conf=": - conf_file = os.path.expanduser(arg[7:]) - print("Setting TEST_CONF to " + conf_file) - os.environ["TEST_CONF"] = conf_file - elif arg[:8] == "--group=": - groups.append(arg[8:]) - elif arg == "--test-config": - if index >= len(sys.argv) - 1: - print('Expected an argument to follow "--test-conf".') - sys.exit() - conf_line = sys.argv[index + 1] - extra_test_conf_lines.append(conf_line) - elif arg[:11] == "--flagfile=": - pass - elif arg[:14] == "--config-file=": - rdl_config_file = arg[14:] - elif arg[:13] == "--nova-flags=": - nova_flag_file = arg[13:] - elif arg.startswith('--hide-elapsed'): - show_elapsed = False - else: - nose_args.append(arg) - index += 1 - - # Many of the test decorators depend on configuration values, so before - # start importing modules we have to load the test config followed by the - # flag files. - from trove.tests.config import CONFIG - - # Find config file. - if not "TEST_CONF" in os.environ: - raise RuntimeError("Please define an environment variable named " + - "TEST_CONF with the location to a conf file.") - file_path = os.path.expanduser(os.environ["TEST_CONF"]) - if not os.path.exists(file_path): - raise RuntimeError("Could not find TEST_CONF at " + file_path + ".") - # Load config file and then any lines we read from the arguments. - CONFIG.load_from_file(file_path) - for line in extra_test_conf_lines: - CONFIG.load_from_line(line) - - if CONFIG.white_box: # If white-box testing, set up the flags. - # Handle loading up RDL's config file madness. - initialize_rdl_config(rdl_config_file) - - # Set up the report, and print out how we're running the tests. - from tests.util import report - from datetime import datetime - report.log("Trove Integration Tests, %s" % datetime.now()) - report.log("Invoked via command: " + str(sys.argv)) - report.log("Groups = " + str(groups)) - report.log("Test conf file = %s" % os.environ["TEST_CONF"]) - if CONFIG.white_box: - report.log("") - report.log("Test config file = %s" % rdl_config_file) - report.log("") - report.log("sys.path:") - for path in sys.path: - report.log("\t%s" % path) - - # Now that all configurations are loaded its time to import everything - test_importer() - - atexit.register(_clean_up) - - c = config.Config(stream=sys.stdout, - env=os.environ, - verbosity=3, - plugins=core.DefaultPluginManager()) - runner = NovaTestRunner(stream=c.stream, - verbosity=c.verbosity, - config=c, - show_elapsed=show_elapsed, - known_bugs=CONFIG.known_bugs) - MAIN_RUNNER = runner - - if repl: - # Turn off the following "feature" of the unittest module in case - # we want to start a REPL. - sys.exit = lambda x: None - - proboscis.TestProgram(argv=nose_args, groups=groups, config=c, - testRunner=MAIN_RUNNER).run_and_exit() - sys.stdout = sys.__stdout__ - sys.stderr = sys.__stderr__ - - -if __name__ == "__main__": - run_main(import_tests) diff --git a/tests/integration/localhost.test.conf b/tests/integration/localhost.test.conf deleted file mode 100644 index 6459935..0000000 --- a/tests/integration/localhost.test.conf +++ /dev/null @@ -1,95 +0,0 @@ -{ - "include-files":["core.test.conf"], - - "fake_mode": true, - "dbaas_url":"http://localhost:8779/v1.0", - "version_url":"http://localhost:8779", - "nova_auth_url":"http://localhost:8779/v1.0/auth", - "trove_auth_url":"http://localhost:8779/v1.0/auth", - "trove_client_insecure":false, - "auth_strategy":"fake", - - "trove_version":"v1.0", - "trove_api_updated":"2012-08-01T00:00:00Z", - - "trove_dns_support":false, - "trove_ip_support":false, - - "nova_client": null, - - - "users": [ - { - "auth_user":"admin", - "auth_key":"password", - "tenant":"admin-1000", - "requirements": { - "is_admin":true, - "services": ["trove"] - } - }, - { - "auth_user":"jsmith", - "auth_key":"password", - "tenant":"2500", - "requirements": { - "is_admin":false, - "services": ["trove"] - } - }, - { - "auth_user":"hub_cap", - "auth_key":"password", - "tenant":"3000", - "requirements": { - "is_admin":false, - "services": ["trove"] - } - } - ], - - "flavors": [ - { - "id": 1, - "name": "m1.tiny", - "ram": 512 - }, - { - "id": 2, - "name": "m1.small", - "ram": 2048 - }, - { - "id": 3, - "name": "m1.medium", - "ram": 4096 - }, - { - "id": 4, - "name": "m1.large", - "ram": 8192 - }, - { - "id": 5, - "name": "m1.xlarge", - "ram": 16384 - }, - { - "id": 6, - "name": "tinier", - "ram": 506 - }, - { - "id": 7, - "name": "m1.rd-tiny", - "ram": 512 - }, - { - "id": 8, - "name": "m1.rd-smaller", - "ram": 768 - } - - ], - "sentinel": null -} diff --git a/tests/integration/run_local.sh b/tests/integration/run_local.sh deleted file mode 100755 index 83d313d..0000000 --- a/tests/integration/run_local.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash -# Specify the path to the Trove repo as argument one. -# This script will create a .pid file and report in the current directory. - -set -e -if [ $# -lt 1 ]; then - echo "Please give the path to the Trove repo as argument one." - exit 5 -else - TROVE_PATH=$1 -fi -if [ $# -lt 2 ]; then - echo "Please give the path to the Trove Client as argument two." - exit 5 -else - TROVECLIENT_PATH=$2 -fi -shift; -shift; - - -PID_FILE="`pwd`.pid" - -function start_server() { - pushd $TROVE_PATH - bin/start_server.sh --pid_file=$PID_FILE - popd -} - -function stop_server() { - if [ -f $PID_FILE ]; - then - pushd $TROVE_PATH - bin/stop_server.sh $PID_FILE - popd - else - echo "The pid file did not exist, so not stopping server." - fi -} -function on_error() { - echo "Something went wrong!" - stop_server -} - -trap on_error EXIT # Proceed to trap - END in event of failure. - -TROVE_CLIENT_PATH=$TROVECLIENT_PATH tox -e py26 -start_server -.tox/py26/bin/pip install -U $TROVECLIENT_PATH -PYTHONPATH=$PYTHONPATH:$TROVECLIENT_PATH .tox/py26/bin/python int_tests.py \ - --conf=localhost.test.conf -- $@ -stop_server - - -trap - EXIT -echo "Ran tests successfully. :)" -exit 0 diff --git a/tests/integration/setup.py b/tests/integration/setup.py deleted file mode 100644 index 52216f6..0000000 --- a/tests/integration/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -# 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 setuptools import setup - - -def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read() - - -setup( - name="Trove Integration Tests", - version="0.0.9.9", - author='OpenStack', - description="Runs integration tests on Ridley.", - license='Apache', - py_modules=[], - packages=['tests'], - scripts=[] -) diff --git a/tests/integration/tests/README b/tests/integration/tests/README deleted file mode 100644 index 05e1db6..0000000 --- a/tests/integration/tests/README +++ /dev/null @@ -1 +0,0 @@ -Integration tests. diff --git a/tests/integration/tests/__init__.py b/tests/integration/tests/__init__.py deleted file mode 100644 index 65f633d..0000000 --- a/tests/integration/tests/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright (c) 2011 OpenStack, LLC. -# 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. - -""" -:mod:`tests` -- Integration / Functional Tests for Nova -=================================== - -.. automodule:: tests - :platform: Unix - :synopsis: Tests for Nova. -.. moduleauthor:: Nirmal Ranganathan <nirmal.ranganathan@rackspace.com> -.. moduleauthor:: Tim Simpson <tim.simpson@rackspace.com> -""" diff --git a/tests/integration/tests/api/__init__.py b/tests/integration/tests/api/__init__.py deleted file mode 100644 index 40d014d..0000000 --- a/tests/integration/tests/api/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2011 OpenStack LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. diff --git a/tests/integration/tests/api/delete_all.py b/tests/integration/tests/api/delete_all.py deleted file mode 100644 index 98c67ab..0000000 --- a/tests/integration/tests/api/delete_all.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# 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. - -from proboscis import test - -from trove.tests.config import CONFIG -from trove.tests.util import create_dbaas_client -from trove.tests.util.users import Requirements - -GROUP = "dbaas.api.instances.delete" - - -@test(groups=[GROUP]) -def delete_all(): - """Delete every single one.""" - user = CONFIG.users.find_user(Requirements(is_admin=False)) - dbaas = create_dbaas_client(user) - instances = dbaas.instances.list() - for instance in instances: - instance.delete() diff --git a/tests/integration/tests/api/instances_pagination.py b/tests/integration/tests/api/instances_pagination.py deleted file mode 100644 index a21aadd..0000000 --- a/tests/integration/tests/api/instances_pagination.py +++ /dev/null @@ -1,219 +0,0 @@ - -from proboscis import after_class -from proboscis import before_class -from proboscis import test -from proboscis.asserts import assert_equal -from proboscis.asserts import assert_is_not -from proboscis.asserts import assert_is_none -from proboscis.asserts import assert_true - - -from troveclient.compat import exceptions -from trove.tests.config import CONFIG -from trove.tests.util import create_dbaas_client -from trove.tests.util.users import Requirements - - -class TestBase(object): - - def set_up(self): - """Create a ton of instances.""" - reqs = Requirements(is_admin=False) - self.user = CONFIG.users.find_user(reqs) - self.dbaas = create_dbaas_client(self.user) - - def delete_instances(self): - chunk = 0 - while True: - chunk += 1 - attempts = 0 - instances = self.dbaas.instances.list() - if len(instances) == 0: - break - # Sit around and try to delete this chunk. - while True: - instance_results = [] - attempts += 1 - deleted_count = 0 - for instance in instances: - try: - instance.delete() - result = "[w]" - except exceptions.UnprocessableEntity: - result = "[W]" - except exceptions.NotFound: - result = "[O]" - deleted_count += 1 - except Exception: - result = "[X]" - instance_results.append(result) - print("Chunk %d, attempt %d : %s" - % (chunk, attempts, ",".join(instance_results))) - if deleted_count == len(instances): - break - - def create_instances(self): - self.ids = [] - for index in range(self.max): - name = "multi-%03d" % index - result = self.dbaas.instances.create(name, 1, - {'size': 1}, [], []) - self.ids.append(result.id) - # Sort the list of IDs in order, so we can confirm the lists pagination - # returns is also sorted correctly. - self.ids.sort() - - @staticmethod - def assert_instances_sorted_by_ids(instances): - # Assert that the strings are always increasing. - last_id = "" - for instance in instances: - assert_true(last_id < instance.id) - - def print_list(self, instances): - print("Length = %d" % len(instances)) - print(",".join([instance.id for instance in instances])) - - def test_pagination(self, requested_limit, requested_marker, - expected_length, expected_marker, expected_last_item): - instances = self.dbaas.instances.list(limit=requested_limit, - marker=requested_marker) - marker = instances.next - - self.print_list(instances) - - # Better get as many as we asked for. - assert_equal(len(instances), expected_length) - # The last one should be roughly this one in the list. - assert_equal(instances[-1].id, expected_last_item) - # Because limit < count, the marker must be something. - if expected_marker: - assert_is_not(marker, None) - assert_equal(marker, expected_marker) - else: - assert_is_none(marker) - self.assert_instances_sorted_by_ids(instances) - - -@test(runs_after_groups=["dbaas.guest.shutdown"], - groups=['dbaas.api.instances.pagination']) -class SimpleCreateAndDestroy(TestBase): - """ - It turns out a big part of guaranteeing pagination works is to make sure - we can create a big batch of instances and delete them without problems. - Even in fake mode though its worth it to check this is the case. - """ - - max = 5 - - @before_class - def set_up(self): - """Create a ton of instances.""" - super(SimpleCreateAndDestroy, self).set_up() - self.delete_instances() - - @test - def spin_up(self): - self.create_instances() - - @after_class(always_run=True) - def tear_down(self): - self.delete_instances() - - -@test(runs_after_groups=["dbaas.guest.shutdown"], - groups=['dbaas.api.instances.pagination']) -class InstancePagination50(TestBase): - - max = 50 - - @before_class - def set_up(self): - """Create a ton of instances.""" - super(InstancePagination50, self).set_up() - self.delete_instances() - self.create_instances() - - @after_class(always_run=True) - def tear_down(self): - """Tear down all instances.""" - self.delete_instances() - - @test - def pagination_short(self): - self.test_pagination(requested_limit=10, requested_marker=None, - expected_length=10, expected_marker=self.ids[9], - expected_last_item=self.ids[9]) - - @test - def pagination_default(self): - self.test_pagination(requested_limit=None, requested_marker=None, - expected_length=20, expected_marker=self.ids[19], - expected_last_item=self.ids[19]) - - @test - def pagination_full(self): - self.test_pagination(requested_limit=50, requested_marker=None, - expected_length=20, expected_marker=self.ids[19], - expected_last_item=self.ids[19]) - - -@test(runs_after_groups=["dbaas.guest.shutdown"], - groups=['dbaas.api.instances.pagination']) -class InstancePagination20(TestBase): - - max = 20 - - @before_class - def set_up(self): - """Create a ton of instances.""" - super(InstancePagination20, self).set_up() - self.delete_instances() - self.create_instances() - - @after_class(always_run=True) - def tear_down(self): - """Tear down all instances.""" - self.delete_instances() - - @test - def pagination_short(self): - self.test_pagination(requested_limit=10, requested_marker=None, - expected_length=10, expected_marker=self.ids[9], - expected_last_item=self.ids[9]) - - @test - def pagination_default(self): - self.test_pagination(requested_limit=None, requested_marker=None, - expected_length=20, expected_marker=None, - expected_last_item=self.ids[19]) - - @test - def pagination_full(self): - self.test_pagination(requested_limit=20, requested_marker=None, - expected_length=20, expected_marker=None, - expected_last_item=self.ids[19]) - - @test - def pagination_overkill(self): - self.test_pagination(requested_limit=30, requested_marker=None, - expected_length=20, expected_marker=None, - expected_last_item=self.ids[19]) - - @test - def pagination_last_half(self): - self.test_pagination(requested_limit=10, requested_marker=self.ids[9], - expected_length=10, expected_marker=None, - expected_last_item=self.ids[19]) - - @test - def pagination_third_quarter(self): - self.test_pagination(requested_limit=5, requested_marker=self.ids[9], - expected_length=5, expected_marker=self.ids[14], - expected_last_item=self.ids[14]) - - @test - def pagination_fourth_quarter(self): - self.test_pagination(requested_limit=20, requested_marker=self.ids[14], - expected_length=5, expected_marker=None, - expected_last_item=self.ids[19]) diff --git a/tests/integration/tests/api/instances_quotas.py b/tests/integration/tests/api/instances_quotas.py deleted file mode 100644 index 3a1c2de..0000000 --- a/tests/integration/tests/api/instances_quotas.py +++ /dev/null @@ -1,47 +0,0 @@ -from proboscis import before_class -from proboscis import test -from proboscis.asserts import assert_raises - -from troveclient.compat import exceptions -from trove.tests.config import CONFIG -from trove.tests.util import create_client - - -@test(groups=['dbaas.api.instances.quotas']) -class InstanceQuotas(object): - - created_instances = [] - - @before_class - def setup(self): - self.client = create_client(is_admin=False) - - @test - def test_too_many_instances(self): - self.created_instances = [] - if 'trove_max_instances_per_user' in CONFIG.values: - too_many = CONFIG.values['trove_max_instances_per_user'] - already_there = len(self.client.instances.list()) - flavor = 1 - for i in range(too_many - already_there): - response = self.client.instances.create('too_many_%d' % i, - flavor, - {'size': 1}) - self.created_instances.append(response) - # This one better fail, because we just reached our quota. - assert_raises(exceptions.OverLimit, - self.client.instances.create, - "too_many", flavor, - {'size': 1}) - - @test(runs_after=[test_too_many_instances]) - def delete_excessive_entries(self): - # Delete all the instances called too_many*. - for id in self.created_instances: - while True: - try: - self.client.instances.delete(id) - except exceptions.UnprocessableEntity: - continue - except exceptions.NotFound: - break diff --git a/tests/integration/tests/api/instances_states.py b/tests/integration/tests/api/instances_states.py deleted file mode 100644 index 965d8e7..0000000 --- a/tests/integration/tests/api/instances_states.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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. - - -GROUP = "dbaas.api.instances.status" - -from proboscis import before_class -from proboscis import test -from proboscis.asserts import assert_equal - -from trove.tests.config import CONFIG -from trove.tests.util import create_dbaas_client -from trove.tests.util.users import Requirements -from trove.common.utils import poll_until - - -@test(groups=[GROUP]) -class InstanceStatusTests(object): - - @before_class - def set_up(self): - reqs = Requirements(is_admin=False) - self.user = CONFIG.users.find_user(reqs) - self.dbaas = create_dbaas_client(self.user) - - @test - def test_create_failure_on_volume_prov_failure(self): - # Fake nova will fail a volume of size 9. - response = self.dbaas.instances.create('volume_fail', 1, - {'size': 9}, []) - poll_until(lambda: self.dbaas.instances.get(response.id), - lambda instance: instance.status == 'ERROR', - time_out=10) - instance = self.dbaas.instances.get(response.id) - print "Status: %s" % instance.status - assert_equal(instance.status, "ERROR", - "Instance did not drop to error after volume prov failure.") - - @test - def test_create_failure_on_server_failure(self): - # Fake nova will fail a server ending with 'SERVER_ERROR'." - response = self.dbaas.instances.create('test_SERVER_ERROR', 1, - {'size': 1}, []) - poll_until(lambda: self.dbaas.instances.get(response.id), - lambda instance: instance.status == 'ERROR', - time_out=10) - instance = self.dbaas.instances.get(response.id) - print "Status: %s" % instance.status - assert_equal(instance.status, "ERROR", - "Instance did not drop to error after server prov failure.") - - ###TODO(ed-): We don't at present have a way to test DNS in FAKE_MODE. - @test(enabled=False) - def test_create_failure_on_dns_failure(self): - #TODO(ed-): Throw DNS-specific monkeywrench into works - response = self.dbaas.instances.create('test_DNS_ERROR', 1, - {'size': 1}, []) - poll_until(lambda: self.dbaas.instances.get(response.id), - lambda instance: instance.status == 'ERROR', - time_out=10) - instance = self.dbaas.instances.get(response.id) - print "Status: %s" % instance.status - assert_equal(instance.status, "ERROR", - "Instance did not drop to error after DNS prov failure.") diff --git a/tests/integration/tests/colorizer.py b/tests/integration/tests/colorizer.py deleted file mode 100644 index 4dd797d..0000000 --- a/tests/integration/tests/colorizer.py +++ /dev/null @@ -1,446 +0,0 @@ -#!/usr/bin/env python -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -# Colorizer Code is borrowed from Twisted: -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -"""Unittest runner for Nova. - -To run all tests - python run_tests.py - -To run a single test: - python run_tests.py test_compute:ComputeTestCase.test_run_terminate - -To run a single test module: - python run_tests.py test_compute - - or - - python run_tests.py api.test_wsgi - -""" - -import gettext -import heapq -import logging -import os -import unittest -import sys -import time - -gettext.install('nova', unicode=1) - -from nose import config -from nose import core -from nose import result -from proboscis import case -from proboscis import SkipTest - -class _AnsiColorizer(object): - """ - A colorizer is an object that loosely wraps around a stream, allowing - callers to write text to the stream in a particular color. - - Colorizer classes must implement C{supported()} and C{write(text, color)}. - """ - _colors = dict(black=30, red=31, green=32, yellow=33, - blue=34, magenta=35, cyan=36, white=37) - - def __init__(self, stream): - self.stream = stream - - def supported(cls, stream=sys.stdout): - """ - A class method that returns True if the current platform supports - coloring terminal output using this method. Returns False otherwise. - """ - if not stream.isatty(): - return False # auto color only on TTYs - try: - import curses - except ImportError: - return False - else: - try: - try: - return curses.tigetnum("colors") > 2 - except curses.error: - curses.setupterm() - return curses.tigetnum("colors") > 2 - except: - raise - # guess false in case of error - return False - supported = classmethod(supported) - - def write(self, text, color): - """ - Write the given text to the stream in the given color. - - @param text: Text to be written to the stream. - - @param color: A string label for a color. e.g. 'red', 'white'. - """ - color = self._colors[color] - self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text)) - - -class _Win32Colorizer(object): - """ - See _AnsiColorizer docstring. - """ - def __init__(self, stream): - from win32console import GetStdHandle, STD_OUT_HANDLE, \ - FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, \ - FOREGROUND_INTENSITY - red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN, - FOREGROUND_BLUE, FOREGROUND_INTENSITY) - self.stream = stream - self.screenBuffer = GetStdHandle(STD_OUT_HANDLE) - self._colors = { - 'normal': red | green | blue, - 'red': red | bold, - 'green': green | bold, - 'blue': blue | bold, - 'yellow': red | green | bold, - 'magenta': red | blue | bold, - 'cyan': green | blue | bold, - 'white': red | green | blue | bold - } - - def supported(cls, stream=sys.stdout): - try: - import win32console - screenBuffer = win32console.GetStdHandle( - win32console.STD_OUT_HANDLE) - except ImportError: - return False - import pywintypes - try: - screenBuffer.SetConsoleTextAttribute( - win32console.FOREGROUND_RED | - win32console.FOREGROUND_GREEN | - win32console.FOREGROUND_BLUE) - except pywintypes.error: - return False - else: - return True - supported = classmethod(supported) - - def write(self, text, color): - color = self._colors[color] - self.screenBuffer.SetConsoleTextAttribute(color) - self.stream.write(text) - self.screenBuffer.SetConsoleTextAttribute(self._colors['normal']) - - -class _NullColorizer(object): - """ - See _AnsiColorizer docstring. - """ - def __init__(self, stream): - self.stream = stream - - def supported(cls, stream=sys.stdout): - return True - supported = classmethod(supported) - - def write(self, text, color): - self.stream.write(text) - - -def get_elapsed_time_color(elapsed_time): - if elapsed_time > 1.0: - return 'yellow' - elif elapsed_time > 0.25: - return 'cyan' - else: - return 'green' - - -class NovaTestResult(case.TestResult): - def __init__(self, *args, **kw): - self.show_elapsed = kw.pop('show_elapsed') - self.known_bugs = kw.pop('known_bugs', {}) - super(NovaTestResult, self).__init__(*args, **kw) - self.num_slow_tests = 5 - self.slow_tests = [] # this is a fixed-sized heap - self._last_case = None - self.colorizer = None - # NOTE(vish): reset stdout for the terminal check - stdout = sys.stdout - sys.stdout = sys.__stdout__ - for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]: - if colorizer.supported(): - self.colorizer = colorizer(self.stream) - break - sys.stdout = stdout - - # NOTE(lorinh): Initialize start_time in case a sqlalchemy-migrate - # error results in it failing to be initialized later. Otherwise, - # _handleElapsedTime will fail, causing the wrong error message to - # be outputted. - self.start_time = time.time() - - def _intercept_known_bugs(self, test, err): - name = str(test) - excuse = self.known_bugs.get(name, None) - if excuse: - tracker_id, error_string = excuse - if error_string in str(err[1]): - skip = SkipTest("KNOWN BUG: %s\n%s" - % (tracker_id, str(err[1]))) - self.onError(test) - super(NovaTestResult, self).addSkip(test, skip) - else: - result = (RuntimeError, RuntimeError( - 'Test "%s" contains known bug %s.\n' - 'Expected the following error string:\n%s\n' - 'What was seen was the following:\n%s\n' - 'If the bug is no longer happening, please change ' - 'the test config.' - % (name, tracker_id, error_string, str(err))), None) - self.onError(test) - super(NovaTestResult, self).addError(test, result) - return True - return False - - def getDescription(self, test): - return str(test) - - def _handleElapsedTime(self, test): - self.elapsed_time = time.time() - self.start_time - item = (self.elapsed_time, test) - # Record only the n-slowest tests using heap - if len(self.slow_tests) >= self.num_slow_tests: - heapq.heappushpop(self.slow_tests, item) - else: - heapq.heappush(self.slow_tests, item) - - def _writeElapsedTime(self, test): - color = get_elapsed_time_color(self.elapsed_time) - self.colorizer.write(" %.2f" % self.elapsed_time, color) - - def _writeResult(self, test, long_result, color, short_result, success): - if self.showAll: - self.colorizer.write(long_result, color) - if self.show_elapsed and success: - self._writeElapsedTime(test) - self.stream.writeln() - elif self.dots: - self.stream.write(short_result) - self.stream.flush() - - # NOTE(vish): copied from unittest with edit to add color - def addSuccess(self, test): - if self._intercept_known_bugs(test, None): - return - unittest.TestResult.addSuccess(self, test) - self._handleElapsedTime(test) - self._writeResult(test, 'OK', 'green', '.', True) - - # NOTE(vish): copied from unittest with edit to add color - def addFailure(self, test, err): - if self._intercept_known_bugs(test, err): - return - self.onError(test) - unittest.TestResult.addFailure(self, test, err) - self._handleElapsedTime(test) - self._writeResult(test, 'FAIL', 'red', 'F', False) - - # NOTE(vish): copied from nose with edit to add color - def addError(self, test, err): - """Overrides normal addError to add support for - errorClasses. If the exception is a registered class, the - error will be added to the list for that class, not errors. - """ - if self._intercept_known_bugs(test, err): - return - self.onError(test) - self._handleElapsedTime(test) - stream = getattr(self, 'stream', None) - ec, ev, tb = err - try: - exc_info = self._exc_info_to_string(err, test) - except TypeError: - # 2.3 compat - exc_info = self._exc_info_to_string(err) - for cls, (storage, label, isfail) in self.errorClasses.items(): - if result.isclass(ec) and issubclass(ec, cls): - if isfail: - test.passed = False - storage.append((test, exc_info)) - # Might get patched into a streamless result - if stream is not None: - if self.showAll: - message = [label] - detail = result._exception_detail(err[1]) - if detail: - message.append(detail) - stream.writeln(": ".join(message)) - elif self.dots: - stream.write(label[:1]) - return - self.errors.append((test, exc_info)) - test.passed = False - if stream is not None: - self._writeResult(test, 'ERROR', 'red', 'E', False) - - @staticmethod - def get_doc(cls_or_func): - """Grabs the doc abbreviated doc string.""" - try: - return cls_or_func.__doc__.split("\n")[0].strip() - except (AttributeError, IndexError): - return None - - def startTest(self, test): - unittest.TestResult.startTest(self, test) - self.start_time = time.time() - test_name = None - try: - entry = test.test.__proboscis_case__.entry - if entry.method: - current_class = entry.method.im_class - test_name = self.get_doc(entry.home) or entry.home.__name__ - else: - current_class = entry.home - except AttributeError: - current_class = test.test.__class__ - - if self.showAll: - if current_class.__name__ != self._last_case: - self.stream.writeln(current_class.__name__) - self._last_case = current_class.__name__ - try: - doc = self.get_doc(current_class) - except (AttributeError, IndexError): - doc = None - if doc: - self.stream.writeln(' ' + doc) - - if not test_name: - if hasattr(test.test, 'shortDescription'): - test_name = test.test.shortDescription() - if not test_name: - test_name = test.test._testMethodName - self.stream.write('\t%s' % str(test_name).ljust(60)) - self.stream.flush() - - -class NovaTestRunner(core.TextTestRunner): - def __init__(self, *args, **kwargs): - self.show_elapsed = kwargs.pop('show_elapsed') - self.known_bugs = kwargs.pop('known_bugs', {}) - self.__result = None - self.__finished = False - self.__start_time = None - super(NovaTestRunner, self).__init__(*args, **kwargs) - - def _makeResult(self): - self.__result = NovaTestResult( - self.stream, - self.descriptions, - self.verbosity, - self.config, - show_elapsed=self.show_elapsed, - known_bugs=self.known_bugs) - self.__start_time = time.time() - return self.__result - - def _writeSlowTests(self, result_): - # Pare out 'fast' tests - slow_tests = [item for item in result_.slow_tests - if get_elapsed_time_color(item[0]) != 'green'] - if slow_tests: - slow_total_time = sum(item[0] for item in slow_tests) - self.stream.writeln("Slowest %i tests took %.2f secs:" - % (len(slow_tests), slow_total_time)) - for elapsed_time, test in sorted(slow_tests, reverse=True): - time_str = "%.2f" % elapsed_time - self.stream.writeln(" %s %s" % (time_str.ljust(10), test)) - - def on_exit(self): - if self.__result is None: - print("Exiting before tests even started.") - else: - if not self.__finished: - msg = "Tests aborted, trying to print available results..." - print(msg) - stop_time = time.time() - self.__result.printErrors() - self.__result.printSummary(self.__start_time, stop_time) - self.config.plugins.finalize(self.__result) - if self.show_elapsed: - self._writeSlowTests(self.__result) - - def run(self, test): - result_ = super(NovaTestRunner, self).run(test) - if self.show_elapsed: - self._writeSlowTests(result_) - self.__finished = True - return result_ - - -if __name__ == '__main__': - logging.setup() - # If any argument looks like a test name but doesn't have "nova.tests" in - # front of it, automatically add that so we don't have to type as much - show_elapsed = True - argv = [] - test_fixture = os.getenv("UNITTEST_FIXTURE", "trove") - for x in sys.argv: - if x.startswith('test_'): - argv.append('%s.tests.%s' % (test_fixture, x)) - elif x.startswith('--hide-elapsed'): - show_elapsed = False - else: - argv.append(x) - - testdir = os.path.abspath(os.path.join(test_fixture, "tests")) - c = config.Config(stream=sys.stdout, - env=os.environ, - verbosity=3, - workingDir=testdir, - plugins=core.DefaultPluginManager()) - - runner = NovaTestRunner(stream=c.stream, - verbosity=c.verbosity, - config=c, - show_elapsed=show_elapsed) - sys.exit(not core.run(config=c, testRunner=runner, argv=argv)) diff --git a/tests/integration/tests/dns/__init__.py b/tests/integration/tests/dns/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/integration/tests/dns/__init__.py +++ /dev/null diff --git a/tests/integration/tests/dns/check_domain.py b/tests/integration/tests/dns/check_domain.py deleted file mode 100644 index 61e5f63..0000000 --- a/tests/integration/tests/dns/check_domain.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# 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. -"""Checks that the domain specified in the flag file exists and is valid. - -If you define the environment variable ADD_DOMAINS=True when running the tests, -they will create the domain if its not found (see below for details). - -""" -import os -import time -import unittest -from proboscis import test -from proboscis import before_class -from proboscis.asserts import assert_equal -from proboscis.asserts import assert_not_equal -from proboscis.decorators import expect_exception -from proboscis.decorators import time_out - -from trove.tests.config import CONFIG - -WHITE_BOX = CONFIG.white_box -RUN_DNS = CONFIG.values.get("trove_dns_support", False) - -if WHITE_BOX: - from nova import utils - from nova import flags - import rsdns - from trove.dns.rsdns.driver import create_client_with_flag_values - from trove.dns.driver import DnsEntry - from trove.dns.rsdns.driver import RsDnsInstanceEntryFactory - from trove.dns.rsdns.driver import RsDnsDriver - from trove.dns.rsdns.driver import RsDnsZone - from trove.utils import poll_until - FLAGS = flags.FLAGS - TEST_CONTENT = "126.1.1.1" - TEST_NAME = "hiwassup.%s" % FLAGS.dns_domain_name - DNS_DOMAIN_ID = None - - -@test(groups=["rsdns.domains", "rsdns.show_entries"], - enabled=WHITE_BOX and RUN_DNS) -class ClientTests(object): - - @before_class - def increase_logging(self): - import httplib2 - httplib2.debuglevel = 1 - - @test - def can_auth(self): - self.client = create_client_with_flag_values() - self.client.authenticate() - - @test(depends_on=[can_auth]) - def list_domains(self): - domains = self.client.domains.list() - print(domains) - - -@test(groups=["rsdns.domains"], depends_on=[ClientTests], - enabled=WHITE_BOX and RUN_DNS) -class RsDnsDriverTests(object): - """Tests the RS DNS Driver.""" - - def create_domain_if_needed(self): - """Adds the domain specified in the flags.""" - print("Creating domain %s" % self.driver.default_dns_zone.name) - future = self.driver.dns_client.domains.create( - self.driver.default_dns_zone.name) - while not future.ready: - time.sleep(2) - print("Got something: %s" % future.resource) - with open('/home/vagrant/dns_resource.txt', 'w') as f: - f.write('%r\n' % future.result[0].id) - global DNS_DOMAIN_ID - DNS_DOMAIN_ID = future.result[0].id - print("The domain should have been created with id=%s" % DNS_DOMAIN_ID) - - @test - @time_out(2 * 60) - def ensure_domain_specified_in_flags_exists(self): - """Make sure the domain in the FLAGS exists.""" - self.driver = RsDnsDriver(raise_if_zone_missing=False) - assert_not_equal(None, self.driver.default_dns_zone) - - def zone_found(): - zones = self.driver.get_dns_zones() - print("Retrieving zones.") - for zone in zones: - print("zone %s" % zone) - if zone.name == self.driver.default_dns_zone.name: - self.driver.default_dns_zone.id = zone.id - global DNS_DOMAIN_ID - DNS_DOMAIN_ID = zone.id - return True - return False - if zone_found(): - return - self.create_domain_if_needed() - for i in range(5): - if zone_found(): - return - self.fail("""Could not find default dns zone. - This happens when they clear the staging DNS service of data. - To fix it, manually run the tests as follows: - $ ADD_DOMAINS=True python int_tests.py - and if all goes well the tests will create a new domain - record.""") - - @test(depends_on=[ensure_domain_specified_in_flags_exists], - enabled=WHITE_BOX and FLAGS.dns_domain_name != "dbaas.rackspace.com") - def delete_all_entries(self): - """Deletes all entries under the default domain.""" - list = self.driver.get_entries() - for entry in list: - if entry.type == "A": - self.driver.delete_entry(name=entry.name, type=entry.type, - dns_zone=entry.dns_zone) - # It takes awhile for them to be deleted. - poll_until(lambda: self.driver.get_entries_by_name(TEST_NAME), - lambda list: len(list) == 0, - sleep_time=4, time_out=60) - - @test(depends_on=[delete_all_entries]) - def create_test_entry(self): - fullname = TEST_NAME - entry = DnsEntry(name=fullname, content=TEST_CONTENT, type="A", - ttl=3600) - self.driver.create_entry(entry) - list = None - for i in range(500): - list = self.driver.get_entries_by_name(name=fullname) - if len(list) > 0: - break - time.sleep(1) - print("This is the list: %r" % list) - assert_equal(1, len(list)) - list2 = self.driver.get_entries_by_content(content=TEST_CONTENT) - assert_equal(1, len(list2)) - - @test(depends_on=[delete_all_entries]) - def create_test_rsdns_entry(self): - """Create an entry using the RsDnsInstanceEntryFactory.""" - instance = {'uuid': '000136c0-effa-4711-a747-a5b9fbfcb3bd', 'id': '10'} - ip = "10.100.2.7" - factory = RsDnsInstanceEntryFactory(dns_domain_id=DNS_DOMAIN_ID) - entry = factory.create_entry(instance) - entry.content = ip - self.driver.create_entry(entry) - entries = self.driver.get_entries_by_name(name=entry.name) - assert_equal(1, len(entries)) - assert_equal(ip, entries[0].content) - assert_equal(FLAGS.dns_ttl, entries[0].ttl) - - @test(depends_on=[create_test_entry]) - def delete_test_entry(self): - fullname = TEST_NAME - self.driver.delete_entry(fullname, "A") - # It takes awhile for them to be deleted. - poll_until(lambda: self.driver.get_entries_by_name(TEST_NAME), - lambda list: len(list) == 0, - sleep_time=2, time_out=60) diff --git a/tests/integration/tests/dns/concurrency.py b/tests/integration/tests/dns/concurrency.py deleted file mode 100644 index 4fe460b..0000000 --- a/tests/integration/tests/dns/concurrency.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# 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. -""" -This test recreates an issue we had with eventlet. In the logs, we'd see that -the JSON response was malformed; instead of JSON, it contained the following -string: -Second simultaneous read on fileno 5 detected. Unless you really know what -you're doing, make sure that only one greenthread can read any particular -socket. Consider using a pools.Pool. If you do know what you're doing and want -to disable this error, call -eventlet.debug.hub_multiple_reader_prevention(False) - -It is perhaps the most helpful error message ever created. - -The root issue was that a subclass of httplib2.Http was created at program -started and used in all threads. - -Using the old (broken) RsDNS client code this test recreates the greatest error -message ever. -""" - -try: - import eventlet - CAN_USE_EVENTLET = True -except ImportError: - CAN_USE_EVENTLET = False -import uuid - -from proboscis import before_class -from proboscis import test -from proboscis.asserts import assert_true - -from trove.tests.config import CONFIG - -WHITE_BOX = CONFIG.white_box -RUN_DNS = CONFIG.values.get("trove_dns_support", False) - - -if CONFIG.white_box: - from trove.dns.rsdns.driver import RsDnsInstanceEntryFactory - from nova import flags - from nova import utils - FLAGS = flags.FLAGS - - -@test(groups=["rsdns.eventlet"], enabled=CAN_USE_EVENTLET) -class RsdnsEventletTests(object): - """Makes sure the RSDNS client can be used from multiple green threads.""" - - def assert_record_created(self, index): - msg = "Record %d wasn't created!" % index - assert_true(index in self.new_records, msg) - - @before_class(enabled=WHITE_BOX and RUN_DNS) - def create_driver(self): - """Creates the DNS Driver used in subsequent tests.""" - self.driver = utils.import_object(FLAGS.dns_driver) - self.entry_factory = RsDnsInstanceEntryFactory() - self.test_uuid = uuid.uuid4().hex - self.new_records = {} - - def make_record(self, index): - """Creates a record with the form 'eventlet-%s-%d'.""" - uuid = "eventlet-%s-%d" % (self.test_uuid, index) - instance = {'uuid': uuid} - entry = self.entry_factory.create_entry(instance) - entry.name = uuid + "." + self.entry_factory.default_dns_zone.name - entry.content = "123.123.123.123" - self.driver.create_entry(entry) - self.new_records[index] = True - - @test(enabled=WHITE_BOX and RUN_DNS) - def use_dns_from_a_single_thread(self): - """Add DNS records one at a time.""" - self.new_records = {} - for index in range(-1, -5, -1): - self.make_record(index) - self.assert_record_created(index) - - @test(enabled=WHITE_BOX and RUN_DNS) - def use_dns_from_multiple_greenthreads(self): - """Add multiple DNS records at once.""" - self.new_records = {} - - def make_record(index): - def __cb(): - self.make_record(index) - self.assert_record_created(index) - return index - return __cb - - pile = eventlet.GreenPile() - indices = range(1, 4) - for index in indices: - pile.spawn(make_record(index)) - - list(pile) # Wait for them to finish - for index in indices: - self.assert_record_created(index) diff --git a/tests/integration/tests/dns/conversion.py b/tests/integration/tests/dns/conversion.py deleted file mode 100644 index 2af3b95..0000000 --- a/tests/integration/tests/dns/conversion.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# 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. -"""Tests classes which convert RS style-entries to Nova DNS entries.""" - -import hashlib -import re -import unittest -from proboscis import test -from proboscis.decorators import expect_exception - -from trove.tests.config import CONFIG - - -if CONFIG.white_box: - from nova import flags - from rsdns.client.records import Record - from trove.dns.rsdns.driver import EntryToRecordConverter - from trove.dns.rsdns.driver import RsDnsInstanceEntryFactory - from trove.dns.rsdns.driver import RsDnsZone - FLAGS = flags.FLAGS - driver = None - DEFAULT_ZONE = RsDnsZone(1, "dbaas.rackspace.org") - TEST_CONTENT = "126.1.1.1" - TEST_NAME = "hiwassup.dbaas.rackspace.org" - - -@test(groups=["unit", "rsdns.conversion"], - enabled=CONFIG.white_box) -class ConvertingNovaEntryNamesToRecordNames(unittest.TestCase): - - def setUp(self): - self.converter = EntryToRecordConverter(DEFAULT_ZONE) - self.fake_zone = RsDnsZone(id=5, name="blah.org") - - def test_normal_name(self): - long_name = self.converter.name_to_long_name("hi", self.fake_zone) - self.assertEqual("hi.blah.org", long_name) - - def test_short_name(self): - long_name = self.converter.name_to_long_name("", self.fake_zone) - self.assertEqual("", long_name) - - def test_long_name(self): - long_name = self.converter.name_to_long_name("blah.org.", - self.fake_zone) - self.assertEqual("blah.org..blah.org", long_name) - - -@test(groups=["unit", "rsdns.conversion"], - enabled=CONFIG.white_box) -class ConvertingRecordsToEntries(unittest.TestCase): - - def setUp(self): - self.converter = EntryToRecordConverter(DEFAULT_ZONE) - self.fake_zone = RsDnsZone(id=5, name="blah.org") - - def test_normal_name(self): - record = Record(None, {"id": 5, "name": "hi.blah.org", - "data": "stacker.com blah@blah 13452378", - "ttl": 5, - "type": "SOA"}) - entry = self.converter.record_to_entry(record=record, - dns_zone=self.fake_zone) - self.assertEqual("stacker.com blah@blah 13452378", entry.content) - self.assertEqual("hi.blah.org", entry.name) - self.assertEqual("5", str(entry.ttl)) - self.assertEqual("SOA", entry.type) - - -@test(groups=["rsdns.conversion"], - enabled=CONFIG.white_box) -class WhenCreatingAnEntryForAnInstance(unittest.TestCase): - # This isn't a unit test because RsDnsInstanceEntryFactory connects to the - # service. - - def setUp(self): - self.creator = RsDnsInstanceEntryFactory() - - def test_should_concatanate_strings(self): - instance = {'id': '56', - 'uuid': '000136c0-effa-4711-a747-a5b9fbfcb3bd'} - entry = self.creator.create_entry(instance) - expected_name = "%s.%s" % (hashlib.sha1(instance['uuid']).hexdigest(), - FLAGS.dns_domain_name) - self.assertEqual(expected_name, entry.name, - msg="Entry name should match - %s" % entry.name) - self.assertIsNone(entry.content) - self.assertEqual("A", entry.type) - self.assertEqual(FLAGS.dns_ttl, entry.ttl) - self.assertIsNone(entry.priority) - self.assertEqual(FLAGS.dns_domain_name, entry.dns_zone.name) - if not entry.dns_zone.id: - self.fail(msg="DNS Zone Id should not be empty") diff --git a/tests/integration/tests/dns/dns.py b/tests/integration/tests/dns/dns.py deleted file mode 100644 index 3734ad5..0000000 --- a/tests/integration/tests/dns/dns.py +++ /dev/null @@ -1,104 +0,0 @@ - -import unittest - -from proboscis import test - -from trove.tests.api.instances import instance_info -from trove.tests.api.instances import GROUP_START as INSTANCE_START -from trove.tests.api.instances import GROUP_TEST -from trove.tests.api.instances import GROUP_STOP as INSTANCE_STOP -from trove.tests.config import CONFIG -from trove.common.utils import import_object -from trove.common.utils import poll_until - -WHITE_BOX = CONFIG.white_box - -if WHITE_BOX: - # TODO(tim.simpson): Restore this once white box functionality can be - # added back to this test module. - pass - # import rsdns - # from nova import flags - # from nova import utils - - # from trove import exception - # from trove.utils import poll_until - - # FLAGS = flags.FLAGS - -dns_driver = None - -GROUP = "dbaas.guest.dns" - - -@test(groups=[GROUP, GROUP_TEST]) -class Setup(unittest.TestCase): - """Creates the DNS Driver and entry factory used in subsequent tests.""" - - def test_create_rs_dns_driver(self): - global dns_driver - dns_driver = import_object(FLAGS.dns_driver) - - -def expected_dns_entry(): - """Returns expected DNS entry for this instance. - - :rtype: Instance of :class:`DnsEntry`. - - """ - return create_dns_entry(instance_info.local_id, instance_info.id) - - -@test(depends_on_classes=[Setup], - depends_on_groups=[INSTANCE_START], - groups=[GROUP, GROUP_TEST]) -class WhenInstanceIsCreated(unittest.TestCase): - """Make sure the DNS name was provisioned. - - This class actually calls the DNS driver to confirm the entry that should - exist for the given instance does exist. - - """ - - def test_dns_entry_should_exist(self): - entry = expected_dns_entry() - if entry: - def get_entries(): - return dns_driver.get_entries_by_name(entry.name) - try: - poll_until(get_entries, lambda entries: len(entries) > 0, - sleep_time=2, time_out=60) - except exception.PollTimeOut: - self.fail("Did not find name " + entry.name + \ - " in the entries, which were as follows:" - + str(dns_driver.get_entries())) - - -@test(depends_on_classes=[Setup, WhenInstanceIsCreated], - depends_on_groups=[INSTANCE_STOP], - groups=[GROUP]) -class AfterInstanceIsDestroyed(unittest.TestCase): - """Make sure the DNS name is removed along with an instance. - - Because the compute manager calls the DNS manager with RPC cast, it can - take awhile. So we wait for 30 seconds for it to disappear. - - """ - - def test_dns_entry_exist_should_be_removed_shortly_thereafter(self): - entry = expected_dns_entry() - - if not entry: - return - - def get_entries(): - return dns_driver.get_entries_by_name(entry.name) - - try: - poll_until(get_entries, lambda entries: len(entries) == 0, - sleep_time=2, time_out=60) - except exception.PollTimeOut: - # Manually delete the rogue item - dns_driver.delete_entry(entry.name, entry.type, entry.dns_zone) - self.fail("The DNS entry was never deleted when the instance " - "was destroyed.") diff --git a/tests/integration/tests/initialize.py b/tests/integration/tests/initialize.py deleted file mode 100644 index ddd5aa8..0000000 --- a/tests/integration/tests/initialize.py +++ /dev/null @@ -1,176 +0,0 @@ -# Copyright (c) 2011 OpenStack, LLC. -# 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 unittest -import os -import time -import socket - -from nose.plugins.skip import SkipTest - -from proboscis import test -from proboscis.asserts import fail -from proboscis.decorators import time_out -from tests.util.services import Service -from tests.util.services import start_proc -from tests.util.services import WebService -from trove.tests.config import CONFIG - - -FAKE = CONFIG.fake_mode -START_SERVICES = (not FAKE) and CONFIG.values.get('start_services', False) -START_NOVA_NETWORK = (START_SERVICES and - not CONFIG.values.get('neutron_enabled', - False)) -KEYSTONE_ALL = CONFIG.values.get('keystone_use_combined', True) -USE_NOVA_VOLUME = CONFIG.values.get('use_nova_volume', False) - -dbaas_image = None -instance_name = None -success_statuses = ["build", "active"] - - -def dbaas_url(): - return str(CONFIG.values.get("dbaas_url")) - -def nova_url(): - return str(CONFIG.values.get("nova_client")['url']) - - - -class Daemon(object): - """Starts a daemon.""" - - def __init__(self, alternate_path=None, conf_file_name=None, - extra_cmds=None, service_path_root=None, service_path=None): - # The path to the daemon bin if the other one doesn't work. - self.alternate_path = alternate_path - self.extra_cmds = extra_cmds or [] - # The name of a test config value which points to a conf file. - self.conf_file_name = conf_file_name - # The name of a test config value, which is inserted into the service_path. - self.service_path_root = service_path_root - # The first path to the daemon bin we try. - self.service_path = service_path or "%s" - - def run(self): - # Print out everything to make it - print("Looking for config value %s..." % self.service_path_root) - print(CONFIG.values[self.service_path_root]) - path = self.service_path % CONFIG.values[self.service_path_root] - print("Path = %s" % path) - if not os.path.exists(path): - path = self.alternate_path - if path is None: - fail("Could not find path to %s" % self.service_path_root) - conf_path = str(CONFIG.values[self.conf_file_name]) - cmds = CONFIG.python_cmd_list() + [path] + self.extra_cmds + \ - [conf_path] - print("Running cmds: %s" % cmds) - self.service = Service(cmds) - if not self.service.is_service_alive(): - self.service.start() - -@test(groups=["services.initialize"], - enabled=START_SERVICES and (not KEYSTONE_ALL)) -def start_keystone_all(): - """Starts the Keystone API.""" - Daemon(service_path_root="usr_bin_dir", - service_path="%s/keystone-all", - extra_cmds=['--config-file'], - conf_file_name="keystone_conf").run() - - -@test(groups=["services.initialize", "services.initialize.glance"], - enabled=START_SERVICES) -def start_glance_registry(): - """Starts the Glance Registry.""" - Daemon(alternate_path="/usr/bin/glance-registry", - conf_file_name="glance_reg_conf", - service_path_root="usr_bin_dir", - service_path="%s/glance-registry").run() - - -@test(groups=["services.initialize", "services.initialize.glance"], - depends_on=[start_glance_registry], enabled=START_SERVICES) -def start_glance_api(): - """Starts the Glance API.""" - Daemon(alternate_path="/usr/bin/glance-api", - conf_file_name="glance_reg_conf", - service_path_root="usr_bin_dir", - service_path="%s/glance-api").run() - - -@test(groups=["services.initialize"], depends_on_classes=[start_glance_api], - enabled=START_NOVA_NETWORK) -def start_nova_network(): - """Starts the Nova Network Service.""" - Daemon(service_path_root="usr_bin_dir", - service_path="%s/nova-network", - extra_cmds=['--config-file='], - conf_file_name="nova_conf").run() - - -@test(groups=["services.initialize"], enabled=START_SERVICES) -def start_scheduler(): - """Starts the Scheduler Service.""" - Daemon(service_path_root="usr_bin_dir", - service_path="%s/nova-scheduler", - extra_cmds=['--config-file='], - conf_file_name="nova_conf").run() - - -@test(groups=["services.initialize"], - depends_on_classes=[start_glance_api], - enabled=START_SERVICES) -def start_compute(): - """Starts the Nova Compute Service.""" - Daemon(service_path_root="usr_bin_dir", - service_path="%s/nova-compute", - extra_cmds=['--config-file='], - conf_file_name="nova_conf").run() - - -@test(groups=["services.initialize"], depends_on_classes=[start_scheduler], - enabled=START_SERVICES and USE_NOVA_VOLUME) -def start_volume(): - """Starts the Nova Compute Service.""" - Daemon(service_path_root="usr_bin_dir", - service_path="%s/nova-volume", - extra_cmds=['--config-file='], - conf_file_name="nova_conf").run() - - -@test(groups=["services.initialize"], - depends_on_classes=[start_glance_api, start_nova_network, start_compute, - start_volume], - enabled=START_SERVICES) -def start_nova_api(): - """Starts the Nova Compute Service.""" - Daemon(service_path_root="usr_bin_dir", - service_path="%s/nova-api", - extra_cmds=['--config-file='], - conf_file_name="nova_conf").run() - - -@test(groups=["services.initialize"], - depends_on_classes=[start_nova_api], - enabled=START_SERVICES) -def start_trove_api(): - """Starts the Trove Service.""" - Daemon(service_path_root="usr_bin_dir", - service_path="%s/trove-api", - extra_cmds=['--config-file='], - conf_file_name="trove_conf").run() diff --git a/tests/integration/tests/smoke/__init__.py b/tests/integration/tests/smoke/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/integration/tests/smoke/__init__.py +++ /dev/null diff --git a/tests/integration/tests/smoke/instance.py b/tests/integration/tests/smoke/instance.py deleted file mode 100644 index 3488e5f..0000000 --- a/tests/integration/tests/smoke/instance.py +++ /dev/null @@ -1,103 +0,0 @@ - -from proboscis.asserts import assert_equal -from proboscis import test -from proboscis import before_class - -from trove.common.utils import poll_until -from trove.tests.util import create_client - - -class InstanceGenerator(object): - - def __init__(self, client, status=None, name=None, flavor=None, - account_id=None, created_at=None, databases=None, users=None, - volume_size=None): - self.client = client - self.status = status - self.name = name - self.flavor = flavor - self.account_id = account_id - self.databases = databases - self.users = users - self.volume_size = volume_size - self.id = None - - def create_instance(self): - #make the call to create the instance - instance = self.client.instances.create(self.name, self.flavor, - self.volume_size, self.databases, self.users) - self.client.assert_http_code(200) - - #verify we are in a build state - assert_equal(instance.status, "BUILD") - #pull out the ID - self.id = instance.id - - return instance - - def wait_for_build_to_finish(self): - poll_until(lambda: self.client.instance.get(self.id), - lambda instance: instance.status != "BUILD", - time_out=600) - - def get_active_instance(self): - instance = self.client.instance.get(self.id) - self.client.assert_http_code(200) - - #check the container name - assert_equal(instance.name, self.name) - - #pull out volume info and verify - assert_equal(str(instance.volume_size), str(self.volume_size)) - - #pull out the flavor and verify - assert_equal(str(instance.flavor), str(self.flavor)) - - return instance - - -@test(groups=['smoke', 'positive']) -class CreateInstance(object): - - @before_class - def set_up(self): - client = create_client(is_admin=False) - name = 'test_createInstance_container' - flavor = 1 - volume_size = 1 - db_name = 'test_db' - databases = [ - { - "name": db_name - } - ] - users = [ - { - "name": "lite", - "password": "litepass", - "databases": [{"name": db_name}] - } - ] - - #create the Instance - instance = InstanceGenerator(client, name=self.name, - flavor=flavor, - volume_size=self.volume_size, - databases=databases, users=users) - instance.create_instance() - - #wait for the instance - instance.wait_for_build_to_finish() - - #get the active instance - inst = instance.get_active_instance() - - #list out the databases for our instance and verify the db name - dbs = client.databases.list(inst.id) - client.assert_http_code(200) - - assert_equal(len(dbs), 1) - assert_equal(dbs[0].name, instance.db_name) - - client.instance.delete(inst.id) - client.assert_http_code(202) diff --git a/tests/integration/tests/util/__init__.py b/tests/integration/tests/util/__init__.py deleted file mode 100644 index 671d3c1..0000000 --- a/tests/integration/tests/util/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 OpenStack, LLC. -# 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. diff --git a/tests/integration/tests/util/report.py b/tests/integration/tests/util/report.py deleted file mode 100644 index c3c1007..0000000 --- a/tests/integration/tests/util/report.py +++ /dev/null @@ -1,76 +0,0 @@ -"""Creates a report for the test. -""" - -import os -import shutil -from os import path -from trove.tests.config import CONFIG - -USE_LOCAL_OVZ = CONFIG.use_local_ovz - - -class Reporter(object): - """Saves the logs from a test run.""" - - def __init__(self, root_path): - self.root_path = root_path - if not path.exists(self.root_path): - os.mkdir(self.root_path) - for file in os.listdir(self.root_path): - if file.endswith(".log"): - os.remove(path.join(self.root_path, file)) - - def _find_all_instance_ids(self): - instances = [] - if USE_LOCAL_OVZ: - for dir in os.listdir("/var/lib/vz/private"): - instances.append(dir) - return instances - - def log(self, msg): - with open("%s/report.log" % self.root_path, 'a') as file: - file.write(str(msg) + "\n") - - def _save_syslog(self): - try: - shutil.copyfile("/var/log/syslog", "host-syslog.log") - except (shutil.Error, IOError) as err: - self.log("ERROR logging syslog : %s" % (err)) - - def _update_instance(self, id): - root = "%s/%s" % (self.root_path, id) - - def save_file(path, short_name): - if USE_LOCAL_OVZ: - try: - shutil.copyfile("/var/lib/vz/private/%s/%s" % (id, path), - "%s-%s.log" % (root, short_name)) - except (shutil.Error, IOError) as err: - self.log("ERROR logging %s for instance id %s! : %s" - % (path, id, err)) - else: - #TODO: Can we somehow capture these (maybe SSH to the VM)? - pass - - save_file("/var/log/firstboot", "firstboot") - save_file("/var/log/syslog", "syslog") - save_file("/var/log/nova/guest.log", "nova-guest") - - def _update_instances(self): - for id in self._find_all_instance_ids(): - self._update_instance(id) - - def update(self): - self._update_instances() - self._save_syslog() - - -REPORTER = Reporter(CONFIG.report_directory) - - -def log(msg): - REPORTER.log(msg) - - -def update(): - REPORTER.update() diff --git a/tests/integration/tests/util/rpc.py b/tests/integration/tests/util/rpc.py deleted file mode 100644 index d534ff3..0000000 --- a/tests/integration/tests/util/rpc.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (c) 2012 OpenStack, LLC. -# 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. -""" -Test utility for RPC checks. - -Functionality to check for rabbit here depends on having rabbit running on -the same machine as the tests, so that the rabbitmqctl commands will function. -The functionality is turned on or off by the test config "rabbit_runs_locally". - -""" - -import re - -from trove.tests.config import CONFIG -from services import start_proc - - -if CONFIG.values.get('rabbit_runs_locally', False) == True: - - DIRECT_ACCESS = True - - class Rabbit(object): - - def declare_queue(self, topic): - """Call this to declare a queue from Python.""" - #from trove.rpc.impl_kombu import Connection - from trove.openstack.common.rpc import create_connection - with create_connection() as conn: - consumer = conn.declare_topic_consumer(topic=topic) - - def get_queue_items(self, queue_name): - """Determines if the queue exists and if so the message count. - - If the queue exists the return value is an integer, otherwise - its None. - - Be careful because queue_name is used in a regex and can't have - any unescaped characters. - - """ - proc = start_proc(["/usr/bin/sudo", "rabbitmqctl", "list_queues"], - shell=False) - for line in iter(proc.stdout.readline, ""): - print("LIST QUEUES:" + line) - m = re.search("""%s\s+([0-9]+)""" % queue_name, line) - if m: - return int(m.group(1)) - return None - - @property - def is_alive(self): - """Calls list_queues, should fail.""" - try: - stdout, stderr = self.run(0, "rabbitmqctl", "list_queues") - for lines in stdout, stderr: - for line in lines: - if "no_exists" in line: - return False - return True - except Exception: - return False - - def reset(self): - out, err = self.run(0, "rabbitmqctl", "reset") - print(out) - print(err) - - def run(self, check_exit_code, *cmd): - cmds = ["/usr/bin/sudo"] + list(cmd) - proc = start_proc(cmds) - lines = proc.stdout.readlines() - err_lines = proc.stderr.readlines() - return lines, err_lines - - def start(self): - print("Calling rabbitmqctl start_app") - out = self.run(0, "rabbitmqctl", "start_app") - print(out) - out, err = self.run(0, "rabbitmqctl", "change_password", "guest", - CONFIG.values['rabbit_password']) - print(out) - print(err) - - def stop(self): - print("Calling rabbitmqctl stop_app") - out = self.run(0, "rabbitmqctl", "stop_app") - print(out) - -else: - - DIRECT_ACCESS = False - - class Rabbit(object): - - def __init__(self): - raise RuntimeError("rabbit_runs_locally is set to False in the " - "test config, so this test cannot be run.") - diff --git a/tests/integration/tests/util/services.py b/tests/integration/tests/util/services.py deleted file mode 100644 index b54f92d..0000000 --- a/tests/integration/tests/util/services.py +++ /dev/null @@ -1,280 +0,0 @@ -# Copyright (c) 2011 OpenStack, LLC. -# 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. - -"""Functions to initiate and shut down services needed by the tests.""" - -import os -import re -import subprocess -import time - -from collections import namedtuple -from httplib2 import Http -from nose.plugins.skip import SkipTest - -from proboscis import decorators - - -def _is_web_service_alive(url): - """Does a HTTP GET request to see if the web service is up.""" - client = Http() - try: - resp = client.request(url, 'GET') - return resp != None - except Exception: - return False - - -_running_services = [] - - -def get_running_services(): - """ Returns the list of services which this program has started.""" - return _running_services - - -def start_proc(cmd, shell=False): - """Given a command, starts and returns a process.""" - env = os.environ.copy() - proc = subprocess.Popen( - cmd, - shell=shell, - stdin=subprocess.PIPE, - bufsize=0, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=env - ) - return proc - - -MemoryInfo = namedtuple("MemoryInfo", ['mapped', 'writeable', 'shared']) - - -class Service(object): - """Starts and stops a service under test. - - The methods to start and stop the service will not actually do anything - if they detect the service is already running on this machine. This is - because it may be useful for developers to start the services themselves - some other way. - - """ - - # TODO(tim.simpson): Hard to follow, consider renaming certain attributes. - - def __init__(self, cmd): - """Defines a service to run.""" - if not isinstance(cmd, list): - raise TypeError() - self.cmd = cmd - self.do_not_manage_proc = False - self.proc = None - - def __del__(self): - if self.is_running: - self.stop() - - def ensure_started(self): - """Starts the service if it is not running.""" - if not self.is_running: - self.start() - - def find_proc_id(self): - """Finds and returns the process id.""" - if not self.cmd: - return False - # The cmd[1] signifies the executable python script. It gets invoked - # as python /path/to/executable args, so the entry is - # /path/to/executable - actual_command = self.cmd[1].split("/")[-1] - proc_command = ["/usr/bin/pgrep", "-f", actual_command] - proc = start_proc(proc_command, shell=False) - # this is to make sure there is only one pid returned from the pgrep - has_two_lines = False - pid = None - for line in iter(proc.stdout.readline, ""): - if has_two_lines: - raise RuntimeError("Found PID twice.") - pid = int(line) - has_two_lines = True - return pid - - def get_memory_info(self): - """Returns how much memory the process is using according to pmap.""" - pid = self.find_proc_id() - if not pid: - raise RuntimeError("Can't find PID, so can't get memory.") - proc = start_proc(["/usr/bin/pmap", "-d", str(pid)], - shell=False) - for line in iter(proc.stdout.readline, ""): - m = re.search("""mapped\:\s([0-9]+)K\s+""" - """writeable/private:\s([0-9]+)K\s+""" - """shared:\s+([0-9]+)K""", line) - if m: - return MemoryInfo(int(m.group(1)), int(m.group(2)), - int(m.group(3))) - raise RuntimeError("Memory info not found.") - - def get_fd_count_from_proc_file(self): - """Returns file descriptors according to /proc/<id>/status.""" - pid = self.find_proc_id() - with open("/proc/%d/status" % pid) as status: - for line in status.readlines(): - index = line.find(":") - name = line[:index] - value = line[index + 1:] - if name == "FDSize": - return int(value) - raise RuntimeError("FDSize not found!") - - def get_fd_count(self): - """Returns file descriptors according to /proc/<id>/status.""" - pid = self.find_proc_id() - cmd = "Finding file descriptors..." - print("CMD" + cmd) - proc = start_proc(['ls', '-la', '/proc/%d/fd' % pid], shell=False) - count = -3 - has_two_lines = False - for line in iter(proc.stdout.readline, ""): - print("\t" + line) - count += 1 - if not count: - raise RuntimeError("Could not get file descriptors!") - return count - - - with open("/proc/%d/fd" % pid) as status: - for line in status.readlines(): - index = line.find(":") - name = line[:index] - value = line[index + 1:] - if name == "FDSize": - return int(value) - raise RuntimeError("FDSize not found!") - - def kill_proc(self): - """Kills the process, wherever it may be.""" - pid = self.find_proc_id() - if pid: - start_proc("sudo kill -9 " + str(pid), shell=True) - time.sleep(1) - if self.is_service_alive(): - raise RuntimeError('Cannot kill process, PID=' + - str(self.proc.pid)) - - def is_service_alive(self, proc_name_index=1): - """Searches for the process to see if its alive. - - This function will return true even if this class has not started - the service (searches using ps). - - """ - if not self.cmd: - return False - time.sleep(1) - # The cmd[1] signifies the executable python script. It gets invoked - # as python /path/to/executable args, so the entry is - # /path/to/executable - actual_command = self.cmd[proc_name_index].split("/")[-1] - print actual_command - proc_command = ["/usr/bin/pgrep", "-f", actual_command] - print proc_command - proc = start_proc(proc_command, shell=False) - line = proc.stdout.readline() - print line - # pgrep only returns a pid. if there is no pid, it'll return nothing - return len(line) != 0 - - @property - def is_running(self): - """Returns true if the service has already been started. - - Returns true if this program has started the service or if it - previously detected it had started. The main use of this property - is to know if the service was already begun by this program- - use is_service_alive for a more definitive answer. - - """ - return self.proc or self.do_not_manage_proc - - def restart(self, extra_args): - if self.do_not_manage_proc: - raise RuntimeError("Can't restart proc as the tests don't own it.") - self.stop() - time.sleep(2) - self.start(extra_args=extra_args) - - def start(self, time_out=30, extra_args=None): - """Starts the service if necessary.""" - extra_args = extra_args or [] - if self.is_running: - raise RuntimeError("Process is already running.") - if self.is_service_alive(): - self.do_not_manage_proc = True - return - self.proc = start_proc(self.cmd + extra_args, shell=False) - if not self._wait_for_start(time_out=time_out): - self.stop() - raise RuntimeError("Issued the command successfully but the " - "service (" + str(self.cmd + extra_args) + - ") never seemed to start.") - _running_services.append(self) - - def stop(self): - """Stops the service, but only if this program started it.""" - if self.do_not_manage_proc: - return - if not self.proc: - raise RuntimeError("Process was not started.") - self.proc.terminate() - self.proc.kill() - self.proc.wait() - self.proc.stdin.close() - self.kill_proc() - self.proc = None - global _running_services - _running_services = [svc for svc in _running_services if svc != self] - - def _wait_for_start(self, time_out): - """Waits until time_out (in seconds) for service to appear.""" - give_up_time = time.time() + time_out - while time.time() < give_up_time: - if self.is_service_alive(): - return True - return False - - -class NativeService(Service): - - def is_service_alive(self): - return super(NativeService, self).is_service_alive(proc_name_index=0) - - - -class WebService(Service): - """Starts and stops a web service under test.""" - - def __init__(self, cmd, url): - """Defines a service to run.""" - Service.__init__(self, cmd) - if not isinstance(url, (str, unicode)): - raise TypeError() - self.url = url - self.do_not_manage_proc = self.is_service_alive() - - def is_service_alive(self): - """Searches for the process to see if its alive.""" - return _is_web_service_alive(self.url) diff --git a/tests/integration/tests/volumes/__init__.py b/tests/integration/tests/volumes/__init__.py deleted file mode 100644 index 09c4cfe..0000000 --- a/tests/integration/tests/volumes/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2011 OpenStack, LLC. -# 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. - -""" -:mod:`volumes` -- Tests for volumes. -=================================== -""" - -""""Tests for Volumes.""" - -# Is a set of tests written directly against the VolumeManager and VolumeClient -# classes which doesn't require standing up Nova daemons or anything. -VOLUMES_DRIVER = "trove.volumes.driver" diff --git a/tests/integration/tests/volumes/driver.py b/tests/integration/tests/volumes/driver.py deleted file mode 100644 index 221b2a4..0000000 --- a/tests/integration/tests/volumes/driver.py +++ /dev/null @@ -1,546 +0,0 @@ -# Copyright (c) 2012 OpenStack, LLC. -# 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. - -from numbers import Number -import os -import re -import shutil -import socket -import time -import unittest - -import pexpect - -from proboscis import test -from proboscis.asserts import assert_raises -from proboscis.decorators import expect_exception -from proboscis.decorators import time_out - -from trove.tests.config import CONFIG -from trove.common.utils import poll_until -from trove.tests.util import process -from trove.common.utils import import_class -from tests import initialize - - -WHITE_BOX = CONFIG.white_box -VOLUMES_DRIVER = "trove.volumes.driver" - -if WHITE_BOX: - # TODO(tim.simpson): Restore this once white box functionality can be - # added back to this test module. - pass - # from nova import context - # from nova import exception - # from nova import flags - # from nova import utils - # from trove import exception as trove_exception - # from trove.utils import poll_until - # from trove import volume - # from trove.tests.volume import driver as test_driver - - # FLAGS = flags.FLAGS - - -UUID_PATTERN = re.compile('^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-' - '[0-9a-f]{4}-[0-9a-f]{12}$') - -HUGE_VOLUME = 5000 - - -def is_uuid(text): - return UUID_PATTERN.search(text) is not None - - -class StoryDetails(object): - - def __init__(self): - self.api = volume.API() - self.client = volume.Client() - self.context = context.get_admin_context() - self.device_path = None - self.volume_desc = None - self.volume_id = None - self.volume_name = None - self.volume = None - self.host = socket.gethostname() - self.original_uuid = None - self.original_device_info = None - self.resize_volume_size = 2 - - def get_volume(self): - return self.api.get(self.context, self.volume_id) - - @property - def mount_point(self): - return "%s/%s" % (LOCAL_MOUNT_PATH, self.volume_id) - - @property - def test_mount_file_path(self): - return "%s/test.txt" % self.mount_point - - -story = None -storyFail = None - -LOCAL_MOUNT_PATH = "/testsmnt" - - -class VolumeTest(unittest.TestCase): - """This test tells the story of a volume, from cradle to grave.""" - - def __init__(self, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - - def setUp(self): - global story, storyFail - self.story = story - self.storyFail = storyFail - - def assert_volume_as_expected(self, volume): - self.assertIsInstance(volume["id"], Number) - self.assertEqual(self.story.volume_name, volume["display_name"]) - self.assertEqual(self.story.volume_desc, volume["display_description"]) - self.assertEqual(1, volume["size"]) - self.assertEqual(self.story.context.user_id, volume["user_id"]) - self.assertEqual(self.story.context.project_id, volume["project_id"]) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[initialize.start_volume]) -class SetUp(VolumeTest): - - def test_05_create_story(self): - """Creating 'story' vars used by the rest of these tests.""" - global story, storyFail - story = StoryDetails() - storyFail = StoryDetails() - - @time_out(60) - def test_10_wait_for_topics(self): - """Wait until the volume topic is up before proceeding.""" - topics = ["volume"] - from tests.util.topics import hosts_up - while not all(hosts_up(topic) for topic in topics): - pass - - def test_20_refresh_local_folders(self): - """Delete the local folders used as mount locations if they exist.""" - if os.path.exists(LOCAL_MOUNT_PATH): - #TODO(rnirmal): Also need to remove any existing mounts. - shutil.rmtree(LOCAL_MOUNT_PATH) - os.mkdir(LOCAL_MOUNT_PATH) - # Give some time for the services to startup - time.sleep(10) - - @time_out(60) - def test_30_mgmt_volume_check(self): - """Get the volume information from the mgmt API""" - story_context = self.story.context - device_info = self.story.api.get_storage_device_info(story_context) - print("device_info : %r" % device_info) - self.assertNotEqual(device_info, None, - "the storage device information should exist") - self.story.original_device_info = device_info - - @time_out(60) - def test_31_mgmt_volume_info(self): - """Check the available space against the mgmt API info.""" - story_context = self.story.context - device_info = self.story.api.get_storage_device_info(story_context) - print("device_info : %r" % device_info) - info = {'spaceTotal': device_info['raw_total'], - 'spaceAvail': device_info['raw_avail']} - self._assert_available_space(info) - - def _assert_available_space(self, device_info, fail=False): - """ - Give the SAN device_info(fake or not) and get the asserts for free - """ - print("DEVICE_INFO on SAN : %r" % device_info) - # Calculate the GBs; Divide by 2 for the FLAGS.san_network_raid_factor - gbs = 1.0 / 1024 / 1024 / 1024 / 2 - total = int(device_info['spaceTotal']) * gbs - free = int(device_info['spaceAvail']) * gbs - used = total - free - usable = total * (FLAGS.san_max_provision_percent * 0.01) - real_free = float(int(usable - used)) - - print("total : %r" % total) - print("free : %r" % free) - print("used : %r" % used) - print("usable : %r" % usable) - print("real_free : %r" % real_free) - - check_space = self.story.api.check_for_available_space - self.assertFalse(check_space(self.story.context, HUGE_VOLUME)) - self.assertFalse(check_space(self.story.context, real_free + 1)) - - if fail: - self.assertFalse(check_space(self.story.context, real_free)) - self.assertFalse(check_space(self.story.context, real_free - 1)) - self.assertFalse(check_space(self.story.context, 1)) - else: - self.assertTrue(check_space(self.story.context, real_free)) - self.assertTrue(check_space(self.story.context, real_free - 1)) - self.assertTrue(check_space(self.story.context, 1)) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[SetUp]) -class AddVolumeFailure(VolumeTest): - - @time_out(60) - def test_add(self): - """ - Make call to FAIL a prov. volume and assert the return value is a - FAILURE. - """ - self.assertIsNone(self.storyFail.volume_id) - name = "TestVolume" - desc = "A volume that was created for testing." - self.storyFail.volume_name = name - self.storyFail.volume_desc = desc - volume = self.storyFail.api.create(self.storyFail.context, - size=HUGE_VOLUME, - snapshot_id=None, name=name, - description=desc) - self.assertEqual(HUGE_VOLUME, volume["size"]) - self.assertTrue("creating", volume["status"]) - self.assertTrue("detached", volume["attach_status"]) - self.storyFail.volume = volume - self.storyFail.volume_id = volume["id"] - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[AddVolumeFailure]) -class AfterVolumeFailureIsAdded(VolumeTest): - """Check that the volume can be retrieved via the API, and setup. - - All we want to see returned is a list-like with an initial string. - - """ - - @time_out(120) - def test_api_get(self): - """Wait until the volume is a FAILURE.""" - volume = poll_until(lambda: self.storyFail.get_volume(), - lambda volume: volume["status"] != "creating") - self.assertEqual(volume["status"], "error") - self.assertTrue(volume["attach_status"], "detached") - - @time_out(60) - def test_mgmt_volume_check(self): - """Get the volume information from the mgmt API""" - info = self.story.api.get_storage_device_info(self.story.context) - print("device_info : %r" % info) - self.assertNotEqual(info, None, - "the storage device information should exist") - self.assertEqual(self.story.original_device_info['raw_total'], - info['raw_total']) - self.assertEqual(self.story.original_device_info['raw_avail'], - info['raw_avail']) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[SetUp]) -class AddVolume(VolumeTest): - - @time_out(60) - def test_add(self): - """Make call to prov. a volume and assert the return value is OK.""" - self.assertIsNone(self.story.volume_id) - name = "TestVolume" - desc = "A volume that was created for testing." - self.story.volume_name = name - self.story.volume_desc = desc - volume = self.story.api.create(self.story.context, size=1, - snapshot_id=None, name=name, - description=desc) - self.assert_volume_as_expected(volume) - self.assertTrue("creating", volume["status"]) - self.assertTrue("detached", volume["attach_status"]) - self.story.volume = volume - self.story.volume_id = volume["id"] - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[AddVolume]) -class AfterVolumeIsAdded(VolumeTest): - """Check that the volume can be retrieved via the API, and setup. - - All we want to see returned is a list-like with an initial string. - - """ - - @time_out(120) - def test_api_get(self): - """Wait until the volume is finished provisioning.""" - volume = poll_until(lambda: self.story.get_volume(), - lambda volume: volume["status"] != "creating") - self.assertEqual(volume["status"], "available") - self.assert_volume_as_expected(volume) - self.assertTrue(volume["attach_status"], "detached") - - @time_out(60) - def test_mgmt_volume_check(self): - """Get the volume information from the mgmt API""" - print("self.story.original_device_info : %r" % - self.story.original_device_info) - info = self.story.api.get_storage_device_info(self.story.context) - print("device_info : %r" % info) - self.assertNotEqual(info, None, - "the storage device information should exist") - self.assertEqual(self.story.original_device_info['raw_total'], - info['raw_total']) - volume_size = int(self.story.volume['size']) * (1024 ** 3) * 2 - print("volume_size: %r" % volume_size) - print("self.story.volume['size']: %r" % self.story.volume['size']) - avail = int(self.story.original_device_info['raw_avail']) - volume_size - print("avail space: %r" % avail) - self.assertEqual(int(info['raw_avail']), avail) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[AfterVolumeIsAdded]) -class SetupVolume(VolumeTest): - - @time_out(60) - def test_assign_volume(self): - """Tell the volume it belongs to this host node.""" - #TODO(tim.simpson) If this is important, could we add a test to - # make sure some kind of exception is thrown if it - # isn't added to certain drivers? - self.assertNotEqual(None, self.story.volume_id) - self.story.api.assign_to_compute(self.story.context, - self.story.volume_id, - self.story.host) - - @time_out(60) - def test_setup_volume(self): - """Set up the volume on this host. AKA discovery.""" - self.assertNotEqual(None, self.story.volume_id) - device = self.story.client._setup_volume(self.story.context, - self.story.volume_id, - self.story.host) - if not isinstance(device, basestring): - self.fail("Expected device to be a string, but instead it was " + - str(type(device)) + ".") - self.story.device_path = device - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[SetupVolume]) -class FormatVolume(VolumeTest): - - @expect_exception(IOError) - @time_out(60) - def test_10_should_raise_IOError_if_format_fails(self): - """ - - Tests that if the driver's _format method fails, its - public format method will perform an assertion properly, discover - it failed, and raise an exception. - - """ - - volume_driver_cls = import_class(FLAGS.volume_driver) - - class BadFormatter(volume_driver_cls): - - def _format(self, device_path): - pass - - bad_client = volume.Client(volume_driver=BadFormatter()) - bad_client._format(self.story.device_path) - - @time_out(60) - def test_20_format(self): - self.assertNotEqual(None, self.story.device_path) - self.story.client._format(self.story.device_path) - - def test_30_check_options(self): - cmd = ("sudo dumpe2fs -h %s 2> /dev/null | " - "awk -F ':' '{ if($1 == \"Reserved block count\") " - "{ rescnt=$2 } } { if($1 == \"Block count\") " - "{ blkcnt=$2 } } END { print (rescnt/blkcnt)*100 }'") - cmd = cmd % self.story.device_path - out, err = process(cmd) - self.assertEqual(float(5), round(float(out)), msg=out) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[FormatVolume]) -class MountVolume(VolumeTest): - - @time_out(60) - def test_mount(self): - self.story.client._mount(self.story.device_path, - self.story.mount_point) - with open(self.story.test_mount_file_path, 'w') as file: - file.write("Yep, it's mounted alright.") - self.assertTrue(os.path.exists(self.story.test_mount_file_path)) - - def test_mount_options(self): - cmd = "mount -l | awk '/%s.*noatime/ { print $1 }'" - cmd %= LOCAL_MOUNT_PATH.replace('/', '') - out, err = process(cmd) - self.assertEqual(os.path.realpath(self.story.device_path), out.strip(), - msg=out) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[MountVolume]) -class ResizeVolume(VolumeTest): - - @time_out(300) - def test_resize(self): - self.story.api.resize(self.story.context, self.story.volume_id, - self.story.resize_volume_size) - - volume = poll_until(lambda: self.story.get_volume(), - lambda volume: volume["status"] == "resized") - self.assertEqual(volume["status"], "resized") - self.assertTrue(volume["attach_status"], "attached") - self.assertTrue(volume['size'], self.story.resize_volume_size) - - @time_out(300) - def test_resizefs_rescan(self): - self.story.client.resize_fs(self.story.context, - self.story.volume_id) - expected = "trove.tests.volume.driver.ISCSITestDriver" - if FLAGS.volume_driver is expected: - size = self.story.resize_volume_size * \ - test_driver.TESTS_VOLUME_SIZE_MULTIPLIER * 1024 * 1024 - else: - size = self.story.resize_volume_size * 1024 * 1024 - out, err = process('sudo blockdev --getsize64 %s' % - os.path.realpath(self.story.device_path)) - if int(out) < (size * 0.8): - self.fail("Size %s is not more or less %s" % (out, size)) - - # Reset the volume status to available - self.story.api.update(self.story.context, self.story.volume_id, - {'status': 'available'}) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[MountVolume]) -class UnmountVolume(VolumeTest): - - @time_out(60) - def test_unmount(self): - self.story.client._unmount(self.story.mount_point) - child = pexpect.spawn("sudo mount %s" % self.story.mount_point) - child.expect("mount: can't find %s in" % self.story.mount_point) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[UnmountVolume]) -class GrabUuid(VolumeTest): - - @time_out(60) - def test_uuid_must_match_pattern(self): - """UUID must be hex chars in the form 8-4-4-4-12.""" - client = self.story.client # volume.Client() - device_path = self.story.device_path # '/dev/sda5' - uuid = client.get_uuid(device_path) - self.story.original_uuid = uuid - self.assertTrue(is_uuid(uuid), "uuid must match regex") - - @time_out(60) - def test_get_invalid_uuid(self): - """DevicePathInvalidForUuid is raised if device_path is wrong.""" - client = self.story.client - device_path = "gdfjghsfjkhggrsyiyerreygghdsghsdfjhf" - self.assertRaises(trove_exception.DevicePathInvalidForUuid, - client.get_uuid, device_path) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[GrabUuid]) -class RemoveVolume(VolumeTest): - - @time_out(60) - def test_remove(self): - self.story.client.remove_volume(self.story.context, - self.story.volume_id, - self.story.host) - self.assertRaises(Exception, - self.story.client._format, self.story.device_path) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[GrabUuid]) -class Initialize(VolumeTest): - - @time_out(300) - def test_10_initialize_will_format(self): - """initialize will setup, format, and store the UUID of a volume""" - self.assertTrue(self.story.get_volume()['uuid'] is None) - self.story.client.initialize(self.story.context, self.story.volume_id, - self.story.host) - volume = self.story.get_volume() - self.assertTrue(is_uuid(volume['uuid']), "uuid must match regex") - self.assertNotEqual(self.story.original_uuid, volume['uuid'], - "Validate our assumption that the volume UUID " - "will change when the volume is formatted.") - self.story.client.remove_volume(self.story.context, - self.story.volume_id, - self.story.host) - - @time_out(60) - def test_20_initialize_the_second_time_will_not_format(self): - """If initialize is called but a UUID exists, it should not format.""" - old_uuid = self.story.get_volume()['uuid'] - self.assertTrue(old_uuid is not None) - - class VolumeClientNoFmt(volume.Client): - - def _format(self, device_path): - raise RuntimeError("_format should not be called!") - - no_fmt_client = VolumeClientNoFmt() - no_fmt_client.initialize(self.story.context, self.story.volume_id, - self.story.host) - self.assertEqual(old_uuid, self.story.get_volume()['uuid'], - "UUID should be the same as no formatting occurred.") - self.story.client.remove_volume(self.story.context, - self.story.volume_id, - self.story.host) - - def test_30_check_device_exists(self): - assert_raises(exception.InvalidDevicePath, self.story.client._format, - self.story.device_path) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[Initialize]) -class DeleteVolume(VolumeTest): - - @time_out(60) - def test_delete(self): - self.story.api.delete(self.story.context, self.story.volume_id) - - -@test(groups=[VOLUMES_DRIVER], depends_on_classes=[DeleteVolume]) -class ConfirmMissing(VolumeTest): - - @time_out(60) - def test_discover_should_fail(self): - try: - self.story.client.driver.discover_volume(self.story.context, - self.story.volume) - self.fail("Expecting an error but did not get one.") - except exception.Error: - pass - except trove_exception.ISCSITargetNotDiscoverable: - pass - - @time_out(60) - def test_get_missing_volume(self): - try: - volume = poll_until(lambda: self.story.api.get(self.story.context, - self.story.volume_id), - lambda volume: volume["status"] != "deleted") - self.assertEqual(volume["deleted"], False) - except exception.VolumeNotFound: - pass diff --git a/tests/integration/tox.ini b/tests/integration/tox.ini deleted file mode 100644 index 8105149..0000000 --- a/tests/integration/tox.ini +++ /dev/null @@ -1,28 +0,0 @@ -# Examples: -# Run tests against Trove running locally in fake mode: -# TROVE_CLIENT_PATH=../some_path tox -e local -- --group=blackbox -[tox] -envlist = py26 - -[testenv] -deps = - coverage - nose - pexpect - proboscis - sqlalchemy - {env:TROVE_PATH} - {env:TROVE_CLIENT_PATH} - -[testenv:py26] - -[testenv:local] -deps = - nose - pexpect - proboscis - sqlalchemy - {env:TROVE_PATH} - {env:TROVE_CLIENT_PATH} -commands = - {envpython} int_tests.py --conf=localhost.test.conf {posargs:DEFAULTS} |