tork 16.0.0 → 17.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.markdown CHANGED
@@ -1,3 +1,49 @@
1
+ ------------------------------------------------------------------------------
2
+ Version 17.0.0 (2012-01-27)
3
+ ------------------------------------------------------------------------------
4
+
5
+ Breaking changes:
6
+
7
+ * tork-herald(1) now emits batches of single-line JSON arrays instead of
8
+ printing one (raw) path per line. This makes IPC uniform across Tork.
9
+
10
+ * tork-master(1) now emits log_file and worker_number in status messages.
11
+
12
+ * The order of parameters for before/after fork hooks has been changed to
13
+ better reflect the order of items in tork-master(1)'s status messages.
14
+
15
+ * The old order was: worker_number, log_file, test_file, line_numbers.
16
+
17
+ * The new order is: test_file, line_numbers, log_file, worker_number.
18
+
19
+ New features:
20
+
21
+ * GH-24: add `tork/config/dotlog` configuration helper to "hide" log files.
22
+
23
+ * GH-25: add `tork/config/logdir` configuration helper to isolate log files.
24
+
25
+ * tork(1) now strips all whitespace from your input, in case you pressed
26
+ spacebar or tab a few times, by accident, before entering your command.
27
+
28
+ Housekeeping:
29
+
30
+ * tork/client: Replace write lock with queue to support SIGCHLD handler.
31
+
32
+ The SIGCHLD handler in tork-master(1) can be triggered at any time, even
33
+ in the middle of writing to the standard output stream! Locking access
34
+ to the output stream in normal code (outside the signal handler) would
35
+ freeze the program because the signal handler, waiting for the lock to
36
+ be released, would never return!
37
+
38
+ One solution is to maintain a thread-safe queue of outgoing items that
39
+ need to be written to the output stream. Both normal code and the
40
+ signal handler can quickly push an outgoing item onto the queue and
41
+ proceed with their business. A separate thread can then have the sole
42
+ responsibility of (and access to) continually writing those outgoing
43
+ items to the output stream.
44
+
45
+ * README: revise instructions, reorganize document, and other improvements.
46
+
1
47
  ------------------------------------------------------------------------------
2
48
  Version 16.0.0 (2012-01-25)
3
49
  ------------------------------------------------------------------------------
data/LICENSE CHANGED
@@ -10,6 +10,7 @@ Thanks to 2012 Jose Pablo Barrantes <xjpablobrx@gmail.com>
10
10
  Thanks to 2012 Spencer Steffen <spencer@citrusme.com>
11
11
  Thanks to 2012 Jesse Cooke <jesse@jc00ke.com>
12
12
  Thanks to 2012 Benjamin Quorning <benjamin@quorning.net>
13
+ Thanks to 2012 Nicolas Fouché <nicolas.fouche@gmail.com>
13
14
 
14
15
  Permission to use, copy, modify, and/or distribute this software for any
15
16
  purpose with or without fee is hereby granted, provided that the above
data/README.markdown CHANGED
@@ -39,19 +39,17 @@ Features
39
39
 
40
40
  * You can override the modular `tork*` programs with your own in $PATH.
41
41
 
42
- * Its core is written in less than 360 lines (SLOC) of pure Ruby code! :-)
42
+ * Its core is written in less than 370 lines (SLOC) of pure Ruby code! :-)
43
43
 
44
- ------------------------------------------------------------------------------
45
- Architecture
46
- ------------------------------------------------------------------------------
44
+ ### Architecture
47
45
 
48
46
  Following UNIX philosophy, Tork is composed of simple text-based programs: so
49
47
  you can build your own custom Tork user interface by wrapping `tork-driver`!
50
48
 
51
- * `tork` is an interactive command-line user interface (CLI) for driver
52
- * `tork-herald` monitors current directory tree and reports changed files
53
- * `tork-driver` tells master to run tests and keeps track of test results
54
- * `tork-master` absorbs test execution overhead and forks to run your tests
49
+ * `tork` is an interactive command-line user interface (CLI) for driver
50
+ * `tork-herald` monitors current directory tree and reports changed files
51
+ * `tork-driver` tells master to run tests and keeps track of test results
52
+ * `tork-master` absorbs test execution overhead and forks to run your tests
55
53
 
56
54
  When the herald observes that files in or beneath the current directory have
57
55
  been written to, it tells the driver, which then commands the master to fork a
@@ -64,9 +62,11 @@ diff and regexps) and then attempts to run just those. To make it run *all*
64
62
  tests in your saved file, simply save the file *again* without changing it.
65
63
 
66
64
  ------------------------------------------------------------------------------
67
- Starting off
65
+ Installation
68
66
  ------------------------------------------------------------------------------
69
67
 
68
+ gem install tork
69
+
70
70
  ### Prerequisites
71
71
 
72
72
  * Ruby 1.8.7 or 1.9.2 or newer.
@@ -83,34 +83,128 @@ Starting off
83
83
  gem install rb-inotify # linux
84
84
  gem install rb-fsevent # macosx
