Skip to content

Commit 7e602b7

Browse files
Merge pull request #53 from edx/hammad/ENT-4202
ENT-4202 | Handled edge cases in `refresh_course_skills` command.
2 parents daed9c8 + 1f25888 commit 7e602b7

File tree

5 files changed

+74
-19
lines changed

5 files changed

+74
-19
lines changed

CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ Change Log
1414
Unreleased
1515
--------------------
1616

17+
[1.6.2] - 2021-03-12
18+
--------------------
19+
20+
* Handled edge cases in `refresh_course_skills` command.
21+
1722
[1.6.1] - 2021-03-10
1823
--------------------
1924

taxonomy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
# 2. MINOR version when you add functionality in a backwards compatible manner, and
1616
# 3. PATCH version when you make backwards compatible bug fixes.
1717
# More details can be found at https://semver.org/
18-
__version__ = '1.6.1'
18+
__version__ = '1.6.2'
1919

2020
default_app_config = 'taxonomy.apps.TaxonomyConfig' # pylint: disable=invalid-name

taxonomy/management/commands/refresh_course_skills.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,4 @@ def handle(self, *args, **options):
9090
raise InvalidCommandOptionsError('Either course or all argument must be provided.')
9191

9292
LOGGER.info('[TAXONOMY] Refresh course skills process started.')
93-
success_courses_count, skipped_courses_count, failures = utils.refresh_course_skills(courses, options['commit'])
94-
LOGGER.info(
95-
'[TAXONOMY] Refresh course skills process completed. \n'
96-
'Failures: %s \n'
97-
'Total Courses Updated Successfully: %s \n'
98-
'Total Courses Skipped: %s \n'
99-
'Total Failures: %s \n',
100-
failures,
101-
success_courses_count,
102-
skipped_courses_count,
103-
len(failures),
104-
)
93+
utils.refresh_course_skills(courses, options['commit'])

taxonomy/utils.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,38 @@ def refresh_course_skills(courses, should_commit_to_db):
7676
if course_description:
7777
try:
7878
course_skills = client.get_course_skills(course_description)
79-
LOGGER.info('[TAXONOMY] Skills data received from EMSI. Skills: [%s]', course_skills)
79+
except TaxonomyAPIError:
80+
message = f'[TAXONOMY] API Error for course_key: {course["key"]}'
81+
LOGGER.error(message)
82+
all_failures.append((course['uuid'], message))
83+
continue
84+
85+
try:
8086
failures = process_skills_data(course, course_skills, should_commit_to_db)
8187
if failures:
88+
LOGGER.info('[TAXONOMY] Skills data received from EMSI. Skills: [%s]', course_skills)
8289
all_failures += failures
8390
else:
8491
success_courses_count += 1
85-
except TaxonomyAPIError:
86-
message = f'[TAXONOMY] API Error for course_key: {course["key"]}'
92+
except Exception as ex: # pylint: disable=broad-except
93+
LOGGER.info('[TAXONOMY] Skills data received from EMSI. Skills: [%s]', course_skills)
94+
message = f'[TAXONOMY] Exception for course_key: {course["key"]} Error: {ex}'
8795
LOGGER.error(message)
8896
all_failures.append((course['uuid'], message))
8997
else:
9098
skipped_courses_count += 1
9199

92-
return success_courses_count, skipped_courses_count, all_failures
100+
LOGGER.info(
101+
'[TAXONOMY] Refresh course skills process completed. \n'
102+
'Failures: %s \n'
103+
'Total Courses Updated Successfully: %s \n'
104+
'Total Courses Skipped: %s \n'
105+
'Total Failures: %s \n',
106+
all_failures,
107+
success_courses_count,
108+
skipped_courses_count,
109+
len(all_failures),
110+
)
93111

94112

95113
def blacklist_course_skill(course_key, skill_id):

