zeus-justinf 0.13.5
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.
- checksums.yaml +15 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +36 -0
- data/MIT-LICENSE +22 -0
- data/Rakefile +22 -0
- data/bin/zeus +17 -0
- data/build/zeus-darwin-amd64 +0 -0
- data/build/zeus-linux-386 +0 -0
- data/build/zeus-linux-amd64 +0 -0
- data/ext/inotify-wrapper/extconf.rb +24 -0
- data/ext/inotify-wrapper/inotify-wrapper.cpp +116 -0
- data/lib/zeus.rb +226 -0
- data/lib/zeus/load_tracking.rb +64 -0
- data/lib/zeus/m.rb +354 -0
- data/lib/zeus/m/test_collection.rb +52 -0
- data/lib/zeus/m/test_method.rb +39 -0
- data/lib/zeus/plan.rb +6 -0
- data/lib/zeus/rails.rb +256 -0
- data/lib/zeus/version.rb +3 -0
- data/spec/fake_mini_test.rb +42 -0
- data/spec/m_spec.rb +110 -0
- data/spec/rails_spec.rb +62 -0
- data/spec/spec_helper.rb +38 -0
- data/zeus.gemspec +35 -0
- metadata +126 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
module Zeus
|
2
|
+
module M
|
3
|
+
### Simple data structure for what a test method contains.
|
4
|
+
#
|
5
|
+
# Too lazy to make a class for this when it's really just a bag of data
|
6
|
+
# without any behavior.
|
7
|
+
#
|
8
|
+
# Includes the name of this method, what line on the file it begins on,
|
9
|
+
# and where it ends.
|
10
|
+
class TestMethod < Struct.new(:name, :start_line, :end_line)
|
11
|
+
# Set up a new test method for this test suite class
|
12
|
+
def self.create(suite_class, test_method, find_locations = true)
|
13
|
+
# Hopefully it's been defined as an instance method, so we'll need to
|
14
|
+
# look up the ruby Method instance for it
|
15
|
+
method = suite_class.instance_method(test_method)
|
16
|
+
|
17
|
+
if find_locations
|
18
|
+
# Ruby can find the starting line for us, so pull that out of the array
|
19
|
+
start_line = method.source_location.last
|
20
|
+
|
21
|
+
# Ruby can't find the end line however, and I'm too lazy to write
|
22
|
+
# a parser. Instead, `method_source` adds `Method#source` so we can
|
23
|
+
# deduce this ourselves.
|
24
|
+
#
|
25
|
+
# The end line should be the number of line breaks in the method source,
|
26
|
+
# added to the starting line and subtracted by one.
|
27
|
+
end_line = method.source.split("\n").size + start_line - 1
|
28
|
+
end
|
29
|
+
|
30
|
+
# Shove the given attributes into a new databag
|
31
|
+
new(test_method, start_line, end_line)
|
32
|
+
end
|
33
|
+
|
34
|
+
def escaped_name
|
35
|
+
Regexp.escape(name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/zeus/plan.rb
ADDED
data/lib/zeus/rails.rb
ADDED
@@ -0,0 +1,256 @@
|
|
1
|
+
def find_rails_path(root_path)
|
2
|
+
paths = %w(spec/dummy test/dummy .)
|
3
|
+
paths.find { |path| File.exists?(File.expand_path(path, root_path)) }
|
4
|
+
end
|
5
|
+
|
6
|
+
ROOT_PATH = File.expand_path(Dir.pwd)
|
7
|
+
RAILS_PATH = find_rails_path(ROOT_PATH)
|
8
|
+
ENV_PATH = File.expand_path('config/environment', RAILS_PATH)
|
9
|
+
BOOT_PATH = File.expand_path('config/boot', RAILS_PATH)
|
10
|
+
APP_PATH = File.expand_path('config/application', RAILS_PATH) unless defined? APP_PATH
|
11
|
+
|
12
|
+
require 'zeus'
|
13
|
+
|
14
|
+
def gem_is_bundled?(gem)
|
15
|
+
gemfile_lock_contents = File.read(ROOT_PATH + "/Gemfile.lock")
|
16
|
+
gemfile_lock_contents.scan(/^\s*#{gem} \(([^=~><]+?)\)/).flatten.first
|
17
|
+
end
|
18
|
+
|
19
|
+
if version = gem_is_bundled?('method_source')
|
20
|
+
gem 'method_source', version
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'zeus/m'
|
24
|
+
|
25
|
+
module Zeus
|
26
|
+
class Rails < Plan
|
27
|
+
def after_fork
|
28
|
+
reconnect_activerecord
|
29
|
+
restart_girl_friday
|
30
|
+
reconnect_redis
|
31
|
+
end
|
32
|
+
|
33
|
+
def _monkeypatch_rake
|
34
|
+
if version = gem_is_bundled?('rake')
|
35
|
+
gem 'rake', version
|
36
|
+
end
|
37
|
+
require 'rake/testtask'
|
38
|
+
Rake::TestTask.class_eval {
|
39
|
+
|
40
|
+
# Create the tasks defined by this task lib.
|
41
|
+
def define
|
42
|
+
desc "Run tests" + (@name==:test ? "" : " for #{@name}")
|
43
|
+
task @name do
|
44
|
+
# ruby "#{ruby_opts_string} #{run_code} #{file_list_string} #{option_list}"
|
45
|
+
rails_env = ENV['RAILS_ENV']
|
46
|
+
rubyopt = ENV['RUBYOPT']
|
47
|
+
ENV['RAILS_ENV'] = nil
|
48
|
+
ENV['RUBYOPT'] = nil # bundler sets this to require bundler :|
|
49
|
+
puts "zeus test #{file_list_string}"
|
50
|
+
ret = system "zeus test #{file_list_string}"
|
51
|
+
ENV['RAILS_ENV'] = rails_env
|
52
|
+
ENV['RUBYOPT'] = rubyopt
|
53
|
+
ret
|
54
|
+
end
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
alias_method :_original_define, :define
|
59
|
+
|
60
|
+
def self.inherited(klass)
|
61
|
+
return unless klass.name == "TestTaskWithoutDescription"
|
62
|
+
klass.class_eval {
|
63
|
+
def self.method_added(sym)
|
64
|
+
class_eval do
|
65
|
+
if !@rails_hack_reversed
|
66
|
+
@rails_hack_reversed = true
|
67
|
+
alias_method :define, :_original_define
|
68
|
+
def desc(*)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
}
|
74
|
+
end
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def boot
|
79
|
+
_monkeypatch_rake
|
80
|
+
$LOAD_PATH.unshift "./lib"
|
81
|
+
|
82
|
+
require BOOT_PATH
|
83
|
+
# config/application.rb normally requires 'rails/all'.
|
84
|
+
# Some 'alternative' ORMs such as Mongoid give instructions to switch this require
|
85
|
+
# out for a list of railties, not including ActiveRecord.
|
86
|
+
# We grep config/application.rb for all requires of rails/all or railties, and require them.
|
87
|
+
rails_components = File.read(APP_PATH + ".rb").
|
88
|
+
scan(/^\s*require\s*['"](.*railtie.*|rails\/all)['"]/).flatten
|
89
|
+
|
90
|
+
rails_components = ["rails/all"] if rails_components == []
|
91
|
+
rails_components.each do |component|
|
92
|
+
require component
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def default_bundle
|
97
|
+
Bundler.require(:default)
|
98
|
+
Zeus::LoadTracking.add_feature('./Gemfile.lock')
|
99
|
+
end
|
100
|
+
|
101
|
+
def development_environment
|
102
|
+
Bundler.require(:development)
|
103
|
+
::Rails.env = ENV['RAILS_ENV'] = "development"
|
104
|
+
require APP_PATH
|
105
|
+
::Rails.application.require_environment!
|
106
|
+
end
|
107
|
+
|
108
|
+
def prerake
|
109
|
+
require 'rake'
|
110
|
+
end
|
111
|
+
|
112
|
+
def rake
|
113
|
+
Rake.application.run
|
114
|
+
end
|
115
|
+
|
116
|
+
def generate
|
117
|
+
load_rails_generators
|
118
|
+
require 'rails/commands/generate'
|
119
|
+
end
|
120
|
+
|
121
|
+
def destroy
|
122
|
+
load_rails_generators
|
123
|
+
require 'rails/commands/destroy'
|
124
|
+
end
|
125
|
+
|
126
|
+
def runner
|
127
|
+
require 'rails/commands/runner'
|
128
|
+
end
|
129
|
+
|
130
|
+
def console
|
131
|
+
if defined?(Pry) && IRB == Pry
|
132
|
+
require "pry"
|
133
|
+
Pry.start
|
134
|
+
else
|
135
|
+
require 'rails/commands/console'
|
136
|
+
::Rails::Console.start(::Rails.application)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def dbconsole
|
141
|
+
require 'rails/commands/dbconsole'
|
142
|
+
|
143
|
+
meth = ::Rails::DBConsole.method(:start)
|
144
|
+
|
145
|
+
# `Rails::DBConsole.start` has been changed to load faster in
|
146
|
+
# https://github.com/rails/rails/commit/346bb018499cde6699fcce6c68dd7e9be45c75e1
|
147
|
+
#
|
148
|
+
# This will work with both versions.
|
149
|
+
if meth.arity.zero?
|
150
|
+
::Rails::DBConsole.start
|
151
|
+
else
|
152
|
+
::Rails::DBConsole.start(::Rails.application)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def server
|
157
|
+
require 'rails/commands/server'
|
158
|
+
server = ::Rails::Server.new
|
159
|
+
Dir.chdir(::Rails.application.root)
|
160
|
+
server.start
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_environment
|
164
|
+
Bundler.require(:test)
|
165
|
+
|
166
|
+
::Rails.env = ENV['RAILS_ENV'] = 'test'
|
167
|
+
require APP_PATH
|
168
|
+
|
169
|
+
$rails_rake_task = 'yup' # lie to skip eager loading
|
170
|
+
::Rails.application.require_environment!
|
171
|
+
$rails_rake_task = nil
|
172
|
+
|
173
|
+
$LOAD_PATH.unshift ".", "./lib", "./test", "./spec"
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_helper
|
177
|
+
# don't let minitest setup another exit hook
|
178
|
+
begin
|
179
|
+
require 'minitest/unit'
|
180
|
+
MiniTest::Unit.class_variable_set("@@installed_at_exit", true)
|
181
|
+
rescue LoadError
|
182
|
+
# noop
|
183
|
+
end
|
184
|
+
|
185
|
+
if ENV['RAILS_TEST_HELPER']
|
186
|
+
require ENV['RAILS_TEST_HELPER']
|
187
|
+
else
|
188
|
+
if File.exists?(ROOT_PATH + "/spec/spec_helper.rb")
|
189
|
+
require 'spec_helper'
|
190
|
+
elsif File.exists?(ROOT_PATH + "/test/minitest_helper.rb")
|
191
|
+
require 'minitest_helper'
|
192
|
+
else
|
193
|
+
require 'test_helper'
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def test(argv=ARGV)
|
199
|
+
if spec_file?(argv) && defined?(RSpec)
|
200
|
+
# disable autorun in case the user left it in spec_helper.rb
|
201
|
+
RSpec::Core::Runner.disable_autorun!
|
202
|
+
exit RSpec::Core::Runner.run(argv)
|
203
|
+
else
|
204
|
+
Zeus::M.run(argv)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
|
210
|
+
SPEC_DIR_REGEXP = %r"(^|/)spec"
|
211
|
+
SPEC_FILE_REGEXP = /.+_spec\.rb$/
|
212
|
+
|
213
|
+
def spec_file? argv
|
214
|
+
argv.any? do |arg|
|
215
|
+
arg.match(Regexp.union(SPEC_DIR_REGEXP, SPEC_FILE_REGEXP))
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def restart_girl_friday
|
220
|
+
return unless defined?(GirlFriday::WorkQueue)
|
221
|
+
# The Actor is run in a thread, and threads don't persist post-fork.
|
222
|
+
# We just need to restart each one in the newly-forked process.
|
223
|
+
ObjectSpace.each_object(GirlFriday::WorkQueue) do |obj|
|
224
|
+
obj.send(:start)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def reconnect_activerecord
|
229
|
+
return unless defined?(ActiveRecord::Base)
|
230
|
+
begin
|
231
|
+
ActiveRecord::Base.clear_all_connections!
|
232
|
+
ActiveRecord::Base.establish_connection
|
233
|
+
if ActiveRecord::Base.respond_to?(:shared_connection)
|
234
|
+
ActiveRecord::Base.shared_connection = ActiveRecord::Base.retrieve_connection
|
235
|
+
end
|
236
|
+
rescue ActiveRecord::AdapterNotSpecified
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def reconnect_redis
|
241
|
+
return unless defined?(Redis::Client)
|
242
|
+
ObjectSpace.each_object(Redis::Client) do |client|
|
243
|
+
client.connect rescue nil
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def load_rails_generators
|
248
|
+
require 'rails/generators'
|
249
|
+
::Rails.application.load_generators
|
250
|
+
rescue LoadError # Rails 3.0 doesn't require this block to be run, but 3.2+ does
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
Zeus.plan ||= Zeus::Rails.new
|
data/lib/zeus/version.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module MiniTest
|
2
|
+
module Unit
|
3
|
+
class TestCase
|
4
|
+
end
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def stub_mini_test_methods
|
9
|
+
MiniTest::Unit::TestCase.stub!(:test_suites).and_return [fake_suite]
|
10
|
+
MiniTest::Unit.stub!(:runner).and_return fake_runner
|
11
|
+
end
|
12
|
+
|
13
|
+
def fake_runner
|
14
|
+
@runner ||= stub("Runner", :run => 0)
|
15
|
+
end
|
16
|
+
|
17
|
+
def fake_suite
|
18
|
+
@suite ||= stub("TestSuite",
|
19
|
+
:test_methods => [fake_test_method],
|
20
|
+
:instance_method => fake_instance_method)
|
21
|
+
end
|
22
|
+
|
23
|
+
def fake_suite_with_special_characters
|
24
|
+
@suite ||= stub("TestSuite",
|
25
|
+
:test_methods => [fake_special_characters_test_method],
|
26
|
+
:instance_method => fake_instance_method(fake_special_characters_test_method))
|
27
|
+
end
|
28
|
+
|
29
|
+
def fake_test_method
|
30
|
+
"test_method"
|
31
|
+
end
|
32
|
+
|
33
|
+
def fake_special_characters_test_method
|
34
|
+
"test_my_test_method?"
|
35
|
+
end
|
36
|
+
|
37
|
+
def fake_instance_method(name=fake_test_method)
|
38
|
+
@instance_method ||= stub("InstanceMethod",
|
39
|
+
:source_location => ["path/to/file.rb", 2],
|
40
|
+
:source => "def #{name} \n assert true \n end")
|
41
|
+
end
|
42
|
+
|
data/spec/m_spec.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fake_mini_test'
|
3
|
+
|
4
|
+
module Zeus::M
|
5
|
+
describe Runner do
|
6
|
+
|
7
|
+
context "given a test with a question mark" do
|
8
|
+
before do
|
9
|
+
MiniTest::Unit::TestCase.stub!(:test_suites).and_return [fake_suite_with_special_characters]
|
10
|
+
MiniTest::Unit.stub!(:runner).and_return fake_runner
|
11
|
+
end
|
12
|
+
|
13
|
+
it "escapes the question mark when using line number" do
|
14
|
+
argv = ["path/to/file.rb:2"]
|
15
|
+
|
16
|
+
fake_runner.should_receive(:run).with(["-n", "/(test_my_test_method\\?)/"])
|
17
|
+
|
18
|
+
lambda { Runner.new(argv).run }.should exit_with_code(0)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "escapes the question mark from explicit names" do
|
22
|
+
argv = ["path/to/file.rb", "--name", fake_special_characters_test_method]
|
23
|
+
|
24
|
+
fake_runner.should_receive(:run).with(["-n", "test_my_test_method\\?"])
|
25
|
+
|
26
|
+
lambda { Runner.new(argv).run }.should exit_with_code(0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe Runner do
|
32
|
+
before do
|
33
|
+
stub_mini_test_methods
|
34
|
+
end
|
35
|
+
|
36
|
+
context "no option is given" do
|
37
|
+
it "runs the test without giving any option" do
|
38
|
+
argv = ["path/to/file.rb"]
|
39
|
+
|
40
|
+
fake_runner.should_receive(:run).with([])
|
41
|
+
|
42
|
+
lambda { Runner.new(argv).run }.should exit_with_code(0)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "given a line number" do
|
47
|
+
it "aborts if no test is found" do
|
48
|
+
argv = ["path/to/file.rb:100"]
|
49
|
+
|
50
|
+
STDERR.should_receive(:write).with(/No tests found on line 100/)
|
51
|
+
fake_runner.should_not_receive :run
|
52
|
+
|
53
|
+
lambda { Runner.new(argv).run }.should_not exit_with_code(0)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "runs the test if the correct line number is given" do
|
57
|
+
argv = ["path/to/file.rb:2"]
|
58
|
+
|
59
|
+
fake_runner.should_receive(:run).with(["-n", "/(#{fake_test_method})/"])
|
60
|
+
|
61
|
+
lambda { Runner.new(argv).run }.should exit_with_code(0)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "specifying test name" do
|
66
|
+
it "runs the specified tests when using a pattern in --name option" do
|
67
|
+
argv = ["path/to/file.rb", "--name", "/#{fake_test_method}/"]
|
68
|
+
|
69
|
+
fake_runner.should_receive(:run).with(["-n", "/#{fake_test_method}/"])
|
70
|
+
|
71
|
+
lambda { Runner.new(argv).run }.should exit_with_code(0)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "runs the specified tests when using a pattern in -n option" do
|
75
|
+
argv = ["path/to/file.rb", "-n", "/method/"]
|
76
|
+
|
77
|
+
fake_runner.should_receive(:run).with(["-n", "/method/"])
|
78
|
+
|
79
|
+
lambda { Runner.new(argv).run }.should exit_with_code(0)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "aborts if no test matches the given pattern" do
|
83
|
+
argv = ["path/to/file.rb", "-n", "/garbage/"]
|
84
|
+
|
85
|
+
STDERR.should_receive(:write).with(%r{No test name matches \'/garbage/\'})
|
86
|
+
fake_runner.should_not_receive :run
|
87
|
+
|
88
|
+
lambda { Runner.new(argv).run }.should_not exit_with_code(0)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "runs the specified tests when using a name (no pattern)" do
|
92
|
+
argv = ["path/to/file.rb", "-n", "#{fake_test_method}"]
|
93
|
+
|
94
|
+
fake_runner.should_receive(:run).with(["-n", fake_test_method])
|
95
|
+
|
96
|
+
lambda { Runner.new(argv).run }.should exit_with_code(0)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "aborts if no test matches the given test name" do
|
100
|
+
argv = ["path/to/file.rb", "-n", "method"]
|
101
|
+
|
102
|
+
STDERR.should_receive(:write).with(%r{No test name matches \'method\'})
|
103
|
+
fake_runner.should_not_receive :run
|
104
|
+
|
105
|
+
lambda { Runner.new(argv).run }.should_not exit_with_code(0)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|