<filename>tests/test_client.py
from unittest import TestCase
from unittest import mock

from slack_backup import client
from slack_backup import objects as o

CHANNELS = {"ok": True,
            "channels": [{"id": "C00000000",
                          "name": "somechannel",
                          "is_channel": True,
                          "created": 1479147929,
                          "creator": "UAAAAAAAA",
                          "is_archived": False,
                          "is_general": False,
                          "is_member": True,
                          "members": ["UAAAAAAAA",
                                      "UBBBBBBBB",
                                      "UCCCCCCCC"],
                          "topic": {"value": "",
                                    "creator": "",
                                    "last_set": 0},
                          "purpose": {"value": "",
                                      "creator": "",
                                      "last_set": 0},
                          "num_members": 7},
                         {"id": "C00000001",
                          "name": "general",
                          "is_channel": True,
                          "created": 1416042849,
                          "creator": "USLACKBOT",
                          "is_archived": False,
                          "is_general": True,
                          "is_member": True,
                          "members": ["UAAAAAAAA",
                                      "UBBBBBBBB",
                                      "UCCCCCCCC"],
                          "topic": {"value": "",
                                    "creator": "",
                                    "last_set": 0},
                          "purpose": {"value": "This channel is for team-wide"
                                               " communication and "
                                               "announcements. All team "
                                               "members are in this channel.",
                                      "creator": "",
                                      "last_set": 0},
                          "num_members": 14}]}

PROFILES = [{'always_active': False,
             'api_app_id': '',
             'avatar_hash': '167c4585f3b5',
             'bot_id': 'B34RR91SQ',
             'image_1024': 'https://bla.com/2016-11-19/12345_72.png',
             'image_192': 'https://bla.com/2016-11-19/12345_72.png',
             'image_24': 'https://bla.com/2016-11-19/12345_24.png',
             'image_32': 'https://bla.com/2016-11-19/12345_32.png',
             'image_48': 'https://bla.com/2016-11-19/12345_48.png',
             'image_512': 'https://bla.com/2016-11-19/12345_72.png',
             'image_72': 'https://bla.com/2016-11-19/12345_72.png',
             'image_original': 'https://bla.com/2016-11-19/12345_original.png',
             'real_name': '',
             'real_name_normalized': '',
             'title': 'all your base are belongs to us'},
            {'avatar_hash': 'bab01f158419',
             'email': '<EMAIL>',
             'first_name': 'name',
             'image_1024': 'https://bla.com/2016-11-19/23456_512.png',
             'image_192': 'https://bla.com/2016-11-19/23456_192.png',
             'image_24': 'https://bla.com/2016-11-19/23456_24.png',
             'image_32': 'https://bla.com/2016-11-19/23456_32.png',
             'image_48': 'https://bla.com/2016-11-19/23456_48.png',
             'image_512': 'https://bla.com/2016-11-19/23456_512.png',
             'image_72': 'https://bla.com/2016-11-19/23456_72.png',
             'image_original': 'https://bla.com/2016-11-19/23456_original.png',
             'last_name': 'lastname',
             'real_name': '<NAME>',
             'real_name_normalized': 'name lastname'},
            {'avatar_hash': '398907b00c64',
             'email': '<EMAIL>',
             'first_name': 'othername',
             'image_1024': 'https://bla.com/2016-11-19/34567_72.gif',
             'image_192': 'https://bla.com/2016-11-19/34567_72.gif',
             'image_24': 'https://bla.com/2016-11-19/34567_24.gif',
             'image_32': 'https://bla.com/2016-11-19/34567_32.gif',
             'image_48': 'https://bla.com/2016-11-19/34567_48.gif',
             'image_512': 'https://bla.com/2016-11-19/34567_72.gif',
             'image_72': 'https://bla.com/2016-11-19/34567_72.gif',
             'image_original': 'https://bla.com/2016-11-19/34567_original.gif',
             'last_name': 'totallylast',
             'phone': '',
             'real_name': 'othername totallylast',
             'real_name_normalized': 'othername totallylast',
             'skype': '',
             'title': 'blah & blah'},
            {'avatar_hash': 'sv1454671952',
             'fields': None,
             'first_name': 'slackbot',
             'image_192': 'https://bla.com/65f9/img/slackbot_192.png',
             'image_24': 'https://bla.com/181c/img/slackbot_24.png',
             'image_32': 'https://bla.com/0fac/slackbot/assets/service_32.png',
             'image_48': 'https://bla.com/4fac/slackbot/assets/service_48.png',
             'image_512': 'https://bla.com/1803/img/slackbot_512.png',
             'image_72': 'https://bla.com/1780/img/slackbot_72.png',
             'last_name': '',
             'real_name': 'slackbot',
             'real_name_normalized': 'slackbot'}]

