Update DueDateCacher to use EffectiveDueDates

fixes CNVS-33651

Test plan:
* Create a course
* Enroll 3 students
* Create 2 assignments with different due dates
* In rails console:
	* Submission.pluck(:assignment_id, :cached_due_date) should return
	  an array of 6 tuples of (assignment id, its due date)
* Create an override for one student on one assignment
* In rails console:
  * Submission.where(
  		assignment_id: <assignment picked above>,
  		user_id: <user picked above>
  	).cached_due_date should equal the override date
* Smoke test grading and viewing students in different places to make
  sure the new dummy submissions aren't breaking anything

Change-Id: Idc2721fd3f05214555db780b452ddf53e67ff404
Reviewed-on: https://gerrit.instructure.com/109027
Tested-by: Jenkins
Reviewed-by: Keith T. Garner <kgarner@instructure.com>
QA-Review: Anju Reddy <areddy@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
This commit is contained in:
Neil Gupta 2017-04-18 22:09:10 -05:00
parent 5ff873c6da
commit 1e052eae19
58 changed files with 384 additions and 494 deletions

View File

@ -201,7 +201,7 @@ class SubmissionsApiController < ApplicationController
@current_user, section_ids)
.pluck(:user_id)
end
submissions = @assignment.submissions.where(user_id: student_ids).preload(:originality_reports)
submissions = @assignment.submissions.not_placeholder.where(user_id: student_ids).preload(:originality_reports)
if includes.include?("visibility")
json = bulk_process_submissions_for_visibility(submissions, includes)
@ -368,7 +368,7 @@ class SubmissionsApiController < ApplicationController
"assignments.workflow_state != 'deleted'"
)
end
submissions = submissions_scope.preload(:originality_reports).to_a
submissions = submissions_scope.not_placeholder.preload(:originality_reports).to_a
bulk_load_attachments_and_previews(submissions)
submissions_for_user = submissions.group_by(&:user_id)
@ -417,7 +417,7 @@ class SubmissionsApiController < ApplicationController
order_by = params[:order] == "graded_at" ? "graded_at" : :id
order_direction = params[:order_direction] == "descending" ? "desc nulls last" : "asc"
order = "#{order_by} #{order_direction}"
submissions = @context.submissions.except(:order).where(:user_id => student_ids).order(order)
submissions = @context.submissions.not_placeholder.except(:order).where(user_id: student_ids).order(order)
submissions = submissions.where(:assignment_id => assignments) unless assignments.empty?
submissions = submissions.preload(:user, :originality_reports)
@ -610,8 +610,7 @@ class SubmissionsApiController < ApplicationController
@user = get_user_considering_section(params[:user_id])
authorized = false
@submission = @assignment.submissions.where(user_id: @user).first ||
@assignment.submissions.build(user: @user)
@submission = @assignment.submissions.find_or_create_by!(user: @user)
if params[:submission] || params[:rubric_assessment]
authorized = authorized_action(@submission, @current_user, :grade)
@ -732,7 +731,7 @@ class SubmissionsApiController < ApplicationController
students = Api.paginate(student_scope, self, api_v1_course_assignment_gradeable_students_url(@context, @assignment))
if (include_pg = includes.include?('provisional_grades'))
return unless authorized_action(@context, @current_user, :moderate_grades)
submissions = @assignment.submissions.where(user_id: students).preload(:provisional_grades).index_by(&:user_id)
submissions = @assignment.submissions.not_placeholder.where(user_id: students).preload(:provisional_grades).index_by(&:user_id)
selections = @assignment.moderated_grading_selections.where(student_id: students).index_by(&:student_id)
end
render :json => students.map { |student|
@ -908,7 +907,7 @@ class SubmissionsApiController < ApplicationController
def change_topic_read_state(new_state)
@assignment = @context.assignments.active.find(params[:assignment_id])
@user = get_user_considering_section(params[:user_id])
@submission = @assignment.submissions.where(user_id: @user).first || @assignment.submissions.build(user: @user)
@submission = @assignment.submissions.find_or_create_by!(user: @user)
render_state_change_result @submission.change_read_state(new_state, @current_user)
end

View File

@ -392,9 +392,18 @@ class Assignment < ActiveRecord::Base
grading_period = GradingPeriod.for_date_in_course(date: due_at, course: context)
return true if grading_period_was&.id == grading_period&.id
[grading_period_was, grading_period].compact.each do |gp|
context.recompute_student_scores(grading_period_id: gp)
if grading_period_was
# recalculate just the old grading period's score
context.recompute_student_scores(grading_period_id: grading_period_was, update_course_score: false)
end
# recalculate the new grading period's score. If the grading period group is
# weighted, then we need to recalculate the overall course score too. (If
# grading period is nil, make sure we pass true for `update_course_score`
# so we can use a singleton job.)
context.recompute_student_scores(
grading_period_id: grading_period,
update_course_score: !grading_period || grading_period.grading_period_group&.weighted?
)
true
end
private :update_grading_period_grades

View File

@ -102,9 +102,19 @@ class AssignmentOverride < ActiveRecord::Base
students = applies_to_students.map(&:id)
return true if students.blank?
[grading_period_was, grading_period].compact.each do |gp|
course.recompute_student_scores(students, grading_period_id: gp)
if grading_period_was
# recalculate just the old grading period's score
course.recompute_student_scores(students, grading_period_id: grading_period_was, update_course_score: false)
end
# recalculate the new grading period's score. If the grading period group is
# weighted, then we need to recalculate the overall course score too. (If
# grading period is nil, make sure we pass true for `update_course_score`
# so we can use a singleton job.)
course.recompute_student_scores(
students,
grading_period_id: grading_period,
update_course_score: !grading_period || grading_period.grading_period_group&.weighted?
)
true
end
private :update_grading_period_grades

View File

@ -1046,9 +1046,11 @@ class Course < ActiveRecord::Base
end
end
def recompute_student_scores(student_ids = nil, grading_period_id: nil, update_all_grading_period_scores: true)
def recompute_student_scores(student_ids = nil, grading_period_id: nil,
update_all_grading_period_scores: true,
update_course_score: true)
inst_job_opts = {}
if student_ids.blank? && grading_period_id.nil? && update_all_grading_period_scores
if student_ids.blank? && grading_period_id.nil? && update_all_grading_period_scores && update_course_score
# if we have all default args, let's queue this job in a singleton to avoid duplicates
inst_job_opts[:singleton] = "recompute_student_scores:#{global_id}"
end

View File

@ -68,6 +68,7 @@ class EnrollmentTerm < ActiveRecord::Base
def recompute_course_scores(update_all_grading_period_scores: true)
courses.active.each do |course|
course.recompute_student_scores(update_all_grading_period_scores: update_all_grading_period_scores)
DueDateCacher.recompute_course(course)
end
end

View File

@ -242,6 +242,7 @@ class GradingPeriod < ActiveRecord::Base
gp_id = time_boundaries_changed? ? id : nil
if course_group?
recompute_score_for(grading_period_group.course, gp_id)
DueDateCacher.recompute_course(grading_period_group.course) if gp_id
else
self.send_later_if_production(:recompute_scores_for_term_courses, gp_id) # there could be a lot of courses here
end

View File

@ -27,6 +27,7 @@ class GradingPeriodGroup < ActiveRecord::Base
validate :associated_with_course_or_root_account, if: :active?
after_save :recompute_course_scores, if: :weighted_changed?
after_save :recache_grading_period, if: :course_id_changed?
after_destroy :dissociate_enrollment_terms
set_policy do
@ -75,6 +76,11 @@ class GradingPeriodGroup < ActiveRecord::Base
enrollment_terms.each { |term| term.recompute_course_scores(update_all_grading_period_scores: false) }
end
def recache_grading_period
DueDateCacher.recompute_course(course) if course
DueDateCacher.recompute_course(course_id_was) if course_id_was
end
def associated_with_course_or_root_account
if course_id.blank? && account_id.blank?
errors.add(:course_id, t("cannot be nil when account_id is nil"))

View File

@ -58,6 +58,7 @@ class Submission < ActiveRecord::Base
belongs_to :assignment
belongs_to :user
belongs_to :grader, :class_name => 'User'
belongs_to :grading_period
belongs_to :group
belongs_to :media_object
belongs_to :student, :class_name => 'User', :foreign_key => :user_id
@ -400,20 +401,14 @@ class Submission < ActiveRecord::Base
else
Rails.logger.info "GRADES: submission #{global_id} score changed. recomputing grade for course #{context.global_id} user #{user_id}."
self.class.connection.after_transaction_commit do
effective_due_dates = EffectiveDueDates.new(self.context, self.assignment_id)
grading_period_id = effective_due_dates.grading_period_id_for(
student_id: self.user_id,
assignment_id: self.assignment_id
)
Enrollment.recompute_final_score_in_singleton(
self.user_id,
self.context.id,
grading_period_id: grading_period_id,
update_all_grading_period_scores: false
grading_period_id: grading_period_id
)
end
end
self.assignment.send_later_if_production(:multiple_module_actions, [self.user_id], :scored, self.score) if self.assignment
self.assignment&.send_later_if_production(:multiple_module_actions, [self.user_id], :scored, self.score)
end
true
end
@ -1089,8 +1084,9 @@ class Submission < ActiveRecord::Base
end
self.accepted_at = nil unless late_policy_status == 'late'
self.submitted_at ||= Time.now if self.has_submission? || (self.submission_type && !self.submission_type.empty?)
self.submitted_at ||= Time.now if self.has_submission?
self.quiz_submission.reload if self.quiz_submission_id
self.workflow_state = 'submitted' if self.unsubmitted? && self.submitted_at
self.workflow_state = 'unsubmitted' if self.submitted? && !self.has_submission?
self.workflow_state = 'graded' if self.grade && self.score && self.grade_matches_current_submission
self.workflow_state = 'pending_review' if self.submission_type == 'online_quiz' && self.quiz_submission.try(:latest_submitted_attempt).try(:pending_review?)
@ -1229,6 +1225,8 @@ class Submission < ActiveRecord::Base
student_id = user_id || self.user.try(:id)
# TODO: replace this check with `grading_period&.closed?` once
# the populate_grading_period_for_submissions data fixup finishes
if assignment.in_closed_grading_period_for_student?(student_id)
:assignment_in_closed_grading_period
else
@ -1257,6 +1255,8 @@ class Submission < ActiveRecord::Base
student_id = self.user_id || self.user.try(:id)
# TODO: replace this check with `grading_period&.closed?` once
# the populate_grading_period_for_submissions data fixup finishes
if assignment.in_closed_grading_period_for_student?(student_id)
:assignment_in_closed_grading_period
else
@ -1483,7 +1483,7 @@ class Submission < ActiveRecord::Base
unless submission_type
self.submission_type ||= "online_url" if self.url
self.submission_type ||= "online_text_entry" if self.body
self.submission_type ||= "online_upload" if !self.attachments.empty?
self.submission_type ||= "online_upload" unless self.attachment_ids.blank?
end
true
end
@ -1506,6 +1506,9 @@ class Submission < ActiveRecord::Base
scope :having_submission, -> { where("submissions.submission_type IS NOT NULL") }
scope :without_submission, -> { where(submission_type: nil, workflow_state: "unsubmitted") }
scope :not_placeholder, -> {
where("submissions.submission_type IS NOT NULL or submissions.excused or submissions.score IS NOT NULL")
}
scope :include_user, -> { preload(:user) }

View File

@ -19,7 +19,10 @@ class InitializeSubmissionCachedDueDate < ActiveRecord::Migration[4.2]
tag :postdeploy
def self.up
DataFixup::InitializeSubmissionCachedDueDate.send_later_if_production(:run)
DataFixup::InitializeSubmissionCachedDueDate.send_later_if_production_enqueue_args(
:run,
singleton: "DataFixup:InitializeSubmissionCachedDueDate:#{Shard.current.id}"
)
end
def self.down

View File

@ -19,6 +19,9 @@ class PopulateOverriddenDueAtForDueDateCacher < ActiveRecord::Migration[4.2]
tag :postdeploy
def self.up
DataFixup::PopulateOverriddenDueAtForDueDateCacher.send_later_if_production(:run)
DataFixup::InitializeSubmissionCachedDueDate.send_later_if_production_enqueue_args(
:run,
singleton: "DataFixup:InitializeSubmissionCachedDueDate:#{Shard.current.id}"
)
end
end

View File

@ -0,0 +1,8 @@
class AddGradingPeriodToSubmissions < ActiveRecord::Migration[4.2]
tag :predeploy
def change
add_column :submissions, :grading_period_id, :integer, limit: 8
add_foreign_key :submissions, :grading_periods
end
end

View File

@ -0,0 +1,10 @@
class PopulateGradingPeriodForSubmissions < ActiveRecord::Migration[4.2]
tag :postdeploy
def self.up
DataFixup::InitializeSubmissionCachedDueDate.send_later_if_production_enqueue_args(
:run,
singleton: "DataFixup:InitializeSubmissionCachedDueDate:#{Shard.current.id}"
)
end
end

View File

@ -17,8 +17,10 @@
module DataFixup::InitializeSubmissionCachedDueDate
def self.run
Assignment.find_ids_in_ranges do |min, max|
DueDateCacher.recompute_batch(min.to_i..max.to_i)
Course.find_in_batches do |courses|
courses.each do |course|
DueDateCacher.recompute_course(course, nil, priority: Delayed::LOWER_PRIORITY)
end
end
end
end

View File

@ -1,35 +0,0 @@
#
# Copyright (C) 2011 - 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/>.
#
module DataFixup::PopulateOverriddenDueAtForDueDateCacher
def self.run
Shackles.activate(:slave) do
overrides = AssignmentOverride.active
.overriding_due_at
.select("DISTINCT assignment_id")
.order(:assignment_id)
overrides.find_in_batches do |batch|
assignment_ids = batch.map(&:assignment_id)
Shackles.activate(:master) do
DueDateCacher.recompute_batch(assignment_ids)
end
end
end
end
end

View File

@ -17,144 +17,74 @@
class DueDateCacher
def self.recompute(assignment)
new([assignment]).send_later_if_production_enqueue_args(
:recompute,
singleton: "cached_due_date:calculator:Assignment:#{assignment.global_id}"
)
recompute_course(assignment.context, [assignment.id],
singleton: "cached_due_date:calculator:Assignment:#{assignment.global_id}")
end
def self.recompute_course(course, assignments = nil)
assignments ||= Assignment.where(context_id: course, context_type: 'Course').pluck(:id)
def self.recompute_course(course, assignments = nil, inst_jobs_opts = {})
course = Course.find(course) unless course.is_a?(Course)
inst_jobs_opts[:singleton] ||= "cached_due_date:calculator:Course:#{course.global_id}" if assignments.nil?
assignments ||= Assignment.where(context: course).pluck(:id)
return if assignments.empty?
new(assignments).send_later_if_production_enqueue_args(:recompute,
:strand => "cached_due_date:calculator:Course:#{Shard.global_id_for(course)}")
new(course, assignments).send_later_if_production_enqueue_args(:recompute, inst_jobs_opts)
end
def self.recompute_batch(assignments)
new(assignments).send_later_if_production_enqueue_args(:recompute,
:strand => "cached_due_date:calculator:batch:#{Shard.current.id}",
:priority => Delayed::LOWER_PRIORITY)
end
# expects all assignments to be on the same shard
def initialize(assignments)
def initialize(course, assignments)
@course = course
@assignments = assignments
@shard = Shard.shard_for(assignments.first)
end
def shard
@shard
def recompute
# in a transaction on the correct shard:
@course.shard.activate do
Assignment.transaction do
# Create dummy submissions for caching due date
create_missing_submissions
# Update each submission with user's calculated due date and grading period
queries = effective_due_dates.map do |assignment_id, students|
students.map do |student_id, submission_info|
due_date = submission_info[:due_at] ? "'#{submission_info[:due_at].iso8601}'::timestamptz" : 'NULL'
"UPDATE #{Submission.quoted_table_name} SET
cached_due_date = #{due_date},
grading_period_id = #{submission_info[:grading_period_id] || 'NULL'}
WHERE user_id = #{student_id} AND assignment_id = #{assignment_id};"
end
end.flatten
Assignment.connection.execute(queries.join("\n")) unless queries.empty?
end
end
end
def submissions
Submission.where(:assignment_id => @assignments)
private
def effective_due_dates
@effective_due_dates ||= EffectiveDueDates.for_course(@course, @assignments).to_hash
end
def create_overridden_submissions
# Get the students that have an overridden due date
overridden_students = Assignment.participants_with_overridden_due_at(@assignments)
return if overridden_students.length < 1
def student_ids
@students ||= effective_due_dates.map { |_, assignment| assignment.keys }.flatten.uniq
end
# Get default submission values.
default_submission = Submission.new
default_submission.infer_values
def create_missing_submissions
return if student_ids.empty?
# Create insert scope
insert_scope = Course
.select("DISTINCT assignments.id, enrollments.user_id, '#{default_submission.workflow_state}',
now() AT TIME ZONE 'UTC', assignments.context_code, 0")
.select("DISTINCT assignments.id, enrollments.user_id, 'unsubmitted',
now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC', assignments.context_code, 0")
.joins("INNER JOIN #{Assignment.quoted_table_name} ON assignments.context_id = courses.id
AND assignments.context_type = 'Course'
LEFT OUTER JOIN #{Submission.quoted_table_name} ON submissions.user_id = enrollments.user_id
AND submissions.assignment_id = assignments.id")
.joins(:current_enrollments)
.where("enrollments.user_id IN (?) AND assignments.id IN (?) AND submissions.id IS NULL", overridden_students, @assignments)
.where("courses.id = ? AND enrollments.user_id IN (?) AND assignments.id IN (?) AND submissions.id IS NULL",
@course.id, student_ids, @assignments)
# Create submissions that do not exist yet to calculate due dates for non submitted assignments.
Assignment.connection.update("INSERT INTO #{Submission.quoted_table_name} (assignment_id,
user_id, workflow_state, created_at, context_code,
user_id, workflow_state, created_at, updated_at, context_code,
process_attempts) #{insert_scope.to_sql}")
end
def recompute
# in a transaction on the correct shard:
shard.activate do
Assignment.transaction do
# Create overridden due date submissions
create_overridden_submissions
overrides = AssignmentOverride.active.overriding_due_at.where(:assignment_id => @assignments)
if overrides.exists?
# create temporary table
Assignment.connection.execute("CREATE TEMPORARY TABLE calculated_due_ats AS (#{submissions.select([
"submissions.id AS submission_id",
"submissions.user_id",
"submissions.assignment_id",
"assignments.due_at",
"CAST(#{Submission.sanitize(false)} AS BOOL) AS overridden"
]).joins(:assignment).where(assignments: { id: @assignments }).to_sql})")
# for each override, narrow to the affected subset of the table, and
# apply
overrides.each do |override|
override_scope(Submission.from("calculated_due_ats"), override).update_all(
:due_at => override.due_at,
:overridden => true)
end
# copy the results back to the submission table
submissions.
joins("INNER JOIN calculated_due_ats ON calculated_due_ats.submission_id=submissions.id").
where("cached_due_date<>calculated_due_ats.due_at OR (cached_due_date IS NULL)<>(calculated_due_ats.due_at IS NULL)").
update_all("cached_due_date=calculated_due_ats.due_at")
# clean up
Assignment.connection.execute("DROP TABLE calculated_due_ats")
else
# just copy the assignment due dates to the submissions
submissions.
joins(:assignment).
where("cached_due_date<>assignments.due_at OR (cached_due_date IS NULL)<>(assignments.due_at IS NULL)").
update_all("cached_due_date=assignments.due_at")
end
end
end
end
def override_scope(scope, override)
scope = scope.where(calculated_due_ats: { assignment_id: override.assignment_id })
# and the override's due_at is more lenient than any existing overridden
# due_at
if override.due_at
scope = scope.where(
"NOT overridden OR (due_at IS NOT NULL AND due_at<?)",
override.due_at)
end
case override.set_type
when 'ADHOC'
# any student explicitly tagged by an adhoc override,
scope.joins("INNER JOIN #{AssignmentOverrideStudent.quoted_table_name} ON assignment_override_students.user_id=calculated_due_ats.user_id").
where(:assignment_override_students => {
:assignment_override_id => override
})
when 'CourseSection'
# any student in a section override's tagged section, or
scope.joins("INNER JOIN #{Enrollment.quoted_table_name} ON enrollments.user_id=calculated_due_ats.user_id").
where(:enrollments => {
:workflow_state => 'active',
:type => ['StudentEnrollment', 'StudentViewEnrollment'],
:course_section_id => override.set_id
})
when 'Group'
# any student in a group override's tagged group
scope.joins("INNER JOIN #{GroupMembership.quoted_table_name} ON group_memberships.user_id=calculated_due_ats.user_id").
where(:group_memberships => {
:workflow_state => 'accepted',
:group_id => override.set_id
})
when 'Noop'
scope.none
end
end
end

View File

@ -43,7 +43,7 @@ class EffectiveDueDates
hsh[assignment_id] ||= {}
attributes = {}
if include?(included, :due_at)
attributes[:due_at] = row["due_at"] && Time.zone.parse(row["due_at"])
attributes[:due_at] = row["due_at"] && Time.parse(row["due_at"])
end
if include?(included, :grading_period_id)
attributes[:grading_period_id] = row["grading_period_id"] && row["grading_period_id"].to_i

View File

@ -1345,7 +1345,7 @@ describe DiscussionTopicsController, type: :request do
@topic.save
student_in_course(:active_all => true)
expect(@user.submissions).to be_empty
expect(@user.submissions.not_placeholder).to be_empty
json = api_call(
:post, "/api/v1/courses/#{@course.id}/discussion_topics/#{@topic.id}/entries.json",
@ -1354,8 +1354,8 @@ describe DiscussionTopicsController, type: :request do
{:message => @message})
@user.reload
expect(@user.submissions.size).to eq 1
expect(@user.submissions.first.submission_type).to eq 'discussion_topic'
expect(@user.submissions.not_placeholder.size).to eq 1
expect(@user.submissions.not_placeholder.first.submission_type).to eq 'discussion_topic'
end
it "should create a submission from a reply on a graded topic" do
@ -1365,7 +1365,7 @@ describe DiscussionTopicsController, type: :request do
@topic.save
student_in_course(:active_all => true)
expect(@user.submissions).to be_empty
expect(@user.submissions.not_placeholder).to be_empty
json = api_call(
:post, "/api/v1/courses/#{@course.id}/discussion_topics/#{@topic.id}/entries/#{top_entry.id}/replies.json",
@ -1374,8 +1374,8 @@ describe DiscussionTopicsController, type: :request do
{:message => @message})
@user.reload
expect(@user.submissions.size).to eq 1
expect(@user.submissions.first.submission_type).to eq 'discussion_topic'
expect(@user.submissions.not_placeholder.size).to eq 1
expect(@user.submissions.not_placeholder.first.submission_type).to eq 'discussion_topic'
end
end

View File

@ -55,8 +55,8 @@ describe 'Submissions API', type: :request do
:format => 'json', :course_id => @course.id.to_s,
:assignment_id => @assignment.id.to_s, :user_id => student.id.to_s },
{ :include => %w(submission_history submission_comments rubric_assessment) })
expect(json.delete('id')).to eq nil
expect(json).to eq({
"id" => @assignment.submissions.find_by!(user: student).id,
"assignment_id" => @assignment.id,
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{@assignment.id}/submissions/#{student.id}?preview=1&version=0",
"user_id"=>student.id,
@ -72,7 +72,7 @@ describe 'Submissions API', type: :request do
"submission_comments"=>[],
"grade_matches_current_submission"=>nil,
"score"=>nil,
"workflow_state"=>nil,
"workflow_state"=>"unsubmitted",
"late"=>false,
"graded_at"=>nil,
})
@ -698,7 +698,7 @@ describe 'Submissions API', type: :request do
"body"=>"test!",
"assignment_id" => a1.id,
"submitted_at"=>"1970-01-01T01:00:00Z",
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=2",
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=1",
"grade_matches_current_submission"=>true,
"attempt"=>1,
"url"=>nil,
@ -799,7 +799,7 @@ describe 'Submissions API', type: :request do
mock_kaltura.expects(:media_sources).returns([{:height => "240", :bitrate => "382", :isOriginal => "0", :width => "336", :content_type => "video/mp4",
:containerFormat => "isom", :url => "https://kaltura.example.com/some/url", :size =>"204", :fileExt=>"mp4"}])
submit_homework(a1, student1, :media_comment_id => "54321", :media_comment_type => "video")
submit_homework(a1, student1, submission_type: 'online_text_entry', media_comment_id: 54321, media_comment_type: "video")
stub_kaltura
json = api_call(:get,
"/api/v1/courses/#{@course.id}/assignments/#{a1.id}/submissions.json",
@ -866,7 +866,7 @@ describe 'Submissions API', type: :request do
"body"=>"test!",
"assignment_id" => a1.id,
"submitted_at"=>"1970-01-01T03:00:00Z",
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=4",
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=3",
"grade_matches_current_submission"=>true,
"attachments" =>
[
@ -904,7 +904,7 @@ describe 'Submissions API', type: :request do
"url"=>nil,
"submission_type"=>"online_text_entry",
"user_id"=>student1.id,
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=2",
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=1",
"grade_matches_current_submission"=>nil,
"score"=>nil,
"workflow_state" => "submitted",
@ -927,7 +927,7 @@ describe 'Submissions API', type: :request do
"url"=>nil,
"submission_type"=>"online_text_entry",
"user_id"=>student1.id,
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=3",
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=2",
"grade_matches_current_submission"=>nil,
"score"=>nil,
"workflow_state" => "submitted",
@ -972,7 +972,7 @@ describe 'Submissions API', type: :request do
"url"=>nil,
"submission_type"=>"online_text_entry",
"user_id"=>student1.id,
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=4",
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student1.id}?preview=1&version=3",
"grade_matches_current_submission"=>true,
"score"=>13.5,
"workflow_state" => "graded",
@ -1016,7 +1016,7 @@ describe 'Submissions API', type: :request do
"graded_at"=>sub2.graded_at.as_json,
"assignment_id" => a1.id,
"body"=>nil,
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student2.id}?preview=1&version=2",
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student2.id}?preview=1&version=1",
"grade_matches_current_submission"=>true,
"submitted_at"=>"1970-01-01T04:00:00Z",
"submission_history"=>
@ -1032,7 +1032,7 @@ describe 'Submissions API', type: :request do
"url"=>"http://www.instructure.com",
"submission_type"=>"online_url",
"user_id"=>student2.id,
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student2.id}?preview=1&version=2",
"preview_url" => "http://www.example.com/courses/#{@course.id}/assignments/#{a1.id}/submissions/#{student2.id}?preview=1&version=1",
"grade_matches_current_submission"=>true,
"attachments" =>
[
@ -2815,6 +2815,7 @@ describe 'Submissions API', type: :request do
@enrollment.update_attribute(:limit_privileges_to_course_section, true)
@teacher = @user
s1 = submission_model(:course => @course)
s1.update!(submission_type: 'online_text_entry')
section2 = @course.course_sections.create(:name => "another section")
s2 = submission_model(:course => @course, :username => 'otherstudent@example.com', :section => section2, :assignment => @assignment)
@user = @teacher
@ -3324,7 +3325,7 @@ describe 'Submissions API', type: :request do
progress = Progress.find(json["id"])
expect(progress.completed?).to be_truthy
expect(Submission.count).to eq 1
expect(Submission.not_placeholder.count).to eq 1
s1 = student3.submissions.first
expect(s1.grade).to eq "75%"
end
@ -3395,7 +3396,7 @@ describe 'Submissions API', type: :request do
progress = Progress.find(json["id"])
expect(progress.completed?).to be_truthy
expect(Submission.count).to eq 1
expect(Submission.not_placeholder.count).to eq 1
s1 = @student1.submissions.first
expect(s1.grade).to eq "75%"
end
@ -3709,7 +3710,7 @@ describe 'Submissions API', type: :request do
group.add_user(student1)
group.add_user(student2)
end
let!(:submit_homework) { assignment.submit_homework(student1) }
let!(:submit_homework) { assignment.submit_homework(student1, submission_type: 'online_text_entry') }
let(:path) { "/api/v1/courses/#{test_course.id}/assignments/#{assignment.id}/submissions" }
let(:params) do

View File

@ -99,14 +99,14 @@ describe DiscussionEntriesController do
assignment_model(:course => @course)
@topic.assignment = @assignment
@topic.save
expect(@student.submissions).to be_empty
expect(@student.submissions.not_placeholder).to be_empty
post 'create', :course_id => @course.id, :discussion_entry => {:discussion_topic_id => @topic.id, :message => "yo"}
expect(response).to be_redirect
@student.reload
expect(@student.submissions.size).to eq 1
expect(@student.submissions.first.submission_type).to eq 'discussion_topic'
expect(@student.submissions.not_placeholder.size).to eq 1
expect(@student.submissions.not_placeholder.first.submission_type).to eq 'discussion_topic'
end
end

View File

@ -262,7 +262,7 @@ XML
expect(response.content_type).to eq 'application/xml'
xml = Nokogiri::XML.parse(response.body)
expect(xml.at_css('imsx_POXEnvelopeResponse > imsx_POXHeader > imsx_POXResponseHeaderInfo > imsx_statusInfo > imsx_codeMajor').content).to eq failure_type
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
desc = xml.at_css('imsx_description').content.match(/(?<description>.+)\n\[EID_(?<error_report>[^\]]+)\]/)
expect(desc[:description]).to eq error_message if error_message
expect(desc[:error_report]).to_not be_empty
@ -287,7 +287,7 @@ XML
end
it "should allow updating the submission score" do
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
make_call('body' => replace_result(score: '0.6'))
check_success
@ -350,7 +350,7 @@ XML
expect(xml.at_css('imsx_codeMajor').content).to eq 'failure'
expect(xml.at_css('imsx_description').content).to match /^No score given/
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
end
it "should fail if bad score given" do
@ -360,7 +360,7 @@ XML
expect(xml.at_css('imsx_codeMajor').content).to eq 'failure'
expect(xml.at_css('imsx_description').content).to match /^Score is not between 0 and 1/
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
end
it "should fail if assignment has no points possible" do
@ -401,7 +401,7 @@ to because the assignment has no points possible.
end
it "should reject out of bound scores" do
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
make_call('body' => replace_result(score: '-1'))
check_failure('failure')
make_call('body' => replace_result(score: '1.1'))
@ -421,7 +421,7 @@ to because the assignment has no points possible.
end
it "should reject non-numeric scores" do
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
make_call('body' => replace_result(score: "OHAI SCORES"))
check_failure('failure')
end
@ -494,7 +494,7 @@ to because the assignment has no points possible.
end
it "should reject non-numeric scores" do
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
make_call('body' => replace_result(raw_score: "OHAI SCORES"))
check_failure('failure')
end
@ -690,13 +690,13 @@ to because the assignment has no points possible.
expect(response.content_type).to eq 'application/xml'
xml = Nokogiri::XML.parse(response.body)
expect(xml.at_css('message_response > statusinfo > codemajor').content).to eq failure_type
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
xml
end
describe "basic-lis-updateresult" do
it "should allow updating the submission score" do
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
make_call('body' => update_result('0.6'))
xml = check_success
@ -710,7 +710,7 @@ to because the assignment has no points possible.
end
it "should reject out of bound scores" do
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
make_call('body' => update_result('-1'))
check_failure('Failure')
make_call('body' => update_result('1.1'))
@ -730,7 +730,7 @@ to because the assignment has no points possible.
end
it "should reject non-numeric scores" do
expect(@assignment.submissions.where(user_id: @student)).not_to be_exists
expect(@assignment.submissions.not_placeholder.where(user_id: @student)).not_to be_exists
make_call('body' => update_result("OHAI SCORES"))
check_failure('Failure')
end

View File

@ -43,6 +43,7 @@ describe Submissions::SubmissionForShow do
describe '#submission' do
it 'instantiates a new submission when one is not present' do
Submission.delete_all
expect(subject.submission).to be_new_record
end

View File

@ -122,7 +122,7 @@ module Factories
submission_count = opts[:submissions] || 1
submission_count.times do |s|
assignment = @course.assignments.create!(:title => "test #{s} assignment")
submission = assignment.submissions.create!(:assignment_id => assignment.id, :user_id => @student.id)
submission = assignment.submissions.find_by!(user: @student)
submission.update_attributes!(score: '5') if opts[:submission_points]
end
end

View File

@ -30,9 +30,10 @@ module Factories
# just create the object, we don't care about callbacks or usual side effects
def bare_submission_model(assignment, user, opts = {})
opts = (opts.presence || {submission_type: "online_text_entry", body: "o hai"}).merge(user: user, workflow_state: "submitted")
opts = (opts.presence || {submission_type: "online_text_entry", body: "o hai"}).merge(workflow_state: "submitted")
submitted_at = opts.delete(:submitted_at)
submission = assignment.submissions.build(opts)
submission = assignment.submissions.find_by!(user: user)
submission.attributes = opts
submission.submitted_at = submitted_at if submitted_at
submission.save_without_callbacks
submission

View File

@ -34,7 +34,7 @@ describe AssignmentsHelper do
end
it "is false if the assignment already has submissions" do
@assignment.submissions.create!(user_id: @student, submission_type: 'online_url')
@assignment.submissions.find_by!(user_id: @student).update!(submission_type: 'online_url')
expect(assignment_publishing_enabled?(@assignment, @teacher)).to be_falsey
end

View File

@ -20,6 +20,7 @@ require_relative '../../config/initializers/consul'
describe ConsulInitializer do
after(:each) do
Canvas::DynamicSettings.config = nil
Canvas::DynamicSettings.reset_cache!
Canvas::DynamicSettings.fallback_data = nil
end

View File

@ -139,7 +139,6 @@ describe "download submissions link" do
end
it "should not show download submissions button with no submissions" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_success
doc = Nokogiri::XML(response.body)
@ -147,10 +146,10 @@ describe "download submissions link" do
end
it "should show download submissions button with submission not graded" do
@submission = Submission.new(:assignment => @assignment, :user => @student, :submission_type => 'online_url')
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update(submission_type: 'online_url')
expect(@submission.state).to eql(:submitted)
@submission.save!
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_success
doc = Nokogiri::XML(response.body)
@ -158,14 +157,15 @@ describe "download submissions link" do
end
it "should show download submissions button with a submission graded" do
@submission = Submission.new(:assignment => @assignment, :user => @student, :submission_type => 'online_url')
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
@submission.grade_it
@submission.score = 5
@submission.save!
expect(@submission.state).to eql(:graded)
@submission2 = Submission.new(:assignment => @assignment, :user => @student2, :submission_type => 'online_url')
@submission2.save!
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_success
doc = Nokogiri::XML(response.body)
@ -173,17 +173,19 @@ describe "download submissions link" do
end
it "should show download submissions button with all submissions graded" do
@submission = Submission.new(:assignment => @assignment, :user => @student, :submission_type => 'online_url')
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
@submission.grade_it
@submission.score = 5
@submission.save!
expect(@submission.state).to eql(:graded)
@submission2 = Submission.new(:assignment => @assignment, :user => @student2, :submission_type => 'online_url')
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
@submission2.grade_it
@submission2.score = 5
@submission2.save!
expect(@submission2.state).to eql(:graded)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_success
doc = Nokogiri::XML(response.body)
@ -191,10 +193,9 @@ describe "download submissions link" do
end
it "should not show download submissions button to students" do
@submission = Submission.new(:assignment => @assignment, :user => @student, :submission_type => 'online_url')
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
expect(@submission.state).to eql(:submitted)
@submission.save!
user_session(@student)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_success
@ -232,13 +233,13 @@ describe "ratio of submissions graded" do
end
it "should show ratio of submissions graded with submission not graded" do
@submission = Submission.new(:assignment => @assignment, :user => @student, :submission_type => 'online_url')
@submission.save!
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
expect(@submission.state).to eql(:submitted)
@submission2 = Submission.new(:assignment => @assignment, :user => @student2, :submission_type => 'online_url')
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
expect(@submission2.state).to eql(:submitted)
@submission2.save!
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_success
doc = Nokogiri::XML(response.body)
@ -246,15 +247,15 @@ describe "ratio of submissions graded" do
end
it "should show ratio of submissions graded with a submission graded" do
@submission = Submission.new(:assignment => @assignment, :user => @student, :submission_type => 'online_url')
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
@submission.grade_it
@submission.score = 5
@submission.save!
expect(@submission.state).to eql(:graded)
@submission2 = Submission.new(:assignment => @assignment, :user => @student2, :submission_type => 'online_url')
expect(@submission2.state).to eql(:submitted)
@submission2.save!
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_success
doc = Nokogiri::XML(response.body)
@ -262,18 +263,19 @@ describe "ratio of submissions graded" do
end
it "should show ratio of submissions graded with all submissions graded" do
@submission = Submission.new(:assignment => @assignment, :user => @student, :submission_type => 'online_url')
@submission.grade_it
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
@submission.grade_it
@submission.score = 5
@submission.save!
expect(@submission.state).to eql(:graded)
@submission2 = Submission.new(:assignment => @assignment, :user => @student2, :submission_type => 'online_url')
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
@submission2.grade_it
@submission2.score = 5
@submission2.save!
expect(@submission2.state).to eql(:graded)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_success
doc = Nokogiri::XML(response.body)
@ -281,10 +283,10 @@ describe "ratio of submissions graded" do
end
it "should not show ratio of submissions graded to students" do
@submission = Submission.new(:assignment => @assignment, :user => @student, :submission_type => 'online_url')
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
expect(@submission.state).to eql(:submitted)
@submission.save!
user_session(@student)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_success

View File

@ -276,7 +276,7 @@ describe BasicLTI::BasicOutcomes do
it "creates a new submissions if there isn't one" do
xml.css('resultData').remove
expect{BasicLTI::BasicOutcomes.process_request(tool, xml)}.
to change{assignment.submissions.where(user_id: @user.id).count}.from(0).to(1)
to change{assignment.submissions.not_placeholder.where(user_id: @user.id).count}.from(0).to(1)
end
it 'creates a new submission of type "external_tool" when a grade is passed back without a submission' do

View File

@ -215,7 +215,7 @@ describe Canvas::LiveEvents do
submission.grader = @teacher
submission.grade = '10'
submission.score = 10
Canvas::LiveEvents.grade_changed(submission, submission.versions.current.model)
Canvas::LiveEvents.grade_changed(submission)
end
it "should include the user_id and assignment_id" do

View File

@ -31,7 +31,7 @@ describe DueDateCacher do
end
it "should wrap assignment in an array" do
@new_expectation.with([@assignment])
@new_expectation.with(@course, [@assignment.id])
DueDateCacher.recompute(@assignment)
end
@ -56,12 +56,12 @@ describe DueDateCacher do
end
it "should pass along the whole array" do
@new_expectation.with(@assignments)
@new_expectation.with(@course, @assignments)
DueDateCacher.recompute_course(@course, @assignments)
end
it "should default to all assignments in the context" do
@new_expectation.with { |assignment_ids| assignment_ids.sort == @assignments.map(&:id).sort }
@new_expectation.with { |course, assignment_ids| course.id == @course.id && assignment_ids.sort == @assignments.map(&:id).sort }
DueDateCacher.recompute_course(@course)
end
@ -70,80 +70,75 @@ describe DueDateCacher do
DueDateCacher.recompute_course(@course, @assignments)
end
it "should queue a delayed job on a context-specific strand in production" do
it "should queue a delayed job in a singleton in production if assignments.nil" do
@instance.expects(:send_later_if_production_enqueue_args).
with(:recompute, :strand => "cached_due_date:calculator:Course:#{@course.global_id}")
with(:recompute, singleton: "cached_due_date:calculator:Course:#{@course.global_id}")
DueDateCacher.recompute_course(@course)
end
it "should queue a delayed job without a singleton if assignments is passed" do
@instance.expects(:send_later_if_production_enqueue_args).with(:recompute, {})
DueDateCacher.recompute_course(@course, @assignments)
end
it "should operate on a course id" do
@instance.expects(:send_later_if_production_enqueue_args).
with(:recompute, :strand => "cached_due_date:calculator:Course:#{@course.global_id}")
@new_expectation.with { |assignment_ids| assignment_ids.sort == @assignments.map(&:id).sort }
with(:recompute, singleton: "cached_due_date:calculator:Course:#{@course.global_id}")
@new_expectation.with { |course, assignment_ids| course.id == @course.id && assignment_ids.sort == @assignments.map(&:id).sort }
DueDateCacher.recompute_course(@course.id)
end
end
describe ".recompute_batch" do
before do
@assignments = [@assignment]
@assignments << assignment_model(:course => @course)
@instance = stub('instance', :recompute => nil)
@new_expectation = DueDateCacher.expects(:new).returns(@instance)
end
it "should pass along the whole array" do
@new_expectation.with(@assignments)
DueDateCacher.recompute_batch(@assignments)
end
it "should delegate to an instance" do
@instance.expects(:recompute)
DueDateCacher.recompute_batch(@assignments)
end
it "should queue a delayed job on a batch-specific singleton strand in production" do
@instance.expects(:send_later_if_production_enqueue_args).
with(:recompute, :strand => "cached_due_date:calculator:batch:#{Shard.current.id}",
:priority => Delayed::LOWER_PRIORITY)
DueDateCacher.recompute_batch(@assignments)
end
end
describe "#submissions" do
it "should not create submissions for enrollments that are not overridden" do
cacher = DueDateCacher.new([@assignment])
expect(cacher.submissions.size).to eql(0)
end
it "should create submissions for enrollments that are overridden" do
assignment_override_model(
:assignment => @assignment,
:set => @course.default_section)
@override.override_due_at(@assignment.due_at + 1.day)
@override.save!
cacher = DueDateCacher.new([@assignment])
expect(cacher.submissions.size).to eql(1)
expect(cacher.submissions.first.assignment).to eq @assignment
expect(cacher.submissions.first.user).to eq @student
end
end
describe "#recompute" do
before do
@cacher = DueDateCacher.new([@assignment])
@cacher = DueDateCacher.new(@course, [@assignment])
submission_model(:assignment => @assignment, :user => @student)
Submission.update_all(:cached_due_date => nil)
end
context 'without existing submissions' do
it "should create submissions for enrollments that are not overridden" do
Submission.destroy_all
expect { @cacher.recompute }.to change {
Submission.where(assignment_id: @assignment.id).count
}.from(0).to(1)
end
it "should create submissions for enrollments that are overridden" do
assignment_override_model(assignment: @assignment, set: @course.default_section)
@override.override_due_at(@assignment.due_at + 1.day)
@override.save!
Submission.destroy_all
expect { @cacher.recompute }.to change {
Submission.where(assignment_id: @assignment.id).count
}.from(0).to(1)
end
end
it "should not create another submission for enrollments that have a submission" do
expect { @cacher.recompute }.not_to change {
Submission.where(assignment_id: @assignment.id).count
}
end
it "should not create another submission for enrollments that have a submission, even with an overridden" do
assignment_override_model(assignment: @assignment, set: @course.default_section)
@override.override_due_at(@assignment.due_at + 1.day)
@override.save!
expect { @cacher.recompute }.not_to change {
Submission.where(assignment_id: @assignment.id).count
}
end
context "no overrides" do
it "should set the cached_due_date to the assignment due_at" do
@assignment.due_at += 1.day
@assignment.save!
@cacher.recompute
expect(@submission.reload.cached_due_date).to eq @assignment.due_at
expect(@submission.reload.cached_due_date).to eq @assignment.due_at.change(sec: 0)
end
it "should set the cached_due_date to nil if the assignment has no due_at" do
@ -167,7 +162,7 @@ describe DueDateCacher do
@override.save!
@cacher.recompute
expect(@submission.reload.cached_due_date).to eq @override.due_at
expect(@submission.reload.cached_due_date).to eq @override.due_at.change(sec: 0)
end
it "should prefer override's due_at over assignment's nil" do
@ -178,7 +173,7 @@ describe DueDateCacher do
@assignment.save!
@cacher.recompute
expect(@submission.reload.cached_due_date).to eq @override.due_at
expect(@submission.reload.cached_due_date).to eq @override.due_at.change(sec: 0)
end
it "should prefer override's nil over assignment's due_at" do
@ -194,7 +189,7 @@ describe DueDateCacher do
@override.save!
@cacher.recompute
expect(@submission.reload.cached_due_date).to eq @assignment.due_at
expect(@submission.reload.cached_due_date).to eq @assignment.due_at.change(sec: 0)
end
end
@ -217,11 +212,11 @@ describe DueDateCacher do
end
it "should apply to students in the adhoc set" do
expect(@submission2.reload.cached_due_date).to eq @override.due_at
expect(@submission2.reload.cached_due_date).to eq @override.due_at.change(sec: 0)
end
it "should not apply to students not in the adhoc set" do
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at.change(sec: 0)
end
end
@ -246,11 +241,11 @@ describe DueDateCacher do
end
it "should apply to students in that section" do
expect(@submission2.reload.cached_due_date).to eq @override.due_at
expect(@submission2.reload.cached_due_date).to eq @override.due_at.change(sec: 0)
end
it "should not apply to students in other sections" do
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at.change(sec: 0)
end
it "should not apply to non-active enrollments in that section" do
@ -258,7 +253,7 @@ describe DueDateCacher do
:enrollment_state => 'deleted',
:section => @course_section,
:allow_multiple_enrollments => true)
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at.change(sec: 0)
end
end
@ -290,23 +285,16 @@ describe DueDateCacher do
end
it "should apply to students in that group" do
expect(@submission2.reload.cached_due_date).to eq @override.due_at
expect(@submission2.reload.cached_due_date).to eq @override.due_at.change(sec: 0)
end
it "should not apply to students not in the group" do
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at.change(sec: 0)
end
it "should not apply to non-active memberships in that group" do
@group.add_user(@student1, 'deleted')
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at
end
end
context "noop override" do
it "should apply to absolutely no one" do
assignment_override_model(assignment: assignment_model, set_type: 'Noop', set_id: 1, title: 'Tag 1')
expect(@cacher.override_scope(Submission.all, @override)).to be_a ActiveRecord::NullRelation
expect(@submission1.reload.cached_due_date).to eq @assignment.due_at.change(sec: 0)
end
end
@ -331,7 +319,7 @@ describe DueDateCacher do
@override1.save!
@cacher.recompute
expect(@submission.reload.cached_due_date).to eq @override1.due_at
expect(@submission.reload.cached_due_date).to eq @override1.due_at.change(sec: 0)
end
it "should prefer second override's due_at if latest" do
@ -339,7 +327,7 @@ describe DueDateCacher do
@override2.save!
@cacher.recompute
expect(@submission.reload.cached_due_date).to eq @override2.due_at
expect(@submission.reload.cached_due_date).to eq @override2.due_at.change(sec: 0)
end
it "should be nil if first override's nil" do
@ -391,7 +379,7 @@ describe DueDateCacher do
@override1.save!
@cacher.recompute
expect(@submission1.reload.cached_due_date).to eq @override1.due_at
expect(@submission1.reload.cached_due_date).to eq @override1.due_at.change(sec: 0)
end
it "should use second override where the first doesn't apply" do
@ -399,7 +387,7 @@ describe DueDateCacher do
@override2.save!
@cacher.recompute
expect(@submission2.reload.cached_due_date).to eq @override2.due_at
expect(@submission2.reload.cached_due_date).to eq @override2.due_at.change(sec: 0)
end
it "should use the best override where both apply" do
@ -407,7 +395,7 @@ describe DueDateCacher do
@override1.save!
@cacher.recompute
expect(@submission2.reload.cached_due_date).to eq @override2.due_at
expect(@submission2.reload.cached_due_date).to eq @override2.due_at.change(sec: 0)
end
end
@ -425,15 +413,15 @@ describe DueDateCacher do
@submission2 = submission_model(:assignment => @assignment2, :user => @student)
Submission.update_all(:cached_due_date => nil)
DueDateCacher.new([@assignment1, @assignment2]).recompute
DueDateCacher.new(@course, [@assignment1, @assignment2]).recompute
end
it "should apply to submission on the overridden assignment" do
expect(@submission1.reload.cached_due_date).to eq @override.due_at
expect(@submission1.reload.cached_due_date).to eq @override.due_at.change(sec: 0)
end
it "should not apply to apply to submission on the other assignment" do
expect(@submission2.reload.cached_due_date).to eq @assignment.due_at
expect(@submission2.reload.cached_due_date).to eq @assignment.due_at.change(sec: 0)
end
end
end

