# This file is part of the Reproducible Open Benchmarks for Data Analysis
# Platform (ROB).
#
# Copyright (C) 2019 NYU.
#
# ROB is free software; you can redistribute it and/or modify it under the
# terms of the MIT License; see LICENSE file for more details.

"""Test functionality of the user manager."""

import os
import pytest
import time

from benchengine.db import DatabaseDriver
from benchengine.user.manager import UserManager

import benchengine.error as err
import benchtmpl.util.core as util


class TestUserManager(object):
    """Test user registration and password reset."""
    def connect(self, base_dir):
        """Create a fresh database and return connected user manager."""
        connect_string = 'sqlite:{}/auth.db'.format(str(base_dir))
        DatabaseDriver.init_db(connect_string=connect_string)
        con = DatabaseDriver.connect(connect_string=connect_string)
        return UserManager(con)

    def test_activate_user(self, tmpdir):
        """Test creating inactive users and activating them."""
        # Create an inactive user.
        umanager = self.connect(tmpdir)
        user_id = umanager.register_user('<EMAIL>', '<PASSWORD>', verify=True)
        # Attempt to login will raise error
        with pytest.raises(err.UnknownUserError):
            umanager.login('<EMAIL>', '<PASSWORD>')
        # After activating the user login should succeed
        umanager.activate_user(user_id)
        api_key = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key)
        assert user.email == '<EMAIL>'

    def test_get_user(self, tmpdir):
        """Test getting user information."""
        umanager = self.connect(tmpdir)
        user_id = umanager.register_user('<EMAIL>', '<PASSWORD>')
        user = umanager.get_user('<EMAIL>')
        assert user.identifier == user_id
        assert user.username == '<EMAIL>'
        with pytest.raises(err.UnknownUserError):
            umanager.get_user('<EMAIL>')

    def test_list_user(self, tmpdir):
        """Test listing user."""
        umanager = self.connect(tmpdir)
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        users = [u.username for u in umanager.list_user()]
        assert len(users) == 2
        assert '<EMAIL>' in users
        assert '<EMAIL>' in users
        for user in umanager.list_user():
            assert not user.is_logged_in()
        umanager.login('<EMAIL>', '<PASSWORD>')
        umanager.login('<EMAIL>', '<PASSWORD>')
        assert len(users) == 2
        for user in umanager.list_user():
            assert user.is_logged_in()

    def test_register_user(self, tmpdir):
        """Test registering a new user."""
        umanager = self.connect(tmpdir)
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        api_key_1 = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key_1)
        assert user.email == '<EMAIL>'
        assert user.email == user.username
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        api_key_2 = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key_2)
        assert user.email == '<EMAIL>'
        users = [u.username for u in umanager.list_user()]
        assert len(users) == 2
        assert '<EMAIL>' in users
        assert '<EMAIL>' in users
        # Register user with existing email address raises error
        with pytest.raises(err.DuplicateUserError):
            umanager.register_user('<EMAIL>', '<PASSWORD>')
        # Providing invalid email or passowrd will raise error
        with pytest.raises(err.ConstraintViolationError):
            umanager.register_user('a' * 256, '<PASSWORD>')
        with pytest.raises(err.ConstraintViolationError):
            umanager.register_user('<EMAIL>', ' ')

    def test_reset_password(self, tmpdir):
        """Test resetting a user password."""
        umanager = self.connect(tmpdir)
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        api_key = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key)
        assert user.email == '<EMAIL>'
        request_id_1 = umanager.request_password_reset('<EMAIL>')
        assert not request_id_1 is None
        # Request reset for unknown user will return a reset request id
        request_id_2 = umanager.request_password_reset('<EMAIL>')
        assert not request_id_2 is None
        assert request_id_1 != request_id_2
        # Reset password for existing user
        umanager.reset_password(request_id=request_id_1, password='<PASSWORD>')
        # After resetting the password the previous API key for the user is
        # invalid
        with pytest.raises(err.UnauthenticatedAccessError):
            umanager.authenticate(api_key)
        api_key = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key)
        assert user.email == '<EMAIL>'
        # An error is raised when (i) trying to use a request for an unknown
        # user, (ii) a previously completed reset request, or (iii) an unknown
        # request identifier to reset a user password
        with pytest.raises(err.UnknownResourceError):
            umanager.reset_password(request_id=request_id_1, password='<PASSWORD>')
        with pytest.raises(err.UnknownResourceError):
            umanager.reset_password(request_id=request_id_2, password='<PASSWORD>')
        with pytest.raises(err.UnknownResourceError):
            umanager.reset_password(request_id='unknown', password='<PASSWORD>')

    def test_reset_request_timeout(self, tmpdir):
        """Test resetting a user password using a request identifier that has
        timed out.
        """
        umanager = self.connect(tmpdir)
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        api_key = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key)
        assert user.email == '<EMAIL>'
        # Hack: Manipulate the login_timeout value to similate timeout
        umanager.login_timeout = 1
        # Request reset and sleep for two seconds. This should allow the request
        # to timeout
        request_id = umanager.request_password_reset('<EMAIL>')
        time.sleep(2)
        with pytest.raises(err.UnknownResourceError):
            umanager.reset_password(request_id=request_id, password='<PASSWORD>')

