Commit 8716cedc034f94a2771478b1e49a3c269af636d6

Authored by Luke Baker
1 parent 3bd8a171

update spacing in test_api.rake

Showing 1 changed file with 447 additions and 445 deletions   Show diff stats
lib/tasks/test_api.rake
@@ -5,120 +5,120 @@ namespace :test_api do @@ -5,120 +5,120 @@ namespace :test_api do
5 desc "Don't run unless you know what you are doing" 5 desc "Don't run unless you know what you are doing"
6 task(:generate_lots_of_votes => :environment) do 6 task(:generate_lots_of_votes => :environment) do
7 if Rails.env.production? 7 if Rails.env.production?
8 - print "You probably don't want to run this in production as it will falsify a bunch of random votes" 8 + print "You probably don't want to run this in production as it will falsify a bunch of random votes"
9 end 9 end
10 10
11 11
12 current_user = User.first 12 current_user = User.first
13 1000.times do |n| 13 1000.times do |n|
14 - puts "#{n} votes completed" if n % 100 == 0 14 + puts "#{n} votes completed" if n % 100 == 0
15 question = Question.find(214) # test question change as needed 15 question = Question.find(214) # test question change as needed
16 - @prompt = question.catchup_choose_prompt 16 + @prompt = question.catchup_choose_prompt
17 @appearance = current_user.record_appearance(current_user.default_visitor, @prompt) 17 @appearance = current_user.record_appearance(current_user.default_visitor, @prompt)
18 18
19 - direction = (rand(2) == 0) ? "left" : "right"  
20 - current_user.record_vote(:prompt => @prompt, :direction => direction, :appearance_lookup => @appearance.lookup) 19 + direction = (rand(2) == 0) ? "left" : "right"
  20 + current_user.record_vote(:prompt => @prompt, :direction => direction, :appearance_lookup => @appearance.lookup)
21 end 21 end
22 22
23 end 23 end
24 24
25 desc "Generate appearances for any votes that have no current appearance, should only need to be run once" 25 desc "Generate appearances for any votes that have no current appearance, should only need to be run once"
26 task(:generate_appearances_for_existing_votes => :environment) do 26 task(:generate_appearances_for_existing_votes => :environment) do
27 - votes = Vote.all 27 + votes = Vote.all
28 28
29 - count = 0  
30 - votes.each do |v|  
31 - if v.appearance.nil?  
32 - print "."  
33 - 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)  
34 - v.appearance = a  
35 - v.save 29 + count = 0
  30 + votes.each do |v|
  31 + if v.appearance.nil?
  32 + print "."
  33 + 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)
  34 + v.appearance = a
  35 + v.save
36 36
37 - count += 1  
38 - end  
39 - end 37 + count += 1
  38 + end
  39 + end
40 40
41 - print count 41 + print count
42 end 42 end
43 43
44 44
45 desc "Generate past density information" 45 desc "Generate past density information"
46 task(:generate_past_densities => :environment) do 46 task(:generate_past_densities => :environment) do
47 - #this is not elegant, but should only be run once, so quick and dirty wins  
48 -  
49 - start_date = Vote.find(:all, :conditions => 'loser_choice_id IS NOT NULL', :order => :created_at, :limit => 1).first.created_at.to_date  
50 - start_date.upto(Date.today) do |the_date|  
51 - questions = Question.find(:all, :conditions => ['created_at < ?', the_date])  
52 -  
53 - print the_date.to_s  
54 - questions.each do |q|  
55 - puts q.id  
56 - relevant_choices = q.choices.find(:all, :conditions => ['created_at < ?', the_date])  
57 -  
58 - seed_choices = 0  
59 -  
60 - if relevant_choices == 0  
61 - next  
62 - #this question had not been created yet  
63 - end  
64 -  
65 - relevant_choices.each do |c|  
66 - if !c.user_created  
67 - seed_choices+=1  
68 - end  
69 -  
70 - end  
71 -  
72 - nonseed_choices = relevant_choices.size - seed_choices  
73 -  
74 - seed_seed_total = seed_choices **2 - seed_choices  
75 - nonseed_nonseed_total = nonseed_choices **2 - nonseed_choices  
76 - seed_nonseed_total = seed_choices * nonseed_choices  
77 - nonseed_seed_total = seed_choices * nonseed_choices  
78 -  
79 - seed_seed_sum = 0  
80 - seed_nonseed_sum= 0  
81 - nonseed_seed_sum= 0  
82 - nonseed_nonseed_sum= 0  
83 -  
84 - q.appearances.find_each(:conditions => ['prompt_id IS NOT NULL AND created_at < ?', the_date]) do |a|  
85 -  
86 - p = a.prompt  
87 - if p.left_choice.user_created == false && p.right_choice.user_created == false  
88 - seed_seed_sum += 1  
89 - elsif p.left_choice.user_created == false && p.right_choice.user_created == true  
90 - seed_nonseed_sum += 1  
91 - elsif p.left_choice.user_created == true && p.right_choice.user_created == false  
92 - nonseed_seed_sum += 1  
93 - elsif p.left_choice.user_created == true && p.right_choice.user_created == true  
94 - nonseed_nonseed_sum += 1  
95 - end  
96 - end  
97 -  
98 - densities = {}  
99 - densities[:seed_seed] = seed_seed_sum.to_f / seed_seed_total.to_f  
100 - densities[:seed_nonseed] = seed_nonseed_sum.to_f / seed_nonseed_total.to_f  
101 - densities[:nonseed_seed] = nonseed_seed_sum.to_f / nonseed_seed_total.to_f  
102 - densities[:nonseed_nonseed] = nonseed_nonseed_sum.to_f / nonseed_nonseed_total.to_f  
103 -  
104 - densities.each do |type, average|  
105 - d = Density.new  
106 - d.created_at = the_date  
107 - d.question_id = q.id  
108 - d.prompt_type = type.to_s  
109 - d.value = average.nan? ? nil : average  
110 - d.save!  
111 - end  
112 -  
113 - puts "Seed_seed sum: #{seed_seed_sum}, seed_seed total num: #{seed_seed_total}"  
114 - puts "Seed_nonseed sum: #{seed_nonseed_sum}, seed_nonseed total num: #{seed_nonseed_total}"  
115 - puts "Nonseed_seed sum: #{nonseed_seed_sum}, nonseed_seed total num: #{nonseed_seed_total}"  
116 - puts "Nonseed_nonseed sum: #{nonseed_nonseed_sum}, nonseed_nonseed total num: #{nonseed_nonseed_total}"  
117 -  
118 -  
119 - end  
120 -  
121 - end 47 + #this is not elegant, but should only be run once, so quick and dirty wins
  48 +
  49 + start_date = Vote.find(:all, :conditions => 'loser_choice_id IS NOT NULL', :order => :created_at, :limit => 1).first.created_at.to_date
  50 + start_date.upto(Date.today) do |the_date|
  51 + questions = Question.find(:all, :conditions => ['created_at < ?', the_date])
  52 +
  53 + print the_date.to_s
  54 + questions.each do |q|
  55 + puts q.id
  56 + relevant_choices = q.choices.find(:all, :conditions => ['created_at < ?', the_date])
  57 +
  58 + seed_choices = 0
  59 +
  60 + if relevant_choices == 0
  61 + next
  62 + #this question had not been created yet
  63 + end
  64 +
  65 + relevant_choices.each do |c|
  66 + if !c.user_created
  67 + seed_choices+=1
  68 + end
  69 +
  70 + end
  71 +
  72 + nonseed_choices = relevant_choices.size - seed_choices
  73 +
  74 + seed_seed_total = seed_choices **2 - seed_choices
  75 + nonseed_nonseed_total = nonseed_choices **2 - nonseed_choices
  76 + seed_nonseed_total = seed_choices * nonseed_choices
  77 + nonseed_seed_total = seed_choices * nonseed_choices
  78 +
  79 + seed_seed_sum = 0
  80 + seed_nonseed_sum= 0
  81 + nonseed_seed_sum= 0
  82 + nonseed_nonseed_sum= 0
  83 +
  84 + q.appearances.find_each(:conditions => ['prompt_id IS NOT NULL AND created_at < ?', the_date]) do |a|
  85 +
  86 + p = a.prompt
  87 + if p.left_choice.user_created == false && p.right_choice.user_created == false
  88 + seed_seed_sum += 1
  89 + elsif p.left_choice.user_created == false && p.right_choice.user_created == true
  90 + seed_nonseed_sum += 1
  91 + elsif p.left_choice.user_created == true && p.right_choice.user_created == false
  92 + nonseed_seed_sum += 1
  93 + elsif p.left_choice.user_created == true && p.right_choice.user_created == true
  94 + nonseed_nonseed_sum += 1
  95 + end
  96 + end
  97 +
  98 + densities = {}
  99 + densities[:seed_seed] = seed_seed_sum.to_f / seed_seed_total.to_f
  100 + densities[:seed_nonseed] = seed_nonseed_sum.to_f / seed_nonseed_total.to_f
  101 + densities[:nonseed_seed] = nonseed_seed_sum.to_f / nonseed_seed_total.to_f
  102 + densities[:nonseed_nonseed] = nonseed_nonseed_sum.to_f / nonseed_nonseed_total.to_f
  103 +
  104 + densities.each do |type, average|
  105 + d = Density.new
  106 + d.created_at = the_date
  107 + d.question_id = q.id
  108 + d.prompt_type = type.to_s
  109 + d.value = average.nan? ? nil : average
  110 + d.save!
  111 + end
  112 +
  113 + puts "Seed_seed sum: #{seed_seed_sum}, seed_seed total num: #{seed_seed_total}"
  114 + puts "Seed_nonseed sum: #{seed_nonseed_sum}, seed_nonseed total num: #{seed_nonseed_total}"
  115 + puts "Nonseed_seed sum: #{nonseed_seed_sum}, nonseed_seed total num: #{nonseed_seed_total}"
  116 + puts "Nonseed_nonseed sum: #{nonseed_nonseed_sum}, nonseed_nonseed total num: #{nonseed_nonseed_total}"
  117 +
  118 +
  119 + end
  120 +
  121 + end
122 122
123 end 123 end
124 124
@@ -126,53 +126,53 @@ namespace :test_api do @@ -126,53 +126,53 @@ namespace :test_api do
126 desc "Should only need to be run once" 126 desc "Should only need to be run once"
127 task(:generate_all_possible_prompts => :environment) do 127 task(:generate_all_possible_prompts => :environment) do
128 Question.find(:all).each do |q| 128 Question.find(:all).each do |q|
129 - choices = q.choices  
130 - if q.prompts.size > choices.size**2 - choices.size  
131 - print "ERROR: #{q.id}\n"  
132 - next  
133 - elsif q.prompts.size == choices.size**2 - choices.size  
134 - print "#{q.id} has enough prompts, skipping...\n"  
135 - next  
136 - else  
137 - print "#{q.id} should add #{(choices.size ** 2 - choices.size) - q.prompts.size}\n"  
138 -  
139 - end 129 + choices = q.choices
  130 + if q.prompts.size > choices.size**2 - choices.size
  131 + print "ERROR: #{q.id}\n"
  132 + next
  133 + elsif q.prompts.size == choices.size**2 - choices.size
  134 + print "#{q.id} has enough prompts, skipping...\n"
  135 + next
  136 + else
  137 + print "#{q.id} should add #{(choices.size ** 2 - choices.size) - q.prompts.size}\n"
  138 +
  139 + end
