nestor 0.1.0
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/.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
|