Cleaned up v1.0 and v1.1 test setup to remove globals and encapsulate custom asserts. Still duplicate code, but closer to being able to remove. Now tests set up OpenStackClient much closer to how users will do it, minus the stubbing of the client.

This commit is contained in:
Brian Lamar 2011-08-04 09:13:46 -04:00
parent fc8253f2ca
commit 6c73d4c3b6
5 changed files with 174 additions and 178 deletions

View File

@ -37,9 +37,6 @@ def env(e):
class OpenStackComputeShell(object):
# Hook for the test suite to inject a fake server.
_api_class = None
def get_base_parser(self):
parser = argparse.ArgumentParser(
prog='nova',
@ -167,15 +164,13 @@ class OpenStackComputeShell(object):
args.func(self.cs, args)
def get_api_class(self, version):
if self._api_class is not None:
return self._api_class
try:
return {
"1.0": shell_v1_0.CLIENT_CLASS,
"1.1": shell_v1_1.CLIENT_CLASS,
}[version]
except KeyError:
print "Bad API version provided, falling back to v1.0."
return shell_v1_0.CLIENT_CLASS
@utils.arg('command', metavar='<subcommand>', nargs='?',

View File

@ -0,0 +1 @@
from novaclient.v1_0.client import Client

View File

@ -0,0 +1 @@
from novaclient.v1_1.client import Client

View File

@ -10,74 +10,73 @@ from tests import utils
class ShellTest(utils.TestCase):
# Patch os.environ to avoid required auth info.
def setUp(self):
global _old_env
fake_env = {
"""Run before each test."""
self.old_environment = os.environ.copy()
os.environ = {
'NOVA_USERNAME': 'username',
'NOVA_API_KEY': 'password',
'NOVA_PROJECT_ID': 'project_id'
}
_old_env, os.environ = os.environ, fake_env.copy()
# Make a fake shell object, a helping wrapper to call it, and a quick way
# of asserting that certain API calls were made.
global shell, _shell, assert_called, assert_called_anytime
_shell = OpenStackComputeShell()
_shell._api_class = fakes.FakeClient
assert_called = lambda m, u, b=None: _shell.cs.assert_called(m, u, b)
assert_called_anytime = lambda m, u, b=None: \
_shell.cs.assert_called_anytime(m, u, b)
def shell(cmd):
command = ['--version=1.0',]
command.extend(cmd.split())
_shell.main(command)
self.shell = OpenStackComputeShell()
self.shell.get_api_class = lambda *_: fakes.FakeClient
def tearDown(self):
global _old_env
os.environ = _old_env
os.environ = self.old_environment
def run_command(self, cmd):
command = ['--version=1.0']
command.extend(cmd.split())
print command
self.shell.main(command)
def assert_called(self, method, url, body=None):
return self.shell.cs.assert_called(method, url, body)
def assert_called_anytime(self, method, url, body=None):
return self.shell.cs.assert_called_anytime(method, url, body)
def test_backup_schedule(self):
shell('backup-schedule 1234')
assert_called('GET', '/servers/1234/backup_schedule')
self.run_command('backup-schedule 1234')
self.assert_called('GET', '/servers/1234/backup_schedule')
shell('backup-schedule sample-server --weekly monday')
assert_called(
self.run_command('backup-schedule sample-server --weekly monday')
self.assert_called(
'POST', '/servers/1234/backup_schedule',
{'backupSchedule': {'enabled': True, 'daily': 'DISABLED',
'weekly': 'MONDAY'}}
)
shell('backup-schedule sample-server '
self.run_command('backup-schedule sample-server '
'--weekly disabled --daily h_0000_0200')
assert_called(
self.assert_called(
'POST', '/servers/1234/backup_schedule',
{'backupSchedule': {'enabled': True, 'daily': 'H_0000_0200',
'weekly': 'DISABLED'}}
)
shell('backup-schedule sample-server --disable')
assert_called(
self.run_command('backup-schedule sample-server --disable')
self.assert_called(
'POST', '/servers/1234/backup_schedule',
{'backupSchedule': {'enabled': False, 'daily': 'DISABLED',
'weekly': 'DISABLED'}}
)
def test_backup_schedule_delete(self):
shell('backup-schedule-delete 1234')
assert_called('DELETE', '/servers/1234/backup_schedule')
self.run_command('backup-schedule-delete 1234')
self.assert_called('DELETE', '/servers/1234/backup_schedule')
def test_boot(self):
shell('boot --image 1 some-server')
assert_called(
self.run_command('boot --image 1 some-server')
self.assert_called(
'POST', '/servers',
{'server': {'flavorId': 1, 'name': 'some-server', 'imageId': '1',
'min_count': 1, 'max_count': 1}}
)
shell('boot --image 1 --meta foo=bar --meta spam=eggs some-server ')
assert_called(
self.run_command('boot --image 1 --meta foo=bar --meta spam=eggs some-server ')
self.assert_called(
'POST', '/servers',
{'server': {'flavorId': 1, 'name': 'some-server', 'imageId': '1',
'min_count': 1, 'max_count': 1,
@ -88,10 +87,10 @@ class ShellTest(utils.TestCase):
testfile = os.path.join(os.path.dirname(__file__), 'testfile.txt')
expected_file_data = open(testfile).read().encode('base64')
shell('boot some-server --image 1 --file /tmp/foo=%s --file /tmp/bar=%s' %
self.run_command('boot some-server --image 1 --file /tmp/foo=%s --file /tmp/bar=%s' %
(testfile, testfile))
assert_called(
self.assert_called(
'POST', '/servers',
{'server': {'flavorId': 1, 'name': 'some-server', 'imageId': '1',
'min_count': 1, 'max_count': 1,
@ -104,7 +103,7 @@ class ShellTest(utils.TestCase):
def test_boot_invalid_file(self):
invalid_file = os.path.join(os.path.dirname(__file__), 'asdfasdfasdfasdf')
self.assertRaises(exceptions.CommandError, shell, 'boot some-server --image 1 '
self.assertRaises(exceptions.CommandError, self.run_command, 'boot some-server --image 1 '
'--file /foo=%s' % invalid_file)
def test_boot_key_auto(self):
@ -116,8 +115,8 @@ class ShellTest(utils.TestCase):
@mock.patch('os.path.exists', mock_exists)
@mock.patch('__builtin__.open', mock_open)
def test_shell_call():
shell('boot some-server --image 1 --key')
assert_called(
self.run_command('boot some-server --image 1 --key')
self.assert_called(
'POST', '/servers',
{'server': {'flavorId': 1, 'name': 'some-server', 'imageId': '1',
'min_count': 1, 'max_count': 1,
@ -135,7 +134,7 @@ class ShellTest(utils.TestCase):
@mock.patch('os.path.exists', mock_exists)
def test_shell_call():
self.assertRaises(exceptions.CommandError, shell,
self.assertRaises(exceptions.CommandError, self.run_command,
'boot some-server --image 1 --key')
test_shell_call()
@ -143,8 +142,8 @@ class ShellTest(utils.TestCase):
def test_boot_key_file(self):
testfile = os.path.join(os.path.dirname(__file__), 'testfile.txt')
expected_file_data = open(testfile).read().encode('base64')
shell('boot some-server --image 1 --key %s' % testfile)
assert_called(
self.run_command('boot some-server --image 1 --key %s' % testfile)
self.assert_called(
'POST', '/servers',
{'server': {'flavorId': 1, 'name': 'some-server', 'imageId': '1',
'min_count': 1, 'max_count': 1,
@ -157,117 +156,117 @@ class ShellTest(utils.TestCase):
def test_boot_invalid_keyfile(self):
invalid_file = os.path.join(os.path.dirname(__file__), 'asdfasdfasdfasdf')
self.assertRaises(exceptions.CommandError, shell, 'boot some-server '
self.assertRaises(exceptions.CommandError, self.run_command, 'boot some-server '
'--image 1 --key %s' % invalid_file)
def test_boot_ipgroup(self):
shell('boot --image 1 --ipgroup 1 some-server')
assert_called(
self.run_command('boot --image 1 --ipgroup 1 some-server')
self.assert_called(
'POST', '/servers',
{'server': {'flavorId': 1, 'name': 'some-server', 'imageId': '1',
'sharedIpGroupId': 1, 'min_count': 1, 'max_count': 1}}
)
def test_boot_ipgroup_name(self):
shell('boot --image 1 --ipgroup group1 some-server')
assert_called(
self.run_command('boot --image 1 --ipgroup group1 some-server')
self.assert_called(
'POST', '/servers',
{'server': {'flavorId': 1, 'name': 'some-server', 'imageId': '1',
'sharedIpGroupId': 1, 'min_count': 1, 'max_count': 1}}
)
def test_flavor_list(self):
shell('flavor-list')
assert_called_anytime('GET', '/flavors/detail')
self.run_command('flavor-list')
self.assert_called_anytime('GET', '/flavors/detail')
def test_image_list(self):
shell('image-list')
assert_called('GET', '/images/detail')
self.run_command('image-list')
self.assert_called('GET', '/images/detail')
def test_snapshot_create(self):
shell('image-create sample-server mysnapshot')
assert_called(
self.run_command('image-create sample-server mysnapshot')
self.assert_called(
'POST', '/images',
{'image': {'name': 'mysnapshot', 'serverId': 1234}}
)
def test_image_delete(self):
shell('image-delete 1')
assert_called('DELETE', '/images/1')
self.run_command('image-delete 1')
self.assert_called('DELETE', '/images/1')
def test_ip_share(self):
shell('ip-share sample-server 1 1.2.3.4')
assert_called(
self.run_command('ip-share sample-server 1 1.2.3.4')
self.assert_called(
'PUT', '/servers/1234/ips/public/1.2.3.4',
{'shareIp': {'sharedIpGroupId': 1, 'configureServer': True}}
)
def test_ip_unshare(self):
shell('ip-unshare sample-server 1.2.3.4')
assert_called('DELETE', '/servers/1234/ips/public/1.2.3.4')
self.run_command('ip-unshare sample-server 1.2.3.4')
self.assert_called('DELETE', '/servers/1234/ips/public/1.2.3.4')
def test_ipgroup_list(self):
shell('ipgroup-list')
self.run_command('ipgroup-list')
assert ('GET', '/shared_ip_groups/detail', None) in \
_shell.cs.client.callstack
assert_called('GET', '/servers/5678')
self.shell.cs.client.callstack
self.assert_called('GET', '/servers/5678')
def test_ipgroup_show(self):
shell('ipgroup-show 1')
assert_called('GET', '/shared_ip_groups/1')
shell('ipgroup-show group2')
self.run_command('ipgroup-show 1')
self.assert_called('GET', '/shared_ip_groups/1')
self.run_command('ipgroup-show group2')
# does a search, not a direct GET
assert_called('GET', '/shared_ip_groups/detail')
self.assert_called('GET', '/shared_ip_groups/detail')
def test_ipgroup_create(self):
shell('ipgroup-create a-group')
assert_called(
self.run_command('ipgroup-create a-group')
self.assert_called(
'POST', '/shared_ip_groups',
{'sharedIpGroup': {'name': 'a-group'}}
)
shell('ipgroup-create a-group sample-server')
assert_called(
self.run_command('ipgroup-create a-group sample-server')
self.assert_called(
'POST', '/shared_ip_groups',
{'sharedIpGroup': {'name': 'a-group', 'server': 1234}}
)
def test_ipgroup_delete(self):
shell('ipgroup-delete group1')
assert_called('DELETE', '/shared_ip_groups/1')
self.run_command('ipgroup-delete group1')
self.assert_called('DELETE', '/shared_ip_groups/1')
def test_list(self):
shell('list')
assert_called('GET', '/servers/detail')
self.run_command('list')
self.assert_called('GET', '/servers/detail')
def test_reboot(self):
shell('reboot sample-server')
assert_called('POST', '/servers/1234/action', {'reboot': {'type': 'SOFT'}})
shell('reboot sample-server --hard')
assert_called('POST', '/servers/1234/action', {'reboot': {'type': 'HARD'}})
self.run_command('reboot sample-server')
self.assert_called('POST', '/servers/1234/action', {'reboot': {'type': 'SOFT'}})
self.run_command('reboot sample-server --hard')
self.assert_called('POST', '/servers/1234/action', {'reboot': {'type': 'HARD'}})
def test_rebuild(self):
shell('rebuild sample-server 1')
assert_called('POST', '/servers/1234/action', {'rebuild': {'imageId': 1}})
self.run_command('rebuild sample-server 1')
self.assert_called('POST', '/servers/1234/action', {'rebuild': {'imageId': 1}})
def test_rename(self):
shell('rename sample-server newname')
assert_called('PUT', '/servers/1234', {'server': {'name': 'newname'}})
self.run_command('rename sample-server newname')
self.assert_called('PUT', '/servers/1234', {'server': {'name': 'newname'}})
def test_resize(self):
shell('resize sample-server 1')
assert_called('POST', '/servers/1234/action', {'resize': {'flavorId': 1}})
self.run_command('resize sample-server 1')
self.assert_called('POST', '/servers/1234/action', {'resize': {'flavorId': 1}})
def test_resize_confirm(self):
shell('resize-confirm sample-server')
assert_called('POST', '/servers/1234/action', {'confirmResize': None})
self.run_command('resize-confirm sample-server')
self.assert_called('POST', '/servers/1234/action', {'confirmResize': None})
def test_resize_revert(self):
shell('resize-revert sample-server')
assert_called('POST', '/servers/1234/action', {'revertResize': None})
self.run_command('resize-revert sample-server')
self.assert_called('POST', '/servers/1234/action', {'revertResize': None})
def test_backup(self):
shell('backup sample-server mybackup daily 1')
assert_called(
self.run_command('backup sample-server mybackup daily 1')
self.assert_called(
'POST', '/servers/1234/action',
{'createBackup': {'name': 'mybackup', 'backup_type': 'daily',
'rotation': 1}}
@ -275,35 +274,35 @@ class ShellTest(utils.TestCase):
@mock.patch('getpass.getpass', mock.Mock(return_value='p'))
def test_root_password(self):
shell('root-password sample-server')
assert_called('PUT', '/servers/1234', {'server': {'adminPass': 'p'}})
self.run_command('root-password sample-server')
self.assert_called('PUT', '/servers/1234', {'server': {'adminPass': 'p'}})
def test_show(self):
shell('show 1234')
self.run_command('show 1234')
# XXX need a way to test multiple calls
# assert_called('GET', '/servers/1234')
assert_called('GET', '/images/2')
# self.assert_called('GET', '/servers/1234')
self.assert_called('GET', '/images/2')
def test_delete(self):
shell('delete 1234')
assert_called('DELETE', '/servers/1234')
shell('delete sample-server')
assert_called('DELETE', '/servers/1234')
self.run_command('delete 1234')
self.assert_called('DELETE', '/servers/1234')
self.run_command('delete sample-server')
self.assert_called('DELETE', '/servers/1234')
def test_zone(self):
shell('zone 1')
assert_called('GET', '/zones/1')
self.run_command('zone 1')
self.assert_called('GET', '/zones/1')
shell('zone 1 --api_url=http://zzz --zone_username=frank --password=xxx')
assert_called(
self.run_command('zone 1 --api_url=http://zzz --zone_username=frank --password=xxx')
self.assert_called(
'PUT', '/zones/1',
{'zone': {'api_url': 'http://zzz', 'username': 'frank',
'password': 'xxx'}}
)
def test_zone_add(self):
shell('zone-add http://zzz frank xxx 0.0 1.0')
assert_called(
self.run_command('zone-add http://zzz frank xxx 0.0 1.0')
self.assert_called(
'POST', '/zones',
{'zone': {'api_url': 'http://zzz', 'username': 'frank',
'password': 'xxx',
@ -311,9 +310,9 @@ class ShellTest(utils.TestCase):
)
def test_zone_delete(self):
shell('zone-delete 1')
assert_called('DELETE', '/zones/1')
self.run_command('zone-delete 1')
self.assert_called('DELETE', '/zones/1')
def test_zone_list(self):
shell('zone-list')
assert ('GET', '/zones/detail', None) in _shell.cs.client.callstack
self.run_command('zone-list')
assert ('GET', '/zones/detail', None) in self.shell.cs.client.callstack

View File

@ -12,35 +12,35 @@ class ShellTest(utils.TestCase):
# Patch os.environ to avoid required auth info.
def setUp(self):
global _old_env
fake_env = {
"""Run before each test."""
self.old_environment = os.environ.copy()
os.environ = {
'NOVA_USERNAME': 'username',
'NOVA_API_KEY': 'password',
'NOVA_PROJECT_ID': 'project_id'
'NOVA_PROJECT_ID': 'project_id',
}
_old_env, os.environ = os.environ, fake_env.copy()
# Make a fake shell object, a helping wrapper to call it, and a quick way
# of asserting that certain API calls were made.
global shell, _shell, assert_called, assert_called_anytime
_shell = OpenStackComputeShell()
_shell._api_class = fakes.FakeClient
assert_called = lambda m, u, b=None: _shell.cs.assert_called(m, u, b)
assert_called_anytime = lambda m, u, b=None: \
_shell.cs.assert_called_anytime(m, u, b)
def shell(cmd):
command = ['--version=1.1',]
command.extend(cmd.split())
_shell.main(command)
self.shell = OpenStackComputeShell()
self.shell.get_api_class = lambda *_: fakes.FakeClient
def tearDown(self):
global _old_env
os.environ = _old_env
os.environ = self.old_environment
def run_command(self, cmd):
command = ['--version=1.1']
command.extend(cmd.split())
print command
self.shell.main(command)
def assert_called(self, method, url, body=None):
return self.shell.cs.assert_called(method, url, body)
def assert_called_anytime(self, method, url, body=None):
return self.shell.cs.assert_called_anytime(method, url, body)
def test_boot(self):
shell('boot --image 1 some-server')
assert_called(
self.run_command('boot --image 1 some-server')
self.assert_called(
'POST', '/servers',
{'server': {
'flavorRef': 1,
@ -51,8 +51,8 @@ class ShellTest(utils.TestCase):
}}
)
shell('boot --image 1 --meta foo=bar --meta spam=eggs some-server ')
assert_called(
self.run_command('boot --image 1 --meta foo=bar --meta spam=eggs some-server ')
self.assert_called(
'POST', '/servers',
{'server': {
'flavorRef': 1,
@ -68,9 +68,9 @@ class ShellTest(utils.TestCase):
expected_file_data = open(testfile).read().encode('base64')
cmd = 'boot some-server --image 1 --file /tmp/foo=%s --file /tmp/bar=%s'
shell(cmd % (testfile, testfile))
self.run_command(cmd % (testfile, testfile))
assert_called(
self.assert_called(
'POST', '/servers',
{'server': {
'flavorRef': 1,
@ -87,7 +87,7 @@ class ShellTest(utils.TestCase):
def test_boot_invalid_file(self):
invalid_file = os.path.join(os.path.dirname(__file__), 'asdfasdfasdfasdf')
cmd = 'boot some-server --image 1 --file /foo=%s' % invalid_file
self.assertRaises(exceptions.CommandError, shell, cmd)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_boot_key_auto(self):
mock_exists = mock.Mock(return_value=True)
@ -98,8 +98,8 @@ class ShellTest(utils.TestCase):
@mock.patch('os.path.exists', mock_exists)
@mock.patch('__builtin__.open', mock_open)
def test_shell_call():
shell('boot some-server --image 1 --key')
assert_called(
self.run_command('boot some-server --image 1 --key')
self.assert_called(
'POST', '/servers',
{'server': {
'flavorRef': 1,
@ -120,7 +120,7 @@ class ShellTest(utils.TestCase):
@mock.patch('os.path.exists', mock_exists)
def test_shell_call():
self.assertRaises(exceptions.CommandError, shell,
self.assertRaises(exceptions.CommandError, self.run_command,
'boot some-server --image 1 --key')
test_shell_call()
@ -128,8 +128,8 @@ class ShellTest(utils.TestCase):
def test_boot_key_file(self):
testfile = os.path.join(os.path.dirname(__file__), 'testfile.txt')
expected_file_data = open(testfile).read().encode('base64')
shell('boot some-server --image 1 --key %s' % testfile)
assert_called(
self.run_command('boot some-server --image 1 --key %s' % testfile)
self.assert_called(
'POST', '/servers',
{'server': {
'flavorRef': 1,
@ -144,71 +144,71 @@ class ShellTest(utils.TestCase):
def test_boot_invalid_keyfile(self):
invalid_file = os.path.join(os.path.dirname(__file__), 'asdfasdfasdfasdf')
self.assertRaises(exceptions.CommandError, shell, 'boot some-server '
self.assertRaises(exceptions.CommandError, self.run_command, 'boot some-server '
'--image 1 --key %s' % invalid_file)
def test_flavor_list(self):
shell('flavor-list')
assert_called_anytime('GET', '/flavors/detail')
self.run_command('flavor-list')
self.assert_called_anytime('GET', '/flavors/detail')
def test_image_list(self):
shell('image-list')
assert_called('GET', '/images/detail')
self.run_command('image-list')
self.assert_called('GET', '/images/detail')
def test_create_image(self):
shell('create-image sample-server mysnapshot')
assert_called(
self.run_command('create-image sample-server mysnapshot')
self.assert_called(
'POST', '/servers/1234/action',
{'createImage': {'name': 'mysnapshot', 'metadata': {}}}
)
def test_image_delete(self):
shell('image-delete 1')
assert_called('DELETE', '/images/1')
self.run_command('image-delete 1')
self.assert_called('DELETE', '/images/1')
def test_list(self):
shell('list')
assert_called('GET', '/servers/detail')
self.run_command('list')
self.assert_called('GET', '/servers/detail')
def test_reboot(self):
shell('reboot sample-server')
assert_called('POST', '/servers/1234/action', {'reboot': {'type': 'SOFT'}})
shell('reboot sample-server --hard')
assert_called('POST', '/servers/1234/action', {'reboot': {'type': 'HARD'}})
self.run_command('reboot sample-server')
self.assert_called('POST', '/servers/1234/action', {'reboot': {'type': 'SOFT'}})
self.run_command('reboot sample-server --hard')
self.assert_called('POST', '/servers/1234/action', {'reboot': {'type': 'HARD'}})
def test_rebuild(self):
shell('rebuild sample-server 1')
assert_called('POST', '/servers/1234/action', {'rebuild': {'imageRef': 1}})
self.run_command('rebuild sample-server 1')
self.assert_called('POST', '/servers/1234/action', {'rebuild': {'imageRef': 1}})
def test_rename(self):
shell('rename sample-server newname')
assert_called('PUT', '/servers/1234', {'server': {'name': 'newname'}})
self.run_command('rename sample-server newname')
self.assert_called('PUT', '/servers/1234', {'server': {'name': 'newname'}})
def test_resize(self):
shell('resize sample-server 1')
assert_called('POST', '/servers/1234/action', {'resize': {'flavorRef': 1}})
self.run_command('resize sample-server 1')
self.assert_called('POST', '/servers/1234/action', {'resize': {'flavorRef': 1}})
def test_resize_confirm(self):
shell('resize-confirm sample-server')
assert_called('POST', '/servers/1234/action', {'confirmResize': None})
self.run_command('resize-confirm sample-server')
self.assert_called('POST', '/servers/1234/action', {'confirmResize': None})
def test_resize_revert(self):
shell('resize-revert sample-server')
assert_called('POST', '/servers/1234/action', {'revertResize': None})
self.run_command('resize-revert sample-server')
self.assert_called('POST', '/servers/1234/action', {'revertResize': None})
@mock.patch('getpass.getpass', mock.Mock(return_value='p'))
def test_root_password(self):
shell('root-password sample-server')
assert_called('POST', '/servers/1234/action', {'changePassword': {'adminPass': 'p'}})
self.run_command('root-password sample-server')
self.assert_called('POST', '/servers/1234/action', {'changePassword': {'adminPass': 'p'}})
def test_show(self):
shell('show 1234')
self.run_command('show 1234')
# XXX need a way to test multiple calls
# assert_called('GET', '/servers/1234')
assert_called('GET', '/images/2')
self.assert_called('GET', '/images/2')
def test_delete(self):
shell('delete 1234')
assert_called('DELETE', '/servers/1234')
shell('delete sample-server')
assert_called('DELETE', '/servers/1234')
self.run_command('delete 1234')
self.assert_called('DELETE', '/servers/1234')
self.run_command('delete sample-server')
self.assert_called('DELETE', '/servers/1234')