USERS = {'cache_ts': 1479577519,
         'ok': True,
         'members': [{'color': 'd58247',
                      'deleted': False,
                      'id': 'UAAAAAAAA',
                      'is_admin': False,
                      'is_bot': True,
                      'is_owner': False,
                      'is_primary_owner': False,
                      'is_restricted': False,
                      'is_ultra_restricted': False,
                      'name': 'borg',
                      'profile': PROFILES[0],
                      'real_name': '',
                      'status': None,
                      'team_id': 'T0000TEST',
                      'tz': None,
                      'tz_label': 'Pacific Standard Time',
                      'tz_offset': -28800},
                     {'color': '4bbe2e',
                      'deleted': False,
                      'has_2fa': False,
                      'id': 'UBBBBBBBB',
                      'is_admin': True,
                      'is_bot': False,
                      'is_owner': True,
                      'is_primary_owner': False,
                      'is_restricted': False,
                      'is_ultra_restricted': False,
                      'name': 'name1',
                      'profile': PROFILES[1],
                      'real_name': '<NAME>',
                      'status': None,
                      'team_id': 'T0000TEST',
                      'tz': 'America/Los_Angeles',
                      'tz_label': 'Pacific Standard Time',
                      'tz_offset': -28800},
                     {'color': 'e96699',
                      'deleted': False,
                      'has_2fa': False,
                      'id': 'UCCCCCCCC',
                      'is_admin': False,
                      'is_bot': False,
                      'is_owner': False,
                      'is_primary_owner': False,
                      'is_restricted': False,
                      'is_ultra_restricted': False,
                      'name': 'name2',
                      'profile': PROFILES[2],
                      'real_name': '<NAME>',
                      'status': None,
                      'team_id': 'T0000TEST',
                      'tz': 'America/Los_Angeles',
                      'tz_label': 'Pacific Standard Time',
                      'tz_offset': -28800},
                     {'color': '757575',
                      'deleted': False,
                      'id': 'USLACKBOT',
                      'is_admin': False,
                      'is_bot': False,
                      'is_owner': False,
                      'is_primary_owner': False,
                      'is_restricted': False,
                      'is_ultra_restricted': False,
                      'name': 'slackbot',
                      'profile': PROFILES[3],
                      'real_name': 'slackbot',
                      'status': None,
                      'team_id': 'T0000TEST',
                      'tz': None,
                      'tz_label': 'Pacific Standard Time',
                      'tz_offset': -28800}]}

MSGS = {'messages': [{"type": "message",
                      "user": "UAAAAAAAA",
                      "text": "Class aptent taciti sociosqu ad litora torquent"
                              " per conubia nostra, per",
                      "ts": "1479501074.000032"},
                     {"reactions": [{"name": "+1",
                                     "users": ["UBBBBBBBB", "UCCCCCCCC"],
                                     "count": 2}],
                      "attachments": [{"service_icon": "https://bla/icon.png",
                                       "title": "Nulla sollicitudin",
                                       "thumb_width": 400,
                                       "thumb_height": 400,
                                       "from_url": "https://bla",
                                       "service_name": "Bla",
                                       "fallback": "Bla: Nulla sollicitudin",
                                       "title_link": "https://bla/nulla",
                                       "text": "Bla - bla bla",
                                       "thumb_url": "https://avatars/1.gif",
                                       "id": 1}],
                      "type": "message",
                      "user": "UCCCCCCCC",
                      "text": "Mauris ut metus sit amet mi cursus commodo. "
                              "Morbi congue mauris ac sapien. "
                              "https://bla/nulla",
                      "ts": "1479493038.000029"},
                     {"subtype": "pinned_item",
                      "item": {"mode": "hosted",
                               "size": 2949,
                               "comments_count": 1,
                               "timestamp": 1479146954,
                               "url_private_download": "https://files.slack."
                                                       "com/files-pri/bin.bin",
                               "is_external": False,
                               "external_type": "",
                               "username": "",
                               "display_as_bot": False,
                               "pinned_to": ["C00000001"],
                               "permalink_public": "https://slack-files.com/"
                                                   "hash",
                               "channels": ["C00000001"],
                               "title": "binary.prg",
                               "ims": [],
                               "url_private": "https://files.slack.com/hash/"
                                              "binary.prg",
                               "groups": [],
                               "filetype": "binary",
                               "user": "UAAAAAAAA",
                               "initial_comment": {"is_intro": True,
                                                   "user": "UAAAAAAAA",
                                                   "channel": "",
                                                   "timestamp": 1479146954,
                                                   "created": 1479146954,
                                                   "comment": "sample image",
                                                   "id": "Fc331R6CNT"},
                               "permalink": "https://bla.slack.com/files/borg/"
                                            "F331R60LX/binary.prg",
                               "name": "Conan.hires.prg",
                               "num_stars": 1,
                               "public_url_shared": False,
                               "is_public": True,
                               "mimetype": "application/octet-stream",
                               "created": 1479146954,
                               "id": "F331R60LX",
                               "pretty_type": "Binary",
                               "editable": False},
                      "item_type": "F",
                      "type": "message",
                      "user": "UAAAAAAAA",
                      "text": "<@UAAAAAAAA|borg> pinned their Binary "
                              "<https://bla.slack.com/files/borg/F331R60LX/"
                              "binary.prg|Binary.prg> to this channel.",
                      "ts": "1479146975.000197"},
                     {"type": "message",
                      "subtype": "channel_join",
                      "user": "UAAAAAAAA",
                      "text": "<@UAAAAAAAA|borg> has joined the channel",
                      "ts": "1479108214.000002"},
                     {"display_as_bot": False,
                      "subtype": "file_share",
                      "username": "<@UCCCCCCCC|name2>",
                      "file": {"thumb_960": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_960.png",
                               "user": "UCCCCCCCC",
                               "size": 77222,
                               "thumb_1024_h": 754,
                               "timestamp": 1479407569,
                               "url_private_download": "https://files.slack.co"
                                                       "m/files-pri/hsh/downlo"
                                                       "ad/screenshot.png",
                               "thumb_360": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_360.png",
                               "username": "",
                               "external_type": "",
                               "thumb_64": "https://files.slack.com/files-tmb/"
                                           "hash/screenshot_64.png",
                               "created": 1479407569,
                               "ims": [],
                               "groups": [],
                               "filetype": "png",
                               "thumb_1024": "https://files.slack.com/files-"
                                             "tmb/hash/screenshot_1024.png",
                               "original_w": 1193,
                               "name": "Screenshot.png",
                               "thumb_360_h": 265,
                               "is_public": True,
                               "thumb_960_h": 707,
                               "original_h": 878,
                               "mimetype": "image/png",
                               "id": "F3405RRB5",
                               "pretty_type": "PNG",
                               "editable": False,
                               "thumb_960_w": 960,
                               "thumb_80": "https://files.slack.com/files-tmb/"
                                           "hash/screenshot_80.png",
                               "comments_count": 0,
                               "image_exif_rotation": 1,
                               "thumb_160": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_160.png",
                               "thumb_480_w": 480,
                               "is_external": False,
                               "display_as_bot": False,
                               "thumb_720_h": 530,
                               "channels": ["C00000001"],
                               "title": "Screenshot.png",
                               "thumb_480": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_480.png",
                               "url_private": "https://files.slack.com/files-"
                                              "pri/hsh/screenshot.png",
                               "mode": "hosted",
                               "thumb_1024_w": 1024,
                               "permalink": "https://esm64.slack.com/files/"
                                            "name2/F3405RRB5/screenshot.png",
                               "thumb_480_h": 353,
                               "public_url_shared": False,
                               "thumb_720": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_720.png",
                               "thumb_360_w": 360,
                               "permalink_public": "https://slack-files.com/"
                                                   "hsh-7dbb96b758",
                               "thumb_720_w": 720},
                      "type": "message",
                      "user": "UCCCCCCCC",
                      "bot_id": None,
                      "text": "<@UCCCCCCCC|name2> uploaded a file: "
                              "<https://esm64.slack.com/files/name2/F3405RRB5/"
                              "screenshot.png|Screenshot.png>",
                      "ts": "1478107371.000052",
                      "upload": True},
                     {'type': 'something else',
                      'ts': '1502003415232.000001',
                      "wibblr": True}],
        "ok": True,
        "latest": "1479501075.000020",
        "has_more": True}

MSG2 = {'messages': [{"type": "message",
                      "user": "UCCCCCCCC",
                      "text": "Pellentesque molestie nunc id enim. Etiam "
                              "mollis tempus neque. Duis. per conubia "
                              "nostra, per",
                      "ts": "1479505026.000002"}],
        "ok": True,
        "latest": "1479505026.000003",
        "has_more": True}

MSG3 = {"ok": True,
        "oldest": "1479505026.000003",
        "messages": [],
        "has_more": False,
        "is_limited": False}


class FakeArgs(object):
    token = 'token_string'
    user = 'fake_user'
    password = '<PASSWORD>password'
    team = 'fake_team'
    database = None
    channels = None

    def __contains__(self, key):
        return hasattr(self, key)


class TestApiCalls(TestCase):

    def test_channels_list(self):
        cl = client.Client(FakeArgs())
        cl.slack.api_call = mock.MagicMock(return_value=CHANNELS)
        channels = cl._channels_list()
        self.assertListEqual(CHANNELS['channels'], channels)

    def test_users_list(self):
        cl = client.Client(FakeArgs())
        cl.slack.api_call = mock.MagicMock(return_value=USERS)
        users = cl._users_list()
        self.assertListEqual(USERS['members'], users)

    def test_channels_history(self):
        cl = client.Client(FakeArgs())

        cl.slack.api_call = mock.MagicMock(return_value=USERS)
        cl.downloader._download = mock.MagicMock(return_value=None)
        cl.update_users()

        cl.slack.api_call = mock.MagicMock(return_value=CHANNELS)
        cl.update_channels()

        cl.slack.api_call = mock.MagicMock()
        cl.slack.api_call.side_effect = [MSGS, MSG2, MSG3]

        channel = cl.q(o.Channel).filter(o.Channel.slackid ==
                                         "C00000001").one()

        msg, ts = cl._channels_history(channel, 0)
        self.assertEqual(len(msg), 6)
        self.assertEqual(ts, '1479501074.000032')

        msg, ts = cl._channels_history(channel, ts)
        self.assertEqual(len(msg), 1)
        self.assertEqual(ts, '1479505026.000002')

        msg, ts = cl._channels_history(channel, ts)
        self.assertEqual(len(msg), 0)
        self.assertIsNone(ts)


class TestClient(TestCase):

    def test_update_users(self):
        cl = client.Client(FakeArgs())
        cl.slack.api_call = mock.MagicMock(return_value=USERS)
        cl.downloader._download = mock.MagicMock(return_value=None)
        cl.update_users()
        users = cl.session.query(o.User).all()
        self.assertEqual(len(users), 4)
        self.assertEqual(users[0].id, 1)

        cl.update_users()
        users = cl.session.query(o.User).all()
        self.assertEqual(len(users), 4)
        self.assertEqual(users[0].id, 1)
        self.assertEqual(users[0].slackid, 'UAAAAAAAA')


class TestMessage(TestCase):

    def setUp(self):
        args = FakeArgs()
        args.channels = ['general']

        self.cl = client.Client(args)
        self.cl.downloader.authorize = mock.MagicMock()
        self.cl.slack.api_call = mock.MagicMock(return_value=USERS)
        self.cl.downloader._download = mock.MagicMock(return_value=None)
        self.cl.update_users()

        self.cl.slack.api_call = mock.MagicMock(return_value=CHANNELS)
        self.cl.update_channels()

        self.cl.slack.api_call = mock.MagicMock()

    @mock.patch('slack_backup.download.Download.download')
    def test_update_history(self, download):

        download.return_value = 'foo'

        self.cl.downloader._download = mock.MagicMock(return_value=None)
        self.cl.slack.api_call.side_effect = [MSGS, MSG3]
        self.cl.update_history()
        self.assertEqual(len(self.cl.q(o.Message).all()), 5)

        self.cl.slack.api_call.side_effect = [MSG2, MSG3]
        self.cl.update_history()

        self.assertEqual(len(self.cl.q(o.Message).all()), 6)

