cwninja-drunit 0.1

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/README.markdown ADDED
@@ -0,0 +1,32 @@
1
+ # Distributed Ruby Unit (Testing)
2
+
3
+ A library for running tests across multiple applications from a single test case.
4
+
5
+
6
+ ## Basic usage:
7
+
8
+ class MainTest < Test::Unit::TestCase
9
+ include Drunit
10
+ RemoteApp(:fake_app, FAKE_APP_PATH + "/fake_app.rb")
11
+ RemoteApp(:rails_app, RAILS_APP_PATH + "/script/runner")
12
+
13
+ def test_should_use_the_same_db
14
+ id = in_app(:fake_app){
15
+ User.create!(:name => "Some Name")
16
+ }
17
+
18
+ in_app(:rails_app, id) do |id|
19
+ assert_nothing_raised() { User.find(id) }
20
+ end
21
+ end
22
+ end
23
+
24
+ ## Other "features"
25
+ * Automatically "Brings Up" and "Takes Down" your apps as needed. (Uses GC to tell when it's no longer needed.)
26
+ * Tracking of assertion counts.
27
+ * Beautified (a little) backtraces.
28
+ * Line number preserving between apps.
29
+ * Packed full of bugs (probably, I'm not sure).
30
+ * Packed full of 1.9 incompatibilities (I'm assuming).
31
+ * Packed full of space ninjas.
32
+ * Over 14% more awesome than a bag of chips.
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/gempackagetask'
6
+ require 'date'
7
+
8
+ desc 'Default: run unit tests.'
9
+ task :default => :test
10
+
11
+ desc 'run tests.'
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'lib'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+
18
+ spec = Gem::Specification.new do |s|
19
+ s.name = %q{drunit}
20
+ s.version = "0.1"
21
+ s.summary = %q{A library for running tests across multiple applications from a single test case.}
22
+ s.description = %q{A library for running tests across multiple applications from a single test case.}
23
+
24
+ s.files = FileList['[A-Z]*', 'lib/**/*.rb', 'test/**/*.rb', 'rails/*']
25
+ s.executables = "drunit_remote"
26
+ s.require_path = 'lib'
27
+ s.test_files = Dir[*['test/**/*_test.rb']]
28
+
29
+ s.has_rdoc = true
30
+ s.extra_rdoc_files = ["README.markdown"]
31
+ s.rdoc_options = ['--line-numbers', '--inline-source', "--main", "README.markdown"]
32
+
33
+ s.authors = ["Tom Lea"]
34
+ s.email = %q{commits@tomlea.co.uk}
35
+
36
+ s.platform = Gem::Platform::RUBY
37
+ end
38
+
39
+ Rake::GemPackageTask.new spec do |pkg|
40
+ pkg.need_tar = true
41
+ pkg.need_zip = true
42
+ end
43
+
44
+ desc "Clean files generated by rake tasks"
45
+ task :clobber => [:clobber_rdoc, :clobber_package]
46
+
47
+ desc "Generate a gemspec file"
48
+ task :gemspec do
49
+ File.open("#{spec.name}.gemspec", 'w') do |f|
50
+ f.write spec.to_ruby
51
+ end
52
+ end
data/bin/drunit_remote ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), *%w[.. lib drunit remote_test])
4
+
5
+ include Drunit
6
+ require ARGV.first
7
+
8
+ DRb.start_service nil, RemoteTest.new
9
+
10
+ STDOUT.puts DRb.uri
11
+ STDOUT.reopen(STDERR)
12
+
13
+ load ARGV.shift
14
+
15
+ DRb.thread.join
data/lib/drunit.rb ADDED
@@ -0,0 +1,46 @@
1
+ module Drunit
2
+ class RemoteError < RuntimeError
3
+ def self.name
4
+ @@name
5
+ end
6
+
7
+ def class
8
+ if type = look_up_exception
9
+ return type
10
+ else
11
+ @@name = @real_exception.to_s
12
+ super
13
+ end
14
+ end
15
+
16
+ def look_up_exception
17
+ @real_exception.split("::").inject(Object){|node, part|
18
+ node && node.const_defined?(part) && node.const_get(part)
19
+ }
20
+ end
21
+ end
22
+
23
+ module ClassMethods
24
+ def RemoteApp(name, *args)
25
+ const_set "RemoteAppFor_#{name}", RemoteApp.new(name, *args)
26
+ end
27
+ end
28
+
29
+ def in_app(name, *args, &block)
30
+ file, line, method = caller(2).first.split(":")
31
+ remote_app_for(name).run(method.gsub(/^in /, "").gsub(/[^a-zA-Z0-9_?!]/, ""), file, line.to_i, *args, &block)
32
+ ensure
33
+ remote_app_for(name).last_assertion_count.times{ add_assertion } rescue nil
34
+ end
35
+
36
+ def remote_app_for(name)
37
+ self.class.const_get("RemoteAppFor_#{name}")
38
+ end
39
+
40
+ def self.included(other)
41
+ other.send(:extend, ClassMethods)
42
+ end
43
+ end
44
+
45
+ require File.join(File.dirname(__FILE__), *%w[drunit remote_app])
46
+
@@ -0,0 +1,52 @@
1
+ require 'drb'
2
+ require 'ruby2ruby'
3
+
4
+ module Drunit
5
+ class RemoteApp
6
+ def initialize(name, boot = nil)
7
+ @name = name
8
+ @boot = boot
9
+ @boot ||= "#{name}/test/drunit_test_helper.rb" if File.exist? "#{name}/test/drunit_test_helper.rb"
10
+ @boot ||= "#{name}/test/test_helper.rb" if File.exist? "#{name}/test/test_helper.rb"
11
+ @remote_object = nil
12
+ end
13
+
14
+ def run(method_name, file, line, *args, &block)
15
+ raise_or_return(app.eval(block_to_source(method_name, &block), file, line, method_name, *args), method_name)
16
+ end
17
+
18
+ def last_assertion_count
19
+ app.last_assertion_count
20
+ end
21
+
22
+ private
23
+ def raise_or_return(e, method_name)
24
+ return e unless e.is_a? Exception
25
+ if first_remote_line = e.backtrace.grep(Regexp.new(method_name)).last
26
+ index = e.backtrace.index(first_remote_line)
27
+ raise e, e.message, e.backtrace[0..index] + ["RemoteApp<#{@name}>"] + caller(0)
28
+ end
29
+ raise e
30
+ end
31
+
32
+ def start_app!
33
+ drb_server = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "bin", "drunit_remote"))
34
+ pipe = IO.popen("#{drb_server} #{@boot}")
35
+ pid = pipe.pid
36
+ url = pipe.gets.chomp
37
+ remote_object = DRbObject.new(nil, url)
38
+ ObjectSpace.define_finalizer(remote_object, proc{|id| Process.kill("KILL", pid) && Process.wait})
39
+ return remote_object
40
+ end
41
+
42
+ def app
43
+ @remote_object ||= start_app!
44
+ end
45
+
46
+ def block_to_source(method_name, &block)
47
+ m = Module.new
48
+ m.send(:define_method, method_name, &block)
49
+ Ruby2Ruby.translate(m, method_name)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,54 @@
1
+ require 'drb'
2
+ require 'test/unit'
3
+
4
+ module Drunit
5
+ class RemoteError < RuntimeError
6
+ def initialize(real_exception)
7
+ @real_exception = real_exception
8
+ end
9
+ end
10
+
11
+ class RemoteTest
12
+ attr_reader :last_assertion_count
13
+
14
+ class TestCase
15
+ include Test::Unit::Assertions
16
+ attr_reader :assertion_count
17
+
18
+ def initialize(code, source_file, source_line, method_name)
19
+ @assertion_count = 0
20
+ @method_name = method_name
21
+ instance_eval(code, source_file, source_line)
22
+ end
23
+
24
+ def add_assertion
25
+ @assertion_count += 1
26
+ end
27
+
28
+ def run(*args)
29
+ send(@method_name, *args)
30
+ end
31
+ end
32
+
33
+ def eval(code, source_file, source_line, method_name, *args)
34
+ test_case = TestCase.new(code, source_file, source_line, method_name)
35
+ return rewrite_exceptions{ test_case.run(*args) }
36
+ rescue Exception => e
37
+ return e
38
+ ensure
39
+ @last_assertion_count = defined?(test_case.assertion_count) ? test_case.assertion_count : 0
40
+ end
41
+ private
42
+ # We need to strib down and generalise the exceptions to prevent the integration project from having to know anything about anything.
43
+ def rewrite_exceptions
44
+ return yield
45
+ rescue Test::Unit::AssertionFailedError
46
+ raise
47
+ rescue ArgumentError => e
48
+ raise e unless e.message =~ /Anonymous modules /
49
+ raise NameError, "Const Missing", e.backtrace[3..-1]
50
+ rescue Exception => e
51
+ raise Drunit::RemoteError.new(e.class.name), e.message, e.backtrace
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,13 @@
1
+ class SomeFoo
2
+ def multiply(a,b)
3
+ a * b
4
+ end
5
+ end
6
+
7
+ class SomeException < Exception
8
+ end
9
+
10
+ module MyModule
11
+ class SomeOtherException < Exception
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
2
+ require "test/unit"
3
+ require "drunit"
4
+
5
+ FAKE_APP_PATH = File.join(File.dirname(__FILE__), *%w[fake_app])
@@ -0,0 +1,41 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. test_helper])
2
+
3
+ class MainTest < Test::Unit::TestCase
4
+ include Drunit
5
+ RemoteApp(:fake_app, FAKE_APP_PATH + "/fake_app.rb")
6
+ def InApp(*args, &block)
7
+ in_app(:fake_app, *args, &block)
8
+ end
9
+
10
+ def test_should_not_raise_in_a_basic_case
11
+ InApp do
12
+ assert true
13
+ end
14
+ end
15
+
16
+ def test_should_raise_an_exception
17
+ assert_raise(RuntimeError) { InApp{ raise "Fail" } }
18
+ end
19
+
20
+ def test_should_raise_an_exception_faking_its_class_name_if_we_have_never_heard_of_it
21
+ InApp{ raise SomeException, "Fooo" }
22
+ flunk "Should have raised."
23
+ rescue => e
24
+ assert_equal "SomeException", e.class.name
25
+ end
26
+
27
+ def test_should_inject_the_fact_we_are_in_a_remote_app_into_the_backtrace
28
+ e = assert_raise(RuntimeError) { InApp{ raise "Fail" } }
29
+ assert_equal 1, e.backtrace.grep("RemoteApp<fake_app>").size
30
+ end
31
+
32
+ def test_should_raise_the_assertion_count_when_we_assert
33
+ original_count = @_result.assertion_count
34
+ InApp{ assert true}
35
+ assert_equal original_count + 1, @_result.assertion_count
36
+ end
37
+
38
+ def test_should_be_able_to_pass_in_simple_params
39
+ assert_equal 12, InApp(2,6){|a,b| SomeFoo.new.multiply(a, b)}
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cwninja-drunit
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Tom Lea
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-26 00:00:00 -08:00
13
+ default_executable: drunit_remote
14
+ dependencies: []
15
+
16
+ description: A library for running tests across multiple applications from a single test case.
17
+ email: commits@tomlea.co.uk
18
+ executables:
19
+ - drunit_remote
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - Rakefile
26
+ - README.markdown
27
+ - lib/drunit/remote_app.rb
28
+ - lib/drunit/remote_test.rb
29
+ - lib/drunit.rb
30
+ - test/fake_app/fake_app.rb
31
+ - test/test_helper.rb
32
+ - test/unit/main_test.rb
33
+ - bin/drunit_remote
34
+ has_rdoc: true
35
+ homepage:
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --line-numbers
39
+ - --inline-source
40
+ - --main
41
+ - README.markdown
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.2.0
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: A library for running tests across multiple applications from a single test case.
63
+ test_files:
64
+ - test/unit/main_test.rb