209 lines
7.4 KiB
Python
209 lines
7.4 KiB
Python
# Copyright (c) 2013 - 2015 EMC Corporation.
|
|
# 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.
|
|
import copy
|
|
|
|
import requests
|
|
import six
|
|
|
|
from cinder import test
|
|
from cinder.tests.unit.volume.drivers.dell_emc.vxflexos import mocks
|
|
from cinder.volume import configuration as conf
|
|
from cinder.volume.drivers.dell_emc.vxflexos import driver
|
|
|
|
|
|
class CustomResponseMode(object):
|
|
"""A context manager to define a custom set of per-request response modes.
|
|
|
|
Example:
|
|
|
|
with CustomResponseMode(self, **{
|
|
'some/api/path': RESPONSE_MODE.Valid,
|
|
'another/api/path': RESPONSE_MODE.BadStatus,
|
|
'last/api/path': MockResponse('some data',
|
|
status_code=403),
|
|
}):
|
|
self.assertRaises(SomeException, self.driver.api_call, data)
|
|
"""
|
|
def __init__(self, test_instance, **kwargs):
|
|
self.test_instance = test_instance
|
|
self.custom_responses = kwargs
|
|
self.current_responses = None
|
|
|
|
def __enter__(self):
|
|
self.current_responses = self.test_instance.HTTPS_MOCK_RESPONSES
|
|
|
|
https_responses = copy.deepcopy(
|
|
self.test_instance.HTTPS_MOCK_RESPONSES
|
|
)
|
|
current_mode = self.test_instance.current_https_response_mode
|
|
|
|
for call, new_mode in self.custom_responses.items():
|
|
if isinstance(new_mode, mocks.MockHTTPSResponse):
|
|
https_responses[current_mode][call] = new_mode
|
|
else:
|
|
https_responses[current_mode][call] = \
|
|
self.test_instance.get_https_response(call, new_mode)
|
|
|
|
self.test_instance.HTTPS_MOCK_RESPONSES = https_responses
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
self.test_instance.HTTPS_MOCK_RESPONSES = self.current_responses
|
|
|
|
|
|
class TestVxFlexOSDriver(test.TestCase):
|
|
"""Base ``TestCase`` subclass for the ``VxFlexOSDriver``"""
|
|
RESPONSE_MODE = type(str('ResponseMode'), (object, ), dict(
|
|
Valid='0',
|
|
Invalid='1',
|
|
BadStatus='2',
|
|
ValidVariant='3',
|
|
))
|
|
__RESPONSE_MODE_NAMES = {
|
|
'0': 'Valid',
|
|
'1': 'Invalid',
|
|
'2': 'BadStatus',
|
|
'3': 'ValidVariant',
|
|
}
|
|
|
|
BAD_STATUS_RESPONSE = mocks.MockHTTPSResponse(
|
|
{
|
|
'errorCode': 500,
|
|
'message': 'BadStatus Response Test',
|
|
}, 500
|
|
)
|
|
|
|
OLD_VOLUME_NOT_FOUND_ERROR = 78
|
|
VOLUME_NOT_FOUND_ERROR = 79
|
|
|
|
HTTPS_MOCK_RESPONSES = {}
|
|
__COMMON_HTTPS_MOCK_RESPONSES = {
|
|
RESPONSE_MODE.Valid: {
|
|
'login': 'login_token',
|
|
'version': '3.5'
|
|
},
|
|
RESPONSE_MODE.BadStatus: {
|
|
'login': mocks.MockHTTPSResponse(
|
|
{
|
|
'errorCode': 403,
|
|
'message': 'Bad Login Response Test',
|
|
}, 403
|
|
),
|
|
'version': '3.5'
|
|
},
|
|
}
|
|
__https_response_mode = RESPONSE_MODE.Valid
|
|
log = None
|
|
|
|
STORAGE_POOL_ID = six.text_type('1')
|
|
STORAGE_POOL_NAME = 'SP1'
|
|
|
|
PROT_DOMAIN_ID = six.text_type('1')
|
|
PROT_DOMAIN_NAME = 'PD1'
|
|
|
|
STORAGE_POOLS = ['{}:{}'.format(PROT_DOMAIN_NAME, STORAGE_POOL_NAME)]
|
|
|
|
def setUp(self):
|
|
"""Setup a test case environment.
|
|
|
|
Creates a ``VxFlexOSDriver`` instance
|
|
Mocks the ``requests.get/post`` methods to return
|
|
``MockHTTPSResponse``'s instead.
|
|
"""
|
|
super(TestVxFlexOSDriver, self).setUp()
|
|
self.configuration = conf.Configuration(driver.vxflexos_opts,
|
|
conf.SHARED_CONF_GROUP)
|
|
self._set_overrides()
|
|
self.driver = mocks.VxFlexOSDriver(configuration=self.configuration)
|
|
self.driver.primary_client = mocks.VxFlexOSClient(self.configuration)
|
|
self.driver.secondary_client = mocks.VxFlexOSClient(self.configuration,
|
|
is_primary=False)
|
|
self.driver.do_setup({})
|
|
|
|
self.mock_object(requests, 'get', self.do_request)
|
|
self.mock_object(requests, 'post', self.do_request)
|
|
|
|
self.driver.primary_client.do_setup()
|
|
self.driver.secondary_client.do_setup()
|
|
|
|
def _set_overrides(self):
|
|
# Override the defaults to fake values
|
|
self.override_config('san_ip', override='127.0.0.1',
|
|
group=conf.SHARED_CONF_GROUP)
|
|
self.override_config('vxflexos_rest_server_port', override='8888',
|
|
group=conf.SHARED_CONF_GROUP)
|
|
self.override_config('san_login', override='test',
|
|
group=conf.SHARED_CONF_GROUP)
|
|
self.override_config('san_password', override='pass',
|
|
group=conf.SHARED_CONF_GROUP)
|
|
self.override_config('vxflexos_storage_pools',
|
|
override='PD1:SP1',
|
|
group=conf.SHARED_CONF_GROUP)
|
|
self.override_config('max_over_subscription_ratio',
|
|
override=5.0, group=conf.SHARED_CONF_GROUP)
|
|
self.override_config('vxflexos_server_api_version',
|
|
override='2.0.0', group=conf.SHARED_CONF_GROUP)
|
|
|
|
def do_request(self, url, *args, **kwargs):
|
|
"""Do a fake GET/POST API request.
|
|
|
|
Splits `url` on '/api/' to get the what API call is, then returns
|
|
the value of `self.HTTPS_MOCK_RESPONSES[<response_mode>][<api_call>]`
|
|
converting to a `MockHTTPSResponse` if necessary.
|
|
|
|
:raises test.TestingException: If the current mode/api_call does not
|
|
exist.
|
|
:returns MockHTTPSResponse:
|
|
"""
|
|
return self.get_https_response(url.split('/api/')[1])
|
|
|
|
def set_https_response_mode(self, mode=RESPONSE_MODE.Valid):
|
|
"""Set the HTTPS response mode.
|
|
|
|
RESPONSE_MODE.Valid: Respond with valid data
|
|
RESPONSE_MODE.Invalid: Respond with invalid data
|
|
RESPONSE_MODE.BadStatus: Response with not-OK status code.
|
|
"""
|
|
self.__https_response_mode = mode
|
|
|
|
def get_https_response(self, api_path, mode=None):
|
|
if mode is None:
|
|
mode = self.__https_response_mode
|
|
|
|
try:
|
|
response = self.HTTPS_MOCK_RESPONSES[mode][api_path]
|
|
except KeyError:
|
|
try:
|
|
response = self.__COMMON_HTTPS_MOCK_RESPONSES[mode][api_path]
|
|
except KeyError:
|
|
raise test.TestingException(
|
|
'Mock API Endpoint not implemented: [{}]{}'.format(
|
|
self.__RESPONSE_MODE_NAMES[mode], api_path
|
|
)
|
|
)
|
|
|
|
if not isinstance(response, mocks.MockHTTPSResponse):
|
|
return mocks.MockHTTPSResponse(response, 200)
|
|
return response
|
|
|
|
@property
|
|
def current_https_response_mode(self):
|
|
return self.__https_response_mode
|
|
|
|
def https_response_mode_name(self, mode):
|
|
return self.__RESPONSE_MODE_NAMES[mode]
|
|
|
|
def custom_response_mode(self, **kwargs):
|
|
return CustomResponseMode(self, **kwargs)
|