text: """Tests for runway.cfngin.hooks.base."""
  # pylint: disable=no-self-use,too-few-public-methods
  import logging
  
  import pytest
  from mock import MagicMock, call, patch
  
  from runway.cfngin.exceptions import StackFailed
  from runway.cfngin.hooks.base import (
      Hook,
      HookBuildAction,
      HookDestroyAction,
      HookStackDefinition,
  )
  from runway.cfngin.status import (
      COMPLETE,
      FAILED,
      SKIPPED,
      SUBMITTED,
      CompleteStatus,
      SubmittedStatus,
  )
  
  COMPLETE_W_REASON = CompleteStatus("test successful")
  
  
  class TestHook(object):
      """Tests for runway.cfngin.hooks.base.Hook."""
  
      def test_attributes(self, cfngin_context):
          """Test attributes set during __init__."""
          provider = MagicMock()
          args = {"key": "val"}
          result = Hook(cfngin_context, provider, **args)
  
          assert result.args.key == "val"
          assert result.args.tags == {}
          assert not result.blueprint
          assert result.context == cfngin_context
          assert result.provider == provider
          assert not result.stack
          assert result.stack_name == "stack"
  
      def test_tags(self, cfngin_context):
          """Test tags property."""
          cfngin_context.config["tags"] = {"context_tag": "val"}
  
          hook = Hook(cfngin_context, MagicMock(), **{"tags": {"arg_tag": "val"}})
  
          assert hook.tags.to_dict() == [
              {"Key": "arg_tag", "Value": "val"},
              {"Key": "context_tag", "Value": "val"},
          ]
  
      def test_get_template_description(self, cfngin_context):
          """Test for get_template_description."""
          hook = Hook(cfngin_context, MagicMock())
  
          result = hook.get_template_description()
  
          assert result == "Automatically generated by {}".format(
              hook.__class__.__module__
          )
          assert hook.get_template_description("suffix").endswith(" - suffix")
  
      @patch(
          "runway.cfngin.hooks.base.HookBuildAction.run", MagicMock(return_value=COMPLETE)
      )
      def test_deploy_stack(self, cfngin_context, caplog):
          """Test for deploy_stack."""
          hook = Hook(cfngin_context, MagicMock())
          stack = MagicMock()
          stack.name = "test-stack"
  
          with caplog.at_level(logging.INFO, logger="runway.cfngin.hooks.base"):
              assert hook.deploy_stack(stack=stack, wait=False) == COMPLETE
  
          assert caplog.records[0].message == "%s:%s" % (stack.name, COMPLETE.name)
  
      @patch(
          "runway.cfngin.hooks.base.HookBuildAction.run",
          MagicMock(side_effect=[SUBMITTED, COMPLETE]),
      )
      def test_deploy_stack_wait(self, cfngin_context, caplog):
          """Test for deploy_stack with wait."""
          hook = Hook(cfngin_context, MagicMock())
          stack = MagicMock()
          stack.name = "test-stack"
  
          with caplog.at_level(logging.DEBUG, logger="runway.cfngin.hooks.base"):
              assert hook.deploy_stack(stack=stack, wait=True) == COMPLETE
  
          assert caplog.records[0].message == "%s:%s" % (stack.name, SUBMITTED.name)
          assert caplog.records[1].message == "waiting for stack to complete..."
          assert caplog.records[2].message == "%s:%s" % (stack.name, COMPLETE.name)
  
      @patch(
          "runway.cfngin.hooks.base.HookBuildAction.run", MagicMock(side_effect=[SKIPPED])
      )
      def test_deploy_stack_wait_skipped(self, cfngin_context, caplog):
          """Test for deploy_stack with wait and skip."""
          hook = Hook(cfngin_context, MagicMock())
          stack = MagicMock()
          stack.name = "test-stack"
  
          with caplog.at_level(logging.INFO, logger="runway.cfngin.hooks.base"):
              assert hook.deploy_stack(stack=stack, wait=True) == SKIPPED
  
          assert caplog.records[0].message == "%s:%s" % (stack.name, SKIPPED.name)
  
      @patch(
          "runway.cfngin.hooks.base.HookBuildAction.run", MagicMock(side_effect=[FAILED])
      )
      def test_deploy_stack_wait_failed(self, cfngin_context):
          """Test for deploy_stack with wait and skip."""
          hook = Hook(cfngin_context, MagicMock())
          stack = MagicMock()
          stack.name = "test-stack"
  
          with pytest.raises(StackFailed):
              assert hook.deploy_stack(stack=stack, wait=True) == FAILED
  
      @patch(
          "runway.cfngin.hooks.base.HookDestroyAction.run",
          MagicMock(side_effect=[SUBMITTED, COMPLETE_W_REASON]),
      )
      def test_destroy_stack(self, cfngin_context, caplog):
          """Test for destroy_stack with wait."""
          hook = Hook(cfngin_context, MagicMock())
          stack = MagicMock()
          stack.name = "test-stack"
  
          with caplog.at_level(logging.DEBUG, logger="runway.cfngin.hooks.base"):
              assert hook.destroy_stack(stack=stack, wait=True) == COMPLETE
  
          assert caplog.records[0].message == "%s:%s" % (stack.name, SUBMITTED.name)
          assert caplog.records[1].message == "waiting for stack to complete..."
          assert caplog.records[2].message == "%s:%s (%s)" % (
              stack.name,
              COMPLETE_W_REASON.name,
              COMPLETE_W_REASON.reason,
          )
  
      def test_wait_for_stack_till_reason(self, cfngin_context):
          """Test _wait_for_stack till_reason option."""
          hook = Hook(cfngin_context, MagicMock())
          stack = MagicMock(fqn="test-stack", name="stack")
          action = MagicMock()
          action.run.side_effect = [
              SUBMITTED,
              SubmittedStatus("not yet"),
              SubmittedStatus("catch"),
              COMPLETE,
          ]
  
          result = hook._wait_for_stack(  # pylint: disable=protected-access
              action, stack=stack, till_reason="catch"
          )
          assert result == SUBMITTED
          assert result.reason == "catch"
  
      def test_wait_for_stack_log_change(self, cfngin_context, monkeypatch):
          """Test _wait_for_stack log status change."""
          hook = Hook(cfngin_context, MagicMock())
          stack = MagicMock(fqn="test-stack", name="stack")
          new_status = SubmittedStatus("new")
          action = MagicMock()
          action.run.side_effect = [new_status, COMPLETE]
          mock_log = MagicMock()
  
          monkeypatch.setattr(hook, "_log_stack", mock_log)
  
          hook._wait_for_stack(  # pylint: disable=protected-access
              action,
              last_status=SubmittedStatus("original"),
              stack=stack,
              till_reason="catch",
          )
  
          mock_log.assert_has_calls([call(stack, new_status), call(stack, COMPLETE)])
          assert mock_log.call_count == 2
  
      def test_post_deploy(self, cfngin_context):
          """Test post_deploy."""
          hook = Hook(cfngin_context, MagicMock())
  
          with pytest.raises(NotImplementedError):
              hook.post_deploy()
  
      def test_post_destroy(self, cfngin_context):
          """Test post_destroy."""
          hook = Hook(cfngin_context, MagicMock())
  
          with pytest.raises(NotImplementedError):
              hook.post_destroy()
  
      def test_pre_deploy(self, cfngin_context):
          """Test pre_deploy."""
          hook = Hook(cfngin_context, MagicMock())
  
          with pytest.raises(NotImplementedError):
              hook.pre_deploy()
  
      def test_pre_destroy(self, cfngin_context):
          """Test pre_destroy."""
          hook = Hook(cfngin_context, MagicMock())
  
          with pytest.raises(NotImplementedError):
              hook.pre_destroy()
  
  
  class TestHookBuildAction(object):
      """Tests for runway.cfngin.hooks.base.HookBuildAction."""
  
      def test_provider(self, cfngin_context):
          """Test provider property."""
          provider = MagicMock()
          obj = HookBuildAction(cfngin_context, provider)
  
          assert obj.provider == provider
  
      def test_build_provider(self, cfngin_context):
          """Test build_provider."""
          provider = MagicMock()
          obj = HookBuildAction(cfngin_context, provider)
  
          assert obj.build_provider(None) == provider
  
      def test_run(self, cfngin_context, monkeypatch):
          """Test run."""
          obj = HookBuildAction(cfngin_context, MagicMock())
          monkeypatch.setattr(obj, "_launch_stack", lambda: "success")
  
          assert obj.run() == "success"
  
  
  class TestHookDestroyAction(object):
      """Tests for runway.cfngin.hooks.base.HookDestroyAction."""
  
      def test_run(self, cfngin_context, monkeypatch):
          """Test run."""
          obj = HookDestroyAction(cfngin_context, MagicMock())
          monkeypatch.setattr(obj, "_destroy_stack", lambda: "success")
  
          assert obj.run() == "success"
  
  
  class TestHookStackDefinition(object):
      """Tests for runway.cfngin.hooks.base.HookStackDefinition."""
  
      def test_getattr(self):
          """Test __getattr__."""
          obj = HookStackDefinition("test")
  
          assert obj.name == "test"
  
          with pytest.raises(AttributeError):
              assert obj.invalid
  