View File

@ -54,6 +54,16 @@ describe Course do
@assignment_in_other_course = @other_course.assignments.create!
end
it 'properly converts timezones' do
Time.zone = 'Alaska'
default_due = DateTime.parse("01 Jan 2011 14:00 AKST")
@assignment4 = @test_course.assignments.create!(title: "some assignment", due_at: default_due, submission_types: ['online_text_entry'])
edd = EffectiveDueDates.for_course(@test_course, @assignment4)
result = edd.to_hash
expect(result[@assignment4.id][@student1.id][:due_at]).to eq default_due
end
it 'returns the effective due dates per assignment per student' do
edd = EffectiveDueDates.for_course(@test_course)
result = edd.to_hash
@ -551,7 +561,10 @@ describe Course do
end
it 'includes not-assigned students with existing graded submissions' do
@assignment1.submissions.create!(user: @student1, submission_type: 'online_text_entry', workflow_state: 'graded')
@assignment1.submissions.find_by!(user: @student1).update!(
submission_type: 'online_text_entry',
workflow_state: 'graded'
)
edd = EffectiveDueDates.for_course(@test_course, @assignment1)
result = edd.to_hash
@ -572,7 +585,7 @@ describe Course do
it 'uses assigned date instead of submission date even if submission was late' do
override = @assignment1.assignment_overrides.create!(due_at: 3.days.from_now(@now), due_at_overridden: true)
override.assignment_override_students.create!(user: @student1)
@assignment1.submissions.find_by(user: @student1).update!(
@assignment1.submissions.find_by!(user: @student1).update!(
submitted_at: 1.week.from_now(@now),
submission_type: 'online_text_entry',
workflow_state: 'graded'
@ -634,7 +647,7 @@ describe Course do
it 'prioritizes the override due date even if it is earlier than the Everyone Else date and the student has a graded submission that does not qualify' do
override = @assignment2.assignment_overrides.create!(due_at: 3.days.ago(@now), due_at_overridden: true)
override.assignment_override_students.create!(user: @student1)
@assignment2.submissions.find_by(user: @student1).update!(
@assignment2.submissions.find_by!(user: @student1).update!(
submitted_at: 1.week.from_now(@now),
submission_type: 'online_text_entry',
workflow_state: 'graded'
@ -675,8 +688,7 @@ describe Course do
it 'prioritizes the Everyone Else due date if it exists over the submission NULL date' do
@assignment2.due_at = 4.days.from_now(@now)
@assignment2.save!
@assignment2.submissions.create!(
user: @student1,
@assignment2.submissions.find_by!(user: @student1).update!(
submitted_at: 1.week.from_now(@now),
submission_type: 'online_text_entry',
workflow_state: 'graded'
@ -713,7 +725,10 @@ describe Course do
end
it 'ignores not-assigned students with ungraded submissions' do
@assignment1.submissions.create!(user: @student1, submission_type: 'online_text_entry', workflow_state: 'submitted')
@assignment1.submissions.find_by!(user: @student1).update!(
submission_type: 'online_text_entry',
workflow_state: 'submitted'
)
edd = EffectiveDueDates.for_course(@test_course, @assignment1)
expect(edd.to_hash).to eq({})
@ -1344,8 +1359,7 @@ describe Course do
end_date: 15.days.ago(@now),
close_date: 10.days.ago(@now)
})
@assignment1.submissions.create!(
user: @student1,
@assignment1.submissions.find_by!(user: @student1).update!(
submitted_at: 1.week.from_now(@now),
submission_type: 'online_text_entry',
workflow_state: 'graded'

View File

@ -108,7 +108,7 @@ describe GradeCalculator do
@group = @course.assignment_groups.create!(name: "some group", group_weight: 100)
@assignment = @course.assignments.create!(title: "Some Assignment", points_possible: 10, assignment_group: @group)
@assignment2 = @course.assignments.create!(title: "Some Assignment2", points_possible: 10, assignment_group: @group)
@submission = @assignment2.submissions.create!(user: @user)
@submission = @assignment2.submissions.find_by!(user: @user)
end
@submission.update_column(:score, 5)
@ -137,8 +137,8 @@ describe GradeCalculator do
@course.assignments.create!(title: "Some Assignment2", due_at: now, points_possible: 10, assignment_group: @group)
@assignment_in_period = @course.assignments.create!(title: 'In a Grading Period', due_at: 2.months.from_now(now), points_possible: 10)
@course.assignments.create!(title: 'In a Grading Period', due_at: 2.months.from_now(now), points_possible: 10)
@submission = @assignment.submissions.create!(user: @user)
@submission_in_period = @assignment_in_period.submissions.create!(user: @user)
@submission = @assignment.submissions.find_by!(user: @user)
@submission_in_period = @assignment_in_period.submissions.find_by!(user: @user)
end
@submission.update_column(:score, 5)

View File

@ -23,7 +23,8 @@ describe 'rubric_assessment_submission_reminder' do
before :once do
user_model
rubric_assessment_model(user: @user)
@submission = @course.assignments.first.submissions.create!(user: @user)
@course.enroll_student(@user)
@submission = @course.assignments.first.submissions.find_by!(user: @user)
@object = @rubric_association.assessment_requests.create!(user: @user,
asset: @submission,
assessor: @user,

View File

@ -1,61 +0,0 @@
#
# Copyright (C) 2013 - 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 'lib/data_fixup/populate_overridden_due_at_for_due_date_cacher.rb'
describe DataFixup::PopulateOverriddenDueAtForDueDateCacher do
before do
course_with_student(:active_all => true)
@assignment1 = assignment_model(:course => @course)
assignment_model(:course => @course)
@section = @course.course_sections.create!
student_in_section(@section, :course => @course)
# Create an override
@due_at = @assignment.due_at - 1.day
assignment_override_model(:assignment => @assignment, :set => @section)
@override.override_due_at(@due_at)
@override.save!
# Delete Submissions simulating current data state.
@assignment.submissions.destroy_all
@assignment1.submissions.destroy_all
end
it "should recompute cached date dues for overridden assignments" do
DueDateCacher.expects(:recompute_batch).once.with([@assignment.id])
DataFixup::PopulateOverriddenDueAtForDueDateCacher.run
end
it "should create submission for overridden assignments" do
DataFixup::PopulateOverriddenDueAtForDueDateCacher.run
@assignment1.reload
expect(@assignment1.submissions.size).to eql(0)
@assignment.reload
expect(@assignment.submissions.size).to eql(1)
@submission = @assignment.submissions.first
expect(@submission.user).to eq @user
expect(@submission.assignment).to eq @assignment
expect(@submission.cached_due_date).to eq @due_at
end
end

View File

@ -30,7 +30,7 @@ describe DataFixup::PopulateSubmissionVersions do
it "should not migrate a submission version already having a submission_version" do
course_with_student
submission = @user.submissions.create(:assignment => @course.assignments.create!)
@course.assignments.create!
expect{
DataFixup::PopulateSubmissionVersions.run
}.not_to change(SubmissionVersion, :count)
@ -39,9 +39,7 @@ describe DataFixup::PopulateSubmissionVersions do
it "should migrate all submission version rows without submission_versions" do
n = 5
course_with_student
submission = @user.submissions.build(:assignment => @course.assignments.create!)
submission.without_versioning{ submission.save! }
expect(submission.versions.exists?).to be_falsey
submission = @user.submissions.find_by(assignment: @course.assignments.create!)
n.times { |x| Version.create(:versionable => submission, :yaml => submission.attributes.to_yaml) }
expect{
DataFixup::PopulateSubmissionVersions.run
@ -50,12 +48,8 @@ describe DataFixup::PopulateSubmissionVersions do
it "should skip submission version rows without a corresponding submission object" do
course_with_student
submission = @user.submissions.build(:assignment => @course.assignments.create!)
submission.without_versioning{ submission.save! }
submission = @user.submissions.find_by(assignment: @course.assignments.create!)
Version.create(:versionable => submission, :yaml => submission.attributes.to_yaml)
submission.reload
expect(submission.versions.exists?).to be_truthy
submission.delete
expect{

View File

@ -221,7 +221,9 @@ describe Assignment::SpeedGrader do
json = Assignment::SpeedGrader.new(assignment, @teacher).json
json[:submissions].each do |submission|
user = [student_1, student_2].detect { |s| s.id.to_s == submission[:user_id] }
expect(submission[:late]).to eq user.submissions.first.late?
if(submission[:workflow_state] == "submitted")
expect(submission[:late]).to eq user.submissions.first.late?
end
end
end

View File

@ -2577,7 +2577,7 @@ describe Assignment do
it "should include re-submitted submissions in the list of submissions needing grading" do
expect(@assignment).to be_published
expect(@assignment.submissions.size).to eq 1
expect(@assignment.submissions.not_placeholder.size).to eq 1
expect(Assignment.need_grading_info.where(id: @assignment).first).to be_nil
@assignment.submit_homework(@stu1, :body => "Changed my mind!")
@sub1.reload
@ -2822,7 +2822,7 @@ describe Assignment do
sub = @a.submit_homework(@u1, :submission_type => "online_text_entry", :body => "Some text for you")
expect(sub.user_id).to eql(@u1.id)
@a.reload
subs = @a.submissions
subs = @a.submissions.not_placeholder
expect(subs.length).to eql(2)
expect(subs.map(&:group_id).uniq).to eql([@group.id])
expect(subs.map(&:submission_type).uniq).to eql(['online_text_entry'])
@ -2833,7 +2833,7 @@ describe Assignment do
@a.update_attribute(:grade_group_students_individually, true)
res = @a.submit_homework(@u1, :submission_type => "online_text_entry", :body => "Test submission")
@a.reload
submissions = @a.submissions
submissions = @a.submissions.not_placeholder
expect(submissions.length).to eql 2
expect(submissions.map(&:group_id).uniq).to eql [@group.id]
expect(submissions.map(&:submission_type).uniq).to eql ["online_text_entry"]
@ -2882,7 +2882,7 @@ describe Assignment do
expect(sub.user_id).to eql(@u1.id)
expect(sub.submission_comments.size).to eql 1
@a.reload
other_sub = (@a.submissions - [sub])[0]
other_sub = (@a.submissions.not_placeholder - [sub])[0]
expect(other_sub.submission_comments.size).to eql 1
end
@ -2919,7 +2919,7 @@ describe Assignment do
context: @u1,
filename: 'blah.txt'
@a.submit_homework(@u1, attachments: [f])
@a.submissions.reload.each { |s|
@a.submissions.reload.not_placeholder.each { |s|
expect(s.attachments).to eq [f]
}
end
@ -4090,7 +4090,7 @@ describe Assignment do
context "when the student is not in a group" do
let!(:associate_student_and_submission) {
assignment.submissions.create user: @student
assignment.submissions.find_by user: @student
}
let(:update_submission_response) { assignment.update_submission(@student) }

View File

@ -362,7 +362,7 @@ describe Course do
end
it 'should be able to i18n without keys' do
Importers::CourseContentImporter.translate('stuff')
expect { Importers::CourseContentImporter.translate('stuff') }.not_to raise_error
end
end

View File

@ -23,7 +23,7 @@ describe ModeratedGrading::ProvisionalGrade do
grade.scorer = scorer
end
end
let(:submission) { assignment.submissions.create!(user: student) }
let(:submission) { assignment.submissions.find_by!(user: student) }
let(:assignment) { course.assignments.create! submission_types: 'online_text_entry' }
let(:account) { a = account_model; a}
let(:course) { c = account.courses.create!; c }

View File

@ -22,21 +22,21 @@ describe Pseudonym do
it "should create a new instance given valid attributes" do
user_model
factory_with_protected_attributes(Pseudonym, valid_pseudonym_attributes)
expect{factory_with_protected_attributes(Pseudonym, valid_pseudonym_attributes)}.to change(Pseudonym, :count).by(1)
end
it "should allow single character usernames" do
user_model
pseudonym_model
@pseudonym.unique_id = 'c'
@pseudonym.save!
expect(@pseudonym.save).to be true
end
it "should allow a username that starts with a special character" do
user_model
pseudonym_model
@pseudonym.unique_id = '+c'
@pseudonym.save!
expect(@pseudonym.save).to be true
end
it "should allow apostrophes in usernames" do

View File

@ -1554,7 +1554,8 @@ describe Quizzes::QuizSubmission do
finished_at: Time.zone.now, user: @user, quiz: quiz, workflow_state: :complete
)
expect(qs.submission.minutes_late).to eq(4)
expected_minutes_late = (Time.zone.now - 60.seconds - 5.minutes.ago.change(sec: 0)) / 60
expect(qs.submission.minutes_late).to eq(expected_minutes_late)
end
end
end

View File

@ -265,13 +265,12 @@ describe SplitUsers do
assignment.workflow_state = "published"
assignment.save
valid_attributes = {
assignment_id: assignment.id,
user_id: user1.id,
grade: "1.5",
grader: @teacher,
url: "www.instructure.com"
}
submission = Submission.create!(valid_attributes)
submission = assignment.submissions.find_by!(user: user1)
submission.update!(valid_attributes)
UserMerge.from(user1).into(user2)
expect(submission.reload.user).to eq user2
@ -286,15 +285,14 @@ describe SplitUsers do
assignment.workflow_state = "published"
assignment.save
valid_attributes = {
assignment_id: assignment.id,
user_id: user1.id,
grade: "1.5",
grader: @teacher,
url: "www.instructure.com"
}
submission1 = Submission.create!(valid_attributes)
valid_attributes[:user_id] = user2.id
submission2 = Submission.create!(valid_attributes)
submission1 = assignment.submissions.find_by!(user: user1)
submission1.update!(valid_attributes)
submission2 = assignment.submissions.find_by!(user: user2)
submission2.update!(valid_attributes)
UserMerge.from(user1).into(user2)
expect(submission1.reload.user).to eq user1

View File

@ -282,8 +282,8 @@ This text has a http://www.google.com link in it...
context 'given a submission with several group comments' do
let!(:assignment) { @course.assignments.create! }
let!(:unrelated_assignment) { @course.assignments.create! }
let!(:submission) { assignment.submissions.create!(user: @user) }
let!(:unrelated_submission) { unrelated_assignment.submissions.create!(user: @user) }
let!(:submission) { assignment.submissions.find_by!(user: @user) }
let!(:unrelated_submission) { unrelated_assignment.submissions.find_by!(user: @user) }
let!(:first_comment) do
submission.submission_comments.create!(
group_comment_id: 'uuid',
@ -327,8 +327,8 @@ This text has a http://www.google.com link in it...
context 'given a submission with several group comments' do
let!(:assignment) { @course.assignments.create! }
let!(:unrelated_assignment) { @course.assignments.create! }
let!(:submission) { assignment.submissions.create!(user: @user) }
let!(:unrelated_submission) { unrelated_assignment.submissions.create!(user: @user) }
let!(:submission) { assignment.submissions.find_by!(user: @user) }
let!(:unrelated_submission) { unrelated_assignment.submissions.find_by!(user: @user) }
let!(:first_comment) do
submission.submission_comments.create!(
group_comment_id: 'uuid',

View File

@ -29,11 +29,12 @@ describe Submission do
@assignment.workflow_state = "published"
@assignment.save
@valid_attributes = {
assignment_id: @assignment.id,
user_id: @user.id,
assignment: @assignment,
user: @user,
grade: "1.5",
grader: @teacher,
url: "www.instructure.com"
url: "www.instructure.com",
workflow_state: "submitted"
}
end
@ -76,7 +77,7 @@ describe Submission do
before(:once) do
@assignment.due_at = in_open_grading_period
@assignment.save!
@submission = Submission.create!(@valid_attributes)
submission_spec_model
end
it "has grade permissions if the user is a root account admin" do
@ -98,7 +99,7 @@ describe Submission do
before(:once) do
@assignment.due_at = outside_of_any_grading_period
@assignment.save!
@submission = Submission.create!(@valid_attributes)
submission_spec_model
end
it "has grade permissions if the user is a root account admin" do
@ -124,7 +125,7 @@ describe Submission do
@now = Time.zone.local(2013, 10, 18)
end
let(:submission) { @assignment.submissions.find_by(user_id: @student) }
let(:submission) { @assignment.submissions.find_by!(user_id: @student) }
it "gets initialized during submission creation" do
# create an invited user, so that the submission is not automatically
@ -138,8 +139,8 @@ describe Submission do
override.override_due_at(Time.zone.now + 1.day)
override.save!
submission = @assignment.submissions.create(:user => @user)
expect(submission.cached_due_date).to eq override.reload.due_at
submission = @assignment.submissions.find_by!(user: @user)
expect(submission.cached_due_date).to eq override.reload.due_at.change(sec: 0)
end
context 'due date changes after student submits' do
@ -352,7 +353,7 @@ describe Submission do
)
override_student = student_override.assignment_override_students.create!(user: @student)
submission = assignment.submissions.find_by(user: @student)
submission = assignment.submissions.find_by!(user: @student)
expect { @student.enrollments.find_by(course_section: section).destroy }.to change {
submission.reload.cached_due_date
}.from(6.minutes.ago(@now)).to(14.minutes.ago(@now))
@ -416,7 +417,7 @@ describe Submission do
@assignment.update!(due_at: 1.hour.ago(@date), submission_types: "online_text_entry")
end
let(:submission) { @assignment.submissions.find_by(user_id: @student) }
let(:submission) { @assignment.submissions.find_by!(user_id: @student) }
it "returns time between submitted_at and cached_due_date" do
Timecop.freeze(@date) do
@ -526,11 +527,11 @@ describe Submission do
include_examples "url validation tests"
it "should check url validity" do
test_url_validation(Submission.create!(@valid_attributes))
test_url_validation(submission_spec_model)
end
it "should add http:// to the body for long urls, too" do
s = Submission.create!(@valid_attributes)
s = submission_spec_model
expect(s.url).to eq 'http://www.instructure.com'
long_url = ("a"*300 + ".com")
@ -1049,7 +1050,7 @@ describe Submission do
describe 'computation of scores' do
before(:once) do
@assignment.update!(points_possible: 10)
@submission = Submission.create!(@valid_attributes)
submission_spec_model
end
let(:scores) do
@ -1720,19 +1721,13 @@ describe Submission do
end
it "should return the correct quiz_submission_version" do
# see redmine #6048
# set up the data to have a submission with a quiz submission with multiple versions
course_factory
quiz = @course.quizzes.create!
quiz_submission = quiz.generate_submission @user, false
quiz_submission.save
submission = Submission.create!({
:assignment_id => @assignment.id,
:user_id => @user.id,
:quiz_submission_id => quiz_submission.id
})
@assignment.submissions.find_by!(user: @user).update!(quiz_submission_id: quiz_submission.id)
submission = @assignment.submit_homework @user, :submission_type => 'online_quiz'
submission.quiz_submission_id = quiz_submission.id
@ -2355,7 +2350,7 @@ describe Submission do
describe "#get_web_snapshot" do
it "should not blow up if web snapshotting fails" do
sub = Submission.new(@valid_attributes)
sub = submission_spec_model
CutyCapt.expects(:enabled?).returns(true)
CutyCapt.expects(:snapshot_attachment_for_url).with(sub.url).returns(nil)
sub.get_web_snapshot
@ -2807,7 +2802,7 @@ describe Submission do
describe '#add_comment' do
before(:once) do
@submission = Submission.create!(@valid_attributes)
submission_spec_model
end
it 'creates a draft comment when passed true in the draft_comment option' do
@ -3068,8 +3063,12 @@ describe Submission do
def submission_spec_model(opts={})
@submission = Submission.new(@valid_attributes.merge(opts))
@submission.save!
opts = @valid_attributes.merge(opts)
assignment = opts.delete(:assignment) || Assignment.find(opts.delete(:assignment_id))
user = opts.delete(:user) || User.find(opts.delete(:user_id))
@submission = assignment.submissions.find_by!(user: user)
@submission.update!(opts)
@submission
end
def setup_account_for_turnitin(account)

View File

@ -22,9 +22,7 @@ describe SubmissionVersion do
def unversioned_submission
# bypass the built-in submission versioning
course_with_student
submission = @user.submissions.build(:assignment => @course.assignments.create!)
submission.without_versioning{ submission.save! }
submission
@user.submissions.find_by(assignment: @course.assignments.create!)
end
before do

View File

@ -170,12 +170,15 @@ describe "assignments" do
assignment_form = f('#submit_online_text_entry_form')
wait_for_tiny(assignment_form)
wait_for_ajaximations
expect {
type_in_tiny('#submission_body', 'something to submit')
body_text = 'something to submit'
expect do
type_in_tiny('#submission_body', body_text)
wait_for_ajaximations
submit_form(assignment_form)
wait_for_ajaximations
}.to change(Submission, :count).by(1)
end.to change {
@assignment.submissions.find_by!(user: @student).body
}.from(nil).to("<p>#{body_text}</p>")
end
end

View File

@ -231,31 +231,32 @@ describe "submissions" do
f('.submit_assignment_link').click
assignment_form = f('#submit_online_text_entry_form')
wait_for_tiny(assignment_form)
submit_form(assignment_form)
submission = @assignment.submissions.find_by!(user_id: @student)
# it should not actually submit and pop up an error message
expect { submit_form(assignment_form) }.not_to change { submission.reload.updated_at }
expect(submission.reload.body).to be nil
expect(ff('.error_box')[1]).to include_text('Required')
expect(Submission.count).to eq 0
# now make sure it works
type_in_tiny('#submission_body', 'now it is not blank')
submit_form(assignment_form)
expect { Submission.count }.to become 1
body_text = 'now it is not blank'
type_in_tiny('#submission_body', body_text)
expect { submit_form(assignment_form) }.to change { submission.reload.updated_at }
expect(submission.reload.body).to eq "<p>#{body_text}</p>"
end
it "should not allow a submission with only comments", priority: "1", test_id: 237027 do
@assignment.update_attributes(:submission_types => "online_text_entry")
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
f('.submit_assignment_link').click
expect(f('#submission_body_ifr')).to be_displayed
replace_content(f('#submit_online_text_entry_form').find_element(:id, 'submission_comment'), 'this should not be able to be submitted for grading')
submit_form("#submit_online_text_entry_form")
submission = @assignment.submissions.find_by!(user_id: @student)
# it should not actually submit and pop up an error message
expect { submit_form("#submit_online_text_entry_form") }.not_to change { submission.reload.updated_at }
expect(ff('.error_box')[1]).to include_text('Required')
expect(Submission.count).to eq 0
# navigate off the page and dismiss the alert box to avoid problems
# with other selenium tests

View File

@ -36,7 +36,6 @@ describe "submissions" do
student_in_course
assignment = create_assignment
assignment.submissions.create(:user => @student)
get "/courses/#{@course.id}/assignments/#{assignment.id}/submissions/#{@student.id}"
# make sure the JS didn't burn any bridges, and submit two
@ -51,7 +50,6 @@ describe "submissions" do
it "should display the grade in grade field", priority: "1", test_id: 237033 do
student_in_course
assignment = create_assignment
assignment.submissions.create(:user => @student)
assignment.grade_student @student, grade: 2, grader: @teacher
get "/courses/#{@course.id}/assignments/#{assignment.id}/submissions/#{@student.id}"
expect(f('.grading_value')[:value]).to eq '2'

View File

@ -131,8 +131,9 @@ describe "editing grades" do
edit_grade('#gradebook_grid .container_1 .slick-row:nth-child(1) .l5', 'A-')
expect(f('#gradebook_grid .container_1 .slick-row:nth-child(1) .l5')).to include_text('A-')
expect(@assignment.reload.submissions.size).to eq 1
sub = @assignment.submissions.first
submissions = @assignment.submissions.where('grade is not null')
expect(submissions.count).to eq 1
sub = submissions.first
expect(sub.grade).to eq 'A-'
expect(sub.score).to eq 0.0
end

View File

@ -192,9 +192,7 @@ describe "gradebook" do
})
project_group = group_assignment.group_category.groups.create!(:name => 'g1', :context => @course)
project_group.users << @student_1
graded_assignment.submissions.create(:user => @student)
graded_assignment.grade_student @student_1, grade: 10, grader: @teacher # 10 points possible
group_assignment.submissions.create(:user => @student)
group_assignment.grade_student @student_1, grade: 2, grader: @teacher # 0 points possible
@gradebook_page.visit_gradebook(@course)

View File

@ -167,7 +167,7 @@ describe "gradebook uploads" do
expect(@course.assignments.count).to eql (assignment_count + 1)
assignment = @course.assignments.order(:created_at).last
expect(assignment.name).to eq "Assignment 2"
expect(assignment.submissions.count).to eql 0
expect(assignment.submissions.having_submission.count).to eql 0
expect(f('#gradebook_wrapper')).to be_displayed
end

View File

@ -136,8 +136,8 @@ describe "Gradezilla editing grades" do
edit_grade('#gradebook_grid .container_1 .slick-row:nth-child(1) .l4', 'A-')
expect(f('#gradebook_grid .container_1 .slick-row:nth-child(1) .l4')).to include_text('A-')
expect(@assignment.reload.submissions.size).to eq 1
sub = @assignment.submissions.first
expect(@assignment.submissions.where('grade is not null').count).to eq 1
sub = @assignment.submissions.where('grade is not null').first
expect(sub.grade).to eq 'A-'
expect(sub.score).to eq 0.0
end

View File

@ -210,9 +210,7 @@ describe "Gradezilla" do
})
project_group = group_assignment.group_category.groups.create!(:name => 'g1', :context => @course)
project_group.users << @student_1
graded_assignment.submissions.create(:user => @student)
graded_assignment.grade_student @student_1, grade: 10, grader: @teacher # 10 points possible
group_assignment.submissions.create(:user => @student)
group_assignment.grade_student @student_1, grade: 2, grader: @teacher # 0 points possible
gradezilla_page.visit(@course)

View File

@ -167,7 +167,7 @@ describe "Gradezilla - uploads" do
expect(@course.assignments.count).to eql (assignment_count + 1)
assignment = @course.assignments.order(:created_at).last
expect(assignment.name).to eq "Assignment 2"
expect(assignment.submissions.count).to eql 0
expect(assignment.submissions.having_submission.count).to eql 0
expect(f('#gradebook_wrapper')).to be_displayed
end

View File

@ -51,7 +51,7 @@ describe "speedgrader with grading periods" do
Speedgrader.enter_grade(8)
expect(Speedgrader.current_grade).to eq ""
expect(Submission.where(assignment_id: assignment.id, user_id: @student.id).first).to eq nil
expect(Submission.where(assignment_id: assignment.id, user_id: @student.id).first).not_to be_graded
expect(Speedgrader.top_bar).to contain_css(Speedgrader.closed_gp_notice_selector)
end
end

View File

@ -231,9 +231,8 @@ describe 'Speedgrader' do
purpose: 'grading',
use_for_grading: true
)
@submission = Submission.create!(
user: @student,
assignment: @assignment,
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(
submission_type: "online_text_entry",
has_rubric_assessment: true
)

View File

@ -202,7 +202,7 @@ describe 'Screenreader Gradebook grading' do
SRGB.select_assignment(assignment)
expect(SRGB.grading_enabled?).to be false
expect(Submission.where(assignment_id: assignment.id, user_id: @student.id).first).to eq nil
expect(Submission.not_placeholder.where(assignment_id: assignment.id, user_id: @student.id).first).to eq nil
end
end
end

View File

@ -305,7 +305,7 @@ describe "grades" do
it "should show rubric even if there are no comments", priority: "1", test_id: 229669 do
@third_association = @rubric.associate_with(@third_assignment, @course, :purpose => 'grading')
@third_submission = @third_assignment.submissions.create!(:user => @student_1) # unsubmitted submission :/
@third_submission = @third_assignment.submissions.find_by!(user: @student_1) # unsubmitted submission :/
@third_association.assess({
:user => @student_1,

View File

@ -28,8 +28,8 @@ describe "student interactions report" do
@student2 = student_in_course(:active_all => true, :name => "zzz student").user
@assignment = @course.assignments.create(:name => "first assignment", :points_possible => 10)
@sub1 = @assignment.submissions.create(:user => @student1)
@sub2 = @assignment.submissions.create(:user => @student2)
@sub1 = @assignment.submissions.find_by!(user: @student1)
@sub2 = @assignment.submissions.find_by!(user: @student2)
@sub1.update_attribute(:score, 10)
@sub2.update_attribute(:score, 5)