summaryrefslogtreecommitdiffstats
path: root/nova/tests
diff options
context:
space:
mode:
authorJustin Santa Barbara <justin@fathomdb.com>2010-08-18 22:14:24 +0100
committerJustin Santa Barbara <justin@fathomdb.com>2010-08-18 22:14:24 +0100
commitd8f8d121a00173cb3f5fb5e496cc010dc179cf19 (patch)
tree79ae8953421d065a13309ae5052a0faaee94b485 /nova/tests
parent993563b6cc9db9f24480678cf8b2d0750aee7a92 (diff)
parent2af3bad97be40c135fb73f2e595e7fda86f17900 (diff)
Merged with trunk
Diffstat (limited to 'nova/tests')
-rw-r--r--nova/tests/auth_unittest.py16
-rw-r--r--nova/tests/cloud_unittest.py2
-rw-r--r--nova/tests/declare_flags.py23
-rw-r--r--nova/tests/flags_unittest.py87
-rw-r--r--nova/tests/network_unittest.py236
-rw-r--r--nova/tests/rpc_unittest.py85
-rw-r--r--nova/tests/runtime_flags.py23
-rw-r--r--nova/tests/virt_unittest.py69
-rw-r--r--nova/tests/volume_unittest.py77
9 files changed, 496 insertions, 122 deletions
diff --git a/nova/tests/auth_unittest.py b/nova/tests/auth_unittest.py
index f7e0625a3..0b404bfdc 100644
--- a/nova/tests/auth_unittest.py
+++ b/nova/tests/auth_unittest.py
@@ -179,7 +179,21 @@ class AuthTestCase(test.BaseTestCase):
project.add_role('test1', 'sysadmin')
self.assertTrue(project.has_role('test1', 'sysadmin'))
- def test_211_can_remove_project_role(self):
+ def test_211_can_list_project_roles(self):
+ project = self.manager.get_project('testproj')
+ user = self.manager.get_user('test1')
+ self.manager.add_role(user, 'netadmin', project)
+ roles = self.manager.get_user_roles(user)
+ self.assertTrue('sysadmin' in roles)
+ self.assertFalse('netadmin' in roles)
+ project_roles = self.manager.get_user_roles(user, project)
+ self.assertTrue('sysadmin' in project_roles)
+ self.assertTrue('netadmin' in project_roles)
+ # has role should be false because global role is missing
+ self.assertFalse(self.manager.has_role(user, 'netadmin', project))
+
+
+ def test_212_can_remove_project_role(self):
project = self.manager.get_project('testproj')
self.assertTrue(project.has_role('test1', 'sysadmin'))
project.remove_role('test1', 'sysadmin')
diff --git a/nova/tests/cloud_unittest.py b/nova/tests/cloud_unittest.py
index 40837405c..3501771cc 100644
--- a/nova/tests/cloud_unittest.py
+++ b/nova/tests/cloud_unittest.py
@@ -132,7 +132,7 @@ class CloudTestCase(test.BaseTestCase):
'state': 0x01,
'user_data': ''
}
- rv = self.cloud._format_instances(self.context)
+ rv = self.cloud._format_describe_instances(self.context)
self.assert_(len(rv['reservationSet']) == 0)
# simulate launch of 5 instances
diff --git a/nova/tests/declare_flags.py b/nova/tests/declare_flags.py
new file mode 100644
index 000000000..51a55ec72
--- /dev/null
+++ b/nova/tests/declare_flags.py
@@ -0,0 +1,23 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from nova import flags
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_integer('answer', 42, 'test flag')
diff --git a/nova/tests/flags_unittest.py b/nova/tests/flags_unittest.py
new file mode 100644
index 000000000..d49d5dc43
--- /dev/null
+++ b/nova/tests/flags_unittest.py
@@ -0,0 +1,87 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from nova import exception
+from nova import flags
+from nova import test
+
+
+class FlagsTestCase(test.TrialTestCase):
+ def setUp(self):
+ super(FlagsTestCase, self).setUp()
+ self.FLAGS = flags.FlagValues()
+ self.global_FLAGS = flags.FLAGS
+
+ def test_define(self):
+ self.assert_('string' not in self.FLAGS)
+ self.assert_('int' not in self.FLAGS)
+ self.assert_('false' not in self.FLAGS)
+ self.assert_('true' not in self.FLAGS)
+
+ flags.DEFINE_string('string', 'default', 'desc', flag_values=self.FLAGS)
+ flags.DEFINE_integer('int', 1, 'desc', flag_values=self.FLAGS)
+ flags.DEFINE_bool('false', False, 'desc', flag_values=self.FLAGS)
+ flags.DEFINE_bool('true', True, 'desc', flag_values=self.FLAGS)
+
+ self.assert_(self.FLAGS['string'])
+ self.assert_(self.FLAGS['int'])
+ self.assert_(self.FLAGS['false'])
+ self.assert_(self.FLAGS['true'])
+ self.assertEqual(self.FLAGS.string, 'default')
+ self.assertEqual(self.FLAGS.int, 1)
+ self.assertEqual(self.FLAGS.false, False)
+ self.assertEqual(self.FLAGS.true, True)
+
+ argv = ['flags_test',
+ '--string', 'foo',
+ '--int', '2',
+ '--false',
+ '--notrue']
+
+ self.FLAGS(argv)
+ self.assertEqual(self.FLAGS.string, 'foo')
+ self.assertEqual(self.FLAGS.int, 2)
+ self.assertEqual(self.FLAGS.false, True)
+ self.assertEqual(self.FLAGS.true, False)
+
+ def test_declare(self):
+ self.assert_('answer' not in self.global_FLAGS)
+ flags.DECLARE('answer', 'nova.tests.declare_flags')
+ self.assert_('answer' in self.global_FLAGS)
+ self.assertEqual(self.global_FLAGS.answer, 42)
+
+ # Make sure we don't overwrite anything
+ self.global_FLAGS.answer = 256
+ self.assertEqual(self.global_FLAGS.answer, 256)
+ flags.DECLARE('answer', 'nova.tests.declare_flags')
+ self.assertEqual(self.global_FLAGS.answer, 256)
+
+ def test_runtime_and_unknown_flags(self):
+ self.assert_('runtime_answer' not in self.global_FLAGS)
+
+ argv = ['flags_test', '--runtime_answer=60', 'extra_arg']
+ args = self.global_FLAGS(argv)
+ self.assertEqual(len(args), 2)
+ self.assertEqual(args[1], 'extra_arg')
+
+ self.assert_('runtime_answer' not in self.global_FLAGS)
+
+ import nova.tests.runtime_flags
+
+ self.assert_('runtime_answer' in self.global_FLAGS)
+ self.assertEqual(self.global_FLAGS.runtime_answer, 60)
diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py
index 879ee02a4..993bfacc2 100644
--- a/nova/tests/network_unittest.py
+++ b/nova/tests/network_unittest.py
@@ -15,7 +15,9 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
+"""
+Unit Tests for network code
+"""
import IPy
import os
import logging
@@ -31,8 +33,10 @@ from nova.network.exception import NoMoreAddresses
FLAGS = flags.FLAGS
+
class NetworkTestCase(test.TrialTestCase):
- def setUp(self):
+ """Test cases for network code"""
+ def setUp(self): # pylint: disable-msg=C0103
super(NetworkTestCase, self).setUp()
# NOTE(vish): if you change these flags, make sure to change the
# flags in the corresponding section in nova-dhcpbridge
@@ -43,7 +47,6 @@ class NetworkTestCase(test.TrialTestCase):
network_size=32)
logging.getLogger().setLevel(logging.DEBUG)
self.manager = manager.AuthManager()
- self.dnsmasq = FakeDNSMasq()
self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
self.projects = []
self.projects.append(self.manager.create_project('netuser',
@@ -54,47 +57,49 @@ class NetworkTestCase(test.TrialTestCase):
self.projects.append(self.manager.create_project(name,
'netuser',
name))
- self.network = model.PublicNetworkController()
+ vpn.NetworkData.create(self.projects[i].id)
self.service = service.VlanNetworkService()
- def tearDown(self):
+ def tearDown(self): # pylint: disable-msg=C0103
super(NetworkTestCase, self).tearDown()
for project in self.projects:
self.manager.delete_project(project)
self.manager.delete_user(self.user)
def test_public_network_allocation(self):
+ """Makes sure that we can allocaate a public ip"""
pubnet = IPy.IP(flags.FLAGS.public_range)
- address = self.network.allocate_ip(self.user.id, self.projects[0].id, "public")
+ address = self.service.allocate_elastic_ip(self.user.id,
+ self.projects[0].id)
self.assertTrue(IPy.IP(address) in pubnet)
- self.assertTrue(IPy.IP(address) in self.network.network)
def test_allocate_deallocate_fixed_ip(self):
- result = yield self.service.allocate_fixed_ip(
+ """Makes sure that we can allocate and deallocate a fixed ip"""
+ result = self.service.allocate_fixed_ip(
self.user.id, self.projects[0].id)
address = result['private_dns_name']
mac = result['mac_address']
- logging.debug("Was allocated %s" % (address))
net = model.get_project_network(self.projects[0].id, "default")
self.assertEqual(True, is_in_project(address, self.projects[0].id))
hostname = "test-host"
- self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name)
- rv = self.service.deallocate_fixed_ip(address)
+ issue_ip(mac, address, hostname, net.bridge_name)
+ self.service.deallocate_fixed_ip(address)
# Doesn't go away until it's dhcp released
self.assertEqual(True, is_in_project(address, self.projects[0].id))
- self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
+ release_ip(mac, address, hostname, net.bridge_name)
self.assertEqual(False, is_in_project(address, self.projects[0].id))
- def test_range_allocation(self):
- hostname = "test-host"
- result = yield self.service.allocate_fixed_ip(
- self.user.id, self.projects[0].id)
+ def test_side_effects(self):
+ """Ensures allocating and releasing has no side effects"""
+ hostname = "side-effect-host"
+ result = self.service.allocate_fixed_ip(self.user.id,
+ self.projects[0].id)
mac = result['mac_address']
address = result['private_dns_name']
- result = yield self.service.allocate_fixed_ip(
- self.user, self.projects[1].id)
+ result = self.service.allocate_fixed_ip(self.user,
+ self.projects[1].id)
secondmac = result['mac_address']
secondaddress = result['private_dns_name']
@@ -102,66 +107,75 @@ class NetworkTestCase(test.TrialTestCase):
secondnet = model.get_project_network(self.projects[1].id, "default")
self.assertEqual(True, is_in_project(address, self.projects[0].id))
- self.assertEqual(True, is_in_project(secondaddress, self.projects[1].id))
+ self.assertEqual(True, is_in_project(secondaddress,
+ self.projects[1].id))
self.assertEqual(False, is_in_project(address, self.projects[1].id))
# Addresses are allocated before they're issued
- self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name)
- self.dnsmasq.issue_ip(secondmac, secondaddress,
- hostname, secondnet.bridge_name)
+ issue_ip(mac, address, hostname, net.bridge_name)
+ issue_ip(secondmac, secondaddress, hostname, secondnet.bridge_name)
- rv = self.service.deallocate_fixed_ip(address)
- self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
+ self.service.deallocate_fixed_ip(address)
+ release_ip(mac, address, hostname, net.bridge_name)
self.assertEqual(False, is_in_project(address, self.projects[0].id))
# First address release shouldn't affect the second
- self.assertEqual(True, is_in_project(secondaddress, self.projects[1].id))
+ self.assertEqual(True, is_in_project(secondaddress,
+ self.projects[1].id))
- rv = self.service.deallocate_fixed_ip(secondaddress)
- self.dnsmasq.release_ip(secondmac, secondaddress,
- hostname, secondnet.bridge_name)
- self.assertEqual(False, is_in_project(secondaddress, self.projects[1].id))
+ self.service.deallocate_fixed_ip(secondaddress)
+ release_ip(secondmac, secondaddress, hostname, secondnet.bridge_name)
+ self.assertEqual(False, is_in_project(secondaddress,
+ self.projects[1].id))
def test_subnet_edge(self):
- result = yield self.service.allocate_fixed_ip(self.user.id,
+ """Makes sure that private ips don't overlap"""
+ result = self.service.allocate_fixed_ip(self.user.id,
self.projects[0].id)
firstaddress = result['private_dns_name']
hostname = "toomany-hosts"
- for i in range(1,5):
+ for i in range(1, 5):
project_id = self.projects[i].id
- result = yield self.service.allocate_fixed_ip(
+ result = self.service.allocate_fixed_ip(
self.user, project_id)
mac = result['mac_address']
address = result['private_dns_name']
- result = yield self.service.allocate_fixed_ip(
+ result = self.service.allocate_fixed_ip(
self.user, project_id)
mac2 = result['mac_address']
address2 = result['private_dns_name']
- result = yield self.service.allocate_fixed_ip(
+ result = self.service.allocate_fixed_ip(
self.user, project_id)
mac3 = result['mac_address']
address3 = result['private_dns_name']
- self.assertEqual(False, is_in_project(address, self.projects[0].id))
- self.assertEqual(False, is_in_project(address2, self.projects[0].id))
- self.assertEqual(False, is_in_project(address3, self.projects[0].id))
- rv = self.service.deallocate_fixed_ip(address)
- rv = self.service.deallocate_fixed_ip(address2)
- rv = self.service.deallocate_fixed_ip(address3)
net = model.get_project_network(project_id, "default")
- self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
- self.dnsmasq.release_ip(mac2, address2, hostname, net.bridge_name)
- self.dnsmasq.release_ip(mac3, address3, hostname, net.bridge_name)
+ issue_ip(mac, address, hostname, net.bridge_name)
+ issue_ip(mac2, address2, hostname, net.bridge_name)
+ issue_ip(mac3, address3, hostname, net.bridge_name)
+ self.assertEqual(False, is_in_project(address,
+ self.projects[0].id))
+ self.assertEqual(False, is_in_project(address2,
+ self.projects[0].id))
+ self.assertEqual(False, is_in_project(address3,
+ self.projects[0].id))
+ self.service.deallocate_fixed_ip(address)
+ self.service.deallocate_fixed_ip(address2)
+ self.service.deallocate_fixed_ip(address3)
+ release_ip(mac, address, hostname, net.bridge_name)
+ release_ip(mac2, address2, hostname, net.bridge_name)
+ release_ip(mac3, address3, hostname, net.bridge_name)
net = model.get_project_network(self.projects[0].id, "default")
- rv = self.service.deallocate_fixed_ip(firstaddress)
- self.dnsmasq.release_ip(mac, firstaddress, hostname, net.bridge_name)
+ self.service.deallocate_fixed_ip(firstaddress)
+ release_ip(mac, firstaddress, hostname, net.bridge_name)
- def test_212_vpn_ip_and_port_looks_valid(self):
- vpn.NetworkData.create(self.projects[0].id)
+ def test_vpn_ip_and_port_looks_valid(self):
+ """Ensure the vpn ip and port are reasonable"""
self.assert_(self.projects[0].vpn_ip)
self.assert_(self.projects[0].vpn_port >= FLAGS.vpn_start_port)
self.assert_(self.projects[0].vpn_port <= FLAGS.vpn_end_port)
def test_too_many_vpns(self):
+ """Ensure error is raised if we run out of vpn ports"""
vpns = []
for i in xrange(vpn.NetworkData.num_ports_for_ip(FLAGS.vpn_ip)):
vpns.append(vpn.NetworkData.create("vpnuser%s" % i))
@@ -169,84 +183,102 @@ class NetworkTestCase(test.TrialTestCase):
for network_datum in vpns:
network_datum.destroy()
- def test_release_before_deallocate(self):
- pass
+ def test_ips_are_reused(self):
+ """Makes sure that ip addresses that are deallocated get reused"""
+ result = self.service.allocate_fixed_ip(
+ self.user.id, self.projects[0].id)
+ mac = result['mac_address']
+ address = result['private_dns_name']
- def test_deallocate_before_issued(self):
- pass
+ hostname = "reuse-host"
+ net = model.get_project_network(self.projects[0].id, "default")
- def test_too_many_addresses(self):
- """
- Here, we test that a proper NoMoreAddresses exception is raised.
+ issue_ip(mac, address, hostname, net.bridge_name)
+ self.service.deallocate_fixed_ip(address)
+ release_ip(mac, address, hostname, net.bridge_name)
- However, the number of available IP addresses depends on the test
- environment's setup.
+ result = self.service.allocate_fixed_ip(
+ self.user, self.projects[0].id)
+ secondmac = result['mac_address']
+ secondaddress = result['private_dns_name']
+ self.assertEqual(address, secondaddress)
+ issue_ip(secondmac, secondaddress, hostname, net.bridge_name)
+ self.service.deallocate_fixed_ip(secondaddress)
+ release_ip(secondmac, secondaddress, hostname, net.bridge_name)
- Network size is set in test fixture's setUp method.
+ def test_available_ips(self):
+ """Make sure the number of available ips for the network is correct
- There are FLAGS.cnt_vpn_clients addresses reserved for VPN (NUM_RESERVED_VPN_IPS)
+ The number of available IP addresses depends on the test
+ environment's setup.
- And there are NUM_STATIC_IPS that are always reserved by Nova for the necessary
- services (gateway, CloudPipe, etc)
+ Network size is set in test fixture's setUp method.
- So we should get flags.network_size - (NUM_STATIC_IPS +
- NUM_PREALLOCATED_IPS +
- NUM_RESERVED_VPN_IPS)
- usable addresses
+ There are ips reserved at the bottom and top of the range.
+ services (network, gateway, CloudPipe, broadcast)
"""
net = model.get_project_network(self.projects[0].id, "default")
+ num_preallocated_ips = len(net.assigned)
+ net_size = flags.FLAGS.network_size
+ num_available_ips = net_size - (net.num_bottom_reserved_ips +
+ num_preallocated_ips +
+ net.num_top_reserved_ips)
+ self.assertEqual(num_available_ips, len(list(net.available)))
- # Determine expected number of available IP addresses
- num_static_ips = net.num_static_ips
- num_preallocated_ips = len(net.hosts.keys())
- num_reserved_vpn_ips = flags.FLAGS.cnt_vpn_clients
- num_available_ips = flags.FLAGS.network_size - (num_static_ips +
- num_preallocated_ips +
- num_reserved_vpn_ips)
+ def test_too_many_addresses(self):
+ """Test for a NoMoreAddresses exception when all fixed ips are used.
+ """
+ net = model.get_project_network(self.projects[0].id, "default")
hostname = "toomany-hosts"
macs = {}
addresses = {}
- for i in range(0, (num_available_ips - 1)):
- result = yield self.service.allocate_fixed_ip(self.user.id, self.projects[0].id)
+ # Number of availaible ips is len of the available list
+ num_available_ips = len(list(net.available))
+ for i in range(num_available_ips):
+ result = self.service.allocate_fixed_ip(self.user.id,
+ self.projects[0].id)
macs[i] = result['mac_address']
addresses[i] = result['private_dns_name']
- self.dnsmasq.issue_ip(macs[i], addresses[i], hostname, net.bridge_name)
+ issue_ip(macs[i], addresses[i], hostname, net.bridge_name)
+
+ self.assertEqual(len(list(net.available)), 0)
+ self.assertRaises(NoMoreAddresses, self.service.allocate_fixed_ip,
+ self.user.id, self.projects[0].id)
- self.assertFailure(self.service.allocate_fixed_ip(self.user.id, self.projects[0].id), NoMoreAddresses)
+ for i in range(len(addresses)):
+ self.service.deallocate_fixed_ip(addresses[i])
+ release_ip(macs[i], addresses[i], hostname, net.bridge_name)
+ self.assertEqual(len(list(net.available)), num_available_ips)
- for i in range(0, (num_available_ips - 1)):
- rv = self.service.deallocate_fixed_ip(addresses[i])
- self.dnsmasq.release_ip(macs[i], addresses[i], hostname, net.bridge_name)
def is_in_project(address, project_id):
- return address in model.get_project_network(project_id).list_addresses()
+ """Returns true if address is in specified project"""
+ return address in model.get_project_network(project_id).assigned
-def _get_project_addresses(project_id):
- project_addresses = []
- for addr in model.get_project_network(project_id).list_addresses():
- project_addresses.append(addr)
- return project_addresses
def binpath(script):
+ """Returns the absolute path to a script in bin"""
return os.path.abspath(os.path.join(__file__, "../../../bin", script))
-class FakeDNSMasq(object):
- def issue_ip(self, mac, ip, hostname, interface):
- cmd = "%s add %s %s %s" % (binpath('nova-dhcpbridge'),
- mac, ip, hostname)
- env = {'DNSMASQ_INTERFACE': interface,
- 'TESTING' : '1',
- 'FLAGFILE' : FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- logging.debug("ISSUE_IP: %s, %s " % (out, err))
-
- def release_ip(self, mac, ip, hostname, interface):
- cmd = "%s del %s %s %s" % (binpath('nova-dhcpbridge'),
- mac, ip, hostname)
- env = {'DNSMASQ_INTERFACE': interface,
- 'TESTING' : '1',
- 'FLAGFILE' : FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- logging.debug("RELEASE_IP: %s, %s " % (out, err))
+def issue_ip(mac, private_ip, hostname, interface):
+ """Run add command on dhcpbridge"""
+ cmd = "%s add %s %s %s" % (binpath('nova-dhcpbridge'),
+ mac, private_ip, hostname)
+ env = {'DNSMASQ_INTERFACE': interface,
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ logging.debug("ISSUE_IP: %s, %s ", out, err)
+
+
+def release_ip(mac, private_ip, hostname, interface):
+ """Run del command on dhcpbridge"""
+ cmd = "%s del %s %s %s" % (binpath('nova-dhcpbridge'),
+ mac, private_ip, hostname)
+ env = {'DNSMASQ_INTERFACE': interface,
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ logging.debug("RELEASE_IP: %s, %s ", out, err)
diff --git a/nova/tests/rpc_unittest.py b/nova/tests/rpc_unittest.py
new file mode 100644
index 000000000..e12a28fbc
--- /dev/null
+++ b/nova/tests/rpc_unittest.py
@@ -0,0 +1,85 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""
+Unit Tests for remote procedure calls using queue
+"""
+import logging
+
+from twisted.internet import defer
+
+from nova import flags
+from nova import rpc
+from nova import test
+
+
+FLAGS = flags.FLAGS
+
+
+class RpcTestCase(test.BaseTestCase):
+ """Test cases for rpc"""
+ def setUp(self): # pylint: disable-msg=C0103
+ super(RpcTestCase, self).setUp()
+ self.conn = rpc.Connection.instance()
+ self.receiver = TestReceiver()
+ self.consumer = rpc.AdapterConsumer(connection=self.conn,
+ topic='test',
+ proxy=self.receiver)
+
+ self.injected.append(self.consumer.attach_to_tornado(self.ioloop))
+
+ def test_call_succeed(self):
+ """Get a value through rpc call"""
+ value = 42
+ result = yield rpc.call('test', {"method": "echo",
+ "args": {"value": value}})
+ self.assertEqual(value, result)
+
+ def test_call_exception(self):
+ """Test that exception gets passed back properly
+
+ rpc.call returns a RemoteError object. The value of the
+ exception is converted to a string, so we convert it back
+ to an int in the test.
+ """
+ value = 42
+ self.assertFailure(rpc.call('test', {"method": "fail",
+ "args": {"value": value}}),
+ rpc.RemoteError)
+ try:
+ yield rpc.call('test', {"method": "fail",
+ "args": {"value": value}})
+ self.fail("should have thrown rpc.RemoteError")
+ except rpc.RemoteError as exc:
+ self.assertEqual(int(exc.value), value)
+
+
+class TestReceiver(object):
+ """Simple Proxy class so the consumer has methods to call
+
+ Uses static methods because we aren't actually storing any state"""
+
+ @staticmethod
+ def echo(value):
+ """Simply returns whatever value is sent in"""
+ logging.debug("Received %s", value)
+ return defer.succeed(value)
+
+ @staticmethod
+ def fail(value):
+ """Raises an exception with the value sent in"""
+ raise Exception(value)
diff --git a/nova/tests/runtime_flags.py b/nova/tests/runtime_flags.py
new file mode 100644
index 000000000..1eb501406
--- /dev/null
+++ b/nova/tests/runtime_flags.py
@@ -0,0 +1,23 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from nova import flags
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_integer('runtime_answer', 54, 'test flag')
diff --git a/nova/tests/virt_unittest.py b/nova/tests/virt_unittest.py
new file mode 100644
index 000000000..2aab16809
--- /dev/null
+++ b/nova/tests/virt_unittest.py
@@ -0,0 +1,69 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2010 OpenStack LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from nova import flags
+from nova import test
+from nova.virt import libvirt_conn
+
+FLAGS = flags.FLAGS
+
+
+class LibvirtConnTestCase(test.TrialTestCase):
+ def test_get_uri_and_template(self):
+ class MockDataModel(object):
+ def __init__(self):
+ self.datamodel = { 'name' : 'i-cafebabe',
+ 'memory_kb' : '1024000',
+ 'basepath' : '/some/path',
+ 'bridge_name' : 'br100',
+ 'mac_address' : '02:12:34:46:56:67',
+ 'vcpus' : 2 }
+
+ type_uri_map = { 'qemu' : ('qemu:///system',
+ [lambda s: '<domain type=\'qemu\'>' in s,
+ lambda s: 'type>hvm</type' in s,
+ lambda s: 'emulator>/usr/bin/kvm' not in s]),
+ 'kvm' : ('qemu:///system',
+ [lambda s: '<domain type=\'kvm\'>' in s,
+ lambda s: 'type>hvm</type' in s,
+ lambda s: 'emulator>/usr/bin/qemu<' not in s]),
+ 'uml' : ('uml:///system',
+ [lambda s: '<domain type=\'uml\'>' in s,
+ lambda s: 'type>uml</type' in s]),
+ }
+
+ for (libvirt_type,(expected_uri, checks)) in type_uri_map.iteritems():
+ FLAGS.libvirt_type = libvirt_type
+ conn = libvirt_conn.LibvirtConnection(True)
+
+ uri, template = conn.get_uri_and_template()
+ self.assertEquals(uri, expected_uri)
+
+ for i, check in enumerate(checks):
+ xml = conn.toXml(MockDataModel())
+ self.assertTrue(check(xml), '%s failed check %d' % (xml, i))
+
+ # Deliberately not just assigning this string to FLAGS.libvirt_uri and
+ # checking against that later on. This way we make sure the
+ # implementation doesn't fiddle around with the FLAGS.
+ testuri = 'something completely different'
+ FLAGS.libvirt_uri = testuri
+ for (libvirt_type,(expected_uri, checks)) in type_uri_map.iteritems():
+ FLAGS.libvirt_type = libvirt_type
+ conn = libvirt_conn.LibvirtConnection(True)
+ uri, template = conn.get_uri_and_template()
+ self.assertEquals(uri, testuri)
+
diff --git a/nova/tests/volume_unittest.py b/nova/tests/volume_unittest.py
index 0f4f0e34d..2a07afe69 100644
--- a/nova/tests/volume_unittest.py
+++ b/nova/tests/volume_unittest.py
@@ -17,6 +17,10 @@
# under the License.
import logging
+import shutil
+import tempfile
+
+from twisted.internet import defer
from nova import compute
from nova import exception
@@ -34,10 +38,16 @@ class VolumeTestCase(test.TrialTestCase):
super(VolumeTestCase, self).setUp()
self.compute = compute.service.ComputeService()
self.volume = None
+ self.tempdir = tempfile.mkdtemp()
self.flags(connection_type='fake',
- fake_storage=True)
+ fake_storage=True,
+ aoe_export_dir=self.tempdir)
self.volume = volume_service.VolumeService()
+ def tearDown(self):
+ shutil.rmtree(self.tempdir)
+
+ @defer.inlineCallbacks
def test_run_create_volume(self):
vol_size = '0'
user_id = 'fake'
@@ -48,34 +58,40 @@ class VolumeTestCase(test.TrialTestCase):
volume_service.get_volume(volume_id)['volume_id'])
rv = self.volume.delete_volume(volume_id)
- self.assertFailure(volume_service.get_volume(volume_id),
- exception.Error)
+ self.assertRaises(exception.Error, volume_service.get_volume, volume_id)
+ @defer.inlineCallbacks
def test_too_big_volume(self):
vol_size = '1001'
user_id = 'fake'
project_id = 'fake'
- self.assertRaises(TypeError,
- self.volume.create_volume,
- vol_size, user_id, project_id)
+ try:
+ yield self.volume.create_volume(vol_size, user_id, project_id)
+ self.fail("Should have thrown TypeError")
+ except TypeError:
+ pass
+ @defer.inlineCallbacks
def test_too_many_volumes(self):
vol_size = '1'
user_id = 'fake'
project_id = 'fake'
num_shelves = FLAGS.last_shelf_id - FLAGS.first_shelf_id + 1
- total_slots = FLAGS.slots_per_shelf * num_shelves
+ total_slots = FLAGS.blades_per_shelf * num_shelves
vols = []
+ from nova import datastore
+ redis = datastore.Redis.instance()
for i in xrange(total_slots):
vid = yield self.volume.create_volume(vol_size, user_id, project_id)
vols.append(vid)
self.assertFailure(self.volume.create_volume(vol_size,
user_id,
project_id),
- volume_service.NoMoreVolumes)
+ volume_service.NoMoreBlades)
for id in vols:
yield self.volume.delete_volume(id)
+ @defer.inlineCallbacks
def test_run_attach_detach_volume(self):
# Create one volume and one compute to test with
instance_id = "storage-test"
@@ -84,22 +100,26 @@ class VolumeTestCase(test.TrialTestCase):
project_id = 'fake'
mountpoint = "/dev/sdf"
volume_id = yield self.volume.create_volume(vol_size, user_id, project_id)
-
volume_obj = volume_service.get_volume(volume_id)
volume_obj.start_attach(instance_id, mountpoint)
- rv = yield self.compute.attach_volume(volume_id,
- instance_id,
- mountpoint)
+ if FLAGS.fake_tests:
+ volume_obj.finish_attach()
+ else:
+ rv = yield self.compute.attach_volume(instance_id,
+ volume_id,
+ mountpoint)
self.assertEqual(volume_obj['status'], "in-use")
- self.assertEqual(volume_obj['attachStatus'], "attached")
+ self.assertEqual(volume_obj['attach_status'], "attached")
self.assertEqual(volume_obj['instance_id'], instance_id)
self.assertEqual(volume_obj['mountpoint'], mountpoint)
- self.assertRaises(exception.Error,
- self.volume.delete_volume,
- volume_id)
-
- rv = yield self.volume.detach_volume(volume_id)
+ self.assertFailure(self.volume.delete_volume(volume_id), exception.Error)
+ volume_obj.start_detach()
+ if FLAGS.fake_tests:
+ volume_obj.finish_detach()
+ else:
+ rv = yield self.volume.detach_volume(instance_id,
+ volume_id)
volume_obj = volume_service.get_volume(volume_id)
self.assertEqual(volume_obj['status'], "available")
@@ -108,6 +128,27 @@ class VolumeTestCase(test.TrialTestCase):
volume_service.get_volume,
volume_id)
+ @defer.inlineCallbacks
+ def test_multiple_volume_race_condition(self):
+ vol_size = "5"
+ user_id = "fake"
+ project_id = 'fake'
+ shelf_blades = []
+ def _check(volume_id):
+ vol = volume_service.get_volume(volume_id)
+ shelf_blade = '%s.%s' % (vol['shelf_id'], vol['blade_id'])
+ self.assert_(shelf_blade not in shelf_blades)
+ shelf_blades.append(shelf_blade)
+ logging.debug("got %s" % shelf_blade)
+ vol.destroy()
+ deferreds = []
+ for i in range(5):
+ d = self.volume.create_volume(vol_size, user_id, project_id)
+ d.addCallback(_check)
+ d.addErrback(self.fail)
+ deferreds.append(d)
+ yield defer.DeferredList(deferreds)
+
def test_multi_node(self):
# TODO(termie): Figure out how to test with two nodes,
# each of them having a different FLAG for storage_node