diff options
Diffstat (limited to 'nova/tests/unit/api/openstack/compute/test_keypairs.py')
-rw-r--r-- | nova/tests/unit/api/openstack/compute/test_keypairs.py | 172 |
1 files changed, 117 insertions, 55 deletions
diff --git a/nova/tests/unit/api/openstack/compute/test_keypairs.py b/nova/tests/unit/api/openstack/compute/test_keypairs.py index 657973ffbd..590639d5ed 100644 --- a/nova/tests/unit/api/openstack/compute/test_keypairs.py +++ b/nova/tests/unit/api/openstack/compute/test_keypairs.py @@ -13,7 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. -import mock +from unittest import mock + import webob from nova.api.openstack.compute import keypairs as keypairs_v21 @@ -37,6 +38,8 @@ keypair_data = { FAKE_UUID = 'b48316c5-71e8-45e4-9884-6c78055b9b13' +keypair_name_2_92_compatible = 'my-key@ my.host' + def fake_keypair(name): return dict(test_keypair.fake_keypair, @@ -110,16 +113,22 @@ class KeypairsTestV21(test.TestCase): self.assertGreater(len(res_dict['keypair']['private_key']), 0) self._assert_keypair_type(res_dict) - def _test_keypair_create_bad_request_case(self, - body, - exception): - self.assertRaises(exception, - self.controller.create, self.req, body=body) + def _test_keypair_create_bad_request_case( + self, body, exception, error_msg=None + ): + if error_msg: + self.assertRaisesRegex(exception, error_msg, + self.controller.create, + self.req, body=body) + else: + self.assertRaises(exception, + self.controller.create, self.req, body=body) def test_keypair_create_with_empty_name(self): body = {'keypair': {'name': ''}} self._test_keypair_create_bad_request_case(body, - self.validation_error) + self.validation_error, + 'is too short') def test_keypair_create_with_name_too_long(self): body = { @@ -128,7 +137,8 @@ class KeypairsTestV21(test.TestCase): } } self._test_keypair_create_bad_request_case(body, - self.validation_error) + self.validation_error, + 'is too long') def test_keypair_create_with_name_leading_trailing_spaces(self): body = { @@ -136,8 +146,10 @@ class KeypairsTestV21(test.TestCase): 'name': ' test ' } } + expected_msg = 'Can not start or end with whitespace.' self._test_keypair_create_bad_request_case(body, - self.validation_error) + self.validation_error, + expected_msg) def test_keypair_create_with_name_leading_trailing_spaces_compat_mode( self): @@ -152,8 +164,21 @@ class KeypairsTestV21(test.TestCase): 'name': 'test/keypair' } } + expected_msg = 'Only expected characters' self._test_keypair_create_bad_request_case(body, - webob.exc.HTTPBadRequest) + self.validation_error, + expected_msg) + + def test_keypair_create_with_special_characters(self): + body = { + 'keypair': { + 'name': keypair_name_2_92_compatible + } + } + expected_msg = 'Only expected characters' + self._test_keypair_create_bad_request_case(body, + self.validation_error, + expected_msg) def test_keypair_import_bad_key(self): body = { @@ -167,8 +192,10 @@ class KeypairsTestV21(test.TestCase): def test_keypair_create_with_invalid_keypair_body(self): body = {'alpha': {'name': 'create_test'}} + expected_msg = "'keypair' is a required property" self._test_keypair_create_bad_request_case(body, - self.validation_error) + self.validation_error, + expected_msg) def test_keypair_import(self): body = { @@ -228,50 +255,6 @@ class KeypairsTestV21(test.TestCase): self.controller.create, self.req, body=body) self.assertIn('Quota exceeded, too many key pairs.', ex.explanation) - @mock.patch('nova.objects.Quotas.check_deltas') - def test_keypair_create_over_quota_during_recheck(self, mock_check): - # Simulate a race where the first check passes and the recheck fails. - # First check occurs in compute/api. - exc = exception.OverQuota(overs='key_pairs', usages={'key_pairs': 100}) - mock_check.side_effect = [None, exc] - body = { - 'keypair': { - 'name': 'FAKE', - }, - } - - self.assertRaises(webob.exc.HTTPForbidden, - self.controller.create, self.req, body=body) - - ctxt = self.req.environ['nova.context'] - self.assertEqual(2, mock_check.call_count) - call1 = mock.call(ctxt, {'key_pairs': 1}, ctxt.user_id) - call2 = mock.call(ctxt, {'key_pairs': 0}, ctxt.user_id) - mock_check.assert_has_calls([call1, call2]) - - # Verify we removed the key pair that was added after the first - # quota check passed. - key_pairs = objects.KeyPairList.get_by_user(ctxt, ctxt.user_id) - names = [key_pair.name for key_pair in key_pairs] - self.assertNotIn('create_test', names) - - @mock.patch('nova.objects.Quotas.check_deltas') - def test_keypair_create_no_quota_recheck(self, mock_check): - # Disable recheck_quota. - self.flags(recheck_quota=False, group='quota') - - body = { - 'keypair': { - 'name': 'create_test', - }, - } - self.controller.create(self.req, body=body) - - ctxt = self.req.environ['nova.context'] - # check_deltas should have been called only once. - mock_check.assert_called_once_with(ctxt, {'key_pairs': 1}, - ctxt.user_id) - def test_keypair_create_duplicate(self): self.stub_out("nova.objects.KeyPair.create", db_key_pair_create_duplicate) @@ -514,3 +497,82 @@ class KeypairsTestV275(test.TestCase): version='2.75', use_admin_context=True) self.assertRaises(exception.ValidationError, self.controller.delete, req, 1) + + +class KeypairsTestV292(test.TestCase): + wsgi_api_version = '2.92' + wsgi_old_api_version = '2.91' + + def setUp(self): + super(KeypairsTestV292, self).setUp() + self.controller = keypairs_v21.KeypairController() + self.req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version) + self.old_req = fakes.HTTPRequest.blank( + '', version=self.wsgi_old_api_version) + + def test_keypair_create_no_longer_supported(self): + body = { + 'keypair': { + 'name': keypair_name_2_92_compatible, + } + } + self.assertRaises(exception.ValidationError, self.controller.create, + self.req, body=body) + + def test_keypair_create_works_with_old_version(self): + body = { + 'keypair': { + 'name': 'fake', + } + } + res_dict = self.controller.create(self.old_req, body=body) + self.assertEqual('fake', res_dict['keypair']['name']) + self.assertGreater(len(res_dict['keypair']['private_key']), 0) + + def test_keypair_import_works_with_new_version(self): + body = { + 'keypair': { + 'name': 'fake', + 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBYIznA' + 'x9D7118Q1VKGpXy2HDiKyUTM8XcUuhQpo0srqb9rboUp4' + 'a9NmCwpWpeElDLuva707GOUnfaBAvHBwsRXyxHJjRaI6Y' + 'Qj2oLJwqvaSaWUbyT1vtryRqy6J3TecN0WINY71f4uymi' + 'MZP0wby4bKBcYnac8KiCIlvkEl0ETjkOGUq8OyWRmn7lj' + 'j5SESEUdBP0JnuTFKddWTU/wD6wydeJaUhBTqOlHn0kX1' + 'GyqoNTE1UEhcM5ZRWgfUZfTjVyDF2kGj3vJLCJtJ8LoGc' + 'j7YaN4uPg1rBle+izwE/tLonRrds+cev8p6krSSrxWOwB' + 'bHkXa6OciiJDvkRzJXzf', + } + } + res_dict = self.controller.create(self.req, body=body) + self.assertEqual('fake', res_dict['keypair']['name']) + self.assertNotIn('private_key', res_dict['keypair']) + + def test_keypair_create_refuses_special_chars_with_old_version(self): + body = { + 'keypair': { + 'name': keypair_name_2_92_compatible, + } + } + self.assertRaises(exception.ValidationError, self.controller.create, + self.old_req, body=body) + + def test_keypair_import_with_special_characters(self): + body = { + 'keypair': { + 'name': keypair_name_2_92_compatible, + 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBYIznA' + 'x9D7118Q1VKGpXy2HDiKyUTM8XcUuhQpo0srqb9rboUp4' + 'a9NmCwpWpeElDLuva707GOUnfaBAvHBwsRXyxHJjRaI6Y' + 'Qj2oLJwqvaSaWUbyT1vtryRqy6J3TecN0WINY71f4uymi' + 'MZP0wby4bKBcYnac8KiCIlvkEl0ETjkOGUq8OyWRmn7lj' + 'j5SESEUdBP0JnuTFKddWTU/wD6wydeJaUhBTqOlHn0kX1' + 'GyqoNTE1UEhcM5ZRWgfUZfTjVyDF2kGj3vJLCJtJ8LoGc' + 'j7YaN4uPg1rBle+izwE/tLonRrds+cev8p6krSSrxWOwB' + 'bHkXa6OciiJDvkRzJXzf', + } + } + + res_dict = self.controller.create(self.req, body=body) + self.assertEqual(keypair_name_2_92_compatible, + res_dict['keypair']['name']) |