140 created_timestring = q.created_at.to_s(:db) 140 created_timestring = q.created_at.to_s(:db)
141 - updated_timestring = Time.now.to_s(:db) #isn't rails awesome?  
142 - promptscount=0 141 + updated_timestring = Time.now.to_s(:db) #isn't rails awesome?
  142 + promptscount=0
143 inserts = [] 143 inserts = []
144 - the_prompts = Prompt.find(:all, :select => 'id, left_choice_id, right_choice_id', :conditions => {:question_id => q.id}) 144 + the_prompts = Prompt.find(:all, :select => 'id, left_choice_id, right_choice_id', :conditions => {:question_id => q.id})
145 145
146 - the_prompts_hash = {}  
147 - the_prompts.each do |p|  
148 - the_prompts_hash["#{p.left_choice_id},#{p.right_choice_id}"] = 1  
149 - end 146 + the_prompts_hash = {}
  147 + the_prompts.each do |p|
  148 + the_prompts_hash["#{p.left_choice_id},#{p.right_choice_id}"] = 1
  149 + end
150 150
151 choices.each do |l| 151 choices.each do |l|
152 - choices.each do |r|  
153 - if l.id == r.id  
154 - next  
155 - else  
156 - #p = the_prompts.find{|o| o.left_choice_id == l.id && o.right_choice_id == r.id}  
157 - keystring = "#{l.id},#{r.id}"  
158 - p = the_prompts_hash[keystring]  
159 - if p.nil?  
160 - inserts.push("(NULL, #{q.id}, NULL, #{l.id}, '#{created_timestring}', '#{updated_timestring}', NULL, 0, #{r.id}, NULL, NULL)")  
161 - promptscount+=1  
162 - end  
163 -  
164 - end  
165 -  
166 - end 152 + choices.each do |r|
  153 + if l.id == r.id
  154 + next
  155 + else
  156 + #p = the_prompts.find{|o| o.left_choice_id == l.id && o.right_choice_id == r.id}
  157 + keystring = "#{l.id},#{r.id}"
  158 + p = the_prompts_hash[keystring]
  159 + if p.nil?
  160 + inserts.push("(NULL, #{q.id}, NULL, #{l.id}, '#{created_timestring}', '#{updated_timestring}', NULL, 0, #{r.id}, NULL, NULL)")
  161 + promptscount+=1
  162 + end
  163 +
  164 + end
  165 +
  166 + end
167 end 167 end
168 168
169 - print "Added #{promptscount} to #{q.id}\n"  
170 - 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(', ')}"  
171 - unless inserts.empty?  
172 - ActiveRecord::Base.connection.execute(sql)  
173 - end 169 + print "Added #{promptscount} to #{q.id}\n"
  170 + 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(', ')}"
  171 + unless inserts.empty?
  172 + ActiveRecord::Base.connection.execute(sql)
  173 + end
174 174
175 - Question.update_counters(q.id, :prompts_count => promptscount) 175 + Question.update_counters(q.id, :prompts_count => promptscount)
176 176
177 177
178 end 178 end
@@ -185,337 +185,339 @@ namespace :test_api do @@ -185,337 +185,339 @@ namespace :test_api do
185 desc "Dump votes of a question by left vs right id" 185 desc "Dump votes of a question by left vs right id"
186 task(:make_csv => :environment) do 186 task(:make_csv => :environment) do
187 187
188 - q = Question.find(214)  
189 -  
190 -  
191 - the_prompts = q.prompts_hash_by_choice_ids  
192 -  
193 - #hash_of_choice_ids_from_left_to_right_to_votes  
194 - the_hash = {}  
195 - q.choices.each do |l|  
196 - q.choices.each do |r|  
197 - next if l.id == r.id  
198 -  
199 - if not the_hash.has_key?(l.id)  
200 - the_hash[l.id] = {}  
201 - the_hash[l.id][l.id] = 0  
202 - end  
203 -  
204 - p = the_prompts["#{l.id}, #{r.id}"]  
205 - if p.nil?  
206 - the_hash[l.id][r.id] = 0  
207 - else  
208 - the_hash[l.id][r.id] = p.appearances.size  
209 - end  
210 - end  
211 - end  
212 -  
213 - the_hash.sort.each do |xval, row|  
214 - rowarray = []  
215 - row.sort.each do |yval, cell|  
216 - rowarray << cell  
217 - end  
218 - puts rowarray.join(", ")  
219 - end 188 + q = Question.find(214)
  189 +
  190 +
  191 + the_prompts = q.prompts_hash_by_choice_ids
  192 +
  193 + #hash_of_choice_ids_from_left_to_right_to_votes
  194 + the_hash = {}
  195 + q.choices.each do |l|
  196 + q.choices.each do |r|
  197 + next if l.id == r.id
  198 +
  199 + if not the_hash.has_key?(l.id)
  200 + the_hash[l.id] = {}
  201 + the_hash[l.id][l.id] = 0
  202 + end
  203 +
  204 + p = the_prompts["#{l.id}, #{r.id}"]
  205 + if p.nil?
  206 + the_hash[l.id][r.id] = 0
  207 + else
  208 + the_hash[l.id][r.id] = p.appearances.size
  209 + end
  210 + end
  211 + end
  212 +
  213 + the_hash.sort.each do |xval, row|
  214 + rowarray = []
  215 + row.sort.each do |yval, cell|
  216 + rowarray << cell
  217 + end
  218 + puts rowarray.join(", ")
  219 + end
220 end 220 end
221 221
222 222
223 desc "Generate density information for each question - should be run nightly" 223 desc "Generate density information for each question - should be run nightly"
224 task(:generate_density_information => :environment) do 224 task(:generate_density_information => :environment) do
225 225
226 - # calculating densities is expensive, so only do it for questions with new data  
227 - question_ids = Vote.count(:conditions => ['date(created_at) = ?', Date.yesterday], :group => 'question_id').keys() 226 + # calculating densities is expensive, so only do it for questions with new data
  227 + question_ids = Vote.count(:conditions => ['date(created_at) = ?', Date.yesterday], :group => 'question_id').keys()
