groonga-query-log 1.3.7 → 1.3.8

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
  SHA256:
3
- metadata.gz: f15d15e5f0ca25ffbd6e5dee08c732a4cebb35b4ad4eaa44fcacca85e0e6b386
4
- data.tar.gz: 14b68832f85aff8c122477a5d5ed791a5545c370da51ed291588454216e3a6e9
3
+ metadata.gz: 661030b254c034e486074270e46e90f9ea593ceea13f1e648f9e7b76fe75bb3c
4
+ data.tar.gz: c8cae31736b8265e9b160019dbf0c72e0944e4e6113b94ad67a3a897e3bb240a
5
5
  SHA512:
6
- metadata.gz: b0240ddbc1584dc007f55ad7a742c6b6a7f7c643a6261f08f61bd8ba5a2359e240128d2614be6f7ce1c1be8fe034f1d22906a1222c7ceb507e929c093467b1a8
7
- data.tar.gz: a95c78d3864012a3711dd3ff2e0d54bab936fafdfd4a2fadafc04131e437272ee057221a16f07fa5f6e8478492ac97fa547a872fe075724800b43d0e34a2fd41
6
+ metadata.gz: 821547ca78bda0bc51ea23f12c0f1d72d3bbec079e96ed24884791b355279d9904f5a2a2e03b3f064bc3ca13d519df3be30153effaa530686659bfaf0235780c
7
+ data.tar.gz: fb253f2e4d5d50c6a4f0cc056b7b270647733d6c4b1f99e85316ac30f41f41944bcdfca74060d166f3f6da2094bf8727db6fafe91214aa4ee59abf33c22708c9
@@ -1,5 +1,41 @@
1
1
  # News
2
2
 
3
+ ## 1.3.8: 2018-10-18
4
+
5
+ ### Improvements
6
+
7
+ * `groonga-query-log-verify-server`:
8
+
9
+ * Changed to flush logs as soon as possible.
10
+
11
+ * Added `--vector-not-equal-empty-string` option.
12
+
13
+ * Added support an unification for `"null"` and `null` column types.
14
+
15
+ * `groonga-query-log-run-regression-test`:
16
+
17
+ * Changed to flush logs as soon as possible.
18
+
19
+ * Added support for rewriting `vector == ...` with `vector @ ...`.
20
+
21
+ * Added support for logging rewriting filters.
22
+
23
+ * Added `--vector-not-equal-empty-string` option.
24
+
25
+ * Added support an unification for `"null"` and `null` column types.
26
+
27
+ ### Fixes
28
+
29
+ * `groonga-query-log-verify-server`:
30
+
31
+ * Fixed a bug that logged contents are removed with `.tar.gz`
32
+ query log.
33
+
34
+ * `groonga-query-log-run-regression-test`:
35
+
36
+ * Fixed a bug that logged contents are removed with `.tar.gz`
37
+ query log.
38
+
3
39
  ## 1.3.7: 2018-09-11
4
40
 
5
41
  ### Improvements
@@ -45,6 +45,9 @@ module GroongaQueryLog
45
45
  @skip_finished_queries = false
46
46
  @output_query_log = false
47
47
  @stop_on_failure = false
48
+ @rewrite_vector_equal = false
49
+ @rewrite_vector_not_equal_empty_string = false
50
+ @vector_accessors = []
48
51
 
49
52
  @care_order = true
50
53
  @ignored_drilldown_keys = []
@@ -151,6 +154,22 @@ module GroongaQueryLog
151
154
  "(#{@stop_on_failure})") do |boolean|
152
155
  @stop_on_failure = boolean
153
156
  end
157
+ parser.on("--[no-]rewrite-vector-equal",
158
+ "Rewrite 'vector == ...' with 'vector @ ...'",
159
+ "(#{@rewrite_vector_equal})") do |boolean|
160
+ @rewrite_vector_equal = boolean
161
+ end
162
+ parser.on("--[no-]rewrite-vector-not-equal-empty-string",
163
+ "Rewrite 'vector != \"\"' with 'false'",
164
+ "(#{@rewrite_vector_not_equal_empty_string})") do |boolean|
165
+ @rewrite_vector_not_equal_empty_string = boolean
166
+ end
167
+ parser.on("--vector-accessor=ACCESSOR",
168
+ "Mark ACCESSOR as rewrite vector targets",
169
+ "You can specify multiple vector accessors by",
170
+ "specifying this option multiple times") do |accessor|
171
+ @vector_accessors << accessor
172
+ end
154
173
 
155
174
  parser.separator("")
156
175
  parser.separator("Comparisons:")
@@ -208,6 +227,10 @@ module GroongaQueryLog
208
227
  :skip_finished_queries => @skip_finished_queries,
209
228
  :ignored_drilldown_keys => @ignored_drilldown_keys,
210
229
  :stop_on_failure => @stop_on_failure,
230
+ :rewrite_vector_equal => @rewrite_vector_equal,
231
+ :rewrite_vector_not_equal_empty_string =>
232
+ @rewrite_vector_not_equal_empty_string,
233
+ :vector_accessors => @vector_accessors,
211
234
  :target_command_names => @target_command_names,
212
235
  :read_timeout => @read_timeout,
213
236
  }
@@ -228,7 +251,16 @@ module GroongaQueryLog
228
251
  server_options)
229
252
  end
230
253
 
254
+ module Loggable
255
+ def puts(*args)
256
+ $stdout.puts(*args)
257
+ $stdout.flush
258
+ end
259
+ end
260
+
231
261
  class GroongaServer
262
+ include Loggable
263
+
232
264
  attr_reader :host, :port
233
265
  def initialize(groonga, groonga_options, database_path, options)
234
266
  @input_directory = options[:input_directory] || Pathname.new(".")
@@ -369,6 +401,8 @@ module GroongaQueryLog
369
401
  end
370
402
 
371
403
  class Tester
404
+ include Loggable
405
+
372
406
  def initialize(old, new, options)
373
407
  @old = old
374
408
  @new = new
@@ -473,6 +507,17 @@ module GroongaQueryLog
473
507
  if @stop_on_failure
474
508
  command_line << "--stop-on-failure"
475
509
  end
510
+ if @options[:rewrite_vector_equal]
511
+ command_line << "--rewrite-vector-equal"
512
+ end
513
+ if @options[:rewrite_vector_not_equal_empty_string]
514
+ command_line << "--rewrite-vector-not-equal-empty-string"
515
+ end
516
+ vector_accessors = @options[:vector_accessors] || []
517
+ vector_accessors.each do |vector_accessor|
518
+ command_line << "--vector-accessor"
519
+ command_line << vector_accessor
520
+ end
476
521
  if @options[:target_command_names]
477
522
  command_line << "--target-command-names"
478
523
  command_line << @options[:target_command_names].join(",")
@@ -201,6 +201,25 @@ module GroongaQueryLog
201
201
  @options.stop_on_failure = boolean
202
202
  end
203
203
 
204
+ parser.on("--[no-]rewrite-vector-equal",
205
+ "Rewrite 'vector == ...' with 'vector @ ...'",
206
+ "(#{@options.rewrite_vector_equal?})") do |boolean|
207
+ @options.rewrite_vector_equal = boolean
208
+ end
209
+
210
+ parser.on("--[no-]rewrite-vector-not-equal-empty-string",
211
+ "Rewrite 'vector != \"\"' with 'false'",
212
+ "(#{@options.rewrite_vector_not_equal_empty_string?})") do |boolean|
213
+ @options.rewrite_vector_not_equal_empty_string = boolean
214
+ end
215
+
216
+ parser.on("--vector-accessor=ACCESSOR",
217
+ "Mark ACCESSOR as rewrite vector targets",
218
+ "You can specify multiple vector accessors by",
219
+ "specifying this option multiple times") do |accessor|
220
+ @options.vector_accessors << accessor
221
+ end
222
+
204
223
  parser.separator("Debug options:")
205
224
  parser.separator("")
206
225
 
@@ -0,0 +1,59 @@
1
+ # Copyright (C) 2018 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ module GroongaQueryLog
18
+ class FilterRewriter
19
+ def initialize(filter, options={})
20
+ @filter = filter
21
+ @options = options
22
+ @vector_accessors = @options[:vector_accessors] || []
23
+ end
24
+
25
+ def rewrite
26
+ rewritten = @filter
27
+ if @options[:rewrite_vector_equal]
28
+ rewritten = rewrite_vector_equal(rewritten)
29
+ end
30
+ if @options[:rewrite_vector_not_equal_empty_string]
31
+ rewritten = rewrite_vector_not_equal_empty_string(rewritten)
32
+ end
33
+ rewritten
34
+ end
35
+
36
+ private
37
+ def rewrite_vector_equal(filter)
38
+ filter.gsub(/([a-zA-Z0-9_.]+) *==/) do |matched|
39
+ variable = $1
40
+ if @vector_accessors.include?(variable)
41
+ "#{variable} @"
42
+ else
43
+ matched
44
+ end
45
+ end
46
+ end
47
+
48
+ def rewrite_vector_not_equal_empty_string(filter)
49
+ filter.gsub(/([a-zA-Z0-9_.]+) *!= *(?:''|"")/) do |matched|
50
+ variable = $1
51
+ if @vector_accessors.include?(variable)
52
+ "false"
53
+ else
54
+ matched
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -113,8 +113,8 @@ module GroongaQueryLog
113
113
  n_hits2 = records_result2[0]
