grntest 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -6,7 +6,8 @@ grntest
6
6
 
7
7
  ## Description
8
8
 
9
- Grntest is a testing framework for groonga. You can write a test for groonga by writing groonga commands and expected result.
9
+ Grntest is a testing framework for groonga. You can write a test for
10
+ groonga by writing groonga commands and expected result.
10
11
 
11
12
  ## Install
12
13
 
@@ -14,9 +15,7 @@ Grntest is a testing framework for groonga. You can write a test for groonga by
14
15
  % gem install grntest
15
16
  ```
16
17
 
17
- ## Usage
18
-
19
- ### Basic usage
18
+ ## Basic usage
20
19
 
21
20
  Write a test script that extension is `.test`. Here is a sample test
22
21
  script `select.test`:
@@ -40,7 +39,7 @@ Run `grntest` with `select.test` as command line argument:
40
39
  N
41
40
  ================================================================================
42
41
  .
43
- select 0.1667s [not checked]
42
+ select 0.3866s [not checked]
44
43
  ================================================================================
45
44
  table_create Users TABLE_HASH_KEY ShortText
46
45
  [[0,0.0,0.0],true]
@@ -55,8 +54,9 @@ select Users --query '_key:Alice'
55
54
  ================================================================================
56
55
 
57
56
 
58
- 5.96 tests/sec: 1 tests, 0 passes, 0 failures, 1 not checked_tests
59
- 0% passed in 0.1678s.
57
+ tests/sec | tests | passes | failures | leaked | !checked |
58
+ 2.57 | 1 | 0 | 0 | 0 | 1 |
59
+ 0% passed in 0.3885s.
60
60
  ```
61
61
 
62
62
  It generates `select.actual` file that contains actual result. If it
@@ -72,8 +72,9 @@ Run `grntest` again:
72
72
  % grntest select.test
73
73
  .
74
74
 
75
- 6.12 tests/sec: 1 tests, 1 passes, 0 failures, 0 not checked_tests
76
- 100% passed in 0.1635s.
75
+ tests/sec | tests | passes | failures | leaked | !checked |
76
+ 5.76 | 1 | 1 | 0 | 0 | 0 |
77
+ 100% passed in 0.1736s.
77
78
  ```
78
79
 
79
80
  It compares actual result and content of `select.expected` and
@@ -103,23 +104,24 @@ Run `grntest` again:
103
104
  F
104
105
  ================================================================================
105
106
  .
106
- select 0.1445s [failed]
107
+ select 0.1767s [failed]
107
108
  ================================================================================
108
- --- (actual)
109
- +++ (expected)
109
+ --- (expected)
110
+ +++ (actual)
110
111
  @@ -6,5 +6,5 @@
111
112
  {"_key": "Bob"}
112
113
  ]
113
114
  [[0,0.0,0.0],2]
114
- -select Users --query '_key:Bob'
115
- -[[0,0.0,0.0],[[[1],[["_id","UInt32"],["_key","ShortText"]],[2,"Bob"]]]]
116
- +select Users --query '_key:Alice'
117
- +[[0,0.0,0.0],[[[1],[["_id","UInt32"],["_key","ShortText"]],[1,"Alice"]]]]
115
+ -select Users --query '_key:Alice'
116
+ -[[0,0.0,0.0],[[[1],[["_id","UInt32"],["_key","ShortText"]],[1,"Alice"]]]]
117
+ +select Users --query '_key:Bob'
118
+ +[[0,0.0,0.0],[[[1],[["_id","UInt32"],["_key","ShortText"]],[2,"Bob"]]]]
118
119
  ================================================================================
119
120
 
120
121
 
121
- 6.68 tests/sec: 1 tests, 0 passes, 1 failures, 0 not checked_tests
122
- 0% passed in 0.1497s.
122
+ tests/sec | tests | passes | failures | leaked | !checked |
123
+ 4.65 | 1 | 0 | 1 | 0 | 0 |
124
+ 0% passed in 0.2153s.
123
125
  ```
124
126
 
125
127
  It says the expected result that is read from `select.expected` and
@@ -140,19 +142,284 @@ Run `grntest` again:
140
142
  % grntest select.test
141
143
  .
142
144
 
