Initial Release

This commit is contained in:
Justin Shepherd 2011-08-11 12:57:44 -05:00 committed by Soren Hansen
parent f88913f26e
commit 0d9bbd1471
18 changed files with 1815 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -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

41
README.rst Normal file
View File

@ -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.

1
etc/README.txt Normal file
View File

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

32
etc/config.ini.sample Normal file
View File

@ -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

View File

@ -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

300
run_tests.py Normal file
View File

@ -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))

94
run_tests.sh Executable file
View File

@ -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

1
sample_vm/README.txt Normal file
View File

@ -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.

View File

@ -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']

100
tests/994_test_rabbitmq.py Normal file
View File

@ -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']

195
tests/995_test_swift.py Normal file
View File

@ -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']

193
tests/996_test_glance.py Normal file
View File

@ -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']

387
tests/998_test_nova.py Normal file
View File

@ -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['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'}
for i in range(1, 10):
# Change imageRef to self.glance['image_id']
json_str = {"server":
{
"name": "test %s" % (i),
"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['multi_server']["test %s" % (i)] = \
json_return['server']['id']
time.sleep(30)
for k, v in self.nova['multi_server'].iteritems():
build_result = self.build_check(v)
self.assertEqual(build_result['ping'], True)
test_999_create_multiple.tags = ['nova']

97
tests/999_test_cleanup.py Normal file
View File

@ -0,0 +1,97 @@
# 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 that utilizes cURL against the API server"""
import json
import os
import tempfile
import unittest
import httplib2
import urllib
import hashlib
from pprint import pprint
import tests
class TestCleanUp(tests.FunctionalTest):
def test_995_delete_server(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, 'DELETE', headers=headers)
self.assertEqual(204, response.status)
test_995_delete_server.tags = ['nova']
def test_996_delete_multi_server(self):
print "Deleting %s instances." % (len(self.nova['multi_server']))
for k, v in self.nova['multi_server'].iteritems():
path = "http://%s:%s/%s/servers/%s" % (self.nova['host'],
self.nova['port'],
self.nova['ver'],
v)
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, 'DELETE', headers=headers)
self.assertEqual(204, response.status)
test_996_delete_multi_server.tags = ['nova']
def test_997_delete_kernel_from_glance(self):
if 'apiver' in self.glance:
path = "http://%s:%s/%s/images/%s" % (self.glance['host'],
self.glance['port'], self.glance['apiver'],
self.glance['kernel_id'])
else:
path = "http://%s:%s/images/%s" % (self.glance['host'],
self.glance['port'], self.glance['kernel_id'])
http = httplib2.Http()
response, content = http.request(path, 'DELETE')
self.assertEqual(200, response.status)
test_997_delete_kernel_from_glance.tags = ['glance', 'nova']
def test_998_delete_initrd_from_glance(self):
if 'apiver' in self.glance:
path = "http://%s:%s/%s/images/%s" % (self.glance['host'],
self.glance['port'], self.glance['apiver'],
self.glance['ramdisk_id'])
else:
path = "http://%s:%s/images/%s" % (self.glance['host'],
self.glance['port'], self.glance['ramdisk_id'])
http = httplib2.Http()
response, content = http.request(path, 'DELETE')
self.assertEqual(200, response.status)
test_998_delete_initrd_from_glance.tags = ['glance', 'nova']
def test_999_delete_image_from_glance(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'])
http = httplib2.Http()
response, content = http.request(path, 'DELETE')
self.assertEqual(200, response.status)
test_999_delete_image_from_glance.tags = ['glance', 'nova']

159
tests/__init__.py Normal file
View File

@ -0,0 +1,159 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010-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 ConfigParser
from hashlib import md5
import nose.plugins.skip
import os
import unittest2
from xmlrpclib import Server
NOVA_DATA = {}
GLANCE_DATA = {}
SWIFT_DATA = {}
RABBITMQ_DATA = {}
CONFIG_DATA = {}
KEYSTONE_DATA = {}
class skip_test(object):
"""Decorator that skips a test."""
def __init__(self, msg):
self.message = msg
def __call__(self, func):
def _skipper(*args, **kw):
"""Wrapped skipper function."""
raise nose.SkipTest(self.message)
_skipper.__name__ = func.__name__
_skipper.__doc__ = func.__doc__
return _skipper
class skip_if(object):
"""Decorator that skips a test."""
def __init__(self, condition, msg):
self.condition = condition
self.message = msg
def __call__(self, func):
def _skipper(*args, **kw):
"""Wrapped skipper function."""
if self.condition:
raise nose.SkipTest(self.message)
func(*args, **kw)
_skipper.__name__ = func.__name__
_skipper.__doc__ = func.__doc__
return _skipper
class skip_unless(object):
"""Decorator that skips a test."""
def __init__(self, condition, msg):
self.condition = condition
self.message = msg
def __call__(self, func):
def _skipper(*args, **kw):
"""Wrapped skipper function."""
if not self.condition:
raise nose.SkipTest(self.message)
func(*args, **kw)
_skipper.__name__ = func.__name__
_skipper.__doc__ = func.__doc__
return _skipper
class FunctionalTest(unittest2.TestCase):
def setUp(self):
global GLANCE_DATA, NOVA_DATA, SWIFT_DATA, RABBITMQ_DATA, KEYSTONE_DATA, CONFIG_DATA
# Define config dict
self.config = CONFIG_DATA
# Define service specific dicts
self.glance = GLANCE_DATA
self.nova = NOVA_DATA
self.swift = SWIFT_DATA
self.rabbitmq = RABBITMQ_DATA
self.keystone = KEYSTONE_DATA
self._parse_defaults_file()
# Swift Setup
if 'swift' in self.config:
self.swift['auth_host'] = self.config['swift']['auth_host']
self.swift['auth_port'] = self.config['swift']['auth_port']
self.swift['auth_prefix'] = self.config['swift']['auth_prefix']
self.swift['auth_ssl'] = self.config['swift']['auth_ssl']
self.swift['account'] = self.config['swift']['account']
self.swift['username'] = self.config['swift']['username']
self.swift['password'] = self.config['swift']['password']
self.swift['ver'] = 'v1.0' # need to find a better way to get this.
# Glance Setup
self.glance['host'] = self.config['glance']['host']
self.glance['port'] = self.config['glance']['port']
if 'apiver' in self.config['glance']:
self.glance['apiver'] = self.config['glance']['apiver']
if 'nova' in self.config:
self.nova['host'] = self.config['nova']['host']
self.nova['port'] = self.config['nova']['port']
self.nova['ver'] = self.config['nova']['apiver']
self.nova['user'] = self.config['nova']['user']
self.nova['key'] = self.config['nova']['key']
if 'keystone' in self.config:
self.keystone['host'] = self.config['keystone']['host']
self.keystone['port'] = self.config['keystone']['port']
self.keystone['apiver'] = self.config['keystone']['apiver']
self.keystone['user'] = self.config['keystone']['user']
self.keystone['pass'] = self.config['keystone']['password']
def _md5sum_file(self, path):
md5sum = md5()
with open(path, 'rb') as file:
for chunk in iter(lambda: file.read(8192), ''):
md5sum.update(chunk)
return md5sum.hexdigest()
def _read_in_chunks(self, infile, chunk_size=1024 * 64):
file_data = open(infile, "rb")
while True:
# chunk = file_data.read(chunk_size).encode('base64')
chunk = file_data.read(chunk_size)
if chunk:
yield chunk
else:
return
file_data.close()
def _parse_defaults_file(self):
cfg = os.path.abspath(os.path.join(os.path.dirname(__file__),
"..", "etc", "config.ini"))
if os.path.exists(cfg):
self._build_config(cfg)
else:
raise Exception("Cannot read %s" % cfg)
def _build_config(self, config_file):
parser = ConfigParser.ConfigParser()
parser.read(config_file)
for section in parser.sections():
self.config[section] = {}
for value in parser.options(section):
self.config[section][value] = parser.get(section, value)
# print "%s = %s" % (value, parser.get(section, value))

135
tools/install_venv.py Normal file
View File

@ -0,0 +1,135 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
"""
Installation script for Kong's testing virtualenv
"""
import os
import stat
import string
import subprocess
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
VENV = os.path.join(ROOT, '.kong-venv')
PIP_REQUIRES = os.path.join(ROOT, 'tools', 'pip-requires')
def die(message, *args):
print >> sys.stderr, message % args
sys.exit(1)
def whereis(executable):
"""
Detect whereis a binary and make sure it's executable we can execute.
"""
for d in string.split(os.environ['PATH'], \
os.pathsep):
f = os.path.join(d, executable)
if os.path.isfile(f):
try:
st = os.stat(f)
except OSError:
continue
if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
return True
return False
def run_command(cmd, redirect_output=True, check_exit_code=True):
"""
Runs a command in an out-of-process shell, returning the
output of that command. Working directory is ROOT.
"""
if redirect_output:
stdout = subprocess.PIPE
else:
stdout = None
proc = subprocess.Popen(cmd, cwd=ROOT, stdout=stdout)
output = proc.communicate()[0]
if check_exit_code and proc.returncode != 0:
die('Command "%s" failed.\n%s', ' '.join(cmd), output)
return output
HAS_EASY_INSTALL = bool(whereis("easy_install"))
HAS_VIRTUALENV = bool(whereis("virtualenv"))
def check_dependencies():
"""Make sure virtualenv is in the path."""
if not HAS_VIRTUALENV:
print 'not found.'
# Try installing it via easy_install...
if HAS_EASY_INSTALL:
print 'Installing virtualenv via easy_install...',
if not run_command(['easy_install', 'virtualenv']):
die('ERROR: virtualenv not found.\n\n'
'Glance development requires virtualenv, please install'
' it using your favorite package management tool')
print 'done.'
print 'done.'
def create_virtualenv(venv=VENV):
"""Creates the virtual environment and installs PIP only into the
virtual environment
"""
print 'Creating venv...',
run_command(['virtualenv', '-q', '--no-site-packages', VENV])
print 'done.'
print 'Installing pip in virtualenv...',
if not run_command(['tools/with_venv.sh', 'easy_install', 'pip']).strip():
die("Failed to install pip.")
print 'done.'
def install_dependencies(venv=VENV):
print 'Installing dependencies with pip (this can take a while)...'
# Install greenlet by hand - just listing it in the requires file does not
# get it in stalled in the right order
venv_tool = 'tools/with_venv.sh'
run_command([venv_tool, 'pip', 'install', '-E', venv, '-r', PIP_REQUIRES],
redirect_output=False)
# Tell the virtual env how to "import glance"
pthfile = os.path.join(venv, "lib", "python2.6", "site-packages",
"glance.pth")
f = open(pthfile, 'w')
f.write("%s\n" % ROOT)
def print_help():
help = """
Kong testing environment setup is complete.
Kong testing uses virtualenv to track and manage Python dependencies
while in development and testing.
To activate the Kong virtualenv for the extent of your current shell
session you can run:
$ source .kong-venv/bin/activate
Or, if you prefer, you can run commands in the virtualenv on a case by case
basis by running:
$ tools/with_venv.sh <your command>
Also, make test will automatically use the virtualenv.
"""
print help
def main(argv):
check_dependencies()
create_virtualenv()
install_dependencies()
print_help()
if __name__ == '__main__':
main(sys.argv)

9
tools/pip-requires Normal file
View File

@ -0,0 +1,9 @@
pep8>=0.5.0
pylint==0.19
anyjson
nose
argparse
httplib2>=0.7.0
pika
dnspython
ipython

4
tools/with_venv.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
TOOLS=`dirname $0`
VENV=$TOOLS/../.kong-venv
source $VENV/bin/activate && $@