<filename>tests/test_client.py
from unittest import TestCase
from unittest import mock

from slack_backup import client
from slack_backup import objects as o

CHANNELS = {"ok": True,
            "channels": [{"id": "C00000000",
                          "name": "somechannel",
                          "is_channel": True,
                          "created": 1479147929,
                          "creator": "UAAAAAAAA",
                          "is_archived": False,
                          "is_general": False,
                          "is_member": True,
                          "members": ["UAAAAAAAA",
                                      "UBBBBBBBB",
                                      "UCCCCCCCC"],
                          "topic": {"value": "",
                                    "creator": "",
                                    "last_set": 0},
                          "purpose": {"value": "",
                                      "creator": "",
                                      "last_set": 0},
                          "num_members": 7},
                         {"id": "C00000001",
                          "name": "general",
                          "is_channel": True,
                          "created": 1416042849,
                          "creator": "USLACKBOT",
                          "is_archived": False,
                          "is_general": True,
                          "is_member": True,
                          "members": ["UAAAAAAAA",
                                      "UBBBBBBBB",
                                      "UCCCCCCCC"],
                          "topic": {"value": "",
                                    "creator": "",
                                    "last_set": 0},
                          "purpose": {"value": "This channel is for team-wide"
                                               " communication and "
                                               "announcements. All team "
                                               "members are in this channel.",
                                      "creator": "",
                                      "last_set": 0},
                          "num_members": 14}]}

PROFILES = [{'always_active': False,
             'api_app_id': '',
             'avatar_hash': '167c4585f3b5',
             'bot_id': 'B34RR91SQ',
             'image_1024': 'https://bla.com/2016-11-19/12345_72.png',
             'image_192': 'https://bla.com/2016-11-19/12345_72.png',
             'image_24': 'https://bla.com/2016-11-19/12345_24.png',
             'image_32': 'https://bla.com/2016-11-19/12345_32.png',
             'image_48': 'https://bla.com/2016-11-19/12345_48.png',
             'image_512': 'https://bla.com/2016-11-19/12345_72.png',
             'image_72': 'https://bla.com/2016-11-19/12345_72.png',
             'image_original': 'https://bla.com/2016-11-19/12345_original.png',
             'real_name': '',
             'real_name_normalized': '',
             'title': 'all your base are belongs to us'},
            {'avatar_hash': 'bab01f158419',
             'email': '<EMAIL>',
             'first_name': 'name',
             'image_1024': 'https://bla.com/2016-11-19/23456_512.png',
             'image_192': 'https://bla.com/2016-11-19/23456_192.png',
             'image_24': 'https://bla.com/2016-11-19/23456_24.png',
             'image_32': 'https://bla.com/2016-11-19/23456_32.png',
             'image_48': 'https://bla.com/2016-11-19/23456_48.png',
             'image_512': 'https://bla.com/2016-11-19/23456_512.png',
             'image_72': 'https://bla.com/2016-11-19/23456_72.png',
             'image_original': 'https://bla.com/2016-11-19/23456_original.png',
             'last_name': 'lastname',
             'real_name': '<NAME>',
             'real_name_normalized': 'name lastname'},
            {'avatar_hash': '398907b00c64',
             'email': '<EMAIL>',
             'first_name': 'othername',
             'image_1024': 'https://bla.com/2016-11-19/34567_72.gif',
             'image_192': 'https://bla.com/2016-11-19/34567_72.gif',
             'image_24': 'https://bla.com/2016-11-19/34567_24.gif',
             'image_32': 'https://bla.com/2016-11-19/34567_32.gif',
             'image_48': 'https://bla.com/2016-11-19/34567_48.gif',
             'image_512': 'https://bla.com/2016-11-19/34567_72.gif',
             'image_72': 'https://bla.com/2016-11-19/34567_72.gif',
             'image_original': 'https://bla.com/2016-11-19/34567_original.gif',
             'last_name': 'totallylast',
             'phone': '',
             'real_name': 'othername totallylast',
             'real_name_normalized': 'othername totallylast',
             'skype': '',
             'title': 'blah & blah'},
            {'avatar_hash': 'sv1454671952',
             'fields': None,
             'first_name': 'slackbot',
             'image_192': 'https://bla.com/65f9/img/slackbot_192.png',
             'image_24': 'https://bla.com/181c/img/slackbot_24.png',
             'image_32': 'https://bla.com/0fac/slackbot/assets/service_32.png',
             'image_48': 'https://bla.com/4fac/slackbot/assets/service_48.png',
             'image_512': 'https://bla.com/1803/img/slackbot_512.png',
             'image_72': 'https://bla.com/1780/img/slackbot_72.png',
             'last_name': '',
             'real_name': 'slackbot',
             'real_name_normalized': 'slackbot'}]