143
- 6.97 tests/sec: 1 tests, 1 passes, 0 failures, 0 not checked_tests
144
- 100% passed in 0.1434s.
145
+ tests/sec | tests | passes | failures | leaked | !checked |
146
+ 6.20 | 1 | 1 | 0 | 0 | 0 |
147
+ 100% passed in 0.1613s.
145
148
  ```
146
149
 
147
150
  The test is succeeded again.
148
151
 
149
- ### Advanced usage
152
+ ## Advanced usage
153
+
154
+ There are more useful features. They are not needed for normal
155
+ users but they are very useful for advanced users.
156
+
157
+ There are advanced features:
158
+
159
+ * Comment
160
+ * Continuation line
161
+ * Directives
162
+
163
+ ### Comment
164
+
165
+ Groonga supports comment line by `#`.
166
+
167
+ Example:
168
+
169
+ ```
170
+ # This line is comment line.
171
+ select Users
172
+ ```
173
+
174
+ Grntest also supports the syntax. You can use `#` as comment mark.
175
+
176
+ ### Continuation line
177
+
178
+ You can break a long line by escaping new line with `\`.
179
+
180
+ Example:
181
+
182
+ ```
183
+ select Users \
184
+ --match_columns name \
185
+ --query Ken
186
+ ```
187
+
188
+ The command is processed as the following command:
189
+
190
+ ```
191
+ select Users --match_columns name --query Ken
192
+ ```
193
+
194
+ You can make your test readable with this feature.
195
+
196
+ Groogna doesn't support this feature.
197
+
198
+ ### Directives
199
+
200
+ Grntest supports directives that control grntest behavior.
201
+
202
+ Here is directive syntax:
203
+
204
+ ```
205
+ #@NAME [ARGUMENTS...]
206
+ ```
150
207
 
151
- See `grntest --help`. It contains many usuful features.
208
+ Here are available `NAME` s:
152
209
 
153
- Some important features are described in this section.
210
+ * `disable-logging`
211
+ * `enable-logging`
212
+ * `suggest-create-dataset`
213
+ * `include`
214
+ * `copy-path`
154
215
 
155
- #### `--n-workers`
216
+ `ARGUMENTS...` are depends on directive. A directive doesn't require
217
+ any arguments but a directive requires arguments.
218
+
219
+ #### `disable-logging`
220
+
221
+ Usage:
222
+
223
+ ```
224
+ #@disable-logging
225
+ ```
226
+
227
+ It disables logging executed command and executed result until
228
+ `enable-logging` directive is used. It is useful for executing
229
+ commands that isn't important for test.
230
+
231
+ Example:
232
+
233
+ ```
234
+ #@disable-logging
235
+ load --table Users
236
+ [
237
+ {"_key": "User1"},
238
+ {"_key": "..."},
239
+ {"_key": "User9999999"}
240
+ ]
241
+ #@enable-logging
242
+
243
+ select Users --query _key:User29
244
+ ```
245
+
246
+ See also: `enable-logging`
247
+
248
+ ### `enable-logging`
249
+
250
+ Usage:
251
+
252
+ ```
253
+ #@enable-logging
254
+ ```
255
+
256
+ It enables logging that is disabled by `disable-logging` directive.
257
+
258
+ See also: `disable-logging`
259
+
260
+ ### suggest-create-dataset
261
+
262
+ Usage:
263
+
264
+ ```
265
+ #@suggest-create-dataset DATASET_NAME
266
+ ```
267
+
268
+ It creates dataset `DATASET_NAME` for suggest feature. It is useful
269
+ for testing suggest feature.
270
+
271
+ Example:
272
+
273
+ ```
274
+ #@suggest-create-dataset rurema
275
+ load --table event_rurema --each 'suggest_preparer(_id, type, item, sequence, time, pair_rurema)'
276
+ [
277
+ ["sequence", "time", "item", "type"],
278
+ ["21e80fd5e5bc2126469db1c927b7a48fb3353dd9",1312134098.0,"f",null],
279
+ ["21e80fd5e5bc2126469db1c927b7a48fb3353dd9",1312134105.0,"er",null],
280
+ ["21e80fd5e5bc2126469db1c927b7a48fb3353dd9",1312134106.0,"erb",null],
281
+ ["21e80fd5e5bc2126469db1c927b7a48fb3353dd9",1312134107.0,"erb","submit"]
282
+ ]
283
+ ```
284
+
285
+ See also: `--groonga-suggest-create-dataset` option
286
+
287
+ ### include
288
+
289
+ Usage:
290
+
291
+ ```
292
+ #@include SUB_TEST_FILE_PATH
293
+ ```
294
+
295
+ It includes `SUB_TEST_FILE_PATH` content. It is useful for sharing
296
+ commands by many tests.
297
+
298
+ You can use `include` in included file. It means that an included file
299
+ is processed in the same way as a test file.
300
+
301
+ If `SUB_TEST_FILE_PATH` is relative path, `SUB_TEST_FILE_PATH` is
302
+ found from base directory. Base directory can be specified by
303
+ `--base-directory` option.
304
+
305
+ Example:
306
+
307
+ init.grn:
308
+
309
+ ```
310
+ #@disable-logging
311
+ #@include ddl.grn
312
+ #@include data.grn
313
+ #@enable-logging
314
+ ```
315
+
316
+ ddl.grn:
317
+
318
+ ```
319
+ table_create Users TABLE_HASH_KEY ShortText
320
+ ```
321
+
322
+ data.grn:
323
+
324
+ ```
325
+ load --table Users
326
+ [
327
+ ["_key"],
328
+ ["Alice"],
329
+ ["Bob"]
330
+ ]
331
+ ```
332
+
333
+ user.test:
334
+
335
+ ```
336
+ #@include init.grn
337
+ select Users --query _key:Alice
338
+ ```
339
+
340
+ See also: `--base-directory` option
341
+
342
+ ### `copy-path`
343
+
344
+ Usage
345
+
346
+ ```
347
+ #@copy-path SOURCE DESTINATION
348
+ ```
349
+
350
+ It copies a path from `SOURCE` to `DESTINATION`. You can use it for
351
+ both file and directory. It is useful for using fixture data.
352
+
353
+ Example:
354
+
355
+ ```
356
+ #@copy-path fixture/query_expander/tsv/japanese_synonyms.tsv tmp/synonyms.tsv
357
+ register "query_expanders/tsv"
358
+ ```
359
+
360
+ ## Options
361
+
362
+ Grntest has many options. You don't need to specify many of them
363
+ because they use suitable default values.
364
+
365
+ This section describes some important options. You can see all options
366
+ by `grntest --help`. You will find many usuful features from it.
367
+
368
+ ### `--test`
369
+
370
+ Usage:
371
+
372
+ ```
373
+ % grntest --test TEST_NAME ...
374
+ % grntest --test /TEST_NAME_REGEXP/ ...
375
+ % grntest --test TEST_NAME1 --test TEST_NAME2 ...
376
+ % grntest --test /TEST_NAME_REGEXP1/ --test /TEST_NAME_REGEXP2/ ...
377
+ ```
378
+
379
+ `--test` option specifies tests that should be ran. It is useful when
380
+ you are interested in only one test.
381
+
382
+ For example, the following command line runs only `vector-geo-point`
383
+ test.
384
+
385
+ ```
386
+ % grntest --test vector-geo-point ...
387
+ ```
388
+
389
+ You can use `--test` option multiple times to run only multiple
390
+ interested tests.
391
+
392
+ For example, the following command line runs only `vector-geo-point`
393
+ and `hash` tests.
394
+
395
+ ```
396
+ % grntest --test vector-geo-point --test hash ...
397
+ ```
398
+
399
+ You can use regular expression to select tests by `/.../` syntax.
400
+
401
+ For example, the following command line runs tests that have `geo` in
402
+ its name.
403
+
404
+ ```
405
+ % grntest --test /geo/ ...
406
+ ```
407
+
408
+ You can also use multiple --test options with regular expression.
409
+
410
+ See also: `--exclude-test` option
411
+
412
+ ### `--exclude-test`
413
+
414
+ ### `--test-suite`
415
+
416
+ ### `--exclude-test-suite`
417
+
418
+ ### `--gdb`
419
+
420
+ ### `--keep-database`
421
+
422
+ ### `--n-workers`
156
423
 
157
424
  `--n-workers` option is very useful. You can run many test scripts at
158
425
  once. Tests are finished quickly. You should specify one or more
@@ -163,31 +430,62 @@ Here is a sample command line to use `--n-workers`:
163
430
 
164
431
  ```
