# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from unittest import mock

from openstack.message.v2 import _proxy
from openstack.message.v2 import claim
from openstack.message.v2 import message
from openstack.message.v2 import queue
from openstack.message.v2 import subscription
from openstack import proxy as proxy_base
from openstack.tests.unit import test_proxy_base

QUEUE_NAME = 'test_queue'


class TestMessageProxy(test_proxy_base.TestProxyBase):
    def setUp(self):
        super().setUp()
        self.proxy = _proxy.Proxy(self.session)


class TestMessageQueue(TestMessageProxy):
    def test_queue_create(self):
        self.verify_create(self.proxy.create_queue, queue.Queue)

    def test_queue_get(self):
        self.verify_get(self.proxy.get_queue, queue.Queue)
        self.verify_get_overrided(
            self.proxy, queue.Queue, 'openstack.message.v2.queue.Queue'
        )

    def test_queues(self):
        self.verify_list(self.proxy.queues, queue.Queue)

    def test_queue_delete(self):
        self.verify_delete(self.proxy.delete_queue, queue.Queue, False)

    def test_queue_delete_ignore(self):
        self.verify_delete(self.proxy.delete_queue, queue.Queue, True)


class TestMessageMessage(TestMessageProxy):
    @mock.patch.object(proxy_base.Proxy, '_get_resource')
    def test_message_post(self, mock_get_resource):
        message_obj = message.Message(queue_name="test_queue")
        mock_get_resource.return_value = message_obj
        self._verify(
            "openstack.message.v2.message.Message.post",
            self.proxy.post_message,
            method_args=["test_queue", ["msg1", "msg2"]],
            expected_args=[self.proxy, ["msg1", "msg2"]],
        )
        mock_get_resource.assert_called_once_with(
            message.Message, None, queue_name="test_queue"
        )

    @mock.patch.object(proxy_base.Proxy, '_get_resource')
    def test_message_get(self, mock_get_resource):
        mock_get_resource.return_value = "resource_or_id"
        self._verify(
            "openstack.proxy.Proxy._get",
            self.proxy.get_message,
            method_args=["test_queue", "resource_or_id"],
            expected_args=[message.Message, "resource_or_id"],
        )
        mock_get_resource.assert_called_once_with(
            message.Message, "resource_or_id", queue_name="test_queue"
        )
        self.verify_get_overrided(
            self.proxy, message.Message, 'openstack.message.v2.message.Message'
        )

    def test_messages(self):
        self.verify_list(
            self.proxy.messages,
            message.Message,
            method_kwargs={"queue_name": "test_queue"},
            expected_kwargs={"queue_name": "test_queue"},
        )

    @mock.patch.object(proxy_base.Proxy, '_get_resource')
    def test_message_delete(self, mock_get_resource):
        fake_message = mock.Mock()
        fake_message.id = "message_id"
        mock_get_resource.return_value = fake_message
        self._verify(
            "openstack.proxy.Proxy._delete",
            self.proxy.delete_message,
            method_args=["test_queue", "resource_or_id", None, False],
            expected_args=[message.Message, fake_message],
            expected_kwargs={"ignore_missing": False},
        )
        self.assertIsNone(fake_message.claim_id)
        mock_get_resource.assert_called_once_with(
            message.Message, "resource_or_id", queue_name="test_queue"
        )

    @mock.patch.object(proxy_base.Proxy, '_get_resource')
    def test_message_delete_claimed(self, mock_get_resource):
        fake_message = mock.Mock()
        fake_message.id = "message_id"
        mock_get_resource.return_value = fake_message
        self._verify(
            "openstack.proxy.Proxy._delete",
            self.proxy.delete_message,
            method_args=["test_queue", "resource_or_id", "claim_id", False],
            expected_args=[message.Message, fake_message],
            expected_kwargs={"ignore_missing": False},
        )
        self.assertEqual("claim_id", fake_message.claim_id)
        mock_get_resource.assert_called_once_with(
            message.Message, "resource_or_id", queue_name="test_queue"
        )

    @mock.patch.object(proxy_base.Proxy, '_get_resource')
    def test_message_delete_ignore(self, mock_get_resource):
        fake_message = mock.Mock()
        fake_message.id = "message_id"
        mock_get_resource.return_value = fake_message
        self._verify(
            "openstack.proxy.Proxy._delete",
            self.proxy.delete_message,
            method_args=["test_queue", "resource_or_id", None, True],
            expected_args=[message.Message, fake_message],
            expected_kwargs={"ignore_missing": True},
        )
        self.assertIsNone(fake_message.claim_id)
        mock_get_resource.assert_called_once_with(
            message.Message, "resource_or_id", queue_name="test_queue"
        )


