test-loop 12.3.1 → 13.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -4,6 +4,7 @@ Copyright 2010 Suraj N. Kurapati <sunaku@gmail.com>
4
4
  Copyright 2011 Brian D. Burns <burns180@gmail.com>
5
5
  Copyright 2011 Daniel Pittman <daniel@rimspace.net>
6
6
  Copyright 2011 Jacob Helwig <jacob@technosorcery.net>
7
+ Copyright 2011 Corné Verbruggen <corne@g-majeur.nl>
7
8
 
8
9
  Permission to use, copy, modify, and/or distribute this software for any
9
10
  purpose with or without fee is hereby granted, provided that the above
data/README.md CHANGED
@@ -100,7 +100,34 @@ Configuration
100
100
 
101
101
  test-loop looks for a configuration file named `.test-loop` in the current
102
102
  working directory. This configuration file is a normal Ruby script in which
103
- you can query and modify the `Test::Loop` OpenStruct configuration as follows:
103
+ you can query and modify the `Test::Loop` OpenStruct configuration object
104
+ according to the configuration options listed below.
105
+
106
+ ------------------------------------------------------------------------------
107
+ Configuration presets
108
+ ------------------------------------------------------------------------------
109
+
110
+ The following sub-libraries provide "preset" configurations. To use them,
111
+ simply add the require() lines shown below to your `.test-loop` file or to
112
+ your application's `test/test_helper.rb` or `spec/spec_helper.rb` file.
113
+
114
+ ### require 'test/loop/notify'
115
+
116
+ Shows on-screen-display notifications for test failures.
117
+
118
+ ### require 'test/loop/rails'
119
+
120
+ Provides support for the Ruby on Rails web framework.
121
+
122
+ ### require 'test-loop/coco'
123
+
124
+ Integrates the [coco](https://github.com/lkdjiin/coco) code coverage library.
125
+
126
+ ------------------------------------------------------------------------------
127
+ Configuration options
128
+ ------------------------------------------------------------------------------
129
+
130
+ The `Test::Loop` OpenStruct configuration object holds the following options:
104
131
 
105
132
  ### Test::Loop.delay_per_iteration
106
133
 
@@ -133,9 +160,8 @@ by an underscore and the file name in reverse like this:
133
160
  Then you would add the following to your configuration file:
134
161
 
135
162
  Test::Loop.test_file_matchers['{lib,app}/**/*.rb'] = lambda do |path|
136
- extn = File.extname(path)
137
- name = File.basename(path, extn)
138
- "{test,spec}/**/#{name}_#{name.reverse}#{extn}"
163
+ name = File.basename(path, '.rb')
164
+ "{test,spec}/**/#{name}_#{name.reverse}.rb"
139
165
  end
140
166
 
141
167
  In addition, these lambda functions can return `nil` if they do not wish for a
@@ -162,18 +188,20 @@ name of the test being defined.
162
188
  Array of lambda functions that are executed inside the worker process before
163
189
  loading the test file.
164
190
 
165
- These functions are passed (1) the path to the test file, (2) the path to
166
- the log file containing the live output of running the test file, and (3) an
167
- array containing the names of tests (which were identified by
191
+ These functions are passed (1) the path to the test file, (2) the path to the
192
+ log file containing the live output of running the test file, (3) an array
193
+ containing the names of tests (which were identified by
168
194
  `Test::Loop.test_name_parser`) inside the test file that have changed since
169
- the last run of the test file.
195
+ the last run of the test file, and (4) a rotating sequence number of the
196
+ worker process that will run the test file.
170
197
 
171
198
  For example, to print a worker process' ID and what work it will perform:
172
199
 
173
200
  Test::Loop.before_each_test.push lambda {
174
- |test_file, log_file, test_names|
201
+ |test_file, log_file, test_names, worker_id|
175
202
 
176
203
  p :worker_pid => $$,
204
+ :worker_id => worker_id,
177
205
  :test_file => test_file,
178
206
  :log_file => log_file,
179
207
  :test_names => test_names
@@ -191,14 +219,15 @@ test has finished running.
191
219
  These functions are passed (1) the path to the test file, (2) the path to the
192
220
  log file containing the output of running the test file, (3) a
193
221
  `Process::Status` object describing the exit status of the worker process that
194
- ran the test file, (4) the time when test execution began, and (5) how many
195
- seconds it took for the overall test execution to complete.
222
+ ran the test file, (4) the time when test execution began, (5) how many
223
+ seconds it took for the overall test execution to complete, and (6) a rotating
224
+ sequence number of the worker process that ran the test file.
196
225
 
197
226
  For example, to delete log files for successful tests, add the following to
198
227
  your configuration file:
199
228
 
200
229
  Test::Loop.after_each_test.push lambda {
201
- |test_file, log_file, run_status, started_at, elapsed_time|
230
+ |test_file, log_file, run_status, started_at, elapsed_time, worker_id|
202
231
 
203
232
  File.delete(log_file) if run_status.success?
204
233
  }
@@ -208,7 +237,7 @@ add the following to your configuration file (**NOTE:** the `test/loop/notify`
208
237
  preset does this for you):
209
238
 
210
239
  Test::Loop.after_each_test.push lambda {
211
- |test_file, log_file, run_status, started_at, elapsed_time|
240
+ |test_file, log_file, run_status, started_at, elapsed_time, worker_id|
212
241
 
213
242
  unless run_status.success? or run_status.signaled?
214
243
  title = 'FAIL at %s in %0.1fs' % [started_at.strftime('%r'), elapsed_time]
@@ -229,7 +258,7 @@ regardless of whether they passed or failed, add the following to your
229
258
  configuration file:
230
259
 
231
260
  Test::Loop.after_each_test.push lambda {
232
- |test_file, log_file, run_status, started_at, elapsed_time|
261
+ |test_file, log_file, run_status, started_at, elapsed_time, worker_id|
233
262
 
234
263
  success = run_status.success?
235
264
 
@@ -250,26 +279,6 @@ configuration file:
250
279
 
251
280
  Maximum number of test files to run concurrently. The default value is 4.
252
281
 
253
- ------------------------------------------------------------------------------
254
- Configuration presets
255
- ------------------------------------------------------------------------------
256
-
257
- The following sub-libraries provide "preset" configurations. To use them,
258
- simply add the require() lines shown below to your `.test-loop` file or to
259
- your application's `test/test_helper.rb` or `spec/spec_helper.rb` file.
260
-
261
- ### require 'test/loop/notify'
262
-
263
- Shows on-screen-display notifications for test failures.
264
-
265
- ### require 'test/loop/rails'
266
-
267
- Provides support for the Ruby on Rails web framework.
268
-
269
- ### require 'test-loop/coco'
270
-
271
- Integrates the [coco](https://github.com/lkdjiin/coco) code coverage library.
272
-
273
282
  ------------------------------------------------------------------------------
274
283
  Known issues
275
284
  ------------------------------------------------------------------------------
data/lib/test/loop.rb CHANGED
@@ -17,9 +17,8 @@ module Test
17
17
  Loop.test_file_matchers = {
18
18
  # source files that correspond to test files
19
19
  'lib/**/*.rb' => lambda do |path|
20
- extn = File.extname(path)
21
- base = File.basename(path, extn)
22
- "{test,spec}/**/#{base}_{test,spec}#{extn}"
20
+ base = File.basename(path, '.rb')
21
+ "{test,spec}/**/#{base}_{test,spec}.rb"
23
22
  end,
24
23
 
25
24
  # the actual test files themselves
@@ -34,7 +33,7 @@ module Test
34
33
  end
35
34
 
36
35
  Loop.before_each_test = [
37
- lambda {|test_file, log_file, test_names|
36
+ lambda {|test_file, log_file, test_names, worker_id|
38
37
  unless test_names.empty?
39
38
  test_name_pattern = test_names.map do |name|
40
39
  # sanitize string interpolations and invalid method name characters
@@ -86,7 +85,7 @@ module Test
86
85
  ANSI_RED = "\e[31m%s\e[0m".freeze
87
86
 
88
87
  Worker = Struct.new(:test_file, :log_file, :started_at, :finished_at,
89
- :exit_status)
88
+ :exit_status, :id)
90
89
 
91
90
  def notify message
92
91
  # using print() because puts() is not an atomic operation.
@@ -122,9 +121,8 @@ module Test
122
121
  def reload_master_process test_files = Set.new
123
122
  test_files.merge currently_running_test_files
124
123
  stop_worker_queue
125
- ENV.replace MASTER_ENV.merge(RESUME_ENV_KEY =>
126
- Base64.encode64(Marshal.dump(test_files)))
127
- exec(*MASTER_EXECV)
124
+ resume_env = Base64.encode64(Marshal.dump(test_files))
125
+ exec MASTER_ENV.merge(RESUME_ENV_KEY => resume_env), *MASTER_EXECV
128
126
  end
129
127
 
130
128
  def load_user_config
@@ -195,6 +193,8 @@ module Test
195
193
  end
196
194
 
197
195
  def init_worker_queue
196
+ @worker_id_pool = (0 ... max_concurrent_tests).to_a
197
+
198
198
  # collect children (of which some may be workers) for reaping below
199
199
  @exited_child_infos = []
200
200
  trap :CHLD do
@@ -237,6 +237,7 @@ module Test
237
237
  def fork_worker worker
238
238
  notify "TEST #{worker.test_file}"
239
239
 
240
+ worker.id = @worker_id_pool.shift
240
241
  worker.log_file = worker.test_file + '.log'
241
242
 
242
243
  # cache the contents of the test file for diffing below
@@ -275,7 +276,7 @@ module Test
275
276
 
276
277
  # tell the testing framework to run only the changed test blocks
277
278
  before_each_test.each do |hook|
278
- hook.call worker.test_file, worker.log_file, test_names
279
+ hook.call worker.test_file, worker.log_file, test_names, worker.id
279
280
  end
280
281
 
281
282
  # make the process title Test::Unit friendly and ps(1) searchable
@@ -301,8 +302,11 @@ module Test
301
302
 
302
303
  after_each_test.each do |hook|
303
304
  hook.call worker.test_file, worker.log_file, worker.exit_status,
304
- worker.started_at, worker.finished_at - worker.started_at
305
+ worker.started_at, worker.finished_at - worker.started_at,
306
+ worker.id
305
307
  end
308
+
309
+ @worker_id_pool.push worker.id
306
310
  end
307
311
  end
308
312
  end
@@ -1,7 +1,8 @@
1
1
  require 'test/loop'
2
2
 
3
3
  Test::Loop.after_each_test.push lambda {
4
- |test_file, log_file, run_status, started_at, elapsed_time|
4
+ |test_file, log_file, run_status, started_at, elapsed_time, worker_id|
5
+
5
6
  unless run_status.success? or run_status.signaled?
6
7
  title = 'FAIL at %s in %0.1fs' % [started_at.strftime('%r'), elapsed_time]
7
8
  statistics = File.readlines(log_file).grep(/^\d+ \w+,/)
@@ -0,0 +1,9 @@
1
+ require 'test/loop'
2
+
3
+ Test::Loop.before_each_test.push lambda {
4
+ |test_file, log_file, test_names, worker_id|
5
+
6
+ # for compatitibilty with parallel_tests gem,
7
+ # use numbers as strings: "", "2", "3", "4"
8
+ ENV['TEST_ENV_NUMBER'] = worker_id.next.to_s if worker_id > 0
9
+ }
@@ -1,4 +1,5 @@
1
1
  require 'test/loop'
2
+ require 'active_support/inflector'
2
3
 
3
4
  Test::Loop.reabsorb_file_globs.push(
4
5
  'config/**/*.{rb,yml}',
@@ -7,20 +8,30 @@ Test::Loop.reabsorb_file_globs.push(
7
8
  )
8
9
 
9
10
  Test::Loop.test_file_matchers['{app,lib,test,spec}/**/*.rb'] =
10
- Test::Loop.test_file_matchers.delete('lib/**/*.rb')
11
+ lambda do |path|
12
+ base = File.basename(path, '.rb')
13
+ poly = ActiveSupport::Inflector.pluralize(base)
14
+ "{test,spec}/**/{#{base},#{poly}_*}_{test,spec}.rb"
15
+ end
11
16
 
12
17
  Test::Loop.test_file_matchers['{test,spec}/factories/**/*_factory.rb'] =
13
18
  lambda do |path|
14
19
  base = File.basename(path, '_factory.rb')
15
- "{test,spec}/**/#{base}_{test,spec}.rb"
20
+ poly = ActiveSupport::Inflector.pluralize(base)
21
+ "{test,spec}/**/{#{base},#{poly}_*}_{test,spec}.rb"
16
22
  end
17
23
 
18
- require 'rails/railtie'
19
- Class.new Rails::Railtie do
20
- config.before_initialize do |app|
21
- if app.config.cache_classes
22
- warn "test-loop: Setting #{app.class}.config.cache_classes = false"
23
- app.config.cache_classes = false
24
+ begin
25
+ require 'rails/railtie'
26
+ Class.new Rails::Railtie do
27
+ config.before_initialize do |app|
28
+ if app.config.cache_classes
29
+ warn "test-loop: Setting #{app.class}.config.cache_classes = false"
30
+ app.config.cache_classes = false
31
+ end
24
32
  end
25
33
  end
34
+ rescue LoadError
35
+ warn "test-loop: Railtie not available; please manually set:\n\t"\
36
+ "config.cache_classes = false"
26
37
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-loop
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.3.1
4
+ version: 13.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,14 +9,15 @@ authors:
9
9
  - Brian D. Burns
10
10
  - Daniel Pittman
11
11
  - Jacob Helwig
12
+ - Corné Verbruggen
12
13
  autorequire:
13
14
  bindir: bin
14
15
  cert_chain: []
15
- date: 2011-07-19 00:00:00.000000000 Z
16
+ date: 2011-08-24 00:00:00.000000000 Z
16
17
  dependencies:
17
18
  - !ruby/object:Gem::Dependency
18
19
  name: diff-lcs
19
- requirement: &21852080 !ruby/object:Gem::Requirement
20
+ requirement: &19985940 !ruby/object:Gem::Requirement
20
21
  none: false
21
22
  requirements:
22
23
  - - ! '>='
@@ -24,7 +25,7 @@ dependencies:
24
25
  version: 1.1.2
25
26
  type: :runtime
26
27
  prerelease: false
27
- version_requirements: *21852080
28
+ version_requirements: *19985940
28
29
  description:
29
30
  email:
30
31
  executables:
@@ -38,6 +39,7 @@ files:
38
39
  - lib/test/loop.rb
39
40
  - lib/test/loop/notify.rb
40
41
  - lib/test/loop/rails.rb
42
+ - lib/test/loop/parallel_tests.rb
41
43
  homepage: http://github.com/sunaku/test-loop
42
44
  licenses: []
43
45
  post_install_message:
@@ -58,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
60
  version: '0'
59
61
  requirements: []
60
62
  rubyforge_project:
61
- rubygems_version: 1.8.5
63
+ rubygems_version: 1.8.9
62
64
  signing_key:
63
65
  specification_version: 3
64
66
  summary: Continuous testing for Ruby with fork/eval