diff --git a/cloudroast/blockstorage/volumes_api/integration/compute/volume_attachments_api/volume_attach_integration.py b/cloudroast/blockstorage/volumes_api/integration/compute/volume_attachments_api/volume_attach_integration.py new file mode 100644 index 00000000..7f3c3713 --- /dev/null +++ b/cloudroast/blockstorage/volumes_api/integration/compute/volume_attachments_api/volume_attach_integration.py @@ -0,0 +1,179 @@ +""" +Copyright 2020 Rackspace + +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 qe_coverage.opencafe_decorators import tags, unless_coverage + +from cafe.drivers.unittest.suite import OpenCafeUnittestTestSuite +from cloudroast.blockstorage.volumes_api.integration.compute.fixtures \ + import ComputeIntegrationTestFixture + + +def load_tests(loader, standard_tests, pattern): + suite = OpenCafeUnittestTestSuite() + suite.addTest(VolumeAttachmentsAPIIntegration( + "test_attach_multi_volume_to_server")) + suite.addTest(VolumeAttachmentsAPIIntegration( + "test_attach_single_volume_to_multi_server")) + suite.addTest(VolumeAttachmentsAPIIntegration( + "test_delete_attached_volume")) + suite.addTest(VolumeAttachmentsAPIIntegration( + "test_attach_non_existing_volume")) + suite.addTest(VolumeAttachmentsAPIIntegration( + "test_volume_attachment_delete")) + return suite + + +class VolumeAttachmentsAPIIntegration(ComputeIntegrationTestFixture): + """Tests related to volume attachment to a server""" + + @unless_coverage + @classmethod + def setUpClass(cls): + super(VolumeAttachmentsAPIIntegration, cls).setUpClass() + cls.test_server = cls.new_server() + cls.test_multi_server = cls.new_server() + cls.test_volume1 = cls.new_volume(add_cleanup=True) + cls.test_volume2 = cls.new_volume(add_cleanup=True) + cls.test_attachment1 = \ + cls.volume_attachments.behaviors.attach_volume_to_server( + cls.test_server.id, cls.test_volume1.id_) + + if cls.test_attachment1 is None: + cls.assertClassSetupFailure( + "Could not attach volume {0} to server {1}".format( + cls.test_volume1.id_, cls.test_server.id)) + + cls.test_attachment2 = \ + cls.volume_attachments.behaviors.attach_volume_to_server( + cls.test_server.id, cls.test_volume2.id_) + + if cls.test_attachment2 is None: + cls.assertClassSetupFailure( + "Could not attach volume {0} to server {1}".format( + cls.test_volume2.id_, cls.test_server.id)) + + cls.addClassCleanup( + cls.volume_attachments.client.delete_volume_attachment, + cls.test_attachment1.id_) + cls.addClassCleanup( + cls.volume_attachments.behaviors. + verify_volume_status_progression_during_detachment, + cls.test_volume1.id_, raise_on_error=False) + cls.addClassCleanup( + cls.volumes.client.delete_volume, cls.test_volume1.id_) + + cls.addClassCleanup( + cls.volume_attachments.client.delete_volume_attachment, + cls.test_attachment2.id_) + cls.addClassCleanup( + cls.volume_attachments.behaviors. + verify_volume_status_progression_during_detachment, + cls.test_volume2.id_, raise_on_error=False) + cls.addClassCleanup( + cls.volumes.client.delete_volume, cls.test_volume2.id_) + + @unless_coverage + def setUp(self): + super(VolumeAttachmentsAPIIntegration, self).setUp() + + @tags('integration', 'regression', 'positive') + def test_attach_multi_volume_to_server(self): + self.assertEqual( + self.test_attachment1.server_id, self.test_server.id, + "Attachment's Server id and actual Server id did not match") + + self.assertEqual( + self.test_attachment1.volume_id, self.test_volume1.id_, + "Attachment's Volume id and actual Volume id did not match") + + self.assertEqual( + self.test_attachment2.server_id, self.test_server.id, + "Attachment's Server id and actual Server id did not match") + + self.assertEqual( + self.test_attachment2.volume_id, self.test_volume2.id_, + "Attachment's Volume id and actual Volume id did not match") + + resp = self.volume_attachments.client.get_server_volume_attachments( + self.test_server.id) + + self.assertResponseDeserializedAndOk(resp) + attachments = resp.entity + + self.assertIn( + self.test_attachment1, attachments, + "Unable to locate volume attachment {0} in list of server {1}'s" + " volume attachments".format( + self.test_attachment1.id_, self.test_server.id)) + + self.assertIn( + self.test_attachment2, attachments, + "Unable to locate volume attachment {0} in list of server {1}'s" + " volume attachments".format( + self.test_attachment2.id_, self.test_server.id)) + + resp = self.volume_attachments.client.get_volume_attachment_details( + self.test_attachment1.id_, self.test_server.id) + + self.assertResponseDeserializedAndOk(resp) + attachment_details = resp.entity + self.assertDictEqual( + vars(self.test_attachment1), vars(attachment_details)) + + resp = self.volume_attachments.client.get_volume_attachment_details( + self.test_attachment2.id_, self.test_server.id) + + self.assertResponseDeserializedAndOk(resp) + attachment_details = resp.entity + self.assertDictEqual( + vars(self.test_attachment2), vars(attachment_details)) + + @tags('integration', 'regression', 'negative') + def test_attach_single_volume_to_multi_server(self): + resp = self.volume_attachments.client.attach_volume( + self.test_multi_server.id, self.test_volume1.id_) + self.assertExactResponseStatus(resp, 400) + + @tags('integration', 'regression', 'negative') + def test_delete_attached_volume(self): + resp = self.volumes.client.delete_volume( + self.test_volume1.id_) + self.assertExactResponseStatus(resp, 400) + + @tags('integration', 'regression', 'negative') + def test_attach_non_existing_volume(self): + non_existing_volume_id = '12345678' + resp = self.volume_attachments.client.attach_volume( + self.test_server.id, non_existing_volume_id) + self.assertExactResponseStatus(resp, 400) + + @tags('integration', 'regression', 'positive') + def test_volume_attachment_delete(self): + resp = self.volume_attachments.client.delete_volume_attachment( + self.test_attachment1.id_, self.test_server.id) + self.assertExactResponseStatus(resp, 202) + + resp = self.volume_attachments.client.delete_volume_attachment( + self.test_attachment2.id_, self.test_server.id) + self.assertExactResponseStatus(resp, 202) + + @unless_coverage + @classmethod + def tearDownClass(cls): + super(VolumeAttachmentsAPIIntegration, cls).tearDownClass() + + @unless_coverage + def tearDown(self): + super(VolumeAttachmentsAPIIntegration, self).tearDown()