Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #205: Add functionality to reset authentication token and logout #233

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
17 changes: 17 additions & 0 deletions evalai/logout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import click

from click import echo, style

from evalai.utils.auth import reset_user_auth_token


@click.group(invoke_without_command=True)
def logout():
"""
Log out the user by resetting authentication token
"""
"""
Invoked by `evalai logout`
"""
reset_user_auth_token()
echo(style("Logout successful", bold=True, fg="green"))
2 changes: 2 additions & 0 deletions evalai/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .teams import teams
from .get_token import get_token
from .login import login
from .logout import logout


@click.version_option()
Expand Down Expand Up @@ -43,3 +44,4 @@ def main(ctx):
main.add_command(teams)
main.add_command(get_token)
main.add_command(login)
main.add_command(logout)
21 changes: 21 additions & 0 deletions evalai/utils/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,24 @@ def get_host_url():
return str(data)
except (OSError, IOError) as e:
echo(style(e, bold=True, fg="red"))


def reset_user_auth_token():
"""
Resets the auth token of the user by deleting token.json file
"""
if not os.path.exists(AUTH_TOKEN_PATH):
echo(
style(
"\nThe authentication token has not been configured. Please use the commands "
"`evalai login` or `evalai set_token TOKEN` first to set up the configuration.\n",
bold=True,
fg="red",
),
)
sys.exit(1)
try:
os.remove(AUTH_TOKEN_PATH)
except (OSError, IOError) as e:
echo(e)
sys.exit(1)
70 changes: 70 additions & 0 deletions tests/test_auth_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import json
import os
import random
import shutil
import string
import tempfile

from io import StringIO
from unittest import mock
from unittest import TestCase

from evalai.utils.auth import reset_user_auth_token


class TestResetUserAuthToken(TestCase):
def setUp(self):
self.base_temp_dir = tempfile.mkdtemp()
self.token_dir = os.path.join(self.base_temp_dir, ".evalai")
self.token_path = os.path.join(self.token_dir, "token.json")

self.token = "".join(random.choice(string.ascii_lowercase) for _ in range(40))
self.token_json = json.dumps({"token": self.token})

os.makedirs(self.token_dir)
with open(self.token_path, "w") as fw:
fw.write(self.token_json)

self.patcher = mock.patch("evalai.utils.auth.AUTH_TOKEN_PATH", self.token_path)
self.patcher.start()

def tearDown(self):
self.patcher.stop()
if os.path.exists(self.base_temp_dir):
shutil.rmtree(self.base_temp_dir)

def test_reset_user_auth_token_success(self):
self.assertTrue(os.path.exists(self.token_path)) # Make sure the path exists already
reset_user_auth_token()

self.assertFalse(os.path.exists(self.token_path))

def test_reset_user_auth_token_when_token_is_not_configured(self):
os.remove(self.token_path)
expected = str(
"The authentication token has not been configured. Please use the commands "
"`evalai login` or `evalai set_token TOKEN` first to set up the configuration."
)

with mock.patch("sys.stdout", StringIO()) as fake_out:
with self.assertRaises(SystemExit) as cm:
reset_user_auth_token()
exit_code = cm.exception.code
value = fake_out.getvalue().strip()

self.assertEqual(exit_code, 1)
self.assertEqual(value, expected)

@mock.patch("evalai.utils.auth.os.remove")
def test_reset_user_auth_token_when_writing_to_file_fails(self, mock_remove):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nikochiko What does this test signify?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pushkalkatara this is the test for the case when file deleting fails. And oops I think I named it incorrectly 😕 . How about changing the name to test_reset_user_auth_token_when_token_file_removal_fails ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! 👍

error = "ExampleError: Example Error Description"
mock_remove.side_effect = OSError(error)

with mock.patch("sys.stdout", StringIO()) as fake_out:
with self.assertRaises(SystemExit) as cm:
reset_user_auth_token()
exit_code = cm.exception.code
value = fake_out.getvalue().strip()

self.assertEqual(exit_code, 1)
self.assertEqual(value, error)