114
114
  return false if n_hits1 != n_hits2
115
115
 
116
- columns1 = records_result1[1]
117
- columns2 = records_result2[1]
116
+ columns1 = normalize_columns(records_result1[1])
117
+ columns2 = normalize_columns(records_result2[1])
118
118
  if all_output_columns?
119
119
  columns1.sort_by(&:first) == columns2.sort_by(&:first)
120
120
  else
@@ -137,8 +137,8 @@ module GroongaQueryLog
137
137
  n_hits2 = records_result2[0]
138
138
  return false if n_hits1 != n_hits2
139
139
 
140
- columns1 = records_result1[1]
141
- columns2 = records_result2[1]
140
+ columns1 = normalize_columns(records_result1[1])
141
+ columns2 = normalize_columns(records_result2[1])
142
142
  records1 = records_result1[2..-1]
143
143
  records2 = records_result2[2..-1]
144
144
 
@@ -185,8 +185,8 @@ module GroongaQueryLog
185
185
  n_hits2 = records_result2[0]
186
186
  return false if n_hits1 != n_hits2
187
187
 
188
- columns1 = records_result1[1]
189
- columns2 = records_result2[1]
188
+ columns1 = normalize_columns(records_result1[1])
189
+ columns2 = normalize_columns(records_result2[1])
190
190
  return false if columns1.sort_by(&:first) != columns2.sort_by(&:first)
191
191
 
192
192
  column_to_index1 = make_column_to_index_map(columns1)
@@ -223,8 +223,8 @@ module GroongaQueryLog
223
223
  n_hits2 = record_set2[0]
224
224
  return false if n_hits1 != n_hits2
225
225
 
226
- columns1 = record_set1[1]
227
- columns2 = record_set2[1]
226
+ columns1 = normalize_columns(record_set1[1])
227
+ columns2 = normalize_columns(record_set2[1])
228
228
  return false if columns1 != columns2
229
229
 
230
230
  records1 = record_set1[2..-1]
@@ -282,6 +282,13 @@ module GroongaQueryLog
282
282
  true
283
283
  end
284
284
 
285
+ def normalize_columns(columns)
286
+ columns.collect do |name, type|
287
+ type = nil if type == "null"
288
+ [name, type]
289
+ end
290
+ end
291
+
285
292
  def normalize_value(value, column)
286
293
  type = column[1]
287
294
  case type
@@ -19,6 +19,7 @@ require "thread"
19
19
 
20
20
  require "groonga/client"
21
21
 
22
+ require "groonga-query-log/filter-rewriter"
22
23
  require "groonga-query-log/parser"
23
24
  require "groonga-query-log/response-comparer"
24
25
 
@@ -118,7 +119,7 @@ module GroongaQueryLog
118
119
 
119
120
  def run_reporter
120
121
  Thread.new do
121
- @options.create_output do |output|
122
+ @options.open_output do |output|
122
123
  loop do
123
124
  result = @different_results.pop
124
125
  break if result.nil?
@@ -135,6 +136,8 @@ module GroongaQueryLog
135
136
  def verify_command(groonga1_client, groonga2_client, command)
136
137
  command["cache"] = "no" if @options.disable_cache?
137
138
  command["output_type"] = "json"
139
+ rewrite_filter(command, "filter")
140
+ rewrite_filter(command, "scorer")
138
141
  response1 = groonga1_client.execute(command)
139
142
  response2 = groonga2_client.execute(command)
