|
1 | 1 | """
|
2 | 2 | Test CMS's upstream->downstream syncing system
|
3 | 3 | """
|
| 4 | +import datetime |
4 | 5 | import ddt
|
| 6 | +from pytz import utc |
5 | 7 |
|
6 | 8 | from organizations.api import ensure_organization
|
7 | 9 | from organizations.models import Organization
|
@@ -42,13 +44,33 @@ def setUp(self):
|
42 | 44 | title="Test Upstream Library",
|
43 | 45 | )
|
44 | 46 | self.upstream_key = libs.create_library_block(self.library.key, "html", "test-upstream").usage_key
|
45 |
| - libs.create_library_block(self.library.key, "video", "video-upstream") |
46 | 47 |
|
47 | 48 | upstream = xblock.load_block(self.upstream_key, self.user)
|
48 | 49 | upstream.display_name = "Upstream Title V2"
|
49 | 50 | upstream.data = "<html><body>Upstream content V2</body></html>"
|
50 | 51 | upstream.save()
|
51 | 52 |
|
| 53 | + self.upstream_problem_key = libs.create_library_block(self.library.key, "problem", "problem-upstream").usage_key |
| 54 | + libs.set_library_block_olx(self.upstream_problem_key, ( |
| 55 | + '<problem' |
| 56 | + ' attempts_before_showanswer_button="1"' |
| 57 | + ' display_name="Upstream Problem Title V2"' |
| 58 | + ' due="2024-01-01T00:00:00Z"' |
| 59 | + ' force_save_button="false"' |
| 60 | + ' graceperiod="1d"' |
| 61 | + ' grading_method="last_attempt"' |
| 62 | + ' matlab_api_key="abc"' |
| 63 | + ' max_attempts="10"' |
| 64 | + ' rerandomize=""always""' |
| 65 | + ' show_correctness="never"' |
| 66 | + ' show_reset_button="false"' |
| 67 | + ' showanswer="on_correct"' |
| 68 | + ' submission_wait_seconds="10"' |
| 69 | + ' use_latex_compiler="false"' |
| 70 | + ' weight="1"' |
| 71 | + '/>\n' |
| 72 | + )) |
| 73 | + |
52 | 74 | libs.publish_changes(self.library.key, self.user.id)
|
53 | 75 |
|
54 | 76 | self.taxonomy_all_org = tagging_api.create_taxonomy(
|
@@ -179,6 +201,100 @@ def test_sync_updates_happy_path(self):
|
179 | 201 | for object_tag in object_tags:
|
180 | 202 | assert object_tag.value in new_upstream_tags
|
181 | 203 |
|
| 204 | + # pylint: disable=too-many-statements |
| 205 | + def test_sync_updates_to_downstream_only_fields(self): |
| 206 | + """ |
| 207 | + If we sync to modified content, will it preserve downstream-only fields, and overwrite the rest? |
| 208 | + """ |
| 209 | + downstream = BlockFactory.create(category='problem', parent=self.unit, upstream=str(self.upstream_problem_key)) |
| 210 | + |
| 211 | + # Initial sync |
| 212 | + sync_from_upstream(downstream, self.user) |
| 213 | + |
| 214 | + # These fields are copied from upstream |
| 215 | + assert downstream.upstream_display_name == "Upstream Problem Title V2" |
| 216 | + assert downstream.display_name == "Upstream Problem Title V2" |
| 217 | + assert downstream.rerandomize == '"always"' |
| 218 | + assert downstream.matlab_api_key == 'abc' |
| 219 | + assert not downstream.use_latex_compiler |
| 220 | + |
| 221 | + # These fields are "downstream only", so field defaults are preserved, and values are NOT copied from upstream |
| 222 | + assert downstream.attempts_before_showanswer_button == 0 |
| 223 | + assert downstream.due is None |
| 224 | + assert not downstream.force_save_button |
| 225 | + assert downstream.graceperiod is None |
| 226 | + assert downstream.grading_method == 'last_score' |
| 227 | + assert downstream.max_attempts is None |
| 228 | + assert downstream.show_correctness == 'always' |
| 229 | + assert not downstream.show_reset_button |
| 230 | + assert downstream.showanswer == 'finished' |
| 231 | + assert downstream.submission_wait_seconds == 0 |
| 232 | + assert downstream.weight is None |
| 233 | + |
| 234 | + # Upstream updates |
| 235 | + libs.set_library_block_olx(self.upstream_problem_key, ( |
| 236 | + '<problem' |
| 237 | + ' attempts_before_showanswer_button="10"' |
| 238 | + ' display_name="Upstream Problem Title V3"' |
| 239 | + ' due="2024-02-02T00:00:00Z"' |
| 240 | + ' force_save_button="false"' |
| 241 | + ' graceperiod=""' |
| 242 | + ' grading_method="final_attempt"' |
| 243 | + ' matlab_api_key="def"' |
| 244 | + ' max_attempts="11"' |
| 245 | + ' rerandomize=""per_student""' |
| 246 | + ' show_correctness="past_due"' |
| 247 | + ' show_reset_button="false"' |
| 248 | + ' showanswer="attempted"' |
| 249 | + ' submission_wait_seconds="11"' |
| 250 | + ' use_latex_compiler="true"' |
| 251 | + ' weight="2"' |
| 252 | + '/>\n' |
| 253 | + )) |
| 254 | + libs.publish_changes(self.library.key, self.user.id) |
| 255 | + |
| 256 | + # Modifing downstream-only fields are "safe" customizations |
| 257 | + downstream.display_name = "Downstream Title Override" |
| 258 | + downstream.attempts_before_showanswer_button = 2 |
| 259 | + downstream.due = datetime.datetime(2025, 2, 2, tzinfo=utc) |
| 260 | + downstream.force_save_button = True |
| 261 | + downstream.graceperiod = '2d' |
| 262 | + downstream.grading_method = 'last_score' |
| 263 | + downstream.max_attempts = 100 |
| 264 | + downstream.show_correctness = 'always' |
| 265 | + downstream.show_reset_button = True |
| 266 | + downstream.showanswer = 'on_expired' |
| 267 | + downstream.submission_wait_seconds = 100 |
| 268 | + downstream.weight = 3 |
| 269 | + |
| 270 | + # Modifying synchronized fields are "unsafe" customizations |
| 271 | + downstream.rerandomize = '"onreset"' |
| 272 | + downstream.matlab_api_key = 'hij' |
| 273 | + downstream.save() |
| 274 | + |
| 275 | + # Follow-up sync. |
| 276 | + sync_from_upstream(downstream, self.user) |
| 277 | + |
| 278 | + # "unsafe" customizations are overridden by upstream |
| 279 | + assert downstream.upstream_display_name == "Upstream Problem Title V3" |
| 280 | + assert downstream.rerandomize == '"per_student"' |
| 281 | + assert downstream.matlab_api_key == 'def' |
| 282 | + assert downstream.use_latex_compiler |
| 283 | + |
| 284 | + # but "safe" customizations survive |
| 285 | + assert downstream.display_name == "Downstream Title Override" |
| 286 | + assert downstream.attempts_before_showanswer_button == 2 |
| 287 | + assert downstream.due == datetime.datetime(2025, 2, 2, tzinfo=utc) |
| 288 | + assert downstream.force_save_button |
| 289 | + assert downstream.graceperiod == '2d' |
| 290 | + assert downstream.grading_method == 'last_score' |
| 291 | + assert downstream.max_attempts == 100 |
| 292 | + assert downstream.show_correctness == 'always' |
| 293 | + assert downstream.show_reset_button |
| 294 | + assert downstream.showanswer == 'on_expired' |
| 295 | + assert downstream.submission_wait_seconds == 100 |
| 296 | + assert downstream.weight == 3 |
| 297 | + |
182 | 298 | def test_sync_updates_to_modified_content(self):
|
183 | 299 | """
|
184 | 300 | If we sync to modified content, will it preserve customizable fields, but overwrite the rest?
|
|
0 commit comments