class TestLoginPOST(unittest.TestCase):
    def setUp(self):
        self.services_factory = mock()
        self.provider = mock()
        self.resource = LoginResource(self.services_factory, self.provider)
        self.web = DummySite(self.resource)

        self.request = DummyRequest([''])
        username = '******'
        self.request.addArg('username', username)
        password = '******'
        self.username = username
        self.password = password
        self.request.addArg('password', password)
        self.request.method = 'POST'
        user_auth = mock()
        user_auth.uuid = 'some_user_uuid'
        self.user_auth = user_auth

    @patch('pixelated.authentication.Authenticator.authenticate')
    @patch('twisted.web.util.redirectTo')
    @patch('pixelated.resources.session.PixelatedSession.is_logged_in')
    def test_should_redirect_to_home_if_user_if_already_logged_in(self, mock_logged_in, mock_redirect, mock_authenticate):
        mock_logged_in.return_value = True
        when(self.services_factory).has_session(ANY()).thenReturn(True)
        mock_redirect.return_value = "mocked redirection"

        d = self.web.get(self.request)

        def assert_redirected_to_home(_):
            mock_redirect.assert_called_once_with('/', self.request)
            self.assertFalse(mock_authenticate.called)

        d.addCallback(assert_redirected_to_home)
        return d

    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    @patch('pixelated.authentication.Authenticator.authenticate')
    def test_should_return_form_back_with_error_message_when_login_fails(self, mock_authenticate,
                                                                         mock_user_bootstrap_setup):
        mock_authenticate.side_effect = UnauthorizedLogin()

        d = self.web.get(self.request)

        def assert_error_response_and_user_services_not_setup(_):
            mock_authenticate.assert_called_once_with(self.username, self.password)
            self.assertEqual(401, self.request.responseCode)
            written_response = ''.join(self.request.written)
            self.assertIn('Invalid username or password', written_response)
            self.assertFalse(mock_user_bootstrap_setup.called)
            self.assertFalse(self.resource.get_session(self.request).is_logged_in())

        d.addCallback(assert_error_response_and_user_services_not_setup)
        return d

    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    @patch('pixelated.authentication.Authenticator.authenticate')
    def test_successful_login_responds_interstitial(self, mock_authenticate, mock_user_bootstrap_setup):
        mock_authenticate.return_value = self.user_auth

        d = self.web.get(self.request)

        def assert_interstitial_in_response(_):
            mock_authenticate.assert_called_once_with(self.username, self.password)
            interstitial_js_in_template = '<script src="startup-assets/Interstitial.js"></script>'
            self.assertIn(interstitial_js_in_template, self.request.written[0])

        d.addCallback(assert_interstitial_in_response)
        return d

    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    @patch('pixelated.authentication.Authenticator.authenticate')
    def test_successful_login_runs_user_services_bootstrap_when_interstitial_loaded(self, mock_authenticate, mock_user_bootstrap_setup):
        mock_authenticate.return_value = self.user_auth

        d = self.web.get(self.request)

        def assert_login_setup_service_for_user(_):
            mock_user_bootstrap_setup.assert_called_once_with(self.user_auth, self.password, 'pt-BR')

        d.addCallback(assert_login_setup_service_for_user)
        return d

    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    @patch('pixelated.authentication.Authenticator.authenticate')
    def test_successful_adds_cookies_to_indicat_logged_in_status_when_services_are_loaded(self, mock_authenticate, mock_user_bootstrap_setup):
        mock_authenticate.return_value = self.user_auth
        irrelevant = None
        mock_user_bootstrap_setup.return_value = defer.succeed(irrelevant)

        d = self.web.get(self.request)

        def assert_login_setup_service_for_user(_):
            self.assertTrue(self.resource.get_session(self.request).is_logged_in())

        d.addCallback(assert_login_setup_service_for_user)
        return d