140
143
  compare_options = {
@@ -148,6 +151,21 @@ module GroongaQueryLog
148
151
  end
149
152
  end
150
153
 
154
+ def rewrite_filter(command, name)
155
+ target = command[name]
156
+ return if target.nil?
157
+ return unless @options.need_filter_rewrite?
158
+
159
+ rewriter = FilterRewriter.new(target, @options.to_filter_rewriter_options)
160
+ rewritten_target = rewriter.rewrite
161
+ return if target == rewritten_target
162
+
163
+ $stderr.puts("Rewritten #{name}")
164
+ $stderr.puts(" Before: #{target}")
165
+ $stderr.puts(" After: #{rewritten_target}")
166
+ command[name] = rewritten_target
167
+ end
168
+
151
169
  def report_result(output, result)
152
170
  @same = false
153
171
  command, response1, response2 = result
@@ -155,6 +173,7 @@ module GroongaQueryLog
155
173
  output.puts("command: #{command_source}")
156
174
  output.puts("response1: #{response1.body.to_json}")
157
175
  output.puts("response2: #{response2.body.to_json}")
176
+ output.flush
158
177
  end
159
178
 
160
179
  def log_client_error(error)
@@ -181,6 +200,9 @@ module GroongaQueryLog
181
200
  attr_writer :verify_cache
182
201
  attr_accessor :ignored_drilldown_keys
183
202
  attr_writer :stop_on_failure
203
+ attr_writer :rewrite_vector_equal
204
+ attr_writer :rewrite_vector_not_equal_empty_string
205
+ attr_accessor :vector_accessors
184
206
  def initialize
185
207
  @groonga1 = GroongaOptions.new
186
208
  @groonga2 = GroongaOptions.new
@@ -188,6 +210,7 @@ module GroongaQueryLog
188
210
  @request_queue_size = nil
189
211
  @disable_cache = false
190
212
  @output_path = nil
213
+ @output_opened = false
191
214
  @target_command_names = [
192
215
  "io_flush",
193
216
  "logical_count",
@@ -203,6 +226,9 @@ module GroongaQueryLog
203
226
  @verify_cache = false
204
227
  @ignored_drilldown_keys = []
205
228
  @stop_on_failure = false
229
+ @rewrite_vector_equal = false
230
+ @rewrite_vector_not_equal_empty_string = false
231
+ @vector_accessors = []
206
232
  end
207
233
 
208
234
  def request_queue_size
@@ -221,6 +247,14 @@ module GroongaQueryLog
221
247
  @stop_on_failure
222
248
  end
223
249
 
250
+ def rewrite_vector_equal?
251
+ @rewrite_vector_equal
252
+ end
253
+
254
+ def rewrite_vector_not_equal_empty_string?
255
+ @rewrite_vector_not_equal_empty_string
256
+ end
257
+
224
258
  def target_command_name?(name)
225
259
  return false if name.nil?
226
260
 
@@ -231,14 +265,34 @@ module GroongaQueryLog
231
265
  end
232
266
  end
233
267
 
234
- def create_output(&block)
268
+ def open_output(&block)
235
269
  if @output_path
236
- FileUtils.mkdir_p(File.dirname(@output_path))
237
- File.open(@output_path, "w", &block)
270
+ if @output_opened
271
+ mode = "a"
272
+ else
273
+ FileUtils.mkdir_p(File.dirname(@output_path))
274
+ mode = "w"
275
+ @output_opened = true
276
+ end
277
+ File.open(@output_path, mode, &block)
238
278
  else
239
279
  yield($stdout)
240
280
  end
241
281
  end
282
+
283
+ def need_filter_rewrite?
284
+ rewrite_vector_equal? or
285
+ rewrite_vector_not_equal_empty_string?
286
+ end
287
+
288
+ def to_filter_rewriter_options
289
+ {
290
+ :rewrite_vector_equal => rewrite_vector_equal?,
291
+ :rewrite_vector_not_equal_empty_string =>
292
+ rewrite_vector_not_equal_empty_string?,
293
+ :vector_accessors => vector_accessors,
294
+ }
295
+ end
242
296
  end
243
297
 
244
298
  class GroongaOptions
@@ -15,5 +15,5 @@
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
  module GroongaQueryLog
18
- VERSION = "1.3.7"
18
+ VERSION = "1.3.8"
19
19
  end
@@ -0,0 +1,75 @@
1
+ # Copyright (C) 2018 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ class FilterRewriterTest < Test::Unit::TestCase
18
+ private
19
+ def rewrite(filter, options)
20
+ rewriter = GroongaQueryLog::FilterRewriter.new(filter, options)
21
+ rewriter.rewrite
22
+ end
23
+
24
+ class VectorEqualTest < self
25
+ def rewrite(filter, vector_accessors)
26
+ super(filter,
27
+ :rewrite_vector_equal => true,
28
+ :vector_accessors => vector_accessors)
29
+ end
30
+
31
+ def test_not_target_accessor
32
+ assert_equal("vector == \"value\"",
33
+ rewrite("vector == \"value\"",
34
+ ["nonexistent"]))
35
+ end
36
+
37
+ def test_parenthesis
38
+ assert_equal("((vector @ \"value\"))",
39
+ rewrite("((vector == \"value\"))",
40
+ ["vector"]))
41
+ end
42
+
43
+ def test_under_score
44
+ assert_equal("vector_column @ \"value\"",
45
+ rewrite("vector_column == \"value\"",
46
+ ["vector_column"]))
47
+ end
48
+ end
49
+
50
+ class VectorNotEqualEmptyStringTest < self
51
+ def rewrite(filter, vector_accessors)
52
+ super(filter,
53
+ :rewrite_vector_not_equal_empty_string => true,
54
+ :vector_accessors => vector_accessors)
55
+ end
56
+
57
+ def test_not_target_accessor
58
+ assert_equal("vector != \"\"",
59
+ rewrite("vector != \"\"",
60
+ ["nonexistent"]))
61
+ end
62
+
63
+ def test_parenthesis
64
+ assert_equal("((false))",
65
+ rewrite("((vector != \"\"))",
66
+ ["vector"]))
67
+ end
68
+
69
+ def test_under_score
70
+ assert_equal("false",
71
+ rewrite("vector_column != \"\"",
72
+ ["vector_column"]))
73
+ end
74
+ end
75
+ end
@@ -363,6 +363,54 @@ class ResponseComparerTest < Test::Unit::TestCase
363
363
  end
364
364
  end
365
365
 
366
+ class ColumnType < self
367
+ class Null < self
368
+ def create_response(type)
369
+ [
370
+ [
371
+ [1],
372
+ [["snippet_html", type]],
373
+ ["...snippet..."],
374
+ ]
375
+ ]
376
+ end
377
+
378
+ def test_all_output_columns
379
+ response1 = create_response("null")
380
+ response2 = create_response(nil)
381
+ assert do
382
+ same?(response1, response2)
383
+ end
384
+ end
385
+
386
+ def test_unary_minus_output_column
387
+ @command["output_columns"] = "-value, snippet_html(body)"
388
+ response1 = create_response("null")
389
+ response2 = create_response(nil)
390
+ assert do
391
+ same?(response1, response2)
392
+ end
393
+ end
394
+
395
+ def test_specific_output_column
396
+ @command["output_columns"] = "snippet_html(body)"
397
+ response1 = create_response("null")
398
+ response2 = create_response(nil)
399
+ assert do
400
+ same?(response1, response2)
401
+ end
402
+ end
403
+
404
+ def test_not_care_order
405
+ response1 = create_response("null")
406
+ response2 = create_response(nil)
407
+ assert do
408
+ same?(response1, response2, care_order: false)
409
+ end
410
+ end
411
+ end
412
+ end
413
+
366
414
  class DrilldownTest < self
367
415
  def create_response(drilldown)
368
416
  [
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: groonga-query-log
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.7
4
+ version: 1.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kouhei Sutou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-11 00:00:00.000000000 Z
11
+ date: 2018-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: groonga-command-parser
@@ -224,6 +224,7 @@ files:
224
224
  - lib/groonga-query-log/command/run-regression-test.rb
225
225
  - lib/groonga-query-log/command/show-running-queries.rb
226
226
  - lib/groonga-query-log/command/verify-server.rb
227
+ - lib/groonga-query-log/filter-rewriter.rb
227
228
  - lib/groonga-query-log/incompatibility-detector.rb
228
229
  - lib/groonga-query-log/memory-leak-detector.rb
229
230
  - lib/groonga-query-log/parser.rb
@@ -289,6 +290,7 @@ files:
289
290
  - test/fixtures/target-tables.expected
290
291
  - test/helper.rb
291
292
  - test/run-test.rb
293
+ - test/test-filter-rewriter.rb
292
294
  - test/test-incompatibility-detector.rb
293
295
  - test/test-parser.rb
294
296
  - test/test-replayer.rb
@@ -321,6 +323,7 @@ summary: Groonga-query-log is a collection of library and tools to process [Groo
321
323
  as a library. You can analyze your Groonga's queries and test with your Groonga's
322
324
  query log by using groonga-query-log as a tool.
323
325
  test_files:
326
+ - test/test-filter-rewriter.rb
324
327
  - test/fixtures/multi.expected
325
328
  - test/fixtures/target-tables.expected
326
329
  - test/fixtures/target-commands.expected