tests/management/test_refresh_course_skills.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,10 @@ def test_course_skill_not_saved_for_key_error(self, get_course_skills_mock, get_
260260
[
261261
'[TAXONOMY] Refresh Course Skills. Options: [%s]',
262262
'[TAXONOMY] Refresh course skills process started.',
263-
'[TAXONOMY] Skills data received from EMSI. Skills: [%s]',
264263
f'[TAXONOMY] Missing keys in skills data for course_key: {self.course_1.key}',
265264
'[TAXONOMY] Skills data received from EMSI. Skills: [%s]',
266265
f'[TAXONOMY] Missing keys in skills data for course_key: {self.course_2.key}',
266+
'[TAXONOMY] Skills data received from EMSI. Skills: [%s]',
267267
'[TAXONOMY] Refresh course skills process completed. \n'
268268
'Failures: %s \n'
269269
'Total Courses Updated Successfully: %s \n'
@@ -301,10 +301,10 @@ def test_course_skill_not_saved_for_type_error(self, get_course_skills_mock, get
301301
[
302302
'[TAXONOMY] Refresh Course Skills. Options: [%s]',
303303
'[TAXONOMY] Refresh course skills process started.',
304-
'[TAXONOMY] Skills data received from EMSI. Skills: [%s]',
305304
f'[TAXONOMY] Invalid type for `confidence` in course skills for course_key: {self.course_1.key}',
306305
'[TAXONOMY] Skills data received from EMSI. Skills: [%s]',
307306
f'[TAXONOMY] Invalid type for `confidence` in course skills for course_key: {self.course_2.key}',
307+
'[TAXONOMY] Skills data received from EMSI. Skills: [%s]',
308308
'[TAXONOMY] Refresh course skills process completed. \n'
309309
'Failures: %s \n'
310310
'Total Courses Updated Successfully: %s \n'
@@ -315,3 +315,46 @@ def test_course_skill_not_saved_for_type_error(self, get_course_skills_mock, get
315315

316316
self.assertEqual(skill.count(), 0)
317317
self.assertEqual(course_skill.count(), 0)
318+
319+
@responses.activate
320+
@mock.patch('taxonomy.management.commands.refresh_course_skills.get_course_metadata_provider')
321+
@mock.patch('taxonomy.management.commands.refresh_course_skills.utils.EMSISkillsApiClient.get_course_skills')
322+
@mock.patch('taxonomy.management.commands.refresh_course_skills.utils.process_skills_data')
323+
def test_course_skill_not_saved_for_exception(
324+
self,
325+
mock_process_skills_data,
326+
get_course_skills_mock,
327+
get_course_provider_mock,
328+
329+
):
330+
"""
331+
Test that the command does not create any records when a record value error occurs.
332+
"""
333+
get_course_skills_mock.return_value = self.skills_emsi_client_response
334+
get_course_provider_mock.return_value = DiscoveryCourseMetadataProvider([self.course_1])
335+
mock_process_skills_data.side_effect = Exception("UNKNOWN ERROR.")
336+
skill = Skill.objects.all()
337+
course_skill = CourseSkills.objects.all()
338+
self.assertEqual(skill.count(), 0)
339+
self.assertEqual(course_skill.count(), 0)
340+
341+
with LogCapture(level=logging.INFO) as log_capture:
342+
call_command(self.command, '--course', self.course_1.uuid, '--commit')
343+
# Validate a descriptive and readable log message.
344+
self.assertEqual(len(log_capture.records), 5)
345+
messages = [record.msg for record in log_capture.records]
346+
self.assertEqual(
347+
messages,
348+
['[TAXONOMY] Refresh Course Skills. Options: [%s]',
349+
'[TAXONOMY] Refresh course skills process started.',
350+
'[TAXONOMY] Skills data received from EMSI. Skills: [%s]',
351+
f'[TAXONOMY] Exception for course_key: {self.course_1.key} Error: UNKNOWN ERROR.',
352+
'[TAXONOMY] Refresh course skills process completed. \n'
353+
'Failures: %s \n'
354+
'Total Courses Updated Successfully: %s \n'
355+
'Total Courses Skipped: %s \n'
356+
'Total Failures: %s \n']
357+
)
358+
359+
self.assertEqual(skill.count(), 0)
360+
self.assertEqual(course_skill.count(), 0)

0 commit comments

Comments
 (0)