summaryrefslogtreecommitdiffstats
path: root/ansible/run_yardstick_tests.yml
blob: 1490b8c559c5ce5f861ee06989882ac830a96904 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Copyright (c) 2017 Intel Corporation.
#
# 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.
---
- name: run yardstick tests
  hosts: yardstick
  vars_files:
    - yardstick_config.yml

    - role: install_storperf
      when: "NODE_NAME == 'huawei-pod1'"
#    - run_test
    - role: remove_storperf
      when: "NODE_NAME == 'huawei-pod1'"
Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gi { color: #a6e22e } /* Generic.Inserted */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #75715e } /* Generic.Subheading */ .highlight .kc { color: #66d9ef } /* Keyword.Constant */ .highlight .kd { color: #66d9ef } /* Keyword.Declaration */ .highlight .kn { color: #f92672 } /* Keyword.Namespace */ .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ .highlight .kt { color: #66d9ef } /* Keyword.Type */ .highlight .ld { color: #e6db74 } /* Literal.Date */ .highlight .m { color: #ae81ff } /* Literal.Number */ .highlight .s { color: #e6db74 } /* Literal.String */ .highlight .na { color: #a6e22e } /* Name.Attribute */ .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ .highlight .nc { color: #a6e22e } /* Name.Class */ .highlight .no { color: #66d9ef } /* Name.Constant */ .highlight .nd { color: #a6e22e } /* Name.Decorator */ .highlight .ni { color: #f8f8f2 } /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
#!/usr/bin/env python

##############################################################################
# Copyright (c) 2017 Intel Corporation
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################

# Unittest for yardstick.benchmark.orchestrator.heat
from contextlib import contextmanager
from tempfile import NamedTemporaryFile
import unittest
import uuid
import time
import mock

from yardstick.benchmark.contexts import node
from yardstick.orchestrator import heat


TARGET_MODULE = 'yardstick.orchestrator.heat'


def mock_patch_target_module(inner_import):
    return mock.patch('.'.join([TARGET_MODULE, inner_import]))


@contextmanager
def timer():
    start = time.time()
    data = {'start': start}
    try:
        yield data
    finally:
        data['end'] = end = time.time()
        data['delta'] = end - start

def get_error_message(error):
    try:
        # py2
        return error.message
    except AttributeError:
        # py3
        return next((arg for arg in error.args if isinstance(arg, str)), None)


class HeatContextTestCase(unittest.TestCase):

    def test_get_short_key_uuid(self):
        u = uuid.uuid4()
        k = heat.get_short_key_uuid(u)
        self.assertEqual(heat.HEAT_KEY_UUID_LENGTH, len(k))
        self.assertIn(k, str(u))

class HeatTemplateTestCase(unittest.TestCase):

    def setUp(self):
        self.template = heat.HeatTemplate('test')

    def test_add_tenant_network(self):
        self.template.add_network('some-network')

        self.assertEqual(self.template.resources['some-network']['type'], 'OS::Neutron::Net')

    def test_add_provider_network(self):
        self.template.add_network('some-network', 'physnet2', 'sriov')

        self.assertEqual(self.template.resources['some-network']['type'], 'OS::Neutron::ProviderNet')
        self.assertEqual(self.template.resources['some-network']['properties']['physical_network'], 'physnet2')

    def test_add_subnet(self):
        netattrs = {'cidr': '10.0.0.0/24', 'provider': None, 'external_network': 'ext_net'}
        self.template.add_subnet('some-subnet', "some-network", netattrs['cidr'])

        self.assertEqual(self.template.resources['some-subnet']['type'], 'OS::Neutron::Subnet')
        self.assertEqual(self.template.resources['some-subnet']['properties']['cidr'], '10.0.0.0/24')

    def test_add_router(self):
        self.template.add_router('some-router', 'ext-net', 'some-subnet')

        self.assertEqual(self.template.resources['some-router']['type'], 'OS::Neutron::Router')
        self.assertIn('some-subnet', self.template.resources['some-router']['depends_on'])

    def test_add_router_interface(self):
        self.template.add_router_interface('some-router-if', 'some-router', 'some-subnet')

        self.assertEqual(self.template.resources['some-router-if']['type'], 'OS::Neutron::RouterInterface')
        self.assertIn('some-subnet', self.template.resources['some-router-if']['depends_on'])

    def test_add_servergroup(self):
        self.template.add_servergroup('some-server-group', 'anti-affinity')

        self.assertEqual(self.template.resources['some-server-group']['type'], 'OS::Nova::ServerGroup')
        self.assertEqual(self.template.resources['some-server-group']['properties']['policies'], ['anti-affinity'])

    def test__add_resources_to_template_raw(self):
        test_context = node.NodeContext()
        test_context.name = 'foo'
        test_context.template_file = '/tmp/some-heat-file'
        test_context.heat_parameters = {'image': 'cirros'}
        test_context.key_filename = "/tmp/1234"
        test_context.keypair_name = "foo-key"
        test_context.secgroup_name = "foo-secgroup"
        test_context.key_uuid = "2f2e4997-0a8e-4eb7-9fa4-f3f8fbbc393b"
        heat_object = heat.HeatObject()

        heat_stack = heat.HeatStack("tmpStack")
        self.assertTrue(heat_stack.stacks_exist())

        test_context.tmpfile = NamedTemporaryFile(delete=True, mode='w+t')
        test_context.tmpfile.write("heat_template_version: 2015-04-30")
        test_context.tmpfile.flush()
        test_context.tmpfile.seek(0)
        heat_template = heat.HeatTemplate(heat_object)
        heat_template.resources = {}

        heat_template.add_network("network1")
        heat_template.add_network("network2")
        heat_template.add_security_group("sec_group1")
        heat_template.add_security_group("sec_group2")
        heat_template.add_subnet("subnet1", "network1", "cidr1")
        heat_template.add_subnet("subnet2", "network2", "cidr2")
        heat_template.add_router("router1", "gw1", "subnet1")
        heat_template.add_router_interface("router_if1", "router1", "subnet1")
        heat_template.add_port("port1", "network1", "subnet1")
        heat_template.add_port("port2", "network2", "subnet2", sec_group_id="sec_group1",provider="not-sriov")
        heat_template.add_port("port3", "network2", "subnet2", sec_group_id="sec_group1",provider="sriov")
        heat_template.add_floating_ip("floating_ip1", "network1", "port1", "router_if1")
        heat_template.add_floating_ip("floating_ip2", "network2", "port2", "router_if2", "foo-secgroup")
        heat_template.add_floating_ip_association("floating_ip1_association", "floating_ip1", "port1")
        heat_template.add_servergroup("server_grp2", "affinity")
        heat_template.add_servergroup("server_grp3", "anti-affinity")
        heat_template.add_security_group("security_group")
        heat_template.add_server(name="server1", image="image1", flavor="flavor1", flavors=[])
        heat_template.add_server_group(name="servergroup", policies=["policy1","policy2"])
        heat_template.add_server_group(name="servergroup", policies="policy1")
        heat_template.add_server(name="server2", image="image1", flavor="flavor1", flavors=[], ports=["port1", "port2"],
                                 networks=["network1", "network2"], scheduler_hints="hints1", user="user1",
                                 key_name="foo-key", user_data="user", metadata={"cat": 1, "doc": 2},
                                 additional_properties={"prop1": 1, "prop2": 2})
        heat_template.add_server(name="server2", image="image1", flavor="flavor1", flavors=["flavor1", "flavor2"],
                                 ports=["port1", "port2"],
                                 networks=["network1", "network2"], scheduler_hints="hints1", user="user1",
                                 key_name="foo-key", user_data="user", metadata={"cat": 1, "doc": 2},
                                 additional_properties={"prop1": 1, "prop2": 2} )
        heat_template.add_server(name="server2", image="image1", flavor="flavor1", flavors=["flavor3", "flavor4"],
                                 ports=["port1", "port2"],
                                 networks=["network1", "network2"], scheduler_hints="hints1", user="user1",
                                 key_name="foo-key", user_data="user", metadata={"cat": 1, "doc": 2},
                                 additional_properties={"prop1": 1, "prop2": 2})
        heat_template.add_flavor(name="flavor1", vcpus=1, ram=2048, disk=1,extra_specs={"cat": 1, "dog": 2})
        heat_template.add_flavor(name=None, vcpus=1, ram=2048)
        heat_template.add_server(name="server1",
                                 image="image1",
                                 flavor="flavor1",
                                 flavors=[],
                                 ports=["port1", "port2"],
                                 networks=["network1", "network2"],
                                 scheduler_hints="hints1",
                                 user="user1",
                                 key_name="foo-key",
                                 user_data="user",
                                 metadata={"cat": 1, "doc": 2},
                                 additional_properties= {"prop1": 1, "prop2": 2} )
        heat_template.add_network("network1")

        heat_template.add_flavor("test")
        self.assertEqual(heat_template.resources['test']['type'], 'OS::Nova::Flavor')

    @mock_patch_target_module('op_utils')
    @mock_patch_target_module('heatclient.client.Client')
    def test_create_negative(self, mock_heat_client_class, mock_op_utils):
        self.template.HEAT_WAIT_LOOP_INTERVAL = interval = 0.2
        mock_heat_client = mock_heat_client_class()  # get the constructed mock

        # populate attributes of the constructed mock
        mock_heat_client.stacks.get().stack_status_reason = 'the reason'

        expected_status_calls = 0
        expected_constructor_calls = 1  # above, to get the instance
        expected_create_calls = 0
        expected_op_utils_usage = 0

        with mock.patch.object(self.template, 'status', return_value=None) as mock_status:
            # block with timeout hit
            timeout = 2
            with self.assertRaises(RuntimeError) as raised, timer() as time_data:
                self.template.create(block=True, timeout=timeout)

            # ensure runtime is approximately the timeout value
            expected_time_low = timeout - interval * 0.2
            expected_time_high = timeout + interval * 0.2
            self.assertTrue(expected_time_low < time_data['delta'] < expected_time_high)

            # ensure op_utils was used
            expected_op_utils_usage += 1
            self.assertEqual(mock_op_utils.get_session.call_count, expected_op_utils_usage)
            self.assertEqual(mock_op_utils.get_endpoint.call_count, expected_op_utils_usage)
            self.assertEqual(mock_op_utils.get_heat_api_version.call_count, expected_op_utils_usage)

            # ensure the constructor and instance were used
            expected_constructor_calls += 1
            expected_create_calls += 1
            self.assertEqual(mock_heat_client_class.call_count, expected_constructor_calls)
            self.assertEqual(mock_heat_client.stacks.create.call_count, expected_create_calls)

            # ensure that the status was used
            self.assertGreater(mock_status.call_count, expected_status_calls)
            expected_status_calls = mock_status.call_count  # synchronize the value

            # ensure the expected exception was raised
            error_message = get_error_message(raised.exception)
            self.assertIn('timeout', error_message)
            self.assertNotIn('the reason', error_message)

            # block with create failed
            timeout = 10
            mock_status.side_effect = iter([None, None, u'CREATE_FAILED'])
            with self.assertRaises(RuntimeError) as raised, timer() as time_data:
                self.template.create(block=True, timeout=timeout)

            # ensure runtime is approximately two intervals
            expected_time_low = interval * 1.8
            expected_time_high = interval * 2.2
            self.assertTrue(expected_time_low < time_data['delta'] < expected_time_high)

            # ensure the existing heat_client was used and op_utils was used again
            self.assertEqual(mock_op_utils.get_session.call_count, expected_op_utils_usage)
            self.assertEqual(mock_op_utils.get_endpoint.call_count, expected_op_utils_usage)
            self.assertEqual(mock_op_utils.get_heat_api_version.call_count, expected_op_utils_usage)

            # ensure the constructor was not used but the instance was used
            expected_create_calls += 1
            self.assertEqual(mock_heat_client_class.call_count, expected_constructor_calls)
            self.assertEqual(mock_heat_client.stacks.create.call_count, expected_create_calls)

            # ensure that the status was used three times
            expected_status_calls += 3
            self.assertEqual(mock_status.call_count, expected_status_calls)

            # ensure the expected exception was raised
            error_message = get_error_message(raised.exception)
            self.assertNotIn('timeout', error_message)
            self.assertIn('the reason', error_message)

    @mock_patch_target_module('op_utils')
    @mock_patch_target_module('heatclient.client.Client')
    def test_create(self, mock_heat_client_class, mock_op_utils):
        self.template.HEAT_WAIT_LOOP_INTERVAL = interval = 0.2
        mock_heat_client = mock_heat_client_class()

        # populate attributes of the constructed mock
        mock_heat_client.stacks.get().outputs = [
            {'output_key': 'key1', 'output_value': 'value1'},
            {'output_key': 'key2', 'output_value': 'value2'},
            {'output_key': 'key3', 'output_value': 'value3'},
        ]
        expected_outputs = {
            'key1': 'value1',
            'key2': 'value2',
            'key3': 'value3',
        }

        expected_status_calls = 0
        expected_constructor_calls = 1  # above, to get the instance
        expected_create_calls = 0
        expected_op_utils_usage = 0

        with mock.patch.object(self.template, 'status') as mock_status:
            # no block
            with timer() as time_data:
                self.assertIsInstance(self.template.create(block=False, timeout=2), heat.HeatStack)

            # ensure runtime is much less than one interval
            self.assertLess(time_data['delta'], interval * 0.2)

            # ensure op_utils was used
            expected_op_utils_usage += 1
            self.assertEqual(mock_op_utils.get_session.call_count, expected_op_utils_usage)
            self.assertEqual(mock_op_utils.get_endpoint.call_count, expected_op_utils_usage)
            self.assertEqual(mock_op_utils.get_heat_api_version.call_count, expected_op_utils_usage)

            # ensure the constructor and instance were used
            expected_constructor_calls += 1
            expected_create_calls += 1
            self.assertEqual(mock_heat_client_class.call_count, expected_constructor_calls)
            self.assertEqual(mock_heat_client.stacks.create.call_count, expected_create_calls)

            # ensure that the status was not used
            self.assertEqual(mock_status.call_count, expected_status_calls)

            # ensure no outputs because this requires blocking
            self.assertEqual(self.template.outputs, {})

            # block with immediate complete
            mock_status.return_value = u'CREATE_COMPLETE'
            with timer() as time_data:
                self.assertIsInstance(self.template.create(block=True, timeout=2), heat.HeatStack)

            # ensure runtime is less than one interval
            self.assertLess(time_data['delta'], interval * 0.2)

            # ensure existing instance was re-used and op_utils was not used
            expected_create_calls += 1
            self.assertEqual(mock_heat_client_class.call_count, expected_constructor_calls)
            self.assertEqual(mock_heat_client.stacks.create.call_count, expected_create_calls)

            # ensure status was checked once
            expected_status_calls += 1
            self.assertEqual(mock_status.call_count, expected_status_calls)

            # ensure the expected outputs are present
            self.assertDictEqual(self.template.outputs, expected_outputs)

            # reset template outputs
            self.template.outputs = None

            # block with delayed complete
            mock_status.side_effect = iter([None, None, u'CREATE_COMPLETE'])
            with timer() as time_data:
                self.assertIsInstance(self.template.create(block=True, timeout=2), heat.HeatStack)

            # ensure runtime is approximately two intervals
            expected_time_low = interval * 1.8
            expected_time_high = interval * 2.2
            self.assertTrue(expected_time_low < time_data['delta'] < expected_time_high)

            # ensure existing instance was re-used and op_utils was not used
            expected_create_calls += 1
            self.assertEqual(mock_heat_client_class.call_count, expected_constructor_calls)
            self.assertEqual(mock_heat_client.stacks.create.call_count, expected_create_calls)

            # ensure status was checked three more times
            expected_status_calls += 3
            self.assertEqual(mock_status.call_count, expected_status_calls)


class HeatStackTestCase(unittest.TestCase):

    def test_delete_calls__delete_multiple_times(self):
        stack = heat.HeatStack('test')
        stack.uuid = 1
        with mock.patch.object(stack, "_delete") as delete_mock:
            stack.delete()
        # call once and then call again if uuid is not none
        self.assertGreater(delete_mock.call_count, 1)

    def test_delete_all_calls_delete(self):
        stack = heat.HeatStack('test')
        stack.uuid = 1
        with mock.patch.object(stack, "delete") as delete_mock:
            stack.delete_all()
        self.assertGreater(delete_mock.call_count, 0)