tork 16.0.0 → 17.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 +46 -0
- data/LICENSE +1 -0
- data/README.markdown +133 -100
- data/bin/tork +9 -11
- data/bin/tork-driver +1 -1
- data/bin/tork-herald +5 -3
- data/bin/tork-master +11 -9
- data/lib/tork/client.rb +34 -18
- data/lib/tork/config.rb +2 -1
- data/lib/tork/config/cucumber.rb +4 -2
- data/lib/tork/config/dotlog.rb +8 -0
- data/lib/tork/config/logdir.rb +10 -0
- data/lib/tork/config/parallel_tests.rb +4 -2
- data/lib/tork/driver.rb +18 -17
- data/lib/tork/master.rb +8 -9
- data/lib/tork/server.rb +11 -17
- data/lib/tork/version.rb +1 -1
- data/man/man1/tork-driver.1 +1 -1
- data/man/man1/tork-herald.1 +3 -2
- data/man/man1/tork-master.1 +15 -11
- data/man/man1/tork.1 +1 -1
- metadata +17 -20
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
|
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
|
-
|
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
|
-
###
|
86
|
+
### Development
|
87
87
|
|
88
|
-
|
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
|
-
|
94
|
+
------------------------------------------------------------------------------
|
95
|
+
Usage
|
96
|
+
------------------------------------------------------------------------------
|
97
|
+
|
98
|
+
### At the command line
|
91
99
|
|
92
100
|
tork --help
|
93
101
|
|
94
|
-
|
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
|
-
###
|
106
|
+
### With [Ruby on Rails]
|
99
107
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
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
|
112
|
-
can query and modify the `Tork::Config` object
|
113
|
-
|
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
|
185
|
-
|
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
|
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
|
-
|
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
|
210
|
-
|
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
|
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
|
-
|
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-
|
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 |
|
55
|
-
|
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,
|
63
|
-
message = [
|
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
|
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(
|
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.
|
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
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-
|
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
|
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-
|
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
|
34
|
-
|
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
|
-
|
37
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
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
|
7
|
-
def initialize
|
8
|
-
|
9
|
-
|
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
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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 <
|
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
|
-
|
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
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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 |
|
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)
|
data/lib/tork/config/cucumber.rb
CHANGED
@@ -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
|
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
|
-
|
29
|
+
}
|
@@ -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
|
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
|
-
|
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 |
|
34
|
-
event, file, tests =
|
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.
|
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::
|
67
|
-
|
68
|
-
|
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
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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.
|
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
|
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
|
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.
|
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.
|
87
|
-
command[0] = child_status.success?
|
88
|
-
@client.
|
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 '
|
1
|
+
require 'tork/client'
|
2
2
|
|
3
3
|
module Tork
|
4
4
|
module Server
|
5
5
|
|
6
6
|
def quit
|
7
|
-
|
7
|
+
Thread.exit # kill Client::Receiver in loop()
|
8
8
|
end
|
9
9
|
|
10
10
|
def loop
|
11
|
-
|
11
|
+
@client = Client::Transmitter.new(STDOUT.dup)
|
12
12
|
STDOUT.reopen(STDERR).sync = true
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
command
|
19
|
-
|
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
data/man/man1/tork-driver.1
CHANGED
data/man/man1/tork-herald.1
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
.TH TORK\-HERALD 1 2012\-01\-
|
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
|
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
|
data/man/man1/tork-master.1
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
.TH TORK\-MASTER 1 2012\-01\-
|
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
|
24
|
-
|
25
|
-
.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
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:
|
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-
|
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: &
|
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: *
|
25
|
+
version_requirements: *17780080
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: json
|
28
|
-
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: *
|
39
|
+
version_requirements: *17779540
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: guard
|
42
|
-
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: *
|
53
|
+
version_requirements: *17778800
|
54
54
|
- !ruby/object:Gem::Dependency
|
55
55
|
name: diff-lcs
|
56
|
-
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: *
|
67
|
+
version_requirements: *17778060
|
68
68
|
- !ruby/object:Gem::Dependency
|
69
69
|
name: md2man
|
70
|
-
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: *
|
78
|
+
version_requirements: *17777300
|
79
79
|
- !ruby/object:Gem::Dependency
|
80
80
|
name: rake
|
81
|
-
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: *
|
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:
|