From 962271466822553a28325b3e7a4a76319ad783fa Mon Sep 17 00:00:00 2001 From: Alexandru Coman Date: Thu, 16 Feb 2017 12:22:50 +0200 Subject: [PATCH] Fix the refresh_model method For the moment the refresh_model method doesn't recreate the initial structure of the model and some submodels are not created anymore. In order to avoid this scenario all the submodels will be created in process_raw_data insted of the from_raw_data method. This patch also add some debug messages in order to ease the debuging process. --- .pylintrc | 2 +- hnv/client.py | 147 +++++++++++++++++++-------------- hnv/common/utils.py | 13 +-- hnv/tests/common/test_utils.py | 45 ++++++---- hnv/tests/test_client.py | 45 ++++++---- 5 files changed, 149 insertions(+), 103 deletions(-) diff --git a/.pylintrc b/.pylintrc index ea357cb..5558bfe 100644 --- a/.pylintrc +++ b/.pylintrc @@ -373,7 +373,7 @@ max-args=15 ignored-argument-names=_.* # Maximum number of locals for function / method body -max-locals=15 +max-locals=20 # Maximum number of return / yield for function / method body max-returns=6 diff --git a/hnv/client.py b/hnv/client.py index 774d8be..bdcad06 100644 --- a/hnv/client.py +++ b/hnv/client.py @@ -119,6 +119,22 @@ class _BaseHNVModel(model.Model): # Lock the current model self._provision_done = True + def is_ready(self): + """Check if the current model is ready to be used.""" + if not self.provisioning_state: + raise exception.ServiceException("The object doesn't contain " + "`provisioningState`.") + elif self.provisioning_state == constant.FAILED: + raise exception.ServiceException( + "Failed to complete the required operation.") + elif self.provisioning_state == constant.SUCCEEDED: + LOG.debug("The model %s: %s was successfully updated " + "(or created).", + self.__class__.__name__, self.resource_id) + return True + + return False + @staticmethod def _get_client(): """Create a new client for the HNV REST API.""" @@ -212,8 +228,13 @@ class _BaseHNVModel(model.Model): elapsed_time = 0 while wait: try: - client.get_resource(endpoint) + resource = cls._get(resource_id=resource_id, + parent_id=parent_id, + grandparent_id=grandparent_id) + resource.is_ready() + LOG.debug("The resource is still available. %r", resource) except exception.NotFound: + LOG.debug("The resource was successfully removed.") break elapsed_time += CONFIG.HNV.retry_interval @@ -248,9 +269,12 @@ class _BaseHNVModel(model.Model): in that case). """ if not self._changes: + LOG.debug("No changes available for %s: %s", + self.__class__.__name__, self.resource_id) return - super(_BaseHNVModel, self).commit(wait=wait, timeout=timeout) + LOG.debug("Apply all the changes on the current %s: %s", + self.__class__.__name__, self.resource_id) client = self._get_client() endpoint = self._endpoint.format( resource_id=self.resource_id or "", @@ -263,15 +287,8 @@ class _BaseHNVModel(model.Model): elapsed_time = 0 while wait: self.refresh() # Update the representation of the current model - if not self.provisioning_state: - raise exception.ServiceException("The object doesn't contain " - "`provisioningState`.") - elif self.provisioning_state == constant.FAILED: - raise exception.ServiceException( - "Failed to complete the required operation.") - elif self.provisioning_state == constant.SUCCEEDED: + if self.is_ready(): break - elapsed_time += CONFIG.HNV.retry_interval if timeout and elapsed_time > timeout: raise exception.TimeOut("The request timed out.") @@ -286,7 +303,7 @@ class _BaseHNVModel(model.Model): return self @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -300,7 +317,7 @@ class _BaseHNVModel(model.Model): configuration = ConfigurationState.from_raw_data(raw_state) properties["configurationState"] = configuration - return super(_BaseHNVModel, cls).from_raw_data(raw_data) + return super(_BaseHNVModel, cls).process_raw_data(raw_data) def _set_fields(self, fields): """Set or update the fields value.""" @@ -522,7 +539,7 @@ class LogicalSubnetworks(_BaseHNVModel): administrator portal.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data["properties"] @@ -545,7 +562,7 @@ class LogicalSubnetworks(_BaseHNVModel): network_interfaces.append(resource) properties["networkInterfaces"] = network_interfaces - return super(LogicalSubnetworks, cls).from_raw_data(raw_data) + return super(LogicalSubnetworks, cls).process_raw_data(raw_data) class LogicalNetworks(_BaseHNVModel): @@ -577,7 +594,7 @@ class LogicalNetworks(_BaseHNVModel): the network.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data["properties"] @@ -592,7 +609,7 @@ class LogicalNetworks(_BaseHNVModel): virtual_networks.append(Resource.from_raw_data(raw_network)) properties["virtualNetworks"] = virtual_networks - return super(LogicalNetworks, cls).from_raw_data(raw_data) + return super(LogicalNetworks, cls).process_raw_data(raw_data) class IPConfiguration(_BaseHNVModel): @@ -659,7 +676,7 @@ class IPConfiguration(_BaseHNVModel): is connected to.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data["properties"] @@ -690,7 +707,7 @@ class IPConfiguration(_BaseHNVModel): resource = Resource.from_raw_data(raw_content) properties["subnet"] = resource - return super(IPConfiguration, cls).from_raw_data(raw_data) + return super(IPConfiguration, cls).process_raw_data(raw_data) class DNSSettings(model.Model): @@ -791,12 +808,12 @@ class PortSettings(model.Model): is_required=False, is_property=False) @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" raw_settings = raw_data.get("qosSettings", {}) qos_settings = QosSettings.from_raw_data(raw_settings) raw_data["qosSettings"] = qos_settings - return super(PortSettings, cls).from_raw_data(raw_data) + return super(PortSettings, cls).process_raw_data(raw_data) class ConfigurationState(model.Model): @@ -883,7 +900,7 @@ class NetworkInterfaces(_BaseHNVModel): this networkInterfaces resource is part of.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data["properties"] @@ -903,7 +920,7 @@ class NetworkInterfaces(_BaseHNVModel): port_settings = PortSettings.from_raw_data(raw_settings) properties["portSettings"] = port_settings - return super(NetworkInterfaces, cls).from_raw_data(raw_data) + return super(NetworkInterfaces, cls).process_raw_data(raw_data) class SubNetworks(_BaseHNVModel): @@ -959,7 +976,7 @@ class SubNetworks(_BaseHNVModel): are connected to the subnet.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data["properties"] @@ -984,7 +1001,7 @@ class SubNetworks(_BaseHNVModel): ip_configurations.append(Resource.from_raw_data(raw_config)) properties["ipConfigurations"] = ip_configurations - return super(SubNetworks, cls).from_raw_data(raw_data) + return super(SubNetworks, cls).process_raw_data(raw_data) class DHCPOptions(model.Model): @@ -1051,7 +1068,7 @@ class VirtualNetworks(_BaseHNVModel): underlay network which the virtual network runs on.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data["properties"] @@ -1075,7 +1092,7 @@ class VirtualNetworks(_BaseHNVModel): subnetworks.append(SubNetworks.from_raw_data(raw_subnet)) properties["subnets"] = subnetworks - return super(VirtualNetworks, cls).from_raw_data(raw_data) + return super(VirtualNetworks, cls).process_raw_data(raw_data) class ACLRules(_BaseHNVModel): @@ -1198,10 +1215,16 @@ class AccessControlLists(_BaseHNVModel): control list is associated with.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data["properties"] + ip_configurations = [] + for raw_content in properties.get("ipConfigurations", []): + resource = Resource.from_raw_data(raw_content) + ip_configurations.append(resource) + properties["ipConfigurations"] = ip_configurations + subnetworks = [] for raw_subnet in properties.get("subnets", []): subnetworks.append(Resource.from_raw_data(raw_subnet)) @@ -1213,7 +1236,7 @@ class AccessControlLists(_BaseHNVModel): acl_rules.append(ACLRules.from_raw_data(raw_rule)) properties["aclRules"] = acl_rules - return super(AccessControlLists, cls).from_raw_data(raw_data) + return super(AccessControlLists, cls).process_raw_data(raw_data) class VirtualSwtichQosSettings(model.Model): @@ -1284,13 +1307,13 @@ class VirtualSwitchManager(_BaseHNVModel): return cls._get(resource_id, parent_id, grandparent_id) @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data["properties"] qos_settings = properties.get("qosSettings", {}) properties["qosSettings"] = VirtualSwtichQosSettings.from_raw_data( raw_data=qos_settings) - return super(VirtualSwitchManager, cls).from_raw_data(raw_data) + return super(VirtualSwitchManager, cls).process_raw_data(raw_data) @classmethod def remove(cls, resource_id, parent_id=None, grandparent_id=None, @@ -1369,7 +1392,7 @@ class RouteTables(_BaseHNVModel): table is associated with.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data["properties"] @@ -1386,7 +1409,7 @@ class RouteTables(_BaseHNVModel): subnets.append(Resource.from_raw_data(raw_subnet)) properties["subnets"] = subnets - return super(RouteTables, cls).from_raw_data(raw_data) + return super(RouteTables, cls).process_raw_data(raw_data) class MainMode(model.Model): @@ -1566,7 +1589,7 @@ class IPSecConfiguration(model.Model): """Indicates collection of IPsec TrafficSelectors on the tenant side.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" raw_main = raw_data.get("mainMode", None) if raw_main is not None: @@ -1590,7 +1613,7 @@ class IPSecConfiguration(model.Model): raw_remote_vpn)) raw_data["remoteVpnTrafficSelector"] = remote_vpn_ts - return super(IPSecConfiguration, cls).from_raw_data(raw_data) + return super(IPSecConfiguration, cls).process_raw_data(raw_data) class IPAddress(model.Model): @@ -1836,7 +1859,7 @@ class NetworkConnections(_BaseHNVModel): is_required=False, is_read_only=False) @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -1876,7 +1899,7 @@ class NetworkConnections(_BaseHNVModel): gateway = Resource.from_raw_data(raw_content) properties["gateway"] = gateway - return super(NetworkConnections, cls).from_raw_data(raw_data) + return super(NetworkConnections, cls).process_raw_data(raw_data) class PublicIPAddresses(_BaseHNVModel): @@ -1938,7 +1961,7 @@ class PublicIPAddresses(_BaseHNVModel): """ @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -1947,7 +1970,7 @@ class PublicIPAddresses(_BaseHNVModel): resource = Resource.from_raw_data(raw_content) properties["ipConfiguration"] = resource - return super(PublicIPAddresses, cls).from_raw_data(raw_data) + return super(PublicIPAddresses, cls).process_raw_data(raw_data) class BackendAddressPools(_BaseHNVModel): @@ -1997,7 +2020,7 @@ class BackendAddressPools(_BaseHNVModel): resources that use this backend address pool.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -2019,7 +2042,7 @@ class BackendAddressPools(_BaseHNVModel): outbound_nat_rules.append(resource) properties["outboundNatRules"] = outbound_nat_rules - return super(BackendAddressPools, cls).from_raw_data(raw_data) + return super(BackendAddressPools, cls).process_raw_data(raw_data) class FrontendIPConfigurations(_BaseHNVModel): @@ -2104,7 +2127,7 @@ class FrontendIPConfigurations(_BaseHNVModel): """ @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -2131,7 +2154,7 @@ class FrontendIPConfigurations(_BaseHNVModel): resource = Resource.from_raw_data(raw_content) properties["subnet"] = resource - return super(FrontendIPConfigurations, cls).from_raw_data(raw_data) + return super(FrontendIPConfigurations, cls).process_raw_data(raw_data) class InboundNATRules(_BaseHNVModel): @@ -2218,7 +2241,7 @@ class InboundNATRules(_BaseHNVModel): """ @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -2236,7 +2259,7 @@ class InboundNATRules(_BaseHNVModel): frontend_ip_configurations.append(resource) properties["frontendIPConfigurations"] = frontend_ip_configurations - return super(InboundNATRules, cls).from_raw_data(raw_data) + return super(InboundNATRules, cls).process_raw_data(raw_data) class LoadBalancingRules(_BaseHNVModel): @@ -2359,7 +2382,7 @@ class LoadBalancingRules(_BaseHNVModel): """ @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -2379,7 +2402,7 @@ class LoadBalancingRules(_BaseHNVModel): resource = Resource.from_raw_data(raw_content) properties["probe"] = resource - return super(LoadBalancingRules, cls).from_raw_data(raw_data) + return super(LoadBalancingRules, cls).process_raw_data(raw_data) class OutboundNATRules(_BaseHNVModel): @@ -2426,7 +2449,7 @@ class OutboundNATRules(_BaseHNVModel): """ @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -2441,7 +2464,7 @@ class OutboundNATRules(_BaseHNVModel): resource = Resource.from_raw_data(raw_content) properties["backendAddressPool"] = resource - return super(OutboundNATRules, cls).from_raw_data(raw_data) + return super(OutboundNATRules, cls).process_raw_data(raw_data) class Probes(_BaseHNVModel): @@ -2510,7 +2533,7 @@ class Probes(_BaseHNVModel): """ @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -2520,7 +2543,7 @@ class Probes(_BaseHNVModel): load_balancing_rules.append(resource) properties["loadBalancingRules"] = load_balancing_rules - return super(Probes, cls).from_raw_data(raw_data) + return super(Probes, cls).process_raw_data(raw_data) class LoadBalancers(_BaseHNVModel): @@ -2580,7 +2603,7 @@ class LoadBalancers(_BaseHNVModel): """ @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): properties = raw_data.get("properties", {}) backend_address_pools = [] @@ -2608,8 +2631,8 @@ class LoadBalancers(_BaseHNVModel): outbound_nat_rules = [] for raw_content in properties.get("outboundNatRules", []): raw_content["parentResourceID"] = raw_data["resourceId"] - inbound_nat_rule = OutboundNATRules.from_raw_data(raw_content) - outbound_nat_rules.append(inbound_nat_rule) + outbound_nat_rule = OutboundNATRules.from_raw_data(raw_content) + outbound_nat_rules.append(outbound_nat_rule) properties["outboundNatRules"] = outbound_nat_rules load_balancing_rules = [] @@ -2626,7 +2649,7 @@ class LoadBalancers(_BaseHNVModel): probes.append(probe) properties["probes"] = probes - return super(LoadBalancers, cls).from_raw_data(raw_data) + return super(LoadBalancers, cls).process_raw_data(raw_data) class _BGPPeersStatistics(model.Model): @@ -2783,7 +2806,7 @@ class BGPPeersStatistics(model.Model): """Time stamp when the stats were last updated.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" # pylint: disable=redefined-variable-type @@ -2825,7 +2848,7 @@ class BGPPeersStatistics(model.Model): statistics = IPV6Route.from_raw_data(raw_content) raw_data["ipv6Route"] = statistics - return super(BGPPeersStatistics, cls).from_raw_data(raw_data) + return super(BGPPeersStatistics, cls).process_raw_data(raw_data) class BGPPeers(_BaseHNVModel): @@ -2894,7 +2917,7 @@ class BGPPeers(_BaseHNVModel): """This flag is set to `True` for iBGP peers.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -2903,7 +2926,7 @@ class BGPPeers(_BaseHNVModel): statistics = BGPPeersStatistics.from_raw_data(raw_content) properties["statistics"] = statistics - super(BGPPeers, cls).from_raw_data(raw_data) + return super(BGPPeers, cls).process_raw_data(raw_data) class BGPRouters(_BaseHNVModel): @@ -2957,7 +2980,7 @@ class BGPRouters(_BaseHNVModel): """Collection of BGP peers associated with the BGP Routers resource.""" @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -2968,7 +2991,7 @@ class BGPRouters(_BaseHNVModel): bgp_peers.append(BGPPeers.from_raw_data(raw_content)) properties["bgpPeers"] = bgp_peers - return super(BGPRouters, cls).from_raw_data(raw_data) + return super(BGPRouters, cls).process_raw_data(raw_data) class LoadBalancerManager(_BaseHNVModel): @@ -3012,7 +3035,7 @@ class LoadBalancerManager(_BaseHNVModel): return cls._get(resource_id, parent_id, grandparent_id) @classmethod - def from_raw_data(cls, raw_data): + def process_raw_data(cls, raw_data): """Create a new model using raw API response.""" properties = raw_data.get("properties", {}) @@ -3022,4 +3045,4 @@ class LoadBalancerManager(_BaseHNVModel): vip_ip_pools.append(resource) properties["vipIpPools"] = vip_ip_pools - return super(LoadBalancerManager, cls).from_raw_data(raw_data) + return super(LoadBalancerManager, cls).process_raw_data(raw_data) diff --git a/hnv/common/utils.py b/hnv/common/utils.py index 1b7860c..ef23040 100644 --- a/hnv/common/utils.py +++ b/hnv/common/utils.py @@ -105,7 +105,7 @@ class _HNVClient(object): return not self._https_allow_insecure def _http_request(self, resource, method=constant.GET, body=None, - if_match=None): + if_match=False): if not resource.startswith("http"): url = requests.compat.urljoin(self._base_url, resource) else: @@ -113,10 +113,10 @@ class _HNVClient(object): headers = self._get_headers() if method in (constant.PUT, constant.PATCH): - if not isinstance(if_match, six.string_types): - if_match = (body or {}).get("etag", None) - if if_match is not None: - headers["If-Match"] = if_match + if if_match: + etag = (body or {}).get("etag", None) + if etag is not None: + headers["If-Match"] = etag attemts = 0 while True: @@ -127,7 +127,8 @@ class _HNVClient(object): timeout=CONFIG.HNV.http_request_timeout ) break - except requests.ConnectionError as exc: + except (requests.ConnectionError, + requests.RequestException) as exc: attemts += 1 self._http_session = None LOG.debug("Request failed: %s", exc) diff --git a/hnv/tests/common/test_utils.py b/hnv/tests/common/test_utils.py index cadd1cd..5ba63b3 100644 --- a/hnv/tests/common/test_utils.py +++ b/hnv/tests/common/test_utils.py @@ -79,7 +79,7 @@ class TestHNVClient(unittest.TestCase): @mock.patch("hnv.common.utils._HNVClient._get_headers") def _test_http_request(self, mock_headers, mock_session, mock_join, mock_dump, mock_sleep, - method, body, response, status_code): + method, body, response, status_code, if_match): output = [] headers = mock_headers.return_value = {} mock_join.return_value = mock.sentinel.url @@ -105,35 +105,38 @@ class TestHNVClient(unittest.TestCase): if isinstance(expected_response, requests.exceptions.SSLError): self.assertRaises(exception.CertificateVerifyFailed, client._http_request, - "/fake/resource", method, body) + "/fake/resource", method, body, if_match) return elif isinstance(expected_response, requests.ConnectionError): self.assertRaises(requests.ConnectionError, client._http_request, - "/fake/resource", method, body) + "/fake/resource", method, body, if_match) return elif status_code == 400: self.assertRaises(exception.ServiceException, client._http_request, - "/fake/resource", method, body) + "/fake/resource", method, body, if_match) elif status_code == 404: self.assertRaises(exception.NotFound, client._http_request, - "/fake/resource", method, body) + "/fake/resource", method, body, if_match) elif status_code != 200: self.assertRaises(requests.HTTPError, client._http_request, - "/fake/resource", method, body) + "/fake/resource", method, body, if_match) else: client_response = client._http_request("/fake/resource", - method, body) + method, body, if_match) mock_join.assert_called_once_with(mock.sentinel.url, "/fake/resource") mock_headers.assert_called_once_with() - if not method == constant.GET: + if not method == constant.GET and if_match: etag = (body or {}).get("etag", None) - self.assertEqual(headers["If-Match"], etag) + if etag is None: + self.assertNotIn("If-Match", headers) + else: + self.assertEqual(headers["If-Match"], etag) if len(response) == 1: session_request.assert_called_once_with( @@ -154,14 +157,16 @@ class TestHNVClient(unittest.TestCase): self._test_http_request(method=constant.GET, body=mock.sentinel.body, response=response, - status_code=200) + status_code=200, + if_match=False) def test_http_request_put(self): response = [mock.MagicMock()] self._test_http_request(method=constant.PUT, body={"etag": mock.sentinel.etag}, response=response, - status_code=200) + status_code=200, + if_match=True) def test_http_request_with_connection_error(self): response = [requests.ConnectionError(), mock.MagicMock()] @@ -169,7 +174,8 @@ class TestHNVClient(unittest.TestCase): self._test_http_request(method=constant.GET, body=mock.sentinel.body, response=response, - status_code=200) + status_code=200, + if_match=False) def test_http_request_connection_error(self): response = [requests.ConnectionError(), requests.ConnectionError()] @@ -177,7 +183,8 @@ class TestHNVClient(unittest.TestCase): self._test_http_request(method=constant.GET, body=mock.sentinel.body, response=response, - status_code=200) + status_code=200, + if_match=False) def test_http_request_ssl_error(self): response = [requests.exceptions.SSLError(), @@ -186,28 +193,32 @@ class TestHNVClient(unittest.TestCase): self._test_http_request(method=constant.GET, body=mock.sentinel.body, response=response, - status_code=200) + status_code=200, + if_match=False) def test_http_request_not_found(self): response = [mock.MagicMock()] self._test_http_request(method=constant.GET, body=mock.sentinel.body, response=response, - status_code=404) + status_code=404, + if_match=False) def test_http_request_bad_request(self): response = [mock.MagicMock()] self._test_http_request(method=constant.GET, body=mock.sentinel.body, response=response, - status_code=400) + status_code=400, + if_match=False) def test_http_request_server_error(self): response = [mock.MagicMock()] self._test_http_request(method=constant.GET, body=mock.sentinel.body, response=response, - status_code=500) + status_code=500, + if_match=False) @mock.patch("hnv.common.utils._HNVClient._http_request") def test_get_resource(self, mock_http_request): diff --git a/hnv/tests/test_client.py b/hnv/tests/test_client.py index 72614c2..8cfdec4 100644 --- a/hnv/tests/test_client.py +++ b/hnv/tests/test_client.py @@ -22,7 +22,6 @@ except ImportError: import mock from hnv import client -from hnv.common import constant from hnv.common import exception from hnv import config as hnv_config from hnv.tests.fake import fake_response @@ -77,15 +76,23 @@ class TestBaseHNVModel(unittest.TestCase): self.assertEqual(resources, [{} for _ in range(10)]) @mock.patch("time.sleep") + @mock.patch("hnv.client._BaseHNVModel._get") @mock.patch("hnv.client._BaseHNVModel._get_client") - def _test_remove(self, mock_get_client, mock_sleep, + def _test_remove(self, mock_get_client, mock_get, mock_sleep, loop_count, timeout): + resource = mock.Mock() + is_ready = resource.is_ready = mock.Mock() + http_client = mock_get_client.return_value = mock.Mock() remove_resource = http_client.remove_resource = mock.Mock() - get_resource = http_client.get_resource = mock.Mock() - side_effect = [None for _ in range(loop_count)] - side_effect.append(exception.NotFound if not timeout else None) - get_resource.side_effect = side_effect + + side_effect = [resource for _ in range(loop_count)] + side_effect.append(exception.NotFound if not timeout else resource) + mock_get.side_effect = side_effect + + side_effect = [False for _ in range(loop_count)] + side_effect.append(True if not timeout else False) + is_ready.side_effect = side_effect request_timeout = CONFIG.HNV.retry_interval * loop_count request_wait = True if loop_count > 0 else False @@ -115,27 +122,29 @@ class TestBaseHNVModel(unittest.TestCase): return {"properties": {"provisioningState": provisioning_state}} @mock.patch("time.sleep") + @mock.patch("hnv.client._BaseHNVModel._reset_model") + @mock.patch("hnv.client._BaseHNVModel.is_ready") + @mock.patch("hnv.client._BaseHNVModel.refresh") @mock.patch("hnv.client._BaseHNVModel.dump") @mock.patch("hnv.client._BaseHNVModel._get_client") - def _test_commit(self, mock_get_client, mock_dump, - mock_sleep, + def _test_commit(self, mock_get_client, mock_dump, mock_refresh, + mock_is_ready, mock_reset_model, mock_sleep, loop_count, timeout, failed, invalid_response): http_client = mock_get_client.return_value = mock.Mock() update_resource = http_client.update_resource = mock.Mock() + update_resource.return_value = mock.sentinel.response mock_dump.return_value = mock.sentinel.request_body - get_resource = http_client.get_resource = mock.Mock() - side_effect = [self._get_provisioning(constant.UPDATING) - for _ in range(loop_count)] + side_effect = [False for _ in range(loop_count)] if timeout: - side_effect.append(self._get_provisioning(constant.UPDATING)) + side_effect.append(False) elif failed: - side_effect.append(self._get_provisioning(constant.FAILED)) + side_effect.append(exception.ServiceException) elif invalid_response: - side_effect.append(self._get_provisioning(None)) + side_effect.append(False) else: - side_effect.append(self._get_provisioning(constant.SUCCEEDED)) - get_resource.side_effect = side_effect + side_effect.append(True) + mock_is_ready.side_effect = side_effect request_timeout = CONFIG.HNV.retry_interval * loop_count request_wait = True if loop_count > 0 else False @@ -158,7 +167,9 @@ class TestBaseHNVModel(unittest.TestCase): if_match=None) if request_wait: - self.assertEqual(get_resource.call_count, loop_count + 1) + self.assertEqual(mock_refresh.call_count, loop_count + 1) + else: + mock_reset_model.assert_called_once_with(mock.sentinel.response) def test_commit(self): self._test_commit(loop_count=0, timeout=False,