252 lines
9.0 KiB
Ruby
252 lines
9.0 KiB
Ruby
#
|
|
# Copyright (C) 2012 - present Instructure, Inc.
|
|
#
|
|
# This file is part of Canvas.
|
|
#
|
|
# Canvas is free software: you can redistribute it and/or modify it under
|
|
# the terms of the GNU Affero General Public License as published by the Free
|
|
# Software Foundation, version 3 of the License.
|
|
#
|
|
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License along
|
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
|
require_relative '../sharding_spec_helper'
|
|
|
|
describe AssignmentOverrideStudent do
|
|
describe "validations" do
|
|
before :once do
|
|
student_in_course
|
|
@override = assignment_override_model(:course => @course)
|
|
@override_student = @override.assignment_override_students.build
|
|
@override_student.user = @student
|
|
end
|
|
|
|
it "should be valid in nominal setup" do
|
|
expect(@override_student).to be_valid
|
|
end
|
|
|
|
it "should always make assignment match the overridden assignment" do
|
|
assignment = assignment_model
|
|
@override_student.assignment = assignment
|
|
expect(@override_student).to be_valid
|
|
expect(@override_student.assignment).to eq @override.assignment
|
|
end
|
|
|
|
it "should reject an empty assignment_override" do
|
|
@override_student.assignment_override = nil
|
|
expect(@override_student).not_to be_valid
|
|
end
|
|
|
|
it "should reject a non-adhoc assignment_override" do
|
|
@override_student.assignment_override.set = @course.default_section
|
|
expect(@override_student).not_to be_valid
|
|
end
|
|
|
|
it "should reject an empty user" do
|
|
@override_student.user = nil
|
|
expect(@override_student).not_to be_valid
|
|
end
|
|
|
|
it "should reject a student not in the course" do
|
|
@override_student.user = user_model
|
|
expect(@override_student).not_to be_valid
|
|
end
|
|
|
|
it "should reject duplicate tuples" do
|
|
@override_student.save!
|
|
@override_student2 = @override.assignment_override_students.build
|
|
@override_student2.user = @student
|
|
expect(@override_student2).not_to be_valid
|
|
end
|
|
end
|
|
|
|
describe 'recalculation of cached due dates' do
|
|
before(:once) do
|
|
course = Course.create!
|
|
@student = User.create!
|
|
course.enroll_student(@student, active_all: true)
|
|
@assignment = course.assignments.create!
|
|
@assignment_override = @assignment.assignment_overrides.create!
|
|
end
|
|
|
|
it 'on creation, recalculates cached due dates on the assignment' do
|
|
expect(DueDateCacher).to receive(:recompute_users_for_course).with(@student.id, @assignment.context, [@assignment]).once
|
|
@assignment_override.assignment_override_students.create!(user: @student)
|
|
end
|
|
|
|
it 'on destroy, recalculates cached due dates on the assignment' do
|
|
override_student = @assignment_override.assignment_override_students.create!(user: @student)
|
|
|
|
# Expect DueDateCacher to be called once from AssignmentOverrideStudent after it's destroyed and another time
|
|
# after it realizes that its corresponding AssignmentOverride can also be destroyed because it now has an empty
|
|
# set of students. Hence the specific nature of this expectation.
|
|
expect(DueDateCacher).to receive(:recompute_users_for_course).with(@student.id, @assignment.context, [@assignment]).once
|
|
expect(DueDateCacher).to receive(:recompute).with(@assignment).once
|
|
override_student.destroy
|
|
end
|
|
end
|
|
|
|
describe "cross sharded users" do
|
|
specs_require_sharding
|
|
it "should work outside of the users native account" do
|
|
course_with_student(account: @account, active_all: true, user: @student)
|
|
@shard1.activate do
|
|
account = Account.create!
|
|
course = account.courses.create!
|
|
e2 = course.enroll_student(@student)
|
|
e2.update_attribute(:workflow_state, 'active')
|
|
override = assignment_override_model(:course => course)
|
|
override_student = override.assignment_override_students.build
|
|
override_student.user = @student
|
|
expect(override_student).to be_valid
|
|
end
|
|
end
|
|
end
|
|
|
|
it "should maintain assignment from assignment_override" do
|
|
student_in_course
|
|
@override1 = assignment_override_model(:course => @course)
|
|
@override2 = assignment_override_model(:course => @course)
|
|
expect(@override1.assignment_id).not_to eq @override2.assignment_id
|
|
|
|
@override_student = @override1.assignment_override_students.build
|
|
@override_student.user = @student
|
|
@override_student.valid? # trigger maintenance
|
|
expect(@override_student.assignment_id).to eq @override1.assignment_id
|
|
@override_student.assignment_override = @override2
|
|
@override_student.valid? # trigger maintenance
|
|
expect(@override_student.assignment_id).to eq @override2.assignment_id
|
|
end
|
|
|
|
def adhoc_override_with_student
|
|
student_in_course(:active_all => true)
|
|
@assignment = assignment_model(:course => @course)
|
|
@ao = AssignmentOverride.new()
|
|
@ao.assignment = @assignment
|
|
@ao.title = "ADHOC OVERRIDE"
|
|
@ao.workflow_state = "active"
|
|
@ao.set_type = "ADHOC"
|
|
@ao.save!
|
|
@override_student = @ao.assignment_override_students.build
|
|
@override_student.user = @user
|
|
@override_student.save!
|
|
end
|
|
|
|
it "should call destroy its override if its the only student and is deleted" do
|
|
adhoc_override_with_student
|
|
|
|
expect(@ao).to be_active
|
|
@override_student.destroy
|
|
expect(@ao.reload).to be_deleted
|
|
end
|
|
|
|
describe "clean_up_for_assignment" do
|
|
it "if callbacks aren't run clean_up_for_assignment should delete invalid overrides" do
|
|
adhoc_override_with_student
|
|
Score.where(enrollment_id: @user.enrollments).each(&:destroy_permanently!)
|
|
@user.enrollments.each(&:destroy_permanently!)
|
|
|
|
expect(@override_student).to be_active
|
|
expect(@ao).to be_active
|
|
AssignmentOverrideStudent.clean_up_for_assignment(@assignment)
|
|
|
|
expect(@override_student.reload).to be_deleted
|
|
expect(@ao.reload).to be_deleted
|
|
end
|
|
|
|
it "should delete overrides for inactive users" do
|
|
adhoc_override_with_student
|
|
@user.enrollments.each(&:deactivate)
|
|
|
|
expect(@override_student).to be_active
|
|
AssignmentOverrideStudent.clean_up_for_assignment(@assignment)
|
|
expect(@override_student.reload).to be_deleted
|
|
end
|
|
|
|
it "should delete overrides for conclude/completed users" do
|
|
adhoc_override_with_student
|
|
@user.enrollments.each(&:conclude)
|
|
|
|
expect(@override_student).to be_active
|
|
AssignmentOverrideStudent.clean_up_for_assignment(@assignment)
|
|
expect(@override_student.reload).to be_deleted
|
|
end
|
|
|
|
it "should not broadcast notifications when processing a cleanup" do
|
|
Timecop.freeze(1.day.ago) do
|
|
adhoc_override_with_student
|
|
end
|
|
Enrollment.where(:id => @enrollment).update_all(:workflow_state => "deleted") # skip callbacks
|
|
|
|
notification_name = "Assignment Due Date Override Changed"
|
|
@notification = Notification.create! :name => notification_name, :category => "TestImmediately"
|
|
teacher_in_course(active_all: true)
|
|
notification_policy_model
|
|
|
|
expect(DelayedNotification).to_not receive(:process)
|
|
AssignmentOverrideStudent.clean_up_for_assignment(@assignment)
|
|
expect(@ao.reload).to be_deleted
|
|
end
|
|
|
|
it "trying to update an orphaned override student (one without an enrollment) removes it" do
|
|
adhoc_override_with_student
|
|
Score.where(enrollment_id: @user.enrollments).each(&:destroy_permanently!)
|
|
@user.enrollments.each(&:destroy_permanently!)
|
|
|
|
# using update instead of touch in order to trigger validations
|
|
expect { AssignmentOverrideStudent.find(@override_student.id).update(updated_at: Time.zone.now) }.to change {
|
|
AssignmentOverrideStudent.where(id: @override_student.id).active.count
|
|
}.from(1).to(0)
|
|
end
|
|
end
|
|
|
|
describe "default_values" do
|
|
let(:override_student) { AssignmentOverrideStudent.new }
|
|
let(:override) { AssignmentOverride.new }
|
|
let(:quiz_id) { 1 }
|
|
let(:assignment_id) { 2 }
|
|
|
|
before do
|
|
override_student.assignment_override = override
|
|
end
|
|
|
|
context "when the override has an assignment" do
|
|
before do
|
|
override.assignment_id = assignment_id
|
|
override_student.send(:default_values)
|
|
end
|
|
|
|
it "has the assignment's ID" do
|
|
expect(override_student.assignment_id).to eq assignment_id
|
|
end
|
|
|
|
it "has a nil quiz ID" do
|
|
expect(override_student.quiz_id).to be_nil
|
|
end
|
|
end
|
|
|
|
context "when the override has a quiz and assignment" do
|
|
before do
|
|
override.assignment_id = assignment_id
|
|
override.quiz_id = quiz_id
|
|
override_student.send(:default_values)
|
|
end
|
|
|
|
it "has the assignment's ID" do
|
|
expect(override_student.assignment_id).to eq assignment_id
|
|
end
|
|
|
|
it "has the quiz's ID" do
|
|
expect(override_student.quiz_id).to eq quiz_id
|
|
end
|
|
end
|
|
end
|
|
end
|