groonga-query-log 1.0.4 → 1.0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 05b507ee733fc255cabbb5cf09e7d050460ed282
4
- data.tar.gz: 18b939521cb5c1568f7a3cb7d5cce3aee9042bd8
3
+ metadata.gz: 7baac32f5f72c344206d735fa04ab18fad813424
4
+ data.tar.gz: b81cf03d7eac23d3b6701b2539baddb6a794bf2b
5
5
  SHA512:
6
- metadata.gz: 102d611f9a0ca59eaef084a138849cd4ee13cf9b7e7fca2ee9921b3cbe3a9b33fd0024aaa6b3ce80e9996ab9f3e8c0e948d1fd081b1e60fe74f237f6bd9be3ad
7
- data.tar.gz: 5e59087eca3bda7a8488be18c9b747ef08e90ad47bc2a24f22fee0d71ebdf78a249f3da4030ee04893f189600cc2343ac860a26643506fd39e257bd613a3f839
6
+ metadata.gz: a945b55c42cb1b483a178fc8e0d5f3ee87392bd16775df48599498d26cfcefcce66e7a7b4eae5ce7ed0ca4f41cb0ecc4ef74fa332fb05dbcba0b6fcc480548b8
7
+ data.tar.gz: 886297948bbe6b312cd88258498564701cfdf218124d14c68bf8313941b6e01efd7fdab9d4ee53c95e4fe2714a506cee204db0ea01fccaa5829759a300f18175
data/README.md CHANGED
@@ -9,9 +9,9 @@ groonga-query-log
9
9
  ## Description
10
10
 
11
11
  Groonga-query-log is a collection of library and tools to process
