canvas-lms/spec
Evan Battaglia dc0e7b50e8 Fix crash in course copy with LTI module items
The problem:
ContextModule#add_item is called when creating a new module item
(including through the UI, not during course copy), or during course
copy, including updating an existing module item. During course copy to
a course where the module item already exists, such as a blueprint
course sync, the code in add_item() previously tried to overwrite the
existing associated_asset and create a new Lti::ResourceLink with the
same lookup_uuid. Because a Lti::ResourceLink already exists with that
lookup_uuid, the validation would fail. This would cause two things:
* In add_item(), when saving the added_item with the invalid
  associated_asset, the added_item's `associated_item_type` would be set
  to "Lti::ResourceLink", but the `associated_item_id` would be set to
  nil. Regardless, the added_item was being successfully saved without
  error.
* Because we used `context.lti_resource_links.new(...)`, the invalid
  Lti::ResourceLink would be in `context.lti_resource_links`. Much later
  in the code, in `course_content_importer.rb`, on this line:
    course.save! if course.changed?
  `course.save!` would throw an error (crash the import) because one of
  the course's lti_resource_links was invalid.

The solution:
* Use existing Lti::ResourceLinks if one exists with the lookup_uuid,
  instead of trying to create a duplicate.
* If the module item already has a resource link (associated_asset) we
  don't bother changing it since a module item can never have its
  resource link changed anywhere else in the code.
