# # 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 uuid import mock from oslo_utils import reflection import six from heat.common import exception from heat.common import template_format from heat.engine import resource from heat.engine import scheduler from heat.tests import common from heat.tests import utils from ..resources import cloudnetworks # noqa try: from pyrax.exceptions import NotFound # noqa except ImportError: from ..resources.cloudnetworks import NotFound # noqa class FakeNetwork(object): def __init__(self, client, label="test_network", cidr="172.16.0.0/24"): self.client = client self.label = label self.cidr = cidr self.id = str(uuid.uuid4()) def _is_deleted(self): return (self.client and self.id not in [nw.id for nw in self.client.networks]) def get(self): if self._is_deleted(): raise NotFound("I am deleted") def delete(self): self.client._delete(self) class FakeClient(object): def __init__(self): self.networks = [] def create(self, label=None, cidr=None): nw = FakeNetwork(self, label=label, cidr=cidr) self.networks.append(nw) return nw def get(self, nwid): for nw in self.networks: if nw.id == nwid: return nw raise NotFound("No network %s" % nwid) def _delete(self, nw): try: self.networks.remove(nw) except ValueError: pass class FakeClientRaiseException(FakeClient): def create(self, label=None, cidr=None): raise Exception def get(self, nwid): raise Exception @mock.patch.object(cloudnetworks.CloudNetwork, "cloud_networks") class CloudNetworkTest(common.HeatTestCase): _template = template_format.parse(""" heat_template_version: 2013-05-23 description: Test stack for Rackspace Cloud Networks resources: cnw: type: Rackspace::Cloud::Network properties: label: test_network cidr: 172.16.0.0/24 """) def setUp(self): super(CloudNetworkTest, self).setUp() resource._register_class("Rackspace::Cloud::Network", cloudnetworks.CloudNetwork) def _parse_stack(self): class_name = reflection.get_class_name(self, fully_qualified=False) self.stack = utils.parse_stack(self._template, stack_name=class_name) def _setup_stack(self, mock_client, *args): self.fake_cnw = FakeClient(*args) mock_client.return_value = self.fake_cnw self._parse_stack() self.stack.create() self.assertEqual((self.stack.CREATE, self.stack.COMPLETE), self.stack.state) res = self.stack['cnw'] self.assertEqual((res.CREATE, res.COMPLETE), res.state) def test_attributes(self, mock_client): self._setup_stack(mock_client) res = self.stack['cnw'] template_resource = self._template['resources']['cnw'] expect_label = template_resource['properties']['label'] expect_cidr = template_resource['properties']['cidr'] self.assertEqual(expect_label, res.FnGetAtt('label')) self.assertEqual(expect_cidr, res.FnGetAtt('cidr')) def test_create_bad_cidr(self, mock_client): prop = self._template['resources']['cnw']['properties'] prop['cidr'] = "bad cidr" self._parse_stack() exc = self.assertRaises(exception.StackValidationFailed, self.stack.validate) self.assertIn("Invalid net cidr", six.text_type(exc)) # reset property prop['cidr'] = "172.16.0.0/24" def test_check(self, mock_client): self._setup_stack(mock_client) res = self.stack['cnw'] scheduler.TaskRunner(res.check)() self.assertEqual((res.CHECK, res.COMPLETE), res.state) self.fake_cnw.networks = [] exc = self.assertRaises(exception.ResourceFailure, scheduler.TaskRunner(res.check)) self.assertEqual((res.CHECK, res.FAILED), res.state) self.assertIn('No network', str(exc)) def test_delete(self, mock_client): self._setup_stack(mock_client) res = self.stack['cnw'] res_id = res.FnGetRefId() scheduler.TaskRunner(res.delete)() self.assertEqual((res.DELETE, res.COMPLETE), res.state) exc = self.assertRaises(NotFound, self.fake_cnw.get, res_id) self.assertIn(res_id, six.text_type(exc)) def test_delete_no_network_created(self, mock_client): self.fake_cnw = FakeClientRaiseException() mock_client.return_value = self.fake_cnw self._parse_stack() self.stack.create() self.assertEqual((self.stack.CREATE, self.stack.FAILED), self.stack.state) res = self.stack['cnw'] self.assertEqual((res.CREATE, res.FAILED), res.state) scheduler.TaskRunner(res.delete)() self.assertEqual((res.DELETE, res.COMPLETE), res.state) def test_delete_in_use(self, mock_client): self._setup_stack(mock_client) res = self.stack['cnw'] fake_network = res.network() fake_network.delete = mock.Mock() fake_network.delete.side_effect = [cloudnetworks.NetworkInUse(), True] mock_client.return_value = fake_network fake_network.get = mock.Mock() fake_network.get.side_effect = [cloudnetworks.NotFound()] scheduler.TaskRunner(res.delete)() self.assertEqual((res.DELETE, res.COMPLETE), res.state) def test_delete_not_complete(self, mock_client): self._setup_stack(mock_client) res = self.stack['cnw'] mock_client.get = mock.Mock() task = res.handle_delete() self.assertFalse(res.check_delete_complete(task)) def test_delete_not_found(self, mock_client): self._setup_stack(mock_client) self.fake_cnw.networks = [] res = self.stack['cnw'] scheduler.TaskRunner(res.delete)() self.assertEqual((res.DELETE, res.COMPLETE), res.state)