testr 14.0.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.
@@ -0,0 +1,9 @@
1
+ require 'testr/config'
2
+
3
+ TestR::Config.after_fork_hooks << lambda {
4
+ |worker_number, log_file, test_file, test_names|
5
+
6
+ # for compatitibilty with parallel_tests gem,
7
+ # store numbers as strings: "", "2", "3", "4"
8
+ ENV['TEST_ENV_NUMBER'] = (worker_number + 1).to_s if worker_number > 0
9
+ }
@@ -0,0 +1,37 @@
1
+ require 'testr/config'
2
+ require 'active_support/inflector'
3
+
4
+ TestR::Config.reabsorb_file_globs.push(
5
+ 'config/**/*.{rb,yml}',
6
+ 'db/schema.rb',
7
+ 'Gemfile.lock'
8
+ )
9
+
10
+ TestR::Config.test_file_matchers[%r<^(app|lib|test|spec)/.+\.rb$>] =
11
+ lambda do |path|
12
+ base = File.basename(path, '.rb')
13
+ poly = ActiveSupport::Inflector.pluralize(base)
14
+ "{test,spec}/**/{#{base},#{poly}_*}_{test,spec}.rb"
15
+ end
16
+
17
+ TestR::Config.test_file_matchers[%r<^(test|spec)/factories/.+_factory\.rb$>] =
18
+ lambda do |path|
19
+ base = File.basename(path, '_factory.rb')
20
+ poly = ActiveSupport::Inflector.pluralize(base)
21
+ "{test,spec}/**/{#{base},#{poly}_*}_{test,spec}.rb"
22
+ end
23
+
24
+ begin
25
+ require 'rails/railtie'
26
+ Class.new Rails::Railtie do
27
+ config.before_initialize do |app|
28
+ if app.config.cache_classes
29
+ warn "testr/config/rails: Setting #{app.class}.config.cache_classes = false"
30
+ app.config.cache_classes = false
31
+ end
32
+ end
33
+ end
34
+ rescue LoadError
35
+ warn "testr/config/rails: Railtie not available; please manually set:\n\t"\
36
+ "config.cache_classes = false"
37
+ end
@@ -0,0 +1,129 @@
1
+ require 'json'
2
+ require 'diff/lcs'
3
+ require 'testr/client'
4
+ require 'testr/server'
5
+ require 'testr/config'
6
+
7
+ module TestR
8
+ module Driver
9
+
10
+ extend Server
11
+ extend self
12
+
13
+ def run_all_test_files
14
+ run_test_files Dir[*Config.all_test_file_globs]
15
+ end
16
+
17
+ def stop_running_test_files
18
+ @master.send [:stop]
19
+ @running_test_files.clear
20
+ end
21
+
22
+ def rerun_passed_test_files
23
+ run_test_files @passed_test_files
24
+ end
25
+
26
+ def rerun_failed_test_files
27
+ run_test_files @failed_test_files
28
+ end
29
+
30
+ def reabsorb_overhead_files very_first_time = false
31
+ quit_herald_and_master unless very_first_time
32
+
33
+ @master = Client::Transceiver.new('testr-master') do |line|
34
+ event, file = JSON.load(line)
35
+
36
+ case event.to_sym
37
+ when :test
38
+ @running_test_files.push file
39
+
40
+ when :pass
41
+ @passed_test_files.push file unless @passed_test_files.include? file
42
+ @running_test_files.delete file
43
+
44
+ when :fail
45
+ @failed_test_files.push file unless @failed_test_files.include? file
46
+ @running_test_files.delete file
47
+ end
48
+
49
+ @upstream.print line
50
+ end
51
+
52
+ @master.send [:load, Config.overhead_load_paths,
53
+ Dir[*Config.overhead_file_globs]]
54
+
55
+ @herald = Client::Receiver.new('testr-herald') do |line|
56
+ changed_file = line.chomp
57
+ warn "testr-driver: herald: #{changed_file}" if $DEBUG
58
+
59
+ # find and run the tests that correspond to the changed file
60
+ Config.test_file_globbers.each do |source_regexp, test_globber|
61
+ if source_regexp =~ changed_file
62
+ run_test_files Dir[test_globber.call(changed_file).to_s]
63
+ end
64
+ end
65
+
66
+ # reabsorb text execution overhead if overhead files changed
67
+ if Config.reabsorb_file_greps.any? {|r| r =~ changed_file }
68
+ @upstream.puts JSON.dump([:over, changed_file])
69
+ # NOTE: new thread because reabsorb_overhead_files will kill this one
70
+ Thread.new { reabsorb_overhead_files }.join
71
+ end
72
+ end
73
+
74
+ rerun_running_test_files
75
+ end
76
+
77
+ def loop
78
+ reabsorb_overhead_files true
79
+ super
80
+ quit_herald_and_master
81
+ end
82
+
83
+ private
84
+
85
+ def quit_herald_and_master
86
+ @herald.quit
87
+ @master.quit
88
+ end
89
+
90
+ @running_test_files = []
91
+ @passed_test_files = []
92
+ @failed_test_files = []
93
+
94
+ def rerun_running_test_files
95
+ run_test_files @running_test_files
96
+ end
97
+
98
+ def run_test_files files
99
+ files.each {|f| run_test_file f }
100
+ end
101
+
102
+ def run_test_file file
103
+ @master.send [:test, file, find_changed_test_names(file)]
104
+ end
105
+
106
+ @lines_by_file = {}
107
+
108
+ def find_changed_test_names test_file
109
+ # cache the contents of the test file for diffing below
110
+ new_lines = File.readlines(test_file)
111
+ old_lines = @lines_by_file[test_file] || new_lines
112
+ @lines_by_file[test_file] = new_lines
113
+
114
+ # find which tests have changed inside the given test file
115
+ Diff::LCS.diff(old_lines, new_lines).flatten.map do |change|
116
+ catch :found do
117
+ # search backwards from the line that changed up to
118
+ # the first line in the file for test definitions
119
+ change.position.downto(0) do |i|
120
+ if test_name = Config.test_name_extractor.call(new_lines[i])
121
+ throw :found, test_name
122
+ end
123
+ end; nil # prevent unsuccessful search from returning an integer
124
+ end
125
+ end.compact.uniq
126
+ end
127
+
128
+ end
129
+ end
@@ -0,0 +1,100 @@
1
+ require 'json'
2
+ require 'testr/server'
3
+ require 'testr/config'
4
+
5
+ module TestR
6
+ module Master
7
+
8
+ extend Server
9
+ extend self
10
+
11
+ def load paths, files
12
+ $LOAD_PATH.unshift(*paths)
13
+
14
+ files.each do |file|
15
+ branch, leaf = File.split(file)
16
+ file = leaf if paths.include? branch
17
+ require file.sub(/\.rb$/, '')
18
+ end
19
+
20
+ @upstream.print @command_line
21
+ end
22
+
23
+ def test test_file, test_names
24
+ # throttle forking rate to meet the maximum concurrent workers limit
25
+ # NOTE: the next SIGCHLD signal will wake us from this eternal sleep
26
+ sleep until @command_by_worker_pid.size < Config.max_forked_workers
27
+
28
+ log_file = test_file + '.log'
29
+ worker_number = @worker_number_pool.shift
30
+
31
+ Config.before_fork_hooks.each do |hook|
32
+ hook.call worker_number, log_file, test_file, test_names
33
+ end
34
+
35
+ worker_pid = fork do
36
+ # make the process title Test::Unit friendly and ps(1) searchable
37
+ $0 = "testr-worker[#{worker_number}] #{test_file}"
38
+
39
+ # detach worker process from master process' group for kill -pgrp
40
+ Process.setsid
41
+
42
+ # detach worker process from master process' standard input stream
43
+ STDIN.reopen IO.pipe.first
44
+
45
+ # capture test output in log file because tests are run in parallel
46
+ # which makes it difficult to understand interleaved output thereof
47
+ STDERR.reopen(STDOUT.reopen(log_file, 'w')).sync = true
48
+
49
+ Config.after_fork_hooks.each do |hook|
50
+ hook.call worker_number, log_file, test_file, test_names
51
+ end
52
+
53
+ # after loading the user's test file, the at_exit() hook of the user's
54
+ # testing framework will take care of running the tests and reflecting
55
+ # any failures in the worker process' exit status, which will then be
56
+ # handled by the SIGCHLD trap registered in the master process (above)
57
+ Kernel.load test_file
58
+ end
59
+
60
+ @command_by_worker_pid[worker_pid] = @command.push(worker_number)
61
+ @upstream.print @command_line
62
+ end
63
+
64
+ def stop
65
+ # NOTE: the SIGCHLD handler will reap these killed worker processes
66
+ Process.kill :SIGTERM, *@command_by_worker_pid.keys.map {|pid| -pid }
67
+ rescue ArgumentError, SystemCallError
68
+ # some workers might have already exited before we sent them the signal
69
+ end
70
+
71
+ def loop
72
+ super
73
+ stop
74
+ end
75
+
76
+ private
77
+
78
+ @worker_number_pool = (0 ... Config.max_forked_workers).to_a
79
+ @command_by_worker_pid = {}
80
+
81
+ # process exited child processes and report finished workers to upstream
82
+ trap :SIGCHLD do
83
+ begin
84
+ while wait2_array = Process.wait2(-1, Process::WNOHANG)
85
+ child_pid, child_status = wait2_array
86
+ if command = @command_by_worker_pid.delete(child_pid)
87
+ @worker_number_pool.push command.pop
88
+ command[0] = child_status.success? ? 'pass' : 'fail'
89
+ @upstream.puts JSON.dump(command.push(child_status))
90
+ else
91
+ warn "testr-master: unknown child exited: #{wait2_array.inspect}"
92
+ end
93
+ end
94
+ rescue SystemCallError
95
+ # raised by wait2() when there are currently no child processes
96
+ end
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,32 @@
1
+ require 'json'
2
+
3
+ module TestR
4
+ module Server
5
+
6
+ def quit
7
+ throw :testr_server_quit
8
+ end
9
+
10
+ def loop
11
+ (@upstream = STDOUT.dup).sync = true
12
+ STDOUT.reopen(STDERR).sync = true
13
+
14
+ catch :testr_server_quit do
15
+ while line = STDIN.gets
16
+ warn "#{caller[2]} RECV #{line.chomp}" if $DEBUG
17
+
18
+ command = JSON.load(line)
19
+ method = command.first
20
+
21
+ if respond_to? method and method != __method__ # prevent loops
22
+ @command, @command_line = command, line
23
+ __send__(*command)
24
+ else
25
+ warn "#{self}: bad command: #{method}"
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module TestR
2
+ VERSION = "14.0.0"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "testr/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "testr"
7
+ s.version = TestR::VERSION
8
+ s.authors,
9
+ s.email = File.read('LICENSE').scan(/Copyright \d+ (.+) <(.+?)>/).transpose
10
+ s.homepage = "http://github.com/sunaku/testr"
11
+ s.summary = "Continuous testing tool for Ruby"
12
+ s.description = nil
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ # specify any dependencies here; for example:
20
+ # s.add_development_dependency "rspec"
21
+ # s.add_runtime_dependency "rest-client"
22
+ s.add_runtime_dependency "json", ">= 1.6.1"
23
+ s.add_runtime_dependency "guard", ">= 0.8.4"
24
+ s.add_runtime_dependency "diff-lcs", ">= 1.1.2"
25
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: testr
3
+ version: !ruby/object:Gem::Version
4
+ version: 14.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Suraj N. Kurapati
9
+ - Brian D. Burns
10
+ - Daniel Pittman
11
+ - Jacob Helwig
12
+ - Corné Verbruggen
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+ date: 2011-10-09 00:00:00.000000000 Z
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ name: json
20
+ requirement: &20744840 !ruby/object:Gem::Requirement
21
+ none: false
22
+ requirements:
23
+ - - ! '>='
24
+ - !ruby/object:Gem::Version
25
+ version: 1.6.1
26
+ type: :runtime
27
+ prerelease: false
28
+ version_requirements: *20744840
29
+ - !ruby/object:Gem::Dependency
30
+ name: guard
31
+ requirement: &20743380 !ruby/object:Gem::Requirement
32
+ none: false
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: 0.8.4
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: *20743380
40
+ - !ruby/object:Gem::Dependency
41
+ name: diff-lcs
42
+ requirement: &20742260 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.1.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: *20742260
51
+ description: ''
52
+ email:
53
+ - sunaku@gmail.com
54
+ - burns180@gmail.com
55
+ - daniel@rimspace.net
56
+ - jacob@technosorcery.net
57
+ - corne@g-majeur.nl
58
+ executables:
59
+ - testr
60
+ - testr-driver
61
+ - testr-herald
62
+ - testr-master
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .gitignore
67
+ - Gemfile
68
+ - HISTORY.md
69
+ - LICENSE
70
+ - README.md
71
+ - Rakefile
72
+ - bin/testr
73
+ - bin/testr-driver
74
+ - bin/testr-herald
75
+ - bin/testr-master
76
+ - lib/testr/client.rb
77
+ - lib/testr/config.rb
78
+ - lib/testr/config/parallel_tests.rb
79
+ - lib/testr/config/rails.rb
80
+ - lib/testr/driver.rb
81
+ - lib/testr/master.rb
82
+ - lib/testr/server.rb
83
+ - lib/testr/version.rb
84
+ - testr.gemspec
85
+ homepage: http://github.com/sunaku/testr
86
+ licenses: []
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 1.8.11
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Continuous testing tool for Ruby
109
+ test_files: []