mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Report generators for unit tests and memory checks. Configure with
--enable-testing.
This commit is contained in:
parent
60f425d1b3
commit
1033d12040
20
Makefile.in
20
Makefile.in
@ -127,3 +127,23 @@ lcov: $(LCOV_TRACES)
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
ifeq ("$(TESTING)", "yes")
|
||||
# testing and report generation
|
||||
RUBY=ruby1.9 -Ireport-generators/lib -Ireport-generators/test
|
||||
|
||||
.PHONEY: unit-test ruby-test test-programs
|
||||
|
||||
test-programs:
|
||||
|
||||
unit-test: test-programs
|
||||
$(RUBY) report-generators/unit_test.rb $(shell find . -name TESTS)
|
||||
$(RUBY) report-generators/title_page.rb
|
||||
|
||||
memcheck: test-programs
|
||||
$(RUBY) report-generators/memcheck.rb $(shell find . -name TESTS)
|
||||
$(RUBY) report-generators/title_page.rb
|
||||
|
||||
ruby-test:
|
||||
$(RUBY) report-generators/test/ts.rb
|
||||
endif
|
17
configure.in
17
configure.in
@ -700,6 +700,22 @@ if test "x$PROFILING" = xyes; then
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable testing
|
||||
AC_MSG_CHECKING(whether to enable unit testing)
|
||||
AC_ARG_ENABLE(testing,
|
||||
AC_HELP_STRING(--enable-testing, [enable testing targets in the makefile]),
|
||||
TESTING=$enableval, TESTING=no)
|
||||
AC_MSG_RESULT($TESTING)
|
||||
|
||||
if test "$TESTING" = yes; then
|
||||
AC_PATH_PROG(RUBY19, ruby1.9)
|
||||
AC_PATH_PROG(VALGRIND, valgrind)
|
||||
if test -z "$RUBY19" -o -z "$VALGRIND"; then
|
||||
AC_MSG_ERROR([ruby1.9 and valgrind are required for testing])
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable devmapper
|
||||
AC_MSG_CHECKING(whether to use device-mapper)
|
||||
@ -1260,6 +1276,7 @@ AC_SUBST(SELINUX_PC)
|
||||
AC_SUBST(SNAPSHOTS)
|
||||
AC_SUBST(STATICDIR)
|
||||
AC_SUBST(STATIC_LINK)
|
||||
AC_SUBST(TESTING)
|
||||
AC_SUBST(UDEV_LIBS)
|
||||
AC_SUBST(UDEV_PC)
|
||||
AC_SUBST(UDEV_RULES)
|
||||
|
@ -45,6 +45,7 @@ PTHREAD_LIBS = @PTHREAD_LIBS@
|
||||
READLINE_LIBS = @READLINE_LIBS@
|
||||
SELINUX_LIBS = @SELINUX_LIBS@
|
||||
UDEV_LIBS = @UDEV_LIBS@
|
||||
TESTING = @TESTING@
|
||||
|
||||
# Setup directory variables
|
||||
prefix = @prefix@
|
||||
|
30
report-generators/lib/log.rb
Normal file
30
report-generators/lib/log.rb
Normal file
@ -0,0 +1,30 @@
|
||||
# Merely wraps the logger library with a bit of standard policy.
|
||||
require 'logger'
|
||||
|
||||
module Log
|
||||
$log = Logger.new(STDERR)
|
||||
|
||||
def init(io_)
|
||||
$log = Logger.new(io_)
|
||||
end
|
||||
end
|
||||
|
||||
def fatal(*args)
|
||||
$log.fatal(*args)
|
||||
end
|
||||
|
||||
def error(*args)
|
||||
$log.error(*args)
|
||||
end
|
||||
|
||||
def info(*args)
|
||||
$log.info(*args)
|
||||
end
|
||||
|
||||
def warning(*args)
|
||||
$log.warn(*args)
|
||||
end
|
||||
|
||||
def debug(*args)
|
||||
$log.debug(*args)
|
||||
end
|
28
report-generators/lib/report_templates.rb
Normal file
28
report-generators/lib/report_templates.rb
Normal file
@ -0,0 +1,28 @@
|
||||
# Policy for the location of report templates
|
||||
require 'string-store'
|
||||
|
||||
class TemplateStringStore < StringStore
|
||||
def initialize()
|
||||
super(['report-generators/templates'])
|
||||
end
|
||||
end
|
||||
|
||||
module ReportTemplates
|
||||
def generate_report(report, bs, dest_path = nil)
|
||||
include Reports
|
||||
reports = ReportRegister.new
|
||||
template_store = TemplateStringStore.new
|
||||
report = reports.get_report(report)
|
||||
erb = ERB.new(template_store.lookup(report.template))
|
||||
body = erb.result(bs)
|
||||
title = report.short_desc
|
||||
|
||||
erb = ERB.new(template_store.lookup("boiler_plate.rhtml"))
|
||||
txt = erb.result(binding)
|
||||
|
||||
dest_path = dest_path.nil? ? report.path : dest_path
|
||||
dest_path.open("w") do |out|
|
||||
out.puts txt
|
||||
end
|
||||
end
|
||||
end
|
48
report-generators/lib/reports.rb
Normal file
48
report-generators/lib/reports.rb
Normal file
@ -0,0 +1,48 @@
|
||||
# Data about the various reports we support
|
||||
require 'log'
|
||||
require 'pathname'
|
||||
|
||||
module Reports
|
||||
Report = Struct.new(:short_desc, :desc, :path, :template)
|
||||
|
||||
class ReportRegister
|
||||
attr_reader :reports
|
||||
|
||||
private
|
||||
def add_report(sym, *args)
|
||||
@reports[sym] = Report.new(*args)
|
||||
end
|
||||
|
||||
public
|
||||
def initialize()
|
||||
@reports = Hash.new
|
||||
|
||||
add_report(:unit_test,
|
||||
"Unit Tests",
|
||||
"unit tests",
|
||||
Pathname.new("reports/unit.html"),
|
||||
Pathname.new("unit_test.rhtml"))
|
||||
|
||||
add_report(:memcheck,
|
||||
"Memory Tests",
|
||||
"unit tests with valgrind memory checking",
|
||||
Pathname.new("reports/memcheck.html"),
|
||||
Pathname.new("memcheck.rhtml"))
|
||||
|
||||
add_report(:unit_detail,
|
||||
"Unit Test Detail",
|
||||
"unit test detail",
|
||||
Pathname.new("reports/unit_detail.html"), # FIXME replace this with a lambda
|
||||
Pathname.new("unit_detail.rhtml"))
|
||||
end
|
||||
|
||||
def get_report(sym)
|
||||
raise RuntimeError, "unknown report '#{sym}'" unless @reports.member?(sym)
|
||||
@reports[sym]
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
@reports.each(&block)
|
||||
end
|
||||
end
|
||||
end
|
46
report-generators/lib/schedule_file.rb
Normal file
46
report-generators/lib/schedule_file.rb
Normal file
@ -0,0 +1,46 @@
|
||||
# Parses the simple colon delimited test schedule files.
|
||||
|
||||
ScheduledTest = Struct.new(:desc, :command_line, :status, :output)
|
||||
|
||||
class Schedule
|
||||
attr_reader :dir, :schedules
|
||||
|
||||
def initialize(dir, ss)
|
||||
@dir = dir
|
||||
@schedules = ss
|
||||
end
|
||||
|
||||
def run
|
||||
Dir::chdir(@dir.to_s) do
|
||||
@schedules.each do |s|
|
||||
reader, writer = IO.pipe
|
||||
print "#{s.desc} ... "
|
||||
pid = spawn(s.command_line, [ STDERR, STDOUT ] => writer)
|
||||
writer.close
|
||||
_, s.status = Process::waitpid2(pid)
|
||||
puts (s.status.success? ? "pass" : "fail")
|
||||
s.output = reader.read
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.read(dir, io)
|
||||
ss = Array.new
|
||||
|
||||
io.readlines.each do |line|
|
||||
case line.strip
|
||||
when /^\#.*/
|
||||
next
|
||||
|
||||
when /([^:]+):(.*)/
|
||||
ss << ScheduledTest.new($1.strip, $2.strip)
|
||||
|
||||
else
|
||||
raise RuntimeError, "badly formatted schedule line"
|
||||
end
|
||||
end
|
||||
|
||||
Schedule.new(dir, ss)
|
||||
end
|
||||
end
|
||||
|
32
report-generators/lib/string-store.rb
Normal file
32
report-generators/lib/string-store.rb
Normal file
@ -0,0 +1,32 @@
|
||||
# Provides a simple way of accessing the contents of files by a symbol
|
||||
# name. Useful for erb templates.
|
||||
|
||||
require 'pathname'
|
||||
|
||||
class StringStore
|
||||
attr_accessor :path
|
||||
|
||||
def initialize(p)
|
||||
@paths = p.nil? ? Array.new : p # FIXME: do we need to copy p ?
|
||||
end
|
||||
|
||||
def lookup(sym)
|
||||
files = expansions(sym)
|
||||
|
||||
@paths.each do |p|
|
||||
files.each do |f|
|
||||
pn = Pathname.new("#{p}/#{f}")
|
||||
if pn.file?
|
||||
return pn.read
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
raise RuntimeError, "unknown string entry: #{sym}"
|
||||
end
|
||||
|
||||
private
|
||||
def expansions(sym)
|
||||
["#{sym}", "#{sym}.txt"]
|
||||
end
|
||||
end
|
76
report-generators/memcheck.rb
Normal file
76
report-generators/memcheck.rb
Normal file
@ -0,0 +1,76 @@
|
||||
# Reads the schedule files given on the command line. Runs them and
|
||||
# generates the reports.
|
||||
|
||||
# FIXME: a lot of duplication with unit_test.rb
|
||||
|
||||
require 'schedule_file'
|
||||
require 'pathname'
|
||||
require 'reports'
|
||||
require 'erb'
|
||||
require 'report_templates'
|
||||
|
||||
include ReportTemplates
|
||||
|
||||
schedules = ARGV.map do |f|
|
||||
p = Pathname.new(f)
|
||||
Schedule.read(p.dirname, p)
|
||||
end
|
||||
|
||||
total_passed = 0
|
||||
total_failed = 0
|
||||
|
||||
# We need to make sure the lvm shared libs are in the LD_LIBRARY_PATH
|
||||
ENV['LD_LIBRARY_PATH'] = `pwd`.strip + "/libdm:" + (ENV['LD_LIBRARY_PATH'] || '')
|
||||
|
||||
ENV['TEST_TOOL'] = "valgrind --leak-check=full --show-reachable=yes"
|
||||
|
||||
schedules.each do |s|
|
||||
s.run
|
||||
|
||||
s.schedules.each do |t|
|
||||
if t.status.success?
|
||||
total_passed += 1
|
||||
else
|
||||
total_failed += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mangle(txt)
|
||||
txt.gsub(/\s+/, '_')
|
||||
end
|
||||
|
||||
MemcheckStats = Struct.new(:definitely_lost, :indirectly_lost, :possibly_lost, :reachable)
|
||||
|
||||
def format(bytes, blocks)
|
||||
"#{bytes} bytes, #{blocks} blocks"
|
||||
end
|
||||
|
||||
# Examines the output for details of leaks
|
||||
def extract_stats(t)
|
||||
d = i = p = r = '-'
|
||||
|
||||
t.output.split("\n").each do |l|
|
||||
case l
|
||||
when /==\d+== definitely lost: ([0-9,]+) bytes in ([0-9,]+) blocks/
|
||||
d = format($1, $2)
|
||||
when /==\d+== indirectly lost: ([0-9,]+) bytes in ([0-9,]+) blocks/
|
||||
i = format($1, $2)
|
||||
when /==\d+== possibly lost: ([0-9,]+) bytes in ([0-9,]+) blocks/
|
||||
p = format($1, $2)
|
||||
when /==\d+== still reachable: ([0-9,]+) bytes in ([0-9,]+) blocks/
|
||||
r = format($1, $2)
|
||||
end
|
||||
end
|
||||
|
||||
MemcheckStats.new(d, i, p, r)
|
||||
end
|
||||
|
||||
generate_report(:memcheck, binding)
|
||||
|
||||
# now we generate a detail report for each schedule
|
||||
schedules.each do |s|
|
||||
s.schedules.each do |t|
|
||||
generate_report(:unit_detail, binding, Pathname.new("reports/memcheck_#{mangle(t.desc)}.html"))
|
||||
end
|
||||
end
|
25
report-generators/templates/boiler_plate.rhtml
Normal file
25
report-generators/templates/boiler_plate.rhtml
Normal file
@ -0,0 +1,25 @@
|
||||
<html>
|
||||
<head>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
<title><%= title %></title>
|
||||
<link title="Style" type="text/css" rel="stylesheet" href="stylesheet.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="banner">
|
||||
<h2><%= title %></h2>
|
||||
</div>
|
||||
<div id="main">
|
||||
<div id="controls">
|
||||
<table>
|
||||
<tr><td><a href="index.html">Generation times</a></td></tr>
|
||||
<tr><td><a href="unit.html">Unit tests</a></td></tr>
|
||||
<tr><td><a href="memcheck.html">Memory tests</a></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="body">
|
||||
<%= body %>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
17
report-generators/templates/index.rhtml
Normal file
17
report-generators/templates/index.rhtml
Normal file
@ -0,0 +1,17 @@
|
||||
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
|
||||
<tr><th>Report</th><th>Generation time</th></tr>
|
||||
<% [:unit_test, :memcheck].each do |sym| %>
|
||||
<% r = reports.get_report(sym) %>
|
||||
<tr>
|
||||
<td>
|
||||
<% if r.path.file? %>
|
||||
<a href="<%= r.path.to_s.gsub(/^reports\//, '') %>"><%= r.short_desc %></a>
|
||||
<% else %>
|
||||
<%= r.short_desc %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td><%= safe_mtime(r) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
|
30
report-generators/templates/memcheck.rhtml
Normal file
30
report-generators/templates/memcheck.rhtml
Normal file
@ -0,0 +1,30 @@
|
||||
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
|
||||
<tr><th>Tests passed</th><th>Tests failed</th></tr>
|
||||
<tr><td class="pass"><%= total_passed %></td><td <%= total_failed == 0 ? "" : "class=\"fail\""%>><%= total_failed %></td></tr>
|
||||
</table>
|
||||
|
||||
<% schedules.each do |s| %>
|
||||
<h3><%= s.dir.sub('./unit-tests/', '') %></h3>
|
||||
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
|
||||
<tr><th>Test</th><th>Result</th><th>Definitely lost</th><th>indirectly lost</th><th>possibly lost</th><th>still reachable</th><tr>
|
||||
|
||||
<% s.schedules.each do |t| %>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="memcheck_<%= mangle(t.desc) %>.html"><%= t.desc %></a>
|
||||
</td>
|
||||
<% if t.status.success? %>
|
||||
<td class="pass">pass</td>
|
||||
<% else %>
|
||||
<td class="fail">fail</td>
|
||||
<% end %>
|
||||
|
||||
<% stats = extract_stats(t) %>
|
||||
<td><%= stats.definitely_lost %></td>
|
||||
<td><%= stats.indirectly_lost %></td>
|
||||
<td><%= stats.possibly_lost %></td>
|
||||
<td><%= stats.reachable %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
<% end %>
|
37
report-generators/templates/unit_detail.rhtml
Normal file
37
report-generators/templates/unit_detail.rhtml
Normal file
@ -0,0 +1,37 @@
|
||||
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
|
||||
<tr><th>Test</th><th>Result</th></tr>
|
||||
<tr>
|
||||
<td>
|
||||
<%= t.desc %>
|
||||
</td>
|
||||
<% if t.status.success? %>
|
||||
<td class="pass">pass</td>
|
||||
<% else %>
|
||||
<td class="fail">fail</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
|
||||
<tr><th>Command line</th></tr>
|
||||
<tr>
|
||||
<td>
|
||||
<pre>
|
||||
<%= t.command_line %>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
|
||||
<tr><th>Output</th></tr>
|
||||
<tr>
|
||||
<td>
|
||||
<pre>
|
||||
<%= t.output %>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
23
report-generators/templates/unit_test.rhtml
Normal file
23
report-generators/templates/unit_test.rhtml
Normal file
@ -0,0 +1,23 @@
|
||||
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
|
||||
<tr><th>Tests passed</th><th>Tests failed</th></tr>
|
||||
<tr><td class="pass"><%= total_passed %></td><td <%= total_failed == 0 ? "" : "class=\"fail\""%>><%= total_failed %></td></tr>
|
||||
</table>
|
||||
|
||||
<% schedules.each do |s| %>
|
||||
<h3><%= s.dir.sub('./unit-tests/', '') %></h3>
|
||||
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
|
||||
<tr><th>Test</th><th>Result</th></tr>
|
||||
<% s.schedules.each do |t| %>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="detail_<%= mangle(t.desc) %>.html"><%= t.desc %></a>
|
||||
</td>
|
||||
<% if t.status.success? %>
|
||||
<td class="pass">pass</td>
|
||||
<% else %>
|
||||
<td class="fail">fail</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
<% end %>
|
4
report-generators/test/example.schedule
Normal file
4
report-generators/test/example.schedule
Normal file
@ -0,0 +1,4 @@
|
||||
# This is a comment
|
||||
description number 1:$TEST_TOOL ls
|
||||
foo bar: $TEST_TOOL du -hs .
|
||||
this comment is prefixed with whitespace: $TEST_TOOL date
|
1
report-generators/test/strings/more_strings/test3.txt
Normal file
1
report-generators/test/strings/more_strings/test3.txt
Normal file
@ -0,0 +1 @@
|
||||
lorem
|
1
report-generators/test/strings/test1.txt
Normal file
1
report-generators/test/strings/test1.txt
Normal file
@ -0,0 +1 @@
|
||||
Hello, world!
|
3
report-generators/test/strings/test2
Normal file
3
report-generators/test/strings/test2
Normal file
@ -0,0 +1,3 @@
|
||||
one
|
||||
two
|
||||
three
|
26
report-generators/test/tc_log.rb
Normal file
26
report-generators/test/tc_log.rb
Normal file
@ -0,0 +1,26 @@
|
||||
require 'test/unit'
|
||||
require 'stringio'
|
||||
require 'log'
|
||||
|
||||
class TestLog < Test::Unit::TestCase
|
||||
include Log
|
||||
|
||||
private
|
||||
def remove_timestamps(l)
|
||||
l.gsub(/\[[^\]]*\]/, '')
|
||||
end
|
||||
|
||||
public
|
||||
def test_log
|
||||
StringIO.open do |out|
|
||||
init(out)
|
||||
|
||||
info("msg1")
|
||||
warning("msg2")
|
||||
debug("msg3")
|
||||
|
||||
assert_equal("I, INFO -- : msg1\nW, WARN -- : msg2\nD, DEBUG -- : msg3\n",
|
||||
remove_timestamps(out.string))
|
||||
end
|
||||
end
|
||||
end
|
28
report-generators/test/tc_schedule_file.rb
Normal file
28
report-generators/test/tc_schedule_file.rb
Normal file
@ -0,0 +1,28 @@
|
||||
require 'test/unit'
|
||||
require 'pathname'
|
||||
require 'schedule_file'
|
||||
|
||||
class TestScheduleFile < Test::Unit::TestCase
|
||||
def test_reading
|
||||
p = Pathname.new("report-generators/test/example.schedule")
|
||||
p.open do |f|
|
||||
s = Schedule.read(p.dirname, f)
|
||||
|
||||
assert_equal(3, s.schedules.size)
|
||||
assert_equal(s.schedules[2].desc, "this comment is prefixed with whitespace")
|
||||
assert_equal(s.schedules[0].command_line, "$TEST_TOOL ls")
|
||||
end
|
||||
end
|
||||
|
||||
def test_running
|
||||
p = Pathname.new("report-generators/test/example.schedule")
|
||||
p.open do |f|
|
||||
s = Schedule.read(p.dirname, f)
|
||||
s.run
|
||||
|
||||
s.schedules.each do |t|
|
||||
assert(t.status.success?)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
19
report-generators/test/tc_string_store.rb
Normal file
19
report-generators/test/tc_string_store.rb
Normal file
@ -0,0 +1,19 @@
|
||||
require 'string-store'
|
||||
require 'test/unit'
|
||||
|
||||
class TestStringStore < Test::Unit::TestCase
|
||||
def setup
|
||||
@ss = StringStore.new(['report-generators/test/strings',
|
||||
'report-generators/test/strings/more_strings'])
|
||||
end
|
||||
|
||||
def test_lookup
|
||||
assert_equal("Hello, world!\n", @ss.lookup(:test1))
|
||||
assert_equal("one\ntwo\nthree", @ss.lookup(:test2))
|
||||
assert_equal("lorem\n", @ss.lookup(:test3))
|
||||
|
||||
assert_raises(RuntimeError) do
|
||||
@ss.lookup(:unlikely_name)
|
||||
end
|
||||
end
|
||||
end
|
3
report-generators/test/ts.rb
Normal file
3
report-generators/test/ts.rb
Normal file
@ -0,0 +1,3 @@
|
||||
require 'tc_log'
|
||||
require 'tc_string_store'
|
||||
require 'tc_schedule_file'
|
32
report-generators/title_page.rb
Normal file
32
report-generators/title_page.rb
Normal file
@ -0,0 +1,32 @@
|
||||
# This generates the index for the reports, including generation
|
||||
# times.
|
||||
|
||||
require 'log'
|
||||
require 'string-store'
|
||||
require 'reports'
|
||||
require 'erb'
|
||||
require 'report_templates'
|
||||
|
||||
include Reports
|
||||
|
||||
reports = ReportRegister.new
|
||||
|
||||
def safe_mtime(r)
|
||||
r.path.file? ? r.path.mtime.to_s : "not generated"
|
||||
end
|
||||
|
||||
template_store = TemplateStringStore.new
|
||||
|
||||
# FIXME: use generate_report() method
|
||||
erb = ERB.new(template_store.lookup("index.rhtml"))
|
||||
body = erb.result(binding)
|
||||
title = "Generation times"
|
||||
|
||||
erb = ERB.new(template_store.lookup("boiler_plate.rhtml"))
|
||||
txt = erb.result(binding)
|
||||
|
||||
Pathname.new("reports/index.html").open("w") do |f|
|
||||
f.puts txt
|
||||
end
|
||||
|
||||
|
46
report-generators/unit_test.rb
Normal file
46
report-generators/unit_test.rb
Normal file
@ -0,0 +1,46 @@
|
||||
# Reads the schedule files given on the command line. Runs them and
|
||||
# generates the reports.
|
||||
|
||||
require 'schedule_file'
|
||||
require 'pathname'
|
||||
require 'reports'
|
||||
require 'erb'
|
||||
require 'report_templates'
|
||||
|
||||
include ReportTemplates
|
||||
|
||||
schedules = ARGV.map do |f|
|
||||
p = Pathname.new(f)
|
||||
Schedule.read(p.dirname, p)
|
||||
end
|
||||
|
||||
total_passed = 0
|
||||
total_failed = 0
|
||||
|
||||
# We need to make sure the lvm shared libs are in the LD_LIBRARY_PATH
|
||||
ENV['LD_LIBRARY_PATH'] = `pwd`.strip + "/libdm:" + (ENV['LD_LIBRARY_PATH'] || '')
|
||||
|
||||
schedules.each do |s|
|
||||
s.run
|
||||
|
||||
s.schedules.each do |t|
|
||||
if t.status.success?
|
||||
total_passed += 1
|
||||
else
|
||||
total_failed += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mangle(txt)
|
||||
txt.gsub(/\s+/, '_')
|
||||
end
|
||||
|
||||
generate_report(:unit_test, binding)
|
||||
|
||||
# now we generate a detail report for each schedule
|
||||
schedules.each do |s|
|
||||
s.schedules.each do |t|
|
||||
generate_report(:unit_detail, binding, Pathname.new("reports/detail_#{mangle(t.desc)}.html"))
|
||||
end
|
||||
end
|
264
reports/stylesheet.css
Normal file
264
reports/stylesheet.css
Normal file
@ -0,0 +1,264 @@
|
||||
/* I know nothing about css, and am not likely too either since it's
|
||||
* about bottom on my list of things to learn. So this file has been
|
||||
* pinched from the Pragmatic Programmers ruby on rails book. - ejt
|
||||
*/
|
||||
|
||||
/* Global styles */
|
||||
|
||||
/* START:notice */
|
||||
#notice {
|
||||
border: 2px solid red;
|
||||
padding: 1em;
|
||||
margin-bottom: 2em;
|
||||
background-color: #f0f0f0;
|
||||
font: bold smaller sans-serif;
|
||||
}
|
||||
/* END:notice */
|
||||
|
||||
/* Styles for admin/list */
|
||||
|
||||
#product-list .list-title {
|
||||
color: #244;
|
||||
font-weight: bold;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
#product-list .list-image {
|
||||
width: 60px;
|
||||
height: 70px;
|
||||
}
|
||||
|
||||
|
||||
#product-list .list-actions {
|
||||
font-size: x-small;
|
||||
text-align: right;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
#product-list .list-line-even {
|
||||
background: #e0f8f8;
|
||||
}
|
||||
|
||||
#product-list .list-line-odd {
|
||||
background: #f8b0f8;
|
||||
}
|
||||
|
||||
|
||||
/* Styles for main page */
|
||||
|
||||
#banner {
|
||||
background: #9c9;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 2px solid;
|
||||
font: small-caps 20px/20px "Times New Roman", serif;
|
||||
color: #282;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#banner img {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#main {
|
||||
margin-left: 0em;
|
||||
padding-top: 4ex;
|
||||
padding-left: 2em;
|
||||
background: white;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font: 150% sans-serif;
|
||||
color: #226;
|
||||
border-bottom: 3px dotted #77d;
|
||||
}
|
||||
|
||||
/* An entry in the store catalog */
|
||||
|
||||
#store .entry {
|
||||
border-bottom: 1px dotted #77d;
|
||||
}
|
||||
|
||||
#store .title {
|
||||
font-size: 120%;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
#store .entry img {
|
||||
width: 75px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
||||
#store .entry h3 {
|
||||
margin-bottom: 2px;
|
||||
color: #227;
|
||||
}
|
||||
|
||||
#store .entry p {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
|
||||
#store .entry .price-line {
|
||||
}
|
||||
|
||||
#store .entry .add-to-cart {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#store .entry .price {
|
||||
color: #44a;
|
||||
font-weight: bold;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
/* START:inline */
|
||||
#store .entry form, #store .entry form div {
|
||||
display: inline;
|
||||
}
|
||||
/* END:inline */
|
||||
|
||||
/* START:cart */
|
||||
/* Styles for the cart in the main page and the sidebar */
|
||||
|
||||
.cart-title {
|
||||
font: 120% bold;
|
||||
}
|
||||
|
||||
.item-price, .total-line {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.total-line .total-cell {
|
||||
font-weight: bold;
|
||||
border-top: 1px solid #595;
|
||||
}
|
||||
|
||||
|
||||
/* Styles for the cart in the sidebar */
|
||||
|
||||
#cart, #cart table {
|
||||
font-size: smaller;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#cart table {
|
||||
border-top: 1px dotted #595;
|
||||
border-bottom: 1px dotted #595;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
/* END:cart */
|
||||
|
||||
/* Styles for order form */
|
||||
|
||||
.depot-form fieldset {
|
||||
background: #efe;
|
||||
}
|
||||
|
||||
.depot-form legend {
|
||||
color: #dfd;
|
||||
background: #141;
|
||||
font-family: sans-serif;
|
||||
padding: 0.2em 1em;
|
||||
}
|
||||
|
||||
.depot-form label {
|
||||
width: 5em;
|
||||
float: left;
|
||||
text-align: right;
|
||||
margin-right: 0.5em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.depot-form .submit {
|
||||
margin-left: 5.5em;
|
||||
}
|
||||
|
||||
/* The error box */
|
||||
|
||||
.fieldWithErrors {
|
||||
padding: 2px;
|
||||
background-color: red;
|
||||
display: table;
|
||||
}
|
||||
|
||||
#errorExplanation {
|
||||
width: 400px;
|
||||
border: 2px solid red;
|
||||
padding: 7px;
|
||||
padding-bottom: 12px;
|
||||
margin-bottom: 20px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
#errorExplanation h2 {
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
padding: 5px 5px 5px 15px;
|
||||
font-size: 12px;
|
||||
margin: -7px;
|
||||
background-color: #c00;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#errorExplanation p {
|
||||
color: #333;
|
||||
margin-bottom: 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#errorExplanation ul li {
|
||||
font-size: 12px;
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
body {
|
||||
font: normal 75% verdana,arial,helvetica;
|
||||
color:#000000;
|
||||
}
|
||||
|
||||
table tr td, table tr th {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
table.stripes tr th {
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
background: #a0a0a0;
|
||||
}
|
||||
|
||||
table.stripes tr td {
|
||||
background: #ccccc0;
|
||||
}
|
||||
|
||||
td.pass {
|
||||
color: green;
|
||||
}
|
||||
|
||||
td.fail {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#main {
|
||||
padding-left: 0em;
|
||||
}
|
||||
|
||||
#controls {
|
||||
float: left;
|
||||
padding-top: 1em;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
padding-bottom: 1em;
|
||||
width: 14em;
|
||||
border-right: 2px solid;
|
||||
}
|
||||
|
||||
#body {
|
||||
margin-left: 16em;
|
||||
padding-top: 4ex;
|
||||
padding-left: 2em;
|
||||
background: white;
|
||||
border-left: 2px solid;
|
||||
}
|
Loading…
Reference in New Issue
Block a user