tork 17.1.0 → 18.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.
- data/HISTORY.markdown +171 -258
- data/LICENSE +1 -0
- data/README.markdown +91 -63
- data/bin/tork +8 -14
- data/bin/tork-driver +19 -34
- data/bin/tork-engine +73 -0
- data/bin/tork-herald +9 -15
- data/bin/tork-master +17 -25
- data/lib/tork/config.rb +15 -12
- data/lib/tork/config/cucumber.rb +2 -2
- data/lib/tork/config/notify.rb +1 -1
- data/lib/tork/config/rails.rb +4 -10
- data/lib/tork/driver.rb +25 -102
- data/lib/tork/engine.rb +102 -0
- data/lib/tork/master.rb +27 -28
- data/lib/tork/server.rb +7 -5
- data/lib/tork/version.rb +1 -1
- data/man/man1/tork-driver.1 +20 -19
- data/man/man1/tork-engine.1 +66 -0
- data/man/man1/tork-herald.1 +5 -5
- data/man/man1/tork-master.1 +10 -9
- data/man/man1/tork.1 +3 -4
- data/tork.gemspec +9 -9
- metadata +21 -20
data/bin/tork-herald
CHANGED
@@ -1,36 +1,30 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
=begin
|
2
|
+
=begin =======================================================================
|
3
3
|
|
4
|
-
TORK-HERALD 1 2012-
|
5
|
-
==============================================================================
|
4
|
+
# TORK-HERALD 1 2012-02-06 18.0.0
|
6
5
|
|
7
|
-
NAME
|
8
|
-
------------------------------------------------------------------------------
|
6
|
+
## NAME
|
9
7
|
|
10
8
|
tork-herald - reports modified files
|
11
9
|
|
12
|
-
SYNOPSIS
|
13
|
-
------------------------------------------------------------------------------
|
10
|
+
## SYNOPSIS
|
14
11
|
|
15
12
|
`tork-herald` [*OPTION*]...
|
16
13
|
|
17
|
-
DESCRIPTION
|
18
|
-
------------------------------------------------------------------------------
|
14
|
+
## DESCRIPTION
|
19
15
|
|
20
16
|
This program monitors the current working directory and prints relative paths
|
21
17
|
of modified files in batches of single-line JSON arrays to the standard output
|
22
18
|
stream.
|
23
19
|
|
24
|
-
OPTIONS
|
25
|
-
------------------------------------------------------------------------------
|
20
|
+
## OPTIONS
|
26
21
|
|
27
22
|
`-h`, `--help`
|
28
|
-
|
23
|
+
Show this help manual.
|
29
24
|
|
30
|
-
SEE ALSO
|
31
|
-
------------------------------------------------------------------------------
|
25
|
+
## SEE ALSO
|
32
26
|
|
33
|
-
tork(1), tork-driver(1), tork-
|
27
|
+
tork(1), tork-herald(1), tork-driver(1), tork-engine(1), tork-master(1)
|
34
28
|
|
35
29
|
=end =========================================================================
|
36
30
|
|
data/bin/tork-master
CHANGED
@@ -1,24 +1,21 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
=begin
|
2
|
+
=begin =======================================================================
|
3
3
|
|
4
|
-
TORK-MASTER 1 2012-
|
5
|
-
==============================================================================
|
4
|
+
# TORK-MASTER 1 2012-02-06 18.0.0
|
6
5
|
|
7
|
-
NAME
|
8
|
-
------------------------------------------------------------------------------
|
6
|
+
## NAME
|
9
7
|
|
10
8
|
tork-master - absorbs overhead and runs tests
|
11
9
|
|
12
|
-
SYNOPSIS
|
13
|
-
------------------------------------------------------------------------------
|
10
|
+
## SYNOPSIS
|
14
11
|
|
15
12
|
`tork-master` [*OPTION*]...
|
16
13
|
|
17
|
-
DESCRIPTION
|
18
|
-
------------------------------------------------------------------------------
|
14
|
+
## DESCRIPTION
|
19
15
|
|
20
|
-
This program
|
21
|
-
|
16
|
+
This program absorbs the test execution overhead and forks to run your tests.
|
17
|
+
It reads the following single-line commands (JSON arrays) from its standard
|
18
|
+
input stream and performs the respective actions as described below.
|
22
19
|
|
23
20
|
`["load",` *paths*`,` *files*`]`
|
24
21
|
Adds the given array of *paths* to Ruby's $LOAD_PATH, loads the given array
|
@@ -38,10 +35,10 @@ standard input stream and performs the respective actions as described below.
|
|
38
35
|
`["test",` *test_file*`,` *line_numbers*`,` *log_file*`,` *worker_number*`]`
|
39
36
|
|
40
37
|
* Test has passed:
|
41
|
-
`["pass",` *test_file*`,` *line_numbers*`,` *log_file*`,` *worker_number*`,` *
|
38
|
+
`["pass",` *test_file*`,` *line_numbers*`,` *log_file*`,` *worker_number*`,` *exit_code*`,` *exit_info*`]`
|
42
39
|
|
43
40
|
* Test has failed:
|
44
|
-
`["fail",` *test_file*`,` *line_numbers*`,` *log_file*`,` *worker_number*`,` *
|
41
|
+
`["fail",` *test_file*`,` *line_numbers*`,` *log_file*`,` *worker_number*`,` *exit_code*`,` *exit_info*`]`
|
45
42
|
|
46
43
|
`["stop"]`
|
47
44
|
Stops all tests that are currently running and prints the given command line
|
@@ -50,30 +47,26 @@ standard input stream and performs the respective actions as described below.
|
|
50
47
|
`["quit"]`
|
51
48
|
Stops all tests that are currently running and exits.
|
52
49
|
|
53
|
-
OPTIONS
|
54
|
-
------------------------------------------------------------------------------
|
50
|
+
## OPTIONS
|
55
51
|
|
56
52
|
`-h`, `--help`
|
57
|
-
|
53
|
+
Show this help manual.
|
58
54
|
|
59
|
-
FILES
|
60
|
-
------------------------------------------------------------------------------
|
55
|
+
## FILES
|
61
56
|
|
62
57
|
*.tork.rb*
|
63
58
|
Optional Ruby script for configuring tork(1).
|
64
59
|
|
65
|
-
ENVIRONMENT
|
66
|
-
------------------------------------------------------------------------------
|
60
|
+
## ENVIRONMENT
|
67
61
|
|
68
62
|
`TORK_CONFIGS`
|
69
63
|
A single-line JSON array containing paths to actual files or names of
|
70
64
|
helper libraries in the tork/config/ namespace of Ruby's load path.
|
71
65
|
These configuration files are loaded just before *.tork.rb* is loaded.
|
72
66
|
|
73
|
-
SEE ALSO
|
74
|
-
------------------------------------------------------------------------------
|
67
|
+
## SEE ALSO
|
75
68
|
|
76
|
-
tork(1), tork-driver(1), tork-
|
69
|
+
tork(1), tork-herald(1), tork-driver(1), tork-engine(1), tork-master(1)
|
77
70
|
|
78
71
|
=end =========================================================================
|
79
72
|
|
@@ -83,7 +76,6 @@ require 'binman'
|
|
83
76
|
BinMan.help
|
84
77
|
|
85
78
|
require 'tork/master'
|
86
|
-
Tork::Master.loop
|
79
|
+
Tork::Master.new.loop
|
87
80
|
|
88
|
-
Process.waitall
|
89
81
|
raise SystemExit # prevent empty test suite from running in the master process
|
data/lib/tork/config.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
require 'ostruct'
|
2
|
-
|
3
1
|
module Tork
|
4
|
-
_user_config_file = '.tork.rb'
|
5
2
|
|
6
|
-
Config =
|
3
|
+
Config = Struct.new(:max_forked_workers, :overhead_load_paths,
|
4
|
+
:overhead_file_globs, :reabsorb_file_greps,
|
5
|
+
:all_test_file_globs, :test_file_globbers,
|
6
|
+
:before_fork_hooks, :after_fork_hooks,
|
7
|
+
:test_event_hooks).new
|
7
8
|
|
8
9
|
#---------------------------------------------------------------------------
|
9
10
|
# defaults
|
@@ -21,22 +22,21 @@ module Tork
|
|
21
22
|
|
22
23
|
Config.overhead_file_globs = ['{test,spec}/{test,spec}_helper.rb']
|
23
24
|
|
24
|
-
Config.reabsorb_file_greps = [
|
25
|
-
%r<^(test|spec)/\1_helper\.rb$>]
|
25
|
+
Config.reabsorb_file_greps = [%r<^(test|spec)/\1_helper\.rb$>]
|
26
26
|
|
27
27
|
Config.all_test_file_globs = ['{test,spec}/**/*_{test,spec}.rb',
|
28
28
|
'{test,spec}/**/{test,spec}_*.rb']
|
29
29
|
|
30
30
|
Config.test_file_globbers = {
|
31
31
|
# source files that correspond to test files
|
32
|
-
%r<^lib
|
33
|
-
|
34
|
-
["{test,spec}/**/#{
|
35
|
-
"{test,spec}/**/{test,spec}_#{
|
32
|
+
%r<^lib/.*?([^/]+)\.rb$> => lambda do |matches|
|
33
|
+
name = matches[1]
|
34
|
+
["{test,spec}/**/#{name}_{test,spec}.rb",
|
35
|
+
"{test,spec}/**/{test,spec}_#{name}.rb"]
|
36
36
|
end,
|
37
37
|
|
38
38
|
# the actual test files themselves
|
39
|
-
%r<^(test|spec)
|
39
|
+
%r<^(test|spec)/.*?(\1_[^/]+|[^/]+_\1)\.rb$> => lambda {|m| m[0] }
|
40
40
|
}
|
41
41
|
|
42
42
|
Config.before_fork_hooks = []
|
@@ -82,7 +82,9 @@ module Tork
|
|
82
82
|
# overrides
|
83
83
|
#---------------------------------------------------------------------------
|
84
84
|
|
85
|
-
|
85
|
+
if File.exist? user_config_file = '.tork.rb'
|
86
|
+
load user_config_file
|
87
|
+
end
|
86
88
|
|
87
89
|
if ENV.key? 'TORK_CONFIGS'
|
88
90
|
require 'json'
|
@@ -94,4 +96,5 @@ module Tork
|
|
94
96
|
end
|
95
97
|
end
|
96
98
|
end
|
99
|
+
|
97
100
|
end
|
data/lib/tork/config/cucumber.rb
CHANGED
@@ -4,12 +4,12 @@ Tork::Config.all_test_file_globs << 'features/**/*.feature'
|
|
4
4
|
|
5
5
|
Tork::Config.test_file_globbers.update(
|
6
6
|
# source files that correspond to test files
|
7
|
-
%r<^(features/(.+/)?)step_definitions/.+\.rb$> => lambda do |
|
7
|
+
%r<^(features/(.+/)?)step_definitions/.+\.rb$> => lambda do |matches|
|
8
8
|
matches[1] + '*.feature'
|
9
9
|
end,
|
10
10
|
|
11
11
|
# the actual test files themselves
|
12
|
-
%r<^features/.+\.feature$> => lambda {|
|
12
|
+
%r<^features/.+\.feature$> => lambda {|matches| matches[0] }
|
13
13
|
)
|
14
14
|
|
15
15
|
Tork::Config.after_fork_hooks.push lambda {
|
data/lib/tork/config/notify.rb
CHANGED
@@ -4,7 +4,7 @@ require 'set'
|
|
4
4
|
failed_test_files = Set.new
|
5
5
|
|
6
6
|
Tork::Config.test_event_hooks.push lambda {|message|
|
7
|
-
event, test_file, line_numbers, log_file
|
7
|
+
event, test_file, line_numbers, log_file = message
|
8
8
|
|
9
9
|
# make notifications edge-triggered: pass => fail or vice versa.
|
10
10
|
# we do not care about pass => pass or fail => fail transitions.
|
data/lib/tork/config/rails.rb
CHANGED
@@ -8,16 +8,10 @@ Tork::Config.reabsorb_file_greps.push(
|
|
8
8
|
)
|
9
9
|
|
10
10
|
Tork::Config.test_file_globbers.update(
|
11
|
-
%r<^(app|lib|test|spec)
|
12
|
-
|
13
|
-
|
14
|
-
"{test,spec}/**/{#{
|
15
|
-
end,
|
16
|
-
|
17
|
-
%r<^(test|spec)/factories/.+_factory\.rb$> => lambda do |path, matches|
|
18
|
-
base = File.basename(path, '_factory.rb')
|
19
|
-
poly = ActiveSupport::Inflector.pluralize(base)
|
20
|
-
"{test,spec}/**/{#{base},#{poly}_*}_{test,spec}.rb"
|
11
|
+
%r<^(app|lib|test|spec)/.*?([^/]+?)(_factory)?\.rb$> => lambda do |matches|
|
12
|
+
single = matches[2]
|
13
|
+
plural = ActiveSupport::Inflector.pluralize(single)
|
14
|
+
"{test,spec}/**/{#{single},#{plural}_*}_{test,spec}.rb"
|
21
15
|
end
|
22
16
|
)
|
23
17
|
|
data/lib/tork/driver.rb
CHANGED
@@ -1,131 +1,54 @@
|
|
1
1
|
require 'set'
|
2
|
-
require 'diff/lcs'
|
3
2
|
require 'tork/client'
|
4
|
-
require 'tork/
|
3
|
+
require 'tork/engine'
|
5
4
|
require 'tork/config'
|
6
5
|
|
7
6
|
module Tork
|
8
|
-
|
7
|
+
class Driver < Engine
|
9
8
|
|
10
|
-
|
11
|
-
|
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
|
31
|
-
@master.quit if defined? @master
|
32
|
-
|
33
|
-
@master = Client::Transceiver.new('tork-master') do |message|
|
34
|
-
event, file, line_numbers = message
|
35
|
-
|
36
|
-
case event.to_sym
|
37
|
-
when :test
|
38
|
-
@waiting_test_files.delete file
|
39
|
-
@running_test_files.add file
|
40
|
-
|
41
|
-
when :pass
|
42
|
-
@running_test_files.delete file
|
43
|
-
|
44
|
-
# only whole test file runs qualify as pass
|
45
|
-
if line_numbers.empty?
|
46
|
-
@failed_test_files.delete file
|
47
|
-
@passed_test_files.add file
|
48
|
-
end
|
49
|
-
|
50
|
-
when :fail
|
51
|
-
@running_test_files.delete file
|
52
|
-
@failed_test_files.add file
|
53
|
-
@passed_test_files.delete file
|
54
|
-
end
|
55
|
-
|
56
|
-
@client.send message # propagate output downstream
|
57
|
-
Config.test_event_hooks.each {|hook| hook.call message }
|
58
|
-
end
|
59
|
-
|
60
|
-
@master.send [:load, Config.overhead_load_paths,
|
61
|
-
Dir[*Config.overhead_file_globs]]
|
62
|
-
|
63
|
-
rerun_running_test_files
|
64
|
-
end
|
65
|
-
|
66
|
-
def loop
|
67
|
-
reabsorb_overhead_files
|
9
|
+
def initialize
|
10
|
+
super
|
68
11
|
|
69
12
|
@herald = Client::Transceiver.new('tork-herald') do |changed_files|
|
70
|
-
warn "#{$0}(#{$$}): FILE BATCH #{changed_files.size}" if $DEBUG
|
71
13
|
changed_files.each do |changed_file|
|
72
|
-
warn "#{$0}(#{$$}): FILE #{changed_file}" if $DEBUG
|
73
|
-
|
74
14
|
# find and run the tests that correspond to the changed file
|
75
|
-
|
76
|
-
|
77
|
-
|
15
|
+
visited = Set.new
|
16
|
+
visitor = lambda do |source_file|
|
17
|
+
Config.test_file_globbers.each do |regexp, globber|
|
18
|
+
if regexp =~ source_file and globs = globber.call($~)
|
19
|
+
Dir[*globs].each do |test_file|
|
20
|
+
if visited.add? test_file
|
21
|
+
run_test_file test_file
|
22
|
+
visitor.call test_file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
78
26
|
end
|
79
27
|
end
|
28
|
+
visitor.call changed_file
|
80
29
|
|
81
30
|
# reabsorb text execution overhead if overhead files changed
|
82
31
|
if Config.reabsorb_file_greps.any? {|r| r =~ changed_file }
|
83
32
|
@client.send [:over, changed_file]
|
84
|
-
|
85
|
-
Thread.new { reabsorb_overhead_files }.join
|
33
|
+
reabsorb_overhead_files
|
86
34
|
end
|
87
35
|
end
|
88
36
|
end
|
89
37
|
|
90
|
-
|
91
|
-
|
92
|
-
@herald.quit
|
93
|
-
@master.quit
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
|
98
|
-
@waiting_test_files = Set.new
|
99
|
-
@running_test_files = Set.new
|
100
|
-
@passed_test_files = Set.new
|
101
|
-
@failed_test_files = Set.new
|
102
|
-
|
103
|
-
def rerun_running_test_files
|
104
|
-
run_test_files @running_test_files
|
38
|
+
reabsorb_overhead_files
|
105
39
|
end
|
106
40
|
|
107
|
-
def
|
108
|
-
|
41
|
+
def quit
|
42
|
+
@herald.quit
|
43
|
+
super
|
109
44
|
end
|
110
45
|
|
111
|
-
def
|
112
|
-
|
113
|
-
@master.send [:test, file, find_changed_line_numbers(file)]
|
114
|
-
end
|
46
|
+
def run_all_test_files
|
47
|
+
run_test_files Dir[*Config.all_test_file_globs]
|
115
48
|
end
|
116
49
|
|
117
|
-
|
118
|
-
|
119
|
-
def find_changed_line_numbers test_file
|
120
|
-
# cache the contents of the test file for diffing below
|
121
|
-
new_lines = File.readlines(test_file)
|
122
|
-
old_lines = @lines_by_file[test_file] || new_lines
|
123
|
-
@lines_by_file[test_file] = new_lines
|
124
|
-
|
125
|
-
# find which line numbers have changed inside the test file
|
126
|
-
Diff::LCS.diff(old_lines, new_lines).flatten.
|
127
|
-
# +1 because line numbers start at 1, not 0
|
128
|
-
map {|change| change.position + 1 }.uniq
|
50
|
+
def reabsorb_overhead_files
|
51
|
+
reabsorb_overhead Config.overhead_load_paths, Dir[*Config.overhead_file_globs]
|
129
52
|
end
|
130
53
|
|
131
54
|
end
|
data/lib/tork/engine.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'diff/lcs'
|
3
|
+
require 'tork/client'
|
4
|
+
require 'tork/server'
|
5
|
+
require 'tork/config'
|
6
|
+
|
7
|
+
module Tork
|
8
|
+
class Engine < Server
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
@waiting_test_files = Set.new
|
13
|
+
@running_test_files = Set.new
|
14
|
+
@passed_test_files = Set.new
|
15
|
+
@failed_test_files = Set.new
|
16
|
+
@lines_by_file = {}
|
17
|
+
@master = create_master_process
|
18
|
+
end
|
19
|
+
|
20
|
+
def quit
|
21
|
+
@master.quit
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def reabsorb_overhead load_paths, overhead_files
|
26
|
+
@master.quit
|
27
|
+
@master = create_master_process
|
28
|
+
@master.send [:load, load_paths, overhead_files]
|
29
|
+
run_test_files @running_test_files # resume running them in the new master
|
30
|
+
end
|
31
|
+
|
32
|
+
def run_test_file test_file, line_numbers=nil
|
33
|
+
if File.exist? test_file and @waiting_test_files.add? test_file
|
34
|
+
line_numbers ||= find_changed_line_numbers(test_file)
|
35
|
+
@master.send [:test, test_file, line_numbers]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def stop_running_test_files
|
40
|
+
@master.send [:stop]
|
41
|
+
@running_test_files.clear
|
42
|
+
end
|
43
|
+
|
44
|
+
def rerun_passed_test_files
|
45
|
+
run_test_files @passed_test_files
|
46
|
+
end
|
47
|
+
|
48
|
+
def rerun_failed_test_files
|
49
|
+
run_test_files @failed_test_files
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def run_test_files files
|
55
|
+
files.each {|f| run_test_file f }
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def create_master_process
|
61
|
+
Client::Transceiver.new('tork-master') do |message|
|
62
|
+
@client.send message # propagate output downstream
|
63
|
+
|
64
|
+
event, file, line_numbers = message
|
65
|
+
case event.to_sym
|
66
|
+
when :test
|
67
|
+
@waiting_test_files.delete file
|
68
|
+
@running_test_files.add file
|
69
|
+
|
70
|
+
when :pass
|
71
|
+
@running_test_files.delete file
|
72
|
+
|
73
|
+
# only whole test file runs qualify as pass
|
74
|
+
if line_numbers.empty?
|
75
|
+
@failed_test_files.delete file
|
76
|
+
@passed_test_files.add file
|
77
|
+
end
|
78
|
+
|
79
|
+
when :fail
|
80
|
+
@running_test_files.delete file
|
81
|
+
@failed_test_files.add file
|
82
|
+
@passed_test_files.delete file
|
83
|
+
end
|
84
|
+
|
85
|
+
Config.test_event_hooks.each {|hook| hook.call message }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def find_changed_line_numbers test_file
|
90
|
+
# cache test file contents for diffing below
|
91
|
+
new_lines = File.readlines(test_file)
|
92
|
+
old_lines = @lines_by_file[test_file] || new_lines
|
93
|
+
@lines_by_file[test_file] = new_lines
|
94
|
+
|
95
|
+
# find changed line numbers in the test file
|
96
|
+
Diff::LCS.diff(old_lines, new_lines).flatten.
|
97
|
+
# +1 because line numbers start at 1, not 0
|
98
|
+
map {|change| change.position + 1 }.uniq
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|