# -*- coding: utf-8 -*-
'''
    :synopsis: Unit Tests for 'module.aptkernelpkg'
    :platform: Linux
    :maturity: develop
    versionadded:: 2018.3.0
'''
# pylint: disable=invalid-name,no-member

# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals

# Import Salt libs
from salt.ext import six

try:
    # Import Salt Testing Libs
    from tests.support.mixins import LoaderModuleMockMixin
    from tests.support.unit import skipIf, TestCase
    from tests.support.mock import (
        NO_MOCK,
        NO_MOCK_REASON,
        MagicMock,
        patch)

    # Import Salt Libs
    import salt.states.kernelpkg as kernelpkg
    HAS_MODULES = True
except ImportError:
    HAS_MODULES = False

KERNEL_LIST = ['4.4.0-70-generic', '4.4.0-71-generic', '4.5.1-14-generic']
STATE_NAME = 'kernelpkg-test'


@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_MODULES, 'Salt modules could not be loaded')
class KernelPkgTestCase(TestCase, LoaderModuleMockMixin):
    '''
    Test cases for salt.states.aptpkg
    '''

    def setup_loader_modules(self):
        return {
            kernelpkg: {
                '__salt__': {
                    'system.reboot': MagicMock(return_value=None),
                    'kernelpkg.upgrade': MagicMock(return_value={
                        'upgrades': {
                            'kernel': {
                                'old': '1.0.0',
                                'new': '2.0.0',
                            }
                        }
                    }),
                    'kernelpkg.active': MagicMock(return_value=0),
                    'kernelpkg.latest_installed': MagicMock(return_value=0)
                }
            }
        }

    def test_latest_installed_with_changes(self):
        '''
        Test - latest_installed when an upgrade is available
        '''
        installed = MagicMock(return_value=KERNEL_LIST[:-1])
        upgrade = MagicMock(return_value=KERNEL_LIST[-1])
        with patch.dict(kernelpkg.__salt__, {'kernelpkg.list_installed': installed}):
            with patch.dict(kernelpkg.__salt__, {'kernelpkg.latest_available': upgrade}):
                with patch.dict(kernelpkg.__opts__, {'test': False}):
                    kernelpkg.__salt__['kernelpkg.upgrade'].reset_mock()
                    ret = kernelpkg.latest_installed(name=STATE_NAME)
                    self.assertEqual(ret['name'], STATE_NAME)
                    self.assertTrue(ret['result'])
                    self.assertIsInstance(ret['changes'], dict)
                    self.assertIsInstance(ret['comment'], six.text_type)
                    self.assert_called_once(kernelpkg.__salt__['kernelpkg.upgrade'])

                with patch.dict(kernelpkg.__opts__, {'test': True}):
                    kernelpkg.__salt__['kernelpkg.upgrade'].reset_mock()
                    ret = kernelpkg.latest_installed(name=STATE_NAME)
                    self.assertEqual(ret['name'], STATE_NAME)
                    self.assertIsNone(ret['result'])
                    self.assertDictEqual(ret['changes'], {})
                    self.assertIsInstance(ret['comment'], six.text_type)
                    kernelpkg.__salt__['kernelpkg.upgrade'].assert_not_called()

    def test_latest_installed_at_latest(self):
        '''
        Test - latest_installed when no upgrade is available
        '''
        installed = MagicMock(return_value=KERNEL_LIST)
        upgrade = MagicMock(return_value=KERNEL_LIST[-1])
        with patch.dict(kernelpkg.__salt__, {'kernelpkg.list_installed': installed}):
            with patch.dict(kernelpkg.__salt__, {'kernelpkg.latest_available': upgrade}):
                with patch.dict(kernelpkg.__opts__, {'test': False}):
                    ret = kernelpkg.latest_installed(name=STATE_NAME)
                    self.assertEqual(ret['name'], STATE_NAME)
                    self.assertTrue(ret['result'])
                    self.assertDictEqual(ret['changes'], {})
                    self.assertIsInstance(ret['comment'], six.text_type)
                    kernelpkg.__salt__['kernelpkg.upgrade'].assert_not_called()

                with patch.dict(kernelpkg.__opts__, {'test': True}):
                    ret = kernelpkg.latest_installed(name=STATE_NAME)
                    self.assertEqual(ret['name'], STATE_NAME)
                    self.assertTrue(ret['result'])
                    self.assertDictEqual(ret['changes'], {})
                    self.assertIsInstance(ret['comment'], six.text_type)
                    kernelpkg.__salt__['kernelpkg.upgrade'].assert_not_called()

    def test_latest_active_with_changes(self):
        '''
        Test - latest_active when a new kernel is available
        '''
        reboot = MagicMock(return_value=True)
        with patch.dict(kernelpkg.__salt__, {'kernelpkg.needs_reboot': reboot}):
            with patch.dict(kernelpkg.__opts__, {'test': False}):
                kernelpkg.__salt__['system.reboot'].reset_mock()
                ret = kernelpkg.latest_active(name=STATE_NAME)
                self.assertEqual(ret['name'], STATE_NAME)
                self.assertTrue(ret['result'])
                self.assertIsInstance(ret['changes'], dict)
                self.assertIsInstance(ret['comment'], six.text_type)
                self.assert_called_once(kernelpkg.__salt__['system.reboot'])

            with patch.dict(kernelpkg.__opts__, {'test': True}):
                kernelpkg.__salt__['system.reboot'].reset_mock()
                ret = kernelpkg.latest_active(name=STATE_NAME)
                self.assertEqual(ret['name'], STATE_NAME)
                self.assertIsNone(ret['result'])
                self.assertDictEqual(ret['changes'], {})
                self.assertIsInstance(ret['comment'], six.text_type)
                kernelpkg.__salt__['system.reboot'].assert_not_called()

    def test_latest_active_at_latest(self):
        '''
        Test - latest_active when the newest kernel is already active
        '''
        reboot = MagicMock(return_value=False)
        with patch.dict(kernelpkg.__salt__, {'kernelpkg.needs_reboot': reboot}):
            with patch.dict(kernelpkg.__opts__, {'test': False}):
                kernelpkg.__salt__['system.reboot'].reset_mock()
                ret = kernelpkg.latest_active(name=STATE_NAME)
                self.assertEqual(ret['name'], STATE_NAME)
                self.assertTrue(ret['result'])
                self.assertDictEqual(ret['changes'], {})
                self.assertIsInstance(ret['comment'], six.text_type)
                kernelpkg.__salt__['system.reboot'].assert_not_called()

            with patch.dict(kernelpkg.__opts__, {'test': True}):
                kernelpkg.__salt__['system.reboot'].reset_mock()
                ret = kernelpkg.latest_active(name=STATE_NAME)
                self.assertEqual(ret['name'], STATE_NAME)
                self.assertTrue(ret['result'])
                self.assertDictEqual(ret['changes'], {})
                self.assertIsInstance(ret['comment'], six.text_type)
                kernelpkg.__salt__['system.reboot'].assert_not_called()

    def test_latest_wait(self):
        '''
        Test - latest_wait static results
        '''
        ret = kernelpkg.latest_wait(name=STATE_NAME)
        self.assertEqual(ret['name'], STATE_NAME)
        self.assertTrue(ret['result'])
        self.assertDictEqual(ret['changes'], {})
        self.assertIsInstance(ret['comment'], six.text_type)
