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.
Files changed (117) hide show
  1. data/CHANGELOG +47 -0
  2. data/README.rdoc +228 -0
  3. data/Rakefile +247 -0
  4. data/bin/deep_test +15 -0
  5. data/lib/deep_test.rb +91 -0
  6. data/lib/deep_test/database/mysql_setup_listener.rb +112 -0
  7. data/lib/deep_test/database/postgresql_setup_listener.rb +116 -0
  8. data/lib/deep_test/database/setup_listener.rb +125 -0
  9. data/lib/deep_test/deadlock_detector.rb +7 -0
  10. data/lib/deep_test/distributed/dispatch_controller.rb +53 -0
  11. data/lib/deep_test/distributed/drb_client_connection_info.rb +15 -0
  12. data/lib/deep_test/distributed/filename_resolver.rb +40 -0
  13. data/lib/deep_test/distributed/master_test_server.rb +52 -0
  14. data/lib/deep_test/distributed/multi_test_server_proxy.rb +44 -0
  15. data/lib/deep_test/distributed/null_work_unit.rb +12 -0
  16. data/lib/deep_test/distributed/remote_worker_client.rb +54 -0
  17. data/lib/deep_test/distributed/remote_worker_server.rb +82 -0
  18. data/lib/deep_test/distributed/rsync.rb +37 -0
  19. data/lib/deep_test/distributed/show_status.rhtml +41 -0
  20. data/lib/deep_test/distributed/test_server.rb +78 -0
  21. data/lib/deep_test/distributed/test_server_status.rb +9 -0
  22. data/lib/deep_test/distributed/test_server_workers.rb +24 -0
  23. data/lib/deep_test/distributed/throughput_runner.rb +42 -0
  24. data/lib/deep_test/distributed/throughput_statistics.rb +26 -0
  25. data/lib/deep_test/distributed/throughput_worker_client.rb +19 -0
  26. data/lib/deep_test/extensions/drb_extension.rb +34 -0
  27. data/lib/deep_test/extensions/object_extension.rb +40 -0
  28. data/lib/deep_test/listener_list.rb +17 -0
  29. data/lib/deep_test/local_workers.rb +55 -0
  30. data/lib/deep_test/logger.rb +17 -0
  31. data/lib/deep_test/marshallable_exception_wrapper.rb +44 -0
  32. data/lib/deep_test/metrics/gatherer.rb +67 -0
  33. data/lib/deep_test/metrics/queue_lock_wait_time_measurement.rb +133 -0
  34. data/lib/deep_test/null_worker_listener.rb +62 -0
  35. data/lib/deep_test/option.rb +60 -0
  36. data/lib/deep_test/options.rb +110 -0
  37. data/lib/deep_test/process_orchestrator.rb +49 -0
  38. data/lib/deep_test/rake_tasks.rb +11 -0
  39. data/lib/deep_test/result_reader.rb +36 -0
  40. data/lib/deep_test/rspec_detector.rb +21 -0
  41. data/lib/deep_test/server.rb +75 -0
  42. data/lib/deep_test/spec.rb +13 -0
  43. data/lib/deep_test/spec/extensions/example_group_methods.rb +64 -0
  44. data/lib/deep_test/spec/extensions/example_methods.rb +46 -0
  45. data/lib/deep_test/spec/extensions/options.rb +43 -0
  46. data/lib/deep_test/spec/extensions/reporter.rb +29 -0
  47. data/lib/deep_test/spec/extensions/spec_task.rb +20 -0
  48. data/lib/deep_test/spec/runner.rb +57 -0
  49. data/lib/deep_test/spec/work_result.rb +33 -0
  50. data/lib/deep_test/spec/work_unit.rb +59 -0
  51. data/lib/deep_test/test.rb +10 -0
  52. data/lib/deep_test/test/extensions/error.rb +14 -0
  53. data/lib/deep_test/test/runner.rb +24 -0
  54. data/lib/deep_test/test/supervised_test_suite.rb +49 -0
  55. data/lib/deep_test/test/work_result.rb +34 -0
  56. data/lib/deep_test/test/work_unit.rb +40 -0
  57. data/lib/deep_test/test_task.rb +47 -0
  58. data/lib/deep_test/ui/console.rb +76 -0
  59. data/lib/deep_test/ui/null.rb +17 -0
  60. data/lib/deep_test/warlock.rb +134 -0
  61. data/lib/deep_test/worker.rb +57 -0
  62. data/script/internal/run_test_suite.rb +7 -0
  63. data/script/public/master_test_server.rb +24 -0
  64. data/script/public/test_server.rb +18 -0
  65. data/script/public/test_throughput.rb +29 -0
  66. data/spec/deep_test/option_spec.rb +33 -0
  67. data/spec/deep_test/options_spec.rb +183 -0
  68. data/spec/deep_test/spec/extensions/example_group_methods_spec.rb +48 -0
  69. data/spec/deep_test/spec/extensions/example_methods_spec.rb +61 -0
  70. data/spec/deep_test/spec/extensions/options_spec.rb +23 -0
  71. data/spec/deep_test/spec/extensions/reporter_spec.rb +28 -0
  72. data/spec/deep_test/spec/extensions/spec_task_spec.rb +36 -0
  73. data/spec/deep_test/spec/runner_spec.rb +106 -0
  74. data/spec/deep_test/spec/work_result_spec.rb +14 -0
  75. data/spec/deep_test/spec/work_unit_spec.rb +78 -0
  76. data/spec/spec_helper.rb +59 -0
  77. data/spec/thread_worker.rb +25 -0
  78. data/test/deep_test/database/mysql_setup_listener_test.rb +14 -0
  79. data/test/deep_test/distributed/dispatch_controller_test.rb +209 -0
  80. data/test/deep_test/distributed/drb_client_connection_info_test.rb +42 -0
  81. data/test/deep_test/distributed/filename_resolver_test.rb +52 -0
  82. data/test/deep_test/distributed/master_test_server_test.rb +32 -0
  83. data/test/deep_test/distributed/multi_test_server_proxy_test.rb +96 -0
  84. data/test/deep_test/distributed/remote_worker_client_test.rb +180 -0
  85. data/test/deep_test/distributed/remote_worker_server_test.rb +99 -0
  86. data/test/deep_test/distributed/rsync_test.rb +67 -0
  87. data/test/deep_test/distributed/test_server_test.rb +94 -0
  88. data/test/deep_test/distributed/test_server_workers_test.rb +26 -0
  89. data/test/deep_test/distributed/throughput_runner_test.rb +68 -0
  90. data/test/deep_test/distributed/throughput_worker_client_test.rb +28 -0
  91. data/test/deep_test/extensions/object_extension_test.rb +37 -0
  92. data/test/deep_test/listener_list_test.rb +20 -0
  93. data/test/deep_test/local_workers_test.rb +22 -0
  94. data/test/deep_test/logger_test.rb +11 -0
  95. data/test/deep_test/marshallable_exception_wrapper_test.rb +44 -0
  96. data/test/deep_test/metrics/gatherer_test.rb +66 -0
  97. data/test/deep_test/process_orchestrator_test.rb +11 -0
  98. data/test/deep_test/result_reader_test.rb +128 -0
  99. data/test/deep_test/server_test.rb +58 -0
  100. data/test/deep_test/test/extensions/error_test.rb +40 -0
  101. data/test/deep_test/test/runner_test.rb +7 -0
  102. data/test/deep_test/test/supervised_test_suite_test.rb +79 -0
  103. data/test/deep_test/test/work_result_test.rb +81 -0
  104. data/test/deep_test/test/work_unit_test.rb +61 -0
  105. data/test/deep_test/test_task_test.rb +43 -0
  106. data/test/deep_test/ui/console_test.rb +9 -0
  107. data/test/deep_test/warlock_test.rb +38 -0
  108. data/test/deep_test/worker_test.rb +94 -0
  109. data/test/failing.rake +11 -0
  110. data/test/failing.rb +7 -0
  111. data/test/fake_deadlock_error.rb +12 -0
  112. data/test/simple_test_blackboard.rb +45 -0
  113. data/test/simple_test_blackboard_test.rb +33 -0
  114. data/test/test_factory.rb +74 -0
  115. data/test/test_helper.rb +15 -0
  116. data/test/test_task_test.rb +72 -0
  117. metadata +214 -0
@@ -0,0 +1,57 @@
1
+ module DeepTest
2
+ class Worker
3
+ attr_reader :number
4
+
5
+ def initialize(number, blackboard, worker_listener)
6
+ @number = number
7
+ @blackboard = blackboard
8
+ @listener = worker_listener
9
+ end
10
+
11
+ def run
12
+ @listener.starting(self)
13
+ while work_unit = next_work_unit
14
+ @listener.starting_work(self, work_unit)
15
+
16
+ result = begin
17
+ work_unit.run
18
+ rescue Exception => error
19
+ Error.new(work_unit, error)
20
+ end
21
+
22
+ @listener.finished_work(self, work_unit, result)
23
+ @blackboard.write_result result
24
+ if ENV['DEEP_TEST_SHOW_WORKER_DOTS'] == 'yes'
25
+ $stdout.print '.'
26
+ $stdout.flush
27
+ end
28
+ end
29
+ rescue Server::NoWorkUnitsRemainingError
30
+ DeepTest.logger.debug("Worker #{number}: no more work to do")
31
+ end
32
+
33
+ def next_work_unit
34
+ @blackboard.take_work
35
+ rescue Server::NoWorkUnitsAvailableError
36
+ sleep 0.02
37
+ retry
38
+ end
39
+
40
+ class Error
41
+ attr_accessor :work_unit, :error
42
+
43
+ def initialize(work_unit, error)
44
+ @work_unit, @error = work_unit, error
45
+ end
46
+
47
+ def ==(other)
48
+ work_unit == other.work_unit &&
49
+ error == other.error
50
+ end
51
+
52
+ def to_s
53
+ "#{@work_unit}: #{@error}\n" + (@error.backtrace || []).join("\n")
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + "/../../lib/deep_test"
2
+ options = DeepTest::Options.from_command_line(ARGV[0])
3
+ DeepTest.init(options)
4
+ runner = DeepTest::Test::Runner.new(options)
5
+ workers = options.new_workers
6
+ workers.load_files Dir.glob(options.pattern)
7
+ DeepTest::ProcessOrchestrator.run(options, workers, runner)
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + "/../../lib/deep_test"
2
+ require 'drb/drb'
3
+ require 'optparse'
4
+
5
+ uri = "drubyall://:4021"
6
+ slave_uris = OptionParser.new do |opts|
7
+ opts.banner = "Usage: deep_test master_test_server [options] <test_server_uris>"
8
+
9
+ opts.on("--uri URI", "DRb URI to bind server to") do |v|
10
+ uri = v
11
+ end
12
+
13
+ opts.on_tail("-h", "--help", "Show this message") do
14
+ puts opts
15
+ exit
16
+ end
17
+ end.parse(ARGV)
18
+
19
+ begin
20
+ DeepTest::Distributed::MasterTestServer.start(uri, slave_uris)
21
+ rescue Interrupt
22
+ DeepTest.logger.info "Exiting due to Interrupt"
23
+ end
24
+
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + "/../../lib/deep_test"
2
+ require 'drb/drb'
3
+ require 'optparse'
4
+
5
+ config = DeepTest::Distributed::TestServer.parse_args(ARGV)
6
+
7
+ #
8
+ # Clear args so they won't be processed in any forked processes.
9
+ # - When specs are loaded by the RemoteWorkerServer, RSpec
10
+ # attempts to parse ARGV
11
+ #
12
+ ARGV.clear
13
+
14
+ begin
15
+ DeepTest::Distributed::TestServer.start(config)
16
+ rescue Interrupt
17
+ DeepTest.logger.info "Exiting due to Interrupt"
18
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/../../lib/deep_test'
2
+
3
+ unless ARGV.length == 2
4
+ puts "Usage: deep_test test_throughput <server uri> <test_count>"
5
+ exit(1)
6
+ end
7
+
8
+ uri = ARGV[0]
9
+ test_count = ARGV[1].to_i
10
+
11
+ options = DeepTest::Options.new(:distributed_server => uri,
12
+ :sync_options => {:source => ""})
13
+ server = DeepTest::Distributed::TestServer.connect options
14
+ workers = DeepTest::Distributed::ThroughputWorkerClient.new(options, server)
15
+ runner = DeepTest::Distributed::ThroughputRunner.new(options, test_count) do |result|
16
+ $stdout.print "."
17
+ $stdout.flush
18
+ end
19
+
20
+ start_time = Time.now
21
+ DeepTest::ProcessOrchestrator.new(options, workers, runner).run(false)
22
+ end_time = Time.now
23
+
24
+ puts
25
+ puts runner.statistics.summary
26
+
27
+ run_time = end_time.to_f - start_time.to_f
28
+ puts "Total Run Time: #{run_time} seconds"
29
+ puts "Run Time Not Spent On Tests: #{run_time - runner.statistics.timespan_in_seconds}"
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ module DeepTest
4
+ describe Option do
5
+ it "should have hash conversion" do
6
+ option = Option.new(:name, Option::Hash, {})
7
+ string = option.to_command_line({:a => "1", :b => "a"})
8
+ string.should be_instance_of(String)
9
+ option.from_command_line(string).should == {:a => "1", :b => "a"}
10
+ end
11
+
12
+ it "should support booleans in hash" do
13
+ option = Option.new(:name, Option::Hash, {})
14
+ string = option.to_command_line({:a => true})
15
+ string.should be_instance_of(String)
16
+ option.from_command_line(string).should == {:a => true}
17
+ end
18
+
19
+ it "should handle hash values with spaces" do
20
+ option = Option.new(:name, Option::Hash, {})
21
+
22
+ string = option.to_command_line(
23
+ {:a => "has a space", :b => "has more spaces"}
24
+ )
25
+
26
+ string.should be_instance_of(String)
27
+
28
+ option.from_command_line(string).should ==
29
+ {:a => "has a space", :b => "has more spaces"}
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,183 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ module DeepTest
4
+ describe Options do
5
+ it "should support number_of_workers" do
6
+ Options.new(:number_of_workers => 3).number_of_workers.should == 3
7
+ end
8
+
9
+ it "should have reasonable defaults" do
10
+ options = Options.new({})
11
+ options.number_of_workers.should == 2
12
+ options.timeout_in_seconds.should == 30
13
+ options.server_port.should == 6969
14
+ options.pattern.should == nil
15
+ options.metrics_file.should == nil
16
+ end
17
+
18
+ it "should support timeout_in_seconds" do
19
+ Options.new(:timeout_in_seconds => 2).timeout_in_seconds.should == 2
20
+ end
21
+
22
+ it "should support pattern" do
23
+ Options.new(:pattern => '*').pattern.should == '*'
24
+ end
25
+
26
+ it "should support distributed_server" do
27
+ Options.new(:distributed_server => "uri").distributed_server.should == "uri"
28
+ end
29
+
30
+ it "should support server_port" do
31
+ Options.new(:server_port => 10).server_port.should == 10
32
+ end
33
+
34
+ it "should support sync_options" do
35
+ Options.new(:sync_options => {:options => 1}).sync_options.should == {:options => 1}
36
+ end
37
+
38
+ it "should support worker_listener" do
39
+ Options.new(:worker_listener => "AListener").
40
+ worker_listener.should == "AListener"
41
+ end
42
+
43
+ it "should use DeepTest::NullWorkerListener as the default listener" do
44
+ Options.new({}).worker_listener.should == "DeepTest::NullWorkerListener"
45
+ end
46
+
47
+ it "should allow worker_listener to be set with class" do
48
+ class FakeListener; end
49
+ Options.new(:worker_listener => FakeListener).
50
+ worker_listener.should == "DeepTest::FakeListener"
51
+ end
52
+
53
+ it "should allow multiple workers to be specified" do
54
+ class FakeListener1; end
55
+ class FakeListener2; end
56
+ options = Options.new(
57
+ :worker_listener => "DeepTest::FakeListener1,DeepTest::FakeListener2"
58
+ )
59
+ listener = options.new_listener_list
60
+ listener.should be_instance_of(DeepTest::ListenerList)
61
+ listener.listeners.should have(2).listeners
62
+ listener.listeners.first.should be_instance_of(FakeListener1)
63
+ listener.listeners.last.should be_instance_of(FakeListener2)
64
+ end
65
+
66
+ it "should create a list of worker listeners upon request" do
67
+ Options.new({}).new_listener_list.should be_instance_of(DeepTest::ListenerList)
68
+ end
69
+
70
+ it "should support ui" do
71
+ Options.new(:ui => "AUI").ui.should == "AUI"
72
+ end
73
+
74
+ it "should use DeepTest:UIas the default listener" do
75
+ Options.new({}).ui.should == "DeepTest::UI::Console"
76
+ end
77
+
78
+ it "should allow ui to be set with class" do
79
+ class FakeUI; end
80
+ Options.new(:ui => FakeUI).ui.should == "DeepTest::FakeUI"
81
+ end
82
+
83
+ it "should instantiate ui, passing itself as parameter" do
84
+ options = Options.new({})
85
+ DeepTest::UI::Console.should_receive(:new).with(options)
86
+ options.ui_instance
87
+ end
88
+
89
+ it "should instantiate ui only one" do
90
+ options = Options.new({})
91
+ options.ui_instance.should equal(options.ui_instance)
92
+ end
93
+
94
+ it "should support strings as well as symbols" do
95
+ Options.new("number_of_workers" => 2).number_of_workers.should == 2
96
+ end
97
+
98
+ it "should raise error when invalid option is specifed" do
99
+ lambda {
100
+ Options.new(:foo => 1)
101
+ }.should raise_error(Options::InvalidOptionError)
102
+ end
103
+
104
+ it "should convert to command line option string" do
105
+ options = Options.new(:number_of_workers => 1, :timeout_in_seconds => 3)
106
+ options.to_command_line.should ==
107
+ "--number_of_workers 1 --timeout_in_seconds 3"
108
+ end
109
+
110
+ it "should parse from command line option string" do
111
+ options = Options.from_command_line(
112
+ "--number_of_workers 2 --timeout_in_seconds 3 --pattern *")
113
+ options.number_of_workers.should == 2
114
+ options.timeout_in_seconds.should == 3
115
+ options.pattern.should == '*'
116
+ end
117
+
118
+ it "should use default option value when no command line option is present" do
119
+ options = Options.from_command_line("")
120
+ options.number_of_workers.should == 2
121
+ end
122
+
123
+ it "should create local workers by default" do
124
+ options = Options.new({})
125
+ options.new_workers.should be_instance_of(LocalWorkers)
126
+ end
127
+
128
+ it "should create remote worker client when distributed server is specified" do
129
+ options = Options.new(:distributed_server => "uri", :sync_options => {:source => "root"})
130
+ Distributed::TestServer.should_receive(:connect).with(options).and_return(:server_instance)
131
+ Distributed::RemoteWorkerClient.should_receive(:new).with(options, :server_instance, be_instance_of(LocalWorkers))
132
+ options.new_workers
133
+ end
134
+
135
+ it "should create local workers when connect fails" do
136
+ options = Options.new(:distributed_server => "uri", :sync_options => {:source => "root"}, :ui => "DeepTest::UI::Null")
137
+ Distributed::TestServer.should_receive(:connect).and_raise("An error")
138
+ options.new_workers.should be_instance_of(LocalWorkers)
139
+ end
140
+
141
+ it "should return localhost as origin_hostname current hostname is same as when created" do
142
+ options = Options.new({})
143
+ options.origin_hostname.should == 'localhost'
144
+ end
145
+
146
+ it "should hostname at instantiation when current hostname is different" do
147
+ local_hostname = Socket.gethostname
148
+ options = Options.new({})
149
+ Socket.should_receive(:gethostname).and_return("host_of_query")
150
+ options.origin_hostname.should == local_hostname
151
+ end
152
+
153
+ it "should be able to calculate mirror_path based on base an sync_options" do
154
+ Socket.should_receive(:gethostname).and_return("hostname", "server_hostname")
155
+ options = Options.new(:sync_options => {:source => "/my/source/path"})
156
+ options.mirror_path("/mirror/base/path").should ==
157
+ "/mirror/base/path/hostname_my_source_path"
158
+ end
159
+
160
+ it "should raise a useful error if no source is specified" do
161
+ options = DeepTest::Options.new(:sync_options => {})
162
+ lambda {
163
+ options.mirror_path("base")
164
+ }.should raise_error("No source directory specified in sync_options")
165
+ end
166
+
167
+ it "should create drb object to connect to server" do
168
+ options = DeepTest::Options.new({})
169
+ server = options.server
170
+ server.__drburi.should == "druby://#{options.origin_hostname}:#{options.server_port}"
171
+ end
172
+
173
+ it "should be gathering metrics if metrics file is set" do
174
+ options = DeepTest::Options.new(:metrics_file => "filename")
175
+ options.should be_gathering_metrics
176
+ end
177
+
178
+ it "should not be gathering metrics if metrics file is not set" do
179
+ options = DeepTest::Options.new({})
180
+ options.should_not be_gathering_metrics
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + "/../../../spec_helper"
2
+
3
+ module Spec
4
+ module Example
5
+ # NoMethodError: undefined method `subclass' if constant is used below
6
+ # instead of string
7
+ describe "ExampleGroupMethods" do
8
+ before(:each) do
9
+ $show_deep_test_all_block_warning = true
10
+ end
11
+
12
+ it_should_behave_like "sandboxed rspec_options"
13
+
14
+ [:append_before, :before, :after, :prepend_before, :append_after, :prepend_after].each do |rspec_method|
15
+ it "should print warning on first call to #{rspec_method}(:all)" do
16
+ out = capture_stderr do
17
+ describe("test") do
18
+ send(rspec_method, :all) {}
19
+ send(rspec_method, :all) {}
20
+ end
21
+ end
22
+
23
+ out.should == ExampleGroupMethods::DeepTestAllBlockWarning + "\n"
24
+ end
25
+
26
+ it "#{rspec_method}(:all) should not print warning if global setting is turned off" do
27
+ $show_deep_test_all_block_warning = false
28
+
29
+ out = capture_stderr do
30
+ describe("test") do
31
+ send(rspec_method, :all) {}
32
+ end
33
+ end
34
+
35
+ out.should == ""
36
+ end
37
+
38
+ it "should not raise error on #{rspec_method}(:each)" do
39
+ lambda {
40
+ describe("test") do
41
+ send(rspec_method, :each) {}
42
+ end
43
+ }.should_not raise_error
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,61 @@
1
+ require File.dirname(__FILE__) + "/../../../spec_helper"
2
+
3
+ module Spec
4
+ module Example
5
+ describe ExampleMethods do
6
+ it_should_behave_like "sandboxed rspec_options"
7
+
8
+ it "should have identifier that can locate the example by line" do
9
+ group = describe("test") do
10
+ it("example") {}
11
+ it("example") {}
12
+ end
13
+
14
+ example_1 = group.examples.first
15
+ example_2 = group.examples.last
16
+
17
+ example_1.identifier.locate([group]).should == example_1
18
+ example_2.identifier.locate([group]).should == example_2
19
+ end
20
+
21
+ it "should have identifier that can locate the example by name" do
22
+ group = describe("test") do
23
+ 2.times do |i|
24
+ it("example#{i}") {}
25
+ end
26
+ end
27
+
28
+ example_1 = group.examples.first
29
+ example_2 = group.examples.last
30
+
31
+ example_1.identifier.locate([group]).should == example_1
32
+ example_2.identifier.locate([group]).should == example_2
33
+ end
34
+
35
+ describe ExampleMethods::Identifier do
36
+ it "should use descriptions in to_s" do
37
+ group = describe("test") do
38
+ it("example") {}
39
+ end
40
+
41
+ group.examples.first.identifier.to_s.should == "test example"
42
+ end
43
+
44
+ it "should be equal if basenames of paths are equal" do
45
+ id1 = ExampleMethods::Identifier.new("/a/spec.rb",
46
+ 10,
47
+ "group description",
48
+ "description")
49
+
50
+ id2 = ExampleMethods::Identifier.new("/b/spec.rb",
51
+ 10,
52
+ "group description",
53
+ "description")
54
+
55
+ id1.should == id2
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+