# This file is part of the Reproducible Open Benchmarks for Data Analysis
# Platform (ROB).
#
# Copyright (C) 2019 NYU.
#
# ROB is free software; you can redistribute it and/or modify it under the
# terms of the MIT License; see LICENSE file for more details.

"""Test functionality of the user manager."""

import os
import pytest
import time

from benchengine.db import DatabaseDriver
from benchengine.user.manager import UserManager

import benchengine.error as err
import benchtmpl.util.core as util


class TestUserManager(object):
    """Test user registration and password reset."""
    def connect(self, base_dir):
        """Create a fresh database and return connected user manager."""
        connect_string = 'sqlite:{}/auth.db'.format(str(base_dir))
        DatabaseDriver.init_db(connect_string=connect_string)
        con = DatabaseDriver.connect(connect_string=connect_string)
        return UserManager(con)

    def test_activate_user(self, tmpdir):
        """Test creating inactive users and activating them."""
        # Create an inactive user.
        umanager = self.connect(tmpdir)
        user_id = umanager.register_user('<EMAIL>', '<PASSWORD>', verify=True)
        # Attempt to login will raise error
        with pytest.raises(err.UnknownUserError):
            umanager.login('<EMAIL>', '<PASSWORD>')
        # After activating the user login should succeed
        umanager.activate_user(user_id)
        api_key = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key)
        assert user.email == '<EMAIL>'

    def test_get_user(self, tmpdir):
        """Test getting user information."""
        umanager = self.connect(tmpdir)
        user_id = umanager.register_user('<EMAIL>', '<PASSWORD>')
        user = umanager.get_user('<EMAIL>')
        assert user.identifier == user_id
        assert user.username == '<EMAIL>'
        with pytest.raises(err.UnknownUserError):
            umanager.get_user('<EMAIL>')

    def test_list_user(self, tmpdir):
        """Test listing user."""
        umanager = self.connect(tmpdir)
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        users = [u.username for u in umanager.list_user()]
        assert len(users) == 2
        assert '<EMAIL>' in users
        assert '<EMAIL>' in users
        for user in umanager.list_user():
            assert not user.is_logged_in()
        umanager.login('<EMAIL>', '<PASSWORD>')
        umanager.login('<EMAIL>', '<PASSWORD>')
        assert len(users) == 2
        for user in umanager.list_user():
            assert user.is_logged_in()

    def test_register_user(self, tmpdir):
        """Test registering a new user."""
        umanager = self.connect(tmpdir)
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        api_key_1 = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key_1)
        assert user.email == '<EMAIL>'
        assert user.email == user.username
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        api_key_2 = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key_2)
        assert user.email == '<EMAIL>'
        users = [u.username for u in umanager.list_user()]
        assert len(users) == 2
        assert '<EMAIL>' in users
        assert '<EMAIL>' in users
        # Register user with existing email address raises error
        with pytest.raises(err.DuplicateUserError):
            umanager.register_user('<EMAIL>', '<PASSWORD>')
        # Providing invalid email or passowrd will raise error
        with pytest.raises(err.ConstraintViolationError):
            umanager.register_user('a' * 256, '<PASSWORD>')
        with pytest.raises(err.ConstraintViolationError):
            umanager.register_user('<EMAIL>', ' ')

    def test_reset_password(self, tmpdir):
        """Test resetting a user password."""
        umanager = self.connect(tmpdir)
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        api_key = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key)
        assert user.email == '<EMAIL>'
        request_id_1 = umanager.request_password_reset('<EMAIL>')
        assert not request_id_1 is None
        # Request reset for unknown user will return a reset request id
        request_id_2 = umanager.request_password_reset('<EMAIL>')
        assert not request_id_2 is None
        assert request_id_1 != request_id_2
        # Reset password for existing user
        umanager.reset_password(request_id=request_id_1, password='<PASSWORD>')
        # After resetting the password the previous API key for the user is
        # invalid
        with pytest.raises(err.UnauthenticatedAccessError):
            umanager.authenticate(api_key)
        api_key = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key)
        assert user.email == '<EMAIL>'
        # An error is raised when (i) trying to use a request for an unknown
        # user, (ii) a previously completed reset request, or (iii) an unknown
        # request identifier to reset a user password
        with pytest.raises(err.UnknownResourceError):
            umanager.reset_password(request_id=request_id_1, password='<PASSWORD>')
        with pytest.raises(err.UnknownResourceError):
            umanager.reset_password(request_id=request_id_2, password='<PASSWORD>')
        with pytest.raises(err.UnknownResourceError):
            umanager.reset_password(request_id='unknown', password='<PASSWORD>')

    def test_reset_request_timeout(self, tmpdir):
        """Test resetting a user password using a request identifier that has
        timed out.
        """
        umanager = self.connect(tmpdir)
        umanager.register_user('<EMAIL>', '<PASSWORD>')
        api_key = umanager.login('<EMAIL>', '<PASSWORD>')
        user = umanager.authenticate(api_key)
        assert user.email == '<EMAIL>'
        # Hack: Manipulate the login_timeout value to similate timeout
        umanager.login_timeout = 1
        # Request reset and sleep for two seconds. This should allow the request
        # to timeout
        request_id = umanager.request_password_reset('<EMAIL>')
        time.sleep(2)
        with pytest.raises(err.UnknownResourceError):
            umanager.reset_password(request_id=request_id, password='<PASSWORD>')

# This file is part of the Reproducible Open Benchmarks for Data Analysis # Platform (ROB). # # Copyright (C) 2019 NYU. # # ROB is free software; you can redistribute it and/or modify it under the # terms of the MIT License; see LICENSE file for more details. Test functionality of the user manager. Test user registration and password reset. Create a fresh database and return connected user manager. Test creating inactive users and activating them. # Create an inactive user. # Attempt to login will raise error # After activating the user login should succeed Test getting user information. Test listing user. Test registering a new user. # Register user with existing email address raises error # Providing invalid email or passowrd will raise error Test resetting a user password. # Request reset for unknown user will return a reset request id # Reset password for existing user # After resetting the password the previous API key for the user is # invalid # An error is raised when (i) trying to use a request for an unknown # user, (ii) a previously completed reset request, or (iii) an unknown # request identifier to reset a user password Test resetting a user password using a request identifier that has         timed out. # Hack: Manipulate the login_timeout value to similate timeout # Request reset and sleep for two seconds. This should allow the request # to timeout