12
- [groonga](http://groonga.org/)'s query log. You can write a program to
12
+ [Groonga](http://groonga.org/)'s query log. You can write a program to
13
13
  process query log by using groonga-query-log as a library. You can
14
- analyze your groonga's queries and test with your groonga's query log
14
+ analyze your Groonga's queries and test with your Groonga's query log
15
15
  by using groonga-query-log as a tool.
16
16
 
17
17
  ## Install
@@ -20,28 +20,52 @@ by using groonga-query-log as a tool.
20
20
 
21
21
  ## Usage
22
22
 
23
+ ### groonga-query-log-analyze
24
+
25
+ TODO...
26
+
27
+ ### groonga-query-log-detect-memory-leak
28
+
23
29
  TODO...
24
30
 
25
- ## Examples
31
+ ### groonga-query-log-extract
26
32
 
27
33
  TODO...
28
34
 
35
+ ### groonga-query-log-replay
36
+
37
+ TODO...
38
+
39
+ ### groonga-query-log-run-regression-test
40
+
41
+ TODO...
42
+
43
+ ### groonga-query-log-verify-server
44
+
45
+ TODO...
46
+
47
+ ### groonga-query-log-run-regression-test
48
+
49
+ * [doc/text/run-regression-test.md](doc/text/run-regression-test.md)
50
+
29
51
  ## Dependencies
30
52
 
31
- * Ruby
53
+ * Ruby
54
+ * [groonga-command-parser](http://rubygems.org/gems/groonga-command-parser)
55
+ * [groonga-client](http://rubygems.org/gems/groonga-client)
32
56
 
33
57
  ## Mailing list
34
58
 
35
- * English: [groonga-talk@lists.sourceforge.net](https://lists.sourceforge.net/lists/listinfo/groonga-talk)
36
- * Japanese: [groonga-dev@lists.sourceforge.jp](http://lists.sourceforge.jp/mailman/listinfo/groonga-dev)
59
+ * English: [groonga-talk@lists.sourceforge.net](https://lists.sourceforge.net/lists/listinfo/groonga-talk)
60
+ * Japanese: [groonga-dev@lists.sourceforge.jp](http://lists.sourceforge.jp/mailman/listinfo/groonga-dev)
37
61
 
38
62
  ## Thanks
39
63
 
40
- * ...
64
+ * ...
41
65
 
42
66
  ## Authors
43
67
 
44
- * Kouhei Sutou \<kou@clear-code.com\>
68
+ * Kouhei Sutou \<kou@clear-code.com\>
45
69
 
46
70
  ## License
47
71
 
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+
20
+ require "groonga/query-log/command/run-regression-test"
21
+
22
+ command = Groonga::QueryLog::Command::RunRegressionTest.new
23
+ command.run(*ARGV)
data/doc/text/news.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # News
2
2
 
3
+ ## 1.0.5: 2014-05-12
4
+
5
+ ### Improvements
6
+
7
+ * groonga-query-log-verify-server: Supported `groonga-client` 0.0.8.
8
+ * groonga-query-log-verify-server: Supported comparing errors.
9
+ * groonga-query-log-run-regression-test: Added a command that
10
+ runs regression test. It is based on groonga-query-log-verify-server.
11
+
3
12
  ## 1.0.4: 2014-02-09
4
13
 
5
14
  ### Improvements
@@ -0,0 +1,189 @@
1
+ # `groonga-query-log-run-regression-test`
2
+
3
+ `groonga-query-log-run-regression-test` is a regression test tool for
4
+ Groonga. It is useful when you upgrade Groonga. You can compare search
5
+ results by old Groonga and new Groonga by
6
+ `groonga-query-log-run-regression-test`. Test queries are read from
7
+ query logs. You can use query logs on production environment as is.
8
+
9
+ ## Flow
10
+
11
+ Here is a work flow to run regression test with
12
+ `groonga-query-log-run-regression-test`:
13
+
14
+ 1. Prepare schema.
15
+ 2. Prepare data.
16
+ 3. Prepare query logs.
17
+ 4. Load schema into both old Groonga and new Groonga.
18
+ 5. Load data into both old Groonga and new Groonga.
19
+ 6. Send a request extracted from a query log to both old Groonga and
20
+ new Groonga.
21
+ 7. Compare responses from old Groonga and new Groonga.
22
+ 8. Repeat 6. and 7. for all request in query logs.
23
+
24
+ If there is any regression, you can find it by the 7. step.
25
+
26
+ ## Usage
27
+
28
+ This section describe how to use
29
+ `groonga-query-log-run-regression-test`.
30
+
31
+ First, you need to prepare input data. Then you can run regression
32
+ test.
33
+
34
+ ### Prepare
35
+
36
+ This section describes how to prepare to run regression test.
37
+
38
+ Create a directory that has the following structure:
39
+
40
+ .
41
+ |-- schema/
42
+ |-- indexes/
43
+ |-- data/
44
+ `-- query-logs/
45
+
46
+ The following sections describe how to prepare the directories.
47
+
48
+ #### `schema/`
49
+
50
+ Put database schema definitions to `schema/` directory. Each file must
51
+ have `.grn` extension such as `ddl.grn`.
52
+
53
+ You can generate a file to be placed into `schema/` from an existing
54
+ Groonga database by `grndump` command:
55
+
56
+ % grndump --no-dump-indexes --no-dump-tables /groonga/db > schema/ddl.grn
57
+
58
+ Note that `grndump` command is provided by Rroonga. You can install
59
+ Rroonga by the following command:
60
+
61
+ % gem install rroonga
62
+
63
+ #### `indexes/`
64
+
65
+ Put index definitions to `indexes/` directory. Each file must have
66
+ `.grn` extension such as `indexes.grn`.
67
+
68
+ You can put index definitions to `schema/` directory. But it is better
69
+ that put index definitions to `indexes/` directory rather than
70
+ `schema/` directory. Because it is faster.
71
+
72
+ If you use `indexes/` directory, you can use
73
+ [offline index construction][]. Offline index construction is 10 times
74
+ faster than [online index construction][].
75
+
76
+ You can generate a file to be placed into `indexes/` from an existing
77
+ Groonga database by `grndump` command:
78
+
79
+ % grndump --no-dump-schema --no-dump-tables /groonga/db > indexes/indexes.grn
80
+
81
+ #### `data/`
82
+
83
+ Put data to `data/` directory. Each file must have `.grn` extension
84
+ such as `data.grn`.
85
+
86
+ You can generate a file to be placed into `data/` from an existing
87
+ Groonga database by `grndump` command:
88
+
89
+ % grndump --no-dump-schema --no-dump-indexes /groonga/db > data/data.grn
90
+
91
+ #### `query-logs/`
92
+
93
+ Put query logs to `query-logs/` directory. Each file must have `.log`
94
+ extension such as `query.log`.
95
+
96
+ You can put multiple log files like the following:
97
+
98
+ query-logs/
99
+ |-- query-20140506.log
100
+ |-- query-20140507.log
101
+ `-- query-20140508.log
102
+
103
+ Here are links to documents that describe how to create a query log:
104
+
105
+ * Groonga server users: You can create a query log file by using
106
+ `--query-log-path` option. See [groonga command][] documentation
107
+ for details.
108
+ * Groonga HTTPD users: You can create a query log file by using
109
+ `groonga_query_log_path` directive. See [groonga_query_log_path][] documentation
110
+ for details.
111
+
112
+ ### Run
113
+
114
+ Now, you can run regression test.
115
+
116
+ Let the followings:
117
+
118
+ * Use `~/groonga/test` as the working directory to run
119
+ regression test.
120
+ * There is the current Groonga database at `/var/lib/groonga/db`.
121
+ * There are the current query logs at `/var/log/groonga/query-*.log`.
122
+ * The current Groonga is installed at `/opt/groonga-current/bin/groonga`.
123
+ * The new Groonga is installed at `/opt/groonga-new/bin/groonga`.
124
+
125
+ Install required packages:
126
+
127
+ % gem install rroonga groonga-query-log
128
+
129
+ Prepare the working directory:
130
+
131
+ % mkdir -p ~/groonga/test/{schema,indexes,data,query-logs}
132
+ % cd ~/groonga/test/
133
+
134
+ Extract needed data from the current database:
135
+
136
+ % grndump --no-dump-indexes --no-dump-tables /var/lib/groonga/db > schema/ddl.grn
137
+ % grndump --no-dump-schema --no-dump-tables /var/lib/groonga/db > indexes/indexes.grn
138
+ % grndump --no-dump-schema --no-dump-indexes /var/lib/groonga/db > data/data.grn
139
+ % cp /var/log/groonga/query-*.log query-logs/
140
+
141
+ Run regression test:
142
+
143
+ % groonga-query-log-run-regression-test \
144
+ --old-groonga=/opt/groonga-current/bin/groonga \
145
+ --new-groonga=/opt/groonga-new/bin/groonga
146
+
147
+ It creates new two databases from input data. One is created by the
148
+ current Groonga. Another is created by the new Groonga.
149
+
150
+ It starts to send requests in a query log to both Groonga servers
151
+ after databases are created. If responses don't have difference, the
152
+ request isn't a problem. If responses have any difference, the request
153
+ may be a problem.
154
+
155
+ You can find details about requests that generate different response in test
156
+ result logs. You can find test result logs under `results/`
157
+ directory. Test result log file name is the same as input query log
158
+ file name. If query log file is `query-logs/query-20140508.log`, test
159
+ result log file is `results/query-20140508.log`.
160
+
161
+ ## Advanced usage
162
+
163
+ There are some advanced usages. This section describes about them.
164
+
165
+ ### `--n-clients`
166
+
167
+ If your machine has free resource, you can speed up a regression test.
168
+
169
+ Use `--n-clients` option to send multiple requests concurrently. It
170
+ will reduce execution time.
171
+
172
+ Here is a sample command line to use `--n-clients`:
173
+
174
+ % groonga-query-log-run-regression-test \
175
+ --n-clients=4 \
176
+ --old-groonga=/opt/groonga-current/bin/groonga \
177
+ --new-groonga=/opt/groonga-new/bin/groonga
178
+
179
+ ## Conclusion
180
+
181
+ You can run regression test with
182
+ `groonga-query-log-run-regression-test`. It helps you to upgrade
183
+ Groonga safely by confirming a new Groonga doesn't have problem with
184
+ your data.
185
+
186
+ [online index construction]: http://groonga.org/docs/reference/indexing.html#online-index-construction
187
+ [offline index construction]: http://groonga.org/docs/reference/indexing.html#offline-index-construction
188
+ [groonga command]: http://groonga.org/docs/reference/executables/groonga.html
189
+ [groonga_query_log_path]: http://groonga.org/docs/reference/executables/groonga-httpd.html#groonga-query-log-path
@@ -0,0 +1,375 @@
1
+ # Copyright (C) 2014 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
+ require "rbconfig"
18
+ require "optparse"
19
+ require "socket"
20
+ require "fileutils"
21
+ require "pathname"
22
+ require "net/http"
23
+
24
+ require "groonga/query-log"
25
+ require "groonga/query-log/command/verify-server"
26
+
27
+ module Groonga
28
+ module QueryLog
29
+ module Command
30
+ class RunRegressionTest
31
+ def initialize
32
+ @input_directory = Pathname.new(".")
33
+ @working_directory = Pathname.new(".")
34
+
35
+ @old_groonga = "groonga"
36
+ @old_database = "db.old/db"
37
+
38
+ @new_groonga = "groonga"
39
+ @new_database = "db.new/db"
40
+
41
+ @recreate_database = false
42
+ @load_data = true
43
+ @run_queries = true
44
+ @skip_finished_queries = false
45
+ end
46
+
47
+ def run(*command_line)
48
+ option_parser = create_option_parser
49
+ begin
50
+ option_parser.parse!(command_line)
51
+ rescue OptionParser::ParseError => error
52
+ $stderr.puts(error.message)
53
+ return false
54
+ end
55
+
56
+ tester = Tester.new(old_groonga_server,
57
+ new_groonga_server,
58
+ tester_options)
59
+ tester.run
60
+ end
61
+
62
+ private
63
+ def create_option_parser
64
+ parser = OptionParser.new
65
+ parser.version = VERSION
66
+
67
+ parser.separator("")
68
+ parser.separator("Path:")
69
+ parser.on("--input-directory=DIRECTORY",
70
+ "Load schema and data from DIRECTORY.",
71
+ "(#{@input_directory})") do |directory|
72
+ @input_directory = Pathname.new(directory)
73
+ end
74
+ parser.on("--working-directory=DIRECTORY",
75
+ "Use DIRECTORY as working directory.",
76
+ "(#{@working_directory})") do |directory|
77
+ @working_directory = Pathname.new(directory)
78
+ end
79
+
80
+ parser.separator("")
81
+ parser.separator("Throughput:")
82
+ parser.on("--n-clients=N", Integer,
83
+ "Use N clients concurrently.",
84
+ "(#{@n_clients})") do |n|
85
+ @n_clients = n
86
+ end
87
+
88
+ parser.separator("")
89
+ parser.separator("Old Groonga:")
90
+ parser.on("--old-groonga=GROONGA",
91
+ "Old groonga command",
92
+ "(#{@old_groonga})") do |groonga|
93
+ @old_groonga = groonga
94
+ end
95
+
96
+ parser.separator("")
97
+ parser.separator("New Groonga:")
98
+ parser.on("--new-groonga=GROONGA",
99
+ "New groonga command",
100
+ "(#{@new_groonga})") do |groonga|
101
+ @new_groonga = groonga
102
+ end
103
+
104
+ parser.separator("")
105
+ parser.separator("Operations:")
106
+ parser.on("--recreate-database",
107
+ "Always recreate Groonga database") do
108
+ @recreate_database = true
109
+ end
110
+ parser.on("--no-load-data",
111
+ "Don't load data. Just loads schema to Groonga database") do
112
+ @load_data = false
113
+ end
114
+ parser.on("--no-run-queries",
115
+ "Don't run queries. Just creates Groonga database") do
116
+ @run_queries = false
117
+ end
118
+ parser.on("--skip-finished-queries",
119
+ "Don't run finished query logs.") do
120
+ @skip_finished_queries = true
121
+ end
122
+
123
+ parser
124
+ end
125
+
126
+ def directory_options
127
+ {
128
+ :input_directory => @input_directory,
129
+ :working_directory => @working_directory,
130
+ }
131
+ end
132
+
133
+ def server_options
134
+ options = {
135
+ :load_data => @load_data,
136
+ :run_queries => @run_queries,
137
+ :recreate_database => @recreate_database,
138
+ :skip_finished_queries => @skip_finished_queries,
139
+ }
140
+ directory_options.merge(options)
141
+ end
142
+
143
+ def tester_options
144
+ options = {
145
+ :n_clients => @n_clients,
146
+ }
147
+ directory_options.merge(options)
148
+ end
149
+
150
+ def old_groonga_server
151
+ GroongaServer.new(@old_groonga,
152
+ @old_database,
153
+ server_options)
154
+ end
155
+
156
+ def new_groonga_server
157
+ GroongaServer.new(@new_groonga,
158
+ @new_database,
159
+ server_options)
160
+ end
161
+
162
+ class GroongaServer
163
+ attr_reader :host, :port
164
+ def initialize(groonga, database_path, options)
165
+ @input_directory = options[:input_directory] || Pathname.new(".")
166
+ @working_directory = options[:working_directory] || Pathname.new(".")
167
+ @groonga = groonga
168
+ @database_path = @working_directory + database_path
169
+ @host = "127.0.0.1"
170
+ @port = find_unused_port
171
+ @options = options
172
+ end
173
+
174
+ def run
175
+ ensure_database
176
+ return unless @options[:run_queries]
177
+
178
+ @pid = spawn(@groonga,
179
+ "--bind-address", @host,
180
+ "--port", @port.to_s,
181
+ "--log-path", log_path.to_s,
182
+ "--query-log-path", query_log_path.to_s,
183
+ "--protocol", "http",
184
+ "-s",
185
+ @database_path.to_s)
186
+
187
+ n_retries = 10
188
+ begin
189
+ send_command("status")
190
+ rescue SystemCallError
191
+ sleep(1)
192
+ n_retries -= 1
193
+ raise if n_retries.zero?
194
+ retry
195
+ end
196
+
197
+ yield
198
+ end
199
+
200
+ def shutdown
201
+ begin
202
+ send_command("shutdown")
203
+ rescue SystemCallError
204
+ end
205
+ Process.waitpid(@pid)
206
+ end
207
+
208
+ private
209
+ def find_unused_port
210
+ server = TCPServer.new(@host, 0)
211
+ begin
212
+ server.addr[1]
213
+ ensure
214
+ server.close
215
+ end
216
+ end
217
+
218
+ def log_path
219
+ @database_path.dirname + "groonga.log"
220
+ end
221
+
222
+ def query_log_path
223
+ @database_path.dirname + "query.log"
224
+ end
225
+
226
+ def ensure_database
227
+ if @options[:recreate_database]
228
+ FileUtils.rm_rf(@database_path.dirname.to_s)
229
+ end
230
+
231
+ return if @database_path.exist?
232
+ FileUtils.mkdir_p(@database_path.dirname.to_s)
233
+ system(@groonga, "-n", @database_path.to_s, "quit")
234
+ grn_files.each do |grn_file|
235
+ command = [@groonga, @database_path.to_s]
236
+ command_line = "#{command.join(' ')} < #{grn_file}"
237
+ puts("Running...: #{command_line}")
238
+ pid = spawn(*command, :in => grn_file.to_s)
239
+ begin
240
+ pid, status = Process.waitpid2(pid)
241
+ rescue Interrupt
242
+ Process.kill(:TERM, pid)
243
+ pid, status = Process.waitpid2(pid)
244
+ end
245
+ unless status.success?
246
+ raise "Failed to run: #{command_line}"
247
+ end
248
+ end
249
+ end
250
+
251
+ def send_command(name)
252
+ Net::HTTP.start(@host, @port) do |http|
253
+ response = http.get("/d/#{name}")
254
+ response.body
255
+ end
256
+ end
257
+
258
+ def grn_files
259
+ files = schema_files
260
+ files += data_files if @options[:load_data]
261
+ files += index_files
262
+ files
263
+ end
264
+
265
+ def schema_files
266
+ Pathname.glob("#{@input_directory}/schema/**/*.grn").sort
267
+ end
268
+
269
+ def index_files
270
+ Pathname.glob("#{@input_directory}/indexes/**/*.grn").sort
271
+ end
272
+
273
+ def data_files
274
+ Pathname.glob("#{@input_directory}/data/**/*.grn").sort
275
+ end
276
+ end
277
+
278
+ class Tester
279
+ def initialize(old, new, options)
280
+ @old = old
281
+ @new = new
282
+ @input_directory = options[:input_directory] || Pathname.new(".")
283
+ @working_directory = options[:working_directory] || Pathname.new(".")
284
+ @n_clients = options[:n_clients] || 1
285
+ @options = options
286
+ @n_ready_waits = 2
287
+ @clone_pids = []
288
+ end
289
+
290
+ def run
291
+ old_thread = Thread.new do
292
+ @old.run do
293
+ run_test
294
+ end
295
+ end
296
+ new_thread = Thread.new do
297
+ @new.run do
298
+ run_test
299
+ end
300
+ end
301
+
302
+ old_thread.join
303
+ new_thread.join
304
+ end
305
+
306
+ private
307
+ def run_test
308
+ @n_ready_waits -= 1
309
+ return unless @n_ready_waits.zero?
310
+
311
+ @clone_pids.each do |pid|
312
+ Process.waitpid(pid)
313
+ end
314
+
315
+ query_log_paths.each do |query_log_path|
316
+ log_path = test_log_path(query_log_path)
317
+ if @options[:skip_finished_queries] and log_path.exist?
318
+ puts("Skip query log: #{query_log_path}")
319
+ next
320
+ else
321
+ puts("Running test against query log...: #{query_log_path}")
322
+ end
323
+ pid = fork do
324
+ verify_server(log_path, query_log_path)
325
+ exit!
326
+ end
327
+ begin
328
+ Process.waitpid(pid)
329
+ rescue Interrupt
330
+ Process.kill(:TERM, pid)
331
+ Process.waitpid(pid)
332
+ end
333
+ end
334
+
335
+ old_thread = Thread.new do
336
+ @old.shutdown
337
+ end
338
+ new_thread = Thread.new do
339
+ @new.shutdown
340
+ end
341
+ old_thread.join
342
+ new_thread.join
343
+
344
+ true
345
+ end
346
+
347
+ def verify_server(test_log_path, query_log_path)
348
+ command_line = [
349
+ "--n-clients=#{@n_clients}",
350
+ "--groonga1-host=#{@old.host}",
351
+ "--groonga1-port=#{@old.port}",
352
+ "--groonga1-protocol=http",
353
+ "--groonga2-host=#{@new.host}",
354
+ "--groonga2-port=#{@new.port}",
355
+ "--groonga2-protocol=http",
356
+ "--target-command-name=select",
357
+ "--output", test_log_path.to_s,
358
+ query_log_path.to_s,
359
+ ]
360
+ verify_serer = VerifyServer.new
361
+ verify_serer.run(*command_line)
362
+ end
363
+
364
+ def query_log_paths
365
+ Pathname.glob("#{@input_directory}/query-logs/**/*.log").sort
366
+ end
367
+
368
+ def test_log_path(query_log_path)
369
+ @working_directory + "results" + query_log_path.basename
370
+ end
371
+ end
372
+ end
373
+ end
374
+ end
375
+ end
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
1
  # Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
4
2
  #
5
3
  # This library is free software; you can redistribute it and/or
@@ -26,23 +24,41 @@ module Groonga
26
24
  end
27
25
 
28
26
  def same?
29
- case @command.name
30
- when "select"
31
- same_select_response?
27
+ if error_response?(@response1) or error_response?(@response2)
28
+ if error_response?(@response1) and error_response?(@response2)
29
+ same_error_response?
30
+ else
31
+ false
32
+ end
32
33
  else
33
- same_response?
34
+ case @command.name
35
+ when "select"
36
+ same_select_response?
37
+ else
38
+ same_response?
39
+ end
34
40
  end
35
41
  end
36
42
 
37
43
  private
44
+ def error_response?(response)
45
+ response.is_a?(Client::Response::Error)
46
+ end
47
+
48
+ def same_error_response?
49
+ return_code1 = @response1.header[0]
50
+ return_code2 = @response2.header[0]
51
+ return_code1 == return_code2
52
+ end
53
+
38
54
  def same_response?
39
- @response1 == @response2
55
+ @response1.body == @response2.body
40
56
  end
41
57
 
42
58
  def same_select_response?
43
59
  if random_sort?
44
- records_result1 = @response1[0] || []
45
- records_result2 = @response2[0] || []
60
+ records_result1 = @response1.body[0] || []
61
+ records_result2 = @response2.body[0] || []
46
62
  records_result1.size == records_result2.size and
47
63
  records_result1[0..1] == records_result2[0..1]
48
64
  else
@@ -60,15 +60,8 @@ module Groonga
60
60
  def run_consumers
61
61
  @options.n_clients.times.collect do
62
62
  Thread.new do
63
- begin
64
- loop do
65
- break if run_consumer
66
- end
67
- rescue Groonga::Client::Connection::Error
68
- # TODO: add error log mechanism
69
- $stderr.puts(Time.now.iso8601)
70
- $stderr.puts($!.raw_error.message)
71
- $stderr.puts($!.raw_error.backtrace)
63
+ loop do
64
+ break if run_consumer
72
65
  end
73
66
  end
74
67
  end
@@ -83,12 +76,10 @@ module Groonga
83
76
  begin
84
77
  verify_command(groonga1_client, groonga2_client,
85
78
  statistic.command)
86
- rescue Groonga::Client::Connection::Error
87
- # TODO: add error log mechanism
88
- $stderr.puts(Time.now.iso8601)
89
- $stderr.puts(statistic.command.original_source)
90
- $stderr.puts($!.raw_error.message)
91
- $stderr.puts($!.raw_error.backtrace)
79
+ rescue Groonga::Client::Error
80
+ log_client_error($!) do
81
+ $stderr.puts(statistic.command.original_source)
82
+ end
92
83
  return false
93
84
  end
94
85
  end
@@ -116,7 +107,7 @@ module Groonga
116
107
  command["cache"] = "no" if @options.disable_cache?
117
108
  response1 = groonga1_client.execute(command)
118
109
  response2 = groonga2_client.execute(command)
119
- comparer = ResponseComparer.new(command, response1.body, response2.body)
110
+ comparer = ResponseComparer.new(command, response1, response2)
120
111
  unless comparer.same?
121
112
  @different_results.push([command, response1, response2])
122
113
  end
@@ -129,6 +120,18 @@ module Groonga
129
120
  output.puts("response2: #{response2.body}")
130
121
  end
131
122
 
123
+ def log_client_error(error)
124
+ $stderr.puts(Time.now.iso8601)
125
+ yield if block_given?
126
+ if error.respond_to?(:raw_error)
127
+ target_error = error.raw_error
128
+ else
129
+ target_error = error
130
+ end
131
+ $stderr.puts("#{target_error.class}: #{target_error.message}")
132
+ $stderr.puts(target_error.backtrace)
133
+ end
134
+
132
135
  class Options
133
136
  attr_reader :groonga1
134
137
  attr_reader :groonga2
@@ -165,6 +168,7 @@ module Groonga
165
168
 
166
169
  def create_output(&block)
167
170
  if @output_path
171
+ FileUtils.mkdir_p(File.dirname(@output_path))
168
172
  File.open(@output_path, "w", &block)
169
173
  else
170
174
  yield($stdout)
@@ -18,6 +18,6 @@
18
18
 
19
19
  module Groonga
20
20
  module QueryLog
21
- VERSION = "1.0.4"
21
+ VERSION = "1.0.5"
22
22
  end
23
23
  end
@@ -33,8 +33,8 @@ class ReplayerTest < Test::Unit::TestCase
33
33
 
34
34
  def test_port
35
35
  port = 2929
36
- @options.port = 2929
37
- mock_client_open(:port => 2929)
36
+ @options.port = port
37
+ mock_client_open(:port => port)
38
38
  replay
39
39
  end
40
40
 
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
1
  # Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
4
2
  #
5
3
  # This library is free software; you can redistribute it and/or
@@ -19,6 +17,8 @@
19
17
  class ResponseComparerTest < Test::Unit::TestCase
20
18
  private
21
19
  def comparer(response1, response2)
20
+ response1 = normalize_response(response1)
21
+ response2 = normalize_response(response2)
22
22
  Groonga::QueryLog::ResponseComparer.new(@command, response1, response2)
23
23
  end
24
24
 
@@ -26,6 +26,24 @@ class ResponseComparerTest < Test::Unit::TestCase
26
26
  comparer(response1, response2).same?
27
27
  end
28
28
 
29
+ def response(body)
30
+ header = [0, 0.0, 0.0]
31
+ response_class = Groonga::Client::Response.find(@command.name)
32
+ response_class.new(@command, header, body)
33
+ end
34
+
35
+ def error_response(header)
36
+ Groonga::Client::Response::Error.new(@command, header, [])
37
+ end
38
+
39
+ def normalize_response(response_or_body)
40
+ if response_or_body.is_a?(Groonga::Client::Response::Base)
41
+ response_or_body
42
+ else
43
+ response(response_or_body)
44
+ end
45
+ end
46
+
29
47
  class SelectTest < self
30
48
  def setup
31
49
  @command = Groonga::Command::Select.new("select", {})
@@ -63,7 +81,7 @@ class ResponseComparerTest < Test::Unit::TestCase
63
81
  private
64
82
  def random_score?(scorer)
65
83
  @command["scorer"] = scorer
66
- comparer([], []).send(:random_score?)
84
+ comparer([[[0]]], [[[0]]]).send(:random_score?)
67
85
  end
68
86
  end
69
87
  end
@@ -73,7 +91,7 @@ class ResponseComparerTest < Test::Unit::TestCase
73
91
  private
74
92
  def score_sort?(sortby)
75
93
  @command["sortby"] = sortby
76
- comparer([], []).send(:score_sort?)
94
+ comparer([[[0]]], [[[0]]]).send(:score_sort?)
77
95
  end
78
96
 
79
97
  class NoScoreTest < self
@@ -119,5 +137,26 @@ class ResponseComparerTest < Test::Unit::TestCase
119
137
  end
120
138
  end
121
139
  end
140
+
141
+ class ErrorTest < self
142
+ def test_with_location
143
+ response1_header = [
144
+ -63,
145
+ 1.0,
146
+ 0.1,
147
+ "Syntax error! ()",
148
+ [
149
+ ["yy_syntax_error", "ecmascript.lemon", 24],
150
+ ],
151
+ ]
152
+ response2_header = JSON.parse(response1_header.to_json)
153
+ response2_header[4][0][2] += 1
154
+ assert_not_equal(response1_header, response2_header)
155
+
156
+ response1 = error_response(response1_header)
157
+ response2 = error_response(response2_header)
158
+ assert_true(same?(response1, response2))
159
+ end
160
+ end
122
161
  end
123
162
  end
metadata CHANGED
@@ -1,220 +1,224 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: groonga-query-log
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kouhei Sutou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-09 00:00:00.000000000 Z
11
+ date: 2014-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: groonga-command-parser
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: groonga-client
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: test-unit
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: test-unit-notify
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: test-unit-rr
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: bundler
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: packnga
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - '>='
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - '>='
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: yard
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '>='
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - '>='
136
+ - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: redcarpet
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - '>='
143
+ - - ">="
144
144
  - !ruby/object:Gem::Version
145
145
  version: '0'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - '>='
150
+ - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  description: ''
154
154
  email:
155
155
  - kou@clear-code.com
156
156
  executables:
157
- - groonga-query-log-detect-memory-leak
158
- - groonga-query-log-verify-server
157
+ - groonga-query-log-run-regression-test
159
158
  - groonga-query-log-analyze
159
+ - groonga-query-log-detect-memory-leak
160
160
  - groonga-query-log-replay
161
161
  - groonga-query-log-extract
162
+ - groonga-query-log-verify-server
162
163
  extensions: []
163
164
  extra_rdoc_files: []
164
165
  files:
166
+ - ".yardopts"
167
+ - Gemfile
165
168
  - README.md
166
169
  - Rakefile
167
- - Gemfile
170
+ - bin/groonga-query-log-analyze
171
+ - bin/groonga-query-log-detect-memory-leak
172
+ - bin/groonga-query-log-extract
173
+ - bin/groonga-query-log-replay
174
+ - bin/groonga-query-log-run-regression-test
175
+ - bin/groonga-query-log-verify-server
176
+ - doc/text/lgpl-2.1.txt
177
+ - doc/text/news.md
178
+ - doc/text/run-regression-test.md
168
179
  - groonga-query-log.gemspec
169
180
  - lib/groonga/query-log.rb
170
- - lib/groonga/query-log/version.rb
171
- - lib/groonga/query-log/extractor.rb
172
- - lib/groonga/query-log/command/verify-server.rb
181
+ - lib/groonga/query-log/analyzer.rb
182
+ - lib/groonga/query-log/analyzer/reporter.rb
183
+ - lib/groonga/query-log/analyzer/reporter/console.rb
184
+ - lib/groonga/query-log/analyzer/reporter/html.rb
185
+ - lib/groonga/query-log/analyzer/reporter/json.rb
186
+ - lib/groonga/query-log/analyzer/sized-grouped-operations.rb
187
+ - lib/groonga/query-log/analyzer/sized-statistics.rb
188
+ - lib/groonga/query-log/analyzer/statistic.rb
189
+ - lib/groonga/query-log/analyzer/streamer.rb
190
+ - lib/groonga/query-log/command-line-utils.rb
173
191
  - lib/groonga/query-log/command/detect-memory-leak.rb
174
192
  - lib/groonga/query-log/command/replay.rb
193
+ - lib/groonga/query-log/command/run-regression-test.rb
194
+ - lib/groonga/query-log/command/verify-server.rb
195
+ - lib/groonga/query-log/extractor.rb
175
196
  - lib/groonga/query-log/memory-leak-detector.rb
176
197
  - lib/groonga/query-log/parser.rb
177
- - lib/groonga/query-log/analyzer.rb
198
+ - lib/groonga/query-log/replayer.rb
178
199
  - lib/groonga/query-log/response-comparer.rb
179
- - lib/groonga/query-log/command-line-utils.rb
180
200
  - lib/groonga/query-log/server-verifier.rb
181
- - lib/groonga/query-log/replayer.rb
182
- - lib/groonga/query-log/analyzer/statistic.rb
183
- - lib/groonga/query-log/analyzer/streamer.rb
184
- - lib/groonga/query-log/analyzer/sized-statistics.rb
185
- - lib/groonga/query-log/analyzer/sized-grouped-operations.rb
186
- - lib/groonga/query-log/analyzer/reporter.rb
187
- - lib/groonga/query-log/analyzer/reporter/console.rb
188
- - lib/groonga/query-log/analyzer/reporter/json.rb
189
- - lib/groonga/query-log/analyzer/reporter/html.rb
190
- - doc/text/news.md
191
- - doc/text/lgpl-2.1.txt
192
- - .yardopts
193
- - test/test-replayer.rb
201
+ - lib/groonga/query-log/version.rb
194
202
  - test/command/test-select.rb
195
- - test/test-response-comparer.rb
196
- - test/groonga-query-log-test-utils.rb
197
- - test/test-extractor.rb
198
- - test/run-test.rb
199
- - test/fixtures/n_entries.expected
200
- - test/fixtures/other-query.log
201
203
  - test/fixtures/multi.expected
204
+ - test/fixtures/n_entries.expected
205
+ - test/fixtures/no-report-summary.expected
206
+ - test/fixtures/order/-elapsed.expected
202
207
  - test/fixtures/order/-start-time.expected
203
208
  - test/fixtures/order/elapsed.expected
204
209
  - test/fixtures/order/start-time.expected
205
- - test/fixtures/order/-elapsed.expected
206
- - test/fixtures/no-report-summary.expected
210
+ - test/fixtures/other-query.log
207
211
  - test/fixtures/query.log
208
- - test/fixtures/reporter/json.expected
209
- - test/fixtures/reporter/html.expected
210
212
  - test/fixtures/reporter/console.expected
213
+ - test/fixtures/reporter/html.expected
214
+ - test/fixtures/reporter/json.expected
215
+ - test/groonga-query-log-test-utils.rb
216
+ - test/run-test.rb
211
217
  - test/test-analyzer.rb
218
+ - test/test-extractor.rb
212
219
  - test/test-parser.rb
213
- - bin/groonga-query-log-detect-memory-leak
214
- - bin/groonga-query-log-verify-server
215
- - bin/groonga-query-log-analyze
216
- - bin/groonga-query-log-replay
217
- - bin/groonga-query-log-extract
220
+ - test/test-replayer.rb
221
+ - test/test-response-comparer.rb
218
222
  homepage: https://github.com/groonga/groonga-query-log
219
223
  licenses:
220
224
  - LGPLv2.1+
@@ -225,42 +229,42 @@ require_paths:
225
229
  - lib
226
230
  required_ruby_version: !ruby/object:Gem::Requirement
227
231
  requirements:
228
- - - '>='
232
+ - - ">="
229
233
  - !ruby/object:Gem::Version
230
234
  version: '0'
231
235
  required_rubygems_version: !ruby/object:Gem::Requirement
232
236
  requirements:
233
- - - '>='
237
+ - - ">="
234
238
  - !ruby/object:Gem::Version
235
239
  version: '0'
236
240
  requirements: []
237
241
  rubyforge_project:
238
- rubygems_version: 2.0.14
242
+ rubygems_version: 2.2.2
239
243
  signing_key:
240
244
  specification_version: 4
241
- summary: Groonga-query-log is a collection of library and tools to process [groonga](http://groonga.org/)'s
245
+ summary: Groonga-query-log is a collection of library and tools to process [Groonga](http://groonga.org/)'s
242
246
  query log. You can write a program to process query log by using groonga-query-log
243
- as a library. You can analyze your groonga's queries and test with your groonga's
247
+ as a library. You can analyze your Groonga's queries and test with your Groonga's
244
248
  query log by using groonga-query-log as a tool.
245
249
  test_files:
246
- - test/test-replayer.rb
247
- - test/command/test-select.rb
248
- - test/test-response-comparer.rb
249
- - test/groonga-query-log-test-utils.rb
250
- - test/test-extractor.rb
251
250
  - test/run-test.rb
252
- - test/fixtures/n_entries.expected
253
- - test/fixtures/other-query.log
254
- - test/fixtures/multi.expected
255
- - test/fixtures/order/-start-time.expected
251
+ - test/test-extractor.rb
252
+ - test/command/test-select.rb
253
+ - test/test-analyzer.rb
254
+ - test/test-replayer.rb
255
+ - test/test-parser.rb
256
+ - test/fixtures/no-report-summary.expected
256
257
  - test/fixtures/order/elapsed.expected
258
+ - test/fixtures/order/-start-time.expected
257
259
  - test/fixtures/order/start-time.expected
258
260
  - test/fixtures/order/-elapsed.expected
259
- - test/fixtures/no-report-summary.expected
260
- - test/fixtures/query.log
261
+ - test/fixtures/n_entries.expected
262
+ - test/fixtures/other-query.log
261
263
  - test/fixtures/reporter/json.expected
262
- - test/fixtures/reporter/html.expected
263
264
  - test/fixtures/reporter/console.expected
264
- - test/test-analyzer.rb
265
- - test/test-parser.rb
265
+ - test/fixtures/reporter/html.expected
266
+ - test/fixtures/multi.expected
267
+ - test/fixtures/query.log
268
+ - test/groonga-query-log-test-utils.rb
269
+ - test/test-response-comparer.rb
266
270
  has_rdoc: