-
Notifications
You must be signed in to change notification settings - Fork 1
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
feat: add XApiBaseEnrollmentFilter #108
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
"""This file contains all the test for the utils.py file. | ||
|
||
Classes: | ||
ExtractCourseIdFromStringTestCase: Tests cases for the extract_course_id_from_string method. | ||
GetCourseFromIdTestCase: Tests cases for the get_course_from_id method. | ||
""" | ||
from ddt import data, ddt | ||
from django.test import TestCase | ||
from mock import patch | ||
from opaque_keys.edx.keys import CourseKey | ||
|
||
from eox_nelp.utils import extract_course_id_from_string, get_course_from_id | ||
|
||
|
||
@ddt | ||
class ExtractCourseIdFromStringTestCase(TestCase): | ||
"""Test class for the extract_course_id_from_string method.""" | ||
|
||
@data( | ||
"this is a long string", | ||
"hjsdgafhawsdbfhsdyafgbhjsdbf1784561553415534", | ||
"this is a similar string course-v1:77777554a45sd4a2ad42s45d", | ||
"https://example.com/course/course-v1edx+CS105+2023-T3" | ||
) | ||
def test_course_id_not_found(self, value): | ||
""" Test that the method returns an empty string when any course_id is not found | ||
|
||
Expected behavior: | ||
- Returned value is an empty string | ||
""" | ||
result = extract_course_id_from_string(value) | ||
|
||
self.assertEqual("", result) | ||
|
||
@data( | ||
["course-v1:edx+PS874+2023-T3", "this is a course-v1:edx+PS874+2023-T3/) long string"], | ||
["course-v1:edunext+CS105+2019-P3", "hjsdgafhawsdbfhgbhjsdbf1784561553415534course-v1:edunext+CS105+2019-P3"], | ||
["course-v1:NELC+TR675+2022-K3", "this course-v1:NELC+TR675+2022-K3/ is a similar string course-v1:77775s45d"], | ||
["course-v1:edx+CS105+2023-T3", "https://example.com/course/course-v1:edx+CS105+2023-T3"], | ||
) | ||
def test_course_id_found(self, value): | ||
""" Test that the method returns right course id. | ||
|
||
Expected behavior: | ||
- Returned value is the expected course id. | ||
""" | ||
result = extract_course_id_from_string(value[1]) | ||
|
||
self.assertEqual(value[0], result) | ||
|
||
def test_multiple_valid_ids(self): | ||
""" Test that the method returns the first value that matches the regular expression. | ||
|
||
Expected behavior: | ||
- Returned value is the expected course id. | ||
""" | ||
string = ( | ||
"/course-v1:edx+CS105+2023-T3/" | ||
"/course-v1:NELC+TR675+2022-K3/" | ||
"/course-v1:edx+PS874+2023-T3/" | ||
"/course-v1:edunext+CS105+2019-P3/" | ||
) | ||
|
||
result = extract_course_id_from_string(string) | ||
|
||
self.assertEqual("course-v1:edx+CS105+2023-T3", result) | ||
|
||
|
||
class GetCourseFromIdTestCase(TestCase): | ||
"""Test class for the get_course_from_id method.""" | ||
|
||
@patch("eox_nelp.utils.get_course_overviews") | ||
def test_course_id_not_found(self, course_overviews_mock): | ||
""" Test that the method raises the right exception when there are no courses. | ||
|
||
Expected behavior: | ||
- Raises ValueError exception. | ||
- get_course_overviews method was called with the right parameter. | ||
""" | ||
course_id = "course-v1:edx+CS105+2023-T3" | ||
course_overviews_mock.return_value = [] | ||
|
||
self.assertRaises(ValueError, get_course_from_id, course_id) | ||
course_overviews_mock.assert_called_once_with([CourseKey.from_string(course_id)]) | ||
|
||
@patch("eox_nelp.utils.get_course_overviews") | ||
def test_course_id_found(self, course_overviews_mock): | ||
""" Test that the method returns the expected value. | ||
|
||
Expected behavior: | ||
- Returned value is the expected course. | ||
- get_course_overviews method was called with the right parameter. | ||
""" | ||
course_id = "course-v1:edx+CS105+2023-T3" | ||
expected_course = {"name": "test-course", "short_description": "This is a great course"} | ||
course_overviews_mock.return_value = [expected_course] | ||
|
||
course = get_course_from_id(course_id) | ||
|
||
self.assertEqual(expected_course, course) | ||
course_overviews_mock.assert_called_once_with([CourseKey.from_string(course_id)]) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,12 @@ | |
import re | ||
from copy import copy | ||
|
||
from opaque_keys.edx.keys import CourseKey | ||
|
||
from eox_nelp.edxapp_wrapper.course_overviews import get_course_overviews | ||
|
||
NATIONAL_ID_REGEX = r"^[1-2]\d{9}$" | ||
COURSE_ID_REGEX = r'(course-v1:[^/+]+(/|\+)[^/+]+(/|\+)[^/?]+)' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where was extracted this Regex? >>> from django.conf import settings
>>> settings.COURSE_KEY_REGEX
'(?:[^/+]+(/|\\+)[^/+]+(/|\\+)[^/?]+)' There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from that place the modification is the course-v1: |
||
|
||
|
||
def map_instance_attributes_to_dict(instance, attributes_mapping): | ||
|
@@ -78,3 +83,39 @@ def is_valid_national_id(national_id, raise_exception=False): | |
) | ||
|
||
return check_national_id | ||
|
||
|
||
def extract_course_id_from_string(string): | ||
"""This return a sub-string that matches the course_ir regex | ||
|
||
Arguments: | ||
string: This is a string that could contains a sub-string that matches with the course_id form. | ||
|
||
Returns: | ||
course_id <string>: Returns course id or an empty string. | ||
""" | ||
matches = re.search(COURSE_ID_REGEX, string) | ||
|
||
if matches: | ||
return matches.group() | ||
|
||
return "" | ||
|
||
|
||
def get_course_from_id(course_id): | ||
""" | ||
Get Course object using the `course_id`. | ||
|
||
Arguments: | ||
course_id (str) : ID of the course | ||
|
||
Returns: | ||
Course | ||
""" | ||
course_key = CourseKey.from_string(course_id) | ||
course_overviews = get_course_overviews([course_key]) | ||
|
||
if course_overviews: | ||
return course_overviews[0] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok yes is very weird but that method return like a dict of course_overviews: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have to implement the right method |
||
|
||
raise ValueError(f"Course with id {course_id} does not exist.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you prefer the raise of an exception instead a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a copy of this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you are validating
display_name
is not None, but also is possible thatcourse_language
is emptyNone
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@johanv26 How did you set the course language to None since that option is not available on studio ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually is a very good question.
I tried to defined here, but is not working
But on the other hand my course_overview record of that object is empty.
From admin is difficult to change.
Myabe there is a mismatch of mongo and mysql course_overview...