* If for some reason the Lti::ResourceLink is invalid (which it
  shouldn't be now), use `migration.add_issue` instead of crashing the
  whole import where we do the `course.save!`.

This commit also removes duplicative code in lti_resource_link_importer,
and DRYs up code there and in ContextModule#add_item by creating a new
Lti::ResourceLink.find_or_initialize_for_context_and_lookup_uuid method.

flag=none
closes INTEROP-7036

Test plan:
* It's sometimes tricky to trigger the actual crash, which happens when
  there are changes to the actual course to be saved, so it's best when
  testing to add some debugging write before the
  "course.save! if course.changed?" line in
  app/models/importers/course_content_importer.rb (line 192), like this:
    puts "DEBUG-TEMP: changed=#{course.changed?} valid=#{course.valid?}"
  In all runs, course.valid? should be true even if it the course has
  not changed.
* Run a jobs container
* Create a course with one or two module items that are an LTI tool. You
  can put some custom parameters in there (when making the item with deep
  linking) if you like.
* Make the course a blueprint course and add an associated/child course
  that will be the destination course when syncing
* Change the module item (you can just edit it and change the name) at
  least twice and sync changes (in the upper right click the blueprint
  icon). To attempt to trigger the actual crash, try editing the
  blueprint's course settings and changing the navigation (making items
  hidden or shown again), and when running the sync, choose "Include
  course settings". After each change, from a rails console, check the
  following:
    * the destination course's module items (stored as ContentTags in the
      database) should have an association_asset with that is an
      Lti::ResourceLink with the same lookup_uuid as the source course's
      (but the resource links' context will be the destination course) (
    * also check that the name change(s) you made gets updated in the
      destination courses' module item(s).
    * check the debugging you added ("DEBUG-TEMP") that the course is
      valid every time
* Modify one of the destination course's modules item by setting its
  associated_asset_id to null. This simulates the state of module items
  in the DB due to the bug. Run a blueprint sync and make sure the
  associated_asset_id gets fixed to what it was before (the existing
  Lti::ResourceLink)
* Modify the custom parameters of a resource link (may have to do this
  in a rails console) in the blueprint course and run a sync. Check
  that the custom parameters in the resource link of the destination
  course (for that lookup_uuid) have also been updated.
* Add a new module item in the blueprint course, but before you sync,
  modify the call to
  Lti::ResourceLink.find_or_initialize_for_context_and_lookup_uuid in
  context_module.rb to have it send in a nil context_external_tool.
  Restart the jobs container and run a sync. The sync should not
  crash. (A warning like 'The External Tool resource
  link (including any possible custom parameters) could not be set
  for module item "%{title}"' should be made on the migration, but
  migration warnings appear to not be shown in the UI anywhere for
  blueprint course syncs.)

Change-Id: I9bc946e935653796bb19bb23ad2deb62df3986df
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/273602
QA-Review: Mysti Lilla <mysti@instructure.com>
Product-Review: Evan Battaglia <ebattaglia@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Mysti Lilla <mysti@instructure.com>
2021-09-20 18:31:02 +00:00
..
apis ensure sync button appears after initial blueprint sync fails 2021-09-16 22:40:34 +00:00
coffeescripts Fix course title not showing on home front page 2021-09-09 14:12:35 +00:00
contracts Prevent creating LE Kinesis client from hanging 2021-08-23 22:19:44 +00:00
controllers Detect k5 better for trusts/consortiums 2021-09-17 21:43:49 +00:00
factories Add pace plan controller actions 2021-08-30 16:53:44 +00:00
factory_bot add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
fixtures ignore BOM for csv imports 2021-09-14 03:05:20 +00:00
formatters remove code for the old TestQueue 2021-07-29 14:15:14 +00:00
gem_integration/canvas_connect add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
graphql use ID for context_id 2021-09-10 22:12:40 +00:00
helpers Hide notification message for k5 students 2021-09-09 16:00:58 +00:00
initializers update activerecord-pg-extensions 2021-09-10 19:55:20 +00:00
instfs/selenium Remove course image feature flag 2021-08-03 21:07:41 +00:00
integration add ability to run rspecq A/B testing; refs DE-822 2021-09-10 18:48:15 +00:00
javascripts Gradebook frozen props fix 2021-09-16 19:44:46 +00:00
lib Fix crash in course copy with LTI module items 2021-09-20 18:31:02 +00:00
manual_seeding add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
messages move broadcast_policy to mention object 2021-05-18 20:34:43 +00:00
migrations clear account sms overrides 2021-08-31 19:12:00 +00:00
models Fix crash in course copy with LTI module items 2021-09-20 18:31:02 +00:00
observers Add OutcomeFriendlyDescription live events to Canvas 2021-08-30 15:48:59 +00:00
presenters Initial pace plans import 2021-09-01 19:58:33 +00:00
requests Fix url to speedgrader guide 2021-04-02 14:28:09 +00:00
schemas/lti add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
selenium add teacher and student groups selenium 2021-09-17 19:00:51 +00:00
serializers use a separate manage_assignments_edit flag when ff is on 2021-09-08 20:58:12 +00:00
shared_examples disallow reassigning assignments after lock date 2021-07-27 17:53:00 +00:00
support spec: use have_received for statsd increment tests 2021-09-13 17:05:49 +00:00
views show status menu for assignments with due date 2021-09-15 19:36:21 +00:00
.eslintrc Update eslint to v7 2021-05-20 18:28:51 +00:00
.rspec_parallel use parallel_tests for more parallelization 2020-03-30 21:38:47 +00:00
ams_spec_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
axe_selenium_helper.rb Replace canvas-axe-selenium with stormbreaker 2021-06-23 20:19:51 +00:00
broadcast_integration.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
cassandra_spec_helper.rb move database_builder to canvas_cassandra 2021-02-25 15:19:20 +00:00
conditional_release_spec_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
coverage_tool.rb remove docker_processes from core rspec and selenium test runs 2021-05-12 19:47:12 +00:00
factories.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
factory_bot_spec_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
feature_flag_helper.rb features are never enabled on dummy courses or accounts 2021-05-26 16:00:03 +00:00
file_upload_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
force_failure_spec.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
import_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
jspec.sh
lti2_course_spec_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
lti2_spec_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
lti_1_3_spec_helper.rb Add launch url redirect to sessionless launch 2021-09-13 19:23:14 +00:00
lti_1_3_tool_configuration_spec_helper.rb Add launch url redirect to sessionless launch 2021-09-13 19:23:14 +00:00
lti_spec_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
plagiarism_platform_spec_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
quiz_spec_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
rcov.opts
rspec_mock_extensions.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
sharding_spec_helper.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
simple_cov_result_merger.rb add # frozen_string_literal: true for specs 2020-10-27 20:48:35 +00:00
spec.opts remove abort_on_consistent_badness_formatter 2020-10-13 18:10:04 +00:00
spec_helper.rb bump inst-jobs 2021-09-11 00:15:46 +00:00