# coding: utf-8

# Python libs
from __future__ import absolute_import, print_function, unicode_literals

# Salt testing libs
from tests.support.unit import skipIf, TestCase
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock
from tests.support.mixins import LoaderModuleMockMixin

# Salt libs
import salt.beacons.smartos_imgadm as imgadm


# Mock Results
MOCK_CLEAN_STATE = {'first_run': True, 'images': []}
MOCK_IMAGE_NONE = {}
MOCK_IMAGE_ONE = {
    '00000000-0000-0000-0000-000000000001': {
        'description': 'Example Image 1',
        'name': 'example-1',
        'os': 'smartos',
        'published': '2018-01-01T00:42:00Z',
        'source': 'https://images.joyent.com',
        'version': '18.1.0',
    },
}
MOCK_IMAGE_TWO = {
    '00000000-0000-0000-0000-000000000001': {
        'description': 'Example Image 1',
        'name': 'example-1',
        'os': 'smartos',
        'published': '2018-01-01T00:42:00Z',
        'source': 'https://images.joyent.com',
        'version': '18.1.0',
    },
    '00000000-0000-0000-0000-000000000002': {
        'description': 'Example Image 2',
        'name': 'example-2',
        'os': 'smartos',
        'published': '2018-01-01T00:42:00Z',
        'source': 'https://images.joyent.com',
        'version': '18.2.0',
    },
}


@skipIf(NO_MOCK, NO_MOCK_REASON)
class SmartOSImgAdmBeaconTestCase(TestCase, LoaderModuleMockMixin):
    '''
    Test case for salt.beacons.imgadm
    '''

    def setup_loader_modules(self):
        return {
            imgadm: {
                '__context__': {},
                '__salt__': {},
            }
        }

    def test_non_list_config(self):
        '''
        We only have minimal validation so we test that here
        '''
        assert imgadm.validate({}) == (False, 'Configuration for imgadm beacon must be a list!')

    def test_imported_startup(self):
        '''
        Test with one image and startup_import_event
        '''
        # NOTE: this should yield 1 imported event
        with patch.dict(imgadm.IMGADM_STATE, MOCK_CLEAN_STATE), \
             patch.dict(imgadm.__salt__, {'imgadm.list': MagicMock(return_value=MOCK_IMAGE_ONE)}):

            config = [{'startup_import_event': True}]
            assert imgadm.validate(config) == (True, 'Valid beacon configuration')

            ret = imgadm.beacon(config)
            res = [{'description': 'Example Image 1',
                    'name': 'example-1',
                    'os': 'smartos',
                    'published': '2018-01-01T00:42:00Z',
                    'source': 'https://images.joyent.com',
                    'tag': 'imported/00000000-0000-0000-0000-000000000001',
                    'version': '18.1.0'}]
            assert ret == res

    def test_imported_nostartup(self):
        '''
        Test with one image and startup_import_event unset/false
        '''
        # NOTE: this should yield 0 imported event
        with patch.dict(imgadm.IMGADM_STATE, MOCK_CLEAN_STATE), \
             patch.dict(imgadm.__salt__, {'imgadm.list': MagicMock(return_value=MOCK_IMAGE_ONE)}):

            config = []

            assert imgadm.validate(config) == (True, 'Valid beacon configuration')
            assert imgadm.beacon(config) == []

    def test_imported(self):
        '''
        Test with one image and a new image added on the 2nd pass
        '''
        # NOTE: this should yield 1 imported event
        with patch.dict(imgadm.IMGADM_STATE, MOCK_CLEAN_STATE), \
             patch.dict(imgadm.__salt__, {'imgadm.list': MagicMock(side_effect=[MOCK_IMAGE_ONE, MOCK_IMAGE_TWO])}):

            config = []
            assert imgadm.validate(config) == (True, 'Valid beacon configuration')

            # Initial pass (Initialized state and do not yield imported images at startup)
            imgadm.beacon(config)

            # Second pass (After importing a new image)
            ret = imgadm.beacon(config)
            res = [{'description': 'Example Image 2',
                    'name': 'example-2',
                    'os': 'smartos',
                    'published': '2018-01-01T00:42:00Z',
                    'source': 'https://images.joyent.com',
                    'tag': 'imported/00000000-0000-0000-0000-000000000002',
                    'version': '18.2.0'}]

            assert ret == res

    def test_deleted(self):
        '''
        Test with two images and one gets deletes
        '''
        # NOTE: this should yield 1 deleted event
        with patch.dict(imgadm.IMGADM_STATE, MOCK_CLEAN_STATE), \
             patch.dict(imgadm.__salt__, {'imgadm.list': MagicMock(side_effect=[MOCK_IMAGE_TWO, MOCK_IMAGE_ONE])}):

            config = []
            assert imgadm.validate(config) == (True, 'Valid beacon configuration')

            # Initial pass (Initialized state and do not yield imported images at startup)
            imgadm.beacon(config)

            # Second pass (After deleting one image)
            ret = imgadm.beacon(config)
            res = [{'description': 'Example Image 2',
                    'name': 'example-2',
                    'os': 'smartos',
                    'published': '2018-01-01T00:42:00Z',
                    'source': 'https://images.joyent.com',
                    'tag': 'deleted/00000000-0000-0000-0000-000000000002',
                    'version': '18.2.0'}]

            assert ret == res

    def test_complex(self):
        '''
        Test with one image, delete both, import 2
        '''
        # NOTE: this should yield 1 delete and 2 import events
        with patch.dict(imgadm.IMGADM_STATE, MOCK_CLEAN_STATE), \
             patch.dict(imgadm.__salt__, {'imgadm.list': MagicMock(side_effect=[MOCK_IMAGE_ONE, MOCK_IMAGE_NONE, MOCK_IMAGE_TWO])}):

            config = []
            assert imgadm.validate(config), (True, 'Valid beacon configuration')

            # Initial pass (Initialized state and do not yield imported images at startup)
            imgadm.beacon(config)

            # Second pass (After deleting one image)
            ret = imgadm.beacon(config)
            res = [{'description': 'Example Image 1',
                    'name': 'example-1',
                    'os': 'smartos',
                    'published': '2018-01-01T00:42:00Z',
                    'source': 'https://images.joyent.com',
                    'tag': 'deleted/00000000-0000-0000-0000-000000000001',
                    'version': '18.1.0'}]
            assert ret == res

            # Third pass (After importing two images)
            ret = imgadm.beacon(config)
            res = [{'description': 'Example Image 1',
                    'name': 'example-1',
                    'os': 'smartos',
                    'published': '2018-01-01T00:42:00Z',
                    'source': 'https://images.joyent.com',
                    'tag': 'imported/00000000-0000-0000-0000-000000000001',
                    'version': '18.1.0'},
                   {'description': 'Example Image 2',
                    'name': 'example-2',
                    'os': 'smartos',
                    'published': '2018-01-01T00:42:00Z',
                    'source': 'https://images.joyent.com',
                    'tag': 'imported/00000000-0000-0000-0000-000000000002',
                    'version': '18.2.0'}]
            assert len(ret) == 2
            for item in ret:
                assert item in res
