# coding: utf-8

import os

from core.exceptions import CreationException
from mock import Mock, patch, PropertyMock

from tests.helpers import BaseTestCase, custom_wait, wait_for, DatabaseMock
from core.db.models import Provider


class TestOpenstackCloneUnit(BaseTestCase):
    def setUp(self):
        from flask import Flask
        from core.config import setup_config
        setup_config('data/config_openstack.py')

        self.app = Flask(__name__)
        self.app.database = DatabaseMock()

        self.pool = Mock(id=1, provider=Provider(name='fake', url='no//url'))
        self.mocked_origin = Mock(
            short_name="platform_1",
            id=1, status="active",
            get=Mock(return_value="snapshot"),
            min_disk=20,
            min_ram=2,
            instance_type_flavorid=1
        )

        self.ctx = self.app.app_context()
        self.ctx.push()

        with patch(
            "core.utils.openstack_utils.nova_client", Mock(return_value=Mock())
        ), patch(
            "flask.current_app", self.app
        ):
            from core.db.models import OpenstackClone
            self.clone = OpenstackClone(self.mocked_origin, "preloaded", self.pool)

    def tearDown(self):
        self.ctx.pop()
        del self.app

    def test_success_openstack_set_userdata(self):
        file_object = self.clone.set_userdata("%s/data/userdata" % os.path.dirname(__file__))
        self.assertTrue(hasattr(file_object, "read"))

    @patch.multiple(
        "core.db.models.OpenstackClone",
        ready=True,
        _wait_for_activated_service=custom_wait,
    )
    def test_creation_vm(self):
        """
        - call OpenstackClone.create()
        - _wait_for_activated_service has been mocked

        Expected: vm has been created
        """
        self.clone.create()
        self.assertTrue(self.clone.nova_client.servers.create.called)

    @patch.multiple(
        "core.db.models.OpenstackClone",
        get_vm=Mock(return_value=None),
        delete=Mock(),
    )
    def test_exception_in_create(self):
        """
        - call OpenstackClone.create()

        Expected: Exception was raised
        """
        with self.assertRaises(CreationException):
            self.clone.create()

    @patch.multiple(
        "core.db.models.OpenstackClone",
        get_ip=Mock(),
        get_vm=Mock(return_value=Mock(status="active")),
        ping_vm=Mock(return_value=True),
    )
    def test_ping_success(self):
        """
        - call OpenstackClone.create()
        - ping success

        Expected: vm has been created
        """
        self.clone.create()
        wait_for(lambda: self.clone.ready)
        self.assertTrue(self.clone.ready)

    @patch.multiple(
        "core.db.models.OpenstackClone",
        image=PropertyMock(side_effect=Exception("Exception in image")),
    )
    def test_exception_in_getting_image(self):
        """
        - call OpenstackClone.create()
        - exception in OpenstackClone.image

        Expected: Exception was raised
        """
        with self.assertRaises(Exception):
            self.clone.create()

    @patch.multiple(
        "core.db.models.OpenstackClone",
        flavor=PropertyMock(side_effect=Exception("Exception in flavor")),
    )
    def test_exception_in_getting_flavor(self):
        """
        - call OpenstackClone.create()
        - exception in OpenstackClone.flavor

        Expected: Exception was raised
        """
        with self.assertRaises(Exception):
            self.clone.create()

    @patch.multiple(
        "core.db.models.OpenstackClone",
        get_vm=Mock(status="active", delete=Mock(), rebuild=Mock()),
    )
    def test_delete_vm(self):
        """
        - call OpenstackClone.delete(try_to_rebuild=False)

        Expected: vm has been deleted
        """
        self.clone.delete()
        self.assertTrue(self.clone.get_vm.return_value.delete)
        self.assertTrue(self.clone.deleted)
        self.assertFalse(self.clone.ready)

    @patch.multiple(
        "core.db.models.OpenstackClone",
        get_vm=Mock(return_value=None),
        _wait_for_activated_service=custom_wait,
    )
    def test_rebuild_after_delete_vm_if_vm_does_not_exist(self):
        """
        - get_vm return None
        - call OpenstackClone.delete(try_to_rebuild=True)

        Expected: vm has not been deleted
        """