85
85
 
86
- ### Installation
86
+ ### Development
87
87
 
88
- gem install tork
88
+ git clone git://github.com/sunaku/tork
89
+ cd tork
90
+ bundle install --binstubs=bundle_bin
91
+ bundle_bin/tork --help # run it directly
92
+ bundle exec rake -T # packaging tasks
89
93
 
90
- ### Invocation
94
+ ------------------------------------------------------------------------------
95
+ Usage
96
+ ------------------------------------------------------------------------------
97
+
98
+ ### At the command line
91
99
 
92
100
  tork --help
93
101
 
94
- ### Monitoring
102
+ You can monitor your test processes from another terminal:
95
103
 
96
104
  watch 'ps xuw | sed -n "1p; /tor[k]/p" | fgrep -v sed'
97
105
 
98
- ### Development
106
+ ### With [Ruby on Rails]
99
107
 
100
- git clone git://github.com/sunaku/tork
101
- cd tork
102
- bundle install --binstubs=bundle_bin
103
- bundle_bin/tork --help # run it directly
104
- bundle exec rake -T # packaging tasks
108
+ For Rails 3 or newer, use the rails configuration helper (see below).
109
+ Otherwise, ensure that your `config/environments/test.rb` file contains:
110
+
111
+ config.cache_classes = false
112
+
113
+ To use SQLite3 as your test database, install its [in-memory database
114
+ adapter][memory_test_fix]. Otherwise, you *might* face these errors:
115
+
116
+ > SQLite3::BusyException: database is locked
117
+
118
+ > cannot start a transaction within a transaction
119
+
120
+ ### With [factory_girl]
121
+
122
+ Do not load your factories into the master process as part of your test
123
+ execution overhead in your test/spec helper because that would necessitate
124
+ overhead reabsorption whenever you change or create factory definitions.
125
+
126
+ Instead, use `at_exit()` to wait until (1) after the master process has forked
127
+ a worker process and (2) just before that worker process runs its test suite
128
+ (whose execution is started by your test framework's own `at_exit()` handler):
129
+
130
+ # in your test/spec helper
131
+ require 'factory_girl'
132
+ at_exit { FactoryGirl.find_definitions unless $! }
133
+
134
+ This way, worker processes will pick up changes in your factories "for free"
135
+ whenever they (re)run your test files. Skip if Ruby is exiting because of a
136
+ raised exception (denoted by the `$!` global variable in the snippet above).
137
+
138
+ As a bonus, this arrangement also works when tests are run outside of Tork!
105
139
 
106
140
  ------------------------------------------------------------------------------
107
141
  Configuration
108
142
  ------------------------------------------------------------------------------
109
143
 
110
144
  Tork looks for a configuration file named `.tork.rb` in its current working
111
- directory. The configuration file is a normal Ruby script. Inside it, you
112
- can query and modify the `Tork::Config` object (OpenStruct) according to the
113
- configuration options listed below.
145
+ directory. The configuration file is a normal Ruby script, inside which you
146
+ can query and modify the `Tork::Config` object: an instance of OpenStruct.
147
+
148
+ ------------------------------------------------------------------------------
149
+ Configuration helpers
150
+ ------------------------------------------------------------------------------
151
+
152
+ In case you did not read the `tork --help` manual page, please note that you
153
+ can pass *multiple* configuration helpers to tork(1) at the command line!
154
+
155
+ ### [Ruby on Rails]
156
+
157
+ At the command line:
158
+
159
+ tork rails
160
+
161
+ Or in your configuration file:
162
+
163
+ require 'tork/config/rails'
164
+
165
+ ### [Cucumber]
166
+
167
+ At the command line:
168
+
169
+ tork cucumber
170
+
171
+ Or in your configuration file:
172
+
173
+ require 'tork/config/cucumber'
174
+
175
+ ### [parallel_tests]
176
+
177
+ At the command line:
178
+
179
+ tork parallel_tests
180
+
181
+ Or in your configuration file:
182
+
183
+ require 'tork/config/parallel_tests'
184
+
185
+ ### Hide log files by prefixing their names with a dot
186
+
187
+ At the command line:
188
+
189
+ tork dotlog
190
+
191
+ Or in your configuration file:
192
+
193
+ require 'tork/config/dotlog'
194
+
195
+ ### Isolate log files into a separate `log/` directory
196
+
197
+ At the command line:
198
+
199
+ tork logdir
200
+
201
+ Or in your configuration file:
202
+
203
+ require 'tork/config/logdir'
204
+
205
+ ------------------------------------------------------------------------------
206
+ Configuration options
207
+ -----------------------------------------------------------------------------
114
208
 
115
209
  ### Tork::Config.max_forked_workers
116
210
 
@@ -181,19 +275,21 @@ worker process is forked to run a test file. These functions are given:
181
275
 
182
276
  3. The path of the test file that will be run by the worker process.
183
277
 
184
- 4. An array of names of tests inside the test file that will be run. If this
185
- array is empty, then all tests in the test file will be run.
278
+ 4. An array of line numbers in the test file to run. If this array is empty,
279
+ then the entire test file will be run.
186
280
 
187
281
  For example, to see some real values:
188
282
 
189
- Tork::Config.before_fork_hooks << lambda do |worker_number, log_file, test_file, line_numbers|
283
+ Tork::Config.before_fork_hooks.push lambda {
284
+ |test_file, line_numbers, log_file, worker_number|
285
+
190
286
  p :before_fork_hooks => {
191
- :worker_number => worker_number,
192
- :log_file => log_file,
193
287
  :test_file => test_file,
194
288
  :line_numbers => line_numbers,
289
+ :log_file => log_file,
290
+ :worker_number => worker_number,
195
291
  }
196
- end
292
+ }
197
293
 
198
294
  ### Tork::Config.after_fork_hooks
199
295
 
@@ -206,90 +302,27 @@ by `tork-master`. These functions are given:
206
302
 
207
303
  3. The path of the test file that will be run by the worker process.
208
304
 
209
- 4. An array of names of tests inside the test file that will be run. If this
210
- array is empty, then all tests in the test file will be run.
305
+ 4. An array of line numbers in the test file to run. If this array is empty,
306
+ then the entire test file will be run.
211
307
 
212
308
  For example, to see some real values, including the worker process' PID:
213
309
 
214
- Tork::Config.after_fork_hooks << lambda do |worker_number, log_file, test_file, line_numbers|
310
+ Tork::Config.after_fork_hooks.push lambda {
311
+ |test_file, line_numbers, log_file, worker_number|
312
+
215
313
  p :after_fork_hooks => {
216
- :worker_pid => $$,
217
- :worker_number => worker_number,
218
- :log_file => log_file,
219
314
  :test_file => test_file,
220
315
  :line_numbers => line_numbers,
316
+ :log_file => log_file,
317
+ :worker_number => worker_number,
318
+ :worker_pid => $$,
221
319
  }
222
- end
320
+ }
223
321
 
224
322
  The first function in this array instructs Test::Unit and RSpec to only run
225
323
  those tests that are defined on the given line numbers. This accelerates your
226
324
  test-driven development cycle by only running tests you are currently editing.
227
325
 
228
- ------------------------------------------------------------------------------
229
- Configuration helpers
230
- ------------------------------------------------------------------------------
231
-
232
- The following libraries assist you with configuring Tork. To use them,
233
- simply add the `require()` lines shown below to your configuration file
234
- *or* pass their basenames to the tork(1) command, also as shown below.
235
-
236
- ### require 'tork/config/rails' # tork rails
237
-
238
- Support for the [Ruby on Rails] web framework.
239
-
240
- ### require 'tork/config/cucumber' # tork cucumber
241
-
242
- Support for the [Cucumber] testing framework.
243
-
244
- ### require 'tork/config/parallel_tests' # tork parallel_tests
245
-
246
- Support for the [parallel_tests] library.
247
-
248
- ------------------------------------------------------------------------------
249
- Usage tips
250
- ------------------------------------------------------------------------------
251
-
252
- ### [factory_girl] factories
253
-
254
- Don't load your factories in master process (as part of your test execution
255
- overhead) because that would necessitate the reloading of said overhead
256
- whenever you change an existing factory definition or create a new one.
257
-
258
- Instead, use `at_exit()` to wait until (1) after the master process has forked
259
- a worker process and (2) just before that worker process runs its test suite
260
- (whose execution is started by your test framework's own `at_exit()` handler):
261
-
262
- require 'factory_girl'
263
- at_exit { FactoryGirl.find_definitions unless $! }
264
-
265
- This way, worker processes will pick up changes in your factories "for free"
266
- whenever they (re)run your test files. Also, don't load your factories or do
267
- anything else in your `at_exit()` handler if Ruby is exiting because of a
268
- raised exception (denoted by the `$!` global variable in the snippet above).
269
-
270
- ------------------------------------------------------------------------------
271
- Known issues
272
- ------------------------------------------------------------------------------
273
-
274
- ### Ruby on Rails
275
-
276
- * Ensure that your `config/environments/test.rb` file disables class caching
277
- as follows (**NOTE:** if you are using Rails 3, the `tork/config/rails`
278
- configuration helper can do this for you automatically):
279
-
280
- config.cache_classes = false
281
-
282
- Otherwise, Tork will appear to ignore source-code changes in your
283
- models, controllers, helpers, and other Ruby source files.
284
-
285
- * If SQLite3 raises one of the following errors, try using an [in-memory
286
- adapter for SQLite3][memory_test_fix] or use different database software
287
- (such as MySQL) for your test environment.
288
-
289
- * SQLite3::BusyException: database is locked
290
-
291
- * cannot start a transaction within a transaction
292
-
293
326
  ------------------------------------------------------------------------------
294
327
  License
295
328
  ------------------------------------------------------------------------------
data/bin/tork CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  =begin
3
3
 
4
- TORK 1 2012-01-25 16.0.0
4
+ TORK 1 2012-01-27 17.0.0
5
5
  ==============================================================================
6
6
 
7
7
  NAME
@@ -51,23 +51,21 @@ ENV['TORK_CONFIGS'] = JSON.dump(ARGV)
51
51
  require 'tork/client'
52
52
 
53
53
  warn 'tork: Absorbing test execution overhead...'
54
- @driver = Tork::Client::Transceiver.new('tork-driver') do |line|
55
- evstr, *details = JSON.load(line)
56
- event = evstr.to_sym
57
-
58
- case event
54
+ @driver = Tork::Client::Transceiver.new('tork-driver') do |event, *details|
55
+ case event_sym = event.to_sym
59
56
  when :load then warn 'tork: Overhead absorbed. Ready for testing!'
60
57
  when :over then warn 'tork: Reabsorbing changed overhead files...'
61
58
  else
62
- test_file, line_numbers, *details = details
63
- message = [evstr.upcase, test_file, line_numbers.inspect, details].join(' ')
59
+ test_file, line_numbers, log_file, worker_number, exit_status = details
60
+ message = [event.upcase, [test_file, *line_numbers].join(':'),
61
+ exit_status].compact.join(' ')
64
62
 
65
- color = case event
63
+ color = case event_sym
66
64
  when :pass then "\e[34m%s\e[0m" # blue
67
65
  when :fail then "\e[31m%s\e[0m" # red
68
66
  end
69
67
  message = color % message if color and STDOUT.tty?
70
- message = [message, File.read(test_file + '.log'), message] if event == :fail
68
+ message = [message, File.read(log_file), message] if event_sym == :fail
71
69
 
72
70
  puts message
73
71
  end
@@ -87,7 +85,7 @@ COMMANDS = {
87
85
  }
88
86
 
89
87
  begin
90
- while key = STDIN.gets.chomp
88
+ while key = STDIN.gets.strip
91
89
  if command = COMMANDS[key]
92
90
  warn "tork: Sending #{command.to_s.inspect} command..."
93
91
  @driver.send [command]
data/bin/tork-driver CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  =begin
3
3
 
4
- TORK-DRIVER 1 2012-01-25 16.0.0
4
+ TORK-DRIVER 1 2012-01-27 17.0.0
5
5
  ==============================================================================
6
6
 
7
7
  NAME
data/bin/tork-herald CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  =begin
3
3
 
4
- TORK-HERALD 1 2012-01-25 16.0.0
4
+ TORK-HERALD 1 2012-01-27 17.0.0
5
5
  ==============================================================================
6
6
 
7
7
  NAME
@@ -18,7 +18,8 @@ DESCRIPTION
18
18
  ------------------------------------------------------------------------------
19
19
 
20
20
  This program monitors the current working directory and prints relative paths
21
- of modified files, one per line, to the standard output stream.
21
+ of modified files in batches of single-line JSON arrays to the standard output
22
+ stream.
22
23
 
23
24
  OPTIONS
24
25
  ------------------------------------------------------------------------------
@@ -40,8 +41,9 @@ BinMan.help
40
41
 
41
42
  require 'guard'
42
43
  require 'guard/listener'
44
+ require 'json'
43
45
 
44
46
  listener = Guard::Listener.select_and_init(:watch_all_modifications => true)
45
- listener.on_change {|files| puts files }
47
+ listener.on_change {|files| puts JSON.dump(files) }
46
48
  STDOUT.sync = true # don't buffer puts()
47
49
  listener.start
data/bin/tork-master CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  =begin
3
3
 
4
- TORK-MASTER 1 2012-01-25 16.0.0
4
+ TORK-MASTER 1 2012-01-27 17.0.0
5
5
  ==============================================================================
6
6
 
7
7
  NAME
@@ -30,16 +30,18 @@ standard input stream and performs the respective actions as described below.
30
30
  chosen unit testing framework (loaded by your test execution overhead) to
31
31
  only run those tests that are defined on the given array of *line_numbers*.
32
32
 
33
- Prints the given command line to the standard output stream immediately
34
- after forking the child process.
33
+ Prints the following status messages to the standard output stream. The
34
+ standard output and error streams of the forked child process are captured
35
+ in the *log_file* specified in these status messages.
35
36
 
36
- Prints the given command line, modified with `"pass"` (if the test passed)
37
- or `"fail"` (if the test failed) in place of `"test"`, to the standard
38
- output stream after the forked child process finishes.
37
+ * Test is running:
38
+ `["test",` *test_file*`,` *line_numbers*`,` *log_file*`,` *worker_number*`]`
39
39
 
40
- The standard output and error streams of the forked child process are
41
- redirected to a file whose path and name are the same as that of the test
42
- file being run by the forked child process but with ".log" appended.
40
+ * Test has passed:
41
+ `["pass",` *test_file*`,` *line_numbers*`,` *log_file*`,` *worker_number*`,` *exit_status*`]`
42
+
43
+ * Test has failed:
44
+ `["fail",` *test_file*`,` *line_numbers*`,` *log_file*`,` *worker_number*`,` *exit_status*`]`
43
45
 
44
46
  `["stop"]`
45
47
  Stops all tests that are currently running and prints the given command line
data/lib/tork/client.rb CHANGED
@@ -1,34 +1,50 @@
1
1
  require 'thread'
2
+ require 'json'
2
3
 
3
4
  module Tork
4
5
  module Client
5
6
 
6
- class Receiver < Thread
7
- def initialize *popen_args
8
- (@io = IO.popen(*popen_args)).sync = true
9
- super() { loop { yield @io.gets } }
7
+ class Transmitter < Thread
8
+ def initialize output_stream
9
+ output_stream.sync = true
10
+ @outbox = Queue.new
11
+ super() do
12
+ while command = @outbox.deq
13
+ warn "#{$0}(#{$$}): SEND #{command.inspect}" if $DEBUG
14
+ output_stream.puts JSON.dump(command)
15
+ end
16
+ end
10
17
  end
11
18
 
12
- def quit
13
- kill # stop receive loop
14
- Process.kill :SIGTERM, @io.pid
15
- Process.wait @io.pid # reap zombie
16
- @io.close # prevent further I/O
19
+ def send command
20
+ @outbox.enq command
21
+ end
22
+ end
23
+
24
+ class Receiver < Thread
25
+ def initialize input_stream
26
+ super() do
27
+ while command = JSON.load(input_stream.gets)
28
+ warn "#{$0}(#{$$}): RECV #{command.inspect}" if $DEBUG
29
+ yield command
30
+ end
31
+ end
17
32
  end
18
33
  end
19
34
 
20
- class Transceiver < Receiver
21
- def initialize *popen_args
22
- @io_write_lock = Mutex.new
35
+ class Transceiver < Transmitter
36
+ def initialize *popen_args, &receive_block
23
37
  popen_args[1] = 'w+'
24
- super
38
+ @popen_io = IO.popen(*popen_args)
39
+ @receiver = Receiver.new(@popen_io, &receive_block)
40
+ super @popen_io
25
41
  end
26
42
 
27
- def send command
28
- @io_write_lock.synchronize do
29
- warn "#{caller[2]} SEND #{command.inspect}" if $DEBUG
30
- @io.puts JSON.dump(command)
31
- end
43
+ def quit
44
+ kill # stop receive loop
45
+ Process.kill :SIGTERM, @popen_io.pid
46
+ Process.wait @popen_io.pid # reap zombie
47
+ @popen_io.close # prevent further I/O
32
48
  end
33
49
  end
34
50
 
data/lib/tork/config.rb CHANGED
@@ -42,7 +42,7 @@ module Tork
42
42
  Config.after_fork_hooks = [
43
43
  # instruct the testing framework to only run those
44
44
  # tests that are defined on the given line numbers
45
- lambda do |worker_number, log_file, test_file, line_numbers|
45
+ lambda do |test_file, line_numbers, log_file, worker_number|
46
46
  case File.basename(test_file)
47
47
  when /(\b|_)spec(\b|_).*\.rb$/ # RSpec
48
48
  line_numbers.each {|line| ARGV.push '--line_number', line.to_s }
@@ -81,6 +81,7 @@ module Tork
81
81
  load _user_config_file if File.exist? _user_config_file
82
82
 
83
83
  if ENV.key? 'TORK_CONFIGS'
84
+ require 'json'
84
85
  JSON.load(ENV['TORK_CONFIGS']).each do |config|
85
86
  if File.exist? config
86
87
  load File.expand_path(config)
@@ -12,7 +12,9 @@ Tork::Config.test_file_globbers.update(
12
12
  %r<^features/.+\.feature$> => lambda {|path, matches| path }
13
13
  )
14
14
 
15
- Tork::Config.after_fork_hooks << lambda do |worker_number, log_file, test_file, line_numbers|
15
+ Tork::Config.after_fork_hooks.push lambda {
16
+ |test_file, line_numbers, log_file, worker_number|
17
+
16
18
  # pass test_file in ARGV to cucumber(1) for running
17
19
  ARGV << [test_file, *line_numbers].join(':')
18
20
  require 'cucumber'
@@ -24,4 +26,4 @@ Tork::Config.after_fork_hooks << lambda do |worker_number, log_file, test_file,
24
26
  # because cucumber feature files are not Ruby scripts
25
27
  require 'tempfile'
26
28
  test_file.replace Tempfile.new('tork-cucumber').path
27
- end
29
+ }
@@ -0,0 +1,8 @@
1
+ require 'tork/config'
2
+
3
+ Tork::Config.before_fork_hooks.unshift lambda {
4
+ |test_file, line_numbers, log_file, worker_number|
5
+
6
+ dirname, basename = File.split(log_file)
7
+ log_file.replace File.join(dirname, '.' + basename)
8
+ }
@@ -0,0 +1,10 @@
1
+ require 'tork/config'
2
+ require 'fileutils'
3
+
4
+ Tork::Config.before_fork_hooks.unshift lambda {
5
+ |test_file, line_numbers, log_file, worker_number|
6
+
7
+ dirname, basename = File.split(log_file)
8
+ FileUtils.mkdir_p log_dir = File.join('log', dirname)
9
+ log_file.replace File.join(log_dir, basename)
10
+ }
@@ -1,7 +1,9 @@
1
1
  require 'tork/config'
2
2
 
3
- Tork::Config.after_fork_hooks << proc do |worker_number|
3
+ Tork::Config.after_fork_hooks.push lambda {
4
+ |test_file, line_numbers, log_file, worker_number|
5
+
4
6
  # for compatitibilty with parallel_tests gem,
5
7
  # store numbers as strings: "", "2", "3", "4"
6
8
  ENV['TEST_ENV_NUMBER'] = (worker_number + 1).to_s if worker_number > 0
7
- end
9
+ }
data/lib/tork/driver.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'json'
2
1
  require 'diff/lcs'
3
2
  require 'tork/client'
4
3
  require 'tork/server'
@@ -30,8 +29,8 @@ module Driver
30
29
  def reabsorb_overhead_files
31
30
  @master.quit if defined? @master
32
31
 
33
- @master = Client::Transceiver.new('tork-master') do |line|
34
- event, file, tests = JSON.load(line)
32
+ @master = Client::Transceiver.new('tork-master') do |message|
33
+ event, file, tests = message
35
34
 
36
35
  case event.to_sym
37
36
  when :test
@@ -51,7 +50,7 @@ module Driver
51
50
  @failed_test_files.push file unless @failed_test_files.include? file
52
51
  end
53
52
 
54
- @client.print line
53
+ @client.send message
55
54
  end
56
55
 
57
56
  @master.send [:load, Config.overhead_load_paths,
@@ -63,22 +62,24 @@ module Driver
63
62
  def loop
64
63
  reabsorb_overhead_files
65
64
 
66
- @herald = Client::Receiver.new('tork-herald') do |line|
67
- changed_file = line.chomp
68
- warn "tork-driver: herald: #{changed_file}" if $DEBUG
65
+ @herald = Client::Transceiver.new('tork-herald') do |changed_files|
66
+ warn "#{$0}(#{$$}): FILE BATCH #{changed_files.size}" if $DEBUG
67
+ changed_files.each do |changed_file|
68
+ warn "#{$0}(#{$$}): FILE #{changed_file}" if $DEBUG
69
69
 
70
- # find and run the tests that correspond to the changed file
71
- Config.test_file_globbers.each do |regexp, globber|
72
- if regexp =~ changed_file and glob = globber.call(changed_file, $~)
73
- run_test_files Dir[glob]
70
+ # find and run the tests that correspond to the changed file
71
+ Config.test_file_globbers.each do |regexp, globber|
72
+ if regexp =~ changed_file and glob = globber.call(changed_file, $~)
73
+ run_test_files Dir[glob]
74
+ end
74
75
  end
75
- end
76
76
 
77
- # reabsorb text execution overhead if overhead files changed
78
- if Config.reabsorb_file_greps.any? {|r| r =~ changed_file }
79
- @client.puts JSON.dump([:over, changed_file])
80
- # NOTE: new thread because reabsorb_overhead_files will kill this one
81
- Thread.new { reabsorb_overhead_files }.join
77
+ # reabsorb text execution overhead if overhead files changed
78
+ if Config.reabsorb_file_greps.any? {|r| r =~ changed_file }
79
+ @client.send [:over, changed_file]
80
+ # NOTE: new thread because reabsorb_overhead_files will kill this one
81
+ Thread.new { reabsorb_overhead_files }.join
82
+ end
82
83
  end
83
84
  end
84
85
 
data/lib/tork/master.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'json'
2
1
  require 'tork/server'
3
2
  require 'tork/config'
4
3
 
@@ -17,7 +16,7 @@ module Master
17
16
  require file.sub(/\.rb$/, '')
18
17
  end
19
18
 
20
- @client.print @command_line
19
+ @client.send @command
21
20
  end
22
21
 
23
22
  def test test_file, line_numbers
@@ -28,7 +27,7 @@ module Master
28
27
  worker_number = @worker_number_pool.shift
29
28
 
30
29
  Config.before_fork_hooks.each do |hook|
31
- hook.call worker_number, log_file, test_file, line_numbers
30
+ hook.call test_file, line_numbers, log_file, worker_number
32
31
  end
33
32
 
34
33
  worker_pid = fork do
@@ -46,7 +45,7 @@ module Master
46
45
  STDERR.reopen(STDOUT.reopen(log_file, 'w')).sync = true
47
46
 
48
47
  Config.after_fork_hooks.each do |hook|
49
- hook.call worker_number, log_file, test_file, line_numbers
48
+ hook.call test_file, line_numbers, log_file, worker_number
50
49
  end
51
50
 
52
51
  # after loading the user's test file, the at_exit() hook of the user's
@@ -56,8 +55,8 @@ module Master
56
55
  Kernel.load test_file
57
56
  end
58
57
 
59
- @command_by_worker_pid[worker_pid] = @command.push(worker_number)
60
- @client.print @command_line
58
+ @command_by_worker_pid[worker_pid] = @command.push(log_file, worker_number)
59
+ @client.send @command
61
60
  end
62
61
 
63
62
  def stop
@@ -83,9 +82,9 @@ private
83
82
  while wait2_array = Process.wait2(-1, Process::WNOHANG)
84
83
  child_pid, child_status = wait2_array
85
84
  if command = @command_by_worker_pid.delete(child_pid)
86
- @worker_number_pool.push command.pop
87
- command[0] = child_status.success? ? 'pass' : 'fail'
88
- @client.puts JSON.dump(command.push(child_status))
85
+ @worker_number_pool.push command.last
86
+ command[0] = if child_status.success? then :pass else :fail end
87
+ @client.send command.push(child_status)
89
88
  else
90
89
  warn "tork-master: unknown child exited: #{wait2_array.inspect}"
91
90
  end
data/lib/tork/server.rb CHANGED
@@ -1,31 +1,25 @@
1
- require 'json'
1
+ require 'tork/client'
2
2
 
3
3
  module Tork
4
4
  module Server
5
5
 
6
6
  def quit
7
- throw :tork_server_quit
7
+ Thread.exit # kill Client::Receiver in loop()
8
8
  end
9
9
 
10
10
  def loop
11
- (@client = STDOUT.dup).sync = true
11
+ @client = Client::Transmitter.new(STDOUT.dup)
12
12
  STDOUT.reopen(STDERR).sync = true
13
13
 
14
- catch :tork_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
14
+ Client::Receiver.new(STDIN) do |command|
15
+ method = command.first
16
+ if respond_to? method and method != __method__ # prevent loops
17
+ @command = command
18
+ __send__(*command)
19
+ else
20
+ warn "#{self}: invalid command: #{method}"
27
21
  end
28
- end
22
+ end.join
29
23
  rescue Interrupt
30
24
  # forced quit
31
25
  end
data/lib/tork/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Tork
2
- VERSION = "16.0.0"
2
+ VERSION = "17.0.0"
3
3
  end
@@ -1,4 +1,4 @@
1
- .TH TORK\-DRIVER 1 2012\-01\-25 16.0.0
1
+ .TH TORK\-DRIVER 1 2012\-01\-27 17.0.0
2
2
  .SH NAME
3
3
  .PP
4
4
  tork\-driver \- drives
@@ -1,4 +1,4 @@
1
- .TH TORK\-HERALD 1 2012\-01\-25 16.0.0
1
+ .TH TORK\-HERALD 1 2012\-01\-27 17.0.0
2
2
  .SH NAME
3
3
  .PP
4
4
  tork\-herald \- reports modified files
@@ -8,7 +8,8 @@ tork\-herald \- reports modified files
8
8
  .SH DESCRIPTION
9
9
  .PP
10
10
  This program monitors the current working directory and prints relative paths
11
- of modified files, one per line, to the standard output stream.
11
+ of modified files in batches of single\-line JSON arrays to the standard output
12
+ stream.
12
13
  .SH OPTIONS
13
14
  .TP
14
15
  \fB\fC-h\fR, \fB\fC--help\fR
@@ -1,4 +1,4 @@
1
- .TH TORK\-MASTER 1 2012\-01\-25 16.0.0
1
+ .TH TORK\-MASTER 1 2012\-01\-27 17.0.0
2
2
  .SH NAME
3
3
  .PP
4
4
  tork\-master \- absorbs overhead and runs tests
@@ -20,16 +20,20 @@ Runs the given \fItest_file\fP in a forked child process while instructing your
20
20
  chosen unit testing framework (loaded by your test execution overhead) to
21
21
  only run those tests that are defined on the given array of \fIline_numbers\fP.
22
22
  .IP
23
- Prints the given command line to the standard output stream immediately
24
- after forking the child process.
25
- .IP
26
- Prints the given command line, modified with \fB\fC"pass"\fR (if the test passed)
27
- or \fB\fC"fail"\fR (if the test failed) in place of \fB\fC"test"\fR, to the standard
28
- output stream after the forked child process finishes.
29
- .IP
30
- The standard output and error streams of the forked child process are
31
- redirected to a file whose path and name are the same as that of the test
32
- file being run by the forked child process but with ".log" appended.
23
+ Prints the following status messages to the standard output stream. The
24
+ standard output and error streams of the forked child process are captured
25
+ in the \fIlog_file\fP specified in these status messages.
26
+ .RS
27
+ .IP \(bu 2
28
+ Test is running:
29
+ \fB\fC["test",\fR \fItest_file\fP\fB\fC,\fR \fIline_numbers\fP\fB\fC,\fR \fIlog_file\fP\fB\fC,\fR \fIworker_number\fP\fB\fC]\fR
30
+ .IP \(bu 2
31
+ Test has passed:
32
+ \fB\fC["pass",\fR \fItest_file\fP\fB\fC,\fR \fIline_numbers\fP\fB\fC,\fR \fIlog_file\fP\fB\fC,\fR \fIworker_number\fP\fB\fC,\fR \fIexit_status\fP\fB\fC]\fR
33
+ .IP \(bu 2
34
+ Test has failed:
35
+ \fB\fC["fail",\fR \fItest_file\fP\fB\fC,\fR \fIline_numbers\fP\fB\fC,\fR \fIlog_file\fP\fB\fC,\fR \fIworker_number\fP\fB\fC,\fR \fIexit_status\fP\fB\fC]\fR
36
+ .RE
33
37
  .TP
34
38
  \fB\fC["stop"]\fR
35
39
  Stops all tests that are currently running and prints the given command line
data/man/man1/tork.1 CHANGED
@@ -1,4 +1,4 @@
1
- .TH TORK 1 2012\-01\-25 16.0.0
1
+ .TH TORK 1 2012\-01\-27 17.0.0
2
2
  .SH NAME
3
3
  .PP
4
4
  tork \- Continuous testing tool for Ruby
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tork
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.0.0
4
+ version: 17.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-01-26 00:00:00.000000000 Z
13
+ date: 2012-01-27 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: binman
17
- requirement: &15804480 !ruby/object:Gem::Requirement
17
+ requirement: &17780080 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '3'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *15804480
25
+ version_requirements: *17780080
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: json
28
- requirement: &15803820 !ruby/object:Gem::Requirement
28
+ requirement: &17779540 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -36,10 +36,10 @@ dependencies:
36
36
  version: '2'
37
37
  type: :runtime
38
38
  prerelease: false
39
- version_requirements: *15803820
39
+ version_requirements: *17779540
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: guard
42
- requirement: &15818660 !ruby/object:Gem::Requirement
42
+ requirement: &17778800 !ruby/object:Gem::Requirement
43
43
  none: false
44
44
  requirements:
45
45
  - - ! '>='
@@ -50,10 +50,10 @@ dependencies:
50
50
  version: '1'
51
51
  type: :runtime
52
52
  prerelease: false
53
- version_requirements: *15818660
53
+ version_requirements: *17778800
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: diff-lcs
56
- requirement: &15816880 !ruby/object:Gem::Requirement
56
+ requirement: &17778060 !ruby/object:Gem::Requirement
57
57
  none: false
58
58
  requirements:
59
59
  - - ! '>='
@@ -64,10 +64,10 @@ dependencies:
64
64
  version: '2'
65
65
  type: :runtime
66
66
  prerelease: false
67
- version_requirements: *15816880
67
+ version_requirements: *17778060
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: md2man
70
- requirement: &15815560 !ruby/object:Gem::Requirement
70
+ requirement: &17777300 !ruby/object:Gem::Requirement
71
71
  none: false
72
72
  requirements:
73
73
  - - ~>
@@ -75,10 +75,10 @@ dependencies:
75
75
  version: '1'
76
76
  type: :development
77
77
  prerelease: false
78
- version_requirements: *15815560
78
+ version_requirements: *17777300
79
79
  - !ruby/object:Gem::Dependency
80
80
  name: rake
81
- requirement: &15814800 !ruby/object:Gem::Requirement
81
+ requirement: &17776800 !ruby/object:Gem::Requirement
82
82
  none: false
83
83
  requirements:
84
84
  - - ! '>='
@@ -89,7 +89,7 @@ dependencies:
89
89
  version: '1'
90
90
  type: :development
91
91
  prerelease: false
92
- version_requirements: *15814800
92
+ version_requirements: *17776800
93
93
  description: Continuous testing tool for Ruby.
94
94
  email:
95
95
  - sunaku@gmail.com
@@ -115,6 +115,8 @@ files:
115
115
  - lib/tork/client.rb
116
116
  - lib/tork/config.rb
117
117
  - lib/tork/config/cucumber.rb
118
+ - lib/tork/config/dotlog.rb
119
+ - lib/tork/config/logdir.rb
118
120
  - lib/tork/config/parallel_tests.rb
119
121
  - lib/tork/config/rails.rb
120
122
  - lib/tork/driver.rb
@@ -138,18 +140,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
140
  - - ! '>='
139
141
  - !ruby/object:Gem::Version
140
142
  version: '0'
141
- segments:
142
- - 0
143
- hash: 1234155726209121791
144
143
  required_rubygems_version: !ruby/object:Gem::Requirement
145
144
  none: false
146
145
  requirements:
147
146
  - - ! '>='
148
147
  - !ruby/object:Gem::Version
149
148
  version: '0'
150
- segments:
151
- - 0
152
- hash: 1234155726209121791
153
149
  requirements: []
154
150
  rubyforge_project:
155
151
  rubygems_version: 1.8.11
@@ -157,3 +153,4 @@ signing_key:
157
153
  specification_version: 3
158
154
  summary: Test with fork.
159
155
  test_files: []
156
+ has_rdoc: