"""
Unit tests for REST Client
"""

import json
import mock
import requests

from purestorage import FlashArray, PureError, PureHTTPError

CLIENT_PATH = "purestorage.purestorage"
ARRAY_OBJ = CLIENT_PATH + ".FlashArray"

class TestBase(object):

    def setup_method(self, __):
        self.api_token = "12345678-abcd-1234-abcd-1234567890ab"
        self.api_token_data = {"api_token": self.api_token}
        self.other_rest_versions = ["0.1", "1.1", "1.0", "99.9"]
        self.rest_version = "1.2"
        self.rest_version_data = {"version": self.other_rest_versions}
        self.target = "pure-target"

    @staticmethod
    def assert_raises(error, func, *args, **kwargs):
        """Assert that a function raises the correct error

        Fail if the function, called with the specified args and kwargs
        doesn't raise an exception of type error.
        """
        try:
            func(*args, **kwargs)
        except error:
            pass
        else:
            raise AssertionError()

    @classmethod
    def assert_error_propagates(cls, mocks, func, *args, **kwargs):
        """Assert that errors from mocks propogate to func.

        Fail if exceptions raised by mocks are not seen when calling
        func(*args, **kwargs). Ensure that we are really seeing exceptions
        from the mocks by failing if just running func(*args, **kargs) raises
        an exception itself.
        """
        func(*args, **kwargs)
        for mock_func in mocks:
            mock_func.side_effect = PureError("reason")
            cls.assert_raises(PureError, func, *args, **kwargs)
            mock_func.side_effect = None


@mock.patch(ARRAY_OBJ + "._request", autospec=True)
class TestInit(TestBase):

    def setup_method(self, method):
        super(TestInit, self).setup_method(method)
        self.password = "purepass"
        self.username = "pureuser"
        self.username_data = {"username": self.username}

    def test_init_with_api_token(self, mock_request):
        mock_request.side_effect = iter([
            self.rest_version_data,
            self.username_data,
        ])
        array = FlashArray(self.target, api_token=self.api_token)
        expected = [
            mock.call(
                array, "GET", "https://{0}/api/api_version".format(self.target),
                reestablish_session=False),
            mock.call(array, "POST", "auth/session", self.api_token_data,
                      reestablish_session=False),
        ]
        assert array._target == self.target
        assert array._rest_version == "1.1"
        assert array._renegotiate_rest_version == True
        assert array._api_token == self.api_token
        assert mock_request.call_args_list == expected

    def test_init_with_username_password(self, mock_request):
        mock_request.side_effect = iter([
            self.rest_version_data,
            self.api_token_data,
            self.username_data,
        ])
        array = FlashArray(self.target, self.username, self.password)
        expected = [
            mock.call(array, "GET",
                      "https://{0}/api/api_version".format(self.target),
                      reestablish_session=False),
            mock.call(array, "POST", "auth/apitoken",
                      {"username": self.username, "password": self.password},
                      reestablish_session=False),
            mock.call(array, "POST", "auth/session", self.api_token_data,
                      reestablish_session=False),
        ]
        assert array._target == self.target
        assert array._rest_version == "1.1"
        assert array._renegotiate_rest_version == True
        assert array._api_token == self.api_token
        assert mock_request.call_args_list == expected

    def test_init_with_version(self, mock_request):