165
432
  % grntest --n-workers 4 test/function/suite/suggest
433
+ tests/sec | tests | passes | failures | leaked | !checked |
166
434
  [0] [finished]
167
- 8.60 tests/sec: 4 tests, 4 passes, 0 failures, 0 not checked_tests
435
+ 9.95 | 5 | 5 | 0 | 0 | 0 |
168
436
  [1] [finished]
169
- 9.85 tests/sec: 5 tests, 5 passes, 0 failures, 0 not checked_tests
437
+ 9.22 | 4 | 4 | 0 | 0 | 0 |
170
438
  [2] [finished]
171
- 8.63 tests/sec: 4 tests, 4 passes, 0 failures, 0 not checked_tests
439
+ 9.11 | 4 | 4 | 0 | 0 | 0 |
172
440
  [3] [finished]
173
- 9.68 tests/sec: 5 tests, 5 passes, 0 failures, 0 not checked_tests
441
+ 10.10 | 5 | 5 | 0 | 0 | 0 |
174
442
  |-----------------------------------------------------------------------| [100%]
175
443
 
176
- 34.43 tests/sec: 18 tests, 18 passes, 0 failures, 0 not checked_tests
177
- 100% passed in 0.5228s.
444
+ tests/sec | tests | passes | failures | leaked | !checked |
445
+ 34.61 | 18 | 18 | 0 | 0 | 0 |
446
+ 100% passed in 0.5201s.
447
+ ```
448
+
449
+ ### `--base-directory`
450
+
451
+ ### `--database=PATH`
452
+
453
+ Usage:
454
+
178
455
  ```
