Commit fd5da22491e6b145ad7b45649becd39fc995dd50
1 parent
beb3b15f
Exists in
master
and in
1 other branch
reindent test_api.rake
Showing
1 changed file
with
410 additions
and
410 deletions
Show diff stats
lib/tasks/test_api.rake
| @@ -8,8 +8,8 @@ namespace :test_api do | @@ -8,8 +8,8 @@ namespace :test_api do | ||
| 8 | true_losses = question.votes.count(:conditions => {:loser_choice_id => choice.id}) | 8 | true_losses = question.votes.count(:conditions => {:loser_choice_id => choice.id}) |
| 9 | true_wins = choice.votes.count | 9 | true_wins = choice.votes.count |
| 10 | Choice.update_counters choice.id, | 10 | Choice.update_counters choice.id, |
| 11 | - :losses => (true_losses - choice.losses), | ||
| 12 | - :wins => (true_wins - choice.wins) | 11 | + :losses => (true_losses - choice.losses), |
| 12 | + :wins => (true_wins - choice.wins) | ||
| 13 | choice.reload | 13 | choice.reload |
| 14 | choice.score = choice.compute_score | 14 | choice.score = choice.compute_score |
| 15 | choice.save(false) | 15 | choice.save(false) |
| @@ -40,7 +40,7 @@ namespace :test_api do | @@ -40,7 +40,7 @@ namespace :test_api do | ||
| 40 | end | 40 | end |
| 41 | end | 41 | end |
| 42 | 42 | ||
| 43 | - task :all => [:question_vote_consistency,:generate_density_information] | 43 | + task :all => [:question_vote_consistency,:generate_density_information] |
| 44 | 44 | ||
| 45 | desc "Ensure that all choices have 0 <= score <= 100" | 45 | desc "Ensure that all choices have 0 <= score <= 100" |
| 46 | task :verify_range_of_choices_scores => :environment do | 46 | task :verify_range_of_choices_scores => :environment do |
| @@ -73,255 +73,255 @@ namespace :test_api do | @@ -73,255 +73,255 @@ namespace :test_api do | ||
| 73 | return error_message.blank? ? [success_message, false] : [error_message, true] | 73 | return error_message.blank? ? [success_message, false] : [error_message, true] |
| 74 | end | 74 | end |
| 75 | 75 | ||
| 76 | - desc "Don't run unless you know what you are doing" | ||
| 77 | - task(:generate_lots_of_votes => :environment) do | ||
| 78 | - if Rails.env.production? | ||
| 79 | - print "You probably don't want to run this in production as it will falsify a bunch of random votes" | ||
| 80 | - end | ||
| 81 | - | ||
| 82 | - | ||
| 83 | - current_user = User.first | ||
| 84 | - 1000.times do |n| | ||
| 85 | - puts "#{n} votes completed" if n % 100 == 0 | ||
| 86 | - question = Question.find(214) # test question change as needed | ||
| 87 | - @prompt = question.catchup_choose_prompt(1).first | ||
| 88 | - @appearance = current_user.record_appearance(current_user.default_visitor, @prompt) | ||
| 89 | - | ||
| 90 | - direction = (rand(2) == 0) ? "left" : "right" | ||
| 91 | - current_user.record_vote(:prompt => @prompt, :direction => direction, :appearance_lookup => @appearance.lookup) | ||
| 92 | - end | 76 | + desc "Don't run unless you know what you are doing" |
| 77 | + task(:generate_lots_of_votes => :environment) do | ||
| 78 | + if Rails.env.production? | ||
| 79 | + print "You probably don't want to run this in production as it will falsify a bunch of random votes" | ||
| 80 | + end | ||
| 81 | + | ||
| 93 | 82 | ||
| 94 | - end | 83 | + current_user = User.first |
| 84 | + 1000.times do |n| | ||
| 85 | + puts "#{n} votes completed" if n % 100 == 0 | ||
| 86 | + question = Question.find(214) # test question change as needed | ||
| 87 | + @prompt = question.catchup_choose_prompt(1).first | ||
| 88 | + @appearance = current_user.record_appearance(current_user.default_visitor, @prompt) | ||
| 95 | 89 | ||
| 96 | - desc "Generate appearances for any votes that have no current appearance, should only need to be run once" | ||
| 97 | - task(:generate_appearances_for_existing_votes => :environment) do | ||
| 98 | - votes = Vote.all | 90 | + direction = (rand(2) == 0) ? "left" : "right" |
| 91 | + current_user.record_vote(:prompt => @prompt, :direction => direction, :appearance_lookup => @appearance.lookup) | ||
| 92 | + end | ||
| 99 | 93 | ||
| 100 | - count = 0 | ||
| 101 | - votes.each do |v| | ||
| 102 | - if v.appearance.nil? | ||
| 103 | - print "." | ||
| 104 | - a = Appearance.create(:voter_id => v.voter_id, :site_id => v.site_id, :prompt_id => v.prompt_id, :question_id => v.question_id, :created_at => v.created_at, :updated_at => v.updated_at) | ||
| 105 | - v.appearance = a | ||
| 106 | - v.save | ||
| 107 | - | ||
| 108 | - count += 1 | ||
| 109 | - end | ||
| 110 | - end | ||
| 111 | - | ||
| 112 | - print count | ||
| 113 | - end | ||
| 114 | - | ||
| 115 | - | ||
| 116 | - desc "Generate past density information" | ||
| 117 | - task(:generate_past_densities => :environment) do | ||
| 118 | - #this is not elegant, but should only be run once, so quick and dirty wins | ||
| 119 | - | ||
| 120 | - start_date = Vote.find(:all, :conditions => 'loser_choice_id IS NOT NULL', :order => :created_at, :limit => 1).first.created_at.to_date | ||
| 121 | - start_date.upto(Date.today) do |the_date| | ||
| 122 | - questions = Question.find(:all, :conditions => ['created_at < ?', the_date]) | ||
| 123 | - | ||
| 124 | - print the_date.to_s | ||
| 125 | - questions.each do |q| | ||
| 126 | - puts q.id | ||
| 127 | - relevant_choices = q.choices.find(:all, :conditions => ['created_at < ?', the_date]) | ||
| 128 | - | ||
| 129 | - seed_choices = 0 | ||
| 130 | - | ||
| 131 | - if relevant_choices == 0 | ||
| 132 | - next | ||
| 133 | - #this question had not been created yet | ||
| 134 | - end | ||
| 135 | - | ||
| 136 | - relevant_choices.each do |c| | ||
| 137 | - if !c.user_created | ||
| 138 | - seed_choices+=1 | ||
| 139 | - end | ||
| 140 | - | ||
| 141 | - end | ||
| 142 | - | ||
| 143 | - nonseed_choices = relevant_choices.size - seed_choices | ||
| 144 | - | ||
| 145 | - seed_seed_total = seed_choices **2 - seed_choices | ||
| 146 | - nonseed_nonseed_total = nonseed_choices **2 - nonseed_choices | ||
| 147 | - seed_nonseed_total = seed_choices * nonseed_choices | ||
| 148 | - nonseed_seed_total = seed_choices * nonseed_choices | ||
| 149 | - | ||
| 150 | - seed_seed_sum = 0 | ||
| 151 | - seed_nonseed_sum= 0 | ||
| 152 | - nonseed_seed_sum= 0 | ||
| 153 | - nonseed_nonseed_sum= 0 | ||
| 154 | - | ||
| 155 | - q.appearances.find_each(:conditions => ['prompt_id IS NOT NULL AND created_at < ?', the_date]) do |a| | ||
| 156 | - | ||
| 157 | - p = a.prompt | ||
| 158 | - if p.left_choice.user_created == false && p.right_choice.user_created == false | ||
| 159 | - seed_seed_sum += 1 | ||
| 160 | - elsif p.left_choice.user_created == false && p.right_choice.user_created == true | ||
| 161 | - seed_nonseed_sum += 1 | ||
| 162 | - elsif p.left_choice.user_created == true && p.right_choice.user_created == false | ||
| 163 | - nonseed_seed_sum += 1 | ||
| 164 | - elsif p.left_choice.user_created == true && p.right_choice.user_created == true | ||
| 165 | - nonseed_nonseed_sum += 1 | ||
| 166 | - end | ||
| 167 | - end | ||
| 168 | - | ||
| 169 | - densities = {} | ||
| 170 | - densities[:seed_seed] = seed_seed_sum.to_f / seed_seed_total.to_f | ||
| 171 | - densities[:seed_nonseed] = seed_nonseed_sum.to_f / seed_nonseed_total.to_f | ||
| 172 | - densities[:nonseed_seed] = nonseed_seed_sum.to_f / nonseed_seed_total.to_f | ||
| 173 | - densities[:nonseed_nonseed] = nonseed_nonseed_sum.to_f / nonseed_nonseed_total.to_f | ||
| 174 | - | ||
| 175 | - densities.each do |type, average| | ||
| 176 | - d = Density.new | ||
| 177 | - d.created_at = the_date | ||
| 178 | - d.question_id = q.id | ||
| 179 | - d.prompt_type = type.to_s | ||
| 180 | - d.value = average.nan? ? nil : average | ||
| 181 | - d.save! | ||
| 182 | - end | ||
| 183 | - | ||
| 184 | - puts "Seed_seed sum: #{seed_seed_sum}, seed_seed total num: #{seed_seed_total}" | ||
| 185 | - puts "Seed_nonseed sum: #{seed_nonseed_sum}, seed_nonseed total num: #{seed_nonseed_total}" | ||
| 186 | - puts "Nonseed_seed sum: #{nonseed_seed_sum}, nonseed_seed total num: #{nonseed_seed_total}" | ||
| 187 | - puts "Nonseed_nonseed sum: #{nonseed_nonseed_sum}, nonseed_nonseed total num: #{nonseed_nonseed_total}" | 94 | + end |
| 188 | 95 | ||
| 96 | + desc "Generate appearances for any votes that have no current appearance, should only need to be run once" | ||
| 97 | + task(:generate_appearances_for_existing_votes => :environment) do | ||
| 98 | + votes = Vote.all | ||
| 189 | 99 | ||
| 190 | - end | 100 | + count = 0 |
| 101 | + votes.each do |v| | ||
| 102 | + if v.appearance.nil? | ||
| 103 | + print "." | ||
| 104 | + a = Appearance.create(:voter_id => v.voter_id, :site_id => v.site_id, :prompt_id => v.prompt_id, :question_id => v.question_id, :created_at => v.created_at, :updated_at => v.updated_at) | ||
| 105 | + v.appearance = a | ||
| 106 | + v.save | ||
| 191 | 107 | ||
| 192 | - end | ||
| 193 | - | ||
| 194 | - end | ||
| 195 | - | ||
| 196 | - | ||
| 197 | - desc "Should only need to be run once" | ||
| 198 | - task(:generate_all_possible_prompts => :environment) do | ||
| 199 | - Question.find(:all).each do |q| | ||
| 200 | - choices = q.choices | ||
| 201 | - if q.prompts.size > choices.size**2 - choices.size | ||
| 202 | - print "ERROR: #{q.id}\n" | ||
| 203 | - next | ||
| 204 | - elsif q.prompts.size == choices.size**2 - choices.size | ||
| 205 | - print "#{q.id} has enough prompts, skipping...\n" | ||
| 206 | - next | ||
| 207 | - else | ||
| 208 | - print "#{q.id} should add #{(choices.size ** 2 - choices.size) - q.prompts.size}\n" | 108 | + count += 1 |
| 109 | + end | ||
| 110 | + end | ||
| 209 | 111 | ||
| 112 | + print count | ||
| 210 | end | 113 | end |
| 211 | - created_timestring = q.created_at.to_s(:db) | ||
| 212 | - updated_timestring = Time.now.to_s(:db) #isn't rails awesome? | ||
| 213 | - promptscount=0 | ||
| 214 | - inserts = [] | ||
| 215 | - the_prompts = Prompt.find(:all, :select => 'id, left_choice_id, right_choice_id', :conditions => {:question_id => q.id}) | ||
| 216 | - | ||
| 217 | - the_prompts_hash = {} | ||
| 218 | - the_prompts.each do |p| | ||
| 219 | - the_prompts_hash["#{p.left_choice_id},#{p.right_choice_id}"] = 1 | 114 | + |
| 115 | + | ||
| 116 | + desc "Generate past density information" | ||
| 117 | + task(:generate_past_densities => :environment) do | ||
| 118 | + #this is not elegant, but should only be run once, so quick and dirty wins | ||
| 119 | + | ||
| 120 | + start_date = Vote.find(:all, :conditions => 'loser_choice_id IS NOT NULL', :order => :created_at, :limit => 1).first.created_at.to_date | ||
| 121 | + start_date.upto(Date.today) do |the_date| | ||
| 122 | + questions = Question.find(:all, :conditions => ['created_at < ?', the_date]) | ||
| 123 | + | ||
| 124 | + print the_date.to_s | ||
| 125 | + questions.each do |q| | ||
| 126 | + puts q.id | ||
| 127 | + relevant_choices = q.choices.find(:all, :conditions => ['created_at < ?', the_date]) | ||
| 128 | + | ||
| 129 | + seed_choices = 0 | ||
| 130 | + | ||
| 131 | + if relevant_choices == 0 | ||
| 132 | + next | ||
| 133 | + #this question had not been created yet | ||
| 134 | + end | ||
| 135 | + | ||
| 136 | + relevant_choices.each do |c| | ||
| 137 | + if !c.user_created | ||
| 138 | + seed_choices+=1 | ||
| 139 | + end | ||
| 140 | + | ||
| 141 | + end | ||
| 142 | + | ||
| 143 | + nonseed_choices = relevant_choices.size - seed_choices | ||
| 144 | + | ||
| 145 | + seed_seed_total = seed_choices **2 - seed_choices | ||
| 146 | + nonseed_nonseed_total = nonseed_choices **2 - nonseed_choices | ||
| 147 | + seed_nonseed_total = seed_choices * nonseed_choices | ||
| 148 | + nonseed_seed_total = seed_choices * nonseed_choices | ||
| 149 | + | ||
| 150 | + seed_seed_sum = 0 | ||
| 151 | + seed_nonseed_sum= 0 | ||
| 152 | + nonseed_seed_sum= 0 | ||
| 153 | + nonseed_nonseed_sum= 0 | ||
| 154 | + | ||
| 155 | + q.appearances.find_each(:conditions => ['prompt_id IS NOT NULL AND created_at < ?', the_date]) do |a| | ||
| 156 | + | ||
| 157 | + p = a.prompt | ||
| 158 | + if p.left_choice.user_created == false && p.right_choice.user_created == false | ||
| 159 | + seed_seed_sum += 1 | ||
| 160 | + elsif p.left_choice.user_created == false && p.right_choice.user_created == true | ||
| 161 | + seed_nonseed_sum += 1 | ||
| 162 | + elsif p.left_choice.user_created == true && p.right_choice.user_created == false | ||
| 163 | + nonseed_seed_sum += 1 | ||
| 164 | + elsif p.left_choice.user_created == true && p.right_choice.user_created == true | ||
| 165 | + nonseed_nonseed_sum += 1 | ||
| 166 | + end | ||
| 167 | + end | ||
| 168 | + | ||
| 169 | + densities = {} | ||
| 170 | + densities[:seed_seed] = seed_seed_sum.to_f / seed_seed_total.to_f | ||
| 171 | + densities[:seed_nonseed] = seed_nonseed_sum.to_f / seed_nonseed_total.to_f | ||
| 172 | + densities[:nonseed_seed] = nonseed_seed_sum.to_f / nonseed_seed_total.to_f | ||
| 173 | + densities[:nonseed_nonseed] = nonseed_nonseed_sum.to_f / nonseed_nonseed_total.to_f | ||
| 174 | + | ||
| 175 | + densities.each do |type, average| | ||
| 176 | + d = Density.new | ||
| 177 | + d.created_at = the_date | ||
| 178 | + d.question_id = q.id | ||
| 179 | + d.prompt_type = type.to_s | ||
| 180 | + d.value = average.nan? ? nil : average | ||
| 181 | + d.save! | ||
| 182 | + end | ||
| 183 | + | ||
| 184 | + puts "Seed_seed sum: #{seed_seed_sum}, seed_seed total num: #{seed_seed_total}" | ||
| 185 | + puts "Seed_nonseed sum: #{seed_nonseed_sum}, seed_nonseed total num: #{seed_nonseed_total}" | ||
| 186 | + puts "Nonseed_seed sum: #{nonseed_seed_sum}, nonseed_seed total num: #{nonseed_seed_total}" | ||
| 187 | + puts "Nonseed_nonseed sum: #{nonseed_nonseed_sum}, nonseed_nonseed total num: #{nonseed_nonseed_total}" | ||
| 188 | + | ||
| 189 | + | ||
| 190 | + end | ||
| 191 | + | ||
| 192 | + end | ||
| 193 | + | ||
| 220 | end | 194 | end |
| 221 | 195 | ||
| 222 | - choices.each do |l| | ||
| 223 | - choices.each do |r| | ||
| 224 | - if l.id == r.id | ||
| 225 | - next | ||
| 226 | - else | ||
| 227 | - #p = the_prompts.find{|o| o.left_choice_id == l.id && o.right_choice_id == r.id} | ||
| 228 | - keystring = "#{l.id},#{r.id}" | ||
| 229 | - p = the_prompts_hash[keystring] | ||
| 230 | - if p.nil? | ||
| 231 | - inserts.push("(NULL, #{q.id}, NULL, #{l.id}, '#{created_timestring}', '#{updated_timestring}', NULL, 0, #{r.id}, NULL, NULL)") | ||
| 232 | - promptscount+=1 | 196 | + |
| 197 | + desc "Should only need to be run once" | ||
| 198 | + task(:generate_all_possible_prompts => :environment) do | ||
| 199 | + Question.find(:all).each do |q| | ||
| 200 | + choices = q.choices | ||
| 201 | + if q.prompts.size > choices.size**2 - choices.size | ||
| 202 | + print "ERROR: #{q.id}\n" | ||
| 203 | + next | ||
| 204 | + elsif q.prompts.size == choices.size**2 - choices.size | ||
| 205 | + print "#{q.id} has enough prompts, skipping...\n" | ||
| 206 | + next | ||
| 207 | + else | ||
| 208 | + print "#{q.id} should add #{(choices.size ** 2 - choices.size) - q.prompts.size}\n" | ||
| 209 | + | ||
| 210 | + end | ||
| 211 | + created_timestring = q.created_at.to_s(:db) | ||
| 212 | + updated_timestring = Time.now.to_s(:db) #isn't rails awesome? | ||
| 213 | + promptscount=0 | ||
| 214 | + inserts = [] | ||
| 215 | + the_prompts = Prompt.find(:all, :select => 'id, left_choice_id, right_choice_id', :conditions => {:question_id => q.id}) | ||
| 216 | + | ||
| 217 | + the_prompts_hash = {} | ||
| 218 | + the_prompts.each do |p| | ||
| 219 | + the_prompts_hash["#{p.left_choice_id},#{p.right_choice_id}"] = 1 | ||
| 220 | + end | ||
| 221 | + | ||
| 222 | + choices.each do |l| | ||
| 223 | + choices.each do |r| | ||
| 224 | + if l.id == r.id | ||
| 225 | + next | ||
| 226 | + else | ||
| 227 | + #p = the_prompts.find{|o| o.left_choice_id == l.id && o.right_choice_id == r.id} | ||
| 228 | + keystring = "#{l.id},#{r.id}" | ||
| 229 | + p = the_prompts_hash[keystring] | ||
| 230 | + if p.nil? | ||
| 231 | + inserts.push("(NULL, #{q.id}, NULL, #{l.id}, '#{created_timestring}', '#{updated_timestring}', NULL, 0, #{r.id}, NULL, NULL)") | ||
| 232 | + promptscount+=1 | ||
| 233 | + end | ||
| 234 | + | ||
| 235 | + end | ||
| 236 | + | ||
| 237 | + end | ||
| 238 | + end | ||
| 239 | + | ||
| 240 | + print "Added #{promptscount} to #{q.id}\n" | ||
| 241 | + sql = "INSERT INTO `prompts` (`algorithm_id`, `question_id`, `voter_id`, `left_choice_id`, `created_at`, `updated_at`, `tracking`, `votes_count`, `right_choice_id`, `active`, `randomkey`) VALUES #{inserts.join(', ')}" | ||
| 242 | + unless inserts.empty? | ||
| 243 | + ActiveRecord::Base.connection.execute(sql) | ||
| 244 | + end | ||
| 245 | + | ||
| 246 | + Question.update_counters(q.id, :prompts_count => promptscount) | ||
| 247 | + | ||
| 248 | + | ||
| 233 | end | 249 | end |
| 234 | 250 | ||
| 235 | - end | ||
| 236 | 251 | ||
| 237 | - end | ||
| 238 | - end | ||
| 239 | 252 | ||
| 240 | - print "Added #{promptscount} to #{q.id}\n" | ||
| 241 | - sql = "INSERT INTO `prompts` (`algorithm_id`, `question_id`, `voter_id`, `left_choice_id`, `created_at`, `updated_at`, `tracking`, `votes_count`, `right_choice_id`, `active`, `randomkey`) VALUES #{inserts.join(', ')}" | ||
| 242 | - unless inserts.empty? | ||
| 243 | - ActiveRecord::Base.connection.execute(sql) | ||
| 244 | end | 253 | end |
| 245 | 254 | ||
| 246 | - Question.update_counters(q.id, :prompts_count => promptscount) | ||
| 247 | - | ||
| 248 | 255 | ||
| 249 | - end | 256 | + desc "Dump votes of a question by left vs right id" |
| 257 | + task(:make_csv => :environment) do | ||
| 250 | 258 | ||
| 259 | + q = Question.find(214) | ||
| 251 | 260 | ||
| 252 | - | ||
| 253 | - end | ||
| 254 | 261 | ||
| 262 | + the_prompts = q.prompts_hash_by_choice_ids | ||
| 255 | 263 | ||
| 256 | - desc "Dump votes of a question by left vs right id" | ||
| 257 | - task(:make_csv => :environment) do | 264 | + #hash_of_choice_ids_from_left_to_right_to_votes |
| 265 | + the_hash = {} | ||
| 266 | + q.choices.each do |l| | ||
| 267 | + q.choices.each do |r| | ||
| 268 | + next if l.id == r.id | ||
| 258 | 269 | ||
| 259 | - q = Question.find(214) | 270 | + if not the_hash.has_key?(l.id) |
| 271 | + the_hash[l.id] = {} | ||
| 272 | + the_hash[l.id][l.id] = 0 | ||
| 273 | + end | ||
| 260 | 274 | ||
| 275 | + p = the_prompts["#{l.id}, #{r.id}"] | ||
| 276 | + if p.nil? | ||
| 277 | + the_hash[l.id][r.id] = 0 | ||
| 278 | + else | ||
| 279 | + the_hash[l.id][r.id] = p.appearances.size | ||
| 280 | + end | ||
| 281 | + end | ||
| 282 | + end | ||
| 261 | 283 | ||
| 262 | - the_prompts = q.prompts_hash_by_choice_ids | 284 | + the_hash.sort.each do |xval, row| |
| 285 | + rowarray = [] | ||
| 286 | + row.sort.each do |yval, cell| | ||
| 287 | + rowarray << cell | ||
| 288 | + end | ||
| 289 | + puts rowarray.join(", ") | ||
| 290 | + end | ||
| 291 | + end | ||
| 263 | 292 | ||
| 264 | - #hash_of_choice_ids_from_left_to_right_to_votes | ||
| 265 | - the_hash = {} | ||
| 266 | - q.choices.each do |l| | ||
| 267 | - q.choices.each do |r| | ||
| 268 | - next if l.id == r.id | ||
| 269 | - | ||
| 270 | - if not the_hash.has_key?(l.id) | ||
| 271 | - the_hash[l.id] = {} | ||
| 272 | - the_hash[l.id][l.id] = 0 | ||
| 273 | - end | ||
| 274 | 293 | ||
| 275 | - p = the_prompts["#{l.id}, #{r.id}"] | ||
| 276 | - if p.nil? | ||
| 277 | - the_hash[l.id][r.id] = 0 | ||
| 278 | - else | ||
| 279 | - the_hash[l.id][r.id] = p.appearances.size | ||
| 280 | - end | ||
| 281 | - end | ||
| 282 | - end | 294 | + desc "Generate density information for each question - should be run nightly" |
| 295 | + task(:generate_density_information => :environment) do | ||
| 283 | 296 | ||
| 284 | - the_hash.sort.each do |xval, row| | ||
| 285 | - rowarray = [] | ||
| 286 | - row.sort.each do |yval, cell| | ||
| 287 | - rowarray << cell | ||
| 288 | - end | ||
| 289 | - puts rowarray.join(", ") | ||
| 290 | - end | ||
| 291 | - end | 297 | + # calculating densities is expensive, so only do it for questions with new data |
| 298 | + question_ids = Vote.count(:conditions => ['date(created_at) = ?', Date.yesterday], :group => 'question_id').keys() | ||
| 292 | 299 | ||
| 300 | + Question.find(:all, :conditions => {:id => question_ids}).each do |q| | ||
| 301 | + q.save_densities! | ||
| 302 | + end | ||
| 293 | 303 | ||
| 294 | - desc "Generate density information for each question - should be run nightly" | ||
| 295 | - task(:generate_density_information => :environment) do | 304 | + # we can just copy the previous night's data for remaining questions |
| 296 | 305 | ||
| 297 | - # calculating densities is expensive, so only do it for questions with new data | ||
| 298 | - question_ids = Vote.count(:conditions => ['date(created_at) = ?', Date.yesterday], :group => 'question_id').keys() | 306 | + Question.find(:all, :conditions => ['id NOT IN (?)', question_ids]).each do |q| |
| 307 | + densities = q.densities.find(:all, :conditions => ['date(created_at) = ?', Date.yesterday]) | ||
| 299 | 308 | ||
| 300 | - Question.find(:all, :conditions => {:id => question_ids}).each do |q| | ||
| 301 | - q.save_densities! | ||
| 302 | - end | ||
| 303 | 309 | ||
| 304 | - # we can just copy the previous night's data for remaining questions | ||
| 305 | - | ||
| 306 | - Question.find(:all, :conditions => ['id NOT IN (?)', question_ids]).each do |q| | ||
| 307 | - densities = q.densities.find(:all, :conditions => ['date(created_at) = ?', Date.yesterday]) | 310 | + densities.each do |d| |
| 311 | + new_d = d.clone | ||
| 312 | + new_d.created_at = new_d.updated_at = Time.now | ||
| 313 | + new_d.save! | ||
| 314 | + end | ||
| 308 | 315 | ||
| 316 | + if densities.blank? | ||
| 317 | + #fallback in case there wasn't a successful run yesterday | ||
| 318 | + q.save_densities! | ||
| 309 | 319 | ||
| 310 | - densities.each do |d| | ||
| 311 | - new_d = d.clone | ||
| 312 | - new_d.created_at = new_d.updated_at = Time.now | ||
| 313 | - new_d.save! | ||
| 314 | - end | 320 | + end |
| 315 | 321 | ||
| 316 | - if densities.blank? | ||
| 317 | - #fallback in case there wasn't a successful run yesterday | ||
| 318 | - q.save_densities! | ||
| 319 | - | ||
| 320 | - end | 322 | + end |
| 323 | + end | ||
| 321 | 324 | ||
| 322 | - end | ||
| 323 | - end | ||
| 324 | - | ||
| 325 | desc "Description here" | 325 | desc "Description here" |
| 326 | task(:question_vote_consistency => :environment) do | 326 | task(:question_vote_consistency => :environment) do |
| 327 | questions = Question.find(:all) | 327 | questions = Question.find(:all) |
| @@ -384,7 +384,7 @@ namespace :test_api do | @@ -384,7 +384,7 @@ namespace :test_api do | ||
| 384 | end | 384 | end |
| 385 | 385 | ||
| 386 | message, error_occurred = ensure_all_votes_and_skips_have_unique_appearance | 386 | message, error_occurred = ensure_all_votes_and_skips_have_unique_appearance |
| 387 | - | 387 | + |
| 388 | if error_occurred | 388 | if error_occurred |
| 389 | errors << message | 389 | errors << message |
| 390 | else | 390 | else |
| @@ -415,9 +415,9 @@ namespace :test_api do | @@ -415,9 +415,9 @@ namespace :test_api do | ||
| 415 | email_text += " Test Passed: " + m + "\n" | 415 | email_text += " Test Passed: " + m + "\n" |
| 416 | end | 416 | end |
| 417 | end | 417 | end |
| 418 | - | 418 | + |
| 419 | puts email_text | 419 | puts email_text |
| 420 | - | 420 | + |
| 421 | if errors.empty? | 421 | if errors.empty? |
| 422 | CronMailer.deliver_info_message(CRON_EMAIL, "Test of API Vote Consistency passed", email_text) | 422 | CronMailer.deliver_info_message(CRON_EMAIL, "Test of API Vote Consistency passed", email_text) |
| 423 | else | 423 | else |
| @@ -426,34 +426,34 @@ namespace :test_api do | @@ -426,34 +426,34 @@ namespace :test_api do | ||
| 426 | 426 | ||
| 427 | end | 427 | end |
| 428 | 428 | ||
| 429 | - def check_basic_balanced_stats(question) | ||
| 430 | - error_message = "" | ||
| 431 | - success_message = "2 x Total Wins = Total Votes\n" + | ||
| 432 | - "Total Votes (wins + losses) is Even\n" + | ||
| 433 | - "Total Votes (wins + losses) = 2 x the number of vote objects that belong to the question\n" + | ||
| 434 | - "Total generated prompts on left = Total generated prompts on right" | ||
| 435 | - total_wins =0 | ||
| 436 | - total_votes =0 | ||
| 437 | - total_generated_prompts_on_left = 0 | ||
| 438 | - total_generated_prompts_on_right = 0 | ||
| 439 | - total_scores_gte_fifty= 0 | ||
| 440 | - total_scores_lte_fifty= 0 | ||
| 441 | - error_bool = false | ||
| 442 | - # votes before 2010-02-17 have null loser_choice_id therefore we | ||
| 443 | - # want to ignore some tests for any question with votes before 2010-02-17 | ||
| 444 | - question_has_votes_before_2010_02_17 = question.votes.count(:conditions => ["created_at < ?", '2010-02-17']) > 0 | ||
| 445 | - | ||
| 446 | - # reload question to make sure we have most recent data | ||
| 447 | - question.reload | ||
| 448 | - question.choices.each do |choice| | ||
| 449 | - | 429 | + def check_basic_balanced_stats(question) |
| 430 | + error_message = "" | ||
| 431 | + success_message = "2 x Total Wins = Total Votes\n" + | ||
| 432 | + "Total Votes (wins + losses) is Even\n" + | ||
| 433 | + "Total Votes (wins + losses) = 2 x the number of vote objects that belong to the question\n" + | ||
| 434 | + "Total generated prompts on left = Total generated prompts on right" | ||
| 435 | + total_wins =0 | ||
| 436 | + total_votes =0 | ||
| 437 | + total_generated_prompts_on_left = 0 | ||
| 438 | + total_generated_prompts_on_right = 0 | ||
| 439 | + total_scores_gte_fifty= 0 | ||
| 440 | + total_scores_lte_fifty= 0 | ||
| 441 | + error_bool = false | ||
| 442 | + # votes before 2010-02-17 have null loser_choice_id therefore we | ||
| 443 | + # want to ignore some tests for any question with votes before 2010-02-17 | ||
| 444 | + question_has_votes_before_2010_02_17 = question.votes.count(:conditions => ["created_at < ?", '2010-02-17']) > 0 | ||
| 445 | + | ||
| 446 | + # reload question to make sure we have most recent data | ||
| 447 | + question.reload | ||
| 448 | + question.choices.each do |choice| | ||
| 449 | + | ||
| 450 | if choice.wins | 450 | if choice.wins |
| 451 | total_wins += choice.wins | 451 | total_wins += choice.wins |
| 452 | total_votes += choice.wins | 452 | total_votes += choice.wins |
| 453 | end | 453 | end |
| 454 | 454 | ||
| 455 | if choice.losses | 455 | if choice.losses |
| 456 | - total_votes += choice.losses | 456 | + total_votes += choice.losses |
| 457 | end | 457 | end |
| 458 | 458 | ||
| 459 | total_generated_prompts_on_left += choice.prompts_on_the_left.size | 459 | total_generated_prompts_on_left += choice.prompts_on_the_left.size |
| @@ -465,16 +465,16 @@ namespace :test_api do | @@ -465,16 +465,16 @@ namespace :test_api do | ||
| 465 | delta = 0.001 | 465 | delta = 0.001 |
| 466 | 466 | ||
| 467 | if (cached_score - generated_score).abs >= delta | 467 | if (cached_score - generated_score).abs >= delta |
| 468 | - error_message += "Error! The cached_score is not equal to the calculated score for choice #{choice.id}\n" | 468 | + error_message += "Error! The cached_score is not equal to the calculated score for choice #{choice.id}\n" |
| 469 | 469 | ||
| 470 | - print "This score is wrong! #{choice.id} , Question ID: #{question.id}, #{cached_score}, #{generated_score}, updated: #{choice.updated_at}\n" | 470 | + print "This score is wrong! #{choice.id} , Question ID: #{question.id}, #{cached_score}, #{generated_score}, updated: #{choice.updated_at}\n" |
| 471 | 471 | ||
| 472 | 472 | ||
| 473 | end | 473 | end |
| 474 | 474 | ||
| 475 | if cached_score == 0.0 || cached_score == 100.0 || cached_score.nil? | 475 | if cached_score == 0.0 || cached_score == 100.0 || cached_score.nil? |
| 476 | - error_message += "Error! The cached_score for choice #{choice.id} is exactly 0 or 100, the value: #{cached_score}" | ||
| 477 | - print "Either 0 or 100 This score is wrong! #{choice.id} , Question ID: #{question.id}, #{cached_score}, #{generated_score}, updated: #{choice.updated_at}\n" | 476 | + error_message += "Error! The cached_score for choice #{choice.id} is exactly 0 or 100, the value: #{cached_score}" |
| 477 | + print "Either 0 or 100 This score is wrong! #{choice.id} , Question ID: #{question.id}, #{cached_score}, #{generated_score}, updated: #{choice.updated_at}\n" | ||
| 478 | end | 478 | end |
| 479 | 479 | ||
| 480 | unless question_has_votes_before_2010_02_17 | 480 | unless question_has_votes_before_2010_02_17 |
| @@ -493,10 +493,10 @@ namespace :test_api do | @@ -493,10 +493,10 @@ namespace :test_api do | ||
| 493 | end | 493 | end |
| 494 | 494 | ||
| 495 | if (choice.wins != choice.votes.count) | 495 | if (choice.wins != choice.votes.count) |
| 496 | - error_message += "Error!: Cached choice wins != actual choice wins for choice #{choice.id}\n" | ||
| 497 | - error_bool= true | 496 | + error_message += "Error!: Cached choice wins != actual choice wins for choice #{choice.id}\n" |
| 497 | + error_bool= true | ||
| 498 | end | 498 | end |
| 499 | - | 499 | + |
| 500 | # votes before 2010-02-17 have null loser_choice_id | 500 | # votes before 2010-02-17 have null loser_choice_id |
| 501 | # therefore we want to ignore this test for any question with votes | 501 | # therefore we want to ignore this test for any question with votes |
| 502 | # prior to 2010-02-17 | 502 | # prior to 2010-02-17 |
| @@ -507,156 +507,156 @@ namespace :test_api do | @@ -507,156 +507,156 @@ namespace :test_api do | ||
| 507 | end | 507 | end |
| 508 | end | 508 | end |
| 509 | 509 | ||
| 510 | - end | ||
| 511 | - | ||
| 512 | - | ||
| 513 | - unless question_has_votes_before_2010_02_17 | ||
| 514 | - if (2*total_wins != total_votes) | ||
| 515 | - error_message += "Error 1: 2 x Total Wins != Total votes\n" | ||
| 516 | - error_bool= true | ||
| 517 | end | 510 | end |
| 518 | 511 | ||
| 519 | - if(total_votes % 2 != 0) | ||
| 520 | - error_message += "Error 2: Total votes is not Even!\n" | ||
| 521 | - error_bool= true | 512 | + |
| 513 | + unless question_has_votes_before_2010_02_17 | ||
| 514 | + if (2*total_wins != total_votes) | ||
| 515 | + error_message += "Error 1: 2 x Total Wins != Total votes\n" | ||
| 516 | + error_bool= true | ||
| 517 | + end | ||
| 518 | + | ||
| 519 | + if(total_votes % 2 != 0) | ||
| 520 | + error_message += "Error 2: Total votes is not Even!\n" | ||
| 521 | + error_bool= true | ||
| 522 | + end | ||
| 523 | + | ||
| 524 | + if(total_votes != 2* question.votes_count) | ||
| 525 | + error_message += "Error 3: Total votes != 2 x # vote objects\n" | ||
| 526 | + error_bool = true | ||
| 527 | + end | ||
| 522 | end | 528 | end |
| 523 | 529 | ||
| 524 | - if(total_votes != 2* question.votes_count) | ||
| 525 | - error_message += "Error 3: Total votes != 2 x # vote objects\n" | 530 | + if(total_generated_prompts_on_right != total_generated_prompts_on_right) |
| 531 | + error_message += "Error 4: Total generated prompts on left != Total generated prompts on right\n" | ||
| 526 | error_bool = true | 532 | error_bool = true |
| 527 | end | 533 | end |
| 528 | - end | ||
| 529 | 534 | ||
| 530 | - if(total_generated_prompts_on_right != total_generated_prompts_on_right) | ||
| 531 | - error_message += "Error 4: Total generated prompts on left != Total generated prompts on right\n" | ||
| 532 | - error_bool = true | ||
| 533 | - end | 535 | + unless question_has_votes_before_2010_02_17 |
| 536 | + if(total_scores_lte_fifty == question.choices.size || total_scores_gte_fifty == question.choices.size) && (total_scores_lte_fifty != total_scores_gte_fifty) | ||
| 537 | + error_message += "Error: The scores of all choices are either all above 50, or all below 50. This is probably wrong\n" | ||
| 538 | + error_bool = true | ||
| 539 | + puts "Error score fifty: #{question.id}" | ||
| 540 | + end | ||
| 541 | + end | ||
| 534 | 542 | ||
| 535 | - unless question_has_votes_before_2010_02_17 | ||
| 536 | - if(total_scores_lte_fifty == question.choices.size || total_scores_gte_fifty == question.choices.size) && (total_scores_lte_fifty != total_scores_gte_fifty) | ||
| 537 | - error_message += "Error: The scores of all choices are either all above 50, or all below 50. This is probably wrong\n" | ||
| 538 | - error_bool = true | ||
| 539 | - puts "Error score fifty: #{question.id}" | 543 | + if error_bool |
| 544 | + error_message += "Question #{question.id}: 2*wins = #{2*total_wins}, total votes = #{total_votes}, vote_count = #{question.votes_count}\n" | ||
| 540 | end | 545 | end |
| 546 | + return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 541 | end | 547 | end |
| 542 | - | ||
| 543 | - if error_bool | ||
| 544 | - error_message += "Question #{question.id}: 2*wins = #{2*total_wins}, total votes = #{total_votes}, vote_count = #{question.votes_count}\n" | ||
| 545 | - end | ||
| 546 | - return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 547 | - end | ||
| 548 | - def check_each_choice_appears_within_n_stddevs(question) | ||
| 549 | - error_message ="" | ||
| 550 | - success_message = "Each choice has appeared n times, where n falls within 6 stddevs of the mean number of appearances for a question " + | ||
| 551 | - "(Note: this applies only to seed choices (not user submitted) and choices currently marked active)" | 548 | + def check_each_choice_appears_within_n_stddevs(question) |
| 549 | + error_message ="" | ||
| 550 | + success_message = "Each choice has appeared n times, where n falls within 6 stddevs of the mean number of appearances for a question " + | ||
| 551 | + "(Note: this applies only to seed choices (not user submitted) and choices currently marked active)" | ||
| 552 | 552 | ||
| 553 | - wins_by_choice_id = question.votes.active.count(:group => :choice_id) | ||
| 554 | - losses_by_choice_id= question.votes.active.count(:conditions => "loser_choice_id IS NOT NULL", :group => :loser_choice_id) | 553 | + wins_by_choice_id = question.votes.active.count(:group => :choice_id) |
| 554 | + losses_by_choice_id= question.votes.active.count(:conditions => "loser_choice_id IS NOT NULL", :group => :loser_choice_id) | ||
| 555 | 555 | ||
| 556 | - #Rails returns an ordered hash, which doesn't allow for blocks to change merging logic. | ||
| 557 | - #A little hack to create a normal hash | ||
| 558 | - wins_hash = {} | ||
| 559 | - wins_hash.merge!(wins_by_choice_id) | ||
| 560 | - losses_hash = {} | ||
| 561 | - losses_hash.merge!(losses_by_choice_id) | 556 | + #Rails returns an ordered hash, which doesn't allow for blocks to change merging logic. |
| 557 | + #A little hack to create a normal hash | ||
| 558 | + wins_hash = {} | ||
| 559 | + wins_hash.merge!(wins_by_choice_id) | ||
| 560 | + losses_hash = {} | ||
| 561 | + losses_hash.merge!(losses_by_choice_id) | ||
| 562 | 562 | ||
| 563 | 563 | ||
| 564 | 564 | ||
| 565 | - appearances_by_choice_id = wins_hash.merge(losses_hash) do |key, oldval, newval| oldval + newval end | 565 | + appearances_by_choice_id = wins_hash.merge(losses_hash) do |key, oldval, newval| oldval + newval end |
| 566 | 566 | ||
| 567 | - sum = total_appearances = appearances_by_choice_id.values.inject(0) {|sum, x| sum +=x} | ||
| 568 | - mean = average_appearances = total_appearances.to_f / appearances_by_choice_id.size.to_f | 567 | + sum = total_appearances = appearances_by_choice_id.values.inject(0) {|sum, x| sum +=x} |
| 568 | + mean = average_appearances = total_appearances.to_f / appearances_by_choice_id.size.to_f | ||
| 569 | 569 | ||
| 570 | - if sum > 0: | ||
| 571 | - stddev = Math.sqrt( appearances_by_choice_id.values.inject(0) { |sum, e| sum + (e - mean) ** 2 } / appearances_by_choice_id.size.to_f ) | 570 | + if sum > 0: |
| 571 | + stddev = Math.sqrt( appearances_by_choice_id.values.inject(0) { |sum, e| sum + (e - mean) ** 2 } / appearances_by_choice_id.size.to_f ) | ||
| 572 | 572 | ||
| 573 | - appearances_by_choice_id.each do |choice_id, n_i| | ||
| 574 | - if ((n_i < (mean - 6*stddev)) || (n_i > mean + 6 *stddev)) && Choice.find(choice_id).active? | ||
| 575 | - error_message += "Choice #{choice_id} in Question ##{question.id} has an irregular number of appearances: #{n_i}, as compared to the mean: #{mean} and stddev #{stddev} for this question\n" | 573 | + appearances_by_choice_id.each do |choice_id, n_i| |
| 574 | + if ((n_i < (mean - 6*stddev)) || (n_i > mean + 6 *stddev)) && Choice.find(choice_id).active? | ||
| 575 | + error_message += "Choice #{choice_id} in Question ##{question.id} has an irregular number of appearances: #{n_i}, as compared to the mean: #{mean} and stddev #{stddev} for this question\n" | ||
| 576 | + end | ||
| 577 | + end | ||
| 576 | end | 578 | end |
| 577 | - end | ||
| 578 | - end | ||
| 579 | 579 | ||
| 580 | - return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 581 | - end | ||
| 582 | - def check_each_choice_equally_likely_to_appear_left_or_right(question) | 580 | + return error_message.blank? ? [success_message, false] : [error_message, true] |
| 581 | + end | ||
| 582 | + def check_each_choice_equally_likely_to_appear_left_or_right(question) | ||
| 583 | error_message = "" | 583 | error_message = "" |
| 584 | - success_message = "All choices have equal probability of appearing on left or right (within error params)" | ||
| 585 | - question.choices.each do |c| | ||
| 586 | - left_prompts_ids = c.prompts_on_the_left.ids_only | ||
| 587 | - right_prompts_ids = c.prompts_on_the_right.ids_only | 584 | + success_message = "All choices have equal probability of appearing on left or right (within error params)" |
| 585 | + question.choices.each do |c| | ||
| 586 | + left_prompts_ids = c.prompts_on_the_left.ids_only | ||
| 587 | + right_prompts_ids = c.prompts_on_the_right.ids_only | ||
| 588 | 588 | ||
| 589 | - left_appearances = question.appearances.count(:conditions => {:prompt_id => left_prompts_ids}) | ||
| 590 | - right_appearances = question.appearances.count(:conditions => {:prompt_id => right_prompts_ids}) | 589 | + left_appearances = question.appearances.count(:conditions => {:prompt_id => left_prompts_ids}) |
| 590 | + right_appearances = question.appearances.count(:conditions => {:prompt_id => right_prompts_ids}) | ||
| 591 | 591 | ||
| 592 | - n = left_appearances + right_appearances | 592 | + n = left_appearances + right_appearances |
| 593 | 593 | ||
| 594 | - if n == 0 | 594 | + if n == 0 |
| 595 | next | 595 | next |
| 596 | - end | ||
| 597 | - est_p = right_appearances.to_f / n.to_f | ||
| 598 | - z = (est_p - 0.5).abs / Math.sqrt((0.5 * 0.5) / n.to_f) | 596 | + end |
| 597 | + est_p = right_appearances.to_f / n.to_f | ||
| 598 | + z = (est_p - 0.5).abs / Math.sqrt((0.5 * 0.5) / n.to_f) | ||
| 599 | 599 | ||
| 600 | - if z > 6 | ||
| 601 | - error_message += "Error: Choice ID #{c.id} seems to favor one side: Left Appearances #{left_appearances}, Right Appearances: #{right_appearances}, z = #{z}\n" | ||
| 602 | - end | 600 | + if z > 6 |
| 601 | + error_message += "Error: Choice ID #{c.id} seems to favor one side: Left Appearances #{left_appearances}, Right Appearances: #{right_appearances}, z = #{z}\n" | ||
| 602 | + end | ||
| 603 | + end | ||
| 604 | + return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 603 | end | 605 | end |
| 604 | - return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 605 | - end | ||
| 606 | - def check_prompt_cache_hit_rate(question) | ||
| 607 | - error_message = "" | ||
| 608 | - success_message = "At least 90% of prompts on catchup algorithm questions were served from cache\n" | 606 | + def check_prompt_cache_hit_rate(question) |
| 607 | + error_message = "" | ||
| 608 | + success_message = "At least 90% of prompts on catchup algorithm questions were served from cache\n" | ||
| 609 | 609 | ||
| 610 | - misses = question.get_prompt_cache_misses(Date.yesterday).to_i | ||
| 611 | - hits = question.get_prompt_cache_hits(Date.yesterday).to_i | 610 | + misses = question.get_prompt_cache_misses(Date.yesterday).to_i |
| 611 | + hits = question.get_prompt_cache_hits(Date.yesterday).to_i | ||
| 612 | 612 | ||
| 613 | - question.expire_prompt_cache_tracking_keys(Date.yesterday) | ||
| 614 | - | ||
| 615 | - yesterday_appearances = question.appearances.count(:conditions => ['date(created_at) = ?', Date.yesterday]) | 613 | + question.expire_prompt_cache_tracking_keys(Date.yesterday) |
| 616 | 614 | ||
| 617 | - if misses + hits != yesterday_appearances | ||
| 618 | - error_message += "Error! Question #{question.id} isn't tracking prompt cache hits and misses accurately! Expected #{yesterday_appearances}, Actual: #{misses+hits}, Hits: #{hits}, Misses: #{misses}\n" | ||
| 619 | - end | ||
| 620 | - | ||
| 621 | - if yesterday_appearances > 5 # this test isn't worthwhile for small numbers of appearances | ||
| 622 | - miss_rate = misses.to_f / yesterday_appearances.to_f | ||
| 623 | - if miss_rate > 0.1 | ||
| 624 | - error_message += "Warning! Question #{question.id} has less than 90% of appearances taken from a pre-generated cache! Expected <#{0.1}, Actual: #{miss_rate}, total appearances yesterday: #{yesterday_appearances}\n" | 615 | + yesterday_appearances = question.appearances.count(:conditions => ['date(created_at) = ?', Date.yesterday]) |
| 616 | + | ||
| 617 | + if misses + hits != yesterday_appearances | ||
| 618 | + error_message += "Error! Question #{question.id} isn't tracking prompt cache hits and misses accurately! Expected #{yesterday_appearances}, Actual: #{misses+hits}, Hits: #{hits}, Misses: #{misses}\n" | ||
| 625 | end | 619 | end |
| 626 | - end | ||
| 627 | - return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 628 | - end | ||
| 629 | - | ||
| 630 | - def check_object_counter_cache_values_match_actual_values(question) | ||
| 631 | - error_message = "" | ||
| 632 | - success_message = "All cached object values match actual values within database" | ||
| 633 | - # Checks that counter_cache is working as expected | ||
| 634 | - cached_prompts_size = question.prompts.size | ||
| 635 | - actual_prompts_size = question.prompts.count | ||
| 636 | - | ||
| 637 | - if cached_prompts_size != actual_prompts_size | ||
| 638 | - error_message += "Error! Question #{question.id} has an inconsistent # of prompts! cached#: #{cached_prompts_size}, actual#: #{actual_prompts_size}\n" | ||
| 639 | - end | ||
| 640 | - | ||
| 641 | - cached_votes_size = question.votes.size | ||
| 642 | - actual_votes_size = question.votes.count | ||
| 643 | 620 | ||
| 644 | - if cached_votes_size != actual_votes_size | ||
| 645 | - error_message += "Error! Question #{question.id} has an inconsistent # of votes! cached#: #{cached_votes_size}, actual#: #{actual_votes_size}\n" | 621 | + if yesterday_appearances > 5 # this test isn't worthwhile for small numbers of appearances |
| 622 | + miss_rate = misses.to_f / yesterday_appearances.to_f | ||
| 623 | + if miss_rate > 0.1 | ||
| 624 | + error_message += "Warning! Question #{question.id} has less than 90% of appearances taken from a pre-generated cache! Expected <#{0.1}, Actual: #{miss_rate}, total appearances yesterday: #{yesterday_appearances}\n" | ||
| 625 | + end | ||
| 626 | + end | ||
| 627 | + return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 646 | end | 628 | end |
| 647 | - | ||
| 648 | - cached_choices_size = question.choices.size | ||
| 649 | - actual_choices_size = question.choices.count | ||
| 650 | 629 | ||
| 651 | - if cached_choices_size != actual_choices_size | ||
| 652 | - error_message+= "Error! Question #{question.id} has an inconsistent # of choices! cached#: #{cached_choices_size}, actual#: #{actual_choices_size}\n" | ||
| 653 | - end | 630 | + def check_object_counter_cache_values_match_actual_values(question) |
| 631 | + error_message = "" | ||
| 632 | + success_message = "All cached object values match actual values within database" | ||
| 633 | + # Checks that counter_cache is working as expected | ||
| 634 | + cached_prompts_size = question.prompts.size | ||
| 635 | + actual_prompts_size = question.prompts.count | ||
| 654 | 636 | ||
| 655 | - #if cached_prompts_size != question.choices.size **2 - question.choices.size | ||
| 656 | - # error_message += "Error! Question #{question.id} has an incorrect number of prompts! Expected #{question.choices.size **2 - question.choices.size}, Actual: #{cached_prompts_size}\n" | ||
| 657 | - #end | ||
| 658 | - return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 659 | - end | 637 | + if cached_prompts_size != actual_prompts_size |
| 638 | + error_message += "Error! Question #{question.id} has an inconsistent # of prompts! cached#: #{cached_prompts_size}, actual#: #{actual_prompts_size}\n" | ||
| 639 | + end | ||
| 640 | + | ||
| 641 | + cached_votes_size = question.votes.size | ||
| 642 | + actual_votes_size = question.votes.count | ||
| 643 | + | ||
| 644 | + if cached_votes_size != actual_votes_size | ||
| 645 | + error_message += "Error! Question #{question.id} has an inconsistent # of votes! cached#: #{cached_votes_size}, actual#: #{actual_votes_size}\n" | ||
| 646 | + end | ||
| 647 | + | ||
| 648 | + cached_choices_size = question.choices.size | ||
| 649 | + actual_choices_size = question.choices.count | ||
| 650 | + | ||
| 651 | + if cached_choices_size != actual_choices_size | ||
| 652 | + error_message+= "Error! Question #{question.id} has an inconsistent # of choices! cached#: #{cached_choices_size}, actual#: #{actual_choices_size}\n" | ||
| 653 | + end | ||
| 654 | + | ||
| 655 | + #if cached_prompts_size != question.choices.size **2 - question.choices.size | ||
| 656 | + # error_message += "Error! Question #{question.id} has an incorrect number of prompts! Expected #{question.choices.size **2 - question.choices.size}, Actual: #{cached_prompts_size}\n" | ||
| 657 | + #end | ||
| 658 | + return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 659 | + end | ||
| 660 | 660 | ||
| 661 | desc "Ensure that a question has: answered_appearances == votes + skips" | 661 | desc "Ensure that a question has: answered_appearances == votes + skips" |
| 662 | task :answered_appearances_equals_votes_and_skips => :environment do | 662 | task :answered_appearances_equals_votes_and_skips => :environment do |
| @@ -673,63 +673,63 @@ namespace :test_api do | @@ -673,63 +673,63 @@ namespace :test_api do | ||
| 673 | if (total_answered_appearances != total_votes + total_skips) | 673 | if (total_answered_appearances != total_votes + total_skips) |
| 674 | error_message += "Question #{question.id}: answered_appearances = #{total_answered_appearances}, votes = #{total_votes}, skips = #{total_skips}" | 674 | error_message += "Question #{question.id}: answered_appearances = #{total_answered_appearances}, votes = #{total_votes}, skips = #{total_skips}" |
| 675 | end | 675 | end |
| 676 | - | 676 | + |
| 677 | 677 | ||
| 678 | return error_message.blank? ? [success_message, false] : [error_message, true] | 678 | return error_message.blank? ? [success_message, false] : [error_message, true] |
| 679 | end | 679 | end |
| 680 | - | ||
| 681 | - def ensure_all_votes_and_skips_have_unique_appearance | ||
| 682 | - error_message = "" | ||
| 683 | - success_message = "All vote and skip objects have an associated appearance object" | ||
| 684 | 680 | ||
| 685 | - total_answered_appearances = Appearance.count(:conditions => 'answerable_id IS NOT NULL') | ||
| 686 | - total_votes = Vote.count | ||
| 687 | - total_skips = Skip.count | 681 | + def ensure_all_votes_and_skips_have_unique_appearance |
| 682 | + error_message = "" | ||
| 683 | + success_message = "All vote and skip objects have an associated appearance object" | ||
| 688 | 684 | ||
| 689 | - if (total_answered_appearances != total_votes+ total_skips) | ||
| 690 | - difference = (total_votes+ total_skips) - total_answered_appearances | ||
| 691 | - error_message += "Error! There are #{difference} votes or skips without associated appearance objects." | ||
| 692 | - end | 685 | + total_answered_appearances = Appearance.count(:conditions => 'answerable_id IS NOT NULL') |
| 686 | + total_votes = Vote.count | ||
| 687 | + total_skips = Skip.count | ||
| 693 | 688 | ||
| 694 | - return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 695 | - end | 689 | + if (total_answered_appearances != total_votes+ total_skips) |
| 690 | + difference = (total_votes+ total_skips) - total_answered_appearances | ||
| 691 | + error_message += "Error! There are #{difference} votes or skips without associated appearance objects." | ||
| 692 | + end | ||
| 696 | 693 | ||
| 697 | - def response_time_tests | ||
| 698 | - error_message = "" | ||
| 699 | - success_message = "All Vote objects have an client response time < calculated server roundtrip time\n" | 694 | + return error_message.blank? ? [success_message, false] : [error_message, true] |
| 695 | + end | ||
| 700 | 696 | ||
| 701 | - recording_client_time_start_date = Vote.find(:all, :conditions => 'time_viewed IS NOT NULL', :order => 'created_at', :limit => 1).first.created_at | 697 | + def response_time_tests |
| 698 | + error_message = "" | ||
| 699 | + success_message = "All Vote objects have an client response time < calculated server roundtrip time\n" | ||
| 700 | + | ||
| 701 | + recording_client_time_start_date = Vote.find(:all, :conditions => 'time_viewed IS NOT NULL', :order => 'created_at', :limit => 1).first.created_at | ||
| 702 | 702 | ||
| 703 | - Vote.find_each(:batch_size => 1000, :include => :appearance) do |v| | 703 | + Vote.find_each(:batch_size => 1000, :include => :appearance) do |v| |
| 704 | 704 | ||
| 705 | next if v.nil? || v.appearance.nil? | 705 | next if v.nil? || v.appearance.nil? |
| 706 | - # Subtracting DateTime objects results in the difference in days | ||
| 707 | - server_response_time = v.created_at.to_f - v.appearance.created_at.to_f | ||
| 708 | - if server_response_time < 0 | ||
| 709 | - the_error_msg = "Error! Vote #{v.id} was created before the appearance associated with it: Appearance id: #{v.appearance.id}, Vote creation time: #{v.created_at.to_s}, Appearance creation time: #{v.appearance.created_at.to_s}\n" | ||
| 710 | - | ||
| 711 | - error_message += the_error_msg | ||
| 712 | - print "Error!" + the_error_msg | ||
| 713 | - end | ||
| 714 | - | ||
| 715 | - if v.time_viewed && v.time_viewed/1000 > server_response_time | ||
| 716 | - the_error_msg = "Warning! Vote #{v.id} with Appearance #{v.appearance.id}, has a longer client response time than is possible. Server roundtrip time is: #{v.created_at.to_f - v.appearance.created_at.to_f} seconds, but client side response time is: #{v.time_viewed.to_f / 1000.0} seconds\n" | ||
| 717 | - | ||
| 718 | - error_message += the_error_msg | ||
| 719 | - print the_error_msg | ||
| 720 | - | ||
| 721 | - elsif v.time_viewed.nil? | ||
| 722 | - if v.created_at > recording_client_time_start_date && v.missing_response_time_exp != 'invalid' | ||
| 723 | - the_error_msg = "Error! Vote #{v.id} with Appearance #{v.appearance.id}, does not have a client response, even though it should! Vote creation time: #{v.created_at.to_s}, Appearance creation time: #{v.appearance.created_at.to_s}, Client side response time: #{v.time_viewed}\n" | ||
| 724 | - error_message += the_error_msg | ||
| 725 | - print the_error_msg | ||
| 726 | - end | ||
| 727 | - | ||
| 728 | - end | ||
| 729 | - | ||
| 730 | - end | ||
| 731 | - | ||
| 732 | - return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 733 | - end | 706 | + # Subtracting DateTime objects results in the difference in days |
| 707 | + server_response_time = v.created_at.to_f - v.appearance.created_at.to_f | ||
| 708 | + if server_response_time < 0 | ||
| 709 | + the_error_msg = "Error! Vote #{v.id} was created before the appearance associated with it: Appearance id: #{v.appearance.id}, Vote creation time: #{v.created_at.to_s}, Appearance creation time: #{v.appearance.created_at.to_s}\n" | ||
| 710 | + | ||
| 711 | + error_message += the_error_msg | ||
| 712 | + print "Error!" + the_error_msg | ||
| 713 | + end | ||
| 714 | + | ||
| 715 | + if v.time_viewed && v.time_viewed/1000 > server_response_time | ||
| 716 | + the_error_msg = "Warning! Vote #{v.id} with Appearance #{v.appearance.id}, has a longer client response time than is possible. Server roundtrip time is: #{v.created_at.to_f - v.appearance.created_at.to_f} seconds, but client side response time is: #{v.time_viewed.to_f / 1000.0} seconds\n" | ||
| 717 | + | ||
| 718 | + error_message += the_error_msg | ||
| 719 | + print the_error_msg | ||
| 720 | + | ||
| 721 | + elsif v.time_viewed.nil? | ||
| 722 | + if v.created_at > recording_client_time_start_date && v.missing_response_time_exp != 'invalid' | ||
| 723 | + the_error_msg = "Error! Vote #{v.id} with Appearance #{v.appearance.id}, does not have a client response, even though it should! Vote creation time: #{v.created_at.to_s}, Appearance creation time: #{v.appearance.created_at.to_s}, Client side response time: #{v.time_viewed}\n" | ||
| 724 | + error_message += the_error_msg | ||
| 725 | + print the_error_msg | ||
| 726 | + end | ||
| 727 | + | ||
| 728 | + end | ||
| 729 | + | ||
| 730 | + end | ||
| 731 | + | ||
| 732 | + return error_message.blank? ? [success_message, false] : [error_message, true] | ||
| 733 | + end | ||
| 734 | end | 734 | end |
| 735 | 735 |