tork 17.1.0 → 18.0.0

Sign up to get free protection for your applications and to get access to all the features.
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