grntest 1.0.0 → 1.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 +334 -35
- data/doc/text/news.md +33 -0
- data/lib/grntest/tester.rb +214 -47
- data/lib/grntest/version.rb +1 -1
- metadata +2 -2
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
|
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
|
-
##
|
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.
|
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
|
-
|
59
|
-
0
|
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
|
-
|
76
|
-
|
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.
|
107
|
+
select 0.1767s [failed]
|
107
108
|
================================================================================
|
108
|
-
--- (
|
109
|
-
+++ (
|
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:
|
115
|
-
-[[0,0.0,0.0],[[[1],[["_id","UInt32"],["_key","ShortText"]],[
|
116
|
-
+select Users --query '_key:
|
117
|
-
+[[0,0.0,0.0],[[[1],[["_id","UInt32"],["_key","ShortText"]],[
|
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
|
-
|
122
|
-
0
|
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
|
-
|
144
|
-
|
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
|
-
|
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
|
-
|
208
|
+
Here are available `NAME` s:
|
152
209
|
|
153
|
-
|
210
|
+
* `disable-logging`
|
211
|
+
* `enable-logging`
|
212
|
+
* `suggest-create-dataset`
|
213
|
+
* `include`
|
214
|
+
* `copy-path`
|
154
215
|
|
155
|
-
|
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
|
-
|
435
|
+
9.95 | 5 | 5 | 0 | 0 | 0 |
|
168
436
|
[1] [finished]
|
169
|
-
|
437
|
+
9.22 | 4 | 4 | 0 | 0 | 0 |
|
170
438
|
[2] [finished]
|
171
|
-
|
439
|
+
9.11 | 4 | 4 | 0 | 0 | 0 |
|
172
440
|
[3] [finished]
|
173
|
-
|
441
|
+
10.10 | 5 | 5 | 0 | 0 | 0 |
|
174
442
|
|-----------------------------------------------------------------------| [100%]
|
175
443
|
|
176
|
-
|
177
|
-
|
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
|
-
|
477
|
+
## Examples
|
181
478
|
|
182
|
-
See [test/
|
183
|
-
source](https://github.com/groonga/groonga/tree/master/test/
|
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
|
-
|
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
|
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!!!
|
data/lib/grntest/tester.rb
CHANGED
@@ -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.
|
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.
|
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, :
|
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
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
699
|
-
|
700
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
1207
|
-
|
1208
|
-
|
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
|
-
|
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
|
-
"
|
1526
|
-
"
|
1527
|
-
"
|
1528
|
-
"
|
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
|
-
"
|
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
|
-
|
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", "(
|
1563
|
-
"--label", "(
|
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
|
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
|
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
|
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 =
|
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
|
-
|
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
|
data/lib/grntest/version.rb
CHANGED
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.
|
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-
|
13
|
+
date: 2012-10-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json
|