USERS = {'cache_ts': 1479577519,
         'ok': True,
         'members': [{'color': 'd58247',
                      'deleted': False,
                      'id': 'UAAAAAAAA',
                      'is_admin': False,
                      'is_bot': True,
                      'is_owner': False,
                      'is_primary_owner': False,
                      'is_restricted': False,
                      'is_ultra_restricted': False,
                      'name': 'borg',
                      'profile': PROFILES[0],
                      'real_name': '',
                      'status': None,
                      'team_id': 'T0000TEST',
                      'tz': None,
                      'tz_label': 'Pacific Standard Time',
                      'tz_offset': -28800},
                     {'color': '4bbe2e',
                      'deleted': False,
                      'has_2fa': False,
                      'id': 'UBBBBBBBB',
                      'is_admin': True,
                      'is_bot': False,
                      'is_owner': True,
                      'is_primary_owner': False,
                      'is_restricted': False,
                      'is_ultra_restricted': False,
                      'name': 'name1',
                      'profile': PROFILES[1],
                      'real_name': '<NAME>',
                      'status': None,
                      'team_id': 'T0000TEST',
                      'tz': 'America/Los_Angeles',
                      'tz_label': 'Pacific Standard Time',
                      'tz_offset': -28800},
                     {'color': 'e96699',
                      'deleted': False,
                      'has_2fa': False,
                      'id': 'UCCCCCCCC',
                      'is_admin': False,
                      'is_bot': False,
                      'is_owner': False,
                      'is_primary_owner': False,
                      'is_restricted': False,
                      'is_ultra_restricted': False,
                      'name': 'name2',
                      'profile': PROFILES[2],
                      'real_name': '<NAME>',
                      'status': None,
                      'team_id': 'T0000TEST',
                      'tz': 'America/Los_Angeles',
                      'tz_label': 'Pacific Standard Time',
                      'tz_offset': -28800},
                     {'color': '757575',
                      'deleted': False,
                      'id': 'USLACKBOT',
                      'is_admin': False,
                      'is_bot': False,
                      'is_owner': False,
                      'is_primary_owner': False,
                      'is_restricted': False,
                      'is_ultra_restricted': False,
                      'name': 'slackbot',
                      'profile': PROFILES[3],
                      'real_name': 'slackbot',
                      'status': None,
                      'team_id': 'T0000TEST',
                      'tz': None,
                      'tz_label': 'Pacific Standard Time',
                      'tz_offset': -28800}]}

MSGS = {'messages': [{"type": "message",
                      "user": "UAAAAAAAA",
                      "text": "Class aptent taciti sociosqu ad litora torquent"
                              " per conubia nostra, per",
                      "ts": "1479501074.000032"},
                     {"reactions": [{"name": "+1",
                                     "users": ["UBBBBBBBB", "UCCCCCCCC"],
                                     "count": 2}],
                      "attachments": [{"service_icon": "https://bla/icon.png",
                                       "title": "Nulla sollicitudin",
                                       "thumb_width": 400,
                                       "thumb_height": 400,
                                       "from_url": "https://bla",
                                       "service_name": "Bla",
                                       "fallback": "Bla: Nulla sollicitudin",
                                       "title_link": "https://bla/nulla",
                                       "text": "Bla - bla bla",
                                       "thumb_url": "https://avatars/1.gif",
                                       "id": 1}],
                      "type": "message",
                      "user": "UCCCCCCCC",
                      "text": "Mauris ut metus sit amet mi cursus commodo. "
                              "Morbi congue mauris ac sapien. "
                              "https://bla/nulla",
                      "ts": "1479493038.000029"},
                     {"subtype": "pinned_item",
                      "item": {"mode": "hosted",
                               "size": 2949,
                               "comments_count": 1,
                               "timestamp": 1479146954,
                               "url_private_download": "https://files.slack."
                                                       "com/files-pri/bin.bin",
                               "is_external": False,
                               "external_type": "",
                               "username": "",
                               "display_as_bot": False,
                               "pinned_to": ["C00000001"],
                               "permalink_public": "https://slack-files.com/"
                                                   "hash",
                               "channels": ["C00000001"],
                               "title": "binary.prg",
                               "ims": [],
                               "url_private": "https://files.slack.com/hash/"
                                              "binary.prg",
                               "groups": [],
                               "filetype": "binary",
                               "user": "UAAAAAAAA",
                               "initial_comment": {"is_intro": True,
                                                   "user": "UAAAAAAAA",
                                                   "channel": "",
                                                   "timestamp": 1479146954,
                                                   "created": 1479146954,
                                                   "comment": "sample image",
                                                   "id": "Fc331R6CNT"},
                               "permalink": "https://bla.slack.com/files/borg/"
                                            "F331R60LX/binary.prg",
                               "name": "Conan.hires.prg",
                               "num_stars": 1,
                               "public_url_shared": False,
                               "is_public": True,
                               "mimetype": "application/octet-stream",
                               "created": 1479146954,
                               "id": "F331R60LX",
                               "pretty_type": "Binary",
                               "editable": False},
                      "item_type": "F",
                      "type": "message",
                      "user": "UAAAAAAAA",
                      "text": "<@UAAAAAAAA|borg> pinned their Binary "
                              "<https://bla.slack.com/files/borg/F331R60LX/"
                              "binary.prg|Binary.prg> to this channel.",
                      "ts": "1479146975.000197"},
                     {"type": "message",
                      "subtype": "channel_join",
                      "user": "UAAAAAAAA",
                      "text": "<@UAAAAAAAA|borg> has joined the channel",
                      "ts": "1479108214.000002"},
                     {"display_as_bot": False,
                      "subtype": "file_share",
                      "username": "<@UCCCCCCCC|name2>",
                      "file": {"thumb_960": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_960.png",
                               "user": "UCCCCCCCC",
                               "size": 77222,
                               "thumb_1024_h": 754,
                               "timestamp": 1479407569,
                               "url_private_download": "https://files.slack.co"
                                                       "m/files-pri/hsh/downlo"
                                                       "ad/screenshot.png",
                               "thumb_360": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_360.png",
                               "username": "",
                               "external_type": "",
                               "thumb_64": "https://files.slack.com/files-tmb/"
                                           "hash/screenshot_64.png",
                               "created": 1479407569,
                               "ims": [],
                               "groups": [],
                               "filetype": "png",
                               "thumb_1024": "https://files.slack.com/files-"
                                             "tmb/hash/screenshot_1024.png",
                               "original_w": 1193,
                               "name": "Screenshot.png",
                               "thumb_360_h": 265,
                               "is_public": True,
                               "thumb_960_h": 707,
                               "original_h": 878,
                               "mimetype": "image/png",
                               "id": "F3405RRB5",
                               "pretty_type": "PNG",
                               "editable": False,
                               "thumb_960_w": 960,
                               "thumb_80": "https://files.slack.com/files-tmb/"
                                           "hash/screenshot_80.png",
                               "comments_count": 0,
                               "image_exif_rotation": 1,
                               "thumb_160": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_160.png",
                               "thumb_480_w": 480,
                               "is_external": False,
                               "display_as_bot": False,
                               "thumb_720_h": 530,
                               "channels": ["C00000001"],
                               "title": "Screenshot.png",
                               "thumb_480": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_480.png",
                               "url_private": "https://files.slack.com/files-"
                                              "pri/hsh/screenshot.png",
                               "mode": "hosted",
                               "thumb_1024_w": 1024,
                               "permalink": "https://esm64.slack.com/files/"
                                            "name2/F3405RRB5/screenshot.png",
                               "thumb_480_h": 353,
                               "public_url_shared": False,
                               "thumb_720": "https://files.slack.com/files-tmb"
                                            "/hash/screenshot_720.png",
                               "thumb_360_w": 360,
                               "permalink_public": "https://slack-files.com/"
                                                   "hsh-7dbb96b758",
                               "thumb_720_w": 720},
                      "type": "message",
                      "user": "UCCCCCCCC",
                      "bot_id": None,
                      "text": "<@UCCCCCCCC|name2> uploaded a file: "
                              "<https://esm64.slack.com/files/name2/F3405RRB5/"
                              "screenshot.png|Screenshot.png>",
                      "ts": "1478107371.000052",
                      "upload": True},
                     {'type': 'something else',
                      'ts': '1502003415232.000001',
                      "wibblr": True}],
        "ok": True,
        "latest": "1479501075.000020",
        "has_more": True}

MSG2 = {'messages': [{"type": "message",
                      "user": "UCCCCCCCC",
                      "text": "Pellentesque molestie nunc id enim. Etiam "
                              "mollis tempus neque. Duis. per conubia "
                              "nostra, per",
                      "ts": "1479505026.000002"}],
        "ok": True,
        "latest": "1479505026.000003",
        "has_more": True}

MSG3 = {"ok": True,
        "oldest": "1479505026.000003",
        "messages": [],
        "has_more": False,
        "is_limited": False}


class FakeArgs(object):
    token = 'token_string'
    user = 'fake_user'
    password = '<PASSWORD>password'
    team = 'fake_team'
    database = None
    channels = None

    def __contains__(self, key):
        return hasattr(self, key)


class TestApiCalls(TestCase):

    def test_channels_list(self):
        cl = client.Client(FakeArgs())
        cl.slack.api_call = mock.MagicMock(return_value=CHANNELS)
        channels = cl._channels_list()
        self.assertListEqual(CHANNELS['channels'], channels)

    def test_users_list(self):
        cl = client.Client(FakeArgs())
        cl.slack.api_call = mock.MagicMock(return_value=USERS)
        users = cl._users_list()
        self.assertListEqual(USERS['members'], users)

    def test_channels_history(self):
        cl = client.Client(FakeArgs())

        cl.slack.api_call = mock.MagicMock(return_value=USERS)
        cl.downloader._download = mock.MagicMock(return_value=None)
        cl.update_users()

        cl.slack.api_call = mock.MagicMock(return_value=CHANNELS)
        cl.update_channels()

        cl.slack.api_call = mock.MagicMock()
        cl.slack.api_call.side_effect = [MSGS, MSG2, MSG3]

        channel = cl.q(o.Channel).filter(o.Channel.slackid ==
                                         "C00000001").one()

        msg, ts = cl._channels_history(channel, 0)
        self.assertEqual(len(msg), 6)
        self.assertEqual(ts, '1479501074.000032')

        msg, ts = cl._channels_history(channel, ts)
        self.assertEqual(len(msg), 1)
        self.assertEqual(ts, '1479505026.000002')

        msg, ts = cl._channels_history(channel, ts)
        self.assertEqual(len(msg), 0)
        self.assertIsNone(ts)


class TestClient(TestCase):

    def test_update_users(self):
        cl = client.Client(FakeArgs())
        cl.slack.api_call = mock.MagicMock(return_value=USERS)
        cl.downloader._download = mock.MagicMock(return_value=None)
        cl.update_users()
        users = cl.session.query(o.User).all()
        self.assertEqual(len(users), 4)
        self.assertEqual(users[0].id, 1)

        cl.update_users()
        users = cl.session.query(o.User).all()
        self.assertEqual(len(users), 4)
        self.assertEqual(users[0].id, 1)
        self.assertEqual(users[0].slackid, 'UAAAAAAAA')


class TestMessage(TestCase):

    def setUp(self):
        args = FakeArgs()
        args.channels = ['general']

        self.cl = client.Client(args)
        self.cl.downloader.authorize = mock.MagicMock()
        self.cl.slack.api_call = mock.MagicMock(return_value=USERS)
        self.cl.downloader._download = mock.MagicMock(return_value=None)
        self.cl.update_users()

        self.cl.slack.api_call = mock.MagicMock(return_value=CHANNELS)
        self.cl.update_channels()

        self.cl.slack.api_call = mock.MagicMock()

    @mock.patch('slack_backup.download.Download.download')
    def test_update_history(self, download):

        download.return_value = 'foo'

        self.cl.downloader._download = mock.MagicMock(return_value=None)
        self.cl.slack.api_call.side_effect = [MSGS, MSG3]
        self.cl.update_history()
        self.assertEqual(len(self.cl.q(o.Message).all()), 5)

        self.cl.slack.api_call.side_effect = [MSG2, MSG3]
        self.cl.update_history()

        self.assertEqual(len(self.cl.q(o.Message).all()), 6)