class TestLoginPOST(unittest.TestCase):
    def setUp(self):
        self.services_factory = mock()
        self.provider = mock()
        self.authenticator = MagicMock()
        self.resource = LoginResource(self.services_factory, self.provider, authenticator=self.authenticator)
        self.web = DummySite(self.resource)

        self.request = DummyRequest([''])
        username = '******'
        self.request.addArg('username', username)
        password = '******'
        self.username = username
        self.password = password
        self.request.addArg('password', password)
        self.request.method = 'POST'
        user_auth = mock()
        user_auth.uuid = 'some_user_uuid'
        self.user_auth = user_auth

    @patch('twisted.web.util.redirectTo')
    @patch('pixelated.resources.session.PixelatedSession.is_logged_in')
    def test_should_redirect_to_home_if_user_if_already_logged_in(self, mock_logged_in, mock_redirect):
        mock_logged_in.return_value = True
        when(self.services_factory).has_session(ANY()).thenReturn(True)
        mock_redirect.return_value = "mocked redirection"

        d = self.web.get(self.request)

        def assert_redirected_to_home(_):
            mock_redirect.assert_called_once_with('/', self.request)
            self.assertFalse(self.authenticator.authenticate.called)

        d.addCallback(assert_redirected_to_home)
        return d

    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    @patch('twisted.web.util.redirectTo')
    def test_should_redirect_to_login_with_error_flag_when_login_fails(self,
                                                                       mock_redirect,
                                                                       mock_user_bootstrap_setup):
        self.authenticator.authenticate.side_effect = UnauthorizedLogin()
        mock_redirect.return_value = "mocked redirection"

        d = self.web.get(self.request)

        def assert_redirected_to_login(_):
            self.authenticator.authenticate.assert_called_once_with(self.username, self.password)
            mock_redirect.assert_called_once_with('/login?auth-error', self.request)
            self.assertFalse(mock_user_bootstrap_setup.called)
            self.assertFalse(self.resource.get_session(self.request).is_logged_in())

        d.addCallback(assert_redirected_to_login)
        return d

    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    def test_successful_login_responds_interstitial(self, mock_user_bootstrap_setup):
        self.authenticator.authenticate.return_value = self.user_auth

        d = self.web.get(self.request)

        def assert_interstitial_in_response(_):
            self.authenticator.authenticate.assert_called_once_with(self.username, self.password)
            interstitial_js_in_template = '<script src="/public/interstitial.js"></script>'
            self.assertIn(interstitial_js_in_template, self.request.written[0])

        d.addCallback(assert_interstitial_in_response)
        return d

    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    def test_successful_login_runs_user_services_bootstrap_when_interstitial_loaded(self, mock_user_bootstrap_setup):
        self.authenticator.authenticate.return_value = self.user_auth

        d = self.web.get(self.request)

        def assert_login_setup_service_for_user(_):
            mock_user_bootstrap_setup.assert_called_once_with(self.user_auth, self.password, 'en-US')

        d.addCallback(assert_login_setup_service_for_user)
        return d

    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    def test_successful_adds_cookies_to_indicate_logged_in_status_when_services_are_loaded(self, mock_user_bootstrap_setup):
        self.authenticator.authenticate.return_value = self.user_auth
        irrelevant = None
        mock_user_bootstrap_setup.return_value = defer.succeed(irrelevant)

        d = self.web.get(self.request)

        def assert_login_setup_service_for_user(_):
            self.assertTrue(self.resource.get_session(self.request).is_logged_in())

        d.addCallback(assert_login_setup_service_for_user)
        return d

    @patch('pixelated.resources.session.PixelatedSession.login_started')
    def test_session_adds_login_started_status_after_authentication(self, mock_login_started):
        self.authenticator.authenticate.return_value = self.user_auth

        d = self.web.get(self.request)

        def assert_login_started_called(_):
            mock_login_started.assert_called_once()

        d.addCallback(assert_login_started_called)
        return d

    @patch('pixelated.resources.session.PixelatedSession.login_successful')
    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    def test_session_adds_login_successful_status_when_services_setup_finishes(self, mock_user_bootstrap_setup, mock_login_successful):
        self.authenticator.authenticate.return_value = self.user_auth
        mock_user_bootstrap_setup.return_value = defer.succeed(None)

        d = self.web.get(self.request)

        def assert_login_successful_called(_):
            mock_login_successful.assert_called_once()

        d.addCallback(assert_login_successful_called)
        return d

    @patch('pixelated.resources.session.PixelatedSession.login_error')
    @patch('pixelated.config.leap.BootstrapUserServices.setup')
    def test_session_adds_login_error_status_when_services_setup_gets_error(self, mock_user_bootstrap_setup, mock_login_error):
        self.authenticator.authenticate.return_value = self.user_auth
        mock_user_bootstrap_setup.return_value = defer.fail(Exception('Could not setup user services'))

        d = self.web.get(self.request)

        def assert_login_error_called(_):
            mock_login_error.assert_called_once()

        d.addCallback(assert_login_error_called)
        return d