Initial Release

changes/00/800/1
Justin Shepherd 12 years ago committed by Soren Hansen
parent f88913f26e
commit 0d9bbd1471

7
.gitignore vendored

@ -0,0 +1,7 @@
.kong-venv
*.pyc
etc/config.ini
include/swift_objects/swift_small
include/swift_objects/swift_medium
include/swift_objects/swift_large
*.log

@ -0,0 +1,41 @@
::
.-'''-.
' _ \
. / /` '. \ _..._
.'| . | \ ' .' '. .--./)
.' | | ' | '. .-. . /.''\\
< | \ \ / / | ' ' || | | |
| | ____`. ` ..' / | | | | \`-' /
| | \ .' '-...-'` | | | | /("'`
| |/ . | | | | \ '---.
| /\ \ | | | | /'""'.\
| | \ \ | | | | || ||
' \ \ \ | | | | \'. __//
'------' '---' '--' '--' `'---'
kong
====
Kong is a set of tests to be run against a live cluster. Kong sees you when
you're sleeping and knows when you've been bad or good.
Quickstart
----------
You're going to want to make your own config.ini file in the /etc/ directory,
it needs to point at your running cluster.
After that try commands such as::
run_tests.sh --nova
run_tests.sh --glance
run_tests.sh --swift
Additional Info
---------------
There are additional README files in the various subdirectories of this project.

@ -0,0 +1 @@
Copy config.ini.sample to config.ini, and update it to reflect your environment.

@ -0,0 +1,32 @@
[swift]
auth_host = 10.0.0.100
auth_port = 443
auth_prefix = /auth/
auth_ssl = yes
account = system
username = root
password = password
[rabbitmq]
host = 10.0.0.100
user = guest
password =
[glance]
host = 10.0.0.100
apiver = v1.0
port = 9292
[nova]
host = 10.0.0.100
port = 8774
apiver = v1.1
user = admin
key = 24BD8F71-6AD8-439D-B722-7E2E25FD1911
[keystone]
host = 10.0.0.100
port = 5000
apiver = v1.1
user = admin
password = password

@ -0,0 +1,5 @@
## For the swift tests you will need three objects to upload for the test
## examples below are a 512K object, a 500M object, and 1G object
dd if=/dev/zero of=swift_small bs=512 count=1024
dd if=/dev/zero of=swift_medium bs=512 count=1024000
dd if=/dev/zero of=swift_large bs=1024 count=1024000

@ -0,0 +1,300 @@
#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import gettext
import heapq
import os
import unittest
import sys
import time
from nose import config
from nose import result
from nose import core
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 'red'
elif elapsed_time > 0.25:
return 'yellow'
else:
return 'green'
class KongTestResult(result.TextTestResult):
def __init__(self, *args, **kw):
self.show_elapsed = kw.pop('show_elapsed')
result.TextTestResult.__init__(self, *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, tfukushima): 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 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, tfukushima): copied from unittest with edit to add color
def addSuccess(self, test):
unittest.TestResult.addSuccess(self, test)
self._handleElapsedTime(test)
self._writeResult(test, 'OK', 'green', '.', True)
# NOTE(vish, tfukushima): copied from unittest with edit to add color
def addFailure(self, test, err):
unittest.TestResult.addFailure(self, test, err)
self._handleElapsedTime(test)
self._writeResult(test, 'FAIL', 'red', 'F', False)
# NOTE(vish, tfukushima): copied from unittest 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.
"""
self._handleElapsedTime(test)
stream = getattr(self, 'stream', None)
ec, ev, tb = err
try:
exc_info = self._exc_info_to_string(err, test)
except TypeError:
# This is for compatibility with Python 2.3.
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.passwd = 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)
def startTest(self, test):
unittest.TestResult.startTest(self, test)
self.start_time = time.time()
current_case = test.test.__class__.__name__
if self.showAll:
if current_case != self._last_case:
self.stream.writeln(current_case)
self._last_case = current_case
self.stream.write(
' %s' % str(test.test._testMethodName).ljust(60))
self.stream.flush()
class KongTestRunner(core.TextTestRunner):
def __init__(self, *args, **kwargs):
self.show_elapsed = kwargs.pop('show_elapsed')
core.TextTestRunner.__init__(self, *args, **kwargs)
def _makeResult(self):
return KongTestResult(self.stream,
self.descriptions,
self.verbosity,
self.config,
show_elapsed=self.show_elapsed)
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 run(self, test):
result_ = core.TextTestRunner.run(self, test)
if self.show_elapsed:
self._writeSlowTests(result_)
return result_
if __name__ == '__main__':
show_elapsed = True
argv = []
for x in sys.argv:
if x.startswith('test_'):
argv.append('nova.tests.%s' % x)
elif x.startswith('--hide-elapsed'):
show_elapsed = False
else:
argv.append(x)
c = config.Config(stream=sys.stdout,
env=os.environ,
verbosity=3,
plugins=core.DefaultPluginManager())
runner = KongTestRunner(stream=c.stream,
verbosity=c.verbosity,
config=c,
show_elapsed=show_elapsed)
sys.exit(not core.run(config=c, testRunner=runner, argv=argv))

@ -0,0 +1,94 @@
#!/bin/bash
function usage {
echo "Usage: $0 [OPTION]..."
echo "Run the Kong test suite(s)"
echo ""
echo " -V, --virtual-env Always use virtualenv. Install automatically if not present"
echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment"
echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added."
echo " -p, --pep8 Just run pep8"
echo " --nova Run all tests tagged as \"nova\"."
echo " --swift Run all tests tagged as \"swift\"."
echo " --glance Run all tests tagged as \"glance\"."
echo " -h, --help Print this usage message"
echo ""
echo "Note: with no options specified, the script will try to run the tests in a virtual environment,"
echo " If no virtualenv is found, the script will ask if you would like to create one. If you "
echo " prefer to run tests NOT in a virtual environment, simply pass the -N option."
exit
}
function process_option {
case "$1" in
-h|--help) usage;;
-V|--virtual-env) let always_venv=1; let never_venv=0;;
-N|--no-virtual-env) let always_venv=0; let never_venv=1;;
-f|--force) let force=1;;
-p|--pep8) let just_pep8=1;;
--nova) noseargs="$noseargs -a tags=nova";;
--glance) noseargs="$noseargs -a tags=glance";;
--swift) noseargs="$noseargs -a tags=swift";;
*) noseargs="$noseargs $1"
esac
}
venv=.kong-venv
with_venv=tools/with_venv.sh
always_venv=0
never_venv=0
force=0
noseargs=
wrapper=""
just_pep8=0
for arg in "$@"; do
process_option $arg
done
function run_tests {
# Just run the test suites in current environment
${wrapper} $NOSETESTS 2> run_tests.err.log
}
function run_pep8 {
echo "Running pep8 ..."
PEP8_EXCLUDE=vcsversion.y
PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --repeat --show-pep8 --show-source"
PEP8_INCLUDE="tests tools run_tests.py"
${wrapper} pep8 $PEP8_OPTIONS $PEP8_INCLUDE || exit 1
}
NOSETESTS="env python run_tests.py $noseargs"
if [ $never_venv -eq 0 ]
then
# Remove the virtual environment if --force used
if [ $force -eq 1 ]; then
echo "Cleaning virtualenv..."
rm -rf ${venv}
fi
if [ -e ${venv} ]; then
wrapper="${with_venv}"
else
if [ $always_venv -eq 1 ]; then
# Automatically install the virtualenv
env python tools/install_venv.py
wrapper="${with_venv}"
else
echo -e "No virtual environment found...create one? (Y/n) \c"
read use_ve
if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then
# Install the virtualenv and run the test suite in it
env python tools/install_venv.py
wrapper=${with_venv}
fi
fi
fi
fi
if [ $just_pep8 -eq 1 ]; then
run_pep8
exit
fi
run_tests || exit

@ -0,0 +1 @@
You will need to download an image into this directory.. Will also need to update the tests to reference this new image.

@ -0,0 +1,55 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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.
"""
Functional test case to check the status of gepetto and
set information of hosts etc..
"""
import os
import tests
import unittest2
class TestSkipExamples(tests.FunctionalTest):
@tests.skip_test("testing skipping")
def test_absolute_skip(self):
x = 1
@tests.skip_unless(os.getenv("BLAH"),
"Skipping -- Environment variable BLAH does not exist")
def test_skip_unless_env_blah_exists(self):
x = 1
@tests.skip_unless(os.getenv("USER"),
"Not Skipping -- Environment variable USER does not exist")
def test_skip_unless_env_user_exists(self):
x = 1
@tests.skip_if(os.getenv("USER"),
"Skiping -- Environment variable USER exists")
def test_skip_if_env_user_exists(self):
x = 1
@tests.skip_if(os.getenv("BLAH"),
"Not Skipping -- Environment variable BLAH exists")
def test_skip_if_env_blah_exists(self):
x = 1
def test_tags_example(self):
pass
test_tags_example.tags = ['kvm', 'olympus']

@ -0,0 +1,100 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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.
"""Functional test case to check RabbitMQ """
import pika
import tests
from pprint import pprint
#RABBITMQ_HOST = get_config("rabbitmq/host")
#RABBITMQ_USERNAME = get_config("rabbitmq/user")
#RABBITMQ_PASSWORD = get_config("rabbitmq/password")
class TestRabbitMQ(tests.FunctionalTest):
def test_000_ghetto(self):
"""
This sets the host, user, and pass self variables so they
are accessible by all other methods
"""
self.rabbitmq['host'] = self.config['rabbitmq']['host']
self.rabbitmq['user'] = self.config['rabbitmq']['user']
self.rabbitmq['pass'] = self.config['rabbitmq']['password']
test_000_ghetto.tags = ['rabbitmq']
def _cnx(self):
# TODO: Figuring out what's going with creds
# creds = pika.credentials.PlainCredentials(
# self.rabbitmq['user'], self.rabbitmq['pass']
connection = pika.BlockingConnection(pika.ConnectionParameters(
host=self.rabbitmq['host']))
channel = connection.channel()
return (channel, connection)
def test_001_connect(self):
channel, connection = self._cnx()
self.assert_(channel)
connection.close()
test_001_connect.tags = ['rabbitmq']
def test_002_send_receive_msg(self):
unitmsg = 'Hello from unittest'
channel, connection = self._cnx()
channel.queue_declare(queue='u1')
channel.basic_publish(exchange='',
routing_key='u1',
body=unitmsg)
connection.close()
channel, connection = self._cnx()
def callback(ch, method, properties, body):
self.assertEquals(body, unitmsg)
ch.stop_consuming()
channel.basic_consume(callback,
queue='u1',
no_ack=True)
channel.start_consuming()
test_002_send_receive_msg.tags = ['rabbitmq']
def test_003_send_receive_msg_with_persistense(self):
unitmsg = 'Hello from unittest with Persistense'
channel, connection = self._cnx()
channel.queue_declare(queue='u2', durable=True)
prop = pika.BasicProperties(delivery_mode=2)
channel.basic_publish(exchange='',
routing_key='u2',
body=unitmsg,
properties=prop,
)
connection.close()
channel, connection = self._cnx()
channel.queue_declare(queue='u2', durable=True)
def callback(ch, method, properties, body):
self.assertEquals(body, unitmsg)
ch.basic_ack(delivery_tag=method.delivery_tag)
ch.stop_consuming()
channel.basic_qos(prefetch_count=1)
channel.basic_consume(callback,
queue='u2')
channel.start_consuming()
test_003_send_receive_msg_with_persistense.tags = ['rabbitmq']

@ -0,0 +1,195 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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.
"""Functional test case for OpenStack Swift """
import hashlib
import httplib2
import json
import os
import tempfile
import time
import unittest
import urllib
from pprint import pprint
import tests
SMALL_OBJ = "include/swift_objects/swift_small"
MED_OBJ = "include/swift_objects/swift_medium"
LRG_OBJ = "include/swift_objects/swift_large"
class TestSwift(tests.FunctionalTest):
def test_000_auth(self):
if self.swift['auth_ssl'] == "False":
prot = "http://"
else:
prot = "https://"
path = "%s%s:%s%s%s" % (prot, self.swift['auth_host'],
self.swift['auth_port'],
self.swift['auth_prefix'],
self.swift['ver'])
# Uncomment for debugging
# pprint(path)
http = httplib2.Http(disable_ssl_certificate_validation=True)
self.swift['auth_user'] = '%s:%s' % (self.swift['account'],
self.swift['username'])
headers = {'X-Auth-User': '%s' % (self.swift['auth_user']),
'X-Auth-Key': '%s' % (self.swift['password'])}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
self.assertIsNotNone(response['x-auth-token'])
self.assertIsNotNone(response['x-storage-token'])
self.assertIsNotNone(response['x-storage-url'])
for k, v in response.items():
if (k == 'x-auth-token'):
self.swift['x-auth-token'] = v
if (k == 'x-storage-token'):
self.swift['x-storage-token'] = v
# Since we don't have DNS this is a bit of a hack, but works
url = response['x-storage-url'].split('/')
self.swift['storage_url'] = "%s//%s:%s/%s/%s" % (url[0],
self.swift['auth_host'],
self.swift['auth_port'],
url[3],
url[4])
test_000_auth.tags = ['swift']
def test_001_create_container(self):
path = "%s/%s/" % (self.swift['storage_url'], "test_container")
http = httplib2.Http(disable_ssl_certificate_validation=True)
headers = { 'X-Storage-Token': '%s' % (self.swift['x-storage-token'])}
response, content = http.request(path, 'PUT', headers=headers)
self.assertEqual(201, response.status)
test_001_create_container.tags = ['swift']
def test_002_list_containers(self):
http = httplib2.Http(disable_ssl_certificate_validation=True)
headers = {'X-Auth-Token': '%s' % (self.swift['x-auth-token'])}
response, content = http.request(self.swift['storage_url'], 'GET',
headers=headers)
self.assertEqual(200, response.status)
self.assertLessEqual('1', response['x-account-container-count'])
test_002_list_containers.tags = ['swift']
def test_010_create_small_object(self):
md5 = self._md5sum_file(SMALL_OBJ)
path = "%s/%s/%s" % (self.swift['storage_url'],
"test_container",
"swift_small")
http = httplib2.Http(disable_ssl_certificate_validation=True)
headers = {'X-Auth-User': '%s:%s' % (self.swift['account'],
self.swift['username']),
'X-Storage-Token': '%s' % (self.swift['x-storage-token']),
'ETag': '%s' % (md5),
'Content-Length': '%d' % os.path.getsize(SMALL_OBJ),
'Content-Type': 'application/octet-stream'}
upload = open(SMALL_OBJ, "rb")
response, content = http.request(path, 'PUT',
headers=headers,
body=upload)
self.assertEqual(201, response.status)
self.assertIn('201', content)
test_010_create_small_object.tags = ['swift']
def test_011_create_medium_object(self):
md5 = self._md5sum_file(MED_OBJ)
path = "%s/%s/%s" % (self.swift['storage_url'],
"test_container",
"swift_medium")
http = httplib2.Http(disable_ssl_certificate_validation=True)
headers = {'X-Auth-User': '%s:%s' % (self.swift['account'],
self.swift['username']),
'X-Storage-Token': '%s' % (self.swift['x-storage-token']),
'ETag': '%s' % (md5),
'Content-Length': '%d' % (os.path.getsize(MED_OBJ)),
'Content-Type': 'application/octet-stream',
'Content-Encoding': 'gzip'}
upload = ""
for chunk in self._read_in_chunks(MED_OBJ):
upload += chunk
response, content = http.request(path, 'PUT',
headers=headers,
body=upload)
self.assertEqual(201, response.status)
test_011_create_medium_object.tags = ['swift']
def test_013_get_small_object(self):
path = "%s/%s/%s" % (self.swift['storage_url'],
"test_container",
"swift_small")
http = httplib2.Http(disable_ssl_certificate_validation=True)
headers = {'X-Auth-User': '%s:%s' % (self.swift['account'],
self.swift['username']),
'X-Storage-Token': '%s' % (self.swift['x-storage-token'])}
response, content = http.request(path, 'GET',
headers=headers)
self.assertEqual(200, response.status)
self.assertEqual(self._md5sum_file(SMALL_OBJ), response['etag'])
test_013_get_small_object.tags = ['swift']
def test_017_delete_small_object(self):
path = "%s/%s/%s" % (self.swift['storage_url'], "test_container",
"swift_small")
http = httplib2.Http(disable_ssl_certificate_validation=True)
headers = {'X-Auth-User': '%s:%s' % (self.swift['account'],
self.swift['username']),
'X-Storage-Token': '%s' % (
self.swift['x-storage-token'])}
response, content = http.request(path, 'DELETE', headers=headers)
self.assertEqual(204, response.status)
test_017_delete_small_object.tags = ['swift']
def test_018_delete_medium_object(self):
path = "%s/%s/%s" % (self.swift['storage_url'], "test_container",
"swift_medium")
http = httplib2.Http(disable_ssl_certificate_validation=True)
headers = {'X-Auth-User': '%s:%s' % (self.swift['account'],
self.swift['username']),
'X-Storage-Token': '%s' % (
self.swift['x-storage-token'])}
response, content = http.request(path, 'DELETE', headers=headers)
self.assertEqual(204, response.status)
test_018_delete_medium_object.tags = ['swift']
def test_030_check_container_metadata(self):
path = "%s/%s" % (self.swift['storage_url'], "test_container")
http = httplib2.Http(disable_ssl_certificate_validation=True)
headers = {'X-Auth-User': '%s:%s' % (self.swift['account'],
self.swift['username']),
'X-Storage-Token': '%s' % (self.swift['x-storage-token'])}
response, content = http.request(path, 'HEAD', headers=headers)
self.assertEqual(204, response.status)
# pprint(response)
test_030_check_container_metadata.tags = ['swift']
def test_050_delete_container(self):
path = "%s/%s" % (self.swift['storage_url'], "test_container")
http = httplib2.Http(disable_ssl_certificate_validation=True)
headers = {'X-Auth-User': '%s:%s' % (self.swift['account'],
self.swift['username']),
'X-Storage-Token': '%s' % (self.swift['x-storage-token'])}
response, content = http.request(path, 'DELETE', headers=headers)
self.assertEqual(204, response.status)
test_050_delete_container.tags = ['swift']

@ -0,0 +1,193 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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.
"""Validate a working Glance deployment"""
import httplib2
import json
import os
from pprint import pprint
import tests
class TestGlanceAPI(tests.FunctionalTest):
def test_001_connect_to_glance_api(self):
"""
Verifies ability to connect to glance api,
expects glance to return an empty set
"""
if 'apiver' in self.glance:
path = "http://%s:%s/%s/images" % (self.glance['host'],
self.glance['port'], self.glance['apiver'])
else:
path = "http://%s:%s/images" % (self.glance['host'],
self.glance['port'])
http = httplib2.Http()
response, content = http.request(path, 'GET')
self.assertEqual(200, response.status)
data = json.loads(content)
self.assertTrue('images' in data)
test_001_connect_to_glance_api.tags = ['glance']
def test_002_upload_kernel_to_glance(self):
"""
Uploads a test kernal to glance api
"""
kernel = "sample_vm/vmlinuz-2.6.32-23-server"
if 'apiver' in self.glance:
path = "http://%s:%s/%s/images" % (self.glance['host'],
self.glance['port'], self.glance['apiver'])
else:
path = "http://%s:%s/images" % (self.glance['host'],
self.glance['port'])
headers = {'x-image-meta-is-public': 'true',
'x-image-meta-name': 'test-kernel',
'x-image-meta-disk-format': 'aki',
'x-image-meta-container-format': 'aki',
'Content-Length': '%d' % os.path.getsize(kernel),
'Content-Type': 'application/octet-stream'}
image_file = open(kernel, "rb")
http = httplib2.Http()
response, content = http.request(path, 'POST',
headers=headers,
body=image_file)
image_file.close()
self.assertEqual(201, response.status)
data = json.loads(content)
self.glance['kernel_id'] = data['image']['id']
self.assertEqual(data['image']['name'], "test-kernel")
self.assertEqual(data['image']['checksum'], self._md5sum_file(kernel))
test_002_upload_kernel_to_glance.tags = ['glance', 'nova']
def test_003_upload_initrd_to_glance(self):
"""
Uploads a test initrd to glance api
"""
initrd = "sample_vm/initrd.img-2.6.32-23-server"
if 'apiver' in self.glance:
path = "http://%s:%s/%s/images" % (self.glance['host'],
self.glance['port'], self.glance['apiver'])
else:
path = "http://%s:%s/images" % (self.glance['host'],
self.glance['port'])
headers = {'x-image-meta-is-public': 'true',
'x-image-meta-name': 'test-ramdisk',
'x-image-meta-disk-format': 'ari',
'x-image-meta-container-format': 'ari',
'Content-Length': '%d' % os.path.getsize(initrd),
'Content-Type': 'application/octet-stream'}
image_file = open(initrd, "rb")
http = httplib2.Http()
response, content = http.request(path,
'POST',
headers=headers,
body=image_file)
image_file.close()
self.assertEqual(201, response.status)
data = json.loads(content)
self.glance['ramdisk_id'] = data['image']['id']
self.assertEqual(data['image']['name'], "test-ramdisk")
self.assertEqual(data['image']['checksum'], self._md5sum_file(initrd))
test_003_upload_initrd_to_glance.tags = ['glance', 'nova']
def test_004_upload_image_to_glance(self):
"""
Uploads a test image to glance api, and
links it to the initrd and kernel uploaded
earlier
"""
image = "sample_vm/ubuntu-lucid.img"
upload_data = ""
for chunk in self._read_in_chunks(image):
upload_data += chunk
if 'apiver' in self.glance:
path = "http://%s:%s/%s/images" % (self.glance['host'],
self.glance['port'], self.glance['apiver'])
else:
path = "http://%s:%s/images" % (self.glance['host'],
self.glance['port'])
headers = {'x-image-meta-is-public': 'true',
'x-image-meta-name': 'test-image',
'x-image-meta-disk-format': 'ami',
'x-image-meta-container-format': 'ami',
'x-image-meta-property-Kernel_id': '%s' % \
self.glance['kernel_id'],
'x-image-meta-property-Ramdisk_id': '%s' % \
self.glance['ramdisk_id'],
'Content-Length': '%d' % os.path.getsize(image),
'Content-Type': 'application/octet-stream'}
http = httplib2.Http()
response, content = http.request(path, 'POST',
headers=headers,
body=upload_data)
self.assertEqual(201, response.status)
data = json.loads(content)
self.glance['image_id'] = data['image']['id']
self.assertEqual(data['image']['name'], "test-image")
self.assertEqual(data['image']['checksum'], self._md5sum_file(image))
test_004_upload_image_to_glance.tags = ['glance', 'nova']
def test_005_set_image_meta_property(self):
if 'apiver' in self.glance:
path = "http://%s:%s/%s/images/%s" % (self.glance['host'],
self.glance['port'], self.glance['apiver'],
self.glance['image_id'])
else:
path = "http://%s:%s/images/%s" % (self.glance['host'],
self.glance['port'], self.glance['image_id'])
headers = {'X-Image-Meta-Property-Distro': 'Ubuntu',
'X-Image-Meta-Property-Arch': 'x86_64',
'X-Image-Meta-Property-Kernel_id': '%s' % \
self.glance['kernel_id'],
'X-Image-Meta-Property-Ramdisk_id': '%s' % \
self.glance['ramdisk_id']}
http = httplib2.Http()
response, content = http.request(path, 'PUT', headers=headers)
self.assertEqual(response.status, 200)
data = json.loads(content)
self.assertEqual(data['image']['properties']['arch'], "x86_64")
self.assertEqual(data['image']['properties']['distro'], "Ubuntu")
self.assertEqual(data['image']['properties']['kernel_id'],
str(self.glance['kernel_id']))
self.assertEqual(data['image']['properties']['ramdisk_id'],
str(self.glance['ramdisk_id']))
test_005_set_image_meta_property.tags = ['glance']
def test_006_list_image_metadata(self):
image = "sample_vm/ubuntu-lucid.img"
if 'apiver' in self.glance:
path = "http://%s:%s/%s/images/%s" % (self.glance['host'],
self.glance['port'], self.glance['apiver'],
self.glance['image_id'])
else:
path = "http://%s:%s/images/%s" % (self.glance['host'],
self.glance['port'], self.glance['image_id'])
http = httplib2.Http()
response, content = http.request(path, 'HEAD')
self.assertEqual(response.status, 200)
self.assertEqual(response['x-image-meta-name'], "test-image")
self.assertEqual(response['x-image-meta-checksum'],
self._md5sum_file(image))
self.assertEqual(response['x-image-meta-container_format'], "ami")
self.assertEqual(response['x-image-meta-disk_format'], "ami")
self.assertEqual(response['x-image-meta-property-arch'], "x86_64")
self.assertEqual(response['x-image-meta-property-distro'], "Ubuntu")
self.assertEqual(response['x-image-meta-property-kernel_id'],
str(self.glance['kernel_id']))
self.assertEqual(response['x-image-meta-property-ramdisk_id'],
str(self.glance['ramdisk_id']))
test_006_list_image_metadata.tags = ['glance']

@ -0,0 +1,387 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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.
"""Functional test case against the OpenStack Nova API server"""
import json
import os
import tempfile
import unittest
import httplib2
import urllib
import hashlib
import time
import os
from pprint import pprint
import tests
class TestNovaAPI(tests.FunctionalTest):
def build_check(self, id):
self.result = {}
"""
This is intended to check that a server completes the build process
and enters an active state upon creation. Due to reporting errors in
the API we are also testing ping and ssh
"""
count = 0
path = "http://%s:%s/%s/servers/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'],
id)
http = httplib2.Http()
headers = {'X-Auth-User': '%s' % (self.nova['user']),
'X-Auth-Token': '%s' % (self.nova['X-Auth-Token'])}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
data = json.loads(content)
# Get Server status exit when active
while (data['server']['status'] != 'ACTIVE'):
response, content = http.request(path, 'GET', headers=headers)
data = json.loads(content)
time.sleep(5)
count = count + 5
self.result['serverid'] = id
self.result['status'] = data['server']['status']
# Get IP Address of newly created server
if 'addr' in data['server']['addresses']['vmnet'][0]:
netaddr = data['server']['addresses']['vmnet'][0]['addr']
elif 'addr' in data['server']['address']['public'][0]:
netaddr = data['server']['addresses']['public'][0]['addr']
r = "" . join(os.popen('ping -c5 %s' % (netaddr)).readlines())
if r.find('64 bytes') > 1:
self.result['ping'] = True
else:
self.result['ping'] = False
return self.result
def test_002_verify_nova_auth(self):
if 'keystone' in self.config:
path = "http://%s:%s/%s" % (self.keystone['host'],
self.keystone['port'],
self.keystone['apiver'])
headers = {'X-Auth-User': self.keystone['user'],
'X-Auth-Key': self.keystone['pass']}
else:
path = "http://%s:%s/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'])
headers = {'X-Auth-User': self.nova['user'],
'X-Auth-Key': self.nova['key']}
http = httplib2.Http()
response, content = http.request(path, 'HEAD', headers=headers)
self.assertEqual(204, response.status)
self.assertNotEqual(response['x-auth-token'], '')
self.assertNotEqual(response['x-server-management-url'], '')
# Set up Auth Token for all future API interactions
self.nova['X-Auth-Token'] = response['x-auth-token']
test_002_verify_nova_auth.tags = ['nova', 'nova-api']
def test_101_verify_version_selection_default(self):
path = "http://%s:%s/" % (self.nova['host'],
self.nova['port'])
http = httplib2.Http()
headers = {'X-Auth-Token': self.nova['X-Auth-Token']}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
data = json.loads(content)
self.assertEqual(len(data['versions']), 2)
test_101_verify_version_selection_default.tags = ['nova', 'nova-api']
def test_102_verify_version_selection_json(self):
path = "http://%s:%s/.json" % (self.nova['host'],
self.nova['port'])
http = httplib2.Http()
headers = {'X-Auth-Token': self.nova['X-Auth-Token']}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
data = json.loads(content)
self.assertEqual(len(data['versions']), 2)
test_102_verify_version_selection_json.tags = ['nova', 'nova-api']
def test_103_verify_version_selection_xml(self):
path = "http://%s:%s/.xml" % (self.nova['host'],
self.nova['port'])
http = httplib2.Http()
headers = {'X-Auth-Token': self.nova['X-Auth-Token']}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
self.assertTrue('<versions>' in content)
test_103_verify_version_selection_xml.tags = ['nova', 'nova-api']
def test_104_bad_user_bad_key(self):
if 'keystone' in self.config:
path = "http://%s:%s/%s" % (self.keystone['host'],
self.keystone['port'],
self.keystone['apiver'])
else:
path = "http://%s:%s/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'])
http = httplib2.Http()
headers = {'X-Auth-User': 'unknown_auth_user',
'X-Auth-Key': 'unknown_auth_key'}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(response.status, 401)
test_104_bad_user_bad_key.tags = ['nova', 'nova-api']
def test_105_bad_user_good_key(self):
if 'keystone' in self.config:
path = "http://%s:%s/%s" % (self.keystone['host'],
self.keystone['port'],
self.keystone['apiver'])
else:
path = "http://%s:%s/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'])
http = httplib2.Http()
headers = {'X-Auth-User': 'unknown_auth_user',
'X-Auth-Key': self.nova['key']}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(response.status, 401)
test_105_bad_user_good_key.tags = ['nova', 'nova-api']
def test_106_good_user_bad_key(self):
if 'keystone' in self.config:
path = "http://%s:%s/%s" % (self.keystone['host'],
self.keystone['port'],
self.keystone['apiver'])
else:
path = "http://%s:%s/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'])
http = httplib2.Http()
headers = {'X-Auth-User': self.nova['user'],
'X-Auth-Key': 'unknown_auth_key'}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(response.status, 401)
test_106_good_user_bad_key.tags = ['nova', 'nova-api']
def test_107_no_key(self):
if 'keystone' in self.config:
path = "http://%s:%s/%s" % (self.keystone['host'],
self.keystone['port'],
self.keystone['apiver'])
else:
path = "http://%s:%s/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'])
http = httplib2.Http()
headers = {'X-Auth-User': self.nova['user']}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(response.status, 401)
test_107_no_key.tags = ['nova', 'nova-api']
def test_108_bad_token(self):
if 'keystone' in self.config:
path = "http://%s:%s/%s" % (self.keystone['host'],
self.keystone['port'],
self.keystone['apiver'])
else:
path = "http://%s:%s/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'])
http = httplib2.Http()
headers = {'X-Auth-Token': 'unknown_token'}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(response.status, 401)
test_108_bad_token.tags = ['nova', 'nova-api']
def test_109_verify_blank_limits(self):
path = "http://%s:%s/%s/limits" % (self.nova['host'],
self.nova['port'],
self.nova['ver'])
http = httplib2.Http()
headers = {'X-Auth-User': '%s' % (self.nova['user']),
'X-Auth-Token': '%s' % (self.nova['X-Auth-Token'])}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
self.assertNotEqual('{"limits": []}', content)
test_109_verify_blank_limits.tags = ['nova', 'nova-api']
def test_110_list_flavors_v1_1(self):
path = "http://%s:%s/%s/flavors" % (self.nova['host'],
self.nova['port'],
self.nova['ver'])
http = httplib2.Http()
headers = {'X-Auth-User': '%s' % (self.nova['user']),
'X-Auth-Token': '%s' % (self.nova['X-Auth-Token'])}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
self.assertNotEqual('{"flavors": []}', content)
test_110_list_flavors_v1_1.tags = ['nova', 'nova-api']
def test_111_verify_kernel_active_v1_1(self):
# for testing purposes change self.glance['kernel_id'] to an active
# kernel image allow for skipping glance tests
if not 'kernel_id' in self.glance:
self.glance['kernel_id'] = "61"
path = "http://%s:%s/%s/images/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'],
self.glance['kernel_id'])
http = httplib2.Http()
headers = {'X-Auth-User': '%s' % (self.nova['user']),
'X-Auth-Token': '%s' % (self.nova['X-Auth-Token'])}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
data = json.loads(content)
self.assertEqual(data['image']['status'], 'ACTIVE')
test_111_verify_kernel_active_v1_1.tags = ['nova']
def test_112_verify_ramdisk_active_v1_1(self):
# for testing purposes change self.glance['ramdisk_id'] to an active
# ramdisk image, allows you to skip glance tests
if not 'ramdisk_id' in self.glance:
self.glance['ramdisk_id'] = "62"
path = "http://%s:%s/%s/images/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'],
self.glance['ramdisk_id'])
http = httplib2.Http()
headers = {'X-Auth-User': '%s' % (self.nova['user']),
'X-Auth-Token': '%s' % (self.nova['X-Auth-Token'])}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
data = json.loads(content)
self.assertEqual(data['image']['status'], 'ACTIVE')
test_112_verify_ramdisk_active_v1_1.tags = ['nova']
def test_113_verify_image_active_v1_1(self):
# for testing purposes change self.glance['image_id'] to an active
# image id allows for skipping glance tests
if not 'image_id' in self.glance:
self.glance['image_id'] = "63"
path = "http://%s:%s/%s/images/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'],
self.glance['image_id'])
http = httplib2.Http()
headers = {'X-Auth-User': '%s' % (self.nova['user']),
'X-Auth-Token': '%s' % (self.nova['X-Auth-Token'])}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
data = json.loads(content)
self.assertEqual(data['image']['status'], 'ACTIVE')
test_113_verify_image_active_v1_1.tags = ['nova']
def test_200_create_server(self):
path = "http://%s:%s/%s/servers" % (self.nova['host'],
self.nova['port'],
self.nova['ver'])
http = httplib2.Http()
headers = {'X-Auth-User': '%s' % (self.nova['user']),
'X-Auth-Token': '%s' % (self.nova['X-Auth-Token']),
'Content-Type': 'application/json'}
# Change imageRef to self.glance['image_id']
json_str = {"server":
{
"name": "testing server creation",
"flavorRef": "http://%s:%s/%s/flavors/2" % (self.nova['host'],
self.nova['port'],
self.nova['ver']),
"imageRef": self.glance['image_id']
# "imageRef": "http://%s:%s/%s/images/%s" % (self.nova['host'],
# self.nova['port'],
# self.nova['ver'],
# self.glance['image_id'])
}
}
data = json.dumps(json_str)
response, content = http.request(path, 'POST', headers=headers,
body=data)
json_return = json.loads(content)
self.assertEqual(200, response.status)
self.assertEqual(json_return['server']['status'], "BUILD")
self.nova['single_server_id'] = json_return['server']['id']
time.sleep(5)
build_result = self.build_check(self.nova['single_server_id'])
self.assertEqual(build_result['status'], "ACTIVE")
self.assertEqual(build_result['ping'], True)
test_200_create_server.tags = ['nova']
def test_201_get_server_details(self):
path = "http://%s:%s/%s/servers/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'],
self.nova['single_server_id'])
http = httplib2.Http()
headers = {'X-Auth-User': '%s' % (self.nova['user']),
'X-Auth-Token': '%s' % (self.nova['X-Auth-Token'])}
response, content = http.request(path, 'GET', headers=headers)
self.assertEqual(200, response.status)
test_201_get_server_details.tags = ['nova']
# MOVING TO 999 because it can kill the API
# Uncomment next line for testing
# def create_multi(self):
def test_999_create_multiple(self):
self.nova['multi_server'] = {}
path = "http://%s:%s/%s/servers" % (self.nova['host'],
self.nova['port'],
self.nova[<