testowl 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in testowl.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,100 @@
1
+ TestOwl
2
+ =
3
+
4
+ ![TestOwl](https://github.com/billhorsman/testowl/raw/master/images/testowl.png)
5
+
6
+ Narrow Minded TestUnit/RSpec, Watchr and Growl Integration for Continuous Testing. TestOwl assumes you are running Rails and makes some guesses about what tests depend on what files. For instance, if you change model Foo then it looks for foo_test.rb and foos_controller_test.rb.
7
+
8
+ At the very least, it will run each test every time you save it.
9
+
10
+ Usage
11
+ ==
12
+
13
+ From Rails root:
14
+
15
+ testowl
16
+
17
+ If you're using [bundler](http://gembundler.com/) then you should probably run:
18
+
19
+ bundle exec testowl
20
+
21
+ Dependencies
22
+ ==
23
+
24
+ It uses [growlnotifiy](http://growl.info/extras.php) to send messages to Growl. If you don't have it installed then it will only write a message to your terminal. To get the full benefit of TestOwl you should definitely install growlnotify.
25
+
26
+ Bundler
27
+ ==
28
+
29
+ To install using Bundler:
30
+
31
+ group :test do
32
+ gem 'testowl', :git => "git@github.com:billhorsman/testowl.git"
33
+ end
34
+
35
+ RSpec
36
+ ==
37
+
38
+ TestOwl looks for <code>spec/spec_helper.rb</code> and if it finds it then it uses [RSpec](http://relishapp.com/rspec).
39
+
40
+ Test Unit
41
+ ==
42
+
43
+ TestOwl looks for <code>test/test_helper.rb</code> and if it finds it then it uses Test Unit. Actually, it looks for RSpec first and only checks for Test Unit if it can't find RSpec.
44
+
45
+ Spork
46
+ ==
47
+
48
+ [Spork](https://github.com/timcharper/spork) is a testing framework for RSpec and Cucumber (see below for use with Test Unit) that forks before each run to ensure a clean testing state. By preloading the Rails environment it speeds up the launch time to run tests. This is especially significant when running single, small tests.
49
+
50
+ If you are running Spork then it will use it (assuming it is on port 8988) but if it gets no response on that port then it will just run the tests directly.
51
+
52
+ To get it running you just:
53
+
54
+ $ bundle exec spork
55
+ Using TestUnit
56
+ Preloading Rails environment
57
+ Loading Spork.prefork block...
58
+ Spork is ready and listening on 8988!
59
+
60
+ Spork with RSpec
61
+ ==
62
+
63
+ You need to tell RSpec to use Spork by running it with the <code>--drb</code> option. If you want to do that every time then you can add a file called <code>.rspec</code> to your project:
64
+
65
+ --drb
66
+
67
+ If Spork isn't running then RSpec will just run the specs directly.
68
+
69
+ Tip: if you prefer full output instead of just dots then you can use <code>-f d</code> and I always like some color too. My .rspec looks like this:
70
+
71
+ -f d --color --drb
72
+
73
+ Spork with Test Unit
74
+ ==
75
+
76
+ Spork doesn't support Test Unit out of the box, but it does if you include the [spork-testunit](https://github.com/timcharper/spork-testunit) gem. This is what your Gemfile might look like
77
+
78
+ group :test do
79
+ gem 'spork', "~> 0.9.0.rc"
80
+ gem 'spork-testunit', :git => 'git://github.com/timcharper/spork-testunit.git'
81
+ gem 'testowl', :git => "git@github.com:billhorsman/testowl.git"
82
+ end
83
+
84
+ To use Spork you then have to run your tests like this:
85
+
86
+ testdrb test/unit/foo_test.rb
87
+
88
+ TestOwl does that for you.
89
+
90
+ Todo
91
+ ==
92
+
93
+ * Make Drb port configurable
94
+ * DSL to define relationship between changed files and tests to run.
95
+ * Add some more rules for relationships (with or without DSL)
96
+
97
+ Credits
98
+ ==
99
+
100
+ Copyright (c) 2011 [Bill Horsman](http://bill.logicalcobwebs.com), released under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/bin/testowl ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'testowl'
4
+ require 'active_support/inflector'
5
+
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib') unless $LOAD_PATH.include?(File.dirname(__FILE__) + '/../lib')
7
+ CONFIG = File.dirname(__FILE__) + '/../lib/testowl/config.rb'
8
+
9
+
10
+ begin
11
+ success = Testowl::Monitor.new.run
12
+ Kernel.exit 1 unless success
13
+ rescue SystemExit => e
14
+ Kernel.exit(e.status)
15
+ rescue Exception => e
16
+ STDERR.puts("#{e.message} (#{e.class})")
17
+ STDERR.puts(e.backtrace.join("\n"))
18
+ Kernel.exit 1
19
+ end
data/images/error.png ADDED
Binary file
data/images/failed.png ADDED
Binary file
Binary file
data/images/wait.png ADDED
Binary file
@@ -0,0 +1,34 @@
1
+ module Testowl
2
+ module Growl
3
+
4
+ Growlnotify = "growlnotify"
5
+
6
+ def self.grr(title, message, status, files, suffix)
7
+ project = File.expand_path(".").split("/").last
8
+ growlnotify = `which #{Growlnotify}`.chomp
9
+ if growlnotify == ''
10
+ if @warning_done
11
+ puts "Skipping growl"
12
+ else
13
+ puts "If you install #{Growlnotify} you'll get growl notifications. See the README."
14
+ @warning_done = true
15
+ end
16
+ else
17
+ options = []
18
+ options << "-n Watchr"
19
+ options << "--message '#{message.gsub("'", "`")}\n\n#{files.map{|file| file.sub(/^spec\/[^\/]*\//, '').sub(/_test.rb$/, '')}.join("\n")}\n#{suffix}'"
20
+ options << "--sticky" if status == :error
21
+ options << "--image '#{image_path(status)}'"
22
+ options << "--identifier #{Digest::MD5.hexdigest files.join}" # (used for coalescing)
23
+ title = "RSpec #{title} (#{project})"
24
+ system %(#{growlnotify} #{options.join(' ')} '#{title}' &)
25
+ puts message
26
+ end
27
+ end
28
+
29
+ def self.image_path(name)
30
+ File.dirname(__FILE__) + "/../../images/#{name}.png"
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,74 @@
1
+ module Testowl
2
+ class Monitor
3
+
4
+ attr_reader :test_dir, :test_suffix
5
+
6
+ def initialize()
7
+ if File.exist?("spec/spec_helper.rb")
8
+ @runner = RspecRunner.new
9
+ @test_dir = "spec"
10
+ @test_suffix = "spec"
11
+ elsif File.exist?("test/test_helper.rb")
12
+ @runner = TestUnitRunner.new
13
+ @test_dir = "test"
14
+ @test_suffix = "test"
15
+ else
16
+ raise "Can't find either spec_helper.rb or test_helper.rb and this owl is confused."
17
+ end
18
+ end
19
+
20
+ def run
21
+ script = Watchr::Script.new
22
+ # Watch the scripts themselves
23
+ script.watch("#{test_dir}/.*/*_#{test_suffix}\.rb") do |match|
24
+ puts "Detected change in #{match[0]}"
25
+ fire [match[0]], "has been updated"
26
+ end
27
+ # Watch models
28
+ script.watch("app/models/(.*)\.rb") do |match|
29
+ puts "Detected change in #{match[0]}"
30
+ tests = []
31
+ model = match[1]
32
+ tests += tests_for_model(model)
33
+ fire tests, "triggered by #{match[0]}"
34
+ end
35
+ puts "Monitoring files..."
36
+ Watchr::Controller.new(script, Watchr.handler.new).run
37
+ end
38
+
39
+ def fire(files, reason)
40
+ return if files.nil? || files.size == 0
41
+ # We don't want to do no performance testing
42
+ files = files.map{|file| file =~ /^test\/performance\// ? nil : file }.compact
43
+ puts "Running #{files.join(", ")}"
44
+ begin
45
+ test_count, fail_count, timing = @runner.run(files)
46
+ if test_count == 0
47
+ Growl.grr "Empty Test", "No tests run", :error, files, reason
48
+ elsif fail_count > 0
49
+ Growl.grr "Fail", "#{fail_count} out of #{test_count} test#{'s' if test_count > 1} failed in #{timing} :(", :failed, files, reason
50
+ else
51
+ Growl.grr "Pass", "All #{test_count} example#{'s' if test_count > 1} passed in #{timing} :)", :success, files, reason
52
+ end
53
+ rescue => exc
54
+ Growl.grr "Exception", exc.message, :error, files, reason
55
+ end
56
+ end
57
+
58
+ def tests_for_model(model)
59
+ tests = []
60
+ tests += Dir["#{test_dir}/**/#{model.pluralize}_controller_#{test_suffix}.rb"]
61
+ tests += Dir["#{test_dir}/**/#{model}_#{test_suffix}.rb"]
62
+ class_name = model.classify
63
+ count = 0
64
+ `grep #{class_name} -R app/controllers/* | grep '# Dependencies'`.lines.each do |line|
65
+ tests += Dir[line.split(':').first.sub(/^app/, test_suffix).sub(/\.rb$/, "_#{test_suffix}.rb")]
66
+ count += 1
67
+ end
68
+ puts "Found 1 dependency" if count == 1
69
+ puts "Found #{count} dependencies" if count > 1
70
+ tests
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,28 @@
1
+ module Testowl
2
+ class RspecRunner
3
+
4
+ def run(files)
5
+ results = `rspec -c #{files.join(" ")}`
6
+ lines = results.split("\n")
7
+ exception_message = lines.detect{|line| line =~ /^Exception encountered/ }
8
+ counts = lines.detect{|line| line =~ /(\d+)\sexamples?,\s(\d+)\sfailures?/ }
9
+ if counts
10
+ test_count, fail_count = counts.split(',').map(&:to_i)
11
+ timing = lines.detect{|line| line =~ /Finished\sin/}
12
+ timing = timing.sub(/Finished\sin/, '').strip if timing
13
+ if fail_count > 0
14
+ puts results
15
+ end
16
+ return test_count, fail_count, timing
17
+ else
18
+ $stderr.print results
19
+ if exception_message
20
+ raise exception_message
21
+ else
22
+ raise "Problem interpreting output"
23
+ end
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,56 @@
1
+ # These fix 1.8.7 test/unit results where a DRbUnknown is returned because the testdrb client doesn't have the classes
2
+ # in its local namespace. (See issue #2)
3
+ unless RUBY_VERSION =~ /^1\.9/
4
+ # MiniTest is Ruby 1.9, and the classes below only exist in the pre 1.9 test/unit
5
+ require 'test/unit/testresult'
6
+ require 'test/unit/failure'
7
+ end
8
+ require 'drb'
9
+
10
+ module Testowl
11
+ class TestUnitRunner
12
+
13
+ def run(files)
14
+ results = nil
15
+ begin
16
+ results = runDrb(files)
17
+ rescue
18
+ puts "Drb not available. Running tests directly instead."
19
+ results = runDirectly(files)
20
+ end
21
+ puts "Done"
22
+ lines = results.split("\n")
23
+ exception_message = lines.detect{|line| line =~ /^Exception encountered/ }
24
+ counts = lines.detect{|line| line =~ /(\d+)\sassertions?,\s(\d+)\sfailures?/ }
25
+ if counts
26
+ file_count, test_count, fail_count = counts.split(',').map(&:to_i)
27
+ timing = lines.detect{|line| line =~ /Finished\sin/}
28
+ timing = timing.sub(/Finished\sin/, '').strip if timing
29
+ if fail_count > 0
30
+ puts results
31
+ end
32
+ return test_count, fail_count, timing
33
+ else
34
+ if exception_message
35
+ raise exception_message
36
+ else
37
+ $stderr.print results
38
+ raise "Problem interpreting output"
39
+ end
40
+ end
41
+ end
42
+
43
+ def runDrb(files)
44
+ DRb.start_service("druby://127.0.0.1:0") # this allows Ruby to do some magical stuff so you can pass an output stream over DRb.
45
+ test_server = DRbObject.new_with_uri("druby://127.0.0.1:8988")
46
+ results = StringIO.new
47
+ test_server.run(files, $stderr, results)
48
+ results.string
49
+ end
50
+
51
+ def runDirectly(files)
52
+ `ruby #{files.join(' ')}`
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module Testowl
2
+ VERSION = "0.0.2"
3
+ end
data/lib/testowl.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'testowl/growl'
2
+ require 'testowl/monitor'
3
+ require 'testowl/rspec_runner'
4
+ require 'testowl/test_unit_runner'
5
+ require 'testowl/version'
6
+ require 'watchr'
7
+ require 'digest'
8
+ require 'active_support/inflector'
data/testowl.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "testowl/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "testowl"
7
+ s.version = Testowl::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Bill Horsman"]
10
+ s.email = ["bill@logicalcobwebs.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{TestUnit, Watchr and Growl Integration for Continuous Testing}
13
+ s.description = %q{TestUnit, Watchr and Growl Integration for Continuous Testing}
14
+
15
+ s.add_runtime_dependency "watchr"
16
+ s.add_runtime_dependency "rails"
17
+
18
+ s.files = [
19
+ "Gemfile",
20
+ "README.markdown",
21
+ "Rakefile",
22
+ "bin/testowl",
23
+ "images/error.png",
24
+ "images/failed.png",
25
+ "images/success.png",
26
+ "images/wait.png",
27
+ "lib/testowl.rb",
28
+ "lib/testowl/growl.rb",
29
+ "lib/testowl/monitor.rb",
30
+ "lib/testowl/rspec_runner.rb",
31
+ "lib/testowl/test_unit_runner.rb",
32
+ "lib/testowl/version.rb",
33
+ "testowl.gemspec"
34
+ ]
35
+ s.executables = ["testowl"]
36
+ s.require_paths = ["lib"]
37
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: testowl
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Bill Horsman
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-06-14 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ prerelease: false
32
+ type: :runtime
33
+ requirement: *id001
34
+ name: watchr
35
+ - !ruby/object:Gem::Dependency
36
+ version_requirements: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ hash: 3
42
+ segments:
43
+ - 0
44
+ version: "0"
45
+ prerelease: false
46
+ type: :runtime
47
+ requirement: *id002
48
+ name: rails
49
+ description: TestUnit, Watchr and Growl Integration for Continuous Testing
50
+ email:
51
+ - bill@logicalcobwebs.com
52
+ executables:
53
+ - testowl
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - Gemfile
60
+ - README.markdown
61
+ - Rakefile
62
+ - bin/testowl
63
+ - images/error.png
64
+ - images/failed.png
65
+ - images/success.png
66
+ - images/wait.png
67
+ - lib/testowl.rb
68
+ - lib/testowl/growl.rb
69
+ - lib/testowl/monitor.rb
70
+ - lib/testowl/rspec_runner.rb
71
+ - lib/testowl/test_unit_runner.rb
72
+ - lib/testowl/version.rb
73
+ - testowl.gemspec
74
+ has_rdoc: true
75
+ homepage: ""
76
+ licenses: []
77
+
78
+ post_install_message:
79
+ rdoc_options: []
80
+
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: 3
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ requirements: []
102
+
103
+ rubyforge_project:
104
+ rubygems_version: 1.5.0
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: TestUnit, Watchr and Growl Integration for Continuous Testing
108
+ test_files: []
109
+