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/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-01-30 17.1.0
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
- Display this help manual using man(1).
23
+ Show this help manual.
29
24
 
30
- SEE ALSO
31
- ------------------------------------------------------------------------------
25
+ ## SEE ALSO
32
26
 
33
- tork(1), tork-driver(1), tork-master(1), tork-herald(1)
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-01-30 17.1.0
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 reads the following single-line commands (JSON arrays) from its
21
- standard input stream and performs the respective actions as described below.
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*`,` *exit_status*`]`
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*`,` *exit_status*`]`
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
- Display this help manual using man(1).
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-master(1), tork-herald(1)
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 = OpenStruct.new
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 = [/^#{Regexp.quote(_user_config_file)}$/,
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/.+\.rb$> => lambda do |path, matches|
33
- base = File.basename(path, '.rb')
34
- ["{test,spec}/**/#{base}_{test,spec}.rb",
35
- "{test,spec}/**/{test,spec}_#{base}.rb"]
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)/.*(\1_[^/]+|[^/]+_\1)\.rb$> => proc {|path| path }
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
- load _user_config_file if File.exist? _user_config_file
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
@@ -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 |path, matches|
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 {|path, matches| path }
12
+ %r<^features/.+\.feature$> => lambda {|matches| matches[0] }
13
13
  )
14
14
 
15
15
  Tork::Config.after_fork_hooks.push lambda {
@@ -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, worker_number, exit_status = message
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.
@@ -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)/.+\.rb$> => lambda do |path, matches|
12
- base = File.basename(path, '.rb')
13
- poly = ActiveSupport::Inflector.pluralize(base)
14
- "{test,spec}/**/{#{base},#{poly}_*}_{test,spec}.rb"
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/server'
3
+ require 'tork/engine'
5
4
  require 'tork/config'
6
5
 
7
6
  module Tork
8
- module Driver
7
+ class Driver < Engine
9
8
 
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
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
- Config.test_file_globbers.each do |regexp, globber|
76
- if regexp =~ changed_file and globs = globber.call(changed_file, $~)
77
- run_test_files Dir[*globs]
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
- # NOTE: new thread because reabsorb_overhead_files will kill this one
85
- Thread.new { reabsorb_overhead_files }.join
33
+ reabsorb_overhead_files
86
34
  end
87
35
  end
88
36
  end
89
37
 
90
- super
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 run_test_files files
108
- files.each {|f| run_test_file f }
41
+ def quit
42
+ @herald.quit
43
+ super
109
44
  end
110
45
 
111
- def run_test_file file
112
- if File.exist? file and @waiting_test_files.add? file
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
- @lines_by_file = {}
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
@@ -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