groonga-query-log 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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: