Skip to content
This repository has been archived by the owner on Sep 5, 2023. It is now read-only.

Update regex for to accept course names with hyphens and underscores #134

Merged
merged 5 commits into from
Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 22 additions & 21 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
node_modules
.vscode
*.py[co]
*~
*.py[co]
.cache
.coverage
.coverage.*
.DS_Store
*.egg-info
.env
.idea/
*.ipynb
.ipynb_checkpoints
*.pid
.pytest_cache
*.retry
.vim/
.vscode
hosts.*
src/build*

dist
docs/_build
docs/build
docs/source/_static/rest-api
.ipynb_checkpoints
grades-sender.lock
hosts
htmlcov
jupyterhub_cookie_secret
jupyterhub.sqlite
MANIFEST
pip-wheel-metadata
*pycache*
secrets
share/jupyterhub/static/components
share/jupyterhub/static/css/style.min.css
share/jupyterhub/static/css/style.min.css.map
*.egg-info
MANIFEST
.coverage
.coverage.*
htmlcov
.idea/
.vim/
*pycache*
.pytest_cache
pip-wheel-metadata
*hosts
hosts
.env
*.ipynb
venv
*.retry
grades-sender.lock
src/build*
venv
2 changes: 1 addition & 1 deletion ansible/roles/jupyterhub/files/jupyterhub_config_lti11.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@
# this url pattern was changed to accept spaces in the assignment name
c.JupyterHub.extra_handlers = [
(
r'/submit-grades/(?P<course_id>\w+)/(?P<assignment_name>.*)$',
r'/submit-grades/(?P<course_id>[a-zA-Z0-9-_]+)/(?P<assignment_name>.*)$',
'illumidesk.handlers.lms_grades.SendGradesHandler',
),
]
Expand Down
6 changes: 3 additions & 3 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
black==19.10b0
codecov==2.1.4
codecov==2.1.7
coverage==5.1
flake8==3.8.3
mock==4.0.2
pre-commit==2.5.0
pre-commit==2.5.1
pytest==5.4.3
pytest-asyncio==0.12.0
pytest-cov==2.9.0
pytest-cov==2.10.0
pytest-html==2.1.1
pytest-metadata==1.9.0
pytest-mock==3.1.1
Expand Down
13 changes: 1 addition & 12 deletions src/tests/illumidesk/authenticators/test_lti11_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from unittest.mock import patch

from illumidesk.authenticators.authenticator import LTI11AuthenticateHandler

from tests.illumidesk.mocks import mock_handler


Expand All @@ -28,15 +29,3 @@ async def test_lti_11_authenticate_handler_invokes_login_user_method():
with patch.object(LTI11AuthenticateHandler, 'login_user', return_value=None) as mock_login_user:
await LTI11AuthenticateHandler(local_handler.application, local_handler.request).post()
assert mock_login_user.called


@pytest.mark.asyncio
async def test_lti_11_authenticate_handler_invokes_login_user_method():
"""
Does the LTI11AuthenticateHandler call the login_user function?
"""
local_handler = mock_handler(LTI11AuthenticateHandler)
with patch.object(LTI11AuthenticateHandler, 'redirect', return_value=None):
with patch.object(LTI11AuthenticateHandler, 'login_user', return_value=None) as mock_login_user:
await LTI11AuthenticateHandler(local_handler.application, local_handler.request).post()
assert mock_login_user.called
18 changes: 17 additions & 1 deletion src/tests/illumidesk/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,28 @@

from docker.errors import NotFound

from tornado.web import Application
from tornado.web import RequestHandler

from unittest.mock import Mock
from unittest.mock import MagicMock

from illumidesk.handlers.lms_grades import LTIGradesSenderControlFile


@pytest.fixture(scope='module')
def app():
class TestHandler(RequestHandler):
def get(self):
self.write("test")

def post(self):
self.write("test")

application = Application([(r'/', TestHandler),]) # noqa: E231
return application


@pytest.fixture(scope='function')
def jupyterhub_api_environ(monkeypatch):
"""
Expand Down Expand Up @@ -51,7 +67,7 @@ def reset_file_loaded():
@pytest.fixture(scope='function')
def setup_course_environ(monkeypatch, tmp_path, jupyterhub_api_environ):
"""
Set the environment variables used in Course class
Set the environment variables used in Course class`
"""
monkeypatch.setenv('MNT_ROOT', str(tmp_path))
monkeypatch.setenv('NB_UID', '10001')
Expand Down
38 changes: 29 additions & 9 deletions src/tests/illumidesk/handlers/test_lms_grades.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,28 @@

from unittest.mock import patch

from illumidesk.handlers.lms_grades import LTIGradesSenderControlFile
from illumidesk.handlers.lms_grades import LTIGradeSender
from illumidesk.handlers.lms_grades import GradesSenderCriticalError
from illumidesk.handlers.lms_grades import AssignmentWithoutGradesError
from illumidesk.handlers.lms_grades import GradesSenderCriticalError
from illumidesk.handlers.lms_grades import LTIGradeSender
from illumidesk.handlers.lms_grades import LTIGradesSenderControlFile
from illumidesk.handlers.lms_grades import GradesSenderMissingInfoError
from illumidesk.handlers.lms_grades import SendGradesHandler

from tests.illumidesk.mocks import mock_handler


@pytest.fixture
def reset_file_loaded():
LTIGradesSenderControlFile.FILE_LOADED = False


@pytest.mark.usefixtures("reset_file_loaded")
@pytest.mark.usefixtures('reset_file_loaded')
class TestLTIGradesSenderControlFile:
def test_control_file_is_initialized_if_not_exists(self, tmp_path):
"""
Does the LTIGradesSenderControlFile class initializes a file with an empty dict when it not exists?
"""
sender_controlfile = LTIGradesSenderControlFile(tmp_path)
print('tmp_path', tmp_path)
assert Path(sender_controlfile.config_fullname).stat().st_size > 0
with Path(sender_controlfile.config_fullname).open('r') as file:
assert json.load(file) == {}
Expand Down Expand Up @@ -97,16 +99,16 @@ def test_sender_control_file_registers_multiple_students_in_same_assignment(self
assert set([s['lms_user_id'] for s in saved['students']]) == {'user1', 'user2'}


def test_grades_sender_raises_a_critical_error_when_gradebook_not_exits(tmp_path):
def test_grades_sender_raises_a_critical_error_when_gradebook_does_not_exist(tmp_path):
"""
Does the sender raises an error when gradebook is not found?
Does the sender raises an error when the gradebook db is not found?
"""
sender_controlfile = LTIGradeSender('course1', 'problem1')
with pytest.raises(GradesSenderCriticalError):
sender_controlfile.send_grades()


def test_grades_sender_raises_an_error_if_there_are_not_grades(tmp_path):
def test_grades_sender_raises_an_error_if_there_are_no_grades(tmp_path):
"""
Does the sender raises an error when there are no grades?
"""
Expand All @@ -119,7 +121,8 @@ def test_grades_sender_raises_an_error_if_there_are_not_grades(tmp_path):

def test_grades_sender_raises_an_error_if_assignment_not_found_in_control_file(tmp_path):
"""
Does the sender raises an error when there are grades but control file not contains info related with?
Does the sender raise an error when there are grades but control file does not contain info related with
the gradebook data?
"""
sender_controlfile = LTIGradeSender('course1', 'problem1')
_ = LTIGradesSenderControlFile(tmp_path)
Expand All @@ -128,3 +131,20 @@ def test_grades_sender_raises_an_error_if_assignment_not_found_in_control_file(t
with patch.object(LTIGradeSender, '_retrieve_grades_from_db', return_value=(lambda: 10, grades_nbgrader)):
with pytest.raises(GradesSenderMissingInfoError):
sender_controlfile.send_grades()


@pytest.mark.asyncio
async def send_grades_handler_invokes_send_grades_method():
"""
Does the SendGradesHandler call the send_grades function from the LTIGradeSender class?
"""
course_id = 'course-name'
assignment_name = 'assignment-name'
local_handler = mock_handler(SendGradesHandler)
lti_grade_sender = LTIGradeSender(course_id, assignment_name)
lti_grade_sender.send_grades()
with patch.object(lti_grade_sender, 'send_grades', return_value=None) as mock_send_grades_handler:
result = await SendGradesHandler(local_handler.application, local_handler.request).post(
course_id, assignment_name
)
assert mock_send_grades_handler.called