class TestMessageSubscription(TestMessageProxy):
    def test_subscription_create(self):
        self._verify(
            "openstack.message.v2.subscription.Subscription.create",
            self.proxy.create_subscription,
            method_args=["test_queue"],
            expected_args=[self.proxy],
            expected_kwargs={"base_path": None},
        )

    @mock.patch.object(proxy_base.Proxy, '_get_resource')
    def test_subscription_get(self, mock_get_resource):
        mock_get_resource.return_value = "resource_or_id"
        self._verify(
            "openstack.proxy.Proxy._get",
            self.proxy.get_subscription,
            method_args=["test_queue", "resource_or_id"],
            expected_args=[subscription.Subscription, "resource_or_id"],
        )
        mock_get_resource.assert_called_once_with(
            subscription.Subscription,
            "resource_or_id",
            queue_name="test_queue",
        )
        self.verify_get_overrided(
            self.proxy,
            subscription.Subscription,
            'openstack.message.v2.subscription.Subscription',
        )

    def test_subscriptions(self):
        self.verify_list(
            self.proxy.subscriptions,
            subscription.Subscription,
            method_kwargs={"queue_name": "test_queue"},
            expected_kwargs={"queue_name": "test_queue"},
        )

    @mock.patch.object(proxy_base.Proxy, '_get_resource')
    def test_subscription_delete(self, mock_get_resource):
        mock_get_resource.return_value = "test_subscription"
        self.verify_delete(
            self.proxy.delete_subscription,
            subscription.Subscription,
            ignore_missing=False,
            method_args=["test_queue", "resource_or_id"],
            expected_args=["test_subscription"],
        )
        mock_get_resource.assert_called_once_with(
            subscription.Subscription,
            "resource_or_id",
            queue_name="test_queue",
        )

    @mock.patch.object(proxy_base.Proxy, '_get_resource')
    def test_subscription_delete_ignore(self, mock_get_resource):
        mock_get_resource.return_value = "test_subscription"
        self.verify_delete(
            self.proxy.delete_subscription,
            subscription.Subscription,
            ignore_missing=True,
            method_args=["test_queue", "resource_or_id"],
            expected_args=["test_subscription"],
        )
        mock_get_resource.assert_called_once_with(
            subscription.Subscription,
            "resource_or_id",
            queue_name="test_queue",
        )


class TestMessageClaim(TestMessageProxy):
    def test_claim_create(self):
        self._verify(
            "openstack.message.v2.claim.Claim.create",
            self.proxy.create_claim,
            method_args=["test_queue"],
            expected_args=[self.proxy],
            expected_kwargs={"base_path": None},
        )

    def test_claim_get(self):
        self._verify(
            "openstack.proxy.Proxy._get",
            self.proxy.get_claim,
            method_args=["test_queue", "resource_or_id"],
            expected_args=[claim.Claim, "resource_or_id"],
            expected_kwargs={"queue_name": "test_queue"},
        )
        self.verify_get_overrided(
            self.proxy, claim.Claim, 'openstack.message.v2.claim.Claim'
        )

    def test_claim_update(self):
        self._verify(
            "openstack.proxy.Proxy._update",
            self.proxy.update_claim,
            method_args=["test_queue", "resource_or_id"],
            method_kwargs={"k1": "v1"},
            expected_args=[claim.Claim, "resource_or_id"],
            expected_kwargs={"queue_name": "test_queue", "k1": "v1"},
        )

    def test_claim_delete(self):
        self.verify_delete(
            self.proxy.delete_claim,
            claim.Claim,
            ignore_missing=False,
            method_args=["test_queue", "test_claim"],
            expected_args=["test_claim"],
            expected_kwargs={
                "queue_name": "test_queue",
                "ignore_missing": False,
            },
        )

    def test_claim_delete_ignore(self):
        self.verify_delete(
            self.proxy.delete_claim,
            claim.Claim,
            ignore_missing=True,
            method_args=["test_queue", "test_claim"],
            expected_args=["test_claim"],
            expected_kwargs={
                "queue_name": "test_queue",
                "ignore_missing": True,
            },
        )
