jperkins-deep_test 1.2.2
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.
- data/CHANGELOG +47 -0
- data/README.rdoc +228 -0
- data/Rakefile +247 -0
- data/bin/deep_test +15 -0
- data/lib/deep_test.rb +91 -0
- data/lib/deep_test/database/mysql_setup_listener.rb +112 -0
- data/lib/deep_test/database/postgresql_setup_listener.rb +116 -0
- data/lib/deep_test/database/setup_listener.rb +125 -0
- data/lib/deep_test/deadlock_detector.rb +7 -0
- data/lib/deep_test/distributed/dispatch_controller.rb +53 -0
- data/lib/deep_test/distributed/drb_client_connection_info.rb +15 -0
- data/lib/deep_test/distributed/filename_resolver.rb +40 -0
- data/lib/deep_test/distributed/master_test_server.rb +52 -0
- data/lib/deep_test/distributed/multi_test_server_proxy.rb +44 -0
- data/lib/deep_test/distributed/null_work_unit.rb +12 -0
- data/lib/deep_test/distributed/remote_worker_client.rb +54 -0
- data/lib/deep_test/distributed/remote_worker_server.rb +82 -0
- data/lib/deep_test/distributed/rsync.rb +37 -0
- data/lib/deep_test/distributed/show_status.rhtml +41 -0
- data/lib/deep_test/distributed/test_server.rb +78 -0
- data/lib/deep_test/distributed/test_server_status.rb +9 -0
- data/lib/deep_test/distributed/test_server_workers.rb +24 -0
- data/lib/deep_test/distributed/throughput_runner.rb +42 -0
- data/lib/deep_test/distributed/throughput_statistics.rb +26 -0
- data/lib/deep_test/distributed/throughput_worker_client.rb +19 -0
- data/lib/deep_test/extensions/drb_extension.rb +34 -0
- data/lib/deep_test/extensions/object_extension.rb +40 -0
- data/lib/deep_test/listener_list.rb +17 -0
- data/lib/deep_test/local_workers.rb +55 -0
- data/lib/deep_test/logger.rb +17 -0
- data/lib/deep_test/marshallable_exception_wrapper.rb +44 -0
- data/lib/deep_test/metrics/gatherer.rb +67 -0
- data/lib/deep_test/metrics/queue_lock_wait_time_measurement.rb +133 -0
- data/lib/deep_test/null_worker_listener.rb +62 -0
- data/lib/deep_test/option.rb +60 -0
- data/lib/deep_test/options.rb +110 -0
- data/lib/deep_test/process_orchestrator.rb +49 -0
- data/lib/deep_test/rake_tasks.rb +11 -0
- data/lib/deep_test/result_reader.rb +36 -0
- data/lib/deep_test/rspec_detector.rb +21 -0
- data/lib/deep_test/server.rb +75 -0
- data/lib/deep_test/spec.rb +13 -0
- data/lib/deep_test/spec/extensions/example_group_methods.rb +64 -0
- data/lib/deep_test/spec/extensions/example_methods.rb +46 -0
- data/lib/deep_test/spec/extensions/options.rb +43 -0
- data/lib/deep_test/spec/extensions/reporter.rb +29 -0
- data/lib/deep_test/spec/extensions/spec_task.rb +20 -0
- data/lib/deep_test/spec/runner.rb +57 -0
- data/lib/deep_test/spec/work_result.rb +33 -0
- data/lib/deep_test/spec/work_unit.rb +59 -0
- data/lib/deep_test/test.rb +10 -0
- data/lib/deep_test/test/extensions/error.rb +14 -0
- data/lib/deep_test/test/runner.rb +24 -0
- data/lib/deep_test/test/supervised_test_suite.rb +49 -0
- data/lib/deep_test/test/work_result.rb +34 -0
- data/lib/deep_test/test/work_unit.rb +40 -0
- data/lib/deep_test/test_task.rb +47 -0
- data/lib/deep_test/ui/console.rb +76 -0
- data/lib/deep_test/ui/null.rb +17 -0
- data/lib/deep_test/warlock.rb +134 -0
- data/lib/deep_test/worker.rb +57 -0
- data/script/internal/run_test_suite.rb +7 -0
- data/script/public/master_test_server.rb +24 -0
- data/script/public/test_server.rb +18 -0
- data/script/public/test_throughput.rb +29 -0
- data/spec/deep_test/option_spec.rb +33 -0
- data/spec/deep_test/options_spec.rb +183 -0
- data/spec/deep_test/spec/extensions/example_group_methods_spec.rb +48 -0
- data/spec/deep_test/spec/extensions/example_methods_spec.rb +61 -0
- data/spec/deep_test/spec/extensions/options_spec.rb +23 -0
- data/spec/deep_test/spec/extensions/reporter_spec.rb +28 -0
- data/spec/deep_test/spec/extensions/spec_task_spec.rb +36 -0
- data/spec/deep_test/spec/runner_spec.rb +106 -0
- data/spec/deep_test/spec/work_result_spec.rb +14 -0
- data/spec/deep_test/spec/work_unit_spec.rb +78 -0
- data/spec/spec_helper.rb +59 -0
- data/spec/thread_worker.rb +25 -0
- data/test/deep_test/database/mysql_setup_listener_test.rb +14 -0
- data/test/deep_test/distributed/dispatch_controller_test.rb +209 -0
- data/test/deep_test/distributed/drb_client_connection_info_test.rb +42 -0
- data/test/deep_test/distributed/filename_resolver_test.rb +52 -0
- data/test/deep_test/distributed/master_test_server_test.rb +32 -0
- data/test/deep_test/distributed/multi_test_server_proxy_test.rb +96 -0
- data/test/deep_test/distributed/remote_worker_client_test.rb +180 -0
- data/test/deep_test/distributed/remote_worker_server_test.rb +99 -0
- data/test/deep_test/distributed/rsync_test.rb +67 -0
- data/test/deep_test/distributed/test_server_test.rb +94 -0
- data/test/deep_test/distributed/test_server_workers_test.rb +26 -0
- data/test/deep_test/distributed/throughput_runner_test.rb +68 -0
- data/test/deep_test/distributed/throughput_worker_client_test.rb +28 -0
- data/test/deep_test/extensions/object_extension_test.rb +37 -0
- data/test/deep_test/listener_list_test.rb +20 -0
- data/test/deep_test/local_workers_test.rb +22 -0
- data/test/deep_test/logger_test.rb +11 -0
- data/test/deep_test/marshallable_exception_wrapper_test.rb +44 -0
- data/test/deep_test/metrics/gatherer_test.rb +66 -0
- data/test/deep_test/process_orchestrator_test.rb +11 -0
- data/test/deep_test/result_reader_test.rb +128 -0
- data/test/deep_test/server_test.rb +58 -0
- data/test/deep_test/test/extensions/error_test.rb +40 -0
- data/test/deep_test/test/runner_test.rb +7 -0
- data/test/deep_test/test/supervised_test_suite_test.rb +79 -0
- data/test/deep_test/test/work_result_test.rb +81 -0
- data/test/deep_test/test/work_unit_test.rb +61 -0
- data/test/deep_test/test_task_test.rb +43 -0
- data/test/deep_test/ui/console_test.rb +9 -0
- data/test/deep_test/warlock_test.rb +38 -0
- data/test/deep_test/worker_test.rb +94 -0
- data/test/failing.rake +11 -0
- data/test/failing.rb +7 -0
- data/test/fake_deadlock_error.rb +12 -0
- data/test/simple_test_blackboard.rb +45 -0
- data/test/simple_test_blackboard_test.rb +33 -0
- data/test/test_factory.rb +74 -0
- data/test/test_helper.rb +15 -0
- data/test/test_task_test.rb +72 -0
- metadata +214 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
module Distributed
|
|
3
|
+
class TestServer
|
|
4
|
+
DEFAULT_CONFIG = {
|
|
5
|
+
:work_dir => "/tmp",
|
|
6
|
+
:uri => "drubyall://:4022",
|
|
7
|
+
:number_of_workers => 2
|
|
8
|
+
} unless defined?(DEFAULT_CONFIG)
|
|
9
|
+
|
|
10
|
+
def initialize(config)
|
|
11
|
+
@config = config
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def spawn_worker_server(options)
|
|
15
|
+
DeepTest.logger.debug("mirror spawn_worker_server for #{options.origin_hostname}")
|
|
16
|
+
RemoteWorkerServer.start(URI.parse(@config[:uri]).host,
|
|
17
|
+
options.mirror_path(@config[:work_dir]),
|
|
18
|
+
TestServerWorkers.new(options, @config, DRbClientConnectionInfo.new))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def status
|
|
22
|
+
TestServerStatus.new(
|
|
23
|
+
DRb.uri,
|
|
24
|
+
@config[:number_of_workers],
|
|
25
|
+
RemoteWorkerServer.running_server_count
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def sync(options)
|
|
30
|
+
DeepTest.logger.debug "mirror sync for #{options.origin_hostname}"
|
|
31
|
+
path = options.mirror_path(@config[:work_dir])
|
|
32
|
+
DeepTest.logger.debug "Syncing #{options.sync_options[:source]} to #{path}"
|
|
33
|
+
RSync.sync(DRbClientConnectionInfo.new, options, path)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def servers
|
|
37
|
+
[DRbObject.new_with_uri(DRb.uri)]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.start(config)
|
|
41
|
+
server = DeepTest::Distributed::TestServer.new(config)
|
|
42
|
+
DRb.start_service(config[:uri], server)
|
|
43
|
+
DeepTest.logger.info "TestServer listening at #{DRb.uri}"
|
|
44
|
+
DRb.thread.join
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.parse_args(args)
|
|
48
|
+
options = DeepTest::Distributed::TestServer::DEFAULT_CONFIG.dup
|
|
49
|
+
OptionParser.new do |opts|
|
|
50
|
+
opts.banner = "Usage: deep_test test_server [options]"
|
|
51
|
+
|
|
52
|
+
opts.on("--work_dir PATH", "Absolute path to keep mirror working copies at") do |v|
|
|
53
|
+
options[:work_dir] = v
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
opts.on("--uri URI", "DRb URI to bind server to") do |v|
|
|
57
|
+
options[:uri] = v
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
opts.on("--number_of_workers NUM", "Number of workers to start when running tests") do |v|
|
|
61
|
+
options[:number_of_workers] = v.to_i
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
|
65
|
+
puts opts
|
|
66
|
+
exit
|
|
67
|
+
end
|
|
68
|
+
end.parse(args)
|
|
69
|
+
options
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.connect(options)
|
|
73
|
+
servers = DRbObject.new_with_uri(options.distributed_server).servers
|
|
74
|
+
MultiTestServerProxy.new(options, servers)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
module Distributed
|
|
3
|
+
class TestServerWorkers < LocalWorkers
|
|
4
|
+
def initialize(options, test_server_config, connection_info)
|
|
5
|
+
super(options)
|
|
6
|
+
@test_server_config = test_server_config
|
|
7
|
+
@connection_info = connection_info
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def number_of_workers
|
|
11
|
+
@test_server_config[:number_of_workers]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def server
|
|
15
|
+
Server.remote_reference(@connection_info.address, @options.server_port)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def start_all
|
|
19
|
+
super
|
|
20
|
+
@warlock.exit_when_none_running
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
module Distributed
|
|
3
|
+
class ThroughputRunner
|
|
4
|
+
def initialize(options, test_count, blackboard = nil, &block)
|
|
5
|
+
@options = options
|
|
6
|
+
@test_count = test_count
|
|
7
|
+
@blackboard = blackboard
|
|
8
|
+
@progress_block = block
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def blackboard
|
|
12
|
+
@blackboard ||= @options.server
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def statistics
|
|
16
|
+
ThroughputStatistics.new(@test_count, @start_time, @end_time)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def process_work_units
|
|
20
|
+
@start_time = Time.now
|
|
21
|
+
|
|
22
|
+
@test_count.times do
|
|
23
|
+
blackboard.write_work NullWorkUnit.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
results_read = 0
|
|
27
|
+
until results_read == @test_count
|
|
28
|
+
Thread.pass
|
|
29
|
+
result = blackboard.take_result
|
|
30
|
+
if result
|
|
31
|
+
results_read += 1
|
|
32
|
+
@progress_block.call(result) if @progress_block
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
@end_time = Time.now
|
|
37
|
+
|
|
38
|
+
true
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
module Distributed
|
|
3
|
+
class ThroughputStatistics
|
|
4
|
+
attr_reader :test_count, :start_time, :end_time
|
|
5
|
+
|
|
6
|
+
def initialize(test_count, start_time, end_time)
|
|
7
|
+
@test_count, @start_time, @end_time = test_count, start_time, end_time
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def timespan_in_seconds
|
|
11
|
+
@end_time.to_f - @start_time.to_f
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def tests_per_second
|
|
15
|
+
@test_count / timespan_in_seconds
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def summary
|
|
19
|
+
<<-end_summary
|
|
20
|
+
#{test_count} tests run in #{timespan_in_seconds} seconds
|
|
21
|
+
(#{tests_per_second} tests / second)
|
|
22
|
+
end_summary
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
module Distributed
|
|
3
|
+
class ThroughputWorkerClient
|
|
4
|
+
def initialize(options, test_server)
|
|
5
|
+
@options = options
|
|
6
|
+
@test_server = test_server
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def start_all
|
|
10
|
+
@worker_server = @test_server.spawn_worker_server(@options)
|
|
11
|
+
@worker_server.start_all
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def stop_all
|
|
15
|
+
@worker_server.stop_all
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
class DRbBindAllTCPSocket < DRb::DRbTCPSocket
|
|
3
|
+
def self.parse_uri(uri)
|
|
4
|
+
if uri =~ /^drubyall:\/\/(.*?):(\d+)(\?(.*))?$/
|
|
5
|
+
host = $1
|
|
6
|
+
port = $2.to_i
|
|
7
|
+
option = $4
|
|
8
|
+
[host, port, option]
|
|
9
|
+
else
|
|
10
|
+
raise(DRb::DRbBadScheme, uri) unless uri =~ /^drubyall:/
|
|
11
|
+
raise(DRb::DRbBadURI, 'can\'t parse uri:' + uri)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Open a server listening for connections at +uri+ using
|
|
16
|
+
# configuration +config+.
|
|
17
|
+
def self.open_server(uri, config)
|
|
18
|
+
uri = 'drubyall://:0' unless uri
|
|
19
|
+
host, port, opt = parse_uri(uri)
|
|
20
|
+
|
|
21
|
+
if host.size == 0
|
|
22
|
+
host = getservername
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
DeepTest.logger.debug("Listening on port #{port}, all addresses.")
|
|
26
|
+
soc = TCPServer.open('0.0.0.0', port)
|
|
27
|
+
port = soc.addr[1] if port == 0
|
|
28
|
+
uri = "druby://#{host}:#{port}"
|
|
29
|
+
self.new(uri, soc, config)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
DRb::DRbProtocol.add_protocol DeepTest::DRbBindAllTCPSocket
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require "stringio"
|
|
2
|
+
module DeepTest
|
|
3
|
+
module ObjectExtension
|
|
4
|
+
def capture_stdout
|
|
5
|
+
old_stdout, $stdout = $stdout, StringIO.new
|
|
6
|
+
yield
|
|
7
|
+
$stdout.string
|
|
8
|
+
ensure
|
|
9
|
+
$stdout = old_stdout if old_stdout
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def capture_stderr
|
|
13
|
+
old_stderr, $stderr = $stderr, StringIO.new
|
|
14
|
+
yield
|
|
15
|
+
$stderr.string
|
|
16
|
+
ensure
|
|
17
|
+
$stderr = old_stderr if old_stderr
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def retrying(description = nil, times = 5)
|
|
21
|
+
i = 0
|
|
22
|
+
loop do
|
|
23
|
+
begin
|
|
24
|
+
return yield
|
|
25
|
+
rescue => e
|
|
26
|
+
i += 1
|
|
27
|
+
print "#{description} received exception #{e}. "
|
|
28
|
+
if i < times
|
|
29
|
+
puts "Retrying..."
|
|
30
|
+
sleep 0.5
|
|
31
|
+
else
|
|
32
|
+
puts "Aborting."
|
|
33
|
+
raise e
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
Object.send :include, DeepTest::ObjectExtension
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
class ListenerList
|
|
3
|
+
attr_reader :listeners
|
|
4
|
+
|
|
5
|
+
def initialize(listeners)
|
|
6
|
+
@listeners = listeners
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
NullWorkerListener.instance_methods(false).each do |event|
|
|
10
|
+
eval <<-end_src
|
|
11
|
+
def #{event}(*args)
|
|
12
|
+
@listeners.each {|l| l.#{event}(*args)}
|
|
13
|
+
end
|
|
14
|
+
end_src
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
class LocalWorkers
|
|
3
|
+
def initialize(options)
|
|
4
|
+
@options = options
|
|
5
|
+
@warlock = Warlock.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def load_files(files)
|
|
9
|
+
files.each {|f| load f}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def server
|
|
13
|
+
@options.server
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def start_all
|
|
17
|
+
each_worker do |worker_num|
|
|
18
|
+
start_worker(worker_num) do
|
|
19
|
+
reseed_random_numbers
|
|
20
|
+
reconnect_to_database
|
|
21
|
+
worker = DeepTest::Worker.new(worker_num,
|
|
22
|
+
server,
|
|
23
|
+
@options.new_listener_list)
|
|
24
|
+
worker.run
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def stop_all
|
|
30
|
+
@warlock.stop_all
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def number_of_workers
|
|
34
|
+
@options.number_of_workers
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def reconnect_to_database
|
|
40
|
+
ActiveRecord::Base.connection.reconnect! if defined?(ActiveRecord::Base)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def start_worker(worker_num, &blk)
|
|
44
|
+
@warlock.start("worker #{worker_num}", &blk)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def reseed_random_numbers
|
|
48
|
+
srand
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def each_worker
|
|
52
|
+
number_of_workers.to_i.times { |worker_num| yield worker_num }
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
class Logger < ::Logger
|
|
3
|
+
def initialize(*args)
|
|
4
|
+
super
|
|
5
|
+
self.formatter = proc { |severity, time, progname, msg| "[DeepTest] #{msg}\n" }
|
|
6
|
+
self.level = configured_log_level
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def configured_log_level
|
|
10
|
+
if ENV['DEEP_TEST_LOG_LEVEL']
|
|
11
|
+
Logger.const_get(ENV['DEEP_TEST_LOG_LEVEL'])
|
|
12
|
+
else
|
|
13
|
+
Logger::INFO
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
class MarshallableExceptionWrapper
|
|
3
|
+
attr_reader :classname, :message, :backtrace
|
|
4
|
+
|
|
5
|
+
def initialize(exception)
|
|
6
|
+
@classname = exception.class.name
|
|
7
|
+
@message = exception.message
|
|
8
|
+
@backtrace = exception.backtrace
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def ==(other)
|
|
12
|
+
classname == other.classname &&
|
|
13
|
+
message == other.message &&
|
|
14
|
+
backtrace == other.backtrace
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def resolve
|
|
18
|
+
begin
|
|
19
|
+
klass = eval("::" + classname)
|
|
20
|
+
resolved_message = message
|
|
21
|
+
rescue => e
|
|
22
|
+
DeepTest.logger.debug("Unable to load exception class: #{classname}: #{e.message}")
|
|
23
|
+
DeepTest.logger.debug(e.backtrace.join("\n"))
|
|
24
|
+
|
|
25
|
+
klass = UnloadableException
|
|
26
|
+
resolved_message = "#{classname}: #{message}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
begin
|
|
30
|
+
resolved_exception = klass.new resolved_message
|
|
31
|
+
rescue => e
|
|
32
|
+
DeepTest.logger.debug("Unable to instantiation exception class: #{classname}: #{e.message}")
|
|
33
|
+
DeepTest.logger.debug(e.backtrace.join("\n"))
|
|
34
|
+
|
|
35
|
+
resolved_exception = UnloadableException.new resolved_message
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
resolved_exception.set_backtrace backtrace
|
|
39
|
+
resolved_exception
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class UnloadableException < StandardError; end
|
|
44
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
module Metrics
|
|
3
|
+
class Gatherer
|
|
4
|
+
def self.setup(options)
|
|
5
|
+
$metrics_gatherer = new(options)
|
|
6
|
+
|
|
7
|
+
at_exit do
|
|
8
|
+
$metrics_gatherer.write_file
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.enabled?
|
|
13
|
+
return false unless $metrics_gatherer
|
|
14
|
+
$metrics_gatherer.enabled?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.section(title, &block)
|
|
18
|
+
$metrics_gatherer.section(title, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def initialize(options)
|
|
22
|
+
@options = options
|
|
23
|
+
@sections = []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def enabled?
|
|
27
|
+
!@options.metrics_file.nil?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def section(title, &block)
|
|
31
|
+
@sections << Section.new(title, &block) if enabled?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def render
|
|
35
|
+
@sections.map {|s| s.render}.join("\n")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def write_file
|
|
39
|
+
return unless enabled?
|
|
40
|
+
File.open(@options.metrics_file, "w") do |io|
|
|
41
|
+
io << render
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Section
|
|
46
|
+
def initialize(title, &generate_measurements_block)
|
|
47
|
+
@title = title
|
|
48
|
+
@generate_measurements_block = generate_measurements_block
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def measurement(name, value)
|
|
52
|
+
@measurements << [name, value]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def gather_measurements
|
|
56
|
+
@measurements = []
|
|
57
|
+
@generate_measurements_block.call(self)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def render
|
|
61
|
+
gather_measurements
|
|
62
|
+
"[#{@title}]\n" + @measurements.map {|name, value| "#{name}: #{value}"}.join("\n")
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|