CSC/ECE 517 Fall 2022 - E2253.Refactor delayed mailer.rb and scheduled task.rb
E2253. Refactoring the Delayed Mailer and Scheduler
This page provides a description of the Expertiza based OSS project.
About Expertiza
Expertiza is an open source project based on Ruby on Rails framework. Expertiza is an all inclusive web service that allows instructors to create, edit and manage assignments. This includes the functionality for topic selection and team formation across various projects and assignments. Expertiza allows for a variety of submission types including URL and PDF. Expertiza also allows the instructor to assign peer reviews and team assessments.
Problem Statement
The following tasks were accomplished in this project:
- Improved the clarity of code by improving variable and method names.
- Improved the clarity of code by adding comments.
- Ensured one method didn't perform more than one task.
- Added RSPEC testcases for testing Assignments Controller and Mail Worker
About Assignment Controller
This class is responsible for the creation and implementation of assignment forms. This includes due dates, questionnaires and assigning reviews.
Previous Information can be found here E2144
Files Involved (some changed should not have been changed):
- app/controllers/assignments_controller.rb
- app/mailers/mail_worker.rb
- app/models/assignment_form.rb
- config/sidekiq.yml
- spec/models/assignment_form_spec.rb
- spec/sidekiq_mail_worker_spec.rb
- spec/spec_helper.rb
Current Implementation
Functionality
- Instructor should be able to create, edit and assign assignments to all account in their course.
- TA's should be able to create their own assignments and only edit assignments they've created.
- The Sidekiq Gem is used to automate emails to students about upcoming assignments and when assignments have been altered or delayed.
Drawbacks and Solutions
- Problem 1:
- The method delete_from_delayed_queue performs two tasks
def delete_from_delayed_queue queue = Sidekiq::Queue.new('mailers') queue.each do |job| assignmentId = job.args.first job.delete if @assignment.id == assignmentId end queue = Sidekiq::ScheduledSet.new queue.each do |job| assignmentId = job.args.first job.delete if @assignment.id == assignmentId end end
- Solution: The implementation has been changed to include two function that will instead be called back to back:
- delete_from_delayed_queue
- delete_from_scheduled_set
- Problem 2: Duplicate code found within the create and update_assignment_form methods within assignments_controller.rb
def create ... ques_array = assignment_form_params[:assignment_questionnaire] due_array = assignment_form_params[:due_date] ques_array.each do |cur_questionnaire| cur_questionnaire[:assignment_id] = exist_assignment.id.to_s end due_array.each do |cur_due| cur_due[:parent_id] = exist_assignment.id.to_s end assignment_form_params[:assignment_questionnaire] = ques_array assignment_form_params[:due_date] = due_array ... end def update_assignment_form(exist_assignment) questionnaire_array = assignment_form_params[:assignment_questionnaire] questionnaire_array.each { |cur_questionnaire| cur_questionnaire[:assignment_id] = exist_assignment.id.to_s } assignment_form_params[:assignment_questionnaire] due_array = assignment_form_params[:due_date] due_array.each { |cur_due| cur_due[:parent_id] = exist_assignment.id.to_s } assignment_form_params[:due_date] @assignment_form.update(assignment_form_params, current_user) end
- Solution: Create two methods to create the arrays for due dates and questionnaires.
- Problem 3:
- Tests failing within sidekiq_mail_worker_spec.rb
describe 'Tests mailer with sidekiq' do it "should have sent welcome email after user was created" do email = ActionMailer::Base.deliveries.first expect(email.from[0]).to eq("expertiza.development@gmail.com") expect(email.to[0]).to eq("expertiza.development@gmail.com") expect(email.subject).to eq("Your Expertiza account and password has been created") end it 'should send reminder email to required email address with proper content' do Sidekiq::Testing.inline! ActionMailer::Base.deliveries.clear worker = MailWorker.new worker.perform("1", "metareview", "2018-12-31 00:00:01") expect(ActionMailer::Base.deliveries.size).to eq(1) email = ActionMailer::Base.deliveries.first expect(email.from[0]).to eq("expertiza.development@gmail.com") ...
- Solution: Fix the naming convention of the calls
New Implementation
- The method delete_from_delayed_queue has been split into 2 methods now.
- delete_from_delayed_queue- This method will remove the delayed_job from the delayed_jobs queue
- delete_from_scheduled_set- This method will remove the delayed_job from the scheduled set
# Deletes the job with id equal to "delayed_job_id" from the delayed_jobs queue def delete_from_delayed_queue queue = Sidekiq::Queue.new('mailers') queue.each do |job| assignmentId = job.args.first job.delete if @assignment.id == assignmentId end end # Deletes the job with id equal to "delayed_job_id" from the scheduled set def delete_from_scheduled_set queue = Sidekiq::ScheduledSet.new queue.each do |job| assignmentId = job.args.first job.delete if @assignment.id == assignmentId end end
- Created the methods assign_questionnaire_array and assign_due_date_array to handle the creation of the arrays
- assign_questionnaire_array- This method will create the array of questionnaires
- delete_from_scheduled_set- This method will create the array of due dates assorted
def create ... assignment_form_params[:assignment_questionnaire] = assign_questionnaire_array(exist_assignment) assignment_form_params[:due_date] = assign_due_date_array(exist_assignment) ... end def update_assignment_form(exist_assignment) assignment_form_params[:assignment_questionnaire] = assign_questionnaire_array(exist_assignment) assignment_form_params[:due_date] = assign_due_date_array(exist_assignment) @assignment_form.update(assignment_form_params, current_user) end # creates array of questionnaires def assign_questionnaire_array(exist_assignment) questionnaire_array = assignment_form_params[:assignment_questionnaire] questionnaire_array.each { |cur_questionnaire| cur_questionnaire[:assignment_id] = exist_assignment.id.to_s } questionnaire_array end # creates array of due dates def assign_due_date_array(exist_assignment) due_array = assignment_form_params[:due_date] due_array.each { |cur_due| cur_due[:parent_id] = exist_assignment.id.to_s } due_array end
- Fixed bug within tests so that tests run successfully
describe 'Tests mailer with sidekiq' do it "should have sent welcome email after user was created" do email = Mailer.deliveries.first expect(email.from[0]).to eq("expertiza.debugging@gmail.com") expect(email.to[0]).to eq("expertiza.debugging@gmail.com") expect(email.subject).to eq("Your Expertiza account and password has been created") end it 'should send reminder email to required email address with proper content' do Sidekiq::Testing.inline! Mailer.deliveries.clear worker = MailWorker.new worker.perform("1", "metareview", "2018-12-31 00:00:01") expect(Mailer.deliveries.size).to eq(1) email = Mailer.deliveries.first expect(email.from[0]).to eq("expertiza.debugging@gmail.com") ...
Code improvements
- Added comments to methods that lacked clarity in order to improve the readability
- Changed method names to improve readibility
- get_time_diff_btw_due_date_and_now is now get_time_diff_between_due_date_and_now within assignment_form.rb
- Changed variable names to improve readability
- diff_btw_time_left_and_threshold is now diff_between_time_left_and_threshold within assignment_form.rb
- dd is now dueDate within assignment_form.rb within update
- participant_mails is now participant_emails within mail_worker.rb
- review_has_began is now review_has_begun within mail_worker.rb
Testing Plan
New Tests Added to RPEC
The tests below are anti-tests added for the purpose of ensuring emails aren't sent when they shouldn't be.
it "should not return email if deadline is compare_files_with_simicheck" do Sidekiq::Testing.inline! Mailer.delivieries.clear worker = MailWorker.new worker.perform("1", "compare_files_with_simicheck", "2018-12-31 00:00:01") expect(Mailer.delivieries.size).to eq(0) end it "should not return email if deadline is drop_outstanding_reviews" do Sidekiq::Testing.inline! Mailer.delivieries.clear worker = MailWorker.new worker.perform("1", "drop_outstanding_reviews", "2018-12-31 00:00:01") expect(Mailer.delivieries.size).to eq(0) end
Automated Testing using RSPEC
The current version of expertiza included tests for the assignments_form and the mail_worker, but they were far from extensive. Thus we added a few tests of our own.
To run the tests, run the following commands from the expertiza directory
rspec ./spec/models/assignment_form_spec.rb rspec ./spec/workers/sidekiq_mail_worker_spec.rb
Testing from UI
No changes were made to the functionality of the project, however you can access it through the setup below.
- Visit the VCL hosted site: http://152.7.177.156:8080/
- Login: Instructor6
- Password: Password
To Test via UI
1) Login with the login above
2) Click on Manage...
3) Click on Assignments
4) On the right side click the +
5) Once you've added a name, scroll to the bottom and click create
6) Repeat steps 2 and 3, to view the assignment added to the list