from StringIO import StringIO
from ftw.bridge.proxy import LOG
from ftw.bridge.proxy.interfaces import IProxy
from ftw.bridge.proxy.proxy import Proxy
from ftw.bridge.proxy.testing import PYRAMID_LAYER
from ftw.bridge.proxy.views import ProxyView
from logging import DEBUG
from logging import Formatter
from logging import StreamHandler
from mocker import ANY, MockerTestCase
from mocker import ARGS, KWARGS
from pyramid.exceptions import Forbidden
from pyramid.interfaces import IRequest
from pyramid.interfaces import IResponse
from pyramid.response import Response
from pyramid.testing import DummyRequest
from pyramid.threadlocal import get_current_registry
 
 
class TestProxyView(MockerTestCase):
 
    layer = PYRAMID_LAYER
 
    def setUp(self):
        MockerTestCase.setUp(self)
 
        # we do not expect requests, but lets just prevent accidental
        # requests
        self.requests = self.mocker.replace('requests')
        self.expect(self.requests.request(ARGS, KWARGS)).count(0)
 
        self.proxy = self.mocker.mock(Proxy, count=False)
        ProxyMock = self.mocker.mock(count=False)
        self.expect(ProxyMock(ANY)).result(self.proxy)
 
        sm = get_current_registry()
        sm.registerAdapter(ProxyMock, [IRequest], IProxy, name='')
 
    def test_proxy_view_authorizes(self):
        request = DummyRequest(
            path='/proxy/foo/remote/path/@@view',
            headers={})
 
        self.mocker.replay()
        view = ProxyView(request)
        with self.assertRaises(Forbidden):
            view.__call__()
 
    def test_proxy_view(self):
        request = DummyRequest(
            path='/proxy/foo/remote/path/@@view',
            params={'foo': 'bar'},
            headers={'X-BRIDGE-ORIGIN': 'bar',
                     'X-BRIDGE-AC': 'john.doe'},
            environ={'REMOTE_ADDR': '127.0.0.1'})
 
        self.expect(self.proxy()).result(Response('proxied response'))
        self.mocker.replay()
 
        view = ProxyView(request)
        response = view.__call__()
        self.assertTrue(IResponse.providedBy(response))
        self.assertEqual(response.body, 'proxied response')
 
 
class TestProxyViewLogging(MockerTestCase):
 
    layer = PYRAMID_LAYER
 
    def setUp(self):
        MockerTestCase.setUp(self)
 
        # we do not expect requests, but lets just prevent accidental
        # requests
        self.requests = self.mocker.replace('requests')
        self.expect(self.requests.request(ARGS, KWARGS)).count(0)
 
        self.proxy = self.mocker.mock(Proxy, count=False)
        ProxyMock = self.mocker.mock(count=False)
        self.expect(ProxyMock(ANY)).result(self.proxy)
 
        sm = get_current_registry()
        sm.registerAdapter(ProxyMock, [IRequest], IProxy, name='')
 
        self.stream = StringIO()
        self.handler = StreamHandler(self.stream)
        self.handler.setFormatter(Formatter('%(levelname)s %(message)s'))
        LOG.addHandler(self.handler)
        self.ori_log_level = LOG.getEffectiveLevel()
        LOG.setLevel(DEBUG)
 
    def tearDown(self):
        LOG.removeHandler(self.handler)
        LOG.setLevel(self.ori_log_level)
 
    def read_log(self):
        self.stream.seek(0)
        data = self.stream.read()
        self.stream.seek(0)
        return data
 
    def test_normal_request_logged(self):
        url = 'http://bridge/proxy/foo/remote/path/@@view'
        request = DummyRequest(
            url=url,
            path='/proxy/foo/remote/path/@@view',
            headers={'X-BRIDGE-ORIGIN': 'bar',
                     'X-BRIDGE-AC': 'john.doe'},
            environ={'REMOTE_ADDR': '127.0.0.1'})
 
        self.expect(self.proxy()).result(Response('proxied response'))
        self.mocker.replay()
 
        view = ProxyView(request)
        response = view.__call__()
        self.assertEqual(response.body, 'proxied response')
        self.assertEqual(
            self.read_log().strip(),
            'INFO GET: "bar" 200 OK (%s)' % url)
 
    def test_forbidden_request_logged(self):
        url = 'http://bridge/proxy/foo/remote/path/@@view'
        request = DummyRequest(
            url=url,
            headers={'X-BRIDGE-ORIGIN': 'wrong-client',
                     'X-BRIDGE-AC': 'john.doe'})
 
        self.expect(self.proxy()).result(Response('proxied response'))
        self.mocker.replay()
 
        view = ProxyView(request)
        with self.assertRaises(Forbidden):
            view()
 
        self.assertEqual(
            self.read_log().strip(),
            'ERROR GET: "wrong-client" FAILED (%s): ' % url + \
                'HTTPForbidden: Access was denied to this resource.')