228 228
229 - Question.find(:all, :conditions => {:id => question_ids}).each do |q|  
230 - q.save_densities!  
231 - end 229 + Question.find(:all, :conditions => {:id => question_ids}).each do |q|
  230 + q.save_densities!
  231 + end
232 232
233 - # we can just copy the previous night's data for remaining questions  
234 -  
235 - Question.find(:all, :conditions => ['id NOT IN (?)', question_ids]).each do |q|  
236 - densities = q.densities.find(:all, :conditions => ['date(created_at) = ?', Date.yesterday]) 233 + # we can just copy the previous night's data for remaining questions
  234 +
  235 + Question.find(:all, :conditions => ['id NOT IN (?)', question_ids]).each do |q|
  236 + densities = q.densities.find(:all, :conditions => ['date(created_at) = ?', Date.yesterday])
237 237
238 238
239 - densities.each do |d|  
240 - new_d = d.clone  
241 - new_d.created_at = new_d.updated_at = Time.now  
242 - new_d.save!  
243 - end 239 + densities.each do |d|
  240 + new_d = d.clone
  241 + new_d.created_at = new_d.updated_at = Time.now
  242 + new_d.save!
  243 + end
244 244
245 - if densities.blank?  
246 - #fallback in case there wasn't a successful run yesterday  
247 - q.save_densities!  
248 -  
249 - end 245 + if densities.blank?
  246 + #fallback in case there wasn't a successful run yesterday
  247 + q.save_densities!
  248 +
  249 + end
250 250
251 - end 251 + end
252 end 252 end
253 253
254 - desc "Description here"  
255 - task(:question_vote_consistency => :environment) do  
256 - questions = Question.find(:all)  
257 - errors = []  
258 - successes = []  
259 -  
260 - questions.each do |question| 254 + desc "Description here"
  255 + task(:question_vote_consistency => :environment) do
  256 + questions = Question.find(:all)
  257 + errors = []
  258 + successes = []
  259 +
  260 + questions.each do |question|
  261 +
  262 + message, error_occurred = check_basic_balanced_stats(question)
  263 + # hack for now, get around to doing this with block/yield to
  264 + # get rid of duplication
  265 + if error_occurred
  266 + errors << message
  267 + else
  268 + successes << message
  269 + end
261 270
262 - message, error_occurred = check_basic_balanced_stats(question)  
263 - #hack for now, get around to doing this with block /yield to get rid of duplication  
264 - if error_occurred  
265 - errors << message  
266 - else  
267 - successes << message  
268 - end  
269 271
  272 + message, error_occurred = check_each_choice_appears_within_n_stddevs(question)
  273 + if error_occurred
  274 + errors << message
  275 + else
  276 + successes << message
  277 + end
270 278
271 - message, error_occurred = check_each_choice_appears_within_n_stddevs(question)  
272 - if error_occurred  
273 - errors << message  
274 - else  
275 - successes << message  
276 - end  
277 -  
278 - message, error_occurred = check_each_choice_equally_likely_to_appear_left_or_right(question)  
279 - if error_occurred  
280 - errors << message  
281 - else  
282 - successes << message  
283 - end  
284 -  
285 -  
286 -  
287 - message, error_occurred = check_object_counter_cache_values_match_actual_values(question)  
288 - if error_occurred  
289 - errors << message  
290 - else  
291 - successes << message  
292 - end 279 + message, error_occurred = check_each_choice_equally_likely_to_appear_left_or_right(question)
  280 + if error_occurred
  281 + errors << message
  282 + else
  283 + successes << message
  284 + end
293 285
294 286
295 - #catchup specific  
296 - if question.uses_catchup?  
297 - message, error_occurred = check_prompt_cache_hit_rate(question)  
298 - if error_occurred  
299 - errors << message  
300 - else  
301 - successes << message  
302 - end  
303 - end  
304 - end  
305 287
306 - message, error_occurred = ensure_all_votes_and_skips_have_unique_appearance  
307 -  
308 - if error_occurred  
309 - errors << message  
310 - else  
311 - successes << message  
312 - end 288 + message, error_occurred = check_object_counter_cache_values_match_actual_values(question)
  289 + if error_occurred
  290 + errors << message
  291 + else
  292 + successes << message
  293 + end
313 294
314 - message, error_occurred = response_time_tests  
315 295
316 - if error_occurred  
317 - errors << message  
318 - else  
319 - successes << message  
320 - end 296 + #catchup specific
  297 + if question.uses_catchup?
  298 + message, error_occurred = check_prompt_cache_hit_rate(question)
  299 + if error_occurred
  300 + errors << message
  301 + else
  302 + successes << message
  303 + end
  304 + end
