"""Tests for the actors.slack package"""

import mock

from tornado import testing

from kingpin.actors import slack
from kingpin.actors import exceptions
from kingpin.actors.test.helper import mock_tornado
import importlib


__author__ = 'Matt Wise <matt@nextdoor.com>'


class TestSlackBase(testing.AsyncTestCase):

    """Unit tests for the Slack Base actor."""

    def setUp(self, *args, **kwargs):
        # For most tests, mock out the TOKEN
        super(TestSlackBase, self).setUp(*args, **kwargs)
        slack.TOKEN = 'Unittest'

    def test_init(self):
        actor = slack.SlackBase('Unit test action', {})

        # Ensure that the actor._slack_client is configured with a dictionary
        # that contains the token in it.
        slack_client_tokens = actor._slack_client._client._tokens
        self.assertEqual(
            slack_client_tokens,
            {'token': 'Unittest'})

    def test_init_missing_creds(self):
        # Un-set the token now and make sure the init fails
        slack.TOKEN = None
        with self.assertRaises(exceptions.InvalidCredentials):
            slack.SlackBase('Unit Test Action', {})
        # Reload the slack library to re-get the token
        importlib.reload(slack)

    def test_check_results_with_ok_results(self):
        actor = slack.SlackBase('Unit test action', {})
        results = {
            "ok": True, "channel": "C03H4GRDF", "ts": "1423092527.000006",
            "message": {
                "text": "Hi, testing!",
                "username": "Kingpin",
                "type": "message",
                "subtype": "bot_message",
                "ts": "1423092527.000006"
            }
        }
        self.assertEqual(None, actor._check_results(results))

    def test_check_results_with_invalid_creds(self):
        actor = slack.SlackBase('Unit test action', {})
        results = {'ok': False, 'error': 'invalid_auth'}
        with self.assertRaises(exceptions.InvalidCredentials):
            actor._check_results(results)

    def test_check_results_with_unexpected_results(self):
        actor = slack.SlackBase('Unit test action', {})
        results = 'got some unexpected result'
        with self.assertRaises(exceptions.UnrecoverableActorFailure):
            actor._check_results(results)


class TestMessage(testing.AsyncTestCase):

    """Unit tests for the Slack Message actor."""

    def setUp(self, *args, **kwargs):
        # For most cases, mock out the TOKEN
        super(TestMessage, self).setUp(*args, **kwargs)
        slack.TOKEN = 'Unittest'

        self.actor = slack.Message(
            'Unit test message',
            {'channel': '#testing',
             'message': 'Unittest'})
        self._slack_mock = mock.MagicMock(name='SlackAPIMock')
        self.actor._slack_client = self._slack_mock

    @testing.gen_test
    def test_execute_dry(self):
        # Mock out the calls to SlackAPI.auth_test().auth_test()
        auth_test_mock = mock.MagicMock(name='auth_test')
        auth_test_mock.http_post.side_effect = mock_tornado({'ok': 'true'})
        self._slack_mock.auth_test.return_value = auth_test_mock

        # Ensure we're dry
        self.actor._dry = True
        ret = yield self.actor._execute()
        self.assertEqual(None, ret)

        # Ensure the calls were made to the API
        auth_test_mock.http_post.assert_has_calls([mock.call()])

    @testing.gen_test
    def test_execute(self):
        # Mock out the calls to SlackAPI.chat_postMessage().http_post()
        post_mock = mock.MagicMock()
        post_mock.http_post.side_effect = mock_tornado({'ok': 'true'})
        self._slack_mock.chat_postMessage.return_value = post_mock

        ret = yield self.actor._execute()
        self.assertEqual(None, ret)

        # Ensure the calls were made to the API
        post_mock.http_post.assert_has_calls([mock.call(
            username='Kingpin', unfurl_links=True, text='Unittest',
            unfurl_media=True, parse='none', link_names=1, channel='#testing'
        )])

    @testing.gen_test
    def test_execute_list_rooms(self):
        actor = slack.Message(
            'Unit test message',
            {'channel': ['#testing', '#testing2'],
             'message': 'Unittest'})
        actor._slack_client = self._slack_mock

        # Mock out the calls to SlackAPI.chat_postMessage().http_post()
        post_mock = mock.MagicMock()
        post_mock.http_post.side_effect = mock_tornado({'ok': 'true'})
        self._slack_mock.chat_postMessage.return_value = post_mock

        ret = yield actor._execute()
        self.assertEqual(None, ret)

        # Ensure the calls were made to the API
        post_mock.http_post.assert_has_calls([mock.call(
            username='Kingpin', unfurl_links=True, text='Unittest',
            unfurl_media=True, parse='none', link_names=1, channel='#testing'
        )])

    @testing.gen_test
    def test_execute_csv_rooms(self):
        actor = slack.Message(
            'Unit test message',
            {'channel': '#testing, #testing2',
             'message': 'Unittest'})
        actor._slack_client = self._slack_mock

        # Mock out the calls to SlackAPI.chat_postMessage().http_post()
        post_mock = mock.MagicMock()
        post_mock.http_post.side_effect = mock_tornado({'ok': 'true'})
        self._slack_mock.chat_postMessage.return_value = post_mock

        ret = yield actor._execute()
        self.assertEqual(None, ret)

        # Ensure the calls were made to the API
        post_mock.http_post.assert_has_calls([mock.call(
            username='Kingpin', unfurl_links=True, text='Unittest',
            unfurl_media=True, parse='none', link_names=1, channel='#testing'
        )])