456
+ % grntest --database /PATH/TO/EXISTING/DATABASE ...
457
+ ```
458
+
459
+ `--database` option specifies an existing database that is used for
460
+ test. Normally, grntest uses a new empty database for test.
461
+
462
+ `--database` option is very useful for testing against existing
463
+ database.
464
+
465
+ ### `--groonga`
466
+
467
+ ### `--groonga-httpd`
468
+
469
+ ### `--groonga-suggest-create-dataset`
470
+
471
+ ### `--interface`
472
+
473
+ ### `--output-type`
474
+
475
+ ### `--testee`
179
476
 
180
- ### Examples
477
+ ## Examples
181
478
 
182
- See [test/function/ directory in groonga's
183
- source](https://github.com/groonga/groonga/tree/master/test/function). It
479
+ See [test/command/ directory in groonga's
480
+ source](https://github.com/groonga/groonga/tree/master/test/command). It
184
481
  has many test scripts and uses many useful features. They will help you.
185
482
 
186
483
  ## Dependencies
187
484
 
188
485
  * Ruby 1.9.3
486
+ * msgpack gem
189
487
 
190
- ### Mailing list
488
+ ## Mailing list
191
489
 
192
490
  * English: [groonga-talk@lists.sourceforge.net](https://lists.sourceforge.net/lists/listinfo/groonga-talk)
193
491
  * Japanese: [groonga-dev@lists.sourceforge.jp](http://lists.sourceforge.jp/mailman/listinfo/groonga-dev)
@@ -205,4 +503,5 @@ has many test scripts and uses many useful features. They will help you.
205
503
 
206
504
  GPLv3 or later. See doc/text/gpl-3.0.txt for details.
207
505
 
208
- (Kouhei Sutou has a right to change the license including contributed patches.)
506
+ (Kouhei Sutou has a right to change the license including contributed
507
+ patches.)
data/doc/text/news.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # News
2
2
 
3
+ ## 1.0.1: 2012-10-15
4
+
5
+ This has a backward incompatible change. It is directive syntax.
6
+
7
+ Old:
8
+
9
+ # NAME ARGUMENT
10
+
11
+ New:
12
+
13
+ #@NAME ARGUMENT
14
+
15
+ This change is for easy to debug. Conssider about we have a typo in
16
+ `NAME`. It is just ignored in old syntax because it is also a comment
17
+ line. It is reported in new syntax because it syntax is only for
18
+ directive. Grntest can know that user want to use a directive. If
19
+ grntest knows that user want to use a directive, grntest can report an
20
+ error for an unknown directive name.
21
+
22
+ ### Improvements
23
+
24
+ * Inverted expected and actual in diff.
25
+ * Added memory leak check.
26
+ * Documented many features.
27
+ * Changed directive syntax.
28
+ * Added `copy-path` directive.
29
+ * Supported multiple `--test` and `--test-suite` options.
30
+ * Added `--database` option.
31
+
32
+ ### Fixes
33
+
34
+ * Fixed a problem that test report can't be shown for no tests.
35
+
3
36
  ## 1.0.0: 2012-08-29
4
37
 
5
38
  The first release!!!
@@ -122,6 +122,13 @@ module Grntest
122
122
  tester.base_directory = Pathname(directory)
123
123
  end
124
124
 
125
+ parser.on("--database=PATH",
126
+ "Use existing database at PATH " +
127
+ "instead of creating a new database",
128
+ "(creating a new database)") do |path|
129
+ tester.database_path = path
130
+ end
131
+
125
132
  parser.on("--diff=DIFF",
126
133
  "Use DIFF as diff command",
127
134
  "(#{tester.diff})") do |diff|
@@ -224,7 +231,7 @@ module Grntest
224
231
 
225
232
  attr_accessor :groonga, :groonga_httpd, :groonga_suggest_create_dataset
226
233
  attr_accessor :interface, :output_type, :testee
227
- attr_accessor :base_directory, :diff, :diff_options
234
+ attr_accessor :base_directory, :database_path, :diff, :diff_options
228
235
  attr_accessor :n_workers
229
236
  attr_accessor :output
230
237
  attr_accessor :gdb, :default_gdb
@@ -239,6 +246,7 @@ module Grntest
239
246
  @output_type = "json"
240
247
  @testee = "groonga"
241
248
  @base_directory = Pathname(".")
249
+ @database_path = nil
242
250
  @reporter = nil
243
251
  @n_workers = 1
244
252
  @output = $stdout
@@ -288,7 +296,8 @@ module Grntest
288
296
  end
289
297
 
290
298
  def selected_test?(test_name)
291
- @test_patterns.all? do |pattern|
299
+ return true if @test_patterns.empty?
300
+ @test_patterns.any? do |pattern|
292
301
  pattern === test_name
293
302
  end
294
303
  end
@@ -305,7 +314,8 @@ module Grntest
305
314
  end
306
315
 
307
316
  def selected_test_suite?(test_suite_name)
308
- @test_suite_patterns.all? do |pattern|
317
+ return true if @test_suite_patterns.empty?
318
+ @test_suite_patterns.any? do |pattern|
309
319
  pattern === test_suite_name
310
320
  end
311
321
  end
@@ -396,12 +406,14 @@ module Grntest
396
406
  end
397
407
 
398
408
  class WorkerResult < Result
399
- attr_reader :n_tests, :n_passed_tests, :n_not_checked_tests
409
+ attr_reader :n_tests, :n_passed_tests, :n_leaked_tests
410
+ attr_reader :n_not_checked_tests
400
411
  attr_reader :failed_tests
401
412
  def initialize
402
413
  super
403
414
  @n_tests = 0
404
415
  @n_passed_tests = 0
416
+ @n_leaked_tests = 0
405
417
  @n_not_checked_tests = 0
406
418
  @failed_tests = []
407
419
  end
@@ -422,6 +434,10 @@ module Grntest
422
434
  @failed_tests << name
423
435
  end
424
436
 
437
+ def test_leaked(name)
438
+ @n_leaked_tests += 1
439
+ end
440
+
425
441
  def test_not_checked
426
442
  @n_not_checked_tests += 1
427
443
  end
@@ -501,10 +517,16 @@ module Grntest
501
517
  @reporter.fail_test(self, result)
502
518
  end
503
519
 
504
- def not_check_test(result)
520
+ def leaked_test(result)
521
+ @status = "leaked(#{result.n_leaked_objects})"
522
+ @result.test_leaked(test_name)
523
+ @reporter.leaked_test(self, result)
524
+ end
525
+
526
+ def not_checked_test(result)
505
527
  @status = "not checked"
506
528
  @result.test_not_checked
507
- @reporter.not_check_test(self, result)
529
+ @reporter.not_checked_test(self, result)
508
530
  end
509
531
 
510
532
  def finish_test(result)
@@ -545,6 +567,10 @@ module Grntest
545
567
  collect_count(:n_failed_tests)
546
568
  end
547
569
 
570
+ def n_leaked_tests
571
+ collect_count(:n_leaked_tests)
572
+ end
573
+
548
574
  def n_not_checked_tests
549
575
  collect_count(:n_not_checked_tests)
550
576
  end
@@ -633,24 +659,33 @@ module Grntest
633
659
 
634
660
  class TestResult < Result
635
661
  attr_accessor :worker_id, :test_name
636
- attr_accessor :expected, :actual
662
+ attr_accessor :expected, :actual, :n_leaked_objects
637
663
  def initialize(worker)
638
664
  super()
639
665
  @worker_id = worker.id
640
666
  @test_name = worker.test_name
641
667
  @actual = nil
642
668
  @expected = nil
669
+ @n_leaked_objects = 0
643
670
  end
644
671
 
645
672
  def status
646
673
  if @expected
647
674
  if @actual == @expected
648
- :success
675
+ if @n_leaked_objects.zero?
676
+ :success
677
+ else
678
+ :leaked
679
+ end
649
680
  else
650
681
  :failure
651
682
  end
652
683
  else
653
- :not_checked
684
+ if @n_leaked_objects.zero?
685
+ :not_checked
686
+ else
687
+ :leaked
688
+ end
654
689
  end
655
690
  end
656
691
  end
@@ -673,7 +708,7 @@ module Grntest
673
708
  result.measure do
674
709
  result.actual = execute_groonga_script
675
710
  end
676
- result.actual = normalize_result(result.actual)
711
+ normalize_actual_result(result)
677
712
  result.expected = read_expected_result
678
713
  case result.status
679
714
  when :success
@@ -683,8 +718,11 @@ module Grntest
683
718
  @worker.fail_test(result)
684
719
  output_reject_file(result.actual)
685
720
  succeeded = false
721
+ when :leaked
722
+ @worker.leaked_test(result)
723
+ succeeded = false
686
724
  else
687
- @worker.not_check_test(result)
725
+ @worker.not_checked_test(result)
688
726
  output_actual_file(result.actual)
689
727
  end
690
728
  @worker.finish_test(result)
@@ -695,9 +733,13 @@ module Grntest
695
733
  private
696
734
  def execute_groonga_script
697
735
  create_temporary_directory do |directory_path|
698
- db_dir = directory_path + "db"
699
- FileUtils.mkdir_p(db_dir.to_s)
700
- db_path = db_dir + "db"
736
+ if @tester.database_path
737
+ db_path = Pathname(@tester.database_path).expand_path
738
+ else
739
+ db_dir = directory_path + "db"
740
+ FileUtils.mkdir_p(db_dir.to_s)
741
+ db_path = db_dir + "db"
742
+ end
701
743
  context = Executor::Context.new
702
744
  context.temporary_directory_path = directory_path
703
745
  context.db_path = db_path
@@ -708,6 +750,7 @@ module Grntest
708
750
  run_groonga(context) do |executor|
709
751
  executor.execute(test_script_path)
710
752
  end
753
+ check_memory_leak(context)
711
754
  context.result
712
755
  end
713
756
  end
@@ -734,6 +777,10 @@ module Grntest
734
777
  end
735
778
 
736
779
  def run_groonga(context, &block)
780
+ unless @tester.database_path
781
+ create_empty_database(context.db_path.to_s)
782
+ end
783
+
737
784
  case @tester.interface
738
785
  when :stdio
739
786
  run_groonga_stdio(context, &block)
@@ -760,7 +807,6 @@ module Grntest
760
807
  command_line += [
761
808
  "--input-fd", input_fd.to_s,
762
809
  "--output-fd", output_fd.to_s,
763
- "-n",
764
810
  context.relative_db_path.to_s,
765
811
  ]
766
812
  pid = Process.spawn(env, *command_line, spawn_options)
@@ -890,7 +936,6 @@ EOC
890
936
  "--port", port.to_s,
891
937
  "--protocol", "http",
892
938
  "-s",
893
- "-n",
894
939
  context.relative_db_path.to_s,
895
940
  ]
896
941
  when "groonga-httpd"
@@ -907,7 +952,6 @@ EOC
907
952
  end
908
953
 
909
954
  def create_config_file(context, host, port, pid_file_path)
910
- create_empty_database(context.db_path.to_s)
911
955
  config_file_path =
912
956
  context.temporary_directory_path + "groonga-httpd.conf"
913
957
  config_file_path.open("w") do |config_file|
@@ -950,9 +994,9 @@ EOF
950
994
  output_fd.close(true)
951
995
  end
952
996
 
953
- def normalize_result(result)
997
+ def normalize_actual_result(result)
954
998
  normalized_result = ""
955
- result.each do |tag, content, options|
999
+ result.actual.each do |tag, content, options|
956
1000
  case tag
957
1001
  when :input
958
1002
  normalized_result << content
@@ -960,9 +1004,11 @@ EOF
960
1004
  normalized_result << normalize_output(content, options)
961
1005
  when :error
962
1006
  normalized_result << normalize_raw_content(content)
1007
+ when :n_leaked_objects
1008
+ result.n_leaked_objects = content
963
1009
  end
964
1010
  end
965
- normalized_result
1011
+ result.actual = normalized_result
966
1012
  end
967
1013
 
968
1014
  def normalize_raw_content(content)
@@ -1069,6 +1115,17 @@ EOF
1069
1115
  result_file.print(actual_result)
1070
1116
  end
1071
1117
  end
1118
+
1119
+ def check_memory_leak(context)
1120
+ context.log.each_line do |line|
1121
+ timestamp, log_level, message = line.split(/\|\s*/, 3)
1122
+ _ = timestamp # suppress warning
1123
+ next unless /^grn_fin \((\d+)\)$/ =~ message
1124
+ n_leaked_objects = $1.to_i
1125
+ next if n_leaked_objects.zero?
1126
+ context.result << [:n_leaked_objects, n_leaked_objects, {}]
1127
+ end
1128
+ end
1072
1129
  end
1073
1130
 
1074
1131
  class Executor
@@ -1181,17 +1238,64 @@ EOF
1181
1238
 
1182
1239
  def execute_line(line)
1183
1240
  case line
1241
+ when /\A\#@/
1242
+ directive_content = $POSTMATCH
1243
+ execute_directive(line, directive_content)
1184
1244
  when /\A\s*\z/
1185
1245
  # do nothing
1186
1246
  when /\A\s*\#/
1187
- comment_content = $POSTMATCH
1188
- execute_comment(comment_content)
1247
+ # ignore comment
1189
1248
  else
1190
1249
  execute_command_line(line)
1191
1250
  end
1192
1251
  end
1193
1252
 
1194
- def execute_comment(content)
1253
+ def resolve_path(path)
1254
+ if path.relative?
1255
+ @context.base_directory + path
1256
+ else
1257
+ path
1258
+ end
1259
+ end
1260
+
1261
+ def execute_directive_suggest_create_dataset(line, content, options)
1262
+ dataset_name = options.first
1263
+ if dataset_name.nil?
1264
+ log_input(line)
1265
+ log_error("#|e| [suggest-create-dataset] dataset name is missing")
1266
+ return
1267
+ end
1268
+ execute_suggest_create_dataset(dataset_name)
1269
+ end
1270
+
1271
+ def execute_directive_include(line, content, options)
1272
+ path = options.first
1273
+ if path.nil?
1274
+ log_input(line)
1275
+ log_error("#|e| [include] path is missing")
1276
+ return
1277
+ end
1278
+ execute_script(Pathname(path))
1279
+ end
1280
+
1281
+ def execute_directive_copy_path(line, content, options)
1282
+ source, destination, = options
1283
+ if source.nil? or destination.nil?
1284
+ log_input(line)
1285
+ if source.nil?
1286
+ log_error("#|e| [copy-path] source is missing")
1287
+ end
1288
+ if destiantion.nil?
1289
+ log_error("#|e| [copy-path] destination is missing")
1290
+ end
1291
+ return
1292
+ end
1293
+ source = resolve_path(Pathname(source))
1294
+ destination = resolve_path(Pathname(destination))
1295
+ FileUtils.cp_r(source.to_s, destination.to_s)
1296
+ end
1297
+
1298
+ def execute_directive(line, content)
1195
1299
  command, *options = Shellwords.split(content)
1196
1300
  case command
1197
1301
  when "disable-logging"
@@ -1199,13 +1303,14 @@ EOF
1199
1303
  when "enable-logging"
1200
1304
  @context.logging = true
1201
1305
  when "suggest-create-dataset"
1202
- dataset_name = options.first
1203
- return if dataset_name.nil?
1204
- execute_suggest_create_dataset(dataset_name)
1306
+ execute_directive_suggest_create_dataset(line, content, options)
1205
1307
  when "include"
1206
- path = options.first
1207
- return if path.nil?
1208
- execute_script(Pathname(path))
1308
+ execute_directive_include(line, content, options)
1309
+ when "copy-path"
1310
+ execute_directive_copy_path(line, content, options)
1311
+ else
1312
+ log_input(line)
1313
+ log_error("#|e| unknown directive: <#{command}>")
1209
1314
  end
1210
1315
  end
1211
1316
 
@@ -1227,10 +1332,7 @@ EOF
1227
1332
 
1228
1333
  def execute_script(script_path)
1229
1334
  executor = create_sub_executor(@context)
1230
- if script_path.relative?
1231
- script_path = @context.base_directory + script_path
1232
- end
1233
- executor.execute(script_path)
1335
+ executor.execute(resolve_path(script_path))
1234
1336
  end
1235
1337
 
1236
1338
  def execute_command_line(command_line)
@@ -1513,6 +1615,7 @@ EOF
1513
1615
  end
1514
1616
 
1515
1617
  def report_summary(result)
1618
+ puts(statistics_header)
1516
1619
  puts(colorize(statistics(result), result))
1517
1620
  pass_ratio = result.pass_ratio
1518
1621
  elapsed_time = result.elapsed_time
@@ -1520,14 +1623,28 @@ EOF
1520
1623
  puts(colorize(summary, result))
1521
1624
  end
1522
1625
 
1626
+ def statistics_header
1627
+ items = [
1628
+ "tests/sec",
1629
+ "tests",
1630
+ "passes",
1631
+ "failures",
1632
+ "leaked",
1633
+ "!checked",
1634
+ ]
1635
+ " " + ((["%-9s"] * items.size).join(" | ") % items) + " |"
1636
+ end
1637
+
1523
1638
  def statistics(result)
1524
1639
  items = [
1525
- "#{result.n_tests} tests",
1526
- "#{result.n_passed_tests} passes",
1527
- "#{result.n_failed_tests} failures",
1528
- "#{result.n_not_checked_tests} not checked_tests",
1640
+ "%9.2f" % throughput(result),
1641
+ "%9d" % result.n_tests,
1642
+ "%9d" % result.n_passed_tests,
1643
+ "%9d" % result.n_failed_tests,
1644
+ "%9d" % result.n_leaked_tests,
1645
+ "%9d" % result.n_not_checked_tests,
1529
1646
  ]
1530
- "#{throughput(result)}: " + items.join(", ")
1647
+ " " + items.join(" | ") + " |"
1531
1648
  end
1532
1649
 
1533
1650
  def throughput(result)
@@ -1536,7 +1653,7 @@ EOF
1536
1653
  else
1537
1654
  tests_per_second = result.n_tests / result.elapsed_time
1538
1655
  end
1539
- "%.2f tests/sec" % tests_per_second
1656
+ tests_per_second
1540
1657
  end
1541
1658
 
1542
1659
  def report_failure(result)
@@ -1559,8 +1676,8 @@ EOF
1559
1676
  create_temporary_file("expected", expected) do |expected_file|
1560
1677
  create_temporary_file("actual", actual) do |actual_file|
1561
1678
  diff_options = @tester.diff_options.dup
1562
- diff_options.concat(["--label", "(actual)", actual_file.path,
1563
- "--label", "(expected)", expected_file.path])
1679
+ diff_options.concat(["--label", "(expected)", expected_file.path,
1680
+ "--label", "(actual)", actual_file.path])
1564
1681
  system(@tester.diff, *diff_options)
1565
1682
  end
1566
1683
  end
@@ -1669,6 +1786,8 @@ EOF
1669
1786
  else
1670
1787
  if result.n_failed_tests > 0
1671
1788
  :failure
1789
+ elsif result.n_leaked_tests > 0
1790
+ :leaked
1672
1791
  elsif result.n_not_checked_tests > 0
1673
1792
  :not_checked
1674
1793
  else
@@ -1689,6 +1808,8 @@ EOF
1689
1808
  "%s%s%s" % [success_color, message, reset_color]
1690
1809
  when :failure
1691
1810
  "%s%s%s" % [failure_color, message, reset_color]
1811
+ when :leaked
1812
+ "%s%s%s" % [leaked_color, message, reset_color]
1692
1813
  when :not_checked
1693
1814
  "%s%s%s" % [not_checked_color, message, reset_color]
1694
1815
  else
@@ -1722,6 +1843,19 @@ EOF
1722
1843
  })
1723
1844
  end
1724
1845
 
1846
+ def leaked_color
1847
+ escape_sequence({
1848
+ :color => :magenta,
1849
+ :color_256 => [3, 0, 3],
1850
+ :background => true,
1851
+ },
1852
+ {
1853
+ :color => :white,
1854
+ :color_256 => [5, 5, 5],
1855
+ :bold => true,
1856
+ })
1857
+ end
1858
+
1725
1859
  def not_checked_color
1726
1860
  escape_sequence({
1727
1861
  :color => :cyan,
@@ -1823,7 +1957,13 @@ EOF
1823
1957
  end
1824
1958
  end
1825
1959
 
1826
- def not_check_test(worker, result)
1960
+ def leaked_test(worker, result)
1961
+ synchronize do
1962
+ report_test_result_mark("L(#{result.n_leaked_objects})", result)
1963
+ end
1964
+ end
1965
+
1966
+ def not_checked_test(worker, result)
1827
1967
  synchronize do
1828
1968
  report_test_result_mark("N", result)
1829
1969
  puts
@@ -1849,6 +1989,9 @@ EOF
1849
1989
 
1850
1990
  private
1851
1991
  def report_test_result_mark(mark, result)
1992
+ if @term_width < @current_column + mark.bytesize
1993
+ puts
1994
+ end
1852
1995
  print(colorize(mark, result))
1853
1996
  if @term_width <= @current_column
1854
1997
  puts
@@ -1892,7 +2035,11 @@ EOF
1892
2035
  report_failure(result)
1893
2036
  end
1894
2037
 
1895
- def not_check_test(worker, result)
2038
+ def leaked_test(worker, result)
2039
+ report_test_result(result, worker.status)
2040
+ end
2041
+
2042
+ def not_checked_test(worker, result)
1896
2043
  report_test_result(result, worker.status)
1897
2044
  report_actual(result)
1898
2045
  end
@@ -1945,7 +2092,14 @@ EOF
1945
2092
  end
1946
2093
  end
1947
2094
 
1948
- def not_check_test(worker, result)
2095
+ def leaked_test(worker, result)
2096
+ redraw do
2097
+ report_test(worker, result)
2098
+ report_marker(result)
2099
+ end
2100
+ end
2101
+
2102
+ def not_checked_test(worker, result)
1949
2103
  redraw do
1950
2104
  report_test(worker, result)
1951
2105
  report_actual(result)
@@ -1972,6 +2126,7 @@ EOF
1972
2126
 
1973
2127
  private
1974
2128
  def draw
2129
+ draw_statistics_header_line
1975
2130
  @test_suites_result.workers.each do |worker|
1976
2131
  draw_status_line(worker)
1977
2132
  draw_test_line(worker)
@@ -1979,6 +2134,10 @@ EOF
1979
2134
  draw_progress_line
1980
2135
  end
1981
2136
 
2137
+ def draw_statistics_header_line
2138
+ puts(statistics_header)
2139
+ end
2140
+
1982
2141
  def draw_status_line(worker)
1983
2142
  clear_line
1984
2143
  left = "[#{colorize(worker.id, worker.result)}] "
@@ -1994,7 +2153,7 @@ EOF
1994
2153
  if worker.test_name
1995
2154
  label = " #{worker.test_name}"
1996
2155
  else
1997
- label = " #{statistics(worker.result)}"
2156
+ label = statistics(worker.result)
1998
2157
  end
1999
2158
  puts(justify(label, @term_width))
2000
2159
  end
@@ -2002,7 +2161,11 @@ EOF
2002
2161
  def draw_progress_line
2003
2162
  n_done_tests = @test_suites_result.n_tests
2004
2163
  n_total_tests = @test_suites_result.n_total_tests
2005
- finished_test_ratio = n_done_tests.to_f / n_total_tests
2164
+ if n_total_tests.zero?
2165
+ finished_test_ratio = 0.0
2166
+ else
2167
+ finished_test_ratio = n_done_tests.to_f / n_total_tests
2168
+ end
2006
2169
 
2007
2170
  start_mark = "|"
2008
2171
  finish_mark = "|"
@@ -2054,7 +2217,11 @@ EOF
2054
2217
  end
2055
2218
 
2056
2219
  def n_using_lines
2057
- n_worker_lines * n_workers + n_progress_lines
2220
+ n_statistics_header_line + n_worker_lines * n_workers + n_progress_lines
2221
+ end
2222
+
2223
+ def n_statistics_header_line
2224
+ 1
2058
2225
  end
2059
2226
 
2060
2227
  def n_worker_lines
@@ -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.0.0"
17
+ VERSION = "1.0.1"
18
18
  end
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.0.0
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-08-29 00:00:00.000000000 Z
13
+ date: 2012-10-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json