Permalink
Browse files

Fixing #3988 - adding support for watchr

Also added a readme file explaining a bit of how the
continuous testing tools work.

Signed-off-by: Luke Kanies <luke@puppetlabs.com>
  • Loading branch information...
1 parent 3a44f0e commit 182c0033dcc1885a42bd0cbb429d278f53ae9480 @lak lak committed with test branch Jun 10, 2010
View
@@ -0,0 +1,45 @@
+# Continuous Testing
+
+This directory contains configurations for continuous testing, using
+either autotest (part of the ZenTest gem) or watchr (in the watchr
+gem). The purpose of these tools is to automatically run the
+appropriate test when a file is changed or, if appropriate, all
+tests. In general, they do a straightforward mapping from a given
+code file to its unit and/or integration test.
+
+It is highly recommended that you have one of these running at all
+times during development, as they provide immediate and continuous
+feedback as to your development process. There are some general
+usability downsides as you have to track the running process, but
+those downsides are easily worth it.
+
+# How to use
+
+To use autotest, install ZenTest and run it with no arguments
+from the root of the puppet repository:
+
+ $ autotest
+
+It is currently only configured to run specs.
+
+To use watchr, run it with the watchr file specified as its argument:
+
+ $ watchr autotest/watcher.rb
+
+Both will use growl if installed on a Mac, but watchr assumes the
+presence of growl and will likely fail without it. Autotest is a bit
+more mature and should be resilient to either.
+
+The primary reason to use to use watchr over autotest is that it uses
+filesystem events to detect changes (theoretically portably although
+only tested on OS X), thus eliminating the need for polling for
+changes across all files being monitored.
+
+# Gotchas
+
+Autotest will start out by running all tests; if you don't want that,
+stick a syntax error in one of the tests to force a failure, then fix
+it and go on your merry way.
+
+Watchr, on the other hand, will default to only running the files you
+change.
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
@@ -0,0 +1,138 @@
+ENV["WATCHR"] = "1"
+ENV['AUTOTEST'] = 'true'
+
+def run_comp(cmd)
+ puts cmd
+ results = []
+ old_sync = $stdout.sync
+ $stdout.sync = true
+ line = []
+ begin
+ open("| #{cmd}", "r") do |f|
+ until f.eof? do
+ c = f.getc
+ putc c
+ line << c
+ if c == ?\n then
+ results << if RUBY_VERSION >= "1.9" then
+ line.join
+ else
+ line.pack "c*"
+ end
+ line.clear
+ end
+ end
+ end
+ ensure
+ $stdout.sync = old_sync
+ end
+ results.join
+end
+
+def clear
+ #system("clear")
+end
+
+def growl(message, status)
+ # Strip the color codes
+ message.gsub!(/\[\d+m/, '')
+
+ growlnotify = `which growlnotify`.chomp
+ return if growlnotify.empty?
+ title = "Watchr Test Results"
+ image = status == :pass ? "autotest/images/pass.png" : "autotest/images/fail.png"
+ options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'"
+ system %(#{growlnotify} #{options} &)
+end
+
+def file2specs(file)
+ %w{spec/unit spec/integration}.collect { |d|
+ file.sub('lib/puppet', d)
+ }.find_all { |f|
+ File.exist?(f)
+ }
+end
+
+def file2test(file)
+ result = file.sub('lib/puppet', 'test')
+ return nil unless File.exist?(result)
+ result
+end
+
+def run_spec(command)
+ clear
+ result = run_comp(command).split("\n").last
+ status = result.include?('0 failures') ? :pass : :fail
+ growl result, status
+end
+
+def run_test(command)
+ clear
+ result = run_comp(command).split("\n").last
+ status = result.include?('0 failures, 0 errors') ? :pass : :fail
+ growl result.split("\n").last rescue nil
+end
+
+def run_test_file(file)
+ run_test(%Q(#{file}))
+end
+
+def run_spec_files(files)
+ files = Array(files)
+ return if files.empty?
+ opts = File.readlines('spec/spec.opts').collect { |l| l.chomp }.join(" ")
+ run_spec("spec #{files.join(' ')}")
+end
+
+def run_all_tests
+ run_test("rake unit")
+end
+
+def run_all_specs
+ run_test("rake spec")
+end
+
+def run_suite
+ run_all_tests
+ run_all_specs
+end
+
+watch('spec/spec_helper.rb') { run_all_specs }
+watch(%r%^spec/(unit|integration)/.*\.rb$%) { |md| run_spec_files(md[0]) }
+watch(%r%^lib/puppet/(.*)\.rb$%) { |md|
+ run_spec_files(file2specs(md[0]))
+ if t = file2test(md[0])
+ run_test_file(t)
+ end
+}
+watch(%r!^spec/lib/spec.*!) { |md| run_all_specs }
+watch(%r!^spec/lib/monkey_patches/.*!) { |md| run_all_specs }
+watch(%r{test/.+\.rb}) { |md|
+ if md[0] =~ /\/lib\//
+ run_all_tests
+ else
+ run_test_file(md[0])
+ end
+}
+
+# Ctrl-\
+Signal.trap 'QUIT' do
+ puts " --- Running all tests ---\n\n"
+ run_suite
+end
+
+@interrupted = false
+
+# Ctrl-C
+Signal.trap 'INT' do
+ if @interrupted then
+ @wants_to_quit = true
+ abort("\n")
+ else
+ puts "Interrupt a second time to quit; wait for rerun of tests"
+ @interrupted = true
+ Kernel.sleep 1.5
+ # raise Interrupt, nil # let the run loop catch it
+ run_suite
+ end
+end

0 comments on commit 182c003

Please sign in to comment.