321 305
322 - email_text = "Conducted the following tests on API data and found the following results\n" +  
323 - "For each of the #{questions.length} questions in the database: \n"  
324 - errors.each do |e|  
325 - email_text += " Test FAILED: " + e + "\n"  
326 - end 306 + end
327 307
328 - successes.uniq.each do |s|  
329 - s.split("\n").each do |m| # some successes have several lines  
330 - email_text += " Test Passed: " + m + "\n"  
331 - end  
332 - end  
333 -  
334 - puts email_text 308 + message, error_occurred = ensure_all_votes_and_skips_have_unique_appearance
335 309
336 - if errors.empty?  
337 - CronMailer.deliver_info_message(CRON_EMAIL, "Test of API Vote Consistency passed", email_text)  
338 - else  
339 - CronMailer.deliver_info_message(CRON_EMAIL.to_a + ERRORS_EMAIL.to_a, "Error! Failure of API Vote Consistency " , email_text)  
340 - end 310 + if error_occurred
  311 + errors << message
  312 + else
  313 + successes << message
  314 + end
  315 +
  316 + message, error_occurred = response_time_tests
  317 +
  318 + if error_occurred
  319 + errors << message
  320 + else
  321 + successes << message
  322 + end
  323 +
  324 + email_text = "Conducted the following tests on API data and found the following results\n" + "For each of the #{questions.length} questions in the database: \n"
  325 + errors.each do |e|
  326 + email_text += " Test FAILED: " + e + "\n"
  327 + end
  328 +
  329 + successes.uniq.each do |s|
  330 + s.split("\n").each do |m| # some successes have several lines
  331 + email_text += " Test Passed: " + m + "\n"
  332 + end
  333 + end
  334 +
  335 + puts email_text
  336 +
  337 + if errors.empty?
  338 + CronMailer.deliver_info_message(CRON_EMAIL, "Test of API Vote Consistency passed", email_text)
  339 + else
  340 + CronMailer.deliver_info_message(CRON_EMAIL.to_a + ERRORS_EMAIL.to_a, "Error! Failure of API Vote Consistency " , email_text)
  341 + end
  342 +
  343 + end
341 344
342 - end  
343 def check_basic_balanced_stats(question) 345 def check_basic_balanced_stats(question)
344 - error_message = ""  
345 - success_message = "2 x Total Wins = Total Votes\n" +  
346 - "Total Votes (wins + losses) is Even\n" +  
347 - "Total Votes (wins + losses) = 2 x the number of vote objects that belong to the question\n" +  
348 - "Total generated prompts on left = Total generated prompts on right"  
349 - total_wins =0  
350 - total_votes =0  
351 - total_generated_prompts_on_left = 0  
352 - total_generated_prompts_on_right = 0  
353 - total_scores_gte_fifty= 0  
354 - total_scores_lte_fifty= 0  
355 - error_bool = false  
356 -  
357 - question.choices.each do |choice|  
358 -  
359 - if choice.wins  
360 - total_wins += choice.wins  
361 - total_votes += choice.wins  
362 - end  
363 -  
364 - if choice.losses 346 + error_message = ""
  347 + success_message = "2 x Total Wins = Total Votes\n" +
  348 + "Total Votes (wins + losses) is Even\n" +
  349 + "Total Votes (wins + losses) = 2 x the number of vote objects that belong to the question\n" +
  350 + "Total generated prompts on left = Total generated prompts on right"
  351 + total_wins =0
  352 + total_votes =0
  353 + total_generated_prompts_on_left = 0
  354 + total_generated_prompts_on_right = 0
  355 + total_scores_gte_fifty= 0
  356 + total_scores_lte_fifty= 0
  357 + error_bool = false
  358 +
  359 + question.choices.each do |choice|
  360 +
  361 + if choice.wins
  362 + total_wins += choice.wins
  363 + total_votes += choice.wins
  364 + end
  365 +
  366 + if choice.losses
365 total_votes += choice.losses 367 total_votes += choice.losses
366 - end 368 + end
367 369
368 - total_generated_prompts_on_left += choice.prompts_on_the_left.size  
369 - total_generated_prompts_on_right += choice.prompts_on_the_right.size 370 + total_generated_prompts_on_left += choice.prompts_on_the_left.size
  371 + total_generated_prompts_on_right += choice.prompts_on_the_right.size
370 372
371 - cached_score = choice.score.to_f  
372 - generated_score = choice.compute_score.to_f 373 + cached_score = choice.score.to_f
  374 + generated_score = choice.compute_score.to_f
373 375
374 - delta = 0.001 376 + delta = 0.001
375 377
376 - if (cached_score - generated_score).abs >= delta  
377 - error_message += "Error! The cached_score is not equal to the calculated score for choice #{choice.id}\n" 378 + if (cached_score - generated_score).abs >= delta
  379 + error_message += "Error! The cached_score is not equal to the calculated score for choice #{choice.id}\n"
378 380
379 - print "This score is wrong! #{choice.id} , Question ID: #{question.id}, #{cached_score}, #{generated_score}, updated: #{choice.updated_at}\n" 381 + print "This score is wrong! #{choice.id} , Question ID: #{question.id}, #{cached_score}, #{generated_score}, updated: #{choice.updated_at}\n"
380 382
381 383
382 - end 384 + end
383 385
384 - if cached_score == 0.0 || cached_score == 100.0 || cached_score.nil?  
385 - error_message += "Error! The cached_score for choice #{choice.id} is exactly 0 or 100, the value: #{cached_score}"  
386 - print "Either 0 or 100 This score is wrong! #{choice.id} , Question ID: #{question.id}, #{cached_score}, #{generated_score}, updated: #{choice.updated_at}\n"  
387 - end 386 + if cached_score == 0.0 || cached_score == 100.0 || cached_score.nil?
  387 + error_message += "Error! The cached_score for choice #{choice.id} is exactly 0 or 100, the value: #{cached_score}"
  388 + print "Either 0 or 100 This score is wrong! #{choice.id} , Question ID: #{question.id}, #{cached_score}, #{generated_score}, updated: #{choice.updated_at}\n"
  389 + end
388 390
389 391
390 - if cached_score >= 50  
391 - total_scores_gte_fifty +=1  
392 - end  
393 - if cached_score <= 50  
394 - total_scores_lte_fifty +=1  
395 - end 392 + if cached_score >= 50
  393 + total_scores_gte_fifty +=1
  394 + end
  395 + if cached_score <= 50
  396 + total_scores_lte_fifty +=1
  397 + end
396 398
397 - if (choice.wins != choice.votes.count)  
398 - error_message += "Error!: Cached choice wins != actual choice wins for choice #{choice.id}\n"  
399 - error_bool= true  
400 - end  
401 -  
402 - if (choice.losses != question.votes.count(:conditions => {:loser_choice_id => choice.id}))  
403 - error_message += "Error!: Cached choice wins != actual choice wins for choice #{choice.id}\n"  
404 - error_bool= true  
405 - end 399 + if (choice.wins != choice.votes.count)
  400 + error_message += "Error!: Cached choice wins != actual choice wins for choice #{choice.id}\n"
  401 + error_bool= true
  402 + end
  403 +
  404 + if (choice.losses != question.votes.count(:conditions => {:loser_choice_id => choice.id}))
  405 + error_message += "Error!: Cached choice wins != actual choice wins for choice #{choice.id}\n"
  406 + error_bool= true
  407 + end
406 408
407 end 409 end
408 -  
409 -  
410 - if (2*total_wins != total_votes)  
411 - error_message += "Error 1: 2 x Total Wins != Total votes"  
412 - error_bool= true  
413 - end  
414 -  
415 - if(total_votes % 2 != 0)  
416 - error_message += "Error 2: Total votes is not Even!"  
417 - error_bool= true  
418 - end  
419 -  
420 - if(total_votes != 2* question.votes_count)  
421 - error_message += "Error 3: Total votes != 2 x # vote objects"  
422 - error_bool = true  
423 - end  
424 -  
425 - if(total_generated_prompts_on_right != total_generated_prompts_on_right)  
426 - error_message += "Error 4: Total generated prompts on left != Total generated prompts on right"  
427 - error_bool = true  
428 - end  
429 -  
430 - if(total_scores_lte_fifty == question.choices.size || total_scores_gte_fifty == question.choices.size) && (total_scores_lte_fifty != total_scores_gte_fifty)  
431 - error_message += "Error: The scores of all choices are either all above 50, or all below 50. This is probably wrong"  
432 - error_bool = true  
433 - puts "Error score fifty: #{question.id}"  
434 - end  
435 -  
436 - if error_bool  
437 - error_message += "Question #{question.id}: 2*wins = #{2*total_wins}, total votes = #{total_votes}, vote_count = #{question.votes_count}\n"  
438 - end 410 +
  411 +
  412 + if (2*total_wins != total_votes)
  413 + error_message += "Error 1: 2 x Total Wins != Total votes"
  414 + error_bool= true
  415 + end
  416 +
  417 + if(total_votes % 2 != 0)
  418 + error_message += "Error 2: Total votes is not Even!"
  419 + error_bool= true
  420 + end
  421 +
  422 + if(total_votes != 2* question.votes_count)
  423 + error_message += "Error 3: Total votes != 2 x # vote objects"
  424 + error_bool = true
  425 + end
  426 +
  427 + if(total_generated_prompts_on_right != total_generated_prompts_on_right)
  428 + error_message += "Error 4: Total generated prompts on left != Total generated prompts on right"
  429 + error_bool = true
  430 + end
  431 +
  432 + if(total_scores_lte_fifty == question.choices.size || total_scores_gte_fifty == question.choices.size) && (total_scores_lte_fifty != total_scores_gte_fifty)
  433 + error_message += "Error: The scores of all choices are either all above 50, or all below 50. This is probably wrong"
  434 + error_bool = true
  435 + puts "Error score fifty: #{question.id}"
  436 + end
  437 +
  438 + if error_bool
  439 + error_message += "Question #{question.id}: 2*wins = #{2*total_wins}, total votes = #{total_votes}, vote_count = #{question.votes_count}\n"
  440 + end
439 return error_message.blank? ? [success_message, false] : [error_message, true] 441 return error_message.blank? ? [success_message, false] : [error_message, true]
440 end 442 end
441 def check_each_choice_appears_within_n_stddevs(question) 443 def check_each_choice_appears_within_n_stddevs(question)
442 - error_message =""  
443 - success_message = "Each choice has appeared n times, where n falls within 6 stddevs of the mean number of appearances for a question " +  
444 - "(Note: this applies only to seed choices (not user submitted) and choices currently marked active)" 444 + error_message =""
  445 + success_message = "Each choice has appeared n times, where n falls within 6 stddevs of the mean number of appearances for a question " +
  446 + "(Note: this applies only to seed choices (not user submitted) and choices currently marked active)"
445 447
446 - wins_by_choice_id = question.votes.active.count(:group => :choice_id)  
447 - losses_by_choice_id= question.votes.active.count(:conditions => "loser_choice_id IS NOT NULL", :group => :loser_choice_id) 448 + wins_by_choice_id = question.votes.active.count(:group => :choice_id)
  449 + losses_by_choice_id= question.votes.active.count(:conditions => "loser_choice_id IS NOT NULL", :group => :loser_choice_id)
448 450
449 - #Rails returns an ordered hash, which doesn't allow for blocks to change merging logic.  
450 - #A little hack to create a normal hash  
451 - wins_hash = {}  
452 - wins_hash.merge!(wins_by_choice_id)  
453 - losses_hash = {}  
454 - losses_hash.merge!(losses_by_choice_id) 451 + #Rails returns an ordered hash, which doesn't allow for blocks to change merging logic.
  452 + #A little hack to create a normal hash
  453 + wins_hash = {}
  454 + wins_hash.merge!(wins_by_choice_id)
  455 + losses_hash = {}
  456 + losses_hash.merge!(losses_by_choice_id)
455 457
456 458
457 459
458 - appearances_by_choice_id = wins_hash.merge(losses_hash) do |key, oldval, newval| oldval + newval end 460 + appearances_by_choice_id = wins_hash.merge(losses_hash) do |key, oldval, newval| oldval + newval end
459 461
460 - sum = total_appearances = appearances_by_choice_id.values.inject(0) {|sum, x| sum +=x}  
461 - mean = average_appearances = total_appearances.to_f / appearances_by_choice_id.size.to_f 462 + sum = total_appearances = appearances_by_choice_id.values.inject(0) {|sum, x| sum +=x}
  463 + mean = average_appearances = total_appearances.to_f / appearances_by_choice_id.size.to_f
462 464
463 - if sum > 0:  
464 - stddev = Math.sqrt( appearances_by_choice_id.values.inject(0) { |sum, e| sum + (e - mean) ** 2 } / appearances_by_choice_id.size.to_f ) 465 + if sum > 0:
  466 + stddev = Math.sqrt( appearances_by_choice_id.values.inject(0) { |sum, e| sum + (e - mean) ** 2 } / appearances_by_choice_id.size.to_f )
465 467
466 appearances_by_choice_id.each do |choice_id, n_i| 468 appearances_by_choice_id.each do |choice_id, n_i|
467 - if (n_i < (mean - 6*stddev)) || (n_i > mean + 6 *stddev)  
468 - 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"  
469 - end  
470 - end  
471 - end 469 + if (n_i < (mean - 6*stddev)) || (n_i > mean + 6 *stddev)
  470 + 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"
  471 + end
  472 + end
  473 + end
472 474
473 return error_message.blank? ? [success_message, false] : [error_message, true] 475 return error_message.blank? ? [success_message, false] : [error_message, true]
474 end 476 end
475 def check_each_choice_equally_likely_to_appear_left_or_right(question) 477 def check_each_choice_equally_likely_to_appear_left_or_right(question)
476 - error_message = ""  
477 - success_message = "All choices have equal probability of appearing on left or right (within error params)"  
478 - question.choices.each do |c|  
479 - left_prompts_ids = c.prompts_on_the_left.ids_only  
480 - right_prompts_ids = c.prompts_on_the_right.ids_only  
481 -  
482 - left_appearances = question.appearances.count(:conditions => {:prompt_id => left_prompts_ids})  
483 - right_appearances = question.appearances.count(:conditions => {:prompt_id => right_prompts_ids})  
484 -  
485 - n = left_appearances + right_appearances  
486 -  
487 - if n == 0  
488 - next  
489 - end  
490 - est_p = right_appearances.to_f / n.to_f  
491 - z = (est_p - 0.5).abs / Math.sqrt((0.5 * 0.5) / n.to_f)  
492 -  
493 - if z > 6  
494 - error_message += "Error: Choice ID #{c.id} seems to favor one side: Left Appearances #{left_appearances}, Right Appearances: #{right_appearances}, z = #{z}\n"  
495 - end  
496 - end 478 + error_message = ""
  479 + success_message = "All choices have equal probability of appearing on left or right (within error params)"
  480 + question.choices.each do |c|
  481 + left_prompts_ids = c.prompts_on_the_left.ids_only
  482 + right_prompts_ids = c.prompts_on_the_right.ids_only
  483 +
  484 + left_appearances = question.appearances.count(:conditions => {:prompt_id => left_prompts_ids})
  485 + right_appearances = question.appearances.count(:conditions => {:prompt_id => right_prompts_ids})
  486 +
  487 + n = left_appearances + right_appearances
  488 +
  489 + if n == 0
  490 + next
  491 + end
  492 + est_p = right_appearances.to_f / n.to_f
  493 + z = (est_p - 0.5).abs / Math.sqrt((0.5 * 0.5) / n.to_f)
  494 +
  495 + if z > 6
  496 + error_message += "Error: Choice ID #{c.id} seems to favor one side: Left Appearances #{left_appearances}, Right Appearances: #{right_appearances}, z = #{z}\n"
  497 + end
  498 + end
497 return error_message.blank? ? [success_message, false] : [error_message, true] 499 return error_message.blank? ? [success_message, false] : [error_message, true]
498 end 500 end
499 def check_prompt_cache_hit_rate(question) 501 def check_prompt_cache_hit_rate(question)
500 - error_message = ""  
501 - success_message = "At least 90% of prompts on catchup algorithm questions were served from cache\n"  
502 -  
503 - misses = question.get_prompt_cache_misses(Date.yesterday).to_i  
504 - hits = question.get_prompt_cache_hits(Date.yesterday).to_i  
505 -  
506 - question.expire_prompt_cache_tracking_keys(Date.yesterday)  
507 -  
508 - yesterday_appearances = question.appearances.count(:conditions => ['date(created_at) = ?', Date.yesterday])  
509 -  
510 - if misses + hits != yesterday_appearances  
511 - error_message += "Error! Question #{question.id} isn't tracking prompt cache hits and misses accurately! Expected #{yesterday_appearances}, Actual: #{misses+hits}\n"  
512 - end  
513 -  
514 - if yesterday_appearances > 5 # this test isn't worthwhile for small numbers of appearances  
515 - miss_rate = misses.to_f / yesterday_appearances.to_f  
516 - if miss_rate > 0.1  
517 - 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"  
518 - end 502 + error_message = ""
  503 + success_message = "At least 90% of prompts on catchup algorithm questions were served from cache\n"
  504 +
  505 + misses = question.get_prompt_cache_misses(Date.yesterday).to_i
  506 + hits = question.get_prompt_cache_hits(Date.yesterday).to_i
  507 +
  508 + question.expire_prompt_cache_tracking_keys(Date.yesterday)
  509 +
  510 + yesterday_appearances = question.appearances.count(:conditions => ['date(created_at) = ?', Date.yesterday])
  511 +
  512 + if misses + hits != yesterday_appearances
  513 + error_message += "Error! Question #{question.id} isn't tracking prompt cache hits and misses accurately! Expected #{yesterday_appearances}, Actual: #{misses+hits}\n"
  514 + end
  515 +
  516 + if yesterday_appearances > 5 # this test isn't worthwhile for small numbers of appearances
  517 + miss_rate = misses.to_f / yesterday_appearances.to_f
  518 + if miss_rate > 0.1
  519 + 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"
  520 + end
519 end 521 end
520 return error_message.blank? ? [success_message, false] : [error_message, true] 522 return error_message.blank? ? [success_message, false] : [error_message, true]
521 end 523 end
@@ -524,30 +526,30 @@ namespace :test_api do @@ -524,30 +526,30 @@ namespace :test_api do
524 error_message = "" 526 error_message = ""
525 success_message = "All cached object values match actual values within database" 527 success_message = "All cached object values match actual values within database"
526 # Checks that counter_cache is working as expected 528 # Checks that counter_cache is working as expected
527 - cached_prompts_size = question.prompts.size  
528 - actual_prompts_size = question.prompts.count  
529 -  
530 - if cached_prompts_size != actual_prompts_size  
531 - error_message += "Error! Question #{question.id} has an inconsistent # of prompts! cached#: #{cached_prompts_size}, actual#: #{actual_prompts_size}\n"  
532 - end  
533 -  
534 - cached_votes_size = question.votes.size  
535 - actual_votes_size = question.votes.count  
536 -  
537 - if cached_votes_size != actual_votes_size  
538 - error_message += "Error! Question #{question.id} has an inconsistent # of votes! cached#: #{cached_votes_size}, actual#: #{actual_votes_size}\n"  
539 - end  
540 -  
541 - cached_choices_size = question.choices.size  
542 - actual_choices_size = question.choices.count  
543 -  
544 - if cached_choices_size != actual_choices_size  
545 - error_message+= "Error! Question #{question.id} has an inconsistent # of choices! cached#: #{cached_choices_size}, actual#: #{actual_choices_size}\n"  
546 - end  
547 -  
548 - #if cached_prompts_size != question.choices.size **2 - question.choices.size  
549 - # 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"  
550 - #end 529 + cached_prompts_size = question.prompts.size
  530 + actual_prompts_size = question.prompts.count
  531 +
  532 + if cached_prompts_size != actual_prompts_size
  533 + error_message += "Error! Question #{question.id} has an inconsistent # of prompts! cached#: #{cached_prompts_size}, actual#: #{actual_prompts_size}\n"
  534 + end
  535 +
  536 + cached_votes_size = question.votes.size
  537 + actual_votes_size = question.votes.count
  538 +
  539 + if cached_votes_size != actual_votes_size
  540 + error_message += "Error! Question #{question.id} has an inconsistent # of votes! cached#: #{cached_votes_size}, actual#: #{actual_votes_size}\n"
  541 + end
  542 +
  543 + cached_choices_size = question.choices.size
  544 + actual_choices_size = question.choices.count
  545 +
  546 + if cached_choices_size != actual_choices_size
  547 + error_message+= "Error! Question #{question.id} has an inconsistent # of choices! cached#: #{cached_choices_size}, actual#: #{actual_choices_size}\n"
  548 + end
  549 +
  550 + #if cached_prompts_size != question.choices.size **2 - question.choices.size
  551 + # 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"
  552 + #end
551 return error_message.blank? ? [success_message, false] : [error_message, true] 553 return error_message.blank? ? [success_message, false] : [error_message, true]
552 end 554 end
553 555
@@ -561,7 +563,7 @@ namespace :test_api do @@ -561,7 +563,7 @@ namespace :test_api do
561 563
562 if (total_answered_appearances != total_votes+ total_skips) 564 if (total_answered_appearances != total_votes+ total_skips)
563 difference = (total_votes+ total_skips) - total_answered_appearances 565 difference = (total_votes+ total_skips) - total_answered_appearances
564 - error_message += "Error! There are #{difference} votes or skips without associated appearance objects." 566 + error_message += "Error! There are #{difference} votes or skips without associated appearance objects."
565 end 567 end
566 568
567 return error_message.blank? ? [success_message, false] : [error_message, true] 569 return error_message.blank? ? [success_message, false] : [error_message, true]
@@ -575,32 +577,32 @@ namespace :test_api do @@ -575,32 +577,32 @@ namespace :test_api do
575 577
576 Vote.find_each(:batch_size => 1000, :include => :appearance) do |v| 578 Vote.find_each(:batch_size => 1000, :include => :appearance) do |v|
577 579
578 - # Subtracting DateTime objects results in the difference in days  
579 - server_response_time = v.created_at.to_f - v.appearance.created_at.to_f  
580 - if server_response_time < 0  
581 - 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" 580 + # Subtracting DateTime objects results in the difference in days
  581 + server_response_time = v.created_at.to_f - v.appearance.created_at.to_f
  582 + if server_response_time < 0
  583 + 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"
582 584
583 - error_message += the_error_msg  
584 - print "Error!" + the_error_msg  
585 - end 585 + error_message += the_error_msg
  586 + print "Error!" + the_error_msg
  587 + end
586 588
587 - if v.time_viewed && v.time_viewed/1000 > server_response_time  
588 - 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" 589 + if v.time_viewed && v.time_viewed/1000 > server_response_time
  590 + 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"
589 591
590 - error_message += the_error_msg  
591 - print the_error_msg 592 + error_message += the_error_msg
  593 + print the_error_msg
592 594
593 elsif v.time_viewed.nil? 595 elsif v.time_viewed.nil?
594 - if v.created_at > recording_client_time_start_date && v.missing_response_time_exp != 'invalid'  
595 - 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"  
596 - error_message += the_error_msg  
597 - print the_error_msg  
598 - end 596 + if v.created_at > recording_client_time_start_date && v.missing_response_time_exp != 'invalid'
  597 + 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"
  598 + error_message += the_error_msg
  599 + print the_error_msg
  600 + end
599 601
600 - end 602 + end
601 603
602 end 604 end
603 - 605 +
604 return error_message.blank? ? [success_message, false] : [error_message, true] 606 return error_message.blank? ? [success_message, false] : [error_message, true]
605 end 607 end
606 end 608 end