Unit tests for 2.3
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/bb1b8104 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/bb1b8104 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/bb1b8104 Branch: refs/heads/trunk Commit: bb1b810444ba33c11c1bac52151d00477a500123 Parents: e846f57 Author: Samuel Chong <[email protected]> Authored: Wed Nov 16 08:15:09 2016 +1100 Committer: Samuel Chong <[email protected]> Committed: Wed Nov 16 08:15:09 2016 +1100 ---------------------------------------------------------------------- libcloud/compute/drivers/dimensiondata.py | 17 +- libcloud/test/backup/test_dimensiondata.py | 502 --- libcloud/test/backup/test_dimensiondata_v2_3.py | 503 +++ libcloud/test/backup/test_dimensiondata_v2_4.py | 503 +++ .../dimensiondata/2.4/image_customerImage.xml | 50 + ...age_2ffa36c8_1848_49eb_b4fa_9d908775f68c.xml | 17 + ...age_5234e5c7_01de_4411_8b6e_baeb8d91cf5d.xml | 17 + .../dimensiondata/2.4/image_osImage.xml | 34 + ...age_6b4fb0c7_a57b_4f58_b59c_9958f94f971a.xml | 11 + ...age_c14b1a46_2428_44c1_9c1a_b20e6418d08c.xml | 12 + .../dimensiondata/image_customerImage.xml | 59 - ...age_2ffa36c8_1848_49eb_b4fa_9d908775f68c.xml | 21 - ...age_5234e5c7_01de_4411_8b6e_baeb8d91cf5d.xml | 21 - .../fixtures/dimensiondata/image_osImage.xml | 43 - ...age_6b4fb0c7_a57b_4f58_b59c_9958f94f971a.xml | 14 - ...age_c14b1a46_2428_44c1_9c1a_b20e6418d08c.xml | 17 - libcloud/test/compute/test_dimensiondata.py | 3281 ----------------- .../test/compute/test_dimensiondata_v2_3.py | 3282 ++++++++++++++++++ .../test/compute/test_dimensiondata_v2_4.py | 3282 ++++++++++++++++++ .../test/loadbalancer/test_dimensiondata.py | 619 ---- .../loadbalancer/test_dimensiondata_v2_3.py | 620 ++++ .../loadbalancer/test_dimensiondata_v2_4.py | 620 ++++ 22 files changed, 8962 insertions(+), 4583 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/bb1b8104/libcloud/compute/drivers/dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py index d869e0a..ab3a0a7 100644 --- a/libcloud/compute/drivers/dimensiondata.py +++ b/libcloud/compute/drivers/dimensiondata.py @@ -21,6 +21,7 @@ try: except ImportError: from xml.etree import ElementTree as ET +from distutils.version import LooseVersion, StrictVersion from libcloud.common.exceptions import BaseHTTPError from libcloud.compute.base import NodeDriver, Node, NodeAuthPassword from libcloud.compute.base import NodeSize, NodeImage, NodeLocation @@ -2431,7 +2432,8 @@ class DimensionDataNodeDriver(NodeDriver): node_id = self._node_to_node_id(node) # Version 2.3 and lower - if float(self.connection.active_api_version) < 2.4: + if LooseVersion(self.connection.active_api_version) < LooseVersion( + '2.4'): response = self.connection.request_with_orgId_api_1( 'server/%s?clone=%s&desc=%s' % (node_id, image_name, image_description)).object @@ -2469,7 +2471,8 @@ class DimensionDataNodeDriver(NodeDriver): data=ET.tostring(clone_server_elem)).object # Version 2.3 and lower - if float(self.connection.active_api_version) < 2.4: + if LooseVersion(self.connection.active_api_version) < LooseVersion( + '2.4'): response_code = findtext(response, 'result', GENERAL_NS) else: response_code = findtext(response, 'responseCode', TYPES_URN) @@ -3628,7 +3631,8 @@ class DimensionDataNodeDriver(NodeDriver): is_guest_os_customization=None, tagkey_name_value_dictionaries=None): # Unsupported for version lower than 2.4 - if float(self.connection.active_api_version) < 2.4: + if LooseVersion(self.connection.active_api_version) < LooseVersion( + '2.4'): raise Exception("import image is feature is NOT supported in " \ "api version earlier than 2.4") else: @@ -3686,7 +3690,6 @@ class DimensionDataNodeDriver(NodeDriver): response_code = findtext(response, 'responseCode', TYPES_URN) return response_code in ['IN_PROGRESS', 'OK'] - def _format_csv(self, http_response): text = http_response.read() lines = str.splitlines(ensure_string(text)) @@ -3764,7 +3767,8 @@ class DimensionDataNodeDriver(NodeDriver): cpu_spec = self._to_cpu_spec(element.find(fixxpath('cpu', TYPES_URN))) - if float(self.connection.active_api_version) > 2.3: + if LooseVersion(self.connection.active_api_version) > LooseVersion( + '2.3'): os_el = element.find(fixxpath('guest/operatingSystem', TYPES_URN)) else: os_el = element.find(fixxpath('operatingSystem', TYPES_URN)) @@ -4052,7 +4056,8 @@ class DimensionDataNodeDriver(NodeDriver): disks = self._to_disks(element) # Version 2.3 or earlier - if float(self.connection.active_api_version) < 2.4: + if LooseVersion(self.connection.active_api_version) < LooseVersion( + '2.4'): vmware_tools = self._to_vmware_tools( element.find(fixxpath('vmwareTools', TYPES_URN))) operation_system = element.find(fixxpath( http://git-wip-us.apache.org/repos/asf/libcloud/blob/bb1b8104/libcloud/test/backup/test_dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/test/backup/test_dimensiondata.py b/libcloud/test/backup/test_dimensiondata.py deleted file mode 100644 index 3214cff..0000000 --- a/libcloud/test/backup/test_dimensiondata.py +++ /dev/null @@ -1,502 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -try: - from lxml import etree as ET -except ImportError: - from xml.etree import ElementTree as ET - -import sys -from libcloud.utils.py3 import httplib - -from libcloud.common.dimensiondata import DimensionDataAPIException -from libcloud.common.types import InvalidCredsError -from libcloud.backup.base import BackupTargetJob -from libcloud.backup.drivers.dimensiondata import DimensionDataBackupDriver as DimensionData -from libcloud.backup.drivers.dimensiondata import DEFAULT_BACKUP_PLAN - -from libcloud.test import MockHttp, unittest -from libcloud.test.backup import TestCaseMixin -from libcloud.test.file_fixtures import BackupFileFixtures - -from libcloud.test.secrets import DIMENSIONDATA_PARAMS - - -class DimensionDataTests(unittest.TestCase, TestCaseMixin): - - def setUp(self): - DimensionData.connectionCls.conn_classes = (None, DimensionDataMockHttp) - DimensionDataMockHttp.type = None - self.driver = DimensionData(*DIMENSIONDATA_PARAMS) - - def test_invalid_region(self): - with self.assertRaises(ValueError): - self.driver = DimensionData(*DIMENSIONDATA_PARAMS, region='blah') - - def test_invalid_creds(self): - DimensionDataMockHttp.type = 'UNAUTHORIZED' - with self.assertRaises(InvalidCredsError): - self.driver.list_targets() - - def test_list_targets(self): - targets = self.driver.list_targets() - self.assertEqual(len(targets), 2) - self.assertEqual(targets[0].id, '5579f3a7-4c32-4cf5-8a7e-b45c36a35c10') - self.assertEqual(targets[0].address, 'e75ead52-692f-4314-8725-c8a4f4d13a87') - self.assertEqual(targets[0].extra['servicePlan'], 'Enterprise') - - def test_create_target(self): - target = self.driver.create_target( - 'name', - 'e75ead52-692f-4314-8725-c8a4f4d13a87', - extra={'servicePlan': 'Enterprise'}) - self.assertEqual(target.id, 'ee7c4b64-f7af-4a4f-8384-be362273530f') - self.assertEqual(target.address, 'e75ead52-692f-4314-8725-c8a4f4d13a87') - self.assertEqual(target.extra['servicePlan'], 'Enterprise') - - def test_create_target_DEFAULT(self): - DimensionDataMockHttp.type = 'DEFAULT' - target = self.driver.create_target( - 'name', - 'e75ead52-692f-4314-8725-c8a4f4d13a87') - self.assertEqual(target.id, 'ee7c4b64-f7af-4a4f-8384-be362273530f') - self.assertEqual(target.address, 'e75ead52-692f-4314-8725-c8a4f4d13a87') - - def test_create_target_EXISTS(self): - DimensionDataMockHttp.type = 'EXISTS' - with self.assertRaises(DimensionDataAPIException) as context: - self.driver.create_target( - 'name', - 'e75ead52-692f-4314-8725-c8a4f4d13a87', - extra={'servicePlan': 'Enterprise'}) - self.assertEqual(context.exception.code, 'ERROR') - self.assertEqual(context.exception.msg, 'Cloud backup for this server is already enabled or being enabled (state: NORMAL).') - - def test_update_target(self): - target = self.driver.list_targets()[0] - extra = {'servicePlan': 'Essentials'} - new_target = self.driver.update_target(target, extra=extra) - self.assertEqual(new_target.extra['servicePlan'], 'Essentials') - - def test_update_target_DEFAULT(self): - DimensionDataMockHttp.type = 'DEFAULT' - target = 'e75ead52-692f-4314-8725-c8a4f4d13a87' - self.driver.update_target(target) - - def test_update_target_STR(self): - target = 'e75ead52-692f-4314-8725-c8a4f4d13a87' - extra = {'servicePlan': 'Essentials'} - new_target = self.driver.update_target(target, extra=extra) - self.assertEqual(new_target.extra['servicePlan'], 'Essentials') - - def test_delete_target(self): - target = self.driver.list_targets()[0] - self.assertTrue(self.driver.delete_target(target)) - - def test_ex_add_client_to_target(self): - target = self.driver.list_targets()[0] - client = self.driver.ex_list_available_client_types(target)[0] - storage_policy = self.driver.ex_list_available_storage_policies(target)[0] - schedule_policy = self.driver.ex_list_available_schedule_policies(target)[0] - self.assertTrue( - self.driver.ex_add_client_to_target(target, client, storage_policy, - schedule_policy, 'ON_FAILURE', '[email protected]') - ) - - def test_ex_add_client_to_target_STR(self): - self.assertTrue( - self.driver.ex_add_client_to_target('e75ead52-692f-4314-8725-c8a4f4d13a87', 'FA.Linux', '14 Day Storage Policy', - '12AM - 6AM', 'ON_FAILURE', '[email protected]') - ) - - def test_ex_get_backup_details_for_target(self): - target = self.driver.list_targets()[0] - response = self.driver.ex_get_backup_details_for_target(target) - self.assertEqual(response.service_plan, 'Enterprise') - client = response.clients[0] - self.assertEqual(client.id, '30b1ff76-c76d-4d7c-b39d-3b72be0384c8') - self.assertEqual(client.type.type, 'FA.Linux') - self.assertEqual(client.running_job.progress, 5) - self.assertTrue(isinstance(client.running_job, BackupTargetJob)) - self.assertEqual(len(client.alert.notify_list), 2) - self.assertTrue(isinstance(client.alert.notify_list, list)) - - def test_ex_get_backup_details_for_target_NOBACKUP(self): - target = self.driver.list_targets()[0].address - DimensionDataMockHttp.type = 'NOBACKUP' - response = self.driver.ex_get_backup_details_for_target(target) - self.assertTrue(response is None) - - def test_ex_cancel_target_job(self): - target = self.driver.list_targets()[0] - response = self.driver.ex_get_backup_details_for_target(target) - client = response.clients[0] - self.assertTrue(isinstance(client.running_job, BackupTargetJob)) - success = client.running_job.cancel() - self.assertTrue(success) - - def test_ex_cancel_target_job_with_extras(self): - success = self.driver.cancel_target_job( - None, - ex_client='30b1ff76_c76d_4d7c_b39d_3b72be0384c8', - ex_target='e75ead52_692f_4314_8725_c8a4f4d13a87' - ) - self.assertTrue(success) - - def test_ex_cancel_target_job_FAIL(self): - DimensionDataMockHttp.type = 'FAIL' - with self.assertRaises(DimensionDataAPIException) as context: - self.driver.cancel_target_job( - None, - ex_client='30b1ff76_c76d_4d7c_b39d_3b72be0384c8', - ex_target='e75ead52_692f_4314_8725_c8a4f4d13a87' - ) - self.assertEqual(context.exception.code, 'ERROR') - - """Test a backup info for a target that does not have a client""" - def test_ex_get_backup_details_for_target_NO_CLIENT(self): - DimensionDataMockHttp.type = 'NOCLIENT' - response = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87') - self.assertEqual(response.service_plan, 'Essentials') - self.assertEqual(len(response.clients), 0) - - """Test a backup details that has a client, but no alerting or running jobs""" - def test_ex_get_backup_details_for_target_NO_JOB_OR_ALERT(self): - DimensionDataMockHttp.type = 'NOJOB' - response = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314_8725-c8a4f4d13a87') - self.assertEqual(response.service_plan, 'Enterprise') - self.assertTrue(isinstance(response.clients, list)) - self.assertEqual(len(response.clients), 1) - client = response.clients[0] - self.assertEqual(client.id, '30b1ff76-c76d-4d7c-b39d-3b72be0384c8') - self.assertEqual(client.type.type, 'FA.Linux') - self.assertIsNone(client.running_job) - self.assertIsNone(client.alert) - - """Test getting backup info for a server that doesn't exist""" - def test_ex_get_backup_details_for_target_DISABLED(self): - DimensionDataMockHttp.type = 'DISABLED' - with self.assertRaises(DimensionDataAPIException) as context: - self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87') - self.assertEqual(context.exception.code, 'ERROR') - self.assertEqual(context.exception.msg, 'Server e75ead52-692f-4314-8725-c8a4f4d13a87 has not been provisioned for backup') - - def test_ex_list_available_client_types(self): - target = self.driver.list_targets()[0] - answer = self.driver.ex_list_available_client_types(target) - self.assertEqual(len(answer), 1) - self.assertEqual(answer[0].type, 'FA.Linux') - self.assertEqual(answer[0].is_file_system, True) - self.assertEqual(answer[0].description, 'Linux File system') - - def test_ex_list_available_storage_policies(self): - target = self.driver.list_targets()[0] - answer = self.driver.ex_list_available_storage_policies(target) - self.assertEqual(len(answer), 1) - self.assertEqual(answer[0].name, - '30 Day Storage Policy + Secondary Copy') - self.assertEqual(answer[0].retention_period, 30) - self.assertEqual(answer[0].secondary_location, 'Primary') - - def test_ex_list_available_schedule_policies(self): - target = self.driver.list_targets()[0] - answer = self.driver.ex_list_available_schedule_policies(target) - self.assertEqual(len(answer), 1) - self.assertEqual(answer[0].name, '12AM - 6AM') - self.assertEqual(answer[0].description, 'Daily backup will start between 12AM - 6AM') - - def test_ex_remove_client_from_target(self): - target = self.driver.list_targets()[0] - client = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87').clients[0] - self.assertTrue(self.driver.ex_remove_client_from_target(target, client)) - - def test_ex_remove_client_from_target_STR(self): - self.assertTrue( - self.driver.ex_remove_client_from_target( - 'e75ead52-692f-4314-8725-c8a4f4d13a87', - '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' - ) - ) - - def test_ex_remove_client_from_target_FAIL(self): - DimensionDataMockHttp.type = 'FAIL' - with self.assertRaises(DimensionDataAPIException) as context: - self.driver.ex_remove_client_from_target( - 'e75ead52-692f-4314-8725-c8a4f4d13a87', - '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' - ) - self.assertEqual(context.exception.code, 'ERROR') - self.assertTrue('Backup Client is currently performing another operation' in context.exception.msg) - - def test_priv_target_to_target_address(self): - target = self.driver.list_targets()[0] - self.assertEqual( - self.driver._target_to_target_address(target), - 'e75ead52-692f-4314-8725-c8a4f4d13a87' - ) - - def test_priv_target_to_target_address_STR(self): - self.assertEqual( - self.driver._target_to_target_address('e75ead52-692f-4314-8725-c8a4f4d13a87'), - 'e75ead52-692f-4314-8725-c8a4f4d13a87' - ) - - def test_priv_target_to_target_address_TYPEERROR(self): - with self.assertRaises(TypeError): - self.driver._target_to_target_address([1, 2, 3]) - - def test_priv_client_to_client_id(self): - client = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87').clients[0] - self.assertEqual( - self.driver._client_to_client_id(client), - '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' - ) - - def test_priv_client_to_client_id_STR(self): - self.assertEqual( - self.driver._client_to_client_id('30b1ff76-c76d-4d7c-b39d-3b72be0384c8'), - '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' - ) - - def test_priv_client_to_client_id_TYPEERROR(self): - with self.assertRaises(TypeError): - self.driver._client_to_client_id([1, 2, 3]) - - -class InvalidRequestError(Exception): - def __init__(self, tag): - super(InvalidRequestError, self).__init__("Invalid Request - %s" % tag) - - -class DimensionDataMockHttp(MockHttp): - - fixtures = BackupFileFixtures('dimensiondata') - - def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers): - return (httplib.UNAUTHORIZED, "", {}, httplib.responses[httplib.UNAUTHORIZED]) - - def _oec_0_9_myaccount(self, method, url, body, headers): - body = self.fixtures.load('oec_0_9_myaccount.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_myaccount_EXISTS(self, method, url, body, headers): - body = self.fixtures.load('oec_0_9_myaccount.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_myaccount_DEFAULT(self, method, url, body, headers): - body = self.fixtures.load('oec_0_9_myaccount.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_myaccount_INPROGRESS(self, method, url, body, headers): - body = self.fixtures.load('oec_0_9_myaccount.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_myaccount_FAIL(self, method, url, body, headers): - body = self.fixtures.load('oec_0_9_myaccount.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_myaccount_NOCLIENT(self, method, url, body, headers): - body = self.fixtures.load('oec_0_9_myaccount.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_myaccount_DISABLED(self, method, url, body, headers): - body = self.fixtures.load('oec_0_9_myaccount.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_myaccount_NOJOB(self, method, url, body, headers): - body = self.fixtures.load('oec_0_9_myaccount.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87(self, method, url, body, headers): - body = self.fixtures.load( - 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT(self, method, url, body, headers): - body = self.fixtures.load( - 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_NOCLIENT(self, method, url, body, headers): - body = self.fixtures.load( - 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_NOJOB(self, method, url, body, headers): - body = self.fixtures.load( - 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DISABLED(self, method, url, body, headers): - body = self.fixtures.load( - 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server(self, method, url, body, headers): - body = self.fixtures.load( - 'server_server.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_type(self, method, url, body, headers): - body = self.fixtures.load( - '_backup_client_type.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_storagePolicy( - self, method, url, body, headers): - body = self.fixtures.load( - '_backup_client_storagePolicy.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_schedulePolicy( - self, method, url, body, headers): - body = self.fixtures.load( - '_backup_client_schedulePolicy.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client( - self, method, url, body, headers): - if method == 'POST': - body = self.fixtures.load( - '_backup_client_SUCCESS_PUT.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - else: - raise ValueError("Unknown Method {0}".format(method)) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_NOCLIENT( - self, method, url, body, headers): - # only gets here are implemented - # If we get any other method something has gone wrong - assert(method == 'GET') - body = self.fixtures.load( - '_backup_INFO_NOCLIENT.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_DISABLED( - self, method, url, body, headers): - # only gets here are implemented - # If we get any other method something has gone wrong - assert(method == 'GET') - body = self.fixtures.load( - '_backup_INFO_DISABLED.xml') - return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_NOJOB( - self, method, url, body, headers): - # only gets here are implemented - # If we get any other method something has gone wrong - assert(method == 'GET') - body = self.fixtures.load( - '_backup_INFO_NOJOB.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_DEFAULT( - self, method, url, body, headers): - if method != 'POST': - raise InvalidRequestError('Only POST is accepted for this test') - request = ET.fromstring(body) - service_plan = request.get('servicePlan') - if service_plan != DEFAULT_BACKUP_PLAN: - raise InvalidRequestError('The default plan %s should have been passed in. Not %s' % (DEFAULT_BACKUP_PLAN, service_plan)) - body = self.fixtures.load( - '_backup_ENABLE.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup( - self, method, url, body, headers): - if method == 'POST': - body = self.fixtures.load( - '_backup_ENABLE.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - elif method == 'GET': - if url.endswith('disable'): - body = self.fixtures.load( - '_backup_DISABLE.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - body = self.fixtures.load( - '_backup_INFO.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - else: - raise ValueError("Unknown Method {0}".format(method)) - - def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_NOBACKUP( - self, method, url, body, headers): - assert(method == 'GET') - body = self.fixtures.load('server_server_NOBACKUP.xml') - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_EXISTS( - self, method, url, body, headers): - # only POSTs are implemented - # If we get any other method something has gone wrong - assert(method == 'POST') - body = self.fixtures.load( - '_backup_EXISTS.xml') - return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_modify( - self, method, url, body, headers): - request = ET.fromstring(body) - service_plan = request.get('servicePlan') - if service_plan != 'Essentials': - raise InvalidRequestError("Expected Essentials backup plan in request") - body = self.fixtures.load('_backup_modify.xml') - - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_modify_DEFAULT( - self, method, url, body, headers): - request = ET.fromstring(body) - service_plan = request.get('servicePlan') - if service_plan != DEFAULT_BACKUP_PLAN: - raise InvalidRequestError("Expected % backup plan in test" % DEFAULT_BACKUP_PLAN) - body = self.fixtures.load('_backup_modify.xml') - - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8( - self, method, url, body, headers): - if url.endswith('disable'): - body = self.fixtures.load( - ('_remove_backup_client.xml') - ) - elif url.endswith('cancelJob'): - body = self.fixtures.load( - ('' - '_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8_cancelJob.xml') - ) - else: - raise ValueError("Unknown URL: %s" % url) - return (httplib.OK, body, {}, httplib.responses[httplib.OK]) - - def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8_FAIL( - self, method, url, body, headers): - if url.endswith('disable'): - body = self.fixtures.load( - ('_remove_backup_client_FAIL.xml') - ) - elif url.endswith('cancelJob'): - body = self.fixtures.load( - ('' - '_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8_cancelJob_FAIL.xml') - ) - else: - raise ValueError("Unknown URL: %s" % url) - return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) - - -if __name__ == '__main__': - sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/bb1b8104/libcloud/test/backup/test_dimensiondata_v2_3.py ---------------------------------------------------------------------- diff --git a/libcloud/test/backup/test_dimensiondata_v2_3.py b/libcloud/test/backup/test_dimensiondata_v2_3.py new file mode 100644 index 0000000..ae05316 --- /dev/null +++ b/libcloud/test/backup/test_dimensiondata_v2_3.py @@ -0,0 +1,503 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +try: + from lxml import etree as ET +except ImportError: + from xml.etree import ElementTree as ET + +import sys +from libcloud.utils.py3 import httplib + +from libcloud.common.dimensiondata import DimensionDataAPIException +from libcloud.common.types import InvalidCredsError +from libcloud.backup.base import BackupTargetJob +from libcloud.backup.drivers.dimensiondata import DimensionDataBackupDriver as DimensionData +from libcloud.backup.drivers.dimensiondata import DEFAULT_BACKUP_PLAN + +from libcloud.test import MockHttp, unittest +from libcloud.test.backup import TestCaseMixin +from libcloud.test.file_fixtures import BackupFileFixtures + +from libcloud.test.secrets import DIMENSIONDATA_PARAMS + + +class DimensionDataTests(unittest.TestCase, TestCaseMixin): + + def setUp(self): + DimensionData.connectionCls.active_api_version = '2.3' + DimensionData.connectionCls.conn_classes = (None, DimensionDataMockHttp) + DimensionDataMockHttp.type = None + self.driver = DimensionData(*DIMENSIONDATA_PARAMS) + + def test_invalid_region(self): + with self.assertRaises(ValueError): + self.driver = DimensionData(*DIMENSIONDATA_PARAMS, region='blah') + + def test_invalid_creds(self): + DimensionDataMockHttp.type = 'UNAUTHORIZED' + with self.assertRaises(InvalidCredsError): + self.driver.list_targets() + + def test_list_targets(self): + targets = self.driver.list_targets() + self.assertEqual(len(targets), 2) + self.assertEqual(targets[0].id, '5579f3a7-4c32-4cf5-8a7e-b45c36a35c10') + self.assertEqual(targets[0].address, 'e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(targets[0].extra['servicePlan'], 'Enterprise') + + def test_create_target(self): + target = self.driver.create_target( + 'name', + 'e75ead52-692f-4314-8725-c8a4f4d13a87', + extra={'servicePlan': 'Enterprise'}) + self.assertEqual(target.id, 'ee7c4b64-f7af-4a4f-8384-be362273530f') + self.assertEqual(target.address, 'e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(target.extra['servicePlan'], 'Enterprise') + + def test_create_target_DEFAULT(self): + DimensionDataMockHttp.type = 'DEFAULT' + target = self.driver.create_target( + 'name', + 'e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(target.id, 'ee7c4b64-f7af-4a4f-8384-be362273530f') + self.assertEqual(target.address, 'e75ead52-692f-4314-8725-c8a4f4d13a87') + + def test_create_target_EXISTS(self): + DimensionDataMockHttp.type = 'EXISTS' + with self.assertRaises(DimensionDataAPIException) as context: + self.driver.create_target( + 'name', + 'e75ead52-692f-4314-8725-c8a4f4d13a87', + extra={'servicePlan': 'Enterprise'}) + self.assertEqual(context.exception.code, 'ERROR') + self.assertEqual(context.exception.msg, 'Cloud backup for this server is already enabled or being enabled (state: NORMAL).') + + def test_update_target(self): + target = self.driver.list_targets()[0] + extra = {'servicePlan': 'Essentials'} + new_target = self.driver.update_target(target, extra=extra) + self.assertEqual(new_target.extra['servicePlan'], 'Essentials') + + def test_update_target_DEFAULT(self): + DimensionDataMockHttp.type = 'DEFAULT' + target = 'e75ead52-692f-4314-8725-c8a4f4d13a87' + self.driver.update_target(target) + + def test_update_target_STR(self): + target = 'e75ead52-692f-4314-8725-c8a4f4d13a87' + extra = {'servicePlan': 'Essentials'} + new_target = self.driver.update_target(target, extra=extra) + self.assertEqual(new_target.extra['servicePlan'], 'Essentials') + + def test_delete_target(self): + target = self.driver.list_targets()[0] + self.assertTrue(self.driver.delete_target(target)) + + def test_ex_add_client_to_target(self): + target = self.driver.list_targets()[0] + client = self.driver.ex_list_available_client_types(target)[0] + storage_policy = self.driver.ex_list_available_storage_policies(target)[0] + schedule_policy = self.driver.ex_list_available_schedule_policies(target)[0] + self.assertTrue( + self.driver.ex_add_client_to_target(target, client, storage_policy, + schedule_policy, 'ON_FAILURE', '[email protected]') + ) + + def test_ex_add_client_to_target_STR(self): + self.assertTrue( + self.driver.ex_add_client_to_target('e75ead52-692f-4314-8725-c8a4f4d13a87', 'FA.Linux', '14 Day Storage Policy', + '12AM - 6AM', 'ON_FAILURE', '[email protected]') + ) + + def test_ex_get_backup_details_for_target(self): + target = self.driver.list_targets()[0] + response = self.driver.ex_get_backup_details_for_target(target) + self.assertEqual(response.service_plan, 'Enterprise') + client = response.clients[0] + self.assertEqual(client.id, '30b1ff76-c76d-4d7c-b39d-3b72be0384c8') + self.assertEqual(client.type.type, 'FA.Linux') + self.assertEqual(client.running_job.progress, 5) + self.assertTrue(isinstance(client.running_job, BackupTargetJob)) + self.assertEqual(len(client.alert.notify_list), 2) + self.assertTrue(isinstance(client.alert.notify_list, list)) + + def test_ex_get_backup_details_for_target_NOBACKUP(self): + target = self.driver.list_targets()[0].address + DimensionDataMockHttp.type = 'NOBACKUP' + response = self.driver.ex_get_backup_details_for_target(target) + self.assertTrue(response is None) + + def test_ex_cancel_target_job(self): + target = self.driver.list_targets()[0] + response = self.driver.ex_get_backup_details_for_target(target) + client = response.clients[0] + self.assertTrue(isinstance(client.running_job, BackupTargetJob)) + success = client.running_job.cancel() + self.assertTrue(success) + + def test_ex_cancel_target_job_with_extras(self): + success = self.driver.cancel_target_job( + None, + ex_client='30b1ff76_c76d_4d7c_b39d_3b72be0384c8', + ex_target='e75ead52_692f_4314_8725_c8a4f4d13a87' + ) + self.assertTrue(success) + + def test_ex_cancel_target_job_FAIL(self): + DimensionDataMockHttp.type = 'FAIL' + with self.assertRaises(DimensionDataAPIException) as context: + self.driver.cancel_target_job( + None, + ex_client='30b1ff76_c76d_4d7c_b39d_3b72be0384c8', + ex_target='e75ead52_692f_4314_8725_c8a4f4d13a87' + ) + self.assertEqual(context.exception.code, 'ERROR') + + """Test a backup info for a target that does not have a client""" + def test_ex_get_backup_details_for_target_NO_CLIENT(self): + DimensionDataMockHttp.type = 'NOCLIENT' + response = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(response.service_plan, 'Essentials') + self.assertEqual(len(response.clients), 0) + + """Test a backup details that has a client, but no alerting or running jobs""" + def test_ex_get_backup_details_for_target_NO_JOB_OR_ALERT(self): + DimensionDataMockHttp.type = 'NOJOB' + response = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314_8725-c8a4f4d13a87') + self.assertEqual(response.service_plan, 'Enterprise') + self.assertTrue(isinstance(response.clients, list)) + self.assertEqual(len(response.clients), 1) + client = response.clients[0] + self.assertEqual(client.id, '30b1ff76-c76d-4d7c-b39d-3b72be0384c8') + self.assertEqual(client.type.type, 'FA.Linux') + self.assertIsNone(client.running_job) + self.assertIsNone(client.alert) + + """Test getting backup info for a server that doesn't exist""" + def test_ex_get_backup_details_for_target_DISABLED(self): + DimensionDataMockHttp.type = 'DISABLED' + with self.assertRaises(DimensionDataAPIException) as context: + self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(context.exception.code, 'ERROR') + self.assertEqual(context.exception.msg, 'Server e75ead52-692f-4314-8725-c8a4f4d13a87 has not been provisioned for backup') + + def test_ex_list_available_client_types(self): + target = self.driver.list_targets()[0] + answer = self.driver.ex_list_available_client_types(target) + self.assertEqual(len(answer), 1) + self.assertEqual(answer[0].type, 'FA.Linux') + self.assertEqual(answer[0].is_file_system, True) + self.assertEqual(answer[0].description, 'Linux File system') + + def test_ex_list_available_storage_policies(self): + target = self.driver.list_targets()[0] + answer = self.driver.ex_list_available_storage_policies(target) + self.assertEqual(len(answer), 1) + self.assertEqual(answer[0].name, + '30 Day Storage Policy + Secondary Copy') + self.assertEqual(answer[0].retention_period, 30) + self.assertEqual(answer[0].secondary_location, 'Primary') + + def test_ex_list_available_schedule_policies(self): + target = self.driver.list_targets()[0] + answer = self.driver.ex_list_available_schedule_policies(target) + self.assertEqual(len(answer), 1) + self.assertEqual(answer[0].name, '12AM - 6AM') + self.assertEqual(answer[0].description, 'Daily backup will start between 12AM - 6AM') + + def test_ex_remove_client_from_target(self): + target = self.driver.list_targets()[0] + client = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87').clients[0] + self.assertTrue(self.driver.ex_remove_client_from_target(target, client)) + + def test_ex_remove_client_from_target_STR(self): + self.assertTrue( + self.driver.ex_remove_client_from_target( + 'e75ead52-692f-4314-8725-c8a4f4d13a87', + '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' + ) + ) + + def test_ex_remove_client_from_target_FAIL(self): + DimensionDataMockHttp.type = 'FAIL' + with self.assertRaises(DimensionDataAPIException) as context: + self.driver.ex_remove_client_from_target( + 'e75ead52-692f-4314-8725-c8a4f4d13a87', + '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' + ) + self.assertEqual(context.exception.code, 'ERROR') + self.assertTrue('Backup Client is currently performing another operation' in context.exception.msg) + + def test_priv_target_to_target_address(self): + target = self.driver.list_targets()[0] + self.assertEqual( + self.driver._target_to_target_address(target), + 'e75ead52-692f-4314-8725-c8a4f4d13a87' + ) + + def test_priv_target_to_target_address_STR(self): + self.assertEqual( + self.driver._target_to_target_address('e75ead52-692f-4314-8725-c8a4f4d13a87'), + 'e75ead52-692f-4314-8725-c8a4f4d13a87' + ) + + def test_priv_target_to_target_address_TYPEERROR(self): + with self.assertRaises(TypeError): + self.driver._target_to_target_address([1, 2, 3]) + + def test_priv_client_to_client_id(self): + client = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87').clients[0] + self.assertEqual( + self.driver._client_to_client_id(client), + '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' + ) + + def test_priv_client_to_client_id_STR(self): + self.assertEqual( + self.driver._client_to_client_id('30b1ff76-c76d-4d7c-b39d-3b72be0384c8'), + '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' + ) + + def test_priv_client_to_client_id_TYPEERROR(self): + with self.assertRaises(TypeError): + self.driver._client_to_client_id([1, 2, 3]) + + +class InvalidRequestError(Exception): + def __init__(self, tag): + super(InvalidRequestError, self).__init__("Invalid Request - %s" % tag) + + +class DimensionDataMockHttp(MockHttp): + + fixtures = BackupFileFixtures('dimensiondata') + + def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers): + return (httplib.UNAUTHORIZED, "", {}, httplib.responses[httplib.UNAUTHORIZED]) + + def _oec_0_9_myaccount(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_EXISTS(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_DEFAULT(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_INPROGRESS(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_FAIL(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_NOCLIENT(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_DISABLED(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_NOJOB(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_3_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_3_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_3_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_NOCLIENT(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_3_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_NOJOB(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_3_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DISABLED(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_3_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_type(self, method, url, body, headers): + body = self.fixtures.load( + '_backup_client_type.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_storagePolicy( + self, method, url, body, headers): + body = self.fixtures.load( + '_backup_client_storagePolicy.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_schedulePolicy( + self, method, url, body, headers): + body = self.fixtures.load( + '_backup_client_schedulePolicy.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client( + self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load( + '_backup_client_SUCCESS_PUT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + else: + raise ValueError("Unknown Method {0}".format(method)) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_NOCLIENT( + self, method, url, body, headers): + # only gets here are implemented + # If we get any other method something has gone wrong + assert(method == 'GET') + body = self.fixtures.load( + '_backup_INFO_NOCLIENT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_DISABLED( + self, method, url, body, headers): + # only gets here are implemented + # If we get any other method something has gone wrong + assert(method == 'GET') + body = self.fixtures.load( + '_backup_INFO_DISABLED.xml') + return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_NOJOB( + self, method, url, body, headers): + # only gets here are implemented + # If we get any other method something has gone wrong + assert(method == 'GET') + body = self.fixtures.load( + '_backup_INFO_NOJOB.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_DEFAULT( + self, method, url, body, headers): + if method != 'POST': + raise InvalidRequestError('Only POST is accepted for this test') + request = ET.fromstring(body) + service_plan = request.get('servicePlan') + if service_plan != DEFAULT_BACKUP_PLAN: + raise InvalidRequestError('The default plan %s should have been passed in. Not %s' % (DEFAULT_BACKUP_PLAN, service_plan)) + body = self.fixtures.load( + '_backup_ENABLE.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup( + self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load( + '_backup_ENABLE.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + elif method == 'GET': + if url.endswith('disable'): + body = self.fixtures.load( + '_backup_DISABLE.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + body = self.fixtures.load( + '_backup_INFO.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + else: + raise ValueError("Unknown Method {0}".format(method)) + + def _caas_2_3_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_NOBACKUP( + self, method, url, body, headers): + assert(method == 'GET') + body = self.fixtures.load('server_server_NOBACKUP.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_EXISTS( + self, method, url, body, headers): + # only POSTs are implemented + # If we get any other method something has gone wrong + assert(method == 'POST') + body = self.fixtures.load( + '_backup_EXISTS.xml') + return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_modify( + self, method, url, body, headers): + request = ET.fromstring(body) + service_plan = request.get('servicePlan') + if service_plan != 'Essentials': + raise InvalidRequestError("Expected Essentials backup plan in request") + body = self.fixtures.load('_backup_modify.xml') + + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_modify_DEFAULT( + self, method, url, body, headers): + request = ET.fromstring(body) + service_plan = request.get('servicePlan') + if service_plan != DEFAULT_BACKUP_PLAN: + raise InvalidRequestError("Expected % backup plan in test" % DEFAULT_BACKUP_PLAN) + body = self.fixtures.load('_backup_modify.xml') + + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8( + self, method, url, body, headers): + if url.endswith('disable'): + body = self.fixtures.load( + ('_remove_backup_client.xml') + ) + elif url.endswith('cancelJob'): + body = self.fixtures.load( + ('' + '_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8_cancelJob.xml') + ) + else: + raise ValueError("Unknown URL: %s" % url) + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8_FAIL( + self, method, url, body, headers): + if url.endswith('disable'): + body = self.fixtures.load( + ('_remove_backup_client_FAIL.xml') + ) + elif url.endswith('cancelJob'): + body = self.fixtures.load( + ('' + '_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8_cancelJob_FAIL.xml') + ) + else: + raise ValueError("Unknown URL: %s" % url) + return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) + + +if __name__ == '__main__': + sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/bb1b8104/libcloud/test/backup/test_dimensiondata_v2_4.py ---------------------------------------------------------------------- diff --git a/libcloud/test/backup/test_dimensiondata_v2_4.py b/libcloud/test/backup/test_dimensiondata_v2_4.py new file mode 100644 index 0000000..d5da857 --- /dev/null +++ b/libcloud/test/backup/test_dimensiondata_v2_4.py @@ -0,0 +1,503 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +try: + from lxml import etree as ET +except ImportError: + from xml.etree import ElementTree as ET + +import sys +from libcloud.utils.py3 import httplib + +from libcloud.common.dimensiondata import DimensionDataAPIException +from libcloud.common.types import InvalidCredsError +from libcloud.backup.base import BackupTargetJob +from libcloud.backup.drivers.dimensiondata import DimensionDataBackupDriver as DimensionData +from libcloud.backup.drivers.dimensiondata import DEFAULT_BACKUP_PLAN + +from libcloud.test import MockHttp, unittest +from libcloud.test.backup import TestCaseMixin +from libcloud.test.file_fixtures import BackupFileFixtures + +from libcloud.test.secrets import DIMENSIONDATA_PARAMS + + +class DimensionDataTests(unittest.TestCase, TestCaseMixin): + + def setUp(self): + DimensionData.connectionCls.active_api_version = '2.4' + DimensionData.connectionCls.conn_classes = (None, DimensionDataMockHttp) + DimensionDataMockHttp.type = None + self.driver = DimensionData(*DIMENSIONDATA_PARAMS) + + def test_invalid_region(self): + with self.assertRaises(ValueError): + self.driver = DimensionData(*DIMENSIONDATA_PARAMS, region='blah') + + def test_invalid_creds(self): + DimensionDataMockHttp.type = 'UNAUTHORIZED' + with self.assertRaises(InvalidCredsError): + self.driver.list_targets() + + def test_list_targets(self): + targets = self.driver.list_targets() + self.assertEqual(len(targets), 2) + self.assertEqual(targets[0].id, '5579f3a7-4c32-4cf5-8a7e-b45c36a35c10') + self.assertEqual(targets[0].address, 'e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(targets[0].extra['servicePlan'], 'Enterprise') + + def test_create_target(self): + target = self.driver.create_target( + 'name', + 'e75ead52-692f-4314-8725-c8a4f4d13a87', + extra={'servicePlan': 'Enterprise'}) + self.assertEqual(target.id, 'ee7c4b64-f7af-4a4f-8384-be362273530f') + self.assertEqual(target.address, 'e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(target.extra['servicePlan'], 'Enterprise') + + def test_create_target_DEFAULT(self): + DimensionDataMockHttp.type = 'DEFAULT' + target = self.driver.create_target( + 'name', + 'e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(target.id, 'ee7c4b64-f7af-4a4f-8384-be362273530f') + self.assertEqual(target.address, 'e75ead52-692f-4314-8725-c8a4f4d13a87') + + def test_create_target_EXISTS(self): + DimensionDataMockHttp.type = 'EXISTS' + with self.assertRaises(DimensionDataAPIException) as context: + self.driver.create_target( + 'name', + 'e75ead52-692f-4314-8725-c8a4f4d13a87', + extra={'servicePlan': 'Enterprise'}) + self.assertEqual(context.exception.code, 'ERROR') + self.assertEqual(context.exception.msg, 'Cloud backup for this server is already enabled or being enabled (state: NORMAL).') + + def test_update_target(self): + target = self.driver.list_targets()[0] + extra = {'servicePlan': 'Essentials'} + new_target = self.driver.update_target(target, extra=extra) + self.assertEqual(new_target.extra['servicePlan'], 'Essentials') + + def test_update_target_DEFAULT(self): + DimensionDataMockHttp.type = 'DEFAULT' + target = 'e75ead52-692f-4314-8725-c8a4f4d13a87' + self.driver.update_target(target) + + def test_update_target_STR(self): + target = 'e75ead52-692f-4314-8725-c8a4f4d13a87' + extra = {'servicePlan': 'Essentials'} + new_target = self.driver.update_target(target, extra=extra) + self.assertEqual(new_target.extra['servicePlan'], 'Essentials') + + def test_delete_target(self): + target = self.driver.list_targets()[0] + self.assertTrue(self.driver.delete_target(target)) + + def test_ex_add_client_to_target(self): + target = self.driver.list_targets()[0] + client = self.driver.ex_list_available_client_types(target)[0] + storage_policy = self.driver.ex_list_available_storage_policies(target)[0] + schedule_policy = self.driver.ex_list_available_schedule_policies(target)[0] + self.assertTrue( + self.driver.ex_add_client_to_target(target, client, storage_policy, + schedule_policy, 'ON_FAILURE', '[email protected]') + ) + + def test_ex_add_client_to_target_STR(self): + self.assertTrue( + self.driver.ex_add_client_to_target('e75ead52-692f-4314-8725-c8a4f4d13a87', 'FA.Linux', '14 Day Storage Policy', + '12AM - 6AM', 'ON_FAILURE', '[email protected]') + ) + + def test_ex_get_backup_details_for_target(self): + target = self.driver.list_targets()[0] + response = self.driver.ex_get_backup_details_for_target(target) + self.assertEqual(response.service_plan, 'Enterprise') + client = response.clients[0] + self.assertEqual(client.id, '30b1ff76-c76d-4d7c-b39d-3b72be0384c8') + self.assertEqual(client.type.type, 'FA.Linux') + self.assertEqual(client.running_job.progress, 5) + self.assertTrue(isinstance(client.running_job, BackupTargetJob)) + self.assertEqual(len(client.alert.notify_list), 2) + self.assertTrue(isinstance(client.alert.notify_list, list)) + + def test_ex_get_backup_details_for_target_NOBACKUP(self): + target = self.driver.list_targets()[0].address + DimensionDataMockHttp.type = 'NOBACKUP' + response = self.driver.ex_get_backup_details_for_target(target) + self.assertTrue(response is None) + + def test_ex_cancel_target_job(self): + target = self.driver.list_targets()[0] + response = self.driver.ex_get_backup_details_for_target(target) + client = response.clients[0] + self.assertTrue(isinstance(client.running_job, BackupTargetJob)) + success = client.running_job.cancel() + self.assertTrue(success) + + def test_ex_cancel_target_job_with_extras(self): + success = self.driver.cancel_target_job( + None, + ex_client='30b1ff76_c76d_4d7c_b39d_3b72be0384c8', + ex_target='e75ead52_692f_4314_8725_c8a4f4d13a87' + ) + self.assertTrue(success) + + def test_ex_cancel_target_job_FAIL(self): + DimensionDataMockHttp.type = 'FAIL' + with self.assertRaises(DimensionDataAPIException) as context: + self.driver.cancel_target_job( + None, + ex_client='30b1ff76_c76d_4d7c_b39d_3b72be0384c8', + ex_target='e75ead52_692f_4314_8725_c8a4f4d13a87' + ) + self.assertEqual(context.exception.code, 'ERROR') + + """Test a backup info for a target that does not have a client""" + def test_ex_get_backup_details_for_target_NO_CLIENT(self): + DimensionDataMockHttp.type = 'NOCLIENT' + response = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(response.service_plan, 'Essentials') + self.assertEqual(len(response.clients), 0) + + """Test a backup details that has a client, but no alerting or running jobs""" + def test_ex_get_backup_details_for_target_NO_JOB_OR_ALERT(self): + DimensionDataMockHttp.type = 'NOJOB' + response = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314_8725-c8a4f4d13a87') + self.assertEqual(response.service_plan, 'Enterprise') + self.assertTrue(isinstance(response.clients, list)) + self.assertEqual(len(response.clients), 1) + client = response.clients[0] + self.assertEqual(client.id, '30b1ff76-c76d-4d7c-b39d-3b72be0384c8') + self.assertEqual(client.type.type, 'FA.Linux') + self.assertIsNone(client.running_job) + self.assertIsNone(client.alert) + + """Test getting backup info for a server that doesn't exist""" + def test_ex_get_backup_details_for_target_DISABLED(self): + DimensionDataMockHttp.type = 'DISABLED' + with self.assertRaises(DimensionDataAPIException) as context: + self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87') + self.assertEqual(context.exception.code, 'ERROR') + self.assertEqual(context.exception.msg, 'Server e75ead52-692f-4314-8725-c8a4f4d13a87 has not been provisioned for backup') + + def test_ex_list_available_client_types(self): + target = self.driver.list_targets()[0] + answer = self.driver.ex_list_available_client_types(target) + self.assertEqual(len(answer), 1) + self.assertEqual(answer[0].type, 'FA.Linux') + self.assertEqual(answer[0].is_file_system, True) + self.assertEqual(answer[0].description, 'Linux File system') + + def test_ex_list_available_storage_policies(self): + target = self.driver.list_targets()[0] + answer = self.driver.ex_list_available_storage_policies(target) + self.assertEqual(len(answer), 1) + self.assertEqual(answer[0].name, + '30 Day Storage Policy + Secondary Copy') + self.assertEqual(answer[0].retention_period, 30) + self.assertEqual(answer[0].secondary_location, 'Primary') + + def test_ex_list_available_schedule_policies(self): + target = self.driver.list_targets()[0] + answer = self.driver.ex_list_available_schedule_policies(target) + self.assertEqual(len(answer), 1) + self.assertEqual(answer[0].name, '12AM - 6AM') + self.assertEqual(answer[0].description, 'Daily backup will start between 12AM - 6AM') + + def test_ex_remove_client_from_target(self): + target = self.driver.list_targets()[0] + client = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87').clients[0] + self.assertTrue(self.driver.ex_remove_client_from_target(target, client)) + + def test_ex_remove_client_from_target_STR(self): + self.assertTrue( + self.driver.ex_remove_client_from_target( + 'e75ead52-692f-4314-8725-c8a4f4d13a87', + '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' + ) + ) + + def test_ex_remove_client_from_target_FAIL(self): + DimensionDataMockHttp.type = 'FAIL' + with self.assertRaises(DimensionDataAPIException) as context: + self.driver.ex_remove_client_from_target( + 'e75ead52-692f-4314-8725-c8a4f4d13a87', + '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' + ) + self.assertEqual(context.exception.code, 'ERROR') + self.assertTrue('Backup Client is currently performing another operation' in context.exception.msg) + + def test_priv_target_to_target_address(self): + target = self.driver.list_targets()[0] + self.assertEqual( + self.driver._target_to_target_address(target), + 'e75ead52-692f-4314-8725-c8a4f4d13a87' + ) + + def test_priv_target_to_target_address_STR(self): + self.assertEqual( + self.driver._target_to_target_address('e75ead52-692f-4314-8725-c8a4f4d13a87'), + 'e75ead52-692f-4314-8725-c8a4f4d13a87' + ) + + def test_priv_target_to_target_address_TYPEERROR(self): + with self.assertRaises(TypeError): + self.driver._target_to_target_address([1, 2, 3]) + + def test_priv_client_to_client_id(self): + client = self.driver.ex_get_backup_details_for_target('e75ead52-692f-4314-8725-c8a4f4d13a87').clients[0] + self.assertEqual( + self.driver._client_to_client_id(client), + '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' + ) + + def test_priv_client_to_client_id_STR(self): + self.assertEqual( + self.driver._client_to_client_id('30b1ff76-c76d-4d7c-b39d-3b72be0384c8'), + '30b1ff76-c76d-4d7c-b39d-3b72be0384c8' + ) + + def test_priv_client_to_client_id_TYPEERROR(self): + with self.assertRaises(TypeError): + self.driver._client_to_client_id([1, 2, 3]) + + +class InvalidRequestError(Exception): + def __init__(self, tag): + super(InvalidRequestError, self).__init__("Invalid Request - %s" % tag) + + +class DimensionDataMockHttp(MockHttp): + + fixtures = BackupFileFixtures('dimensiondata') + + def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers): + return (httplib.UNAUTHORIZED, "", {}, httplib.responses[httplib.UNAUTHORIZED]) + + def _oec_0_9_myaccount(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_EXISTS(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_DEFAULT(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_INPROGRESS(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_FAIL(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_NOCLIENT(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_DISABLED(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_myaccount_NOJOB(self, method, url, body, headers): + body = self.fixtures.load('oec_0_9_myaccount.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_NOCLIENT(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_NOJOB(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DISABLED(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_DEFAULT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server(self, method, url, body, headers): + body = self.fixtures.load( + 'server_server.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_type(self, method, url, body, headers): + body = self.fixtures.load( + '_backup_client_type.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_storagePolicy( + self, method, url, body, headers): + body = self.fixtures.load( + '_backup_client_storagePolicy.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_schedulePolicy( + self, method, url, body, headers): + body = self.fixtures.load( + '_backup_client_schedulePolicy.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client( + self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load( + '_backup_client_SUCCESS_PUT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + else: + raise ValueError("Unknown Method {0}".format(method)) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_NOCLIENT( + self, method, url, body, headers): + # only gets here are implemented + # If we get any other method something has gone wrong + assert(method == 'GET') + body = self.fixtures.load( + '_backup_INFO_NOCLIENT.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_DISABLED( + self, method, url, body, headers): + # only gets here are implemented + # If we get any other method something has gone wrong + assert(method == 'GET') + body = self.fixtures.load( + '_backup_INFO_DISABLED.xml') + return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_NOJOB( + self, method, url, body, headers): + # only gets here are implemented + # If we get any other method something has gone wrong + assert(method == 'GET') + body = self.fixtures.load( + '_backup_INFO_NOJOB.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_DEFAULT( + self, method, url, body, headers): + if method != 'POST': + raise InvalidRequestError('Only POST is accepted for this test') + request = ET.fromstring(body) + service_plan = request.get('servicePlan') + if service_plan != DEFAULT_BACKUP_PLAN: + raise InvalidRequestError('The default plan %s should have been passed in. Not %s' % (DEFAULT_BACKUP_PLAN, service_plan)) + body = self.fixtures.load( + '_backup_ENABLE.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup( + self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load( + '_backup_ENABLE.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + elif method == 'GET': + if url.endswith('disable'): + body = self.fixtures.load( + '_backup_DISABLE.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + body = self.fixtures.load( + '_backup_INFO.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + else: + raise ValueError("Unknown Method {0}".format(method)) + + def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server_e75ead52_692f_4314_8725_c8a4f4d13a87_NOBACKUP( + self, method, url, body, headers): + assert(method == 'GET') + body = self.fixtures.load('server_server_NOBACKUP.xml') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_EXISTS( + self, method, url, body, headers): + # only POSTs are implemented + # If we get any other method something has gone wrong + assert(method == 'POST') + body = self.fixtures.load( + '_backup_EXISTS.xml') + return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_modify( + self, method, url, body, headers): + request = ET.fromstring(body) + service_plan = request.get('servicePlan') + if service_plan != 'Essentials': + raise InvalidRequestError("Expected Essentials backup plan in request") + body = self.fixtures.load('_backup_modify.xml') + + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_modify_DEFAULT( + self, method, url, body, headers): + request = ET.fromstring(body) + service_plan = request.get('servicePlan') + if service_plan != DEFAULT_BACKUP_PLAN: + raise InvalidRequestError("Expected % backup plan in test" % DEFAULT_BACKUP_PLAN) + body = self.fixtures.load('_backup_modify.xml') + + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8( + self, method, url, body, headers): + if url.endswith('disable'): + body = self.fixtures.load( + ('_remove_backup_client.xml') + ) + elif url.endswith('cancelJob'): + body = self.fixtures.load( + ('' + '_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8_cancelJob.xml') + ) + else: + raise ValueError("Unknown URL: %s" % url) + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_e75ead52_692f_4314_8725_c8a4f4d13a87_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8_FAIL( + self, method, url, body, headers): + if url.endswith('disable'): + body = self.fixtures.load( + ('_remove_backup_client_FAIL.xml') + ) + elif url.endswith('cancelJob'): + body = self.fixtures.load( + ('' + '_backup_client_30b1ff76_c76d_4d7c_b39d_3b72be0384c8_cancelJob_FAIL.xml') + ) + else: + raise ValueError("Unknown URL: %s" % url) + return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK]) + + +if __name__ == '__main__': + sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/bb1b8104/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage.xml b/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage.xml new file mode 100644 index 0000000..4e59e18 --- /dev/null +++ b/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<customerImages xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="35" totalCount="35" pageSize="250"> + <customerImage id="5234e5c7-01de-4411-8b6e-baeb8d91cf5d" datacenterId="NA9"> + <name>ImportedCustomerImage</name> + <description /> + <operatingSystem id="REDHAT664" displayName="REDHAT6/64" family="UNIX" /> + <cpu count="4" speed="STANDARD" coresPerSocket="1" /> + <memoryGb>2</memoryGb> + <disk id="1a82316f-23ed-4fe9-b6d8-6b92ac467423" scsiId="0" sizeGb="12" speed="STANDARD" /> + <createTime>2015-11-19T14:29:02.000Z</createTime> + <source type="IMPORT"> + <artifact type="MF" value="ImportedCustomerImage.mf" date="2015-1119T14:28:54.000Z" /> + <artifact type="OVF" value="ImportedCustomerImage.ovf" date="2015-1119T14:28:05.000Z" /> + <artifact type="VMDK" value="ImportedCustomerImage-disk1.vmdk" date="2015-11-19T12:22:31.000Z" /></source> + <state>NORMAL</state> + <vmwareTools versionStatus="NEED_UPGRADE" runningStatus="NOT_RUNNING" apiVersion="8389" /> + <virtualHardware version="vmx-10" upToDate="true" /> + </customerImage> + <customerImage id="2ffa36c8-1848-49eb-b4fa-9d908775f68c" datacenterId="NA9"> + <name>CustomerImageWithPricedSoftwareLabels</name> + <description /> + <operatingSystem id="WIN2008S32" displayName="WIN2008S/32" family="WINDOWS" /> + <cpu count="1" speed="STANDARD" coresPerSocket="1" /> + <memoryGb>1</memoryGb> + <disk id="29455efc-51af-4b4d-91b3-d81ca0dff7d8" scsiId="0" sizeGb="50" speed="STANDARD" /> + <softwareLabel>MSSQL2008R2S</softwareLabel> + <createTime>2015-11-03T15:25:34.000Z</createTime> + <source type="CLONE"> + <artifact type="SERVER_ID" value="7c9c2551-269d-4274-a247126ba7c6215c" /> + </source> + <state>NORMAL</state> + <vmwareTools versionStatus="CURRENT" runningStatus="NOT_RUNNING" /> + <virtualHardware version="vmx-08" upToDate="false" /> + </customerImage> + <customerImage id="1fc1844f-45d6-4364-b447-f7c7645b47de" datacenterId="NA9"> + <name>CopiedCustomerImage</name> + <description /> + <operatingSystem id="REDHAT664" displayName="REDHAT6/64" family="UNIX" /> + <cpu count="1" speed="STANDARD" coresPerSocket="1" /> + <memoryGb>2</memoryGb> + <disk id="42b20819-c161-4dec-aa94-73ec370a6e37" scsiId="0" sizeGb="10" speed="STANDARD" /> + <createTime>2015-11-11T17:17:00.000Z</createTime> + <source type="COPY"> + <artifact type="IMAGE_ID" value="0b8357b6-f156-4b27-b4fd-b81d09c15efc" /> + </source> + <state>NORMAL</state> + <vmwareTools versionStatus="NEED_UPGRADE" runningStatus="NOT_RUNNING" apiVersion="9355" /> + <virtualHardware version="vmx-10" upToDate="true" /> + </customerImage> +</customerImages> http://git-wip-us.apache.org/repos/asf/libcloud/blob/bb1b8104/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage_2ffa36c8_1848_49eb_b4fa_9d908775f68c.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage_2ffa36c8_1848_49eb_b4fa_9d908775f68c.xml b/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage_2ffa36c8_1848_49eb_b4fa_9d908775f68c.xml new file mode 100644 index 0000000..bff6183 --- /dev/null +++ b/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage_2ffa36c8_1848_49eb_b4fa_9d908775f68c.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> + <customerImage xmlns="urn:didata.com:api:cloud:types" id="2ffa36c8-1848-49eb-b4fa-9d908775f68c" datacenterId="NA9"> + <name>CustomerImageWithPricedSoftwareLabels</name> + <description /> + <operatingSystem id="WIN2008S32" displayName="WIN2008S/32" family="WINDOWS" /> + <cpu count="1" speed="STANDARD" coresPerSocket="1" /> + <memoryGb>1</memoryGb> + <disk id="29455efc-51af-4b4d-91b3-d81ca0dff7d8" scsiId="0" sizeGb="50" speed="STANDARD" /> + <softwareLabel>MSSQL2008R2S</softwareLabel> + <createTime>2015-11-03T15:25:34.000Z</createTime> + <source type="CLONE"> + <artifact type="SERVER_ID" value="7c9c2551-269d-4274-a247126ba7c6215c" /> + </source> + <state>NORMAL</state> + <vmwareTools versionStatus="CURRENT" runningStatus="NOT_RUNNING" /> + <virtualHardware version="vmx-08" upToDate="false" /> + </customerImage> http://git-wip-us.apache.org/repos/asf/libcloud/blob/bb1b8104/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage_5234e5c7_01de_4411_8b6e_baeb8d91cf5d.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage_5234e5c7_01de_4411_8b6e_baeb8d91cf5d.xml b/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage_5234e5c7_01de_4411_8b6e_baeb8d91cf5d.xml new file mode 100644 index 0000000..db5302d --- /dev/null +++ b/libcloud/test/compute/fixtures/dimensiondata/2.4/image_customerImage_5234e5c7_01de_4411_8b6e_baeb8d91cf5d.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> + <customerImage xmlns="urn:didata.com:api:cloud:types" id="5234e5c7-01de-4411-8b6e-baeb8d91cf5d" datacenterId="NA9"> + <name>ImportedCustomerImage</name> + <description /> + <operatingSystem id="REDHAT664" displayName="REDHAT6/64" family="UNIX" /> + <cpu count="4" speed="STANDARD" coresPerSocket="1" /> + <memoryGb>2</memoryGb> + <disk id="1a82316f-23ed-4fe9-b6d8-6b92ac467423" scsiId="0" sizeGb="12" speed="STANDARD" /> + <createTime>2015-11-19T14:29:02.000Z</createTime> + <source type="IMPORT"> + <artifact type="MF" value="ImportedCustomerImage.mf" date="2015-1119T14:28:54.000Z" /> + <artifact type="OVF" value="ImportedCustomerImage.ovf" date="2015-1119T14:28:05.000Z" /> + <artifact type="VMDK" value="ImportedCustomerImage-disk1.vmdk" date="2015-11-19T12:22:31.000Z" /></source> + <state>NORMAL</state> + <vmwareTools versionStatus="NEED_UPGRADE" runningStatus="NOT_RUNNING" apiVersion="8389" /> + <virtualHardware version="vmx-10" upToDate="true" /> + </customerImage>
