nestor 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +34 -0
- data/Rakefile +76 -0
- data/VERSION +1 -0
- data/bin/nestor +3 -0
- data/doc/.gitignore +3 -0
- data/doc/state-diagram.graffle +3870 -0
- data/doc/state-diagram.png +0 -0
- data/lib/nestor/cli.rb +52 -0
- data/lib/nestor/machine.rb +161 -0
- data/lib/nestor/strategies/test/unit.rb +116 -0
- data/lib/nestor/strategies.rb +18 -0
- data/lib/nestor/watchers/rails.rb +56 -0
- data/lib/nestor/watchers/rails_script.rb +83 -0
- data/lib/nestor/watchers.rb +1 -0
- data/lib/nestor.rb +11 -0
- data/spec/machine_spec.rb +56 -0
- data/spec/spec_helper.rb +9 -0
- data/vendor/watchr-0.5.7/.gitignore +5 -0
- data/vendor/watchr-0.5.7/History.txt +32 -0
- data/vendor/watchr-0.5.7/LICENSE +19 -0
- data/vendor/watchr-0.5.7/Manifest +27 -0
- data/vendor/watchr-0.5.7/README.rdoc +108 -0
- data/vendor/watchr-0.5.7/Rakefile +49 -0
- data/vendor/watchr-0.5.7/TODO.txt +40 -0
- data/vendor/watchr-0.5.7/bin/watchr +77 -0
- data/vendor/watchr-0.5.7/docs.watchr +26 -0
- data/vendor/watchr-0.5.7/gem.watchr +32 -0
- data/vendor/watchr-0.5.7/lib/watchr/controller.rb +81 -0
- data/vendor/watchr-0.5.7/lib/watchr/event_handlers/base.rb +48 -0
- data/vendor/watchr-0.5.7/lib/watchr/event_handlers/portable.rb +55 -0
- data/vendor/watchr-0.5.7/lib/watchr/event_handlers/unix.rb +97 -0
- data/vendor/watchr-0.5.7/lib/watchr/script.rb +203 -0
- data/vendor/watchr-0.5.7/lib/watchr.rb +113 -0
- data/vendor/watchr-0.5.7/manifest.watchr +70 -0
- data/vendor/watchr-0.5.7/specs.watchr +38 -0
- data/vendor/watchr-0.5.7/test/README +11 -0
- data/vendor/watchr-0.5.7/test/event_handlers/test_base.rb +24 -0
- data/vendor/watchr-0.5.7/test/event_handlers/test_portable.rb +58 -0
- data/vendor/watchr-0.5.7/test/event_handlers/test_unix.rb +162 -0
- data/vendor/watchr-0.5.7/test/test_controller.rb +103 -0
- data/vendor/watchr-0.5.7/test/test_helper.rb +52 -0
- data/vendor/watchr-0.5.7/test/test_script.rb +123 -0
- data/vendor/watchr-0.5.7/test/test_watchr.rb +60 -0
- data/vendor/watchr-0.5.7/watchr.gemspec +60 -0
- metadata +152 -0
Binary file
|
data/lib/nestor/cli.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "nestor"
|
2
|
+
require "thor"
|
3
|
+
|
4
|
+
module Nestor
|
5
|
+
class Cli < Thor # :nodoc:
|
6
|
+
desc("start", <<-EODESC.gsub(/^\s{6}/, ""))
|
7
|
+
Starts a continuous test server.
|
8
|
+
EODESC
|
9
|
+
method_options :strategy => "test/unit", :watcher => "rails", :script => nil, :debug => false, :include => []
|
10
|
+
def start
|
11
|
+
puts "Using #{options[:strategy].inspect} strategy"
|
12
|
+
begin
|
13
|
+
# Try the internal version
|
14
|
+
require "nestor/strategies/#{options[:strategy]}"
|
15
|
+
rescue LoadError
|
16
|
+
# Else fallback to something I'm not aware of right now
|
17
|
+
require options[:strategy]
|
18
|
+
end
|
19
|
+
|
20
|
+
puts "Using #{options[:watcher].inspect} watcher"
|
21
|
+
begin
|
22
|
+
require "nestor/watchers/#{options[:watcher]}"
|
23
|
+
rescue LoadError
|
24
|
+
# Fallback to something external again
|
25
|
+
require options[:watcher]
|
26
|
+
end
|
27
|
+
|
28
|
+
Watchr.options.debug = options[:debug]
|
29
|
+
|
30
|
+
if options[:script] then
|
31
|
+
puts "Launching with custom script #{options[:script].inspect}"
|
32
|
+
else
|
33
|
+
puts "Launching..."
|
34
|
+
end
|
35
|
+
Nestor::Watchers::Rails.run(:script => Pathname.new(options[:script]))
|
36
|
+
end
|
37
|
+
|
38
|
+
desc("customize PATH", <<-EODESC.gsub(/^\s{6}/, ""))
|
39
|
+
Copies the named script file to PATH to allow customizing.
|
40
|
+
EODESC
|
41
|
+
method_options :strategy => "test/unit", :watcher => "rails"
|
42
|
+
def customize(path)
|
43
|
+
puts "Using #{options[:watcher].inspect} watcher"
|
44
|
+
require "nestor/watchers/#{options[:watcher]}"
|
45
|
+
|
46
|
+
raise "Destination #{path.inspect} already exists: will not overwrite" if File.file?(path)
|
47
|
+
FileUtils.cp(Nestor::Watchers::Rails.path_to_script, path)
|
48
|
+
|
49
|
+
puts "Wrote #{options[:watcher]} script to #{path.inspect}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require "state_machine"
|
2
|
+
|
3
|
+
module Nestor
|
4
|
+
# Implements the state machine that is at the heart of Nestor.
|
5
|
+
#
|
6
|
+
# == Usage
|
7
|
+
#
|
8
|
+
# In the Watchr script, use +@strategy+ to access an instance of this class.
|
9
|
+
#
|
10
|
+
# The available events you may call are:
|
11
|
+
#
|
12
|
+
# <tt>ready!</tt>:: Machine instances start in the +booting+ state. Once the boot is complete,
|
13
|
+
# call +ready+ to indicate you are ready to process events. The default
|
14
|
+
# rails template calls #ready when +test/test_helper.rb+ is loaded.
|
15
|
+
#
|
16
|
+
# <tt>changed!</tt>:: Tells the Machine a file changed. The Watchr script and Strategy are
|
17
|
+
# responsible for assigning meaning to the file. The default Watchr
|
18
|
+
# script knows how to map model, controller and view files to given
|
19
|
+
# tests, and the script thus only tells the Machine about test files.
|
20
|
+
# Nothing prevents another implementation from providing the actual
|
21
|
+
# implementation files and letting the Strategy decide later what to
|
22
|
+
# do about those.
|
23
|
+
#
|
24
|
+
# <tt>run_successful!</tt>:: Tells the Machine that the last build was successful. This
|
25
|
+
# does not necessarily indicate a a completely green build: only
|
26
|
+
# that the last run was successful, given the focused files.
|
27
|
+
#
|
28
|
+
# <tt>run_failed!</tt>:: Tells the Machine there were one or more test failures or errors.
|
29
|
+
# Again, this doesn't mean the whole build failed: only the last couple
|
30
|
+
# of files had something that caused a failure.
|
31
|
+
#
|
32
|
+
# <tt>run!</tt>:: Tells the machine to tell the +#strategy+ to run the tests, given the current
|
33
|
+
# state of affairs. This might be running all tests, or a subset if the Machine
|
34
|
+
# is currently focusing on some items. A separate event is required by the
|
35
|
+
# Machine to allow coalescing multiple change events together.
|
36
|
+
#
|
37
|
+
class Machine
|
38
|
+
# The Machine actually delegates running the tests to another object, and this is it's reference.
|
39
|
+
attr_reader :strategy # :nodoc:
|
40
|
+
|
41
|
+
# The list of files we are focusing on, as received by #changed!
|
42
|
+
attr_reader :focused_files # :nodoc:
|
43
|
+
|
44
|
+
# The last changed file. Set by #changed!
|
45
|
+
attr_reader :changed_file # :nodoc:
|
46
|
+
|
47
|
+
# The list of failing tests or examples being focused on right now
|
48
|
+
attr_reader :focuses # :nodoc:
|
49
|
+
|
50
|
+
# +strategy+ is required, and must implement a couple of methods. See Nestor::Strategies for the required calls.
|
51
|
+
def initialize(strategy)
|
52
|
+
super() # Have to specify no-args, or else it'll raise an ArgumentError
|
53
|
+
|
54
|
+
@strategy = strategy
|
55
|
+
@focused_files, @focuses = [], []
|
56
|
+
|
57
|
+
log_state_change
|
58
|
+
end
|
59
|
+
|
60
|
+
state_machine :initial => :booting do
|
61
|
+
event :ready do
|
62
|
+
transition any => :running_all
|
63
|
+
end
|
64
|
+
|
65
|
+
event :failed do
|
66
|
+
transition [:running_all, :running_multi, :running_focused] => :run_focused
|
67
|
+
end
|
68
|
+
|
69
|
+
event :successful do
|
70
|
+
transition :running_focused => :running_multi
|
71
|
+
transition :running_multi => :running_all
|
72
|
+
transition :running_all => :green
|
73
|
+
end
|
74
|
+
|
75
|
+
event :file_changed do
|
76
|
+
transition [:run_focused, :run_focused_pending] => :run_focused_pending, :if => :changed_file_in_focused_files?
|
77
|
+
transition [:run_focused_pending, :run_multi_pending, :run_focused] => :run_multi_pending
|
78
|
+
transition :green => :run_multi_pending
|
79
|
+
end
|
80
|
+
|
81
|
+
event :run do
|
82
|
+
transition :run_focused_pending => :running_focused
|
83
|
+
transition :run_multi_pending => :running_multi
|
84
|
+
end
|
85
|
+
|
86
|
+
after_transition any => any, :do => :log_state_change
|
87
|
+
after_transition :to => :running_all, :do => :run_all_tests
|
88
|
+
after_transition :to => :running_focused, :do => :run_focused_tests
|
89
|
+
after_transition :to => :running_multi, :do => :run_multi_tests
|
90
|
+
before_transition :to => :run_focused, :do => :log_focus
|
91
|
+
before_transition :to => [:run_focused_pending, :run_multi_pending],
|
92
|
+
:do => :log_pending_run
|
93
|
+
after_transition :on => :file_changed, :do => :add_changed_file_to_focused_files
|
94
|
+
end
|
95
|
+
|
96
|
+
# Indicates the run was succesful: a green build. This does not indicate that the
|
97
|
+
# whole build was successful: only that the files that ran last were successful.
|
98
|
+
def run_successful!(files, tests)
|
99
|
+
successful!
|
100
|
+
end
|
101
|
+
|
102
|
+
# Indicates there were one or more failures. +files+ lists the actual files
|
103
|
+
# that failed, while +tests+ indicates the test names or examples that failed.
|
104
|
+
def run_failed!(files, tests)
|
105
|
+
@focused_files, @focuses = files, tests
|
106
|
+
failed!
|
107
|
+
end
|
108
|
+
|
109
|
+
# Notifies the Machine that a file changed. This might trigger a state change and schedule a build.
|
110
|
+
def changed!(file)
|
111
|
+
@changed_file = file
|
112
|
+
file_changed!
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def run_all_tests
|
118
|
+
reset_focused_files
|
119
|
+
reset_focuses
|
120
|
+
@strategy.run_all
|
121
|
+
end
|
122
|
+
|
123
|
+
def run_multi_tests
|
124
|
+
reset_focuses
|
125
|
+
@strategy.run(focused_files)
|
126
|
+
end
|
127
|
+
|
128
|
+
def run_focused_tests
|
129
|
+
@strategy.run(focused_files, focuses)
|
130
|
+
end
|
131
|
+
|
132
|
+
def reset_focused_files
|
133
|
+
@focused_files.clear
|
134
|
+
end
|
135
|
+
|
136
|
+
def add_changed_file_to_focused_files
|
137
|
+
@focused_files << @changed_file unless @focused_files.include?(@changed_file)
|
138
|
+
end
|
139
|
+
|
140
|
+
def changed_file_in_focused_files?
|
141
|
+
@strategy.log("changed_file #{changed_file}, in focused_files? #{focused_files.inspect}")
|
142
|
+
focused_files.include?(changed_file)
|
143
|
+
end
|
144
|
+
|
145
|
+
def reset_focuses
|
146
|
+
focuses.clear
|
147
|
+
end
|
148
|
+
|
149
|
+
def log_state_change
|
150
|
+
@strategy.log("Machine entering state: #{state.inspect}")
|
151
|
+
end
|
152
|
+
|
153
|
+
def log_focus
|
154
|
+
@strategy.log("Focusing on #{focuses.inspect}")
|
155
|
+
end
|
156
|
+
|
157
|
+
def log_pending_run
|
158
|
+
@strategy.log("Run pending... Waiting for go ahead")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "pathname"
|
3
|
+
require "test/unit/ui/console/testrunner"
|
4
|
+
|
5
|
+
module Nestor
|
6
|
+
module Strategies
|
7
|
+
module Test
|
8
|
+
class Unit
|
9
|
+
def initialize(root)
|
10
|
+
@root = Pathname.new(root).realpath
|
11
|
+
end
|
12
|
+
|
13
|
+
# Logs a message to STDOUT. This implementation forks, so the #log method also
|
14
|
+
# provides the PID of the logger.
|
15
|
+
def log(message)
|
16
|
+
STDOUT.printf "[%d] %s - %s\n", Process.pid, Time.now.strftime("%H:%M:%S"), message
|
17
|
+
STDOUT.flush
|
18
|
+
end
|
19
|
+
|
20
|
+
# Runs absolutely all tests as found by walking test/.
|
21
|
+
def run_all
|
22
|
+
fork do
|
23
|
+
log "Run all tests"
|
24
|
+
test_files = Dir["test/**/*_test.rb"]
|
25
|
+
test_files.each {|f| log(f); load f}
|
26
|
+
|
27
|
+
ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
|
28
|
+
test_runner = ::Nestor::Strategies::Test::TestRunner.new(nil)
|
29
|
+
result = ::Test::Unit::AutoRunner.run(false, nil, []) do |autorunner|
|
30
|
+
autorunner.runner = lambda { test_runner }
|
31
|
+
end
|
32
|
+
|
33
|
+
report(test_runner, test_files)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Runs only the named files, and optionally focuses on only a couple of tests
|
38
|
+
# within the loaded test cases.
|
39
|
+
def run(test_files, focuses=[])
|
40
|
+
fork do
|
41
|
+
log "Running #{focuses.length} focused tests"
|
42
|
+
test_files.each {|f| log(f); load f}
|
43
|
+
|
44
|
+
ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
|
45
|
+
test_runner = ::Nestor::Strategies::Test::TestRunner.new(nil)
|
46
|
+
result = ::Test::Unit::AutoRunner.run(false, nil, []) do |autorunner|
|
47
|
+
autorunner.runner = lambda { test_runner }
|
48
|
+
autorunner.filters << proc{|t| focuses.include?(t.method_name)} unless focuses.empty?
|
49
|
+
end
|
50
|
+
|
51
|
+
report(test_runner, test_files)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# Since we forked, we can't call into the Machine from the child process. Upstream
|
58
|
+
# communications is implemented by writing new files to the filesystem and letting
|
59
|
+
# the parent process catch the changes.
|
60
|
+
def report(test_runner, test_files)
|
61
|
+
info = {"status" => test_runner.passed? ? "successful" : "failed", "failures" => {}}
|
62
|
+
failures = info["failures"]
|
63
|
+
test_runner.faults.each do |failure|
|
64
|
+
filename = if failure.respond_to?(:location) then
|
65
|
+
failure.location.detect do |loc|
|
66
|
+
filename = loc.split(":", 2).first
|
67
|
+
test_files.detect {|tf| filename.include?(tf)}
|
68
|
+
end
|
69
|
+
elsif failure.respond_to?(:exception) then
|
70
|
+
failure.exception.backtrace.detect do |loc|
|
71
|
+
filename = loc.split(":", 2).first
|
72
|
+
test_files.detect {|tf| filename.include?(tf)}
|
73
|
+
end
|
74
|
+
else
|
75
|
+
raise "Unknown object type received as failure: #{failure.inspect} doesn't have #exception or #location methods."
|
76
|
+
end
|
77
|
+
|
78
|
+
test_name = failure.test_name.split("(", 2).first.strip
|
79
|
+
if filename.nil? then
|
80
|
+
log("Could not map #{failure.test_name.inspect} to a specific test file: mapping to #{test_files.length}")
|
81
|
+
test_files.each do |tf|
|
82
|
+
failures[test_name] = tf
|
83
|
+
end
|
84
|
+
else
|
85
|
+
log("Failed #{failure.test_name.inspect} in #{filename.inspect}")
|
86
|
+
failures[test_name] = filename
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
File.open("tmp/nestor-results.yml", "w") {|io| io.write(info.to_yaml) }
|
91
|
+
log "Wrote #{failures.length} failure(s) to tmp/nestor-results.yml"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# A helper class that allows me to get more information from the build.
|
96
|
+
#
|
97
|
+
# This is something that definitely will change when Nestor is tested on Ruby 1.9.
|
98
|
+
class TestRunner < ::Test::Unit::UI::Console::TestRunner #:nodoc:
|
99
|
+
attr_reader :faults
|
100
|
+
|
101
|
+
# This is a duck-typing method. Test::Unit's design requiers a #run method,
|
102
|
+
# but it is implemented as a class method. I fake it here to allow me to
|
103
|
+
# pass an instance and have the actual TestRunner instance available afterwards.
|
104
|
+
def run(suite, output_level=NORMAL)
|
105
|
+
@suite = suite.respond_to?(:suite) ? suite.suite : suite
|
106
|
+
start
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns pass/fail status.
|
110
|
+
def passed?
|
111
|
+
@faults.empty?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Nestor
|
2
|
+
# Nestor::Cli will require a file named +nestor/strategies/#{strategy_name}+. If you want
|
3
|
+
# to provide custom strategies, make it available to Nestor using the correct path.
|
4
|
+
#
|
5
|
+
# Strategies are simple objects that implement the following protocol:
|
6
|
+
#
|
7
|
+
# <tt>log(message)</tt>:: Logs a simple message, either to the console or a logfile.
|
8
|
+
# The Machine will use the +log+ method to notify about it's
|
9
|
+
# state transitions.
|
10
|
+
#
|
11
|
+
# <tt>run_all</tt>:: Runs all the tests, no matter what. In the Rails &
|
12
|
+
# +Test::Unit+ case, this means <tt>Dir["test/**/*_test.rb"]</tt>.
|
13
|
+
#
|
14
|
+
# <tt>run(tests_files, focused_cases=[])</tt>:: Runs only a subset of the tests, maybe
|
15
|
+
# focusing on only a couple of tests / examples.
|
16
|
+
module Strategies
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "watchr"
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
module Nestor
|
5
|
+
module Watchers
|
6
|
+
# Knows how to map file change events from Rails conventions to the corresponding test case.
|
7
|
+
module Rails
|
8
|
+
# Launches a Watchr::Controller to and never returns. The Controller will
|
9
|
+
# listen for file change events and trigger appropriate events on the Machine.
|
10
|
+
#
|
11
|
+
# By default, the Rails watcher will use the +Test::Unit+ strategy.
|
12
|
+
#
|
13
|
+
# @option options :strategy [Nestor::Strategies] The strategy to use. Must be an instance of a class that implements the protocol defined in Nestor::Strategies.
|
14
|
+
# @option options :script The path to the Watchr script.
|
15
|
+
#
|
16
|
+
# @return Never...
|
17
|
+
def self.run(options={})
|
18
|
+
strategy = options[:strategy] || Nestor::Strategies::Test::Unit.new(Dir.pwd)
|
19
|
+
script = instantiate_script(options[:script])
|
20
|
+
|
21
|
+
strategy.log "Instantiating machine"
|
22
|
+
script.nestor_strategy = strategy
|
23
|
+
script.nestor_machine = Nestor::Machine.new(strategy)
|
24
|
+
Watchr::Controller.new(script, Watchr.handler.new).run
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.path_to_script
|
28
|
+
default_script_path
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def self.default_script_path
|
34
|
+
Pathname.new(File.dirname(__FILE__) + "/rails_script.rb")
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.instantiate_script(path) #:nodoc:
|
38
|
+
# Use the default if none provided
|
39
|
+
path = default_script_path if path.nil?
|
40
|
+
|
41
|
+
script = Watchr::Script.new(path)
|
42
|
+
class << script
|
43
|
+
def nestor_machine=(m)
|
44
|
+
@machine = m
|
45
|
+
end
|
46
|
+
|
47
|
+
def nestor_strategy=(s)
|
48
|
+
@strategy = s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
script
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
def log(message) #:nodoc:
|
2
|
+
@strategy.log(message)
|
3
|
+
end
|
4
|
+
|
5
|
+
RAILS_ENV = "test" unless defined?(RAILS_ENV)
|
6
|
+
log "Entering #{RAILS_ENV.inspect} environment"
|
7
|
+
|
8
|
+
log "Creating tmp/ if it doesn't exist"
|
9
|
+
Dir.mkdir("tmp") unless File.directory?("tmp")
|
10
|
+
|
11
|
+
log "Preloading test/test_helper.rb"
|
12
|
+
start_load_at = Time.now
|
13
|
+
$LOAD_PATH.unshift "test" unless $LOAD_PATH.include?("test")
|
14
|
+
require "test_helper"
|
15
|
+
|
16
|
+
end_load_at = Time.now
|
17
|
+
log "Waiting for changes (saving #{end_load_at - start_load_at} seconds per run)..."
|
18
|
+
|
19
|
+
def sendoff(timeout=0.8, path="tmp/nestor-sendoff") #:nodoc:
|
20
|
+
Thread.start(timeout, path) do |timeout, path|
|
21
|
+
log "Sendoff pending #{timeout}..."
|
22
|
+
sleep timeout
|
23
|
+
File.open(path, "w") {|io| io.write(rand.to_s)}
|
24
|
+
log "Sendoff fired on #{path}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def changed!(filename) #:nodoc:
|
29
|
+
@machine.changed! filename
|
30
|
+
sendoff
|
31
|
+
end
|
32
|
+
|
33
|
+
watch 'app/models/(.+)\.rb' do |md|
|
34
|
+
test_file = "test/unit/#{md[1]}_test.rb"
|
35
|
+
log "#{md[0].inspect} => #{test_file.inspect}"
|
36
|
+
changed! test_file if File.file?(test_file)
|
37
|
+
end
|
38
|
+
|
39
|
+
watch 'app/controllers/(.+)\.rb' do |md|
|
40
|
+
test_file = "test/functional/#{md[1]}_test.rb"
|
41
|
+
log "#{md[0].inspect} => #{test_file.inspect}"
|
42
|
+
changed! test_file if File.file?(test_file)
|
43
|
+
end
|
44
|
+
|
45
|
+
# It might be possible to run focused tests with the view name
|
46
|
+
watch 'app/views/(.+)' do |md|
|
47
|
+
segments = md[1].split("/")
|
48
|
+
path = segments[0..-2]
|
49
|
+
test_file = "test/functional/#{path.join("/")}_controller_test.rb"
|
50
|
+
log "#{md[0].inspect} => #{test_file.inspect}"
|
51
|
+
changed! test_file if File.file?(test_file)
|
52
|
+
end
|
53
|
+
|
54
|
+
watch 'config/' do |md|
|
55
|
+
@machine.reset!
|
56
|
+
end
|
57
|
+
|
58
|
+
watch 'test/test_helper\.rb' do |md|
|
59
|
+
@machine.reset!
|
60
|
+
end
|
61
|
+
|
62
|
+
watch 'test/(?:unit|functional|integration|performance)/.*' do |md|
|
63
|
+
log "#{md[0].inspect} => #{md[0].inspect}"
|
64
|
+
changed! md[0]
|
65
|
+
end
|
66
|
+
|
67
|
+
watch 'tmp/nestor-results.yml' do |md|
|
68
|
+
# Since we received the results, we must receive our child process' status, or
|
69
|
+
# else we'll have zombie processes lying around
|
70
|
+
Thread.start { Process.wait }
|
71
|
+
|
72
|
+
info = YAML.load_file(md[0])
|
73
|
+
log "New results in: #{info.inspect}"
|
74
|
+
failures = info["failures"]
|
75
|
+
@machine.send("run_#{info["status"]}!", failures.values.uniq, failures.keys)
|
76
|
+
end
|
77
|
+
|
78
|
+
watch 'tmp/nestor-sendoff' do |_|
|
79
|
+
log "Sendoff"
|
80
|
+
@machine.run!
|
81
|
+
end
|
82
|
+
|
83
|
+
@machine.ready!
|
@@ -0,0 +1 @@
|
|
1
|
+
require "nestor/watchers/rails"
|
data/lib/nestor.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Nestor::Machine do
|
4
|
+
it "should accept a strategy on instantiation" do
|
5
|
+
strategy = mock.as_null_object
|
6
|
+
machine = Nestor::Machine.new(strategy)
|
7
|
+
machine.strategy.should be_equal(strategy)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Nestor::Machine do
|
12
|
+
before(:each) do
|
13
|
+
@strategy = mock
|
14
|
+
@strategy.stub(:run_all)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should start in the :running_all state" do
|
18
|
+
@machine = Nestor::Machine.new(@strategy)
|
19
|
+
machine.should be_running_all
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should tell the strategy to run all tests" do
|
23
|
+
strategy = mock
|
24
|
+
strategy.should_receive(:run_all).with().once
|
25
|
+
Nestor::Machine.new(strategy)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should transition to :green when calling #successful" do
|
29
|
+
machine.successful
|
30
|
+
machine.should be_green
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should transition to :run_focused when calling #failed" do
|
34
|
+
machine.failed
|
35
|
+
machine.should be_run_focused
|
36
|
+
end
|
37
|
+
|
38
|
+
def machine
|
39
|
+
@machine ||= Nestor::Machine.new(@strategy)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe Nestor::Machine, "when in the run_focused state" do
|
44
|
+
before(:each) do
|
45
|
+
@strategy = mock
|
46
|
+
@strategy.stub(:run_all)
|
47
|
+
@machine = Nestor::Machine.new(@strategy)
|
48
|
+
@machine.failed
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should transition to :running_focused when calling #changed!(filename)" do
|
52
|
+
@strategy.should_receive(:run).with(["spec/machine_spec.rb"])
|
53
|
+
@machine.changed!("spec/machine_spec.rb")
|
54
|
+
@machine.should be_running_focused
|
55
|
+
end
|
56
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
=== v0.5.7
|
3
|
+
|
4
|
+
* Added manifest.watchr script
|
5
|
+
* Unix handler supports :deleted event type
|
6
|
+
* Unix handler supports :accessed (atime), :modified (mtime) and :changed
|
7
|
+
(ctime) event types (thanks gzuki[http://github.com/gzuki] for initial work)
|
8
|
+
|
9
|
+
|
10
|
+
=== v0.5.6
|
11
|
+
|
12
|
+
* Rev gem optional in development (thanks TwP[http://github.com/TwP])
|
13
|
+
* Allow gems to bundle .watchr scripts (thanks foca[http://github.com/foca])
|
14
|
+
|
15
|
+
gemname/lib/gemname.watchr
|
16
|
+
|
17
|
+
is now automatically picked up with
|
18
|
+
|
19
|
+
$ watchr gemname.watchr
|
20
|
+
|
21
|
+
* Look for script in path
|
22
|
+
* debug msg when rev not found on *nix
|
23
|
+
* rake task for cross interpreter testing
|
24
|
+
|
25
|
+
|
26
|
+
=== v0.5.5
|
27
|
+
|
28
|
+
* Rev gem is optional. Fixes issue #1
|
29
|
+
Install Rev to automatically get evented handler on *nix
|
30
|
+
|
31
|
+
gem install rev
|
32
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright © 2009 Martin Aumont (mynyml)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
.gitignore
|
2
|
+
History.txt
|
3
|
+
LICENSE
|
4
|
+
Manifest
|
5
|
+
README.rdoc
|
6
|
+
Rakefile
|
7
|
+
TODO.txt
|
8
|
+
bin/watchr
|
9
|
+
docs.watchr
|
10
|
+
gem.watchr
|
11
|
+
lib/watchr.rb
|
12
|
+
lib/watchr/controller.rb
|
13
|
+
lib/watchr/event_handlers/base.rb
|
14
|
+
lib/watchr/event_handlers/portable.rb
|
15
|
+
lib/watchr/event_handlers/unix.rb
|
16
|
+
lib/watchr/script.rb
|
17
|
+
manifest.watchr
|
18
|
+
specs.watchr
|
19
|
+
test/README
|
20
|
+
test/event_handlers/test_base.rb
|
21
|
+
test/event_handlers/test_portable.rb
|
22
|
+
test/event_handlers/test_unix.rb
|
23
|
+
test/test_controller.rb
|
24
|
+
test/test_helper.rb
|
25
|
+
test/test_script.rb
|
26
|
+
test/test_watchr.rb
|
27
|
+
watchr.gemspec
|