Commit fd5da22491e6b145ad7b45649becd39fc995dd50

Authored by Luke Baker
1 parent beb3b15f

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