Skip to content
Open
14 changes: 13 additions & 1 deletion evalai/add_token.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import os
import sys

import click
import json
import validators

from click import echo, style

from evalai.utils.auth import reset_user_auth_token
from evalai.utils.config import AUTH_TOKEN_DIR, AUTH_TOKEN_PATH, LEN_OF_TOKEN


Expand All @@ -16,8 +18,18 @@ def set_token(auth_token):
Configure EvalAI Token.
"""
"""
Invoked by `evalai set_token <your_evalai_auth_token>`.
Invoked by `evalai set_token <your_evalai_auth_token>` or `evalai set_token clear_token`.
"""
if auth_token == "clear_token":
reset_user_auth_token()
echo(
style(
"\nAuthentication Token has been reset successfully.\n",
bold=True,
fg="green",
)
)
sys.exit()
if validators.length(auth_token, min=LEN_OF_TOKEN, max=LEN_OF_TOKEN):
if not os.path.exists(AUTH_TOKEN_DIR):
os.makedirs(AUTH_TOKEN_DIR)
Expand Down
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)