"""Tests for :mod:`compiler.services.filemanager`."""
from unittest import TestCase, mock
import json
import requests
from arxiv.integration.api import exceptions, status
from .. import FileManager
from .... import domain, util
CONFIG = {
    'FILEMANAGER_ENDPOINT': 'http://fooendpoint:1234',
    'FILEMANAGER_VERIFY': False
}
mock_app = mock.MagicMock(config=CONFIG)
[docs]class TestServiceStatus(TestCase):
    """Test :func:`.FileManager.get_status`."""
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_status(self, mock_Session):
        """Get the status of the file manager service sucessfully."""
        mock_Session.return_value = mock.MagicMock(
            get=mock.MagicMock(
                return_value=mock.MagicMock(
                    status_code=status.OK,
                    json=mock.MagicMock(return_value={'iam': 'ok'})
                )
            )
        )
        self.assertEqual(FileManager.get_status(), {'iam': 'ok'},
                         "Gets the response content from the status enpoint")  
[docs]class TestGetUploadInfo(TestCase):
    """:func:`FileManager.get_upload_info` returns the current ETag."""
[docs]    def session(self, status_code=status.OK, method="get", json={},
                content="", headers={}):
        """Make a mock session."""
        return mock.MagicMock(**{
            method: mock.MagicMock(
                return_value=mock.MagicMock(
                    status_code=status_code,
                    json=mock.MagicMock(
                        return_value=json
                    ),
                    content=content,
                    headers=headers
                )
            )
        }) 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_info(self, mock_Session):
        """Get info for an upload workspace that exists."""
        etag = 'asdf12345checksum'
        source_id = '123456'
        mock_Session.return_value = self.session(headers={'ETag': etag})
        info = FileManager.get_upload_info(source_id, 'footoken')
        self.assertIsInstance(info, domain.SourcePackageInfo)
        self.assertEqual(info.etag, etag)
        self.assertEqual(info.source_id, source_id) 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_info_nonexistant(self, mock_Session):
        """Get info for an upload workspace that does not exist."""
        source_id = '123456'
        mock_Session.return_value = self.session(status.NOT_FOUND)
        with self.assertRaises(exceptions.NotFound):
            FileManager.get_upload_info(source_id, 'footoken') 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_info_bad_request(self, mock_Session):
        """We made a bad request."""
        source_id = '123456'
        mock_Session.return_value = self.session(status.BAD_REQUEST)
        with self.assertRaises(exceptions.BadRequest):
            FileManager.get_upload_info(source_id, 'footoken') 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_info_unauthorized(self, mock_Session):
        """We made an unauthorized request."""
        source_id = '123456'
        mock_Session.return_value = self.session(status.UNAUTHORIZED)
        with self.assertRaises(exceptions.RequestUnauthorized):
            FileManager.get_upload_info(source_id, 'footoken') 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_info_forbidden(self, mock_Session):
        """We made a forbidden request."""
        source_id = '123456'
        mock_Session.return_value = self.session(status.FORBIDDEN)
        with self.assertRaises(exceptions.RequestForbidden):
            FileManager.get_upload_info(source_id, 'footoken') 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_info_error(self, mock_Session):
        """FM service replied 500 Internal Server Error."""
        source_id = '123456'
        mock_Session.return_value = self.session(
            status.INTERNAL_SERVER_ERROR
        )
        with self.assertRaises(exceptions.RequestFailed):
            FileManager.get_upload_info(source_id, 'footoken') 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_info_bad_json(self, mock_Session):
        """FM service reurns bad JSON."""
        source_id = '123456'
        def raise_JSONDecodeError(*a, **k):
            raise json.decoder.JSONDecodeError('nope', 'nope', 0)
        mock_Session.return_value = mock.MagicMock(
            get=mock.MagicMock(
                return_value=mock.MagicMock(
                    status_code=status.OK,
                    json=mock.MagicMock(side_effect=raise_JSONDecodeError)
                )
            )
        )
        with self.assertRaises(exceptions.BadResponse):
            FileManager.get_upload_info(source_id, 'footoken') 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_info_bad_ssl(self, mock_Session):
        """FM service has bad TLS."""
        source_id = '123456'
        def raise_ssl_error(*a, **k):
            raise requests.exceptions.SSLError('danger fill bobinson')
        mock_Session.return_value = mock.MagicMock(
            get=mock.MagicMock(side_effect=raise_ssl_error)
        )
        with self.assertRaises(exceptions.SecurityException):
            FileManager.get_upload_info(source_id, 'footoken') 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_info_no_connection(self, mock_Session):
        """FM service cannot connect."""
        source_id = '123456'
        def raise_connection_error(*a, **k):
            raise requests.exceptions.ConnectionError('where r u')
        mock_Session.return_value = mock.MagicMock(
            get=mock.MagicMock(side_effect=raise_connection_error)
        )
        with self.assertRaises(exceptions.ConnectionFailed):
            FileManager.get_upload_info(source_id, 'footoken')  
[docs]class TestGetUpload(TestCase):
    """:func:`FileManager.get_upload` returns the upload content."""
[docs]    def session(self, status_code=status.OK, method="get", json={},
                content="", headers={}):
        """Make a mock session."""
        return mock.MagicMock(**{
            method: mock.MagicMock(
                return_value=mock.MagicMock(
                    status_code=status_code,
                    json=mock.MagicMock(
                        return_value=json
                    ),
                    content=content,
                    headers=headers
                )
            )
        }) 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload(self, mock_Session):
        """Get upload that exists."""
        etag = 'asdf12345checksum'
        source_id = '123456'
        content = b'foocontent'
        mock_iter_content = mock.MagicMock(return_value=[content])
        mock_Session.return_value = mock.MagicMock(
            get=mock.MagicMock(
                return_value=mock.MagicMock(
                    status_code=status.OK,
                    iter_content=mock_iter_content,
                    headers={'ETag': etag}
                )
            )
        )
        info = FileManager.get_source_content(source_id, 'footoken')
        self.assertIsInstance(info, domain.SourcePackage)
        self.assertEqual(info.etag, etag)
        self.assertEqual(info.source_id, source_id)
        self.assertIsInstance(info.path, str) 
[docs]    @mock.patch('arxiv.integration.api.service.current_app', mock_app)
    @mock.patch('arxiv.integration.api.service.requests.Session')
    def test_get_upload_nonexistant(self, mock_Session):
        """Get info for an upload workspace that does not exist."""
        source_id = '123456'
        mock_Session.return_value = self.session(status.NOT_FOUND)
        with self.assertRaises(exceptions.NotFound):
            FileManager.get_source_content(source_id, 'footoken')