soda 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,470 @@
1
+ ###############################################################################
2
+ # Copyright (c) 2010, SugarCRM, Inc.
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ # * Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ # * Redistributions in binary form must reproduce the above copyright
10
+ # notice, this list of conditions and the following disclaimer in the
11
+ # documentation and/or other materials provided with the distribution.
12
+ # * Neither the name of SugarCRM, Inc. nor the
13
+ # names of its contributors may be used to endorse or promote products
14
+ # derived from this software without specific prior written permission.
15
+ #
16
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ # ARE DISCLAIMED. IN NO EVENT SHALL SugarCRM, Inc. BE LIABLE FOR ANY
20
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ ###############################################################################
27
+
28
+ ###############################################################################
29
+ # Needed Ruby libs:
30
+ ###############################################################################
31
+ require 'getoptlong'
32
+ require 'date'
33
+
34
+ class SodaReportSummery
35
+
36
+ ###############################################################################
37
+ # initialize -- constructor
38
+ # This is the class constructor. Really this does all the needed work.
39
+ #
40
+ # Params:
41
+ # dir: This is the dorectory with raw soda logs in it.
42
+ # outfile: This is the new summery html file to create.
43
+ # create_links: This will create links to the soda report files in the
44
+ # summery.
45
+ #
46
+ # Results:
47
+ # Creates a new class and html summery file. Will raise and exception on
48
+ # any errors.
49
+ #
50
+ ###############################################################################
51
+ def initialize(dir ="", outfile = "", create_links = false)
52
+ log_files = nil
53
+ report_data = nil
54
+ result = 0
55
+ html_tmp_file = ""
56
+ timout = true
57
+
58
+ if (dir.empty?)
59
+ raise "Empty 'dir' param!\n"
60
+ elsif (outfile.empty?)
61
+ raise "Empty 'outfile param!"
62
+ end
63
+
64
+ html_tmp_file = File.dirname(outfile)
65
+ html_tmp_file += "/summery.tmp"
66
+
67
+ for i in 0..120
68
+ if (!File.exist?(html_tmp_file))
69
+ timeout = false
70
+ break
71
+ end
72
+
73
+ timeout = true
74
+ sleep(1)
75
+ end
76
+
77
+ # if (timeout != false)
78
+ # raise "Timed out waiting for lock to be released on file:"+
79
+ # " \"#{html_tmp_file}\"!\n"
80
+ # end
81
+
82
+ log_files = GetLogFiles(dir)
83
+ if ( (log_files == nil) || (log_files.length < 1) )
84
+ raise "Failed calling: GetLogFiles(#{dir})!"
85
+ end
86
+
87
+ report_data = GenerateReportData(log_files)
88
+ if (report_data.length < 1)
89
+ raise "No report data found when calling: GenerateReportData()!"
90
+ end
91
+
92
+ result = GenHtmlReport(report_data, html_tmp_file, create_links)
93
+ if (result != 0)
94
+ raise "Failed calling: GenHtmlReport()!"
95
+ end
96
+
97
+ File.rename(html_tmp_file, outfile)
98
+
99
+ end
100
+
101
+ ###############################################################################
102
+ # GetLogFiles -- method
103
+ # This function gets all the log files in a given dir puts them in a list.
104
+ #
105
+ # Params:
106
+ # dir: this is the directory that holds the log files.
107
+ #
108
+ # Results:
109
+ # returns nil on error, else a list of all the log files in the dir.
110
+ #
111
+ ###############################################################################
112
+ def GetLogFiles(dir)
113
+ files = nil
114
+
115
+ if (!File.directory?(dir))
116
+ print "(!)Error: #{dir} is not a directory!\n"
117
+ return nil
118
+ end
119
+
120
+ files = File.join("#{dir}", "*.log")
121
+ files = Dir.glob(files)
122
+ files = files.sort()
123
+ return files
124
+ end
125
+
126
+ private :GetLogFiles
127
+
128
+ ###############################################################################
129
+ # GenerateReportData -- method
130
+ # This function generates needed data from each file passed in.
131
+ #
132
+ # Params:
133
+ # files: This is a list of files to read data from.
134
+ #
135
+ # Results:
136
+ # returns an array of hashed data.
137
+ #
138
+ ###############################################################################
139
+ def GenerateReportData(files)
140
+ test_info = []
141
+
142
+ files.each do |f|
143
+ line = ""
144
+ hash = Hash.new()
145
+ hash['test_start_time'] = ""
146
+ hash['test_end_time'] = ""
147
+ hash['test_report_line'] = ""
148
+ hash['test_file'] = ""
149
+ hash['log_file'] = "#{f}"
150
+ hash['report_hash'] = nil
151
+ hash['total_tests'] = 0
152
+
153
+ print "(*)Opening file: #{f}\n"
154
+ logfd = File.open(f, "r")
155
+ while ( (line = logfd.gets) != nil)
156
+ line = line.chomp()
157
+ case line
158
+ when /\[new\s+test\]/i
159
+ if (!hash['test_start_time'].empty?)
160
+ next
161
+ end
162
+
163
+ line =~ /^\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\]/
164
+ hash['test_start_time'] = "#{$1}"
165
+ when /starting\s+soda\s+test:/i
166
+ if (!hash['test_file'].empty?)
167
+ next
168
+ end
169
+
170
+ data = line.split(/:/)
171
+ test_file = "#{data[data.length() -1]}"
172
+ test_file = test_file.gsub(/^\s+/, "")
173
+ hash['test_file'] = "#{test_file}"
174
+ when /\[end\s+test\]/i
175
+ line =~ /^\[(\d+\/\d+\/\d+-\d+:\d+:\d+)\]/
176
+ hash['test_end_time'] = "#{$1}"
177
+ when /soda\s+test\s+report:/i
178
+ report_hash = Hash.new()
179
+ line = line.gsub(/^(\[\d+\/\d+\/\d+-\d+:\d+:\d+\])\(\*\)/, "")
180
+ line = line.gsub(/^soda\s+test\s+report:/i, "")
181
+ line_data = line.split("--")
182
+ line_data.each do |data|
183
+ if (data.empty?)
184
+ next
185
+ end
186
+
187
+ data = data.split(/:/)
188
+ data[1] = data[1].gsub(/^\s+/, "")
189
+ report_hash["#{data[0]}"] = data[1]
190
+ end
191
+ hash['report_hash'] = report_hash
192
+ test_info.push(hash)
193
+ end # end case #
194
+ end
195
+ logfd.close()
196
+
197
+ end
198
+
199
+ return test_info
200
+ end
201
+
202
+ private :GenerateReportData
203
+
204
+ ###############################################################################
205
+ # GenHtmlReport -- method
206
+ # This function generates an html report from an array of hashed data.
207
+ #
208
+ # Params:
209
+ # data: An array of hashs
210
+ # reportfile: This is the html file to create.
211
+ #
212
+ # Results:
213
+ # Creates an html report file. Retruns -1 on error, else 0 on success.
214
+ #
215
+ ###############################################################################
216
+ def GenHtmlReport(data, reportfile, create_links = false)
217
+ fd = nil
218
+ result = 0
219
+ totals = {}
220
+ log_file_td = ""
221
+ report_file = ""
222
+ now = nil
223
+
224
+ totals['Test Failure Count'] = 0
225
+ totals['Test CSS Error Count'] = 0
226
+ totals['Test JavaScript Error Count'] = 0
227
+ totals['Test Assert Failures'] = 0
228
+ totals['Test Event Count'] = 0
229
+ totals['Test Assert Count'] = 0
230
+ totals['Test Exceptions'] = 0
231
+ totals['Test Major Exceptions'] = 0
232
+ totals['Test Count'] = 0
233
+ totals['Test Skip Count'] = 0
234
+ totals['running_time'] = nil
235
+
236
+ begin
237
+ fd = File.new(reportfile, "w+")
238
+ rescue Exception => e
239
+ fd = nil
240
+ result = -1
241
+ print "Error: trying to open file!\n"
242
+ print "Exception: #{e.message}\n"
243
+ print "StackTrace: #{e.backtrace.join("\n")}\n"
244
+ ensure
245
+ if (result != 0)
246
+ return -1
247
+ end
248
+ end
249
+
250
+ now = Time.now.getlocal()
251
+ html_header = <<HTML
252
+ <html>
253
+ <style type="text/css">
254
+ body
255
+ {
256
+ margin: 0px;
257
+ font-family: Arial, Verdana, Helvetica, sans-serif;
258
+ }
259
+
260
+ a:hover
261
+ {
262
+ color: #24f938;
263
+ }
264
+
265
+ fieldset, table, pre
266
+ {
267
+ margin-bottom:0;
268
+ }
269
+
270
+ p
271
+ {
272
+ margin-top: 0px;
273
+ margin-bottom: 0px;
274
+ font-family: Arial, Verdana, Helvetica, sans-serif;
275
+ font-size: 11px;
276
+ }
277
+
278
+ li
279
+ {
280
+ margin-top: 0px;
281
+ margin-bottom: 0px;
282
+ font-family: Arial, Verdana, Helvetica, sans-serif;
283
+ font-size: 11px;
284
+ }
285
+
286
+ td
287
+ {
288
+ text-align: center;
289
+ vertical-align: middle;
290
+ }
291
+
292
+ .td_file
293
+ {
294
+ text-align: left;
295
+ vertical-align: middle;
296
+ white-space: nowrap;
297
+ }
298
+
299
+ .tr_normal
300
+ {
301
+ background: #e5eef3;
302
+ }
303
+
304
+ .highlight {
305
+ background-color: #8888FF;
306
+ }
307
+
308
+ .tr_header
309
+ {
310
+ white-space: nowrap;
311
+ background: #a4a4a4;
312
+ font-weight: bold;
313
+ }
314
+
315
+ table
316
+ {
317
+ background: #ffff;
318
+ border: 1px solid black;
319
+ border-bottom: 1px solid #0000;
320
+ border-right: 1px solid #0000;
321
+ color: #0000;
322
+ padding: 4px;
323
+ font-size: 11px;
324
+ }
325
+ </style>
326
+ <title>Soda Global Report Summery: #{now}</title>
327
+ <body>
328
+ <li>#{now}</li>
329
+ <table>
330
+ <tr class="tr_header">
331
+ \t<td>Test File:<br>
332
+ \tClick link for full report</td>
333
+ \t<td>Test Count:</td>
334
+ \t<td>Test Skip Count:</td>
335
+ \t<td>Failure Count:</td>
336
+ \t<td>CSS Error Count:</td>
337
+ \t<td>JavaScript Error Count:</td>
338
+ \t<td>Assert Failures:</td>
339
+ \t<td>Event Count:</td>
340
+ \t<td>Assert Count:</td>
341
+ \t<td>Exceptions:</td>
342
+ \t<td>Major Exceptions:</td>
343
+ \t<td>Running Time:<br>(hh:mm:ss):</td>
344
+ </tr>
345
+ HTML
346
+
347
+ fd.write(html_header)
348
+
349
+ data.each do |rpt|
350
+ totals['Test Failure Count'] +=
351
+ rpt['report_hash']['Test Failure Count'].to_i()
352
+ totals['Test CSS Error Count'] +=
353
+ rpt['report_hash']['Test CSS Error Count'].to_i()
354
+ totals['Test JavaScript Error Count'] +=
355
+ rpt['report_hash']['Test JavaScript Error Count'].to_i()
356
+ totals['Test Assert Failures'] +=
357
+ rpt['report_hash']['Test Assert Failures'].to_i()
358
+ totals['Test Event Count'] +=
359
+ rpt['report_hash']['Test Event Count'].to_i()
360
+ totals['Test Assert Count'] +=
361
+ rpt['report_hash']['Test Assert Count'].to_i()
362
+ totals['Test Exceptions'] +=
363
+ rpt['report_hash']['Test Exceptions'].to_i()
364
+ totals['Test Major Exceptions'] +=
365
+ rpt['report_hash']['Test Major Exceptions'].to_i()
366
+ totals['Test Count'] += rpt['report_hash']['Test Count'].to_i()
367
+ totals['Test Skip Count'] += rpt['report_hash']['Test Skip Count'].to_i()
368
+
369
+ start_time = DateTime.strptime("#{rpt['test_start_time']}",
370
+ "%m/%d/%Y-%H:%M:%S")
371
+ stop_time = DateTime.strptime("#{rpt['test_end_time']}",
372
+ "%m/%d/%Y-%H:%M:%S")
373
+ time_diff = stop_time - start_time
374
+ if (totals['running_time'] == nil)
375
+ totals['running_time'] = time_diff
376
+ else
377
+ totals['running_time'] += time_diff
378
+ end
379
+ hours,minutes,seconds,frac = Date.day_fraction_to_time(time_diff)
380
+
381
+ rpt['report_hash'].each do |k,v|
382
+ if ( (v.to_i > 0) && (k !~ /test\s+assert\s+count/i) &&
383
+ (k !~ /test\s+event\s+count/i) &&
384
+ (k !~ /css\s+error\s+count/i) &&
385
+ (k !~ /test\s+count/i))
386
+ tmp = '<font color="#FF0000"><b>'
387
+ tmp += "#{v}</b></font>"
388
+ rpt['report_hash'][k] = tmp
389
+ end
390
+ end
391
+
392
+ report_file = File.basename(rpt['log_file'], ".log")
393
+ report_file = "Report-#{report_file}.html"
394
+
395
+ if (create_links)
396
+ rerun = ""
397
+ if (report_file =~ /-SodaRerun/i)
398
+ rerun = "<b> :Rerun</b>"
399
+ end
400
+ log_file_td = "<a href=\"#{report_file}\">#{rpt['test_file']}</a>"+
401
+ "#{rerun}"
402
+ else
403
+ log_file_td = "#{rpt['test_file']}"
404
+ end
405
+
406
+ str = "<tr class=\"tr_normal\" "+
407
+ "onMouseOver=\"this.className='highlight'\" "+
408
+ "onMouseOut=\"this.className='tr_normal'\">\n" +
409
+ "\t<td class=\"td_file\">#{log_file_td}</td>\n" +
410
+ "\t<td>#{rpt['report_hash']['Test Count']}</td>\n"+
411
+ "\t<td>#{rpt['report_hash']['Test Skip Count']}</td>\n"+
412
+ "\t<td>#{rpt['report_hash']['Test Failure Count']}</td>\n"+
413
+ "\t<td>#{rpt['report_hash']['Test CSS Error Count']}</td>\n" +
414
+ "\t<td>#{rpt['report_hash']['Test JavaScript Error Count']}</td>\n" +
415
+ "\t<td>#{rpt['report_hash']['Test Assert Failures']}</td>\n" +
416
+ "\t<td>#{rpt['report_hash']['Test Event Count']}</td>\n" +
417
+ "\t<td>#{rpt['report_hash']['Test Assert Count']}</td>\n" +
418
+ "\t<td>#{rpt['report_hash']['Test Exceptions']}</td>\n" +
419
+ "\t<td>#{rpt['report_hash']['Test Major Exceptions']}</td>\n" +
420
+ "\t<td>#{hours}:#{minutes}:#{seconds}</td>\n</tr>\n"
421
+ fd.write(str)
422
+ end
423
+
424
+ hours,minutes,seconds,frac =
425
+ Date.day_fraction_to_time(totals['running_time'])
426
+
427
+ totals.each do |k,v|
428
+ if ( (v.to_i > 0) && (k !~ /test\s+assert\s+count/i) &&
429
+ (k !~ /test\s+event\s+count/i) &&
430
+ (k !~ /css\s+error\s+count/i) &&
431
+ (k !~ /test\s+count/i) )
432
+
433
+ tmp = '<font color="#FF0000"><b>'
434
+ tmp += "#{v}</b></font>"
435
+ totals[k] = tmp
436
+ end
437
+ end
438
+
439
+ totals['Test Skip Count'] = totals['Test Skip Count'].to_i()
440
+ test_totals = totals['Test Count'] + totals['Test Skip Count']
441
+ sub_totals = "<tr class=\"tr_header\">\n"+
442
+ "\t<td>Totals:</td>\n"+
443
+ "\t<td>#{totals['Test Count']}</td>\n"+
444
+ "\t<td>#{totals['Test Skip Count']}</td>\n"+
445
+ "\t<td>#{totals['Test Failure Count']}</td>\n"+
446
+ "\t<td>#{totals['Test CSS Error Count']}</td>\n"+
447
+ "\t<td>#{totals['Test JavaScript Error Count']}</td>\n"+
448
+ "\t<td>#{totals['Test Assert Failures']}</td>\n"+
449
+ "\t<td>#{totals['Test Event Count']}</td>\n"+
450
+ "\t<td>#{totals['Test Assert Count']}</td>\n"+
451
+ "\t<td>#{totals['Test Exceptions']}</td>\n"+
452
+ "\t<td>#{totals['Test Major Exceptions']}</td>\n"+
453
+ "\t<td>#{hours}:#{minutes}:#{seconds}</td>\n"+
454
+ "</tr>\n" +
455
+ "<tr class=\"tr_header\">\n"+
456
+ "\t<td>Total Test Count:</td>\n"+
457
+ "\t<td colspan=\"2\">#{test_totals}</td>\n</tr>\n"
458
+
459
+ fd.write(sub_totals)
460
+ fd.write("</table>\n</body>\n</html>\n")
461
+ fd.close()
462
+
463
+ return result
464
+
465
+ end
466
+ private :GenHtmlReport
467
+
468
+ end
469
+
470
+