grntest 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9681ce146649a19fe0099c41cac952e0c53c964c
4
- data.tar.gz: accc76ff8605c28f26a07014082523f7d30134ec
3
+ metadata.gz: 7da2ff4d46c711c2bc7bf534ed0478fc4bb9a510
4
+ data.tar.gz: 7734142d71d8b3d0375e9275eb168fac6df23932
5
5
  SHA512:
6
- metadata.gz: 210cd594bdfb36425deb5d28084acbf798bfd765021c002f7c00fb54d0ee64c7f69a335f269f9f4ec5229e8930692cccecabc74929004e24a66e9d7813f7615e
7
- data.tar.gz: 51151bee659689a783ee6eed2f9c8d8fc48e1a71245cb9ec15c8cd8a9cb48a9c3bbff2b276e402a9d1abec46f740a6760d9d95daeb39b74d9152b6aae87f805f
6
+ metadata.gz: d17ae23c5d7342c7aae95d96bf2c8e271661860232b4766d7397250c1276b7984d1be6b2d415f30639b5a1f2a0b4be8705c6202973bd626afdc4b38bdce63994
7
+ data.tar.gz: e35c94ee423590de22f75f33406f6728ce6ff016d08001aac49645dd1b8d7f74c7d68d0ac14e0396209a20e4efc27284c62910b0a0516602668d0f4ee9602050
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # README
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/grntest.svg)](http://badge.fury.io/rb/grntest)
4
+
3
5
  ## Name
4
6
 
5
7
  grntest
@@ -215,6 +217,8 @@ Here are available `NAME` s:
215
217
  * `long-timeout`
216
218
  * `on-error`
217
219
  * `omit`
220
+ * `add-important-log-levels`
221
+ * `remove-important-log-levels`
218
222
 
219
223
  `ARGUMENTS...` are depends on directive. A directive doesn't require
220
224
  any arguments but a directive requires arguments.
@@ -429,6 +433,83 @@ Example:
429
433
  new_excelent_command
430
434
  ```
431
435
 
436
+ #### `add-important-log-levels`
437
+
438
+ Usage:
439
+
440
+ ```
441
+ #@add-important-log-levels LEVEL_1 LEVEL_2 ...
442
+ ```
443
+
444
+ Add `LEVEL_N` to important log level list. grntest outputs log
445
+ messages when their log level is included in important log level
446
+ list.
447
+
448
+ The default important log level list has the following log levels:
449
+
450
+ * `emergency`
451
+ * `alert`
452
+ * `critical`
453
+ * `error`
454
+ * `warning`
455
+ * `notice`
456
+
457
+ If you want to test log messages for `info`, `debug` or `dump` log
458
+ levels, you need to add the log level to important log level list.
459
+
460
+ Example:
461
+
462
+ ```
463
+ # Enable logs for debug level
464
+ log_level --level debug
465
+ # Collect debug level log messages
466
+ #@add-important-log-levels debug
467
+ log_put --level debug --message "This is a message"
468
+ # The following messages is collected by grntest
469
+ #|d| This is a message
470
+ ```
471
+
472
+ #### `remove-important-log-levels`
473
+
474
+ Usage:
475
+
476
+ ```
477
+ #@remove-important-log-levels LEVEL_1 LEVEL_2 ...
478
+ ```
479
+
480
+ Remove `LEVEL_N` from important log level list. grntest outputs log
481
+ messages when their log level is included in important log level
482
+ list.
483
+
484
+ The default important log level list has the following log levels:
485
+
486
+ * `emergency`
487
+ * `alert`
488
+ * `critical`
489
+ * `error`
490
+ * `warning`
491
+ * `notice`
492
+
493
+ You can remove them from important log level list. You can only remove
494
+ log levels added by `add-important-log-levels`.
495
+
496
+ Example:
497
+
498
+ ```
499
+ # Enable logs for debug level
500
+ log_level --level debug
501
+ # Collect debug level log messages
502
+ #@add-important-log-levels debug
503
+ log_put --level debug --message "This is a message"
504
+ # The following messages is collected by grntest
505
+ #|d| This is a message
506
+
507
+ # Disable collecting debug level log messages
508
+ #@remove-important-log-levels debug
509
+ log_put --level debug --message "This is a message"
510
+ # No message is collected by grntest
511
+ ```
512
+
432
513
  ## Options
433
514
 
434
515
  Grntest has many options. You don't need to specify many of them
@@ -554,7 +635,7 @@ has many test scripts and uses many useful features. They will help you.
554
635
 
555
636
  ## Dependencies
556
637
 
557
- * Ruby 1.9.3
638
+ * Ruby
558
639
  * msgpack gem
559
640
 
560
641
  ## Mailing list
data/doc/text/news.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # News
2
2
 
3
+ ## 1.1.2: 2015-07-08
4
+
5
+ ### Improvements
6
+
7
+ * Improve HTTP server related error case handlings.
8
+ * Support Valgrind.
9
+ * Added `--stop-on-failure` that stops testing when one test is failed.
10
+ * Support JSONP.
11
+ * Add `add-important-log-levels` directive.
12
+ * Add `remove-important-log-levels` directive.
13
+
3
14
  ## 1.1.1: 2015-02-03
4
15
 
5
16
  ### Improvements
@@ -32,14 +32,15 @@ module Grntest
32
32
  end
33
33
 
34
34
  attr_reader :context
35
- def initialize(context=nil)
35
+ def initialize(context)
36
36
  @loading = false
37
37
  @pending_command = ""
38
38
  @pending_load_command = nil
39
39
  @current_command_name = nil
40
40
  @output_type = nil
41
41
  @long_timeout = default_long_timeout
42
- @context = context || ExecutionContext.new
42
+ @context = context
43
+ @custom_important_log_levels = []
43
44
  end
44
45
 
45
46
  def execute(script_path)
@@ -191,6 +192,24 @@ module Grntest
191
192
  @context.omit
192
193
  end
193
194
 
195
+ def execute_directive_add_important_log_levels(line, content, options)
196
+ log_levels = options.collect do |log_level|
197
+ normalize_log_level(log_level)
198
+ end
199
+ @custom_important_log_levels |= log_levels
200
+ end
201
+
202
+ def execute_directive_remove_important_log_levels(line, content, options)
203
+ log_levels = options.collect do |log_level|
204
+ normalize_log_level(log_level)
205
+ end
206
+ @custom_important_log_levels -= log_levels
207
+ end
208
+
209
+ def normalize_log_level(level)
210
+ level[0]
211
+ end
212
+
194
213
  def execute_directive(line, content)
195
214
  command, *options = Shellwords.split(content)
196
215
  case command
@@ -210,6 +229,10 @@ module Grntest
210
229
  execute_directive_on_error(line, content, options)
211
230
  when "omit"
212
231
  execute_directive_omit(line, content, options)
232
+ when "add-important-log-levels"
233
+ execute_directive_add_important_log_levels(line, content, options)
234
+ when "remove-important-log-levels"
235
+ execute_directive_remove_important_log_levels(line, content, options)
213
236
  else
214
237
  log_input(line)
215
238
  log_error("#|e| unknown directive: <#{command}>")
@@ -296,7 +319,8 @@ module Grntest
296
319
  end
297
320
 
298
321
  def important_log_level?(log_level)
299
- ["E", "A", "C", "e", "w"].include?(log_level)
322
+ ["E", "A", "C", "e", "w"].include?(log_level) or
323
+ @custom_important_log_levels.include?(log_level)
300
324
  end
301
325
 
302
326
  def backtrace_log_message?(message)
@@ -22,11 +22,11 @@ require "grntest/executors/base-executor"
22
22
  module Grntest
23
23
  module Executors
24
24
  class HTTPExecutor < BaseExecutor
25
- def initialize(host, port, context=nil)
25
+ def initialize(host, port, context, options={})
26
26
  super(context)
27
27
  @host = host
28
28
  @port = port
29
- @read_timeout = 3
29
+ @read_timeout = options[:read_timeout] || 3
30
30
  end
31
31
 
32
32
  def send_command(command)
@@ -44,13 +44,16 @@ module Grntest
44
44
  rescue Error
45
45
  n_retried += 1
46
46
  sleep(0.1)
47
- retry if n_retried < 50
47
+ retry if n_retried < 100
48
48
  raise
49
49
  end
50
50
  end
51
51
 
52
52
  def shutdown
53
- send_command(command("shutdown"))
53
+ begin
54
+ send_command(command("shutdown"))
55
+ rescue Error
56
+ end
54
57
  end
55
58
 
56
59
  def create_sub_executor(context)
@@ -20,7 +20,7 @@ require "grntest/executors/base-executor"
20
20
  module Grntest
21
21
  module Executors
22
22
  class StandardIOExecutor < BaseExecutor
23
- def initialize(input, output, context=nil)
23
+ def initialize(input, output, context)
24
24
  super(context)
25
25
  @input = input
26
26
  @output = output
@@ -228,16 +228,51 @@ module Grntest
228
228
  end
229
229
  command_line << @tester.gdb
230
230
  gdb_command_path = context.temporary_directory_path + "groonga.gdb"
231
- File.open(gdb_command_path, "w") do |gdb_command|
232
- gdb_command.puts(<<-EOC)
231
+ gdb_command_path.open("w") do |gdb_command|
232
+ gdb_command.puts(<<-COMMANDS)
233
233
  break main
234
234
  run
235
- print chdir("#{context.temporary_directory_path}")
236
- EOC
235
+ call chdir("#{context.temporary_directory_path}")
236
+ COMMANDS
237
237
  end
238
238
  command_line << "--command=#{gdb_command_path}"
239
239
  command_line << "--quiet"
240
240
  command_line << "--args"
241
+ elsif @tester.valgrind
242
+ if libtool_wrapper?(command)
243
+ command_line << find_libtool(command)
244
+ command_line << "--mode=execute"
245
+ end
246
+ command_line << @tester.valgrind
247
+ command_line << "--leak-check=full"
248
+ command_line << "--show-reachable=yes"
249
+ command_line << "--track-origins=yes"
250
+ valgrind_suppressions_file_path =
251
+ context.temporary_directory_path + "groonga.supp"
252
+ valgrind_suppressions_file_path.open("w") do |suppressions|
253
+ suppressions.puts(<<-SUPPRESSIONS)
254
+ {
255
+ dlopen
256
+ Memcheck:Leak
257
+ match-leak-kinds: reachable
258
+ ...
259
+ fun:dlopen*
260
+ ...
261
+ }
262
+ {
263
+ _dl_catch_error
264
+ Memcheck:Leak
265
+ match-leak-kinds: reachable
266
+ ...
267
+ fun:_dl_catch_error
268
+ }
269
+ SUPPRESSIONS
270
+ end
271
+ command_line << "--suppressions=#{valgrind_suppressions_file_path}"
272
+ if @tester.valgrind_gen_suppressions?
273
+ command_line << "--gen-suppressions=all"
274
+ end
275
+ command_line << "--verbose"
241
276
  else
242
277
  spawn_options[:chdir] = context.temporary_directory_path.to_s
243
278
  end
@@ -282,10 +317,15 @@ EOC
282
317
  command_line = groonga_http_command(host, port, pid_file_path, context,
283
318
  spawn_options)
284
319
  pid = nil
320
+ shutdown_wait_timeout = 5
321
+ options = {}
322
+ if @tester.gdb
323
+ options[:read_timeout] = 60 * 10
324
+ end
285
325
  begin
286
326
  pid = Process.spawn(env, *command_line, spawn_options)
287
327
  begin
288
- executor = Executors::HTTPExecutor.new(host, port, context)
328
+ executor = Executors::HTTPExecutor.new(host, port, context, options)
289
329
  begin
290
330
  executor.ensure_groonga_ready
291
331
  rescue
@@ -298,10 +338,15 @@ EOC
298
338
  end
299
339
  yield(executor)
300
340
  ensure
301
- Process.kill(:TERM, pid)
302
- wait_groonga_http_shutdown(pid_file_path)
341
+ executor.shutdown
342
+ if wait_groonga_http_shutdown(pid_file_path, shutdown_wait_timeout)
343
+ pid = nil if wait_pid(pid, shutdown_wait_timeout)
344
+ end
303
345
  end
304
346
  ensure
347
+ return if pid.nil?
348
+ Process.kill(:TERM, pid)
349
+ wait_groonga_http_shutdown(pid_file_path, shutdown_wait_timeout)
305
350
  ensure_process_finished(pid)
306
351
  end
307
352
  end
@@ -314,20 +359,34 @@ EOC
314
359
  finished_pid = Process.waitpid(pid, Process::WNOHANG)
315
360
  break if finished_pid
316
361
  n_retries += 1
317
- break if n_retries > 10
362
+ break if n_retries > 100
318
363
  Process.kill(:TERM, pid)
319
364
  sleep(0.1)
320
365
  end
321
366
  end
322
367
 
323
- def wait_groonga_http_shutdown(pid_file_path)
368
+ def wait_pid(pid, timeout)
369
+ total_sleep_time = 0
370
+ sleep_time = 0.1
371
+ loop do
372
+ return true if Process.waitpid(pid, Process::WNOHANG)
373
+ sleep(sleep_time)
374
+ total_sleep_time += sleep_time
375
+ return false if total_sleep_time > timeout
376
+ end
377
+ end
378
+
379
+ def wait_groonga_http_shutdown(pid_file_path, timeout)
380
+ return false unless pid_file_path.exist?
381
+
324
382
  total_sleep_time = 0
325
383
  sleep_time = 0.1
326
384
  while pid_file_path.exist?
327
385
  sleep(sleep_time)
328
386
  total_sleep_time += sleep_time
329
- break if total_sleep_time > 1.0
387
+ break if total_sleep_time > timeout
330
388
  end
389
+ true
331
390
  end
332
391
 
333
392
  def groonga_http_command(host, port, pid_file_path, context, spawn_options)
@@ -402,6 +461,9 @@ http {
402
461
 
403
462
  def create_empty_database(db_path)
404
463
  output_fd = Tempfile.new("create-empty-database")
464
+ env = {
465
+ "GRN_FMALLOC_PROB" => nil,
466
+ }
405
467
  create_database_command = [
406
468
  @tester.groonga,
407
469
  "--output-fd", output_fd.to_i.to_s,
@@ -411,7 +473,7 @@ http {
411
473
  options = {
412
474
  output_fd.to_i => output_fd.to_i
413
475
  }
414
- system(*create_database_command, options)
476
+ system(env, *create_database_command, options)
415
477
  output_fd.close(true)
416
478
  end
417
479
 
@@ -442,8 +504,17 @@ http {
442
504
  when "json", "msgpack"
443
505
  status = nil
444
506
  values = nil
507
+ content = content.chomp
508
+ if type == "json" and /\A([^(]+\()(.+)(\);)\z/ =~ content
509
+ jsonp = true
510
+ jsonp_start = $1
511
+ content = $2
512
+ jsonp_end = $3
513
+ else
514
+ jsonp = false
515
+ end
445
516
  begin
446
- status, *values = ResponseParser.parse(content.chomp, type)
517
+ status, *values = ResponseParser.parse(content, type)
447
518
  rescue ParseError
448
519
  return $!.message
449
520
  end
@@ -454,7 +525,12 @@ http {
454
525
  if normalized_output.bytesize > @max_n_columns
455
526
  normalized_output = JSON.pretty_generate(normalized_output_content)
456
527
  end
457
- normalize_raw_content(normalized_output)
528
+ normalized_raw_content = normalize_raw_content(normalized_output)
529
+ if jsonp
530
+ "#{jsonp_start}#{normalized_raw_content.chomp}#{jsonp_end}\n"
531
+ else
532
+ normalized_raw_content
533
+ end
458
534
  when "xml"
459
535
  normalized_xml = normalize_output_xml(content, options)
460
536
  normalize_raw_content(normalized_xml)
@@ -64,6 +64,13 @@ module Grntest
64
64
  collect_count(:n_not_checked_tests)
65
65
  end
66
66
 
67
+ def have_failure?
68
+ @workers.any? do |worker|
69
+ worker.result.n_failed_tests > 0 or
70
+ worker.result.n_leaked_tests > 0
71
+ end
72
+ end
73
+
67
74
  private
68
75
  def collect_count(item)
69
76
  counts = @workers.collect do |worker|
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2012-2013 Kouhei Sutou <kou@clear-code.com>
3
+ # Copyright (C) 2012-2015 Kouhei Sutou <kou@clear-code.com>
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -164,12 +164,30 @@ module Grntest
164
164
  tester.gdb = command || tester.default_gdb
165
165
  end
166
166
 
167
+ parser.on("--valgrind[=COMMAND]",
168
+ "Run groonga on valgrind and use COMMAND as valgrind",
169
+ "(#{tester.default_valgrind})") do |command|
170
+ tester.valgrind = command || tester.default_valgrind
171
+ end
172
+
173
+ parser.on("--[no-]valgrind-gen-suppressions",
174
+ "Generate suppressions for Valgrind",
175
+ "(#{tester.valgrind_gen_suppressions?})") do |boolean|
176
+ tester.valgrind_gen_suppressions = boolean
177
+ end
178
+
167
179
  parser.on("--[no-]keep-database",
168
180
  "Keep used database for debug after test is finished",
169
181
  "(#{tester.keep_database?})") do |boolean|
170
182
  tester.keep_database = boolean
171
183
  end
172
184
 
185
+ parser.on("--[no-]stop-on-failure",
186
+ "Stop immediately on the first non success test",
187
+ "(#{tester.stop_on_failure?})") do |boolean|
188
+ tester.stop_on_failure = boolean
189
+ end
190
+
173
191
  parser.on("--output=OUTPUT",
174
192
  "Output to OUTPUT",
175
193
  "(stdout)") do |output|
@@ -206,7 +224,10 @@ module Grntest
206
224
  attr_accessor :n_workers
207
225
  attr_accessor :output
208
226
  attr_accessor :gdb, :default_gdb
227
+ attr_accessor :valgrind, :default_valgrind
228
+ attr_writer :valgrind_gen_suppressions
209
229
  attr_writer :reporter, :keep_database, :use_color
230
+ attr_writer :stop_on_failure
210
231
  attr_reader :test_patterns, :test_suite_patterns
211
232
  attr_reader :exclude_test_patterns, :exclude_test_suite_patterns
212
233
  def initialize
@@ -223,12 +244,14 @@ module Grntest
223
244
  @output = $stdout
224
245
  @keep_database = false
225
246
  @use_color = nil
247
+ @stop_on_failure = false
226
248
  @test_patterns = []
227
249
  @test_suite_patterns = []
228
250
  @exclude_test_patterns = []
229
251
  @exclude_test_suite_patterns = []
230
252
  detect_suitable_diff
231
253
  initialize_debuggers
254
+ initialize_memory_checkers
232
255
  end
233
256
 
234
257
  def run(*targets)
@@ -262,6 +285,14 @@ module Grntest
262
285
  @use_color
263
286
  end
264
287
 
288
+ def stop_on_failure?
289
+ @stop_on_failure
290
+ end
291
+
292
+ def valgrind_gen_suppressions?
293
+ @valgrind_gen_suppressions
294
+ end
295
+
265
296
  def target_test?(test_name)
266
297
  selected_test?(test_name) and not excluded_test?(test_name)
267
298
  end
@@ -343,6 +374,12 @@ module Grntest
343
374
  @default_gdb = "gdb"
344
375
  end
345
376
 
377
+ def initialize_memory_checkers
378
+ @vagrind = nil
379
+ @default_valgrind = "valgrind"
380
+ @vagrind_gen_suppressions = false
381
+ end
382
+
346
383
  def command_exist?(name)
347
384
  ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
348
385
  absolute_path = File.join(path, name)
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2012-2014 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2012-2015 Kouhei Sutou <kou@clear-code.com>
2
2
  #
3
3
  # This program is free software: you can redistribute it and/or modify
4
4
  # it under the terms of the GNU General Public License as published by
@@ -14,5 +14,5 @@
14
14
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
15
 
16
16
  module Grntest
17
- VERSION = "1.1.1"
17
+ VERSION = "1.1.2"
18
18
  end
@@ -63,7 +63,7 @@ module Grntest
63
63
  end
64
64
 
65
65
  class Worker
66
- attr_reader :id, :tester, :test_suites_rusult, :reporter
66
+ attr_reader :id, :tester, :reporter
67
67
  attr_reader :suite_name, :test_script_path, :test_name, :status, :result
68
68
  def initialize(id, tester, test_suites_result, reporter)
69
69
  @id = id
@@ -107,6 +107,9 @@ module Grntest
107
107
  succeeded = false unless runner.run
108
108
 
109
109
  break if interruptted?
110
+ if @tester.stop_on_failure? and @test_suites_result.have_failure?
111
+ break
112
+ end
110
113
  end
111
114
  @status = "finished"
112
115
  @reporter.on_suite_finish(@suite_name) if @suite_name
@@ -17,8 +17,8 @@ require "grntest/executors/base-executor"
17
17
 
18
18
  class TestBaseExecutor < Test::Unit::TestCase
19
19
  def setup
20
- @executor = Grntest::Executors::BaseExecutor.new
21
- @context = @executor.context
20
+ @context = Grntest::ExecutionContext.new
21
+ @executor = Grntest::Executors::BaseExecutor.new(@context)
22
22
  end
23
23
 
24
24
  class TestErrorLogLevel < self
@@ -21,8 +21,9 @@ class TestStandardIOExecutor < Test::Unit::TestCase
21
21
  def setup
22
22
  input = StringIO.new
23
23
  output = StringIO.new
24
- @executor = Grntest::Executors::StandardIOExecutor.new(input, output)
25
- @context = @executor.context
24
+ @context = Grntest::ExecutionContext.new
25
+ @executor = Grntest::Executors::StandardIOExecutor.new(input, output,
26
+ @context)
26
27
  @script = Tempfile.new("test-executor")
27
28
  end
28
29
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grntest
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kouhei Sutou
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-02-03 00:00:00.000000000 Z
12
+ date: 2015-07-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
@@ -204,8 +204,8 @@ specification_version: 4
204
204
  summary: Grntest is a testing framework for Groonga. You can write a test for Groonga
205
205
  by writing Groonga commands and expected result.
206
206
  test_files:
207
+ - test/test-log-parser.rb
207
208
  - test/executors/test-base-executor.rb
208
209
  - test/executors/test-standard-io-executor.rb
209
210
  - test/run-test.rb
210
- - test/test-log-parser.rb
211
211
  has_rdoc: