CSC/ECE 517 Spring 2017/E1730. Override-review-grader pre-sort
E1730
Deployment Link:
About Expertiza:
Expertiza is an open source peer review system. It allows students to upload their work which can then be reviewed by other students using a rubric. Instructors and graders can view the reviews and they can then assign grades to the reviewers as well the reviewee.
Problem Statement:
While grading students, a grader might want to organize reviews by sorting them by a particular metric. The only available metric was ‘Average Volume’ (number of words in the review). A new metric called ‘Overall Sentiment’ is added which is a gauge of the sentiment of the review, that is, whether the review was positive or negative. The task was to allow a grader to select a particular metric, and the view displays that metric for each review. In addition to that, the grader should be able to sort the reviews by that selected metric.
Design:
1) For each review, send a POST request to the Sentiment Analysis URL for sentiment analysis with the review as parameters.
2) Store the sentiment values in a list.
3) In the view, allow the grader to select the metric(average volume or overall sentiment) from the drop down menu.
4) The view is rendered accordingly to either show overall sentiment in the metric or the average volume
5) Using the tablesorter (jQuery) addParser method, the Metric column is sorted by the appropriate metric.
Current Implementation:
Only a single metric for sorting reviews called ‘Average Volume’ was present. The table was sortable only by that metric.
New Implementation:
The ‘Overall Sentiment’ metric is added to the system. The grader can choose between two metrics (Average volume, Overall Sentiment) and sort reviews by that metric.
Gem:
A gem called HTTParty is added which facilitates the sending of HTTP requests (GET, POST, etc.) to the web service using Ruby code.
Code Snippets:
def get_sentiment(review, first_try) if (first_try) response = HTTParty.post('http://peerlogic.csc.ncsu.edu/sentiment/analyze_reviews_bulk',:body => {"reviews"=>[review]}.to_json, :headers => { 'Content-Type' => 'application/json' }) else # Send only the first sentence of the review for sentiment analysis text = review["text"].split('.')[0] reconstructed_review = construct_sentiment_query(review["id"], text) response = HTTParty.post('http://peerlogic.csc.ncsu.edu/sentiment/analyze_reviews_bulk',:body => {"reviews"=>[reconstructed_review]}.to_json, :headers => { 'Content-Type' => 'application/json' }) end response end
The above code is used to send a POST request to the web service which returns the response(the sentiment value).
def get_sentiment_list response_list = [] @sentiment_list = [] @reviewers.each do |r| sentiment = {} review = {} review_text = Response.concatenate_all_review_comments(@id, r).join(" ") review = construct_sentiment_query(r.id, review_text) response = get_sentiment(review, true) # Retry in case of failure by sending only a single sentence for sentiment analysis. if response.code == 200 sentiment["id"] = response.parsed_response["sentiments"][0]["id"] sentiment["sentiment"] = response.parsed_response["sentiments"][0]["sentiment"] @sentiment_list<<sentiment else # Retry once in case of a failure response = get_sentiment(review, false) response_list<<response case response.code when 200 sentiment["id"] = response.parsed_response["sentiments"][0]["id"] sentiment["sentiment"] = response.parsed_response["sentiments"][0]["sentiment"] @sentiment_list<<sentiment when 404 # Error in generating sentiment from the server sentiment["id"] = review["id"] sentiment["sentiment"]="-404" @sentiment_list<<sentiment when 500...600 # Error in generating sentiment from the server sentiment["id"] = review["id"] sentiment["sentiment"]="-500" @sentiment_list<<sentiment end end end @sentiment_list end
The above code populates the @sentiment_list which is used by display_sentiment_metric in the view. Sometimes the web service fails for certain reviews. Based on the error code, we handle the reviews differently.
def display_sentiment_metric(id) hashed_sentiment = @sentiment_list.select {|sentiment| sentiment["id"] == id.to_s} value = hashed_sentiment[0]["sentiment"].to_f.round(2) metric = "Overall Sentiment: #{value}
" metric.html_safe end
The above method is used to display the sentiment value for a particular review id.
Test Plan:
Scenario 1:
Testing Tool:
RSpec
Description:
Check whether the sentiment query is not nil
require 'rails_helper'
describe 'ReviewMappingHelper', :type => :helper do describe "#construct_sentiment_query" do it "should not return nil" do expect(helper.construct_sentiment_query(1,"Text")).not_to eq(nil) end end
Scenario 2:
Testing Tool:
RSpec
Description:
Test whether the webservice does not return nil
describe "#get_sentiment" do it "should not return nil" do review = helper.construct_sentiment_query(1,"Test Review") # Test first try to get sentiment from the sentiment analysis web service expect(helper.get_sentiment(review, true)).not_to eq(nil) # Test a retry to get sentiment from the sentiment analysis web service expect(helper.get_sentiment(review, false)).not_to eq(nil) end end
Scenario 3:
Testing tool:
RSpec
Description:
Check whether the sentiment_list is populated and not nil
describe "#get_sentiment_list" do it "should not return nil" do @id=1 @assignment = Assignment.where(id: @id) @reviewers = ReviewResponseMap.review_response_report(@id, @assignment, "ReviewResponseMap", nil) expect(helper.get_sentiment_list).not_to eq(nil) end end
end
Scenario 4:
Testing tool:
RSpec
Description:
Check whether the web does not respond with a 404 error
it "should not get web response with 404 error" do review = helper.construct_sentiment_query(1,"Test Reviews to check if our Rest Client is able to reach the sentiment analysis service.") # Test first try to get sentiment from the sentiment analysis web service expect(helper.get_sentiment(review, true).code).not_to eq(404) # Test a retry to get sentiment from the sentiment analysis web service expect(helper.get_sentiment(review, true).code).not_to eq(404) end
Scenario 5:
Testing tool:
RSpec
Description:
Check whether the web service does not respond with a 500 error
it "should not get web response with 500 error" do review = helper.construct_sentiment_query(1,"Test Reviews to check if our Rest Client is able to reach the sentiment analysis service.") # Test first try to get sentiment from the sentiment analysis web service expect(helper.get_sentiment(review, true).code).not_to eq(500) # Test a retry to get sentiment from the sentiment analysis web service expect(helper.get_sentiment(review, true).code).not_to eq(500) end
Scenario 6:
Testing tool:
RSpec
Description:
Check whether the web service returns a response in JSON format
it "should return json response" do review = helper.construct_sentiment_query(1,"Test Review") # Test first try to get sentiment from the sentiment analysis web service expect(helper.get_sentiment(review, true).header['Content-Type']).to include 'application/json' # Test a retry to get sentiment from the sentiment analysis web service expect(helper.get_sentiment(review, false).header['Content-Type']).to include 'application/json' end end