|
| 1 | +import json |
| 2 | +import logging |
1 | 3 | from contextlib import contextmanager |
2 | 4 |
|
| 5 | +import mock |
| 6 | +import responses |
| 7 | + |
3 | 8 | from django.conf import settings |
4 | 9 | from django.contrib.auth.models import User |
5 | 10 | from django.db.utils import ConnectionHandler, DatabaseError |
6 | 11 | from django.test import TestCase |
7 | 12 | from django.test.utils import override_settings |
8 | | - |
9 | | -import mock |
10 | 13 | from rest_framework.authtoken.models import Token |
| 14 | + |
11 | 15 | from analytics_data_api.v0.models import CourseEnrollmentDaily, CourseEnrollmentByBirthYear |
| 16 | +from analyticsdataserver.clients import CourseBlocksApiClient |
12 | 17 | from analyticsdataserver.router import AnalyticsApiRouter |
| 18 | +from analyticsdataserver.utils import temp_log_level |
13 | 19 |
|
14 | 20 |
|
15 | 21 | class TestCaseWithAuthentication(TestCase): |
@@ -97,3 +103,98 @@ def test_allow_relation(self): |
97 | 103 | """ |
98 | 104 | self.assertFalse(self.router.allow_relation(CourseEnrollmentDaily, User)) |
99 | 105 | self.assertTrue(self.router.allow_relation(CourseEnrollmentDaily, CourseEnrollmentByBirthYear)) |
| 106 | + |
| 107 | + |
| 108 | +class UtilsTests(TestCase): |
| 109 | + def setUp(self): |
| 110 | + self.logger = logging.getLogger('test_logger') |
| 111 | + |
| 112 | + def test_temp_log_level(self): |
| 113 | + """Ensures log level is adjusted within context manager and returns to original level when exited.""" |
| 114 | + original_level = self.logger.getEffectiveLevel() |
| 115 | + with temp_log_level('test_logger'): # NOTE: defaults to logging.CRITICAL |
| 116 | + self.assertEqual(self.logger.getEffectiveLevel(), logging.CRITICAL) |
| 117 | + self.assertEqual(self.logger.getEffectiveLevel(), original_level) |
| 118 | + |
| 119 | + # test with log_level option used |
| 120 | + with temp_log_level('test_logger', log_level=logging.DEBUG): |
| 121 | + self.assertEqual(self.logger.getEffectiveLevel(), logging.DEBUG) |
| 122 | + self.assertEqual(self.logger.getEffectiveLevel(), original_level) |
| 123 | + |
| 124 | + |
| 125 | +class ClientTests(TestCase): |
| 126 | + @mock.patch('analyticsdataserver.clients.EdxRestApiClient') |
| 127 | + def setUp(self, *args, **kwargs): # pylint: disable=unused-argument |
| 128 | + self.client = CourseBlocksApiClient('http://example.com/', 'token', 5) |
| 129 | + |
| 130 | + @responses.activate |
| 131 | + def test_all_videos(self): |
| 132 | + responses.add(responses.GET, 'http://example.com/blocks/', body=json.dumps({'blocks': { |
| 133 | + 'block-v1:edX+DemoX+Demo_Course+type@video+block@5c90cffecd9b48b188cbfea176bf7fe9': { |
| 134 | + 'id': 'block-v1:edX+DemoX+Demo_Course+type@video+block@5c90cffecd9b48b188cbfea176bf7fe9' |
| 135 | + }, |
| 136 | + 'block-v1:edX+DemoX+Demo_Course+type@video+block@7e9b434e6de3435ab99bd3fb25bde807': { |
| 137 | + 'id': 'block-v1:edX+DemoX+Demo_Course+type@video+block@7e9b434e6de3435ab99bd3fb25bde807' |
| 138 | + } |
| 139 | + }}), status=200, content_type='application/json') |
| 140 | + videos = self.client.all_videos('course_id') |
| 141 | + self.assertListEqual(videos, [ |
| 142 | + { |
| 143 | + 'video_id': 'course_id|5c90cffecd9b48b188cbfea176bf7fe9', |
| 144 | + 'video_module_id': '5c90cffecd9b48b188cbfea176bf7fe9' |
| 145 | + }, |
| 146 | + { |
| 147 | + 'video_id': 'course_id|7e9b434e6de3435ab99bd3fb25bde807', |
| 148 | + 'video_module_id': '7e9b434e6de3435ab99bd3fb25bde807' |
| 149 | + } |
| 150 | + ]) |
| 151 | + |
| 152 | + @responses.activate |
| 153 | + @mock.patch('analyticsdataserver.clients.logger') |
| 154 | + def test_all_videos_401(self, logger): |
| 155 | + responses.add(responses.GET, 'http://example.com/blocks/', status=401, content_type='application/json') |
| 156 | + videos = self.client.all_videos('course_id') |
| 157 | + logger.warning.assert_called_with( |
| 158 | + 'Course Blocks API failed to return video ids (%s). ' + |
| 159 | + 'See README for instructions on how to authenticate the API with your local LMS.', 401) |
| 160 | + self.assertEqual(videos, None) |
| 161 | + |
| 162 | + @responses.activate |
| 163 | + @mock.patch('analyticsdataserver.clients.logger') |
| 164 | + def test_all_videos_404(self, logger): |
| 165 | + responses.add(responses.GET, 'http://example.com/blocks/', status=404, content_type='application/json') |
| 166 | + videos = self.client.all_videos('course_id') |
| 167 | + logger.warning.assert_called_with('Course Blocks API failed to return video ids (%s). ' + |
| 168 | + 'Does the course exist in the LMS?', 404) |
| 169 | + self.assertEqual(videos, None) |
| 170 | + |
| 171 | + @responses.activate |
| 172 | + @mock.patch('analyticsdataserver.clients.logger') |
| 173 | + def test_all_videos_500(self, logger): |
| 174 | + responses.add(responses.GET, 'http://example.com/blocks/', status=418, content_type='application/json') |
| 175 | + videos = self.client.all_videos('course_id') |
| 176 | + logger.warning.assert_called_with('Course Blocks API failed to return video ids (%s).', 418) |
| 177 | + self.assertEqual(videos, None) |
| 178 | + |
| 179 | + @responses.activate |
| 180 | + def test_all_videos_pass_through_bad_id(self): |
| 181 | + responses.add(responses.GET, 'http://example.com/blocks/', body=json.dumps({'blocks': { |
| 182 | + 'block-v1:edX+DemoX+Demo_Course+type@video+block@5c90cffecd9b48b188cbfea176bf7fe9': { |
| 183 | + 'id': 'bad_key' |
| 184 | + }, |
| 185 | + 'block-v1:edX+DemoX+Demo_Course+type@video+block@7e9b434e6de3435ab99bd3fb25bde807': { |
| 186 | + 'id': 'bad_key' |
| 187 | + } |
| 188 | + }}), status=200, content_type='application/json') |
| 189 | + responses.add(responses.GET, 'http://example.com/blocks/', status=200, content_type='application/json') |
| 190 | + videos = self.client.all_videos('course_id') |
| 191 | + self.assertListEqual(videos, [ |
| 192 | + { |
| 193 | + 'video_id': 'course_id|bad_key', |
| 194 | + 'video_module_id': 'bad_key' |
| 195 | + }, |
| 196 | + { |
| 197 | + 'video_id': 'course_id|bad_key', |
| 198 | + 'video_module_id': 'bad_key' |
| 199 | + } |
| 200 | + ]) |
0 commit comments