soda 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+