<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Akkhadse</id>
	<title>Expertiza_Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Akkhadse"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Akkhadse"/>
	<updated>2026-05-20T05:23:25Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2169._Testing_-_Answer_Tagging&amp;diff=142728</id>
		<title>CSC/ECE 517 Fall 2021 - E2169. Testing - Answer Tagging</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2169._Testing_-_Answer_Tagging&amp;diff=142728"/>
		<updated>2021-12-07T18:23:59Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Controller: answer_tags_controller.rb */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Answer tagging (see [https://github.com/expertiza/expertiza/blob/25713567e5e5e1c0b363409715e6d8797b45b01a/app/models/answer_tag.rb answer_tab.rb] and [[Answer_tags|wiki]]) helps determine a few metrics on a student’s responses to a questionnaire. Students can tag these metrics for other students for things such as “Positive Tone” or “Suggest Solutions”. &lt;br /&gt;
&lt;br /&gt;
These specs below all need to be further developed to cover missing methods/lines. Some structures currently exist at the top of spec files (such as assignments, participants, etc) to help make writing tests easier. Please feel free to add to these and write extra tests to cover any edge cases you may think of. &lt;br /&gt;
&lt;br /&gt;
As an instructor on an assignment, going to Etc/View Reports/Answer Tagging Report will show student answer tagging. You will be able to see the percentage of answers tagged, # of answers tagged, # not tagged, and # of taggable answers for each student on a questionnaire.&lt;br /&gt;
&lt;br /&gt;
[[File:Tagging_report.png|thumb|center|Fig. 1]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Project Purpose==&lt;br /&gt;
The objective of the project is unit testing of functionality in these two ruby files and increasing the coverage.&lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fcontrollers%2Fanswer_tags_controller.rb Answer_tags_controller_spec] &lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fmodels%2Ftag_prompt_deployment.rb Tag_prompt_deployment_spec]&lt;br /&gt;
&lt;br /&gt;
== Initial Coverage ==&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fcontrollers%2Fanswer_tags_controller.rb Answer_tags_controller_spec] : 0% Covered&lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fmodels%2Ftag_prompt_deployment.rb Tag_prompt_deployment_spec] : 18% Covered&lt;br /&gt;
&lt;br /&gt;
=== Missed Methods ===&lt;br /&gt;
&lt;br /&gt;
These methods had no tests before our project was done.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;app/controllers/answer_tags_controller.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;create_edit&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;destroy&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/tag_prompt_deployment.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;get_number_of_taggable_answers&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;assignment_tagging_progress&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Project Design ==&lt;br /&gt;
In this project, we have two controllers to be tested using Rspec Unit testing.&lt;br /&gt;
&lt;br /&gt;
The ER diagram of the parent tables is given below for reference ([https://expertiza.csc.ncsu.edu/index.php/Answer_tags Source: Answer_tags]).&lt;br /&gt;
&lt;br /&gt;
[[File:answer_tags_imported.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The flow diagrams below show how controllers in this project are connected with interrelated classes, methods, and views.&lt;br /&gt;
&lt;br /&gt;
[[File:E2169 answer tags controller.png|900px]]&lt;br /&gt;
&lt;br /&gt;
[[File:E2169 tag prompt deployment.png|900px]]&lt;br /&gt;
&lt;br /&gt;
== Testing Plan ==&lt;br /&gt;
=== Controller: answer_tags_controller.rb ===&lt;br /&gt;
&lt;br /&gt;
Existing coverage = 0% &lt;br /&gt;
&lt;br /&gt;
Description: &lt;br /&gt;
The purpose of this controller is to track down the total number of tags done by the students. The output of the controller is the list of answer tags in JSON format. The database structure for the answer_tags can be found here [https://expertiza.csc.ncsu.edu/index.php/Answer_tags]&lt;br /&gt;
&lt;br /&gt;
'''Methods'''&lt;br /&gt;
&lt;br /&gt;
1. action_allowed?  ( params: action )&lt;br /&gt;
&lt;br /&gt;
Description: To allow the functionality only if the accessing user is having student privileges (current_user_has_student_privileges?)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the session is of student type, access should be allowed and index operation should be executed.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the session is of student type, access should be allowed and create_edit operation should be executed.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Edge cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the session is null, Access should be denied for index&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the session is null, Access should be denied for create_edit&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. index ( params : assignment_id, questionnaire_id, user_id )&lt;br /&gt;
&lt;br /&gt;
Description: Populates the tags by fetching the records from AnswerTag corresponding to each TagPromptDeployment based on the filers provided as params.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When all valid params are passed, the function should populate the answer tags.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When user_id is provided, answer tags specific to that user should only be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When questionnaire_id is provided, answer tags specific to that questionnaire should only be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When assignment_id is provided, answer tags specific to that assignment should only be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When only one parameter is passed, the corresponding answer tags should be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Edge test cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When user_id is nil, 0 tags prompts should be returned.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When questionnaire_id is nil, 0 tags prompts should be returned.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When assignment_id is nil, 0 tags prompts should be returned.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. create_edit ( params : answer_id, tag_prompt_deployment_id, value )&lt;br /&gt;
&lt;br /&gt;
Description: Fetches the answer tag with the params provided and then updates the respective tag values by the updated values provided as params.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When the existing tag is found based on the params passed, the existing tag should be updated with new values.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Edge cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; Restricts updating answer tag by the student if no mapping is found related to any answer for that tag (foreign key constraint).&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; Restricts updating answer tag by the student if no mapping is found related to any tag_prompt_deployment for that tag (foreign key constraint).&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; Restricts updating answer tag by student if no updated value is provided for the answer tag.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Controller: tag_prompt_deployment.rb ===&lt;br /&gt;
&lt;br /&gt;
Existing coverage = 18% &lt;br /&gt;
&lt;br /&gt;
Description: &lt;br /&gt;
This Controller is when a user (with instructor privilege) wants to see tagging summary of every user that participated in a tagging assignment. &lt;br /&gt;
&lt;br /&gt;
'''Methods'''&lt;br /&gt;
&lt;br /&gt;
1. tag_prompt&lt;br /&gt;
Description: tag_prompt has existing test cases scoring 18 percentage coverage. Additional testing is not required.&lt;br /&gt;
&lt;br /&gt;
2. get_number_of_taggable_answers ( params: user_id)&lt;br /&gt;
&lt;br /&gt;
Description: To calculate total taggable answers reviewed by a user that participated in the given tagging assignment. user_id is the parameter passed to this method.  An individual and his team will have the same score. Fig 1: The last column values are processed by this method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;when user_id is nil expect an error&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;when a team has given any response then count of taggable answer &amp;gt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When a question or a response does not exists then count of taggable answer = 0 (extreme case) &amp;lt;/code&amp;gt; &lt;br /&gt;
* &amp;lt;code&amp;gt;When answer_length_threshold not set, count taggable answer&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When answer_length_threshold is set, count taggable answer&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Edge cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* user_id (parameter) is nil&lt;br /&gt;
* response is empty&lt;br /&gt;
* question is empty&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. assignment_tagging_progress&lt;br /&gt;
&lt;br /&gt;
Description: To compute the number of tagged answers, number of untagged answers, and percentage of answers tagged by the users that participated in the tagging Assignment to a particular question.&lt;br /&gt;
Fig 1: First three columns after the 2nd column onwards are updated with results obtained from this method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When not team participated in the assignment, assert count(user_answer_tagging) =0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the question does not exist, assert count(user_answer_tagging) =0 &amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When multiple rounds of review, render ReviewResponseMap and assert response object&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When single round of review, render ResponseMap and assert response object&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When answer_length_threshold is SET, number of answers and when answer_length_threshold is NOT SET, number of answers&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When route is success answer_tagging object structure matching&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Edge cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* There are no teams associated with the assignment.&lt;br /&gt;
* There are no questions in the questionnaire that have the question type specified in the TagPromptDeployment object.&lt;br /&gt;
* The assignment is set to vary by round.&lt;br /&gt;
* The assignment is set not to vary by round.&lt;br /&gt;
* There are multiple tags.&lt;br /&gt;
* There are no tags.&lt;br /&gt;
&lt;br /&gt;
== Bug Fixing of Additional Issues ==&lt;br /&gt;
&lt;br /&gt;
===Model: tag_prompt_deployment.rb (method: get_number_of_taggable_answers)===&lt;br /&gt;
&lt;br /&gt;
An additional issue in the method get_number_of_taggable_answers. The error message is as shown below which indicates string concatenation fails between integer and string data types.&lt;br /&gt;
&lt;br /&gt;
''TypeError:''&lt;br /&gt;
no implicit conversion of Fixnum into String at line 23 https://github.com/expertiza/expertiza/blob/beta/app/models/tag_prompt_deployment.rb.&lt;br /&gt;
&lt;br /&gt;
[[File:Get_number_of_taggable_answers_bug.JPG]]&lt;br /&gt;
&lt;br /&gt;
This issue is fixed by correcting the syntax of the two-strings concatenation. After fixing the code is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; answers = answers.where(conditions: &amp;quot;length(comments) &amp;lt; #{self.answer_length_threshold}&amp;quot; ) unless self.answer_length_threshold.nil? &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Model: tag_prompt_deployment.rb (method: assignment_tagging_progress)===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Failure/Error: answers = answers.where(&amp;quot;length(comments) &amp;gt; ?&amp;quot;, self.answer_length_threshold.to_s) unless self.answer_length_threshold.nil?&lt;br /&gt;
     &lt;br /&gt;
     NoMethodError:&lt;br /&gt;
       undefined method `where' for #&amp;lt;Array:0x00000003424b60&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This issue was resolved by using &amp;lt;code&amp;gt;Arrays.select&amp;lt;/code&amp;gt; to achieve the same functionality.&lt;br /&gt;
&lt;br /&gt;
There was another small error in which the TeamsUser &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt; was not found, and the resolution was to find the User model for each &amp;lt;code&amp;gt;TeamsUser.user_id&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
Test cases are added to cover all functionality. With the cases added the coverage has reached to 100%.&lt;br /&gt;
&lt;br /&gt;
Test cases demo can be found at [https://youtu.be/WYSUmL6jcHc OSS Final Project Testing Video]&lt;br /&gt;
&lt;br /&gt;
tag_prompt_deployment.rb: Coverage = 100%&lt;br /&gt;
&lt;br /&gt;
[[File:Tag_prompt_deployment_coverage.jpeg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
answer_tags_controller.rb: Coverage = 100%&lt;br /&gt;
&lt;br /&gt;
[[File:Answer_tag_controller_coverage.jpeg]]&lt;br /&gt;
&lt;br /&gt;
== Collaborators ==&lt;br /&gt;
Nicholas Himes (Mentor)&lt;br /&gt;
&lt;br /&gt;
1. Aditya Khadse&lt;br /&gt;
&lt;br /&gt;
2. Alec Landow&lt;br /&gt;
&lt;br /&gt;
3. Rageeni Sah&lt;br /&gt;
&lt;br /&gt;
4. Sayali Parab&lt;br /&gt;
&lt;br /&gt;
== Relevant Links ==&lt;br /&gt;
Main Expertiza repository can be found at [https://github.com/expertiza/expertiza/tree/beta GitHubExp]&lt;br /&gt;
&lt;br /&gt;
Our forked repository can be found at [https://github.com/akk5597/expertiza Github]&lt;br /&gt;
&lt;br /&gt;
== Video Link ==&lt;br /&gt;
&lt;br /&gt;
Test case run and coverage recording [https://www.youtube.com/watch?v=WYSUmL6jcHc]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2169._Testing_-_Answer_Tagging&amp;diff=142195</id>
		<title>CSC/ECE 517 Fall 2021 - E2169. Testing - Answer Tagging</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2169._Testing_-_Answer_Tagging&amp;diff=142195"/>
		<updated>2021-11-30T01:49:10Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Controller: answer_tags_controller.rb */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Answer tagging (see [https://github.com/expertiza/expertiza/blob/25713567e5e5e1c0b363409715e6d8797b45b01a/app/models/answer_tag.rb answer_tab.rb] and [[Answer_tags|wiki]]) helps determine a few metrics on a student’s responses to a questionnaire. Students can tag these metrics for other students for things such as “Positive Tone” or “Suggest Solutions”. &lt;br /&gt;
&lt;br /&gt;
These specs below all need to be further developed to cover missing methods/lines. Some structures currently exist at the top of spec files (such as assignments, participants, etc) to help make writing tests easier. Please feel free to add to these and write extra tests to cover any edge cases you may think of. &lt;br /&gt;
&lt;br /&gt;
As an instructor on an assignment, going to Etc/View Reports/Answer Tagging Report will show student answer tagging. You will be able to see the percentage of answers tagged, # of answers tagged, # not tagged, and # of taggable answers for each student on a questionnaire.&lt;br /&gt;
&lt;br /&gt;
[[File:Tagging_report.png|thumb|center|Fig. 1]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Project Purpose==&lt;br /&gt;
The objective of the project is unit testing of functionality in these two ruby files and increasing the coverage.&lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fcontrollers%2Fanswer_tags_controller.rb Answer_tags_controller_spec] &lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fmodels%2Ftag_prompt_deployment.rb Tag_prompt_deployment_spec]&lt;br /&gt;
&lt;br /&gt;
== Initial Coverage ==&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fcontrollers%2Fanswer_tags_controller.rb Answer_tags_controller_spec] : 0% Covered&lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fmodels%2Ftag_prompt_deployment.rb Tag_prompt_deployment_spec] : 18% Covered&lt;br /&gt;
&lt;br /&gt;
=== Missed Methods ===&lt;br /&gt;
* &amp;lt;code&amp;gt;app/controllers/answer_tags_controller.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;create_edit&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;destroy&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/tag_prompt_deployment.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;get_number_of_taggable_answers&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;assignment_tagging_progress&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Project Design ==&lt;br /&gt;
In this project, we have two controllers to be tested using Rspec Unit testing.&lt;br /&gt;
&lt;br /&gt;
The ER diagram of the parent tables is given below for reference ([https://expertiza.csc.ncsu.edu/index.php/Answer_tags Source: Answer_tags]).&lt;br /&gt;
&lt;br /&gt;
[[File:answer_tags_imported.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The flow diagrams below show how controllers in this project are connected with interrelated classes, methods, and views.&lt;br /&gt;
&lt;br /&gt;
[[File:E2169 answer tags controller.png|900px]]&lt;br /&gt;
&lt;br /&gt;
[[File:E2169 tag prompt deployment.png|900px]]&lt;br /&gt;
&lt;br /&gt;
== Testing Plan ==&lt;br /&gt;
=== Controller: answer_tags_controller.rb ===&lt;br /&gt;
&lt;br /&gt;
Existing coverage = 0% &lt;br /&gt;
&lt;br /&gt;
Description: &lt;br /&gt;
The purpose of this controller is to track down the total number of tags done by the students. The database structure for the answer_tags can be found here [https://expertiza.csc.ncsu.edu/index.php/Answer_tags]&lt;br /&gt;
&lt;br /&gt;
'''Methods'''&lt;br /&gt;
&lt;br /&gt;
1. action_allowed?  ( params: action )&lt;br /&gt;
&lt;br /&gt;
Description: To allow the functionality only if the accessing user is having student privileges (current_user_has_student_privileges?)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the session is null, Access should be denied&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the session is of student type, access should be allowed and operation should be executed.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. index ( params : assignment_id, questionnaire_id, user_id )&lt;br /&gt;
&lt;br /&gt;
Description: Populates the tags by fetching the records from AnswerTag corresponding to each TagPromptDeployment based on the filers provided as params.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When all valid params are passed, the function should populate the answer tags.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When user_id is provided, answer tags specific to that user should only be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When questionnaire_id is provided, answer tags specific to that questionnaire should only be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When assignment_id is provided, answer tags specific to that assignment should only be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When only one parameter is passed, the corresponding answer tags should be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Edge test cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When user_id is nil, 0 tags prompts should be returned.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When questionnaire_id is nil, 0 tags prompts should be returned.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When assignment_id is nil, 0 tags prompts should be returned.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. create_edit ( params : answer_id, tag_prompt_deployment_id, value )&lt;br /&gt;
&lt;br /&gt;
Description: Fetches the answer tag with the params provided and then updates the respective tag values by the updated values provided as params.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When the existing tag is found based on the params passed, the existing tag should be updated with new values.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Controller: tag_prompt_deployment.rb ===&lt;br /&gt;
&lt;br /&gt;
Existing coverage = 18% &lt;br /&gt;
&lt;br /&gt;
Description: &lt;br /&gt;
This Controller is when a user (with instructor privilege) wants to see tagging summary of every user that participated in a tagging assignment. &lt;br /&gt;
&lt;br /&gt;
'''Methods'''&lt;br /&gt;
&lt;br /&gt;
1. tag_prompt&lt;br /&gt;
Description: tag_prompt has existing test cases scoring 18 percentage coverage. Additional testing is not required.&lt;br /&gt;
&lt;br /&gt;
2. get_number_of_taggable_answers ( params: user_id)&lt;br /&gt;
&lt;br /&gt;
Description: To calculate total taggable answers reviewed by a user that participated in the given tagging assignment. user_id is the parameter passed to this method.  An individual and his team will have the same score. Fig 1: The last column values are processed by this method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;when a team has given any response then count of taggable answer &amp;gt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When a question or a response does not exists then count of taggable answer = 0 (extreme case) &amp;lt;/code&amp;gt; &lt;br /&gt;
* &amp;lt;code&amp;gt;When answer_length_threshold not set, count taggable answer&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When answer_length_threshold is set, count taggable answer&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. assignment_tagging_progress&lt;br /&gt;
&lt;br /&gt;
Description: To compute the number of tagged answers, number of untagged answers, and percentage of answers tagged by the users that participated in the tagging Assignment to a particular question.&lt;br /&gt;
Fig 1: First three columns after the 2nd column onwards are updated with results obtained from this method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When not team participated in the assignment, assert count(user_answer_tagging) =0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the question does not exist, assert count(user_answer_tagging) =0 &amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When multiple rounds of review, render ReviewResponseMap and assert response object&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When single round of review, render ResponseMap and assert response object&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When answer_length_threshold is SET, number of answers and when answer_length_threshold is NOT SET, number of answers&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When route is success answer_tagging object structure matching&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Edge cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* There are no teams associated with the assignment.&lt;br /&gt;
* There are no questions in the questionnaire that have the question type specified in the TagPromptDeployment object.&lt;br /&gt;
* The assignment is set to vary by round.&lt;br /&gt;
* The assignment is set not to vary by round.&lt;br /&gt;
* There are multiple tags.&lt;br /&gt;
&lt;br /&gt;
== Bug Fixing of Additional Issues ==&lt;br /&gt;
&lt;br /&gt;
===Model: tag_prompt_deployment.rb (method: get_number_of_taggable_answers)===&lt;br /&gt;
&lt;br /&gt;
An additional issue in the method get_number_of_taggable_answers. The error message is as shown below which indicates string concatenation fails between integer and string data types.&lt;br /&gt;
&lt;br /&gt;
''TypeError:''&lt;br /&gt;
no implicit conversion of Fixnum into String at line 23 https://github.com/expertiza/expertiza/blob/beta/app/models/tag_prompt_deployment.rb.&lt;br /&gt;
&lt;br /&gt;
[[File:Get_number_of_taggable_answers_bug.JPG]]&lt;br /&gt;
&lt;br /&gt;
This issue is fixed by correcting the syntax of the two-strings concatenation. After fixing the code is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; answers = answers.where(conditions: &amp;quot;length(comments) &amp;lt; #{self.answer_length_threshold}&amp;quot; ) unless self.answer_length_threshold.nil? &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Model: tag_prompt_deployment.rb (method: assignment_tagging_progress)===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Failure/Error: answers = answers.where(&amp;quot;length(comments) &amp;gt; ?&amp;quot;, self.answer_length_threshold.to_s) unless self.answer_length_threshold.nil?&lt;br /&gt;
     &lt;br /&gt;
     NoMethodError:&lt;br /&gt;
       undefined method `where' for #&amp;lt;Array:0x00000003424b60&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This issue was resolved by using &amp;lt;code&amp;gt;Arrays.select&amp;lt;/code&amp;gt; to achieve the same functionality.&lt;br /&gt;
&lt;br /&gt;
There was another small error in which the TeamsUser &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt; was not found, and the resolution was to find the User model for each &amp;lt;code&amp;gt;TeamsUser.user_id&amp;lt;/code&amp;gt;.&lt;br /&gt;
A similar issue was found with TeamsUser&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
Test cases are added to cover all functionality. With test cases the new coverage is as follows:&lt;br /&gt;
&lt;br /&gt;
tag_prompt_deployment.rb: Coverage = 99%&lt;br /&gt;
&lt;br /&gt;
answer_tags_controller.rb: Coverage = 100%&lt;br /&gt;
&lt;br /&gt;
Edge cases that are considered in the project are:&lt;br /&gt;
&lt;br /&gt;
- &lt;br /&gt;
- &lt;br /&gt;
- &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Collaborators ==&lt;br /&gt;
Nicholas Himes (Mentor)&lt;br /&gt;
&lt;br /&gt;
1. Aditya Khadse&lt;br /&gt;
&lt;br /&gt;
2. Alec Landow&lt;br /&gt;
&lt;br /&gt;
3. Rageeni Sah&lt;br /&gt;
&lt;br /&gt;
4. Sayali Pranab&lt;br /&gt;
&lt;br /&gt;
== Relevant Links ==&lt;br /&gt;
Main Expertiza repository can be found at [https://github.com/expertiza/expertiza/tree/beta GitHubExp]&lt;br /&gt;
&lt;br /&gt;
Our forked repository can be found at [https://github.com/akk5597/expertiza Github]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2169._Testing_-_Answer_Tagging&amp;diff=142194</id>
		<title>CSC/ECE 517 Fall 2021 - E2169. Testing - Answer Tagging</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2169._Testing_-_Answer_Tagging&amp;diff=142194"/>
		<updated>2021-11-30T01:48:44Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Testing Plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Answer tagging (see [https://github.com/expertiza/expertiza/blob/25713567e5e5e1c0b363409715e6d8797b45b01a/app/models/answer_tag.rb answer_tab.rb] and [[Answer_tags|wiki]]) helps determine a few metrics on a student’s responses to a questionnaire. Students can tag these metrics for other students for things such as “Positive Tone” or “Suggest Solutions”. &lt;br /&gt;
&lt;br /&gt;
These specs below all need to be further developed to cover missing methods/lines. Some structures currently exist at the top of spec files (such as assignments, participants, etc) to help make writing tests easier. Please feel free to add to these and write extra tests to cover any edge cases you may think of. &lt;br /&gt;
&lt;br /&gt;
As an instructor on an assignment, going to Etc/View Reports/Answer Tagging Report will show student answer tagging. You will be able to see the percentage of answers tagged, # of answers tagged, # not tagged, and # of taggable answers for each student on a questionnaire.&lt;br /&gt;
&lt;br /&gt;
[[File:Tagging_report.png|thumb|center|Fig. 1]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Project Purpose==&lt;br /&gt;
The objective of the project is unit testing of functionality in these two ruby files and increasing the coverage.&lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fcontrollers%2Fanswer_tags_controller.rb Answer_tags_controller_spec] &lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fmodels%2Ftag_prompt_deployment.rb Tag_prompt_deployment_spec]&lt;br /&gt;
&lt;br /&gt;
== Initial Coverage ==&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fcontrollers%2Fanswer_tags_controller.rb Answer_tags_controller_spec] : 0% Covered&lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fmodels%2Ftag_prompt_deployment.rb Tag_prompt_deployment_spec] : 18% Covered&lt;br /&gt;
&lt;br /&gt;
=== Missed Methods ===&lt;br /&gt;
* &amp;lt;code&amp;gt;app/controllers/answer_tags_controller.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;create_edit&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;destroy&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/tag_prompt_deployment.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;get_number_of_taggable_answers&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;assignment_tagging_progress&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Project Design ==&lt;br /&gt;
In this project, we have two controllers to be tested using Rspec Unit testing.&lt;br /&gt;
&lt;br /&gt;
The ER diagram of the parent tables is given below for reference ([https://expertiza.csc.ncsu.edu/index.php/Answer_tags Source: Answer_tags]).&lt;br /&gt;
&lt;br /&gt;
[[File:answer_tags_imported.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The flow diagrams below show how controllers in this project are connected with interrelated classes, methods, and views.&lt;br /&gt;
&lt;br /&gt;
[[File:E2169 answer tags controller.png|900px]]&lt;br /&gt;
&lt;br /&gt;
[[File:E2169 tag prompt deployment.png|900px]]&lt;br /&gt;
&lt;br /&gt;
== Testing Plan ==&lt;br /&gt;
=== Controller: answer_tags_controller.rb ===&lt;br /&gt;
&lt;br /&gt;
Existing coverage = 0% &lt;br /&gt;
&lt;br /&gt;
Description: &lt;br /&gt;
The purpose of this controller is to track down the total number of tags done by the students. The database structure for the answer_tags can be found here [https://expertiza.csc.ncsu.edu/index.php/Answer_tags]&lt;br /&gt;
&lt;br /&gt;
'''Methods'''&lt;br /&gt;
&lt;br /&gt;
1. action_allowed?  ( params: action )&lt;br /&gt;
&lt;br /&gt;
Description: To allow the functionality only if the accessing user is having student privileges (current_user_has_student_privileges?)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the session is null, Access should be denied&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the session is of student type, access should be allowed and operation should be executed.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. index ( params : assignment_id, questionnaire_id, user_id )&lt;br /&gt;
&lt;br /&gt;
Description: Populates the tags by fetching the records from AnswerTag corresponding to each TagPromptDeployment based on the filers provided as params.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When all valid params are passed, the function should populate the answer tags.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When user_id is provided, answer tags specific to that user should only be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When questionnaire_id is provided, answer tags specific to that questionnaire should only be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When assignment_id is provided, answer tags specific to that assignment should only be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When only one parameter is passed, the corresponding answer tags should be populated.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Edge test case:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When user_id is nil, 0 tags prompts should be returned.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When questionnaire_id is nil, 0 tags prompts should be returned.&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When assignment_id is nil, 0 tags prompts should be returned.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. create_edit ( params : answer_id, tag_prompt_deployment_id, value )&lt;br /&gt;
&lt;br /&gt;
Description: Fetches the answer tag with the params provided and then updates the respective tag values by the updated values provided as params.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt; When the existing tag is found based on the params passed, the existing tag should be updated with new values.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Controller: tag_prompt_deployment.rb ===&lt;br /&gt;
&lt;br /&gt;
Existing coverage = 18% &lt;br /&gt;
&lt;br /&gt;
Description: &lt;br /&gt;
This Controller is when a user (with instructor privilege) wants to see tagging summary of every user that participated in a tagging assignment. &lt;br /&gt;
&lt;br /&gt;
'''Methods'''&lt;br /&gt;
&lt;br /&gt;
1. tag_prompt&lt;br /&gt;
Description: tag_prompt has existing test cases scoring 18 percentage coverage. Additional testing is not required.&lt;br /&gt;
&lt;br /&gt;
2. get_number_of_taggable_answers ( params: user_id)&lt;br /&gt;
&lt;br /&gt;
Description: To calculate total taggable answers reviewed by a user that participated in the given tagging assignment. user_id is the parameter passed to this method.  An individual and his team will have the same score. Fig 1: The last column values are processed by this method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;when a team has given any response then count of taggable answer &amp;gt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When a question or a response does not exists then count of taggable answer = 0 (extreme case) &amp;lt;/code&amp;gt; &lt;br /&gt;
* &amp;lt;code&amp;gt;When answer_length_threshold not set, count taggable answer&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When answer_length_threshold is set, count taggable answer&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. assignment_tagging_progress&lt;br /&gt;
&lt;br /&gt;
Description: To compute the number of tagged answers, number of untagged answers, and percentage of answers tagged by the users that participated in the tagging Assignment to a particular question.&lt;br /&gt;
Fig 1: First three columns after the 2nd column onwards are updated with results obtained from this method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Use cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When not team participated in the assignment, assert count(user_answer_tagging) =0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When the question does not exist, assert count(user_answer_tagging) =0 &amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When multiple rounds of review, render ReviewResponseMap and assert response object&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When single round of review, render ResponseMap and assert response object&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When answer_length_threshold is SET, number of answers and when answer_length_threshold is NOT SET, number of answers&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;When route is success answer_tagging object structure matching&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Edge cases:&amp;lt;/code&amp;gt;&lt;br /&gt;
* There are no teams associated with the assignment.&lt;br /&gt;
* There are no questions in the questionnaire that have the question type specified in the TagPromptDeployment object.&lt;br /&gt;
* The assignment is set to vary by round.&lt;br /&gt;
* The assignment is set not to vary by round.&lt;br /&gt;
* There are multiple tags.&lt;br /&gt;
&lt;br /&gt;
== Bug Fixing of Additional Issues ==&lt;br /&gt;
&lt;br /&gt;
===Model: tag_prompt_deployment.rb (method: get_number_of_taggable_answers)===&lt;br /&gt;
&lt;br /&gt;
An additional issue in the method get_number_of_taggable_answers. The error message is as shown below which indicates string concatenation fails between integer and string data types.&lt;br /&gt;
&lt;br /&gt;
''TypeError:''&lt;br /&gt;
no implicit conversion of Fixnum into String at line 23 https://github.com/expertiza/expertiza/blob/beta/app/models/tag_prompt_deployment.rb.&lt;br /&gt;
&lt;br /&gt;
[[File:Get_number_of_taggable_answers_bug.JPG]]&lt;br /&gt;
&lt;br /&gt;
This issue is fixed by correcting the syntax of the two-strings concatenation. After fixing the code is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; answers = answers.where(conditions: &amp;quot;length(comments) &amp;lt; #{self.answer_length_threshold}&amp;quot; ) unless self.answer_length_threshold.nil? &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Model: tag_prompt_deployment.rb (method: assignment_tagging_progress)===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Failure/Error: answers = answers.where(&amp;quot;length(comments) &amp;gt; ?&amp;quot;, self.answer_length_threshold.to_s) unless self.answer_length_threshold.nil?&lt;br /&gt;
     &lt;br /&gt;
     NoMethodError:&lt;br /&gt;
       undefined method `where' for #&amp;lt;Array:0x00000003424b60&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This issue was resolved by using &amp;lt;code&amp;gt;Arrays.select&amp;lt;/code&amp;gt; to achieve the same functionality.&lt;br /&gt;
&lt;br /&gt;
There was another small error in which the TeamsUser &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt; was not found, and the resolution was to find the User model for each &amp;lt;code&amp;gt;TeamsUser.user_id&amp;lt;/code&amp;gt;.&lt;br /&gt;
A similar issue was found with TeamsUser&lt;br /&gt;
&lt;br /&gt;
== Results ==&lt;br /&gt;
Test cases are added to cover all functionality. With test cases the new coverage is as follows:&lt;br /&gt;
&lt;br /&gt;
tag_prompt_deployment.rb: Coverage = 99%&lt;br /&gt;
&lt;br /&gt;
answer_tags_controller.rb: Coverage = 100%&lt;br /&gt;
&lt;br /&gt;
Edge cases that are considered in the project are:&lt;br /&gt;
&lt;br /&gt;
- &lt;br /&gt;
- &lt;br /&gt;
- &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Collaborators ==&lt;br /&gt;
Nicholas Himes (Mentor)&lt;br /&gt;
&lt;br /&gt;
1. Aditya Khadse&lt;br /&gt;
&lt;br /&gt;
2. Alec Landow&lt;br /&gt;
&lt;br /&gt;
3. Rageeni Sah&lt;br /&gt;
&lt;br /&gt;
4. Sayali Pranab&lt;br /&gt;
&lt;br /&gt;
== Relevant Links ==&lt;br /&gt;
Main Expertiza repository can be found at [https://github.com/expertiza/expertiza/tree/beta GitHubExp]&lt;br /&gt;
&lt;br /&gt;
Our forked repository can be found at [https://github.com/akk5597/expertiza Github]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021&amp;diff=140985</id>
		<title>CSC/ECE 517 Fall 2021</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021&amp;diff=140985"/>
		<updated>2021-11-06T18:40:13Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Final Projects */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== OSS Projects ==&lt;br /&gt;
&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2117. Refactor questionaires_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2128. Refactor student_quizzes_controller.rb &amp;amp; late_policies_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2129. Refactor auth_controller.rb &amp;amp; password_retrieval_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2132. Add tests cases for review mapping helper.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2134. Write unit tests for admin_controller.rb and institution_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2138. Auto-generate submission directory names based on assignment]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2142. Improve e-mail notifications]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2133. Write tests for popup_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2120. Refactor reputation_web_service_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2139. Remove multiple topics at a time]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2131. Improve assessment360_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2121. Refactor suggestion_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2122. Refactor impersonate_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2123. Refactor sign_up_sheet_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2126. Refactor account_request_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2124. Refactor review_mapping_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2125. Refactor review_mapping_helper.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2127. Refactor teams_controller]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2130. Refactor submitted_content_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2140. Create new late policy successfully and fix Bank link]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2141. OSS project Finklestein: Instructors &amp;amp; Institutions]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2147. Role-based reviewing]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2145. OSS Project Beige]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2146. Introduce a Student View for instructors]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - Refactor Evaluation of SQL Queries]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2135. Email notification to reviewers and instructors]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2149. Finish Github metrics integration - Reputations]]&lt;br /&gt;
&lt;br /&gt;
== Final Projects ==&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2166._Testing_-_Scoring_%26_Grades#Description_about_project CSC/ECE 517 Fall 2021 - E2166. Testing - Scoring_and_Grades]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2150._Integrate_suggestion_detection_algorithm#Description_about_project CSC/ECE 517 Fall 2021 - E2150. Integrate suggestion detection algorithm]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2151._Allow_reviewers_to_bid_on_what_to_review CSC/ECE 517 Fall 2021 - E2151. Allow reviewers to bid on what to review]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2152._Revision_planning_tool#Description_about_project CSC/ECE 517 Fall 2021 - E2152. Revision_planning_tool]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2170._Testing_-_Response_Maps#Description_about_project CSC/ECE 517 Fall 2021 - E2170. Testing - Response Maps]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2153._Improving_search_facility_in_Expertiza#Description_about_project CSC/ECE 517 Fall 2021 - E2153. Improving search facility in Expertiza]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2162._Further_refactoring_and_improvement_of_review_mapping_helper CSC/ECE 517 Fall 2021 - E2162. Further refactoring and improvement of review mapping helper]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2163._Refactor_waitlist_functionality CSC/ECE 517 Fall 2021 - E2163.  Refactor waitlist functionality]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2165._Fix_teammate-review_view CSC/ECE 517 Fall 2021 - E2165. Fix teammate review view ]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2155._Calibration_submissions_should_be_copied_along_with_calibration_assignments CSC/ECE 517 Fall 2021 - E2155. Calibration submissions should be copied along with calibration assignments]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2148._Completion/Progress_View CSC/ECE 517 Fall 2021 - E2148. Completion/Progress view]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2158._Grading_audit_trail CSC/ECE 517 Fall 2021 - E2158. Grading audit trail ]&lt;br /&gt;
*[https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2159._Expertiza_internationalization CSC/ECE 517 Fall 2021 - E2159. Expertiza internationalization]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2160._Implementing_and_testing_import_export_controllers#Description_about_project CSC/ECE 517 Fall 2021 - E2160. Implementing and testing import and export controllers]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2164._Heatgrid_fixes_and_improvements#Description_about_project CSC/ECE 517 Fall 2021 - E2164. Heatgrid fixes and improvements]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2168. Testing - Reputations]]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2126._Testing_-_Team_Related_Files#Description_about_project CSC/ECE 517 Fall 2021 - E2126. Testing - Team Related Files]&lt;br /&gt;
* [https://expertiza.csc.ncsu.edu/index.php/CSC/ECE_517_Fall_2021_-_E2156._Issues_related_to_meta-reviewing#Description_about_project CSC/ECE 517 Fall 2021 - E2156. Issues related to meta-reviewing]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2169. Testing - Answer Tagging]]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2169._Testing_-_Answer_Tagging&amp;diff=140287</id>
		<title>CSC/ECE 517 Fall 2021 - E2169. Testing - Answer Tagging</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2169._Testing_-_Answer_Tagging&amp;diff=140287"/>
		<updated>2021-10-31T19:46:37Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: Initial Setup&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Answer tagging (see [https://github.com/expertiza/expertiza/blob/25713567e5e5e1c0b363409715e6d8797b45b01a/app/models/answer_tag.rb answer_tab.rb] and [[Answer_tags|wiki]]) helps determine a few metrics on a student’s responses to a questionnaire. Students can tag these metrics for other students for things such as “Positive Tone” or “Suggest Solutions”. &lt;br /&gt;
&lt;br /&gt;
These specs below all need to be further developed to cover missing methods/lines. Some structures currently exist at the top of spec files (such as assignments, participants, etc) to help make writing tests easier. Please feel free to add to these and write extra tests to cover any edge cases you may think of. &lt;br /&gt;
&lt;br /&gt;
As an instructor on an assignment, going to Etc/View Reports/Answer Tagging Report will show student answer tagging. You will be able to see the percentage of answers tagged, # of answers tagged, # not tagged, and # of taggable answers for each student on a questionnaire.&lt;br /&gt;
&lt;br /&gt;
== Initial Coverage ==&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fcontrollers%2Fanswer_tags_controller.rb Answer_tags_controller_spec] : 0% Covered&lt;br /&gt;
&lt;br /&gt;
[https://coveralls.io/builds/43656335/source?filename=app%2Fmodels%2Ftag_prompt_deployment.rb Tag_prompt_deployment_spec] : 18% Covered&lt;br /&gt;
&lt;br /&gt;
=== Missed Methods ===&lt;br /&gt;
* &amp;lt;code&amp;gt;app/controllers/answer_tags_controller.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;action_allowed?&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;index&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;create_edit&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;destroy&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;app/models/tag_prompt_deployment.rb&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;get_number_of_taggable_answers&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;assignment_tagging_progress&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021&amp;diff=140280</id>
		<title>CSC/ECE 517 Fall 2021</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021&amp;diff=140280"/>
		<updated>2021-10-31T19:28:52Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== OSS Projects ==&lt;br /&gt;
&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2117. Refactor questionaires_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2128. Refactor student_quizzes_controller.rb &amp;amp; late_policies_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2129. Refactor auth_controller.rb &amp;amp; password_retrieval_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2132. Add tests cases for review mapping helper.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2134. Write unit tests for admin_controller.rb and institution_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2138. Auto-generate submission directory names based on assignment]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2142. Improve e-mail notifications]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2133. Write tests for popup_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2120. Refactor reputation_web_service_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2139. Remove multiple topics at a time]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2131. Improve assessment360_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2121. Refactor suggestion_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2122. Refactor impersonate_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2123. Refactor sign_up_sheet_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2126. Refactor account_request_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2124. Refactor review_mapping_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2125. Refactor review_mapping_helper.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2127. Refactor teams_controller]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2130. Refactor submitted_content_controller.rb]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2140. Create new late policy successfully and fix Bank link]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2141. OSS project Finklestein: Instructors &amp;amp; Institutions]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2147. Role-based reviewing]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2145. OSS Project Beige]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2146. Introduce a Student View for instructors]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - Refactor Evaluation of SQL Queries]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2135. Email notification to reviewers and instructors]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2168. Testing - Reputations]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2166. Testing - Scoring &amp;amp; Grades]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2149. Finish Github metrics integration - Reputations]]&lt;br /&gt;
* [[CSC/ECE 517 Fall 2021 - E2161. Merge code for role-based reviewing with code for topic-specific rubrics]]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140278</id>
		<title>E2144. Refactor delayed mailer and scheduled task</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140278"/>
		<updated>2021-10-31T19:24:39Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: Akkhadse moved page E2144. Refactor delayed mailer and scheduled task to CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task: Add semester in Title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task]]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140277</id>
		<title>CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140277"/>
		<updated>2021-10-31T19:24:39Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: Akkhadse moved page E2144. Refactor delayed mailer and scheduled task to CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task: Add semester in Title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq’s queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
&lt;br /&gt;
=== Previous Setup ===&lt;br /&gt;
Initial work can be found [https://expertiza.csc.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task here].&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/expertiza/expertiza/pull/1245/files pull request] was found to be reasonable and working. The method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; has:&lt;br /&gt;
{| class=wikitable style=text-align:right&lt;br /&gt;
|+ Metrics for &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method&lt;br /&gt;
|-&lt;br /&gt;
! Metric !! Current Value !! Limit&lt;br /&gt;
|-&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
| 15 || 5&lt;br /&gt;
|-&lt;br /&gt;
! Cyclomatic Complexity&lt;br /&gt;
| 8 || 6&lt;br /&gt;
|-&lt;br /&gt;
! Assignment Branch Condition size&lt;br /&gt;
| 22.93 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Perceived complexity&lt;br /&gt;
| 10 || 7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Previous pull request also has duplicated commit messages and the commits need to be squashed.&lt;br /&gt;
&lt;br /&gt;
Files involved (some changed should not have been changed):&lt;br /&gt;
* app/controllers/assignments_controller.rb&lt;br /&gt;
* app/mailers/mail_worker.rb&lt;br /&gt;
* app/models/assignment_form.rb&lt;br /&gt;
* config/sidekiq.yml&lt;br /&gt;
* spec/models/assignment_form_spec.rb&lt;br /&gt;
* spec/sidekiq_mail_worker_spec.rb&lt;br /&gt;
* spec/spec_helper.rb&lt;br /&gt;
&lt;br /&gt;
There are minor styling issues such as missing or trailing whitespaces, lines that are too long, extra empty line, unused arguments.&lt;br /&gt;
&lt;br /&gt;
=== Problem Statement ===&lt;br /&gt;
&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq's queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method perform() to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
The project was partially merged.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
What needs to be done:  &lt;br /&gt;
Feedback from the previous team (E1835) is:&lt;br /&gt;
Code in pull request seems pretty reasonable.  Some concerns wrt. naming functions, but otherwise reviewers seem to agree that the code is good.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
Your pull request has many duplicated commit messages. Please try to &amp;lt;code&amp;gt;squash&amp;lt;/code&amp;gt; similar commits.&lt;br /&gt;
And using meaningful commit messages later.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should commit changes to the DB schema (&amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt;) only if you have created new DB migrations.&lt;br /&gt;
Please double check your code. If you did not aim to change the DB, please revert the DB schema changes. ***** Important, try not to change the DB.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should not change &amp;lt;code&amp;gt;rails_helper.rb&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;spec_helper.rb&amp;lt;/code&amp;gt; file; please revert these changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The previous team’s code needs a refactor in some places, though the actual function of it seems solid. It is very possible that in the three years since this code has been worked on, more mailer functionality has been added. There are other teams this semester working on mailer code as well. Try to keep your code as contained and simple as possible, so that merging these projects is possible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Summary of Work Needed ==&lt;br /&gt;
After discussing with our project mentor and Dr. Gehringer, we determined the main tasks to be the following:&lt;br /&gt;
# Refactor the single Sidekiq worker into multiple workers&lt;br /&gt;
# Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type&lt;br /&gt;
# Update and add unit tests according to the above changes&lt;br /&gt;
# Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected&lt;br /&gt;
# Code cleanup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Refactor the single Sidekiq worker into multiple workers ===&lt;br /&gt;
Previously there was only a single worker class that handled all types of jobs. Its top-level method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; looked like the following.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def perform(assignment_id, deadline_type, due_at)&lt;br /&gt;
    self.assignment_id = assignment_id&lt;br /&gt;
    self.deadline_type = deadline_type&lt;br /&gt;
    self.due_at = due_at&lt;br /&gt;
&lt;br /&gt;
    assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
    participant_mails = find_participant_emails&lt;br /&gt;
&lt;br /&gt;
    if %w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck].include?(self.deadline_type)&lt;br /&gt;
      drop_one_member_topics if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot; &amp;amp;&amp;amp; assignment.team_assignment&lt;br /&gt;
      drop_outstanding_reviews if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;&lt;br /&gt;
      perform_simicheck_comparisons(self.assignment_id) if self.deadline_type == &amp;quot;compare_files_with_simicheck&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      # Can we rename deadline_type(metareview) to &amp;quot;teammate review&amp;quot;. If, yes then we donot need this if clause below!&lt;br /&gt;
      deadlineText = if self.deadline_type == &amp;quot;metareview&amp;quot;&lt;br /&gt;
                       &amp;quot;teammate review&amp;quot;&lt;br /&gt;
                     else&lt;br /&gt;
                       self.deadline_type&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      email_reminder(participant_mails, deadlineText) unless participant_mails.empty?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The processing was different depending on the &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;s in&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
did not lead to an email reminder being sent, but they were still handled in this &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
To make the code more manageable and easier to follow, it made sense to break up the responsibilities of this single &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class into multiple workers:&lt;br /&gt;
* &amp;lt;code&amp;gt;SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
All three workers extended an &amp;quot;abstract class&amp;quot; called &amp;lt;code&amp;gt;Worker&amp;lt;/code&amp;gt; that contained the Sidekiq-related &amp;lt;code&amp;gt;include&amp;lt;/code&amp;gt; and the queue name to which all jobs would be sent.&lt;br /&gt;
&lt;br /&gt;
For simplicity, we still had all new workers continue to use a single queue, which we renamed from &amp;lt;code&amp;gt;mailers&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;jobs&amp;lt;/code&amp;gt;. A future improvement could divide these jobs to go to multiple different queues if needed.&lt;br /&gt;
&lt;br /&gt;
=== Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type ===&lt;br /&gt;
It was decided that code used for dropping one member or two member teams from topics would never need to be implemented in the Expertiza website. Thus, we removed all code related to the drop_one_member_topics method within the Expertiza beta. This involved removing the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; function from &amp;lt;code&amp;gt;drop_outstanding_reviews_mail_worker.rb&amp;lt;/code&amp;gt;, now renamed &amp;lt;code&amp;gt;drop_outstanding_reviews_worker.rb&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; method was called from the &amp;lt;code&amp;gt;prepare_data&amp;lt;/code&amp;gt; method, which was then called by the Sidekiq method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; so we removed this call. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; was also referenced in &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; using &amp;lt;code&amp;gt;add_delayed_job&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method and in &amp;lt;code&amp;gt;delayed_mailer.html.erb&amp;lt;/code&amp;gt; as an option for the handler so both of these code snippets were removed as well.&lt;br /&gt;
&lt;br /&gt;
=== Code Cleanup ===&lt;br /&gt;
Smaller improvements done while implementing the main tasks included:&lt;br /&gt;
* Using ActiveSupport::Duration objects in order to calculate the minutes and seconds related to the dequeue times&lt;br /&gt;
* Refactoring the time calculations for the dequeue times to the DueDate class&lt;br /&gt;
* Correcting the parameters passed to the workers, which were previously incorrect. As an example:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_delayed_job(_assignment, deadline_type, due_date, min_left)&lt;br /&gt;
    delayed_job_id = MailWorker.perform_in(min_left * 60, due_date.parent_id, deadline_type, due_date.due_at)&lt;br /&gt;
    delayed_job_id&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first parameter after the time delay must be assignment ID, and &amp;lt;code&amp;gt;due_date.parent_id&amp;lt;/code&amp;gt; is not an assignment ID.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Removing whitespace issues reported by codeclimate&lt;br /&gt;
* Refactoring all variable names to be in snake_case&lt;br /&gt;
* Removing identical blocks of code&lt;br /&gt;
* Adding method comments to make methods more understandable&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Unit Tests ===&lt;br /&gt;
In order to properly test that our refactoring had worked properly, we found that we would have to add in multiple tests to account for our new methods as well as refactor old tests to work with the changes that we had made.&lt;br /&gt;
&lt;br /&gt;
For every worker, we have added a test case in the &amp;lt;code&amp;gt;spec/workers/sidekiq_mail_worker_spec.rb&amp;lt;/code&amp;gt; file: one each for MailWorker, SimicheckWorker, DropOutstandingReviewsWorker.&lt;br /&gt;
&lt;br /&gt;
Further, we moved methods &amp;lt;code&amp;gt;find_min_from_now_duration&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;due_date.rb&amp;lt;/code&amp;gt;. Along with that we introduced some methods to make it easier to understand the conversions and values that are being set.&lt;br /&gt;
&lt;br /&gt;
=== Functional Tests ===&lt;br /&gt;
We decided that functional testing would need to be done by manually checking to see if Sidekiq tasks were queued as expected when changes to assignments were made. The three important functional tests that we decided needed to be verified were that the Simicheck Worker was queuing, the Mail Worker was queueing, and the Drop Outstanding Reviews Worker was queuing. These could be considered verified under the condition that the '''When''' field, '''Job''' field, and '''Arguments''' field in the Sidekiq view all came out as expected.&lt;br /&gt;
&lt;br /&gt;
=== Considering Edge Cases and Other Possibilities ===&lt;br /&gt;
&lt;br /&gt;
If we try to set the due date to be a date that has passed, no new jobs are queued as expected.&lt;br /&gt;
&lt;br /&gt;
== Implementing Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Update and add unit tests according to the refactoring changes made  ===&lt;br /&gt;
&lt;br /&gt;
The following tests were added according to the methods we moved and created:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#find_min_from_now_duration&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between due_date and now&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 11, 11).in_time_zone)&lt;br /&gt;
      due_at = Time.parse(DateTime.new(2021, 10, 20, 12, 12, 12).in_time_zone.to_s(:db))&lt;br /&gt;
      expect(DueDate.find_min_from_now_duration(due_at)).to eq(61)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_dequeue_time_as_seconds_duration_from_now&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between now and dequeue of job in seconds&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 00, 00).in_time_zone)&lt;br /&gt;
      due_at = DateTime.new(2021, 10, 20, 12, 00, 00)&lt;br /&gt;
      delay_duration = 1.hour&lt;br /&gt;
      assignment_id = create(:assignment, staggered_deadline: true, name: &amp;quot;testassignment&amp;quot;).id&lt;br /&gt;
      due_date = create(:topic_due_date, deadline_type: @deadline_type,&lt;br /&gt;
                                         submission_allowed_id: @deadline_right, review_allowed_id: @deadline_right,&lt;br /&gt;
                                         review_of_review_allowed_id: @deadline_right, due_at: due_at, parent_id: assignment_id)&lt;br /&gt;
      expect(DueDate.get_dequeue_time_as_seconds_duration_from_now(due_date, delay_duration)).to eq(7200)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected ===&lt;br /&gt;
==== Sidekiq setup ====&lt;br /&gt;
In order to test the Sidekiq workers, we needed to run Sidekiq (steps were obtained from [https://tudip.com/blog-post/how-to-use-sidekiq-in-rails-for-background-processing/ this site]):&lt;br /&gt;
# In a terminal separate from the one in which the main rails application is running, run&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec sidekiq&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Sidekiq-specific terminal will show logs and printed statements from the workers.&lt;br /&gt;
&lt;br /&gt;
NB: To create a generic sidekiq worker to test with, you could use&lt;br /&gt;
&amp;lt;pre&amp;gt;rails g sidekiq:worker TestWorker&amp;lt;/pre&amp;gt;&lt;br /&gt;
to create a shell worker class.&lt;br /&gt;
&lt;br /&gt;
===== Sidekiq UI =====&lt;br /&gt;
To see which messages were being enqueued and dequeued in Sidekiq, we use the Sidekiq user interface, which can be accessed via the &amp;lt;code&amp;gt;/sidekiq&amp;lt;/code&amp;gt; route of the application.&lt;br /&gt;
[[File:Sidekiq-ui.png|950px|The Sidekiq UI]]&lt;br /&gt;
&lt;br /&gt;
==== SimicheckWorker Test ====&lt;br /&gt;
To enqueue a Simicheck job:&lt;br /&gt;
# Edit an assignment.&lt;br /&gt;
# Select the &amp;lt;code&amp;gt;Use simicheck?&amp;lt;/code&amp;gt; box.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Simicheck Delay&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (or to a nonzero value to observe a delay).&lt;br /&gt;
# Set the SimiCheck Similarity Threshold to a nonzero value.&lt;br /&gt;
# Ensure the Late Policy is set to &amp;lt;code&amp;gt;--None--&amp;lt;/code&amp;gt; under the Due Dates tab. If there is a late policy set, per pre-existing code, the enqueued SimicheckWorker job will be deleted and will not appear in the Sidekiq UI (unless it is dequeued quickly, before the code can delete the jobs in the queue).&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Save&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Observe a Simicheck Worker job enqueued and dequeued in the Sidekiq UI.&lt;br /&gt;
&lt;br /&gt;
[[File:Enqueue-simicheck-job.png|500px|How to Enqueue a Simicheck Worker Job]]&lt;br /&gt;
&lt;br /&gt;
[[File:simicheck-job-enqueued.png|950px|How to Enqueue a Simicheck Worker Job]]&lt;br /&gt;
&lt;br /&gt;
==== MailWorker and DropOustandingReviews Test ====&lt;br /&gt;
The Mail Worker sends out notifications to students if the due date of an assignment is changed. Drop Outstanding Reviews Worker drops all reviews that had not been worked on before the due date was changed. These both can be tested together, as when an assignment with a review is updated, Sidekiq should queue both the jobs for Mail Worker and Drop Outstanding Reviews Worker. To test these:&lt;br /&gt;
# Log into Expertiza as an instructor.&lt;br /&gt;
# Navigate to '''Manage'''&amp;gt;'''Assignments''' in the navigation.&lt;br /&gt;
# Click the plus button in the top right corner on the '''Manage Assignments''' and create an assignment with default settings. &lt;br /&gt;
# Go to the '''Due Dates''' tab and assign due dates for both the assignment and the review.&lt;br /&gt;
# Select a late policy next to '''Apply penalty policy:'''. If a late policy has not been created, press '''New Late Policy''' and follow the steps for creating a late policy.&lt;br /&gt;
# Assign student7613 to the assignment you created by clicking the person with the plus icon in the icons next to the assignment on the '''Manage Assignments''' page. &lt;br /&gt;
# Edit the assignment, go to the due dates tab, and change the due date on the review to be a day ahead of its current due date, and press save. The assignment due date must be changed to a time at least an hour ahead of the current time for the job to be queued.&lt;br /&gt;
# To ensure that the assignments are now queued on Sidekiq, visit the Sidekiq UI by going to [Expertiza VCL URL]/sidekiq.&lt;br /&gt;
# Upon arriving on this page, verify that the jobs added to the queue were correct by clicking to '''Scheduled'''. After arriving on this page, you should see something like the following:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Sidekiq-jobs.png|950px|Sidekiq jobs]]&lt;br /&gt;
&lt;br /&gt;
The job '''MailWorker''' that had been queued successfully shows that our refactoring of Mail Worker had worked properly and the Mail Worker was operational. The job '''DropOutstandingReviewsWorker''' showed that our refactoring of Drop Outstanding Reviews Worker had also been done correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Tests ===&lt;br /&gt;
&lt;br /&gt;
The following tests were added to test the workers:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;test different workers&amp;quot; do&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when MailWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      MailWorker.perform_in(42.minutes, 1, &amp;quot;review&amp;quot;, &amp;quot;2021-10-27 00:00:01&amp;quot;)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when SimicheckWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      SimicheckWorker.perform_in(42.minutes, 1)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when DropOutstandingReviewsWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      DropOutstandingReviewsWorker.perform_in(42.minutes, 1, &amp;quot;review&amp;quot;, &amp;quot;2021-10-27 00:00:01&amp;quot;)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140206</id>
		<title>CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140206"/>
		<updated>2021-10-27T02:51:31Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Considering Edge Cases and Other Possibilities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq’s queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
&lt;br /&gt;
=== Previous Setup ===&lt;br /&gt;
Initial work can be found [https://expertiza.csc.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task here].&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/expertiza/expertiza/pull/1245/files pull request] was found to be reasonable and working. The method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; has:&lt;br /&gt;
{| class=wikitable style=text-align:right&lt;br /&gt;
|+ Metrics for &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method&lt;br /&gt;
|-&lt;br /&gt;
! Metric !! Current Value !! Limit&lt;br /&gt;
|-&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
| 15 || 5&lt;br /&gt;
|-&lt;br /&gt;
! Cyclomatic Complexity&lt;br /&gt;
| 8 || 6&lt;br /&gt;
|-&lt;br /&gt;
! Assignment Branch Condition size&lt;br /&gt;
| 22.93 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Perceived complexity&lt;br /&gt;
| 10 || 7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Previous pull request also has duplicated commit messages and the commits need to be squashed.&lt;br /&gt;
&lt;br /&gt;
Files involved (some changed should not have been changed):&lt;br /&gt;
* app/controllers/assignments_controller.rb&lt;br /&gt;
* app/mailers/mail_worker.rb&lt;br /&gt;
* app/models/assignment_form.rb&lt;br /&gt;
* config/sidekiq.yml&lt;br /&gt;
* spec/models/assignment_form_spec.rb&lt;br /&gt;
* spec/sidekiq_mail_worker_spec.rb&lt;br /&gt;
* spec/spec_helper.rb&lt;br /&gt;
&lt;br /&gt;
There are minor styling issues such as missing or trailing whitespaces, lines that are too long, extra empty line, unused arguments.&lt;br /&gt;
&lt;br /&gt;
=== Problem Statement ===&lt;br /&gt;
&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq's queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method perform() to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
The project was partially merged.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
What needs to be done:  &lt;br /&gt;
Feedback from the previous team (E1835) is:&lt;br /&gt;
Code in pull request seems pretty reasonable.  Some concerns wrt. naming functions, but otherwise reviewers seem to agree that the code is good.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
Your pull request has many duplicated commit messages. Please try to &amp;lt;code&amp;gt;squash&amp;lt;/code&amp;gt; similar commits.&lt;br /&gt;
And using meaningful commit messages later.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should commit changes to the DB schema (&amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt;) only if you have created new DB migrations.&lt;br /&gt;
Please double check your code. If you did not aim to change the DB, please revert the DB schema changes. ***** Important, try not to change the DB.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should not change &amp;lt;code&amp;gt;rails_helper.rb&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;spec_helper.rb&amp;lt;/code&amp;gt; file; please revert these changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The previous team’s code needs a refactor in some places, though the actual function of it seems solid. It is very possible that in the three years since this code has been worked on, more mailer functionality has been added. There are other teams this semester working on mailer code as well. Try to keep your code as contained and simple as possible, so that merging these projects is possible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Summary of Work Needed ==&lt;br /&gt;
After discussing with our project mentor and Dr. Gehringer, we determined the main tasks to be the following:&lt;br /&gt;
# Refactor the single Sidekiq worker into multiple workers&lt;br /&gt;
# Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type&lt;br /&gt;
# Update and add unit tests according to the above changes&lt;br /&gt;
# Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected&lt;br /&gt;
# Code cleanup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Refactor the single Sidekiq worker into multiple workers ===&lt;br /&gt;
Previously there was only a single worker class that handled all types of jobs. Its top-level method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; looked like the following.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def perform(assignment_id, deadline_type, due_at)&lt;br /&gt;
    self.assignment_id = assignment_id&lt;br /&gt;
    self.deadline_type = deadline_type&lt;br /&gt;
    self.due_at = due_at&lt;br /&gt;
&lt;br /&gt;
    assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
    participant_mails = find_participant_emails&lt;br /&gt;
&lt;br /&gt;
    if %w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck].include?(self.deadline_type)&lt;br /&gt;
      drop_one_member_topics if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot; &amp;amp;&amp;amp; assignment.team_assignment&lt;br /&gt;
      drop_outstanding_reviews if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;&lt;br /&gt;
      perform_simicheck_comparisons(self.assignment_id) if self.deadline_type == &amp;quot;compare_files_with_simicheck&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      # Can we rename deadline_type(metareview) to &amp;quot;teammate review&amp;quot;. If, yes then we donot need this if clause below!&lt;br /&gt;
      deadlineText = if self.deadline_type == &amp;quot;metareview&amp;quot;&lt;br /&gt;
                       &amp;quot;teammate review&amp;quot;&lt;br /&gt;
                     else&lt;br /&gt;
                       self.deadline_type&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      email_reminder(participant_mails, deadlineText) unless participant_mails.empty?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The processing was different depending on the &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;s in&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
did not lead to an email reminder being sent, but they were still handled in this &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
To make the code more manageable and easier to follow, it made sense to break up the responsibilities of this single &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class into multiple workers:&lt;br /&gt;
* &amp;lt;code&amp;gt;SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
All three workers extended an &amp;quot;abstract class&amp;quot; called &amp;lt;code&amp;gt;Worker&amp;lt;/code&amp;gt; that contained the Sidekiq-related &amp;lt;code&amp;gt;include&amp;lt;/code&amp;gt; and the queue name to which all jobs would be sent.&lt;br /&gt;
&lt;br /&gt;
For simplicity, we still had all new workers continue to use a single queue, which we renamed from &amp;lt;code&amp;gt;mailers&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;jobs&amp;lt;/code&amp;gt;. A future improvement could divide these jobs to go to multiple different queues if needed.&lt;br /&gt;
&lt;br /&gt;
=== Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type ===&lt;br /&gt;
It was decided that code used for dropping one member or two member teams from topics would never need to be implemented in the Expertiza website. Thus, we removed all code related to the drop_one_member_topics method within the Expertiza beta. This involved removing the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; function from &amp;lt;code&amp;gt;drop_outstanding_reviews_mail_worker.rb&amp;lt;/code&amp;gt;, now renamed &amp;lt;code&amp;gt;drop_outstanding_reviews_worker.rb&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; method was called from the &amp;lt;code&amp;gt;prepare_data&amp;lt;/code&amp;gt; method, which was then called by the Sidekiq method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; so we removed this call. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; was also referenced in &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; using &amp;lt;code&amp;gt;add_delayed_job&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method and in &amp;lt;code&amp;gt;delayed_mailer.html.erb&amp;lt;/code&amp;gt; as an option for the handler so both of these code snippets were removed as well.&lt;br /&gt;
&lt;br /&gt;
=== Code Cleanup ===&lt;br /&gt;
Smaller improvements done while implementing the main tasks included:&lt;br /&gt;
* Using ActiveSupport::Duration objects in order to calculate the minutes and seconds related to the dequeue times&lt;br /&gt;
* Refactoring the time calculations for the dequeue times to the DueDate class&lt;br /&gt;
* Correcting the parameters passed to the workers, which were previously incorrect. As an example:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_delayed_job(_assignment, deadline_type, due_date, min_left)&lt;br /&gt;
    delayed_job_id = MailWorker.perform_in(min_left * 60, due_date.parent_id, deadline_type, due_date.due_at)&lt;br /&gt;
    delayed_job_id&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first parameter after the time delay must be assignment ID, and &amp;lt;code&amp;gt;due_date.parent_id&amp;lt;/code&amp;gt; is not an assignment ID.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Removing whitespace issues reported by codeclimate&lt;br /&gt;
* Refactoring all variable names to be in snake_case&lt;br /&gt;
* Removing identical blocks of code&lt;br /&gt;
* Adding method comments to make methods more understandable&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Unit Tests ===&lt;br /&gt;
In order to properly test that our refactoring had worked properly, we found that we would have to add in multiple tests to account for our new methods as well as refactor old tests to work with the changes that we had made.&lt;br /&gt;
&lt;br /&gt;
For every worker, we have added a test case in the &amp;lt;code&amp;gt;spec/workers/sidekiq_mail_worker_spec.rb&amp;lt;/code&amp;gt; file: one each for MailWorker, SimicheckWorker, DropOutstandingReviewsWorker.&lt;br /&gt;
&lt;br /&gt;
Further, we moved methods &amp;lt;code&amp;gt;find_min_from_now_duration&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;due_date.rb&amp;lt;/code&amp;gt;. Along with that we introduced some methods to make it easier to understand the conversions and values that are being set.&lt;br /&gt;
&lt;br /&gt;
=== Functional Tests ===&lt;br /&gt;
We decided that functional testing would need to be done by manually checking to see if Sidekiq tasks were queued as expected when changes to assignments were made. The three important functional tests that we decided needed to be verified were that the Simicheck Worker was queuing, the Mail Worker was queueing, and the Drop Outstanding Reviews Worker was queuing. These could be considered verified under the condition that the '''When''' field, '''Job''' field, and '''Arguments''' field in the Sidekiq view all came out as expected.&lt;br /&gt;
&lt;br /&gt;
=== Considering Edge Cases and Other Possibilities ===&lt;br /&gt;
&lt;br /&gt;
If we try to set the due date to be a date that has passed, no new jobs are queued as expected.&lt;br /&gt;
&lt;br /&gt;
== Implementing Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Update and add unit tests according to the refactoring changes made  ===&lt;br /&gt;
&lt;br /&gt;
The following tests were added according to the methods we moved and created:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#find_min_from_now_duration&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between due_date and now&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 11, 11).in_time_zone)&lt;br /&gt;
      due_at = Time.parse(DateTime.new(2021, 10, 20, 12, 12, 12).in_time_zone.to_s(:db))&lt;br /&gt;
      expect(DueDate.find_min_from_now_duration(due_at)).to eq(61)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_dequeue_time_as_seconds_duration_from_now&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between now and dequeue of job in seconds&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 00, 00).in_time_zone)&lt;br /&gt;
      due_at = DateTime.new(2021, 10, 20, 12, 00, 00)&lt;br /&gt;
      delay_duration = 1.hour&lt;br /&gt;
      assignment_id = create(:assignment, staggered_deadline: true, name: &amp;quot;testassignment&amp;quot;).id&lt;br /&gt;
      due_date = create(:topic_due_date, deadline_type: @deadline_type,&lt;br /&gt;
                                         submission_allowed_id: @deadline_right, review_allowed_id: @deadline_right,&lt;br /&gt;
                                         review_of_review_allowed_id: @deadline_right, due_at: due_at, parent_id: assignment_id)&lt;br /&gt;
      expect(DueDate.get_dequeue_time_as_seconds_duration_from_now(due_date, delay_duration)).to eq(7200)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected ===&lt;br /&gt;
==== Sidekiq setup ====&lt;br /&gt;
In order to test the Sidekiq workers, we needed to run Sidekiq (steps were obtained from [https://tudip.com/blog-post/how-to-use-sidekiq-in-rails-for-background-processing/ this site]):&lt;br /&gt;
# In a terminal separate from the one in which the main rails application is running, run&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec sidekiq&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Sidekiq-specific terminal will show logs and printed statements from the workers.&lt;br /&gt;
&lt;br /&gt;
NB: To create a generic sidekiq worker to test with, you could use&lt;br /&gt;
&amp;lt;pre&amp;gt;rails g sidekiq:worker SimicheckWorker&amp;lt;/pre&amp;gt;&lt;br /&gt;
to create a shell worker class.&lt;br /&gt;
&lt;br /&gt;
===== Sidekiq UI =====&lt;br /&gt;
To see which messages were being enqueued and dequeued in Sidekiq, we use the Sidekiq user interface, which can be accessed via the &amp;lt;code&amp;gt;/sidekiq&amp;lt;/code&amp;gt; route of the application.&lt;br /&gt;
[[File:Sidekiq-ui.png|950px|The Sidekiq UI]]&lt;br /&gt;
&lt;br /&gt;
==== SimicheckWorker Test ====&lt;br /&gt;
To enqueue a Simicheck job:&lt;br /&gt;
# Edit an assignment.&lt;br /&gt;
# Select the &amp;lt;code&amp;gt;Use simicheck?&amp;lt;/code&amp;gt; box.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Simicheck Delay&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (or to a nonzero value to observe a delay).&lt;br /&gt;
# Set the SimiCheck Similarity Threshold to a nonzero value.&lt;br /&gt;
# Ensure the Late Policy is set to &amp;lt;code&amp;gt;--None--&amp;lt;/code&amp;gt; under the Due Dates tab. If there is a late policy set, per pre-existing code, the enqueued SimicheckWorker job will be deleted and will not appear in the Sidekiq UI (unless it is dequeued quickly, before the code can delete the jobs in the queue).&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Save&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Observe a Simicheck Worker job enqueued and dequeued in the Sidekiq UI.&lt;br /&gt;
&lt;br /&gt;
[[File:Enqueue-simicheck-job.png|500px|How to Enqueue a Simicheck Worker Job]]&lt;br /&gt;
&lt;br /&gt;
[[File:simicheck-job-enqueued.png|950px|How to Enqueue a Simicheck Worker Job]]&lt;br /&gt;
&lt;br /&gt;
==== MailWorker and DropOustandingReviews Test ====&lt;br /&gt;
The Mail Worker sends out notifications to students if the due date of an assignment is changed. Drop Outstanding Reviews Worker drops all reviews that had not been worked on before the due date was changed. These both can be tested together, as when an assignment with a review is updated, Sidekiq should queue both the jobs for Mail Worker and Drop Outstanding Reviews Worker. To test these:&lt;br /&gt;
# Log into Expertiza as an instructor&lt;br /&gt;
# Navigate to '''Manage'''&amp;gt;'''Assignments''' in the navigation&lt;br /&gt;
# Click the plus button in the top right corner on the '''Manage Assignments''' and create an assignment with default settings. Make sure when creating the assignment to go to the '''Due Dates''' tab and assign due dates for both the assignment and the review. &lt;br /&gt;
# Assign student7613 to the assignment you created by clicking the person with the plus icon in the icons next to the assignment on the '''Manage Assignments''' page. &lt;br /&gt;
&lt;br /&gt;
At this point, we realized we need to alter the code to test if the code was properly queuing the Mail Worker because the current if statement to add items to the delayed queue required that it have a late policy. However, the late policy code is not currently working. Thus, in the &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; model file, we edited the following code:&lt;br /&gt;
&lt;br /&gt;
[[File:Change_late_policy.png|950px|Late policy code to alter]]&lt;br /&gt;
&lt;br /&gt;
We removed &amp;lt;code&amp;gt;and has_late_policy&amp;lt;/code&amp;gt; so &amp;lt;code&amp;gt;add_delayed_queue&amp;lt;/code&amp;gt; can run even without late policies being implemented. After saving this file, we started up Expertiza again.&lt;br /&gt;
&amp;lt;ol start=&amp;quot;5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Go to the assignment that student7613 had been assigned to &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Edit the assignment, go to the due dates tab, and change the due date on the review to be a day ahead of its current due date, and press save. The assignment due date must be changed to a time at least an hour ahead of the current time for the reminder to be sent. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; To ensure that the assignments are now queued on Sidekiq, visit the Sidekiq UI by going to [Expertiza VCL URL]/sidekiq. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Upon arriving on this page, verify that the jobs added to the queue were correct by clicking to '''Scheduled'''. After arriving on this page, you should see something like the following: &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Sidekiq-jobs.png|950px|Sidekiq jobs]]&lt;br /&gt;
&lt;br /&gt;
The job '''MailWorker''' that had been queued successfully shows that our refactoring of Mail Worker had worked properly and the Mail Worker was operational. The job '''DropOutstandingReviewsWorker''' showed that our refactoring of Drop Outstanding Reviews Worker had also been done correctly.&lt;br /&gt;
&lt;br /&gt;
=== Automated Tests ===&lt;br /&gt;
&lt;br /&gt;
The following tests were added to test the workers:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;test different workers&amp;quot; do&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when MailWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      MailWorker.perform_in(42.minutes, 1, &amp;quot;review&amp;quot;, &amp;quot;2021-10-27 00:00:01&amp;quot;)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when SimicheckWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      SimicheckWorker.perform_in(42.minutes, 1)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when DropOutstandingReviewsWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      DropOutstandingReviewsWorker.perform_in(42.minutes, 1, &amp;quot;review&amp;quot;, &amp;quot;2021-10-27 00:00:01&amp;quot;)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140177</id>
		<title>CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140177"/>
		<updated>2021-10-27T01:44:21Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq’s queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
&lt;br /&gt;
=== Previous Setup ===&lt;br /&gt;
Initial work can be found [https://expertiza.csc.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task here].&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/expertiza/expertiza/pull/1245/files pull request] was found to be reasonable and working. The method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; has:&lt;br /&gt;
{| class=wikitable style=text-align:right&lt;br /&gt;
|+ Metrics for &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method&lt;br /&gt;
|-&lt;br /&gt;
! Metric !! Current Value !! Limit&lt;br /&gt;
|-&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
| 15 || 5&lt;br /&gt;
|-&lt;br /&gt;
! Cyclomatic Complexity&lt;br /&gt;
| 8 || 6&lt;br /&gt;
|-&lt;br /&gt;
! Assignment Branch Condition size&lt;br /&gt;
| 22.93 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Perceived complexity&lt;br /&gt;
| 10 || 7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Previous pull request also has duplicated commit messages and the commits need to be squashed.&lt;br /&gt;
&lt;br /&gt;
Files involved (some changed should not have been changed):&lt;br /&gt;
* app/controllers/assignments_controller.rb&lt;br /&gt;
* app/mailers/mail_worker.rb&lt;br /&gt;
* app/models/assignment_form.rb&lt;br /&gt;
* config/sidekiq.yml&lt;br /&gt;
* spec/models/assignment_form_spec.rb&lt;br /&gt;
* spec/sidekiq_mail_worker_spec.rb&lt;br /&gt;
* spec/spec_helper.rb&lt;br /&gt;
&lt;br /&gt;
There are minor styling issues such as missing or trailing whitespaces, lines that are too long, extra empty line, unused arguments.&lt;br /&gt;
&lt;br /&gt;
=== Problem Statement ===&lt;br /&gt;
&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq's queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method perform() to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
The project was partially merged.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
What needs to be done:  &lt;br /&gt;
Feedback from the previous team (E1835) is:&lt;br /&gt;
Code in pull request seems pretty reasonable.  Some concerns wrt. naming functions, but otherwise reviewers seem to agree that the code is good.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
Your pull request has many duplicated commit messages. Please try to &amp;lt;code&amp;gt;squash&amp;lt;/code&amp;gt; similar commits.&lt;br /&gt;
And using meaningful commit messages later.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should commit changes to the DB schema (&amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt;) only if you have created new DB migrations.&lt;br /&gt;
Please double check your code. If you did not aim to change the DB, please revert the DB schema changes. ***** Important, try not to change the DB.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should not change &amp;lt;code&amp;gt;rails_helper.rb&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;spec_helper.rb&amp;lt;/code&amp;gt; file; please revert these changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The previous team’s code needs a refactor in some places, though the actual function of it seems solid. It is very possible that in the three years since this code has been worked on, more mailer functionality has been added. There are other teams this semester working on mailer code as well. Try to keep your code as contained and simple as possible, so that merging these projects is possible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Summary of Work Needed ==&lt;br /&gt;
After discussing with our project mentor and Dr. Gehringer, we determined the main tasks to be the following:&lt;br /&gt;
# Refactor the single Sidekiq worker into multiple workers&lt;br /&gt;
# Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type&lt;br /&gt;
# Update and add unit tests according to the above changes&lt;br /&gt;
# Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected&lt;br /&gt;
# Code cleanup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Refactor the single Sidekiq worker into multiple workers ===&lt;br /&gt;
Previously there was only a single worker class that handled all types of jobs. Its top-level method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; looked like the following.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def perform(assignment_id, deadline_type, due_at)&lt;br /&gt;
    self.assignment_id = assignment_id&lt;br /&gt;
    self.deadline_type = deadline_type&lt;br /&gt;
    self.due_at = due_at&lt;br /&gt;
&lt;br /&gt;
    assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
    participant_mails = find_participant_emails&lt;br /&gt;
&lt;br /&gt;
    if %w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck].include?(self.deadline_type)&lt;br /&gt;
      drop_one_member_topics if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot; &amp;amp;&amp;amp; assignment.team_assignment&lt;br /&gt;
      drop_outstanding_reviews if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;&lt;br /&gt;
      perform_simicheck_comparisons(self.assignment_id) if self.deadline_type == &amp;quot;compare_files_with_simicheck&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      # Can we rename deadline_type(metareview) to &amp;quot;teammate review&amp;quot;. If, yes then we donot need this if clause below!&lt;br /&gt;
      deadlineText = if self.deadline_type == &amp;quot;metareview&amp;quot;&lt;br /&gt;
                       &amp;quot;teammate review&amp;quot;&lt;br /&gt;
                     else&lt;br /&gt;
                       self.deadline_type&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      email_reminder(participant_mails, deadlineText) unless participant_mails.empty?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The processing was different depending on the &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;s in&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
did not lead to an email reminder being sent, but they were still handled in this &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
To make the code more manageable and easier to follow, it made sense to break up the responsibilities of this single &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class into multiple workers:&lt;br /&gt;
* &amp;lt;code&amp;gt;SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
All three workers extended an &amp;quot;abstract class&amp;quot; called &amp;lt;code&amp;gt;Worker&amp;lt;/code&amp;gt; that contained the Sidekiq-related &amp;lt;code&amp;gt;include&amp;lt;/code&amp;gt; and the queue name to which all jobs would be sent.&lt;br /&gt;
&lt;br /&gt;
For simplicity, we still had all new workers continue to use a single queue, which we renamed from &amp;lt;code&amp;gt;mailers&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;jobs&amp;lt;/code&amp;gt;. A future improvement could divide these jobs to go to multiple different queues if needed.&lt;br /&gt;
&lt;br /&gt;
=== Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type ===&lt;br /&gt;
It was decided that code used for dropping one member or two member teams from topics would never need to be implemented in the Expertiza website. Thus, we removed all code related to the drop_one_member_topics method within the Expertiza beta. This involved removing the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; function from &amp;lt;code&amp;gt;drop_outstanding_reviews_mail_worker.rb&amp;lt;/code&amp;gt;, now renamed &amp;lt;code&amp;gt;drop_outstanding_reviews_worker.rb&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; method was called from the &amp;lt;code&amp;gt;prepare_data&amp;lt;/code&amp;gt; method, which was then called by the Sidekiq method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; so we removed this call. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; was also referenced in &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; using &amp;lt;code&amp;gt;add_delayed_job&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method and in &amp;lt;code&amp;gt;delayed_mailer.html.erb&amp;lt;/code&amp;gt; as an option for the handler so both of these code snippets were removed as well.&lt;br /&gt;
&lt;br /&gt;
=== Code Cleanup ===&lt;br /&gt;
Smaller improvements done while implementing the main tasks included:&lt;br /&gt;
* Using ActiveSupport::Duration objects in order to calculate the minutes and seconds related to the dequeue times&lt;br /&gt;
* Refactoring the time calculations for the dequeue times to the DueDate class&lt;br /&gt;
* Correcting the parameters passed to the workers, which were previously incorrect. As an example:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_delayed_job(_assignment, deadline_type, due_date, min_left)&lt;br /&gt;
    delayed_job_id = MailWorker.perform_in(min_left * 60, due_date.parent_id, deadline_type, due_date.due_at)&lt;br /&gt;
    delayed_job_id&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first parameter after the time delay must be assignment ID, and &amp;lt;code&amp;gt;due_date.parent_id&amp;lt;/code&amp;gt; is not an assignment ID.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Removing whitespace issues reported by codeclimate&lt;br /&gt;
* Refactoring all variable names to be in snake_case&lt;br /&gt;
* Removing identical blocks of code&lt;br /&gt;
* Adding method comments to make methods more understandable&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Unit Tests ===&lt;br /&gt;
In order to properly test that our refactoring had worked properly, we found that we would have to add in multiple tests to account for our new methods as well as refactor old tests to work with the changes that we had made.&lt;br /&gt;
&lt;br /&gt;
For every worker, we have added a test case in the &amp;lt;code&amp;gt;spec/workers/sidekiq_mail_worker_spec.rb&amp;lt;/code&amp;gt; file: one each for MailWorker, SimicheckWorker, DropOutstandingReviewsWorker.&lt;br /&gt;
&lt;br /&gt;
Further, we moved methods &amp;lt;code&amp;gt;find_min_from_now_duration&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;due_date.rb&amp;lt;/code&amp;gt;. Along with that we introduced some methods to make it easier to understand the conversions and values that are being set.&lt;br /&gt;
&lt;br /&gt;
=== Functional Tests ===&lt;br /&gt;
We decided that functional testing would need to be done by manually checking to see if Sidekiq tasks were queued as expected when changes to assignments were made. The three important functional tests that we decided needed to be verified were that the Simicheck Worker was queuing, the Mail Worker was queueing, and the Drop Outstanding Reviews Worker was queuing. These could be considered verified under the condition that the '''When''' field, '''Job''' field, and '''Arguments''' field in the Sidekiq view all came out as expected.&lt;br /&gt;
&lt;br /&gt;
=== Considering Edge Cases and Other Possibilities ===&lt;br /&gt;
&lt;br /&gt;
== Implementing Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Update and add unit tests according to the refactoring changes made  ===&lt;br /&gt;
&lt;br /&gt;
The following tests were added according to the methods we moved and created:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#find_min_from_now_duration&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between due_date and now&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 11, 11).in_time_zone)&lt;br /&gt;
      due_at = Time.parse(DateTime.new(2021, 10, 20, 12, 12, 12).in_time_zone.to_s(:db))&lt;br /&gt;
      expect(DueDate.find_min_from_now_duration(due_at)).to eq(61)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_dequeue_time_as_seconds_duration_from_now&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between now and dequeue of job in seconds&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 00, 00).in_time_zone)&lt;br /&gt;
      due_at = DateTime.new(2021, 10, 20, 12, 00, 00)&lt;br /&gt;
      delay_duration = 1.hour&lt;br /&gt;
      assignment_id = create(:assignment, staggered_deadline: true, name: &amp;quot;testassignment&amp;quot;).id&lt;br /&gt;
      due_date = create(:topic_due_date, deadline_type: @deadline_type,&lt;br /&gt;
                                         submission_allowed_id: @deadline_right, review_allowed_id: @deadline_right,&lt;br /&gt;
                                         review_of_review_allowed_id: @deadline_right, due_at: due_at, parent_id: assignment_id)&lt;br /&gt;
      expect(DueDate.get_dequeue_time_as_seconds_duration_from_now(due_date, delay_duration)).to eq(7200)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected ===&lt;br /&gt;
==== Sidekiq setup ====&lt;br /&gt;
In order to test the Sidekiq workers, we needed to run Sidekiq (steps were obtained from [https://tudip.com/blog-post/how-to-use-sidekiq-in-rails-for-background-processing/ this site]):&lt;br /&gt;
# In a terminal separate from the one in which the main rails application is running, run&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec sidekiq&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Sidekiq-specific terminal will show logs and printed statements from the workers.&lt;br /&gt;
&lt;br /&gt;
NB: To create a generic sidekiq worker to test with, you could use&lt;br /&gt;
&amp;lt;pre&amp;gt;rails g sidekiq:worker SimicheckWorker&amp;lt;/pre&amp;gt;&lt;br /&gt;
to create a shell worker class.&lt;br /&gt;
&lt;br /&gt;
==== SimicheckWorker Test ====&lt;br /&gt;
To enqueue a Simicheck job:&lt;br /&gt;
# Edit an assignment.&lt;br /&gt;
# Select the &amp;lt;code&amp;gt;Use simicheck?&amp;lt;/code&amp;gt; box.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Simicheck Delay&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (or to a nonzero value to observe a delay).&lt;br /&gt;
# Set the SimiCheck Similarity Threshold to a nonzero value.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Save&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Observe a Simicheck Worker job enqueued and dequeued in the Sidekiq UI.&lt;br /&gt;
&lt;br /&gt;
[[File:Enqueue-simicheck-job.png|500px|How to Enqueue a Simicheck Worker Job]]&lt;br /&gt;
&lt;br /&gt;
==== MailWorker and DropOustandingReviews Test ====&lt;br /&gt;
The Mail Worker sends out notifications to students if the due date of an assignment is changed. Drop Outstanding Reviews Worker drops all reviews that had not been worked on before the due date was changed. These both can be tested together, as when an assignment with a review is updated, Sidekiq should queue both the jobs for Mail Worker and Drop Outstanding Reviews Worker. To test these:&lt;br /&gt;
# Log into Expertiza as an instructor&lt;br /&gt;
# Navigate to '''Manage'''&amp;gt;'''Assignments''' in the navigation&lt;br /&gt;
# Click the plus button in the top right corner on the '''Manage Assignments''' and create an assignment with default settings. Make sure when creating the assignment to go to the '''Due Dates''' tab and assign due dates for both the assignment and the review. &lt;br /&gt;
# Assign student7613 to the assignment you created by clicking the person with the plus icon in the icons next to the assignment on the '''Manage Assignments''' page. &lt;br /&gt;
&lt;br /&gt;
At this point, we realized we need to alter the code to test if the code was properly queuing the Mail Worker because the current if statement to add items to the delayed queue required that it have a late policy. However, the late policy code is not currently working. Thus, in the &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; model file, we edited the following code:&lt;br /&gt;
&lt;br /&gt;
[[File:Change_late_policy.png|950px|Late policy code to alter]]&lt;br /&gt;
&lt;br /&gt;
We removed &amp;lt;code&amp;gt;and has_late_policy&amp;lt;/code&amp;gt; so &amp;lt;code&amp;gt;add_delayed_queue&amp;lt;/code&amp;gt; can run even without late policies being implemented. After saving this file, we started up Expertiza again.&lt;br /&gt;
&amp;lt;ol start=&amp;quot;5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Go to the assignment that student7613 had been assigned to &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Edit the assignment, go to the due dates tab, and change the due date on the review to be a day ahead of its current due date, and press save. The assignment due date must be changed to a time at least an hour ahead of the current time for the reminder to be sent. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; To ensure that the assignments are now queued on Sidekiq, visit the Sidekiq UI by going to [Expertiza VCL URL]/sidekiq. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Upon arriving on this page, verify that the jobs added to the queue were correct by clicking to '''Scheduled'''. After arriving on this page, you should see something like the following: &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Sidekiq-jobs.png|950px|Sidekiq jobs]]&lt;br /&gt;
&lt;br /&gt;
The job '''MailWorker''' that had been queued successfully shows that our refactoring of Mail Worker had worked properly and the Mail Worker was operational. The job '''DropOutstandingReviewsWorker''' showed that our refactoring of Drop Outstanding Reviews Worker had also been done correctly.&lt;br /&gt;
&lt;br /&gt;
==== Automated Tests ====&lt;br /&gt;
&lt;br /&gt;
The following tests were added to test the workers:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;test different workers&amp;quot; do&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when MailWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      MailWorker.perform_in(42.minutes, 1, &amp;quot;review&amp;quot;, &amp;quot;2021-10-27 00:00:01&amp;quot;)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when SimicheckWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      SimicheckWorker.perform_in(42.minutes, 1)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when DropOutstandingReviewsWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      DropOutstandingReviewsWorker.perform_in(42.minutes, 1, &amp;quot;review&amp;quot;, &amp;quot;2021-10-27 00:00:01&amp;quot;)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sidekiq UI ===&lt;br /&gt;
To see which messages were being enqueued and dequeued in Sidekiq, we use the Sidekiq user interface, which can be accessed via the &amp;lt;code&amp;gt;/sidekiq&amp;lt;/code&amp;gt; route of the application.&lt;br /&gt;
[[File:Sidekiq-ui.png|950px|The Sidekiq UI]]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140176</id>
		<title>CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140176"/>
		<updated>2021-10-27T01:43:25Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Update and add unit tests according to the refactoring changes made */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq’s queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
&lt;br /&gt;
=== Previous Setup ===&lt;br /&gt;
Initial work can be found [https://expertiza.csc.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task here].&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/expertiza/expertiza/pull/1245/files pull request] was found to be reasonable and working. The method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; has:&lt;br /&gt;
{| class=wikitable style=text-align:right&lt;br /&gt;
|+ Metrics for &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method&lt;br /&gt;
|-&lt;br /&gt;
! Metric !! Current Value !! Limit&lt;br /&gt;
|-&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
| 15 || 5&lt;br /&gt;
|-&lt;br /&gt;
! Cyclomatic Complexity&lt;br /&gt;
| 8 || 6&lt;br /&gt;
|-&lt;br /&gt;
! Assignment Branch Condition size&lt;br /&gt;
| 22.93 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Perceived complexity&lt;br /&gt;
| 10 || 7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Previous pull request also has duplicated commit messages and the commits need to be squashed.&lt;br /&gt;
&lt;br /&gt;
Files involved (some changed should not have been changed):&lt;br /&gt;
* app/controllers/assignments_controller.rb&lt;br /&gt;
* app/mailers/mail_worker.rb&lt;br /&gt;
* app/models/assignment_form.rb&lt;br /&gt;
* config/sidekiq.yml&lt;br /&gt;
* spec/models/assignment_form_spec.rb&lt;br /&gt;
* spec/sidekiq_mail_worker_spec.rb&lt;br /&gt;
* spec/spec_helper.rb&lt;br /&gt;
&lt;br /&gt;
There are minor styling issues such as missing or trailing whitespaces, lines that are too long, extra empty line, unused arguments.&lt;br /&gt;
&lt;br /&gt;
=== Problem Statement ===&lt;br /&gt;
&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq's queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method perform() to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
The project was partially merged.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
What needs to be done:  &lt;br /&gt;
Feedback from the previous team (E1835) is:&lt;br /&gt;
Code in pull request seems pretty reasonable.  Some concerns wrt. naming functions, but otherwise reviewers seem to agree that the code is good.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
Your pull request has many duplicated commit messages. Please try to &amp;lt;code&amp;gt;squash&amp;lt;/code&amp;gt; similar commits.&lt;br /&gt;
And using meaningful commit messages later.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should commit changes to the DB schema (&amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt;) only if you have created new DB migrations.&lt;br /&gt;
Please double check your code. If you did not aim to change the DB, please revert the DB schema changes. ***** Important, try not to change the DB.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should not change &amp;lt;code&amp;gt;rails_helper.rb&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;spec_helper.rb&amp;lt;/code&amp;gt; file; please revert these changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The previous team’s code needs a refactor in some places, though the actual function of it seems solid. It is very possible that in the three years since this code has been worked on, more mailer functionality has been added. There are other teams this semester working on mailer code as well. Try to keep your code as contained and simple as possible, so that merging these projects is possible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Summary of Work Needed ==&lt;br /&gt;
After discussing with our project mentor and Dr. Gehringer, we determined the main tasks to be the following:&lt;br /&gt;
# Refactor the single Sidekiq worker into multiple workers&lt;br /&gt;
# Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type&lt;br /&gt;
# Update and add unit tests according to the above changes&lt;br /&gt;
# Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected&lt;br /&gt;
# Code cleanup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Refactor the single Sidekiq worker into multiple workers ===&lt;br /&gt;
Previously there was only a single worker class that handled all types of jobs. Its top-level method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; looked like the following.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def perform(assignment_id, deadline_type, due_at)&lt;br /&gt;
    self.assignment_id = assignment_id&lt;br /&gt;
    self.deadline_type = deadline_type&lt;br /&gt;
    self.due_at = due_at&lt;br /&gt;
&lt;br /&gt;
    assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
    participant_mails = find_participant_emails&lt;br /&gt;
&lt;br /&gt;
    if %w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck].include?(self.deadline_type)&lt;br /&gt;
      drop_one_member_topics if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot; &amp;amp;&amp;amp; assignment.team_assignment&lt;br /&gt;
      drop_outstanding_reviews if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;&lt;br /&gt;
      perform_simicheck_comparisons(self.assignment_id) if self.deadline_type == &amp;quot;compare_files_with_simicheck&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      # Can we rename deadline_type(metareview) to &amp;quot;teammate review&amp;quot;. If, yes then we donot need this if clause below!&lt;br /&gt;
      deadlineText = if self.deadline_type == &amp;quot;metareview&amp;quot;&lt;br /&gt;
                       &amp;quot;teammate review&amp;quot;&lt;br /&gt;
                     else&lt;br /&gt;
                       self.deadline_type&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      email_reminder(participant_mails, deadlineText) unless participant_mails.empty?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The processing was different depending on the &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;s in&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
did not lead to an email reminder being sent, but they were still handled in this &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
To make the code more manageable and easier to follow, it made sense to break up the responsibilities of this single &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class into multiple workers:&lt;br /&gt;
* &amp;lt;code&amp;gt;SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
All three workers extended an &amp;quot;abstract class&amp;quot; called &amp;lt;code&amp;gt;Worker&amp;lt;/code&amp;gt; that contained the Sidekiq-related &amp;lt;code&amp;gt;include&amp;lt;/code&amp;gt; and the queue name to which all jobs would be sent.&lt;br /&gt;
&lt;br /&gt;
For simplicity, we still had all new workers continue to use a single queue, which we renamed from &amp;lt;code&amp;gt;mailers&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;jobs&amp;lt;/code&amp;gt;. A future improvement could divide these jobs to go to multiple different queues if needed.&lt;br /&gt;
&lt;br /&gt;
=== Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type ===&lt;br /&gt;
It was decided that code used for dropping one member or two member teams from topics would never need to be implemented in the Expertiza website. Thus, we removed all code related to the drop_one_member_topics method within the Expertiza beta. This involved removing the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; function from &amp;lt;code&amp;gt;drop_outstanding_reviews_mail_worker.rb&amp;lt;/code&amp;gt;, now renamed &amp;lt;code&amp;gt;drop_outstanding_reviews_worker.rb&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; method was called from the &amp;lt;code&amp;gt;prepare_data&amp;lt;/code&amp;gt; method, which was then called by the Sidekiq method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; so we removed this call. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; was also referenced in &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; using &amp;lt;code&amp;gt;add_delayed_job&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method and in &amp;lt;code&amp;gt;delayed_mailer.html.erb&amp;lt;/code&amp;gt; as an option for the handler so both of these code snippets were removed as well.&lt;br /&gt;
&lt;br /&gt;
=== Code Cleanup ===&lt;br /&gt;
Smaller improvements done while implementing the main tasks included:&lt;br /&gt;
* Using ActiveSupport::Duration objects in order to calculate the minutes and seconds related to the dequeue times&lt;br /&gt;
* Refactoring the time calculations for the dequeue times to the DueDate class&lt;br /&gt;
* Correcting the parameters passed to the workers, which were previously incorrect. As an example:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_delayed_job(_assignment, deadline_type, due_date, min_left)&lt;br /&gt;
    delayed_job_id = MailWorker.perform_in(min_left * 60, due_date.parent_id, deadline_type, due_date.due_at)&lt;br /&gt;
    delayed_job_id&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first parameter after the time delay must be assignment ID, and &amp;lt;code&amp;gt;due_date.parent_id&amp;lt;/code&amp;gt; is not an assignment ID.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Removing whitespace issues reported by codeclimate&lt;br /&gt;
* Refactoring all variable names to be in snake_case&lt;br /&gt;
* Removing identical blocks of code&lt;br /&gt;
* Adding method comments to make methods more understandable&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Unit Tests ===&lt;br /&gt;
In order to properly test that our refactoring had worked properly, we found that we would have to add in multiple tests to account for our new methods as well as refactor old tests to work with the changes that we had made.&lt;br /&gt;
&lt;br /&gt;
For every worker, we have added a test case in the &amp;lt;code&amp;gt;spec/workers/sidekiq_mail_worker_spec.rb&amp;lt;/code&amp;gt; file: one each for MailWorker, SimicheckWorker, DropOutstandingReviewsWorker.&lt;br /&gt;
&lt;br /&gt;
Further, we moved methods &amp;lt;code&amp;gt;find_min_from_now_duration&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;due_date.rb&amp;lt;/code&amp;gt;. Along with that we introduced some methods to make it easier to understand the conversions and values that are being set.&lt;br /&gt;
&lt;br /&gt;
=== Functional Tests ===&lt;br /&gt;
We decided that functional testing would need to be done by manually checking to see if Sidekiq tasks were queued as expected when changes to assignments were made. The three important functional tests that we decided needed to be verified were that the Simicheck Worker was queuing, the Mail Worker was queueing, and the Drop Outstanding Reviews Worker was queuing. These could be considered verified under the condition that the '''When''' field, '''Job''' field, and '''Arguments''' field in the Sidekiq view all came out as expected.&lt;br /&gt;
&lt;br /&gt;
=== Considering Edge Cases and Other Possibilities ===&lt;br /&gt;
&lt;br /&gt;
== Implementing Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Update and add unit tests according to the refactoring changes made  ===&lt;br /&gt;
&lt;br /&gt;
The following tests were added according to the methods we moved and created:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#find_min_from_now_duration&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between due_date and now&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 11, 11).in_time_zone)&lt;br /&gt;
      due_at = Time.parse(DateTime.new(2021, 10, 20, 12, 12, 12).in_time_zone.to_s(:db))&lt;br /&gt;
      expect(DueDate.find_min_from_now_duration(due_at)).to eq(61)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_dequeue_time_as_seconds_duration_from_now&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between now and dequeue of job in seconds&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 00, 00).in_time_zone)&lt;br /&gt;
      due_at = DateTime.new(2021, 10, 20, 12, 00, 00)&lt;br /&gt;
      delay_duration = 1.hour&lt;br /&gt;
      assignment_id = create(:assignment, staggered_deadline: true, name: &amp;quot;testassignment&amp;quot;).id&lt;br /&gt;
      due_date = create(:topic_due_date, deadline_type: @deadline_type,&lt;br /&gt;
                                         submission_allowed_id: @deadline_right, review_allowed_id: @deadline_right,&lt;br /&gt;
                                         review_of_review_allowed_id: @deadline_right, due_at: due_at, parent_id: assignment_id)&lt;br /&gt;
      expect(DueDate.get_dequeue_time_as_seconds_duration_from_now(due_date, delay_duration)).to eq(7200)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected ===&lt;br /&gt;
==== Sidekiq setup ====&lt;br /&gt;
In order to test the Sidekiq workers, we needed to run Sidekiq (steps were obtained from [https://tudip.com/blog-post/how-to-use-sidekiq-in-rails-for-background-processing/ this site]):&lt;br /&gt;
# In a terminal separate from the one in which the main rails application is running, run&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec sidekiq&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Sidekiq-specific terminal will show logs and printed statements from the workers.&lt;br /&gt;
&lt;br /&gt;
NB: To create a generic sidekiq worker to test with, you could use&lt;br /&gt;
&amp;lt;pre&amp;gt;rails g sidekiq:worker SimicheckWorker&amp;lt;/pre&amp;gt;&lt;br /&gt;
to create a shell worker class.&lt;br /&gt;
&lt;br /&gt;
==== SimicheckWorker Test ====&lt;br /&gt;
To enqueue a Simicheck job:&lt;br /&gt;
# Edit an assignment.&lt;br /&gt;
# Select the &amp;lt;code&amp;gt;Use simicheck?&amp;lt;/code&amp;gt; box.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Simicheck Delay&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (or to a nonzero value to observe a delay).&lt;br /&gt;
# Set the SimiCheck Similarity Threshold to a nonzero value.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Save&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Observe a Simicheck Worker job enqueued and dequeued in the Sidekiq UI.&lt;br /&gt;
&lt;br /&gt;
[[File:Enqueue-simicheck-job.png|500px|How to Enqueue a Simicheck Worker Job]]&lt;br /&gt;
&lt;br /&gt;
==== MailWorker and DropOustandingReviews Test ====&lt;br /&gt;
The Mail Worker sends out notifications to students if the due date of an assignment is changed. Drop Outstanding Reviews Worker drops all reviews that had not been worked on before the due date was changed. These both can be tested together, as when an assignment with a review is updated, Sidekiq should queue both the jobs for Mail Worker and Drop Outstanding Reviews Worker. To test these:&lt;br /&gt;
# Log into Expertiza as an instructor&lt;br /&gt;
# Navigate to '''Manage'''&amp;gt;'''Assignments''' in the navigation&lt;br /&gt;
# Click the plus button in the top right corner on the '''Manage Assignments''' and create an assignment with default settings. Make sure when creating the assignment to go to the '''Due Dates''' tab and assign due dates for both the assignment and the review. &lt;br /&gt;
# Assign student7613 to the assignment you created by clicking the person with the plus icon in the icons next to the assignment on the '''Manage Assignments''' page. &lt;br /&gt;
&lt;br /&gt;
At this point, we realized we need to alter the code to test if the code was properly queuing the Mail Worker because the current if statement to add items to the delayed queue required that it have a late policy. However, the late policy code is not currently working. Thus, in the &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; model file, we edited the following code:&lt;br /&gt;
&lt;br /&gt;
[[File:Change_late_policy.png|950px|Late policy code to alter]]&lt;br /&gt;
&lt;br /&gt;
We removed &amp;lt;code&amp;gt;and has_late_policy&amp;lt;/code&amp;gt; so &amp;lt;code&amp;gt;add_delayed_queue&amp;lt;/code&amp;gt; can run even without late policies being implemented. After saving this file, we started up Expertiza again.&lt;br /&gt;
&amp;lt;ol start=&amp;quot;5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Go to the assignment that student7613 had been assigned to &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Edit the assignment, go to the due dates tab, and change the due date on the review to be a day ahead of its current due date, and press save. The assignment due date must be changed to a time at least an hour ahead of the current time for the reminder to be sent. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; To ensure that the assignments are now queued on Sidekiq, visit the Sidekiq UI by going to [Expertiza VCL URL]/sidekiq. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Upon arriving on this page, verify that the jobs added to the queue were correct by clicking to '''Scheduled'''. After arriving on this page, you should see something like the following: &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Sidekiq-jobs.png|950px|Sidekiq jobs]]&lt;br /&gt;
&lt;br /&gt;
The job '''MailWorker''' that had been queued successfully shows that our refactoring of Mail Worker had worked properly and the Mail Worker was operational. The job '''DropOutstandingReviewsWorker''' showed that our refactoring of Drop Outstanding Reviews Worker had also been done correctly.&lt;br /&gt;
&lt;br /&gt;
=== Sidekiq UI ===&lt;br /&gt;
To see which messages were being enqueued and dequeued in Sidekiq, we use the Sidekiq user interface, which can be accessed via the &amp;lt;code&amp;gt;/sidekiq&amp;lt;/code&amp;gt; route of the application.&lt;br /&gt;
[[File:Sidekiq-ui.png|950px|The Sidekiq UI]]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140174</id>
		<title>CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140174"/>
		<updated>2021-10-27T01:36:19Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Update and add unit tests according to the refactoring changes made */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq’s queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
&lt;br /&gt;
=== Previous Setup ===&lt;br /&gt;
Initial work can be found [https://expertiza.csc.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task here].&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/expertiza/expertiza/pull/1245/files pull request] was found to be reasonable and working. The method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; has:&lt;br /&gt;
{| class=wikitable style=text-align:right&lt;br /&gt;
|+ Metrics for &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method&lt;br /&gt;
|-&lt;br /&gt;
! Metric !! Current Value !! Limit&lt;br /&gt;
|-&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
| 15 || 5&lt;br /&gt;
|-&lt;br /&gt;
! Cyclomatic Complexity&lt;br /&gt;
| 8 || 6&lt;br /&gt;
|-&lt;br /&gt;
! Assignment Branch Condition size&lt;br /&gt;
| 22.93 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Perceived complexity&lt;br /&gt;
| 10 || 7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Previous pull request also has duplicated commit messages and the commits need to be squashed.&lt;br /&gt;
&lt;br /&gt;
Files involved (some changed should not have been changed):&lt;br /&gt;
* app/controllers/assignments_controller.rb&lt;br /&gt;
* app/mailers/mail_worker.rb&lt;br /&gt;
* app/models/assignment_form.rb&lt;br /&gt;
* config/sidekiq.yml&lt;br /&gt;
* spec/models/assignment_form_spec.rb&lt;br /&gt;
* spec/sidekiq_mail_worker_spec.rb&lt;br /&gt;
* spec/spec_helper.rb&lt;br /&gt;
&lt;br /&gt;
There are minor styling issues such as missing or trailing whitespaces, lines that are too long, extra empty line, unused arguments.&lt;br /&gt;
&lt;br /&gt;
=== Problem Statement ===&lt;br /&gt;
&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq's queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method perform() to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
The project was partially merged.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
What needs to be done:  &lt;br /&gt;
Feedback from the previous team (E1835) is:&lt;br /&gt;
Code in pull request seems pretty reasonable.  Some concerns wrt. naming functions, but otherwise reviewers seem to agree that the code is good.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
Your pull request has many duplicated commit messages. Please try to &amp;lt;code&amp;gt;squash&amp;lt;/code&amp;gt; similar commits.&lt;br /&gt;
And using meaningful commit messages later.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should commit changes to the DB schema (&amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt;) only if you have created new DB migrations.&lt;br /&gt;
Please double check your code. If you did not aim to change the DB, please revert the DB schema changes. ***** Important, try not to change the DB.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should not change &amp;lt;code&amp;gt;rails_helper.rb&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;spec_helper.rb&amp;lt;/code&amp;gt; file; please revert these changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The previous team’s code needs a refactor in some places, though the actual function of it seems solid. It is very possible that in the three years since this code has been worked on, more mailer functionality has been added. There are other teams this semester working on mailer code as well. Try to keep your code as contained and simple as possible, so that merging these projects is possible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Summary of Work Needed ==&lt;br /&gt;
After discussing with our project mentor and Dr. Gehringer, we determined the main tasks to be the following:&lt;br /&gt;
# Refactor the single Sidekiq worker into multiple workers&lt;br /&gt;
# Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type&lt;br /&gt;
# Update and add unit tests according to the above changes&lt;br /&gt;
# Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected&lt;br /&gt;
# Code cleanup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Refactor the single Sidekiq worker into multiple workers ===&lt;br /&gt;
Previously there was only a single worker class that handled all types of jobs. Its top-level method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; looked like the following.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def perform(assignment_id, deadline_type, due_at)&lt;br /&gt;
    self.assignment_id = assignment_id&lt;br /&gt;
    self.deadline_type = deadline_type&lt;br /&gt;
    self.due_at = due_at&lt;br /&gt;
&lt;br /&gt;
    assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
    participant_mails = find_participant_emails&lt;br /&gt;
&lt;br /&gt;
    if %w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck].include?(self.deadline_type)&lt;br /&gt;
      drop_one_member_topics if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot; &amp;amp;&amp;amp; assignment.team_assignment&lt;br /&gt;
      drop_outstanding_reviews if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;&lt;br /&gt;
      perform_simicheck_comparisons(self.assignment_id) if self.deadline_type == &amp;quot;compare_files_with_simicheck&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      # Can we rename deadline_type(metareview) to &amp;quot;teammate review&amp;quot;. If, yes then we donot need this if clause below!&lt;br /&gt;
      deadlineText = if self.deadline_type == &amp;quot;metareview&amp;quot;&lt;br /&gt;
                       &amp;quot;teammate review&amp;quot;&lt;br /&gt;
                     else&lt;br /&gt;
                       self.deadline_type&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      email_reminder(participant_mails, deadlineText) unless participant_mails.empty?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The processing was different depending on the &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;s in&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
did not lead to an email reminder being sent, but they were still handled in this &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
To make the code more manageable and easier to follow, it made sense to break up the responsibilities of this single &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class into multiple workers:&lt;br /&gt;
* &amp;lt;code&amp;gt;SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
All three workers extended an &amp;quot;abstract class&amp;quot; called &amp;lt;code&amp;gt;Worker&amp;lt;/code&amp;gt; that contained the Sidekiq-related &amp;lt;code&amp;gt;include&amp;lt;/code&amp;gt; and the queue name to which all jobs would be sent.&lt;br /&gt;
&lt;br /&gt;
For simplicity, we still had all new workers continue to use a single queue, which we renamed from &amp;lt;code&amp;gt;mailers&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;jobs&amp;lt;/code&amp;gt;. A future improvement could divide these jobs to go to multiple different queues if needed.&lt;br /&gt;
&lt;br /&gt;
=== Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type ===&lt;br /&gt;
It was decided that code used for dropping one member or two member teams from topics would never need to be implemented in the Expertiza website. Thus, we removed all code related to the drop_one_member_topics method within the Expertiza beta. This involved removing the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; function from &amp;lt;code&amp;gt;drop_outstanding_reviews_mail_worker.rb&amp;lt;/code&amp;gt;, now renamed &amp;lt;code&amp;gt;drop_outstanding_reviews_worker.rb&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; method was called from the &amp;lt;code&amp;gt;prepare_data&amp;lt;/code&amp;gt; method, which was then called by the Sidekiq method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; so we removed this call. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; was also referenced in &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; using &amp;lt;code&amp;gt;add_delayed_job&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method and in &amp;lt;code&amp;gt;delayed_mailer.html.erb&amp;lt;/code&amp;gt; as an option for the handler so both of these code snippets were removed as well.&lt;br /&gt;
&lt;br /&gt;
=== Code Cleanup ===&lt;br /&gt;
Smaller improvements done while implementing the main tasks included:&lt;br /&gt;
* Using ActiveSupport::Duration objects in order to calculate the minutes and seconds related to the dequeue times&lt;br /&gt;
* Refactoring the time calculations for the dequeue times to the DueDate class&lt;br /&gt;
* Correcting the parameters passed to the workers, which were previously incorrect. As an example:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_delayed_job(_assignment, deadline_type, due_date, min_left)&lt;br /&gt;
    delayed_job_id = MailWorker.perform_in(min_left * 60, due_date.parent_id, deadline_type, due_date.due_at)&lt;br /&gt;
    delayed_job_id&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first parameter after the time delay must be assignment ID, and &amp;lt;code&amp;gt;due_date.parent_id&amp;lt;/code&amp;gt; is not an assignment ID.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Removing whitespace issues reported by codeclimate&lt;br /&gt;
* Refactoring all variable names to be in snake_case&lt;br /&gt;
* Removing identical blocks of code&lt;br /&gt;
* Adding method comments to make methods more understandable&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Unit Tests ===&lt;br /&gt;
In order to properly test that our refactoring had worked properly, we found that we would have to add in multiple tests to account for our new methods as well as refactor old tests to work with the changes that we had made.&lt;br /&gt;
&lt;br /&gt;
For every worker, we have added a test case in the &amp;lt;code&amp;gt;spec/workers/sidekiq_mail_worker_spec.rb&amp;lt;/code&amp;gt; file: one each for MailWorker, SimicheckWorker, DropOutstandingReviewsWorker.&lt;br /&gt;
&lt;br /&gt;
Further, we moved methods &amp;lt;code&amp;gt;find_min_from_now_duration&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;due_date.rb&amp;lt;/code&amp;gt;. Along with that we introduced some methods to make it easier to understand the conversions and values that are being set.&lt;br /&gt;
&lt;br /&gt;
=== Functional Tests ===&lt;br /&gt;
We decided that functional testing would need to be done by manually checking to see if Sidekiq tasks were queued as expected when changes to assignments were made. The three important functional tests that we decided needed to be verified were that the Simicheck Worker was queuing, the Mail Worker was queueing, and the Drop Outstanding Reviews Worker was queuing. These could be considered verified under the condition that the '''When''' field, '''Job''' field, and '''Arguments''' field in the Sidekiq view all came out as expected.&lt;br /&gt;
&lt;br /&gt;
=== Considering Edge Cases and Other Possibilities ===&lt;br /&gt;
&lt;br /&gt;
== Implementing Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Update and add unit tests according to the refactoring changes made  ===&lt;br /&gt;
&lt;br /&gt;
The following tests were added:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe &amp;quot;test different workers&amp;quot; do&lt;br /&gt;
  it &amp;quot;should increase the size of queue by 1 when MailWorker is used&amp;quot; do&lt;br /&gt;
    Sidekiq::Testing.fake!&lt;br /&gt;
    MailWorker.perform_in(42.minutes, 1, &amp;quot;review&amp;quot;, &amp;quot;2021-10-27 00:00:01&amp;quot;)&lt;br /&gt;
    queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
    expect(queue.size).to eq(1)&lt;br /&gt;
    queue.clear&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;should increase the size of queue by 1 when SimicheckWorker is used&amp;quot; do&lt;br /&gt;
    Sidekiq::Testing.fake!&lt;br /&gt;
    SimicheckWorker.perform_in(42.minutes, 1)&lt;br /&gt;
    queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
    expect(queue.size).to eq(1)&lt;br /&gt;
    queue.clear&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;should increase the size of queue by 1 when DropOutstandingReviewsWorker is used&amp;quot; do&lt;br /&gt;
    Sidekiq::Testing.fake!&lt;br /&gt;
    DropOutstandingReviewsWorker.perform_in(42.minutes, 1, &amp;quot;review&amp;quot;, &amp;quot;2021-10-27 00:00:01&amp;quot;)&lt;br /&gt;
    queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
    expect(queue.size).to eq(1)&lt;br /&gt;
    queue.clear&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected ===&lt;br /&gt;
==== Sidekiq setup ====&lt;br /&gt;
In order to test the Sidekiq workers, a few steps were needed to set up the workers and run Sidekiq (steps were obtained from [https://tudip.com/blog-post/how-to-use-sidekiq-in-rails-for-background-processing/ this site]):&lt;br /&gt;
# Initialize three new workers, each having one of the three new worker types:&lt;br /&gt;
## &amp;lt;code&amp;gt;rails g sidekiq:worker SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
## &amp;lt;code&amp;gt;rails g sidekiq:worker DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
## &amp;lt;code&amp;gt;rails g sidekiq:worker MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
# In a terminal separate from the one in which the main rails application is running, run&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec sidekiq&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Sidekiq-specific terminal will show logs and printed statements from the workers.&lt;br /&gt;
&lt;br /&gt;
==== SimicheckWorker Test ====&lt;br /&gt;
To enqueue a Simicheck job:&lt;br /&gt;
# Edit an assignment.&lt;br /&gt;
# Select the &amp;lt;code&amp;gt;Use simicheck?&amp;lt;/code&amp;gt; box.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Simicheck Delay&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (or to a nonzero value to observe a delay).&lt;br /&gt;
# Set the SimiCheck Similarity Threshold to a nonzero value.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Save&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Observe a Simicheck Worker job enqueued and dequeued in the Sidekiq UI.&lt;br /&gt;
&lt;br /&gt;
[[File:Enqueue-simicheck-job.png|500px|How to Enqueue a Simicheck Worker Job]]&lt;br /&gt;
&lt;br /&gt;
==== MailWorker and DropOustandingReviews Test ====&lt;br /&gt;
The Mail Worker sends out notifications to students if the due date of an assignment is changed. Drop Outstanding Reviews Worker drops all reviews that had not been worked on before the due date was changed. These both can be tested together, as when an assignment with a review is updated, Sidekiq should queue both the jobs for Mail Worker and Drop Outstanding Reviews Worker. To test these:&lt;br /&gt;
# Log into Expertiza as an instructor&lt;br /&gt;
# Navigate to '''Manage'''&amp;gt;'''Assignments''' in the navigation&lt;br /&gt;
# Click the plus button in the top right corner on the '''Manage Assignments''' and create an assignment with default settings. Make sure when creating the assignment to go to the '''Due Dates''' tab and assign due dates for both the assignment and the review. &lt;br /&gt;
# Assign student7613 to the assignment you created by clicking the person with the plus icon in the icons next to the assignment on the '''Manage Assignments''' page. &lt;br /&gt;
&lt;br /&gt;
At this point, we realized we need to alter the code to test if the code was properly queuing the Mail Worker because the current if statement to add items to the delayed queue required that it have a late policy. However, the late policy code is not currently working. Thus, in the &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; model file, we edited the following code:&lt;br /&gt;
&lt;br /&gt;
[[File:Change_late_policy.png|950px|Late policy code to alter]]&lt;br /&gt;
&lt;br /&gt;
We removed &amp;lt;code&amp;gt;and has_late_policy&amp;lt;/code&amp;gt; so &amp;lt;code&amp;gt;add_delayed_queue&amp;lt;/code&amp;gt; can run even without late policies being implemented. After saving this file, we started up Expertiza again.&lt;br /&gt;
&amp;lt;ol start=&amp;quot;5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Go to the assignment that student7613 had been assigned to &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Edit the assignment, go to the due dates tab, and change the due date on the review to be a day ahead of its current due date, and press save. The assignment due date must be changed to a time at least an hour ahead of the current time for the reminder to be sent. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; To ensure that the assignments are now queued on Sidekiq, visit the Sidekiq UI by going to [Expertiza VCL URL]/sidekiq. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Upon arriving on this page, verify that the jobs added to the queue were correct by clicking to '''Scheduled'''. After arriving on this page, you should see something like the following: &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Sidekiq-jobs.png|950px|Sidekiq jobs]]&lt;br /&gt;
&lt;br /&gt;
The job '''MailWorker''' that had been queued successfully shows that our refactoring of Mail Worker had worked properly and the Mail Worker was operational. The job '''DropOutstandingReviewsWorker''' showed that our refactoring of Drop Outstanding Reviews Worker had also been done correctly.&lt;br /&gt;
&lt;br /&gt;
=== Sidekiq UI ===&lt;br /&gt;
To see which messages were being enqueued and dequeued in Sidekiq, we use the Sidekiq user interface, which can be accessed via the &amp;lt;code&amp;gt;/sidekiq&amp;lt;/code&amp;gt; route of the application.&lt;br /&gt;
[[File:Sidekiq-ui.png|950px|The Sidekiq UI]]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140173</id>
		<title>CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140173"/>
		<updated>2021-10-27T01:34:47Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Unit Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq’s queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
&lt;br /&gt;
=== Previous Setup ===&lt;br /&gt;
Initial work can be found [https://expertiza.csc.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task here].&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/expertiza/expertiza/pull/1245/files pull request] was found to be reasonable and working. The method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; has:&lt;br /&gt;
{| class=wikitable style=text-align:right&lt;br /&gt;
|+ Metrics for &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method&lt;br /&gt;
|-&lt;br /&gt;
! Metric !! Current Value !! Limit&lt;br /&gt;
|-&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
| 15 || 5&lt;br /&gt;
|-&lt;br /&gt;
! Cyclomatic Complexity&lt;br /&gt;
| 8 || 6&lt;br /&gt;
|-&lt;br /&gt;
! Assignment Branch Condition size&lt;br /&gt;
| 22.93 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Perceived complexity&lt;br /&gt;
| 10 || 7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Previous pull request also has duplicated commit messages and the commits need to be squashed.&lt;br /&gt;
&lt;br /&gt;
Files involved (some changed should not have been changed):&lt;br /&gt;
* app/controllers/assignments_controller.rb&lt;br /&gt;
* app/mailers/mail_worker.rb&lt;br /&gt;
* app/models/assignment_form.rb&lt;br /&gt;
* config/sidekiq.yml&lt;br /&gt;
* spec/models/assignment_form_spec.rb&lt;br /&gt;
* spec/sidekiq_mail_worker_spec.rb&lt;br /&gt;
* spec/spec_helper.rb&lt;br /&gt;
&lt;br /&gt;
There are minor styling issues such as missing or trailing whitespaces, lines that are too long, extra empty line, unused arguments.&lt;br /&gt;
&lt;br /&gt;
=== Problem Statement ===&lt;br /&gt;
&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq's queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method perform() to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
The project was partially merged.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
What needs to be done:  &lt;br /&gt;
Feedback from the previous team (E1835) is:&lt;br /&gt;
Code in pull request seems pretty reasonable.  Some concerns wrt. naming functions, but otherwise reviewers seem to agree that the code is good.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
Your pull request has many duplicated commit messages. Please try to &amp;lt;code&amp;gt;squash&amp;lt;/code&amp;gt; similar commits.&lt;br /&gt;
And using meaningful commit messages later.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should commit changes to the DB schema (&amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt;) only if you have created new DB migrations.&lt;br /&gt;
Please double check your code. If you did not aim to change the DB, please revert the DB schema changes. ***** Important, try not to change the DB.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should not change &amp;lt;code&amp;gt;rails_helper.rb&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;spec_helper.rb&amp;lt;/code&amp;gt; file; please revert these changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The previous team’s code needs a refactor in some places, though the actual function of it seems solid. It is very possible that in the three years since this code has been worked on, more mailer functionality has been added. There are other teams this semester working on mailer code as well. Try to keep your code as contained and simple as possible, so that merging these projects is possible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Summary of Work Needed ==&lt;br /&gt;
After discussing with our project mentor and Dr. Gehringer, we determined the main tasks to be the following:&lt;br /&gt;
# Refactor the single Sidekiq worker into multiple workers&lt;br /&gt;
# Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type&lt;br /&gt;
# Update and add unit tests according to the above changes&lt;br /&gt;
# Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected&lt;br /&gt;
# Code cleanup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Refactor the single Sidekiq worker into multiple workers ===&lt;br /&gt;
Previously there was only a single worker class that handled all types of jobs. Its top-level method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; looked like the following.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def perform(assignment_id, deadline_type, due_at)&lt;br /&gt;
    self.assignment_id = assignment_id&lt;br /&gt;
    self.deadline_type = deadline_type&lt;br /&gt;
    self.due_at = due_at&lt;br /&gt;
&lt;br /&gt;
    assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
    participant_mails = find_participant_emails&lt;br /&gt;
&lt;br /&gt;
    if %w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck].include?(self.deadline_type)&lt;br /&gt;
      drop_one_member_topics if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot; &amp;amp;&amp;amp; assignment.team_assignment&lt;br /&gt;
      drop_outstanding_reviews if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;&lt;br /&gt;
      perform_simicheck_comparisons(self.assignment_id) if self.deadline_type == &amp;quot;compare_files_with_simicheck&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      # Can we rename deadline_type(metareview) to &amp;quot;teammate review&amp;quot;. If, yes then we donot need this if clause below!&lt;br /&gt;
      deadlineText = if self.deadline_type == &amp;quot;metareview&amp;quot;&lt;br /&gt;
                       &amp;quot;teammate review&amp;quot;&lt;br /&gt;
                     else&lt;br /&gt;
                       self.deadline_type&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      email_reminder(participant_mails, deadlineText) unless participant_mails.empty?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The processing was different depending on the &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;s in&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
did not lead to an email reminder being sent, but they were still handled in this &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
To make the code more manageable and easier to follow, it made sense to break up the responsibilities of this single &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class into multiple workers:&lt;br /&gt;
* &amp;lt;code&amp;gt;SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
All three workers extended an &amp;quot;abstract class&amp;quot; called &amp;lt;code&amp;gt;Worker&amp;lt;/code&amp;gt; that contained the Sidekiq-related &amp;lt;code&amp;gt;include&amp;lt;/code&amp;gt; and the queue name to which all jobs would be sent.&lt;br /&gt;
&lt;br /&gt;
For simplicity, we still had all new workers continue to use a single queue, which we renamed from &amp;lt;code&amp;gt;mailers&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;jobs&amp;lt;/code&amp;gt;. A future improvement could divide these jobs to go to multiple different queues if needed.&lt;br /&gt;
&lt;br /&gt;
=== Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type ===&lt;br /&gt;
It was decided that code used for dropping one member or two member teams from topics would never need to be implemented in the Expertiza website. Thus, we removed all code related to the drop_one_member_topics method within the Expertiza beta. This involved removing the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; function from &amp;lt;code&amp;gt;drop_outstanding_reviews_mail_worker.rb&amp;lt;/code&amp;gt;, now renamed &amp;lt;code&amp;gt;drop_outstanding_reviews_worker.rb&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; method was called from the &amp;lt;code&amp;gt;prepare_data&amp;lt;/code&amp;gt; method, which was then called by the Sidekiq method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; so we removed this call. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; was also referenced in &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; using &amp;lt;code&amp;gt;add_delayed_job&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method and in &amp;lt;code&amp;gt;delayed_mailer.html.erb&amp;lt;/code&amp;gt; as an option for the handler so both of these code snippets were removed as well.&lt;br /&gt;
&lt;br /&gt;
=== Code Cleanup ===&lt;br /&gt;
Smaller improvements done while implementing the main tasks included:&lt;br /&gt;
* Using ActiveSupport::Duration objects in order to calculate the minutes and seconds related to the dequeue times&lt;br /&gt;
* Refactoring the time calculations for the dequeue times to the DueDate class&lt;br /&gt;
* Correcting the parameters passed to the workers, which were previously incorrect. As an example:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_delayed_job(_assignment, deadline_type, due_date, min_left)&lt;br /&gt;
    delayed_job_id = MailWorker.perform_in(min_left * 60, due_date.parent_id, deadline_type, due_date.due_at)&lt;br /&gt;
    delayed_job_id&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first parameter after the time delay must be assignment ID, and &amp;lt;code&amp;gt;due_date.parent_id&amp;lt;/code&amp;gt; is not an assignment ID.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Removing whitespace issues reported by codeclimate&lt;br /&gt;
* Refactoring all variable names to be in snake_case&lt;br /&gt;
* Removing identical blocks of code&lt;br /&gt;
* Adding method comments to make methods more understandable&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Unit Tests ===&lt;br /&gt;
In order to properly test that our refactoring had worked properly, we found that we would have to add in multiple tests to account for our new methods as well as refactor old tests to work with the changes that we had made.&lt;br /&gt;
&lt;br /&gt;
For every worker, we have added a test case in the &amp;lt;code&amp;gt;spec/workers/sidekiq_mail_worker_spec.rb&amp;lt;/code&amp;gt; file: one each for MailWorker, SimicheckWorker, DropOutstandingReviewsWorker.&lt;br /&gt;
&lt;br /&gt;
Further, we moved methods &amp;lt;code&amp;gt;find_min_from_now_duration&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;due_date.rb&amp;lt;/code&amp;gt;. Along with that we introduced some methods to make it easier to understand the conversions and values that are being set.&lt;br /&gt;
&lt;br /&gt;
=== Functional Tests ===&lt;br /&gt;
We decided that functional testing would need to be done by manually checking to see if Sidekiq tasks were queued as expected when changes to assignments were made. The three important functional tests that we decided needed to be verified were that the Simicheck Worker was queuing, the Mail Worker was queueing, and the Drop Outstanding Reviews Worker was queuing. These could be considered verified under the condition that the '''When''' field, '''Job''' field, and '''Arguments''' field in the Sidekiq view all came out as expected.&lt;br /&gt;
&lt;br /&gt;
=== Considering Edge Cases and Other Possibilities ===&lt;br /&gt;
&lt;br /&gt;
== Implementing Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Update and add unit tests according to the refactoring changes made  ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected ===&lt;br /&gt;
==== Sidekiq setup ====&lt;br /&gt;
In order to test the Sidekiq workers, a few steps were needed to set up the workers and run Sidekiq (steps were obtained from [https://tudip.com/blog-post/how-to-use-sidekiq-in-rails-for-background-processing/ this site]):&lt;br /&gt;
# Initialize three new workers, each having one of the three new worker types:&lt;br /&gt;
## &amp;lt;code&amp;gt;rails g sidekiq:worker SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
## &amp;lt;code&amp;gt;rails g sidekiq:worker DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
## &amp;lt;code&amp;gt;rails g sidekiq:worker MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
# In a terminal separate from the one in which the main rails application is running, run&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec sidekiq&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Sidekiq-specific terminal will show logs and printed statements from the workers.&lt;br /&gt;
&lt;br /&gt;
==== SimicheckWorker Test ====&lt;br /&gt;
To enqueue a Simicheck job:&lt;br /&gt;
# Edit an assignment.&lt;br /&gt;
# Select the &amp;lt;code&amp;gt;Use simicheck?&amp;lt;/code&amp;gt; box.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Simicheck Delay&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (or to a nonzero value to observe a delay).&lt;br /&gt;
# Set the SimiCheck Similarity Threshold to a nonzero value.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Save&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Observe a Simicheck Worker job enqueued and dequeued in the Sidekiq UI.&lt;br /&gt;
&lt;br /&gt;
[[File:Enqueue-simicheck-job.png|500px|How to Enqueue a Simicheck Worker Job]]&lt;br /&gt;
&lt;br /&gt;
==== MailWorker and DropOustandingReviews Test ====&lt;br /&gt;
The Mail Worker sends out notifications to students if the due date of an assignment is changed. Drop Outstanding Reviews Worker drops all reviews that had not been worked on before the due date was changed. These both can be tested together, as when an assignment with a review is updated, Sidekiq should queue both the jobs for Mail Worker and Drop Outstanding Reviews Worker. To test these:&lt;br /&gt;
# Log into Expertiza as an instructor&lt;br /&gt;
# Navigate to '''Manage'''&amp;gt;'''Assignments''' in the navigation&lt;br /&gt;
# Click the plus button in the top right corner on the '''Manage Assignments''' and create an assignment with default settings. Make sure when creating the assignment to go to the '''Due Dates''' tab and assign due dates for both the assignment and the review. &lt;br /&gt;
# Assign student7613 to the assignment you created by clicking the person with the plus icon in the icons next to the assignment on the '''Manage Assignments''' page. &lt;br /&gt;
&lt;br /&gt;
At this point, we realized we need to alter the code to test if the code was properly queuing the Mail Worker because the current if statement to add items to the delayed queue required that it have a late policy. However, the late policy code is not currently working. Thus, in the &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; model file, we edited the following code:&lt;br /&gt;
&lt;br /&gt;
[[File:Change_late_policy.png|950px|Late policy code to alter]]&lt;br /&gt;
&lt;br /&gt;
We removed &amp;lt;code&amp;gt;and has_late_policy&amp;lt;/code&amp;gt; so &amp;lt;code&amp;gt;add_delayed_queue&amp;lt;/code&amp;gt; can run even without late policies being implemented. After saving this file, we started up Expertiza again.&lt;br /&gt;
&amp;lt;ol start=&amp;quot;5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Go to the assignment that student7613 had been assigned to &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Edit the assignment, go to the due dates tab, and change the due date on the review to be a day ahead of its current due date, and press save. The assignment due date must be changed to a time at least an hour ahead of the current time for the reminder to be sent. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; To ensure that the assignments are now queued on Sidekiq, visit the Sidekiq UI by going to [Expertiza VCL URL]/sidekiq. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Upon arriving on this page, verify that the jobs added to the queue were correct by clicking to '''Scheduled'''. After arriving on this page, you should see something like the following: &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Sidekiq-jobs.png|950px|Sidekiq jobs]]&lt;br /&gt;
&lt;br /&gt;
The job '''MailWorker''' that had been queued successfully shows that our refactoring of Mail Worker had worked properly and the Mail Worker was operational. The job '''DropOutstandingReviewsWorker''' showed that our refactoring of Drop Outstanding Reviews Worker had also been done correctly.&lt;br /&gt;
&lt;br /&gt;
=== Sidekiq UI ===&lt;br /&gt;
To see which messages were being enqueued and dequeued in Sidekiq, we use the Sidekiq user interface, which can be accessed via the &amp;lt;code&amp;gt;/sidekiq&amp;lt;/code&amp;gt; route of the application.&lt;br /&gt;
[[File:Sidekiq-ui.png|950px|The Sidekiq UI]]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140172</id>
		<title>CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=140172"/>
		<updated>2021-10-27T01:32:40Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: /* Unit Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq’s queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
&lt;br /&gt;
=== Previous Setup ===&lt;br /&gt;
Initial work can be found [https://expertiza.csc.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task here].&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/expertiza/expertiza/pull/1245/files pull request] was found to be reasonable and working. The method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; has:&lt;br /&gt;
{| class=wikitable style=text-align:right&lt;br /&gt;
|+ Metrics for &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method&lt;br /&gt;
|-&lt;br /&gt;
! Metric !! Current Value !! Limit&lt;br /&gt;
|-&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
| 15 || 5&lt;br /&gt;
|-&lt;br /&gt;
! Cyclomatic Complexity&lt;br /&gt;
| 8 || 6&lt;br /&gt;
|-&lt;br /&gt;
! Assignment Branch Condition size&lt;br /&gt;
| 22.93 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Perceived complexity&lt;br /&gt;
| 10 || 7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Previous pull request also has duplicated commit messages and the commits need to be squashed.&lt;br /&gt;
&lt;br /&gt;
Files involved (some changed should not have been changed):&lt;br /&gt;
* app/controllers/assignments_controller.rb&lt;br /&gt;
* app/mailers/mail_worker.rb&lt;br /&gt;
* app/models/assignment_form.rb&lt;br /&gt;
* config/sidekiq.yml&lt;br /&gt;
* spec/models/assignment_form_spec.rb&lt;br /&gt;
* spec/sidekiq_mail_worker_spec.rb&lt;br /&gt;
* spec/spec_helper.rb&lt;br /&gt;
&lt;br /&gt;
There are minor styling issues such as missing or trailing whitespaces, lines that are too long, extra empty line, unused arguments.&lt;br /&gt;
&lt;br /&gt;
=== Problem Statement ===&lt;br /&gt;
&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq's queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method perform() to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
The project was partially merged.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
What needs to be done:  &lt;br /&gt;
Feedback from the previous team (E1835) is:&lt;br /&gt;
Code in pull request seems pretty reasonable.  Some concerns wrt. naming functions, but otherwise reviewers seem to agree that the code is good.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
Your pull request has many duplicated commit messages. Please try to &amp;lt;code&amp;gt;squash&amp;lt;/code&amp;gt; similar commits.&lt;br /&gt;
And using meaningful commit messages later.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should commit changes to the DB schema (&amp;lt;code&amp;gt;db/schema.rb&amp;lt;/code&amp;gt;) only if you have created new DB migrations.&lt;br /&gt;
Please double check your code. If you did not aim to change the DB, please revert the DB schema changes. ***** Important, try not to change the DB.&lt;br /&gt;
​&lt;br /&gt;
&lt;br /&gt;
You should not change &amp;lt;code&amp;gt;rails_helper.rb&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;spec_helper.rb&amp;lt;/code&amp;gt; file; please revert these changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The previous team’s code needs a refactor in some places, though the actual function of it seems solid. It is very possible that in the three years since this code has been worked on, more mailer functionality has been added. There are other teams this semester working on mailer code as well. Try to keep your code as contained and simple as possible, so that merging these projects is possible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Summary of Work Needed ==&lt;br /&gt;
After discussing with our project mentor and Dr. Gehringer, we determined the main tasks to be the following:&lt;br /&gt;
# Refactor the single Sidekiq worker into multiple workers&lt;br /&gt;
# Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type&lt;br /&gt;
# Update and add unit tests according to the above changes&lt;br /&gt;
# Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected&lt;br /&gt;
# Code cleanup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Refactor the single Sidekiq worker into multiple workers ===&lt;br /&gt;
Previously there was only a single worker class that handled all types of jobs. Its top-level method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; looked like the following.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def perform(assignment_id, deadline_type, due_at)&lt;br /&gt;
    self.assignment_id = assignment_id&lt;br /&gt;
    self.deadline_type = deadline_type&lt;br /&gt;
    self.due_at = due_at&lt;br /&gt;
&lt;br /&gt;
    assignment = Assignment.find(self.assignment_id)&lt;br /&gt;
    participant_mails = find_participant_emails&lt;br /&gt;
&lt;br /&gt;
    if %w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck].include?(self.deadline_type)&lt;br /&gt;
      drop_one_member_topics if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot; &amp;amp;&amp;amp; assignment.team_assignment&lt;br /&gt;
      drop_outstanding_reviews if self.deadline_type == &amp;quot;drop_outstanding_reviews&amp;quot;&lt;br /&gt;
      perform_simicheck_comparisons(self.assignment_id) if self.deadline_type == &amp;quot;compare_files_with_simicheck&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
      # Can we rename deadline_type(metareview) to &amp;quot;teammate review&amp;quot;. If, yes then we donot need this if clause below!&lt;br /&gt;
      deadlineText = if self.deadline_type == &amp;quot;metareview&amp;quot;&lt;br /&gt;
                       &amp;quot;teammate review&amp;quot;&lt;br /&gt;
                     else&lt;br /&gt;
                       self.deadline_type&lt;br /&gt;
      end&lt;br /&gt;
&lt;br /&gt;
      email_reminder(participant_mails, deadlineText) unless participant_mails.empty?&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The processing was different depending on the &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;deadline_type&amp;lt;/code&amp;gt;s in&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
%w[drop_one_member_topics drop_outstanding_reviews compare_files_with_simicheck]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
did not lead to an email reminder being sent, but they were still handled in this &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
To make the code more manageable and easier to follow, it made sense to break up the responsibilities of this single &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt; class into multiple workers:&lt;br /&gt;
* &amp;lt;code&amp;gt;SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
All three workers extended an &amp;quot;abstract class&amp;quot; called &amp;lt;code&amp;gt;Worker&amp;lt;/code&amp;gt; that contained the Sidekiq-related &amp;lt;code&amp;gt;include&amp;lt;/code&amp;gt; and the queue name to which all jobs would be sent.&lt;br /&gt;
&lt;br /&gt;
For simplicity, we still had all new workers continue to use a single queue, which we renamed from &amp;lt;code&amp;gt;mailers&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;jobs&amp;lt;/code&amp;gt;. A future improvement could divide these jobs to go to multiple different queues if needed.&lt;br /&gt;
&lt;br /&gt;
=== Remove all code related to the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; deadline type ===&lt;br /&gt;
It was decided that code used for dropping one member or two member teams from topics would never need to be implemented in the Expertiza website. Thus, we removed all code related to the drop_one_member_topics method within the Expertiza beta. This involved removing the &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; function from &amp;lt;code&amp;gt;drop_outstanding_reviews_mail_worker.rb&amp;lt;/code&amp;gt;, now renamed &amp;lt;code&amp;gt;drop_outstanding_reviews_worker.rb&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; method was called from the &amp;lt;code&amp;gt;prepare_data&amp;lt;/code&amp;gt; method, which was then called by the Sidekiq method &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; so we removed this call. The &amp;lt;code&amp;gt;drop_one_member_topics&amp;lt;/code&amp;gt; was also referenced in &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; using &amp;lt;code&amp;gt;add_delayed_job&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;add_to_delayed_queue&amp;lt;/code&amp;gt; method and in &amp;lt;code&amp;gt;delayed_mailer.html.erb&amp;lt;/code&amp;gt; as an option for the handler so both of these code snippets were removed as well.&lt;br /&gt;
&lt;br /&gt;
=== Code Cleanup ===&lt;br /&gt;
Smaller improvements done while implementing the main tasks included:&lt;br /&gt;
* Using ActiveSupport::Duration objects in order to calculate the minutes and seconds related to the dequeue times&lt;br /&gt;
* Refactoring the time calculations for the dequeue times to the DueDate class&lt;br /&gt;
* Correcting the parameters passed to the workers, which were previously incorrect. As an example:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def add_delayed_job(_assignment, deadline_type, due_date, min_left)&lt;br /&gt;
    delayed_job_id = MailWorker.perform_in(min_left * 60, due_date.parent_id, deadline_type, due_date.due_at)&lt;br /&gt;
    delayed_job_id&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first parameter after the time delay must be assignment ID, and &amp;lt;code&amp;gt;due_date.parent_id&amp;lt;/code&amp;gt; is not an assignment ID.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* Removing whitespace issues reported by codeclimate&lt;br /&gt;
* Refactoring all variable names to be in snake_case&lt;br /&gt;
* Removing identical blocks of code&lt;br /&gt;
* Adding method comments to make methods more understandable&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Unit Tests ===&lt;br /&gt;
In order to properly test that our refactoring had worked properly, we found that we would have to add in multiple tests to account for our new methods as well as refactor old tests to work with the changes that we had made.&lt;br /&gt;
&lt;br /&gt;
For every worker, we have added a test case in the &amp;lt;code&amp;gt;spec/workers/sidekiq_mail_worker_spec.rb&amp;lt;/code&amp;gt; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;test different workers&amp;quot; do&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when MailWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      MailWorker.perform_in(42.minutes, 1, &amp;quot;review&amp;quot;, &amp;quot;2021-10-27 00:00:01&amp;quot;)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when SimicheckWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      SimicheckWorker.perform_in(42.minutes, 1)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it &amp;quot;should increase the size of queue by 1 when DropOutstandingReviewsWorker is used&amp;quot; do&lt;br /&gt;
      Sidekiq::Testing.fake!&lt;br /&gt;
      DropOutstandingReviewsWorker.perform_in(42.minutes, 1)&lt;br /&gt;
      queue = Sidekiq::Queues[&amp;quot;jobs&amp;quot;]&lt;br /&gt;
      expect(queue.size).to eq(1)&lt;br /&gt;
      queue.clear&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Further, we moved methods &amp;lt;code&amp;gt;find_min_from_now_duration&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;due_date.rb&amp;lt;/code&amp;gt;. Along with that we introduced some methods to make it easier to understand the conversions and values that are being set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  describe &amp;quot;#find_min_from_now_duration&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between due_date and now&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 11, 11).in_time_zone)&lt;br /&gt;
      due_at = Time.parse(DateTime.new(2021, 10, 20, 12, 12, 12).in_time_zone.to_s(:db))&lt;br /&gt;
      expect(DueDate.find_min_from_now_duration(due_at)).to eq(61)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  describe &amp;quot;#get_dequeue_time_as_seconds_duration_from_now&amp;quot; do&lt;br /&gt;
    it &amp;quot;returns time difference between now and dequeue of job in seconds&amp;quot; do&lt;br /&gt;
      allow(DateTime).to receive(:now).and_return(DateTime.new(2021, 10, 20, 11, 00, 00).in_time_zone)&lt;br /&gt;
      due_at = DateTime.new(2021, 10, 20, 12, 00, 00)&lt;br /&gt;
      delay_duration = 1.hour&lt;br /&gt;
      assignment_id = create(:assignment, staggered_deadline: true, name: &amp;quot;testassignment&amp;quot;).id&lt;br /&gt;
      due_date = create(:topic_due_date, deadline_type: @deadline_type,&lt;br /&gt;
                                         submission_allowed_id: @deadline_right, review_allowed_id: @deadline_right,&lt;br /&gt;
                                         review_of_review_allowed_id: @deadline_right, due_at: due_at, parent_id: assignment_id)&lt;br /&gt;
      expect(DueDate.get_dequeue_time_as_seconds_duration_from_now(due_date, delay_duration)).to eq(7200)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Functional Tests ===&lt;br /&gt;
We decided that functional testing would need to be done by manually checking to see if Sidekiq tasks were queued as expected when changes to assignments were made. The three important functional tests that we decided needed to be verified were that the Simicheck Worker was queuing, the Mail Worker was queueing, and the Drop Outstanding Reviews Worker was queuing. These could be considered verified under the condition that the '''When''' field, '''Job''' field, and '''Arguments''' field in the Sidekiq view all came out as expected.&lt;br /&gt;
&lt;br /&gt;
=== Considering Edge Cases and Other Possibilities ===&lt;br /&gt;
&lt;br /&gt;
== Implementing Test Plan ==&lt;br /&gt;
&lt;br /&gt;
=== Update and add unit tests according to the refactoring changes made  ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Test all new worker classes to ensure Sidekiq jobs were being dequeued and run as expected ===&lt;br /&gt;
==== Sidekiq setup ====&lt;br /&gt;
In order to test the Sidekiq workers, a few steps were needed to set up the workers and run Sidekiq (steps were obtained from [https://tudip.com/blog-post/how-to-use-sidekiq-in-rails-for-background-processing/ this site]):&lt;br /&gt;
# Initialize three new workers, each having one of the three new worker types:&lt;br /&gt;
## &amp;lt;code&amp;gt;rails g sidekiq:worker SimicheckWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
## &amp;lt;code&amp;gt;rails g sidekiq:worker DropOutstandingReviewsWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
## &amp;lt;code&amp;gt;rails g sidekiq:worker MailWorker&amp;lt;/code&amp;gt;&lt;br /&gt;
# In a terminal separate from the one in which the main rails application is running, run&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bundle exec sidekiq&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This Sidekiq-specific terminal will show logs and printed statements from the workers.&lt;br /&gt;
&lt;br /&gt;
==== SimicheckWorker Test ====&lt;br /&gt;
To enqueue a Simicheck job:&lt;br /&gt;
# Edit an assignment.&lt;br /&gt;
# Select the &amp;lt;code&amp;gt;Use simicheck?&amp;lt;/code&amp;gt; box.&lt;br /&gt;
# Set &amp;lt;code&amp;gt;Simicheck Delay&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (or to a nonzero value to observe a delay).&lt;br /&gt;
# Set the SimiCheck Similarity Threshold to a nonzero value.&lt;br /&gt;
# Click &amp;lt;code&amp;gt;Save&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Observe a Simicheck Worker job enqueued and dequeued in the Sidekiq UI.&lt;br /&gt;
&lt;br /&gt;
[[File:Enqueue-simicheck-job.png|500px|How to Enqueue a Simicheck Worker Job]]&lt;br /&gt;
&lt;br /&gt;
==== MailWorker and DropOustandingReviews Test ====&lt;br /&gt;
The Mail Worker sends out notifications to students if the due date of an assignment is changed. Drop Outstanding Reviews Worker drops all reviews that had not been worked on before the due date was changed. These both can be tested together, as when an assignment with a review is updated, Sidekiq should queue both the jobs for Mail Worker and Drop Outstanding Reviews Worker. To test these:&lt;br /&gt;
# Log into Expertiza as an instructor&lt;br /&gt;
# Navigate to '''Manage'''&amp;gt;'''Assignments''' in the navigation&lt;br /&gt;
# Click the plus button in the top right corner on the '''Manage Assignments''' and create an assignment with default settings. Make sure when creating the assignment to go to the '''Due Dates''' tab and assign due dates for both the assignment and the review. &lt;br /&gt;
# Assign student7613 to the assignment you created by clicking the person with the plus icon in the icons next to the assignment on the '''Manage Assignments''' page. &lt;br /&gt;
&lt;br /&gt;
At this point, we realized we need to alter the code to test if the code was properly queuing the Mail Worker because the current if statement to add items to the delayed queue required that it have a late policy. However, the late policy code is not currently working. Thus, in the &amp;lt;code&amp;gt;assignment_form.rb&amp;lt;/code&amp;gt; model file, we edited the following code:&lt;br /&gt;
&lt;br /&gt;
[[File:Change_late_policy.png|950px|Late policy code to alter]]&lt;br /&gt;
&lt;br /&gt;
We removed &amp;lt;code&amp;gt;and has_late_policy&amp;lt;/code&amp;gt; so &amp;lt;code&amp;gt;add_delayed_queue&amp;lt;/code&amp;gt; can run even without late policies being implemented. After saving this file, we started up Expertiza again.&lt;br /&gt;
&amp;lt;ol start=&amp;quot;5&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Go to the assignment that student7613 had been assigned to &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Edit the assignment, go to the due dates tab, and change the due date on the review to be a day ahead of its current due date, and press save. The assignment due date must be changed to a time at least an hour ahead of the current time for the reminder to be sent. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; To ensure that the assignments are now queued on Sidekiq, visit the Sidekiq UI by going to [Expertiza VCL URL]/sidekiq. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Upon arriving on this page, verify that the jobs added to the queue were correct by clicking to '''Scheduled'''. After arriving on this page, you should see something like the following: &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Sidekiq-jobs.png|950px|Sidekiq jobs]]&lt;br /&gt;
&lt;br /&gt;
The job '''MailWorker''' that had been queued successfully shows that our refactoring of Mail Worker had worked properly and the Mail Worker was operational. The job '''DropOutstandingReviewsWorker''' showed that our refactoring of Drop Outstanding Reviews Worker had also been done correctly.&lt;br /&gt;
&lt;br /&gt;
=== Sidekiq UI ===&lt;br /&gt;
To see which messages were being enqueued and dequeued in Sidekiq, we use the Sidekiq user interface, which can be accessed via the &amp;lt;code&amp;gt;/sidekiq&amp;lt;/code&amp;gt; route of the application.&lt;br /&gt;
[[File:Sidekiq-ui.png|950px|The Sidekiq UI]]&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=138962</id>
		<title>CSC/ECE 517 Fall 2021 - E2144. Refactor delayed mailer and scheduled task</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2021_-_E2144._Refactor_delayed_mailer_and_scheduled_task&amp;diff=138962"/>
		<updated>2021-10-06T15:59:01Z</updated>

		<summary type="html">&lt;p&gt;Akkhadse: Wiki page for E2144&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Background ==&lt;br /&gt;
This project revolves around the Sidekiq gem for asynchronous processing of email tasks. It has a queue system to hold and then process jobs. Sidekiq’s queue replaces DelayedMailer’s queue. The previous team that worked on this also created a method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; to gather email IDs of all participants in an assignment and send them an email reminder. Some test cases exist for this work.&lt;br /&gt;
&lt;br /&gt;
=== Previous Setup ===&lt;br /&gt;
Initial work can be found [https://expertiza.csc.ncsu.edu/index.php/E1835_Refactor_delayed_mailer_and_scheduled_task here].&lt;br /&gt;
&lt;br /&gt;
Code in the [https://github.com/expertiza/expertiza/pull/1245/files pull request] was found to be reasonable and working. The method &amp;lt;code&amp;gt;perform()&amp;lt;/code&amp;gt; has:&lt;br /&gt;
{| class=wikitable style=text-align:right&lt;br /&gt;
|+ Metrics for &amp;lt;code&amp;gt;perform&amp;lt;/code&amp;gt; method&lt;br /&gt;
|-&lt;br /&gt;
! Metric !! Current Value !! Limit&lt;br /&gt;
|-&lt;br /&gt;
! Cognitive Complexity&lt;br /&gt;
| 15 || 5&lt;br /&gt;
|-&lt;br /&gt;
! Cyclomatic Complexity&lt;br /&gt;
| 8 || 6&lt;br /&gt;
|-&lt;br /&gt;
! Assignment Branch Condition size&lt;br /&gt;
| 22.93 || 15&lt;br /&gt;
|-&lt;br /&gt;
! Perceived complexity&lt;br /&gt;
| 10 || 7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Previous pull request also has duplicated commit messages and the commits need to be squashed.&lt;br /&gt;
&lt;br /&gt;
Files involved (some changed should not have been changed):&lt;br /&gt;
* app/controllers/assignments_controller.rb&lt;br /&gt;
* app/mailers/mail_worker.rb&lt;br /&gt;
* app/models/assignment_form.rb&lt;br /&gt;
* config/sidekiq.yml&lt;br /&gt;
* spec/models/assignment_form_spec.rb&lt;br /&gt;
* spec/sidekiq_mail_worker_spec.rb&lt;br /&gt;
* spec/spec_helper.rb&lt;br /&gt;
&lt;br /&gt;
There are minor styling issues such as missing or trailing whitespaces, lines that are too long, extra empty line, unused arguments.&lt;/div&gt;</summary>
		<author><name>Akkhadse</name></author>
	</entry>
</feed>