test-loop 12.0.0 → 12.0.1
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/README.md +34 -24
- data/lib/test/loop.rb +23 -25
- metadata +2 -2
data/README.md
CHANGED
@@ -4,39 +4,49 @@ test-loop - Continuous testing for Ruby with fork/eval
|
|
4
4
|
test-loop is a fast continuous testing tool for Ruby that automatically
|
5
5
|
detects and tests changes in your application in an efficient manner:
|
6
6
|
|
7
|
-
1. Absorbs the test execution overhead into the main Ruby process.
|
8
|
-
|
9
|
-
|
7
|
+
1. Absorbs the test execution overhead into the main Ruby process.
|
8
|
+
|
9
|
+
2. Forks to run your test files without overhead and in parallel.
|
10
|
+
|
11
|
+
3. Avoids running unchanged test blocks inside changed test files.
|
10
12
|
|
11
13
|
------------------------------------------------------------------------------
|
12
14
|
Features
|
13
15
|
------------------------------------------------------------------------------
|
14
16
|
|
15
|
-
* Tests *changes* in your Ruby application: avoids running (1) unchanged
|
16
|
-
|
17
|
+
* Tests *changes* in your Ruby application: avoids running (1) unchanged
|
18
|
+
test files and (2) unchanged test blocks inside changed test files.
|
17
19
|
|
18
|
-
* Supports Test::Unit, RSpec, and any other testing framework that (1)
|
19
|
-
|
20
|
-
|
20
|
+
* Supports Test::Unit, RSpec, and any other testing framework that (1)
|
21
|
+
reflects failures in the process' exit status and (2) is loaded by your
|
22
|
+
application's `test/test_helper.rb` or `spec/spec_helper.rb` file.
|
21
23
|
|
22
|
-
* Reabsorbs test execution overhead if the test or spec helper file changes.
|
24
|
+
* Reabsorbs test execution overhead if the test or spec helper file changes.
|
23
25
|
|
24
|
-
* Executes test files in parallel, making full use of multiple processors.
|
26
|
+
* Executes test files in parallel, making full use of multiple processors.
|
25
27
|
|
26
|
-
* Logs the output from your tests into separate files: one log per test
|
27
|
-
|
28
|
+
* Logs the output from your tests into separate files: one log per test.
|
29
|
+
The path to a log file is simply the path of its test file plus ".log".
|
28
30
|
|
29
|
-
* Generally I/O bound, so you can
|
31
|
+
* Generally I/O bound, so you can keep it running without CPU slowdown.
|
30
32
|
|
31
|
-
* Configurable through a `.test-loop` file in your
|
33
|
+
* Configurable through a `.test-loop` file in your working directory.
|
32
34
|
|
33
|
-
* Implemented in less than
|
35
|
+
* Implemented in less than 220 lines (SLOC) of pure Ruby code! :-)
|
34
36
|
|
35
37
|
------------------------------------------------------------------------------
|
36
38
|
Prerequisites
|
37
39
|
------------------------------------------------------------------------------
|
38
40
|
|
39
|
-
*
|
41
|
+
* Ruby 1.8.7 or 1.9.2 or newer.
|
42
|
+
|
43
|
+
* Operating system that supports POSIX signals and the `fork()` system call.
|
44
|
+
|
45
|
+
To check if your system qualifies, launch `irb` and enter the following:
|
46
|
+
|
47
|
+
Process.respond_to? :fork # must be true
|
48
|
+
|
49
|
+
Signal.list.keys & %w[INT TSTP QUIT TERM CHLD] # must not be empty
|
40
50
|
|
41
51
|
------------------------------------------------------------------------------
|
42
52
|
Installation
|
@@ -65,7 +75,7 @@ If installed as a Git clone:
|
|
65
75
|
|
66
76
|
You can monitor your test processes in another terminal:
|
67
77
|
|
68
|
-
watch 'ps xf |
|
78
|
+
watch 'ps xf | fgrep test-loop | fgrep -v fgrep'
|
69
79
|
|
70
80
|
If it stops responding, you can annihilate test-loop from another terminal:
|
71
81
|
|
@@ -75,13 +85,13 @@ If it stops responding, you can annihilate test-loop from another terminal:
|
|
75
85
|
Operation
|
76
86
|
------------------------------------------------------------------------------
|
77
87
|
|
78
|
-
* Press Control-Z or send the SIGTSTP signal to forcibly run all
|
79
|
-
|
88
|
+
* Press Control-Z or send the SIGTSTP signal to forcibly run all
|
89
|
+
tests, even if there are no changes in your Ruby application.
|
80
90
|
|
81
|
-
* Press Control-\ or send the SIGQUIT signal to forcibly reabsorb
|
82
|
-
|
91
|
+
* Press Control-\ or send the SIGQUIT signal to forcibly reabsorb
|
92
|
+
the test execution overhead, even if its sources have not changed.
|
83
93
|
|
84
|
-
* Press Control-C or send the SIGINT signal to quit the test loop.
|
94
|
+
* Press Control-C or send the SIGINT signal to quit the test loop.
|
85
95
|
|
86
96
|
------------------------------------------------------------------------------
|
87
97
|
Configuration
|
@@ -112,8 +122,8 @@ hash key; left-hand side of the mapping) change, their associated test files
|
|
112
122
|
For example, if test files had the same names as their source files followed
|
113
123
|
by an underscore and the file name in reverse like this:
|
114
124
|
|
115
|
-
* `lib/hello.rb` => `test/hello_olleh.rb`
|
116
|
-
* `app/world.rb` => `spec/world_ldrow.rb`
|
125
|
+
* `lib/hello.rb` => `test/hello_olleh.rb`
|
126
|
+
* `app/world.rb` => `spec/world_ldrow.rb`
|
117
127
|
|
118
128
|
Then you would add the following to your configuration file:
|
119
129
|
|
data/lib/test/loop.rb
CHANGED
@@ -70,9 +70,9 @@ module Test
|
|
70
70
|
|
71
71
|
private
|
72
72
|
|
73
|
-
|
73
|
+
MASTER_EXECV = [$0, *ARGV].map {|s| s.dup.freeze }.freeze
|
74
|
+
MASTER_ENV = Hash[ENV.map {|k,v| [k.freeze, v.freeze] }].freeze
|
74
75
|
RESUME_ENV_KEY = 'TEST_LOOP_RESUME_FILES'.freeze
|
75
|
-
MASTER_ENV = ENV.to_hash.delete_if {|k,v| k == RESUME_ENV_KEY }.freeze
|
76
76
|
|
77
77
|
ANSI_CLEAR_LINE = "\e[2K\e[0G".freeze
|
78
78
|
ANSI_GREEN = "\e[32m%s\e[0m".freeze
|
@@ -97,7 +97,7 @@ module Test
|
|
97
97
|
def register_signals
|
98
98
|
# this signal is ignored in master and honored in workers, so all
|
99
99
|
# workers can be killed by sending it to the entire process group
|
100
|
-
trap :TERM,
|
100
|
+
trap :TERM, 'IGNORE'
|
101
101
|
|
102
102
|
trap :CHLD do
|
103
103
|
finished_at = Time.now
|
@@ -106,24 +106,22 @@ module Test
|
|
106
106
|
worker_pid = Process.wait
|
107
107
|
run_status = $?
|
108
108
|
|
109
|
-
worker = @worker_by_pid.delete(worker_pid)
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
109
|
+
if worker = @worker_by_pid.delete(worker_pid)
|
110
|
+
@running_files.delete worker.test_file
|
111
|
+
|
112
|
+
# report test results along with any failure logs
|
113
|
+
if run_status.success?
|
114
|
+
notify ANSI_GREEN % "PASS #{worker.test_file}"
|
115
|
+
elsif run_status.exited?
|
116
|
+
notify ANSI_RED % "FAIL #{worker.test_file}"
|
117
|
+
STDERR.print File.read(worker.log_file)
|
118
|
+
end
|
119
|
+
|
120
|
+
after_each_test.each do |hook|
|
121
|
+
hook.call worker.test_file, worker.log_file, run_status,
|
122
|
+
worker.started_at, finished_at - worker.started_at
|
123
|
+
end
|
123
124
|
end
|
124
|
-
|
125
|
-
@running_files.delete worker.test_file
|
126
|
-
|
127
125
|
rescue Errno::ECHILD
|
128
126
|
# could not get the terminated child's PID.
|
129
127
|
# Ruby's backtick operator can cause this:
|
@@ -132,8 +130,8 @@ module Test
|
|
132
130
|
end
|
133
131
|
|
134
132
|
trap(:INT) { raise Interrupt }
|
135
|
-
trap(:QUIT) { reload_master_process }
|
136
133
|
trap(:TSTP) { forcibly_run_all_tests }
|
134
|
+
trap(:QUIT) { reload_master_process }
|
137
135
|
end
|
138
136
|
|
139
137
|
def kill_workers
|
@@ -147,8 +145,8 @@ module Test
|
|
147
145
|
def reload_master_process test_files = []
|
148
146
|
test_files.concat @running_files
|
149
147
|
kill_workers
|
150
|
-
|
151
|
-
|
148
|
+
ENV.replace MASTER_ENV.merge(RESUME_ENV_KEY => test_files.inspect)
|
149
|
+
exec(*MASTER_EXECV)
|
152
150
|
end
|
153
151
|
|
154
152
|
def load_user_config
|
@@ -226,10 +224,10 @@ module Test
|
|
226
224
|
started_at = Time.now
|
227
225
|
worker_pid = fork do
|
228
226
|
# handle signals meant for worker process
|
229
|
-
[:TERM, :CHLD].each {|sig| trap sig,
|
227
|
+
[:TERM, :CHLD].each {|sig| trap sig, 'DEFAULT' }
|
230
228
|
|
231
229
|
# ignore signals meant for master process
|
232
|
-
[:INT, :
|
230
|
+
[:INT, :TSTP, :QUIT].each {|sig| trap sig, 'IGNORE' }
|
233
231
|
|
234
232
|
# detach worker from master's terminal device so that
|
235
233
|
# it does not receieve the user's control-key presses
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: test-loop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 12.0.
|
5
|
+
version: 12.0.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Suraj N. Kurapati
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-04-
|
14
|
+
date: 2011-04-20 00:00:00 -07:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|