<commit_before>import unittest
from textwrap import dedent

from botocore.exceptions import ClientError
from mock import ANY, Mock, patch

from crassus.deployer import (
    Crassus, NOTIFICATION_SUBJECT, ResultMessage, StackUpdateParameter,)

PARAMETER = 'ANY_PARAMETER'
ARN_ID = 'ANY_ARN'
STACK_NAME = 'ANY_STACK'
ANY_TOPIC = ['ANY_TOPIC']

CRASSUS_CFN_PARAMETERS = [
    {
        "updateParameterKey": "ANY_NAME1",
        "updateParameterValue": "ANY_VALUE1"
    },
    {
        "updateParameterKey": "ANY_NAME2",
        "updateParameterValue": "ANY_VALUE2"
    }
]

SAMPLE_EVENT = {
    'Records': [
        {
            'EventVersion': '1.0',
            'EventSubscriptionArn': '<SUBSCRIPTION ARN>',
            'EventSource': 'aws: sns',
            'Sns': {
                'SignatureVersion': '1',
                'Timestamp': '2015-10-23T11: 01: 16.140Z',
                'Signature': '<SIGNATURE>',
                'SigningCertUrl': '<SIGNING URL>',
                'MessageId': '<MESSAGE ID>',
                'Message': '{"version": "1", '
                           '"stackName": "ANY_STACK", '
                           '"region": "eu-west-1", '
                           '"parameters": '
                               '[{"updateParameterKey": "ANY_NAME1", '
                               '"updateParameterValue": "ANY_VALUE1"}, '
                               '{"updateParameterKey": "ANY_NAME2", '
                               '"updateParameterValue": "ANY_VALUE2"}]}',
                'MessageAttributes': {
                },
                'Type': 'Notification',
                'UnsubscribeUrl': '<UNSUBSCRIBE URL>',
                'TopicArn': '<TOPIC ARN>',
                'Subject': None
            }
        }
    ]
}


class TestDeployStack(unittest.TestCase):

    @patch('crassus.deployer.Crassus.load')
    @patch('crassus.deployer.Crassus.update')
    def test_should_call_all_necessary_stuff(self, load_mock, update_mock):
        crassus = Crassus(None, None)
        crassus.deploy()
        load_mock.assert_called_once_with()
        update_mock.assert_called_once_with()


class TestParseParameters(unittest.TestCase):

    def setUp(self):
        self.crassus = Crassus(SAMPLE_EVENT, None)

    def test_parse_valid_event(self):

        self.assertEqual(self.crassus.stack_update_parameters.stack_name,
                         STACK_NAME)


class TestNotify(unittest.TestCase):
    STATUS = 'success'
    MESSAGE = 'ANY MESSAGE'

    @patch('boto3.resource')
    def test_should_notify_sns(self, resource_mock):
        topic_mock = Mock()
        sns_mock = Mock()
        sns_mock.Topic.return_value = topic_mock
        resource_mock.return_value = sns_mock

        self.crassus = Crassus(None, None)
        self.crassus._stack_name = STACK_NAME
        self.crassus._output_topics = ANY_TOPIC

        self.crassus.notify(self.STATUS, self.MESSAGE)

        topic_mock.publish.assert_called_once_with(
            Message=ANY,
            Subject=NOTIFICATION_SUBJECT,
            MessageStructure='string')
        import json
        kwargs = topic_mock.publish.call_args[1]
        expected = ResultMessage(self.STATUS, self.MESSAGE, STACK_NAME)
        self.assertEqual(expected, json.loads(kwargs['Message']))

    @patch('crassus.deployer.Crassus.output_topics', None)
    def test_should_do_gracefully_nothing(self):
        self.crassus = Crassus(None, None)
        self.crassus.notify('status', 'message')


class TestUpdateStack(unittest.TestCase):

    def setUp(self):
        self.stack_mock = Mock()
        self.stack_mock.parameters = [
            {"ParameterKey": "KeyOne",
             "ParameterValue": "OriginalValueOne",
             },
            {"ParameterKey": "KeyTwo",
             "ParameterValue": "OriginalValueTwo",
             }
        ]

        self.update_parameters = {
            "version": 1,
            "stackName": "ANY_STACK",
            "region": "ANY_REGION",
            "parameters":
                {"KeyOne": "UpdateValueOne"},
        }

        self.expected_parameters = [
            {"ParameterKey": "KeyOne",
             "ParameterValue": "UpdateValueOne",
             },
            {"ParameterKey": "KeyTwo",
             "UsePreviousValue": True
             }
        ]
        self.crassus = Crassus(None, None)
        self.crassus._stack_update_parameters = \
            StackUpdateParameter(self.update_parameters)
        self.crassus.stack = self.stack_mock
        self.crassus._stack_name = STACK_NAME
        self.crassus._output_topics = ANY_TOPIC

    @patch('crassus.deployer.Crassus.notify', Mock())
    def test_update_stack_should_call_update(self):
        self.crassus.update()

        self.stack_mock.update.assert_called_once_with(
            UsePreviousTemplate=True,
            Parameters=self.expected_parameters,
            Capabilities=['CAPABILITY_IAM'],
            NotificationARNs=ANY_TOPIC)

    @patch('crassus.deployer.Crassus.notify', Mock())
    @patch('crassus.deployer.logger')
    def test_update_stack_load_throws_clienterror_exception(self, logger_mock):
        self.stack_mock.update.side_effect = ClientError(
            {'Error': {'Code': 'ExpectedException', 'Message': ''}},
            'test_deploy_stack_should_notify_error_in_case_of_client_error')
        self.crassus.update()
        logger_mock.error.assert_called_once_with(ANY)

    """@patch('crassus.deployer.notify')
    def test_update_stack_should_notify_in_case_of_error(self, notify_mock):<commit_msg>fix broken build<commit_after>import unittest
from textwrap import dedent

from botocore.exceptions import ClientError
from mock import ANY, Mock, patch

from crassus.deployer import (
    Crassus, NOTIFICATION_SUBJECT, ResultMessage, StackUpdateParameter,)

PARAMETER = 'ANY_PARAMETER'
ARN_ID = 'ANY_ARN'
STACK_NAME = 'ANY_STACK'
ANY_TOPIC = ['ANY_TOPIC']

CRASSUS_CFN_PARAMETERS = [
    {
        "updateParameterKey": "ANY_NAME1",
        "updateParameterValue": "ANY_VALUE1"
    },
    {
        "updateParameterKey": "ANY_NAME2",
        "updateParameterValue": "ANY_VALUE2"
    }
]

SAMPLE_EVENT = {
    'Records': [
        {
            'EventVersion': '1.0',
            'EventSubscriptionArn': '<SUBSCRIPTION ARN>',
            'EventSource': 'aws: sns',
            'Sns': {
                'SignatureVersion': '1',
                'Timestamp': '2015-10-23T11: 01: 16.140Z',
                'Signature': '<SIGNATURE>',
                'SigningCertUrl': '<SIGNING URL>',
                'MessageId': '<MESSAGE ID>',
                'Message': '{"version": "1", '
                           '"stackName": "ANY_STACK", '
                           '"region": "eu-west-1", '
                           '"parameters": '
                               '[{"updateParameterKey": "ANY_NAME1", '
                               '"updateParameterValue": "ANY_VALUE1"}, '
                               '{"updateParameterKey": "ANY_NAME2", '
                               '"updateParameterValue": "ANY_VALUE2"}]}',
                'MessageAttributes': {
                },
                'Type': 'Notification',
                'UnsubscribeUrl': '<UNSUBSCRIBE URL>',
                'TopicArn': '<TOPIC ARN>',
                'Subject': None
            }
        }
    ]
}


class TestDeployStack(unittest.TestCase):

    @patch('crassus.deployer.Crassus.load')
    @patch('crassus.deployer.Crassus.update')
    def test_should_call_all_necessary_stuff(self, load_mock, update_mock):
        crassus = Crassus(None, None)
        crassus.deploy()
        load_mock.assert_called_once_with()
        update_mock.assert_called_once_with()


class TestParseParameters(unittest.TestCase):

    def setUp(self):
        self.crassus = Crassus(SAMPLE_EVENT, None)

    def test_parse_valid_event(self):

        self.assertEqual(self.crassus.stack_update_parameters.stack_name,
                         STACK_NAME)


class TestNotify(unittest.TestCase):
    STATUS = 'success'
    MESSAGE = 'ANY MESSAGE'

    @patch('boto3.resource')
    def test_should_notify_sns(self, resource_mock):
        topic_mock = Mock()
        sns_mock = Mock()
        sns_mock.Topic.return_value = topic_mock
        resource_mock.return_value = sns_mock

        self.crassus = Crassus(None, None)
        self.crassus._stack_name = STACK_NAME
        self.crassus._output_topics = ANY_TOPIC

        self.crassus.notify(self.STATUS, self.MESSAGE)

        topic_mock.publish.assert_called_once_with(
            Message=ANY,
            Subject=NOTIFICATION_SUBJECT,
            MessageStructure='string')
        import json
        kwargs = topic_mock.publish.call_args[1]
        expected = ResultMessage(self.STATUS, self.MESSAGE, STACK_NAME)
        self.assertEqual(expected, json.loads(kwargs['Message']))

    @patch('crassus.deployer.Crassus.output_topics', None)
    def test_should_do_gracefully_nothing(self):
        self.crassus = Crassus(None, None)
        self.crassus.notify('status', 'message')


class TestUpdateStack(unittest.TestCase):

    def setUp(self):
        self.stack_mock = Mock()
        self.stack_mock.parameters = [
            {"ParameterKey": "KeyOne",
             "ParameterValue": "OriginalValueOne",
             },
            {"ParameterKey": "KeyTwo",
             "ParameterValue": "OriginalValueTwo",
             }
        ]

        self.update_parameters = {
            "version": 1,
            "stackName": "ANY_STACK",
            "region": "ANY_REGION",
            "parameters":
                {"KeyOne": "UpdateValueOne"},
        }

        self.expected_parameters = [
            {"ParameterKey": "KeyOne",
             "ParameterValue": "UpdateValueOne",
             },
            {"ParameterKey": "KeyTwo",
             "UsePreviousValue": True
             }
        ]
        self.crassus = Crassus(None, None)
        self.crassus._stack_update_parameters = \
            StackUpdateParameter(self.update_parameters)
        self.crassus.stack = self.stack_mock
        self.crassus._stack_name = STACK_NAME
        self.crassus._output_topics = ANY_TOPIC

    @patch('crassus.deployer.Crassus.notify', Mock())
    def test_update_stack_should_call_update(self):
        self.crassus.update()

        self.stack_mock.update.assert_called_once_with(
            UsePreviousTemplate=True,
            Parameters=self.expected_parameters,
            Capabilities=['CAPABILITY_IAM'],
            NotificationARNs=None)

    @patch('crassus.deployer.Crassus.notify', Mock())
    @patch('crassus.deployer.logger')
    def test_update_stack_load_throws_clienterror_exception(self, logger_mock):
        self.stack_mock.update.side_effect = ClientError(
            {'Error': {'Code': 'ExpectedException', 'Message': ''}},
            'test_deploy_stack_should_notify_error_in_case_of_client_error')
        self.crassus.update()
        logger_mock.error.assert_called_once_with(ANY)

    """@patch('crassus.deployer.notify')
    def test_update_stack_should_notify_in_case_of_error(self, notify_mock):
{'fraction_non_alphanumeric': 0.11596032461677187, 'fraction_numerical': 0.005951307484220018, 'mean_word_length': 2.2534467585802287, 'pattern_counts': {'":': 50, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1869641', 'n_tokens_mistral': 3382, 'n_tokens_neox': 3277, 'n_words': 485}