groonga-query-log 1.2.8 → 1.2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/bin/groonga-query-log-analyze +3 -4
  3. data/bin/groonga-query-log-analyze-load +22 -0
  4. data/bin/groonga-query-log-check-command-version-compatibility +2 -2
  5. data/bin/groonga-query-log-check-crash +22 -0
  6. data/bin/groonga-query-log-detect-memory-leak +2 -2
  7. data/bin/groonga-query-log-extract +2 -2
  8. data/bin/groonga-query-log-format-regression-test-logs +2 -2
  9. data/bin/groonga-query-log-replay +3 -5
  10. data/bin/groonga-query-log-run-regression-test +2 -2
  11. data/bin/groonga-query-log-show-running-queries +2 -2
  12. data/bin/groonga-query-log-verify-server +2 -2
  13. data/doc/text/news.md +31 -0
  14. data/groonga-query-log.gemspec +5 -4
  15. data/lib/groonga-query-log.rb +42 -0
  16. data/lib/{groonga/query-log/command-line-utils.rb → groonga-query-log/command-line.rb} +25 -13
  17. data/lib/{groonga/query-log → groonga-query-log}/command-version-compatibility-checker.rb +3 -5
  18. data/lib/groonga-query-log/command/analyze-load.rb +188 -0
  19. data/lib/{groonga/query-log → groonga-query-log/command}/analyzer.rb +60 -44
  20. data/lib/{groonga/query-log → groonga-query-log/command}/analyzer/reporter.rb +15 -20
  21. data/lib/{groonga/query-log → groonga-query-log/command}/analyzer/reporter/console.rb +19 -18
  22. data/lib/groonga-query-log/command/analyzer/reporter/csv.rb +77 -0
  23. data/lib/{groonga/query-log → groonga-query-log/command}/analyzer/reporter/html.rb +32 -16
  24. data/lib/{groonga/query-log → groonga-query-log/command}/analyzer/reporter/json-stream.rb +4 -6
  25. data/lib/{groonga/query-log → groonga-query-log/command}/analyzer/reporter/json.rb +7 -7
  26. data/lib/{groonga/query-log → groonga-query-log/command}/analyzer/sized-grouped-operations.rb +3 -5
  27. data/lib/{groonga/query-log → groonga-query-log/command}/analyzer/sized-statistics.rb +4 -6
  28. data/lib/{groonga/query-log → groonga-query-log/command}/analyzer/streamer.rb +4 -6
  29. data/lib/groonga-query-log/command/check-command-version-compatibility.rb +69 -0
  30. data/lib/groonga-query-log/command/check-crash.rb +169 -0
  31. data/lib/groonga-query-log/command/detect-memory-leak.rb +89 -0
  32. data/lib/groonga-query-log/command/extract.rb +171 -0
  33. data/lib/groonga-query-log/command/format-regression-test-logs.rb +143 -0
  34. data/lib/groonga-query-log/command/replay.rb +117 -0
  35. data/lib/groonga-query-log/command/run-regression-test.rb +432 -0
  36. data/lib/groonga-query-log/command/show-running-queries.rb +78 -0
  37. data/lib/{groonga/query-log/command/replay.rb → groonga-query-log/command/verify-server.rb} +68 -37
  38. data/lib/{groonga/query-log → groonga-query-log}/incompatibility-detector.rb +3 -5
  39. data/lib/{groonga/query-log → groonga-query-log}/memory-leak-detector.rb +3 -7
  40. data/lib/groonga-query-log/parser.rb +173 -0
  41. data/lib/{groonga/query-log → groonga-query-log}/replayer.rb +7 -8
  42. data/lib/{groonga/query-log → groonga-query-log}/response-comparer.rb +3 -5
  43. data/lib/{groonga/query-log → groonga-query-log}/server-verifier.rb +3 -5
  44. data/lib/groonga-query-log/statistic.rb +192 -0
  45. data/lib/{groonga/query-log → groonga-query-log}/version.rb +2 -4
  46. data/lib/groonga/query-log.rb +21 -9
  47. data/lib/groonga/query-log/command/analyzer.rb +18 -0
  48. data/lib/groonga/query-log/command/check-command-version-compatibility.rb +2 -55
  49. data/lib/groonga/query-log/command/detect-memory-leak.rb +3 -78
  50. data/lib/groonga/query-log/command/extract.rb +5 -179
  51. data/lib/groonga/query-log/command/format-regression-test-logs.rb +3 -130
  52. data/lib/groonga/query-log/command/reply.rb +18 -0
  53. data/lib/groonga/query-log/command/run-regression-test.rb +2 -418
  54. data/lib/groonga/query-log/command/show-running-queries.rb +3 -65
  55. data/lib/groonga/query-log/command/verify-server.rb +2 -137
  56. data/test/{test-analyzer.rb → command/test-analyzer.rb} +17 -11
  57. data/test/command/test-extract.rb +9 -18
  58. data/test/command/test-format-regression-test-logs.rb +3 -3
  59. data/test/fixtures/reporter/html.expected +55 -20
  60. data/test/helper.rb +22 -7
  61. data/test/test-incompatibility-detector.rb +3 -3
  62. data/test/test-parser.rb +19 -4
  63. data/test/test-replayer.rb +4 -4
  64. data/test/test-response-comparer.rb +2 -2
  65. metadata +86 -97
  66. data/lib/groonga/query-log/analyzer/statistic.rb +0 -194
  67. data/lib/groonga/query-log/parser.rb +0 -125
  68. data/test/fixtures/run-regression-test/db.new/db +0 -0
  69. data/test/fixtures/run-regression-test/db.new/db.0000000 +0 -0
  70. data/test/fixtures/run-regression-test/db.new/db.0000100 +0 -0
  71. data/test/fixtures/run-regression-test/db.new/db.0000101 +0 -0
  72. data/test/fixtures/run-regression-test/db.new/db.0000102 +0 -0
  73. data/test/fixtures/run-regression-test/db.new/db.0000103 +0 -0
  74. data/test/fixtures/run-regression-test/db.new/db.0000103.c +0 -0
  75. data/test/fixtures/run-regression-test/db.new/db.001 +0 -0
  76. data/test/fixtures/run-regression-test/db.new/db.conf +0 -0
  77. data/test/fixtures/run-regression-test/db.new/groonga.log +0 -165
  78. data/test/fixtures/run-regression-test/db.old/db +0 -0
  79. data/test/fixtures/run-regression-test/db.old/db.0000000 +0 -0
  80. data/test/fixtures/run-regression-test/db.old/db.0000100 +0 -0
  81. data/test/fixtures/run-regression-test/db.old/db.0000101 +0 -0
  82. data/test/fixtures/run-regression-test/db.old/db.0000102 +0 -0
  83. data/test/fixtures/run-regression-test/db.old/db.0000103 +0 -0
  84. data/test/fixtures/run-regression-test/db.old/db.0000103.c +0 -0
  85. data/test/fixtures/run-regression-test/db.old/db.001 +0 -0
  86. data/test/fixtures/run-regression-test/db.old/db.conf +0 -0
  87. data/test/fixtures/run-regression-test/db.old/groonga.log +0 -79
  88. data/test/fixtures/run-regression-test/results/query.log +0 -0
@@ -1,11 +1,9 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2011 Kouhei Sutou <kou@clear-code.com>
4
- # Copyright (C) 2012 Haruka Yoshihara <yoshihara@clear-code.com>
1
+ # Copyright (C) 2017 Kouhei Sutou <kou@clear-code.com>
5
2
  #
6
3
  # This library is free software; you can redistribute it and/or
7
4
  # modify it under the terms of the GNU Lesser General Public
8
- # License version 2.1 as published by the Free Software Foundation.
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
9
7
  #
10
8
  # This library is distributed in the hope that it will be useful,
11
9
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,179 +12,7 @@
14
12
  #
15
13
  # You should have received a copy of the GNU Lesser General Public
16
14
  # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
-
19
- require "ostruct"
20
- require "optparse"
21
- require "pathname"
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
16
 
23
17
  require "groonga/query-log"
24
- require "groonga/query-log/command-line-utils"
25
-
26
- module Groonga
27
- module QueryLog
28
- module Command
29
- class Extract
30
- include CommandLineUtils
31
-
32
- class Error < StandardError
33
- end
34
-
35
- attr_accessor :options
36
- attr_reader :option_parser
37
-
38
- def initialize
39
- @options = nil
40
- @option_parser = nil
41
- setup_options
42
- end
43
-
44
- # Executes extractor for groonga's query logs.
45
- # "groonga-query-log-extract" command runs this method.
46
- #
47
- # @example
48
- # extractor = Groonga::QueryLog::Command::Extract.new
49
- # extractor.run("--output", "commands.output",
50
- # "--command", "select",
51
- # "query.log")
52
- #
53
- # If only paths of query log files are specified,
54
- # this method prints command(s) of them to console.
55
- #
56
- # @param [Array<String>] arguments arguments for
57
- # groonga-query-log-extract. Please execute
58
- # "groonga-query-log-extract --help" or see #setup_options.
59
- def run(arguments)
60
- begin
61
- log_paths = @option_parser.parse!(arguments)
62
- rescue OptionParser::ParseError
63
- $stderr.puts($!.message)
64
- return false
65
- end
66
-
67
- if log_paths.empty?
68
- unless log_via_stdin?
69
- $stderr.puts("Error: Please specify input log files.")
70
- return false
71
- end
72
- log = $stdin
73
- else
74
- log = log_paths
75
- end
76
-
77
- if @options.output_path
78
- File.open(@options.output_path, "w") do |output|
79
- extract(log, output)
80
- end
81
- else
82
- extract(log, $stdout)
83
- end
84
-
85
- true
86
- end
87
-
88
- private
89
- def setup_options
90
- @options = OpenStruct.new
91
- @options.unify_format = nil
92
- @options.commands = []
93
- @options.exclude_commands = []
94
- @options.output_path = nil
95
- @option_parser = OptionParser.new do |parser|
96
- parser.version = VERSION
97
- parser.banner += " QUERY_LOG1 ..."
98
-
99
- available_formats = ["uri", "command"]
100
- parser.on("--unify-format=FORMAT",
101
- available_formats,
102
- "Unify command format to FORMAT.",
103
- "(#{available_formats.join(', ')})",
104
- "[not unify]") do |format|
105
- @options.unify_format = format
106
- end
107
-
108
- parser.on("--command=COMMAND",
109
- "Extract only COMMAND.",
110
- "To extract one or more commands,",
111
- "specify this command a number of times.",
112
- "Use /.../ as COMMAND to match command with regular expression.",
113
- "[all commands]") do |command|
114
- case command
115
- when /\A\/(.*)\/(i)?\z/
116
- @options.commands << Regexp.new($1, $2 == "i")
117
- when
118
- @options.commands << command
119
- end
120
- end
121
-
122
- parser.on("--exclude-command=COMMAND",
123
- "Don't extract COMMAND.",
124
- "To ignore one or more commands,",
125
- "specify this command a number of times.",
126
- "Use /.../ as COMMAND to match command with regular expression.",
127
- "[no commands]") do |command|
128
- case command
129
- when /\A\/(.*)\/(i)?\z/
130
- @options.exclude_commands << Regexp.new($1, $2 == "i")
131
- when
132
- @options.exclude_commands << command
133
- end
134
- end
135
-
136
- parser.on("--output=PATH",
137
- "Output to PATH.",
138
- "[standard output]") do |path|
139
- @options.output_path = path
140
- end
141
- end
142
- end
143
-
144
- def extract(log, output)
145
- if log.instance_of?(Array)
146
- log.each do |log_path|
147
- File.open(log_path) do |log_file|
148
- extract_command(log_file, output)
149
- end
150
- end
151
- else
152
- extract_command(log, output)
153
- end
154
- end
155
-
156
- def extract_command(log, output)
157
- parser = Groonga::QueryLog::Parser.new
158
- parser.parse(log) do |statistic|
159
- command = statistic.command
160
- next unless target?(command)
161
- command_text = nil
162
- case @options.unify_format
163
- when "uri"
164
- command_text = command.to_uri_format
165
- when "command"
166
- command_text = command.to_command_format
167
- else
168
- command_text = statistic.raw_command
169
- end
170
- output.puts(command_text)
171
- end
172
- end
173
-
174
- def target?(command)
175
- name = command.command_name
176
- target_commands = @options.commands
177
- exclude_commands = @options.exclude_commands
178
-
179
- unless target_commands.empty?
180
- return target_commands.any? {|target_command| target_command === name}
181
- end
182
-
183
- unless exclude_commands.empty?
184
- return (not exclude_commands.any? {|exclude_command| exclude_command === name})
185
- end
186
-
187
- true
188
- end
189
- end
190
- end
191
- end
192
- end
18
+ require "groonga-query-log/command/extract"
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2014 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2017 Kouhei Sutou <kou@clear-code.com>
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -14,132 +14,5 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
- require "English"
18
- require "find"
19
- require "tempfile"
20
- require "pp"
21
- require "optparse"
22
- require "json"
23
-
24
- require "groonga/command/parser"
25
-
26
- require "groonga/query-log/version"
27
-
28
- module Groonga
29
- module QueryLog
30
- module Command
31
- class FormatRegressionTestLogs
32
- def initialize
33
- end
34
-
35
- def run(command_line)
36
- parser = OptionParser.new
37
- parser.banner += " PATH1 PATH2 ..."
38
- parser.version = VERSION
39
- paths = parser.parse!(command_line)
40
-
41
- if paths.empty?
42
- format_log($stdin, "-")
43
- else
44
- paths.each do |path|
45
- if File.directory?(path)
46
- Find.find(path) do |sub_path|
47
- next unless File.file?(sub_path)
48
- File.open(sub_path) do |file|
49
- format_log(file, sub_path)
50
- end
51
- end
52
- else
53
- File.open(path) do |file|
54
- format_log(file, path)
55
- end
56
- end
57
- end
58
- end
59
- true
60
- end
61
-
62
- private
63
- def format_log(input, path)
64
- command = nil
65
- response_old = nil
66
- response_new = nil
67
-
68
- input.each_line do |line|
69
- unless line.valid_encoding?
70
- puts("invalid encoding line")
71
- puts("#{path}:#{input.lineno}:#{line}")
72
- next
73
- end
74
- case line
75
- when /\Acommand: /
76
- command = $POSTMATCH.chomp
77
- when /\Aresponse1: /
78
- response_old = $POSTMATCH.chomp
79
- when /\Aresponse2: /
80
- response_new = $POSTMATCH.chomp
81
- next unless valid_entry?(command, response_old, response_new)
82
- report_diff(command, response_old, response_new)
83
- end
84
- end
85
- end
86
-
87
- def valid_entry?(command, response_old, response_new)
88
- valid = true
89
-
90
- begin
91
- JSON.parse(response_old)
92
- rescue JSON::ParserError
93
- puts(command)
94
- puts("failed to parse old response: #{$!.message}")
95
- puts(response_old)
96
- valid = false
97
- end
98
-
99
- begin
100
- JSON.parse(response_new)
101
- rescue JSON::ParserError
102
- puts(command)
103
- puts("failed to parse new response: #{$!.message}")
104
- puts(response_new)
105
- valid = false
106
- end
107
-
108
- valid
109
- end
110
-
111
- def report_diff(command, response_old, response_new)
112
- return if response_old == response_new
113
-
114
- Tempfile.open("response-old") do |response_old_file|
115
- PP.pp(JSON.parse(response_old), response_old_file)
116
- response_old_file.flush
117
- Tempfile.open("response-new") do |response_new_file|
118
- PP.pp(JSON.parse(response_new), response_new_file)
119
- response_new_file.flush
120
- report_command(command)
121
- system("diff",
122
- "--label=old",
123
- "--label=new",
124
- "-u",
125
- response_old_file.path, response_new_file.path)
126
- end
127
- end
128
- end
129
-
130
- def report_command(command)
131
- puts(command)
132
- parsed_command = Groonga::Command::Parser.parse(command)
133
- puts("Name: #{parsed_command.name}")
134
- puts("Arguments:")
135
- sorted_arguments = parsed_command.arguments.sort_by do |key, value|
136
- key
137
- end
138
- sorted_arguments.each do |key, value|
139
- puts(" #{key}: #{value}")
140
- end
141
- end
142
- end
143
- end
144
- end
145
- end
17
+ require "groonga/query-log"
18
+ require "groonga-query-log/command/format-regression-test-logs"
@@ -0,0 +1,18 @@
1
+ # Copyright (C) 2017 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 "groonga/query-log"
18
+ require "groonga-query-log/command/reply"
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2014-2017 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2017 Kouhei Sutou <kou@clear-code.com>
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -14,421 +14,5 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
- require "rbconfig"
18
- require "optparse"
19
- require "socket"
20
- require "fileutils"
21
- require "pathname"
22
- require "net/http"
23
-
24
17
  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
- @old_groonga_options = []
38
-
39
- @new_groonga = "groonga"
40
- @new_database = "db.new/db"
41
- @new_groonga_options = []
42
-
43
- @recreate_database = false
44
- @load_data = true
45
- @run_queries = true
46
- @skip_finished_queries = false
47
- @output_query_log = false
48
- @care_order = true
49
- @verify_cachehit_mode = false
50
- end
51
-
52
- def run(command_line)
53
- option_parser = create_option_parser
54
- begin
55
- option_parser.parse!(command_line)
56
- rescue OptionParser::ParseError => error
57
- $stderr.puts(error.message)
58
- return false
59
- end
60
-
61
- tester = Tester.new(old_groonga_server,
62
- new_groonga_server,
63
- tester_options)
64
- tester.run
65
- end
66
-
67
- private
68
- def create_option_parser
69
- parser = OptionParser.new
70
- parser.version = VERSION
71
-
72
- parser.separator("")
73
- parser.separator("Path:")
74
- parser.on("--input-directory=DIRECTORY",
75
- "Load schema and data from DIRECTORY.",
76
- "(#{@input_directory})") do |directory|
77
- @input_directory = Pathname.new(directory)
78
- end
79
- parser.on("--working-directory=DIRECTORY",
80
- "Use DIRECTORY as working directory.",
81
- "(#{@working_directory})") do |directory|
82
- @working_directory = Pathname.new(directory)
83
- end
84
-
85
- parser.separator("")
86
- parser.separator("Throughput:")
87
- parser.on("--n-clients=N", Integer,
88
- "Use N clients concurrently.",
89
- "(#{@n_clients})") do |n|
90
- @n_clients = n
91
- end
92
-
93
- parser.separator("")
94
- parser.separator("Old Groonga:")
95
- parser.on("--old-groonga=GROONGA",
96
- "Old groonga command",
97
- "(#{@old_groonga})") do |groonga|
98
- @old_groonga = groonga
99
- end
100
-
101
- parser.on("--old-groonga-option=OPTION",
102
- "Add an additional old groonga option",
103
- "You can specify this option multiple times to specify multiple groonga options",
104
- "(no options)") do |groonga_option|
105
- @old_groonga_options << groonga_option
106
- end
107
-
108
- parser.separator("")
109
- parser.separator("New Groonga:")
110
- parser.on("--new-groonga=GROONGA",
111
- "New groonga command",
112
- "(#{@new_groonga})") do |groonga|
113
- @new_groonga = groonga
114
- end
115
-
116
- parser.on("--new-groonga-option=OPTION",
117
- "Add an additional new groonga option",
118
- "You can specify this option multiple times to specify multiple groonga options",
119
- "(no options)") do |groonga_option|
120
- @new_groonga_options << groonga_option
121
- end
122
-
123
- parser.separator("")
124
- parser.separator("Operations:")
125
- parser.on("--recreate-database",
126
- "Always recreate Groonga database") do
127
- @recreate_database = true
128
- end
129
- parser.on("--no-load-data",
130
- "Don't load data. Just loads schema to Groonga database") do
131
- @load_data = false
132
- end
133
- parser.on("--no-run-queries",
134
- "Don't run queries. Just creates Groonga database") do
135
- @run_queries = false
136
- end
137
- parser.on("--skip-finished-queries",
138
- "Don't run finished query logs.") do
139
- @skip_finished_queries = true
140
- end
141
- parser.on("--output-query-log",
142
- "Output query log in verified target Groonga servers") do
143
- @output_query_log = true
144
- end
145
- parser.on("--no-care-order",
146
- "Don't care order of select response records") do
147
- @care_order = false
148
- end
149
-
150
- parser
151
- end
152
-
153
- def directory_options
154
- {
155
- :input_directory => @input_directory,
156
- :working_directory => @working_directory,
157
- }
158
- end
159
-
160
- def server_options
161
- options = {
162
- :load_data => @load_data,
163
- :run_queries => @run_queries,
164
- :recreate_database => @recreate_database,
165
- :output_query_log => @output_query_log,
166
- }
167
- directory_options.merge(options)
168
- end
169
-
170
- def tester_options
171
- options = {
172
- :n_clients => @n_clients,
173
- :care_order => @care_order,
174
- :skip_finished_queries => @skip_finished_queries,
175
- }
176
- directory_options.merge(options)
177
- end
178
-
179
- def old_groonga_server
180
- GroongaServer.new(@old_groonga,
181
- @old_groonga_options,
182
- @old_database,
183
- server_options)
184
- end
185
-
186
- def new_groonga_server
187
- GroongaServer.new(@new_groonga,
188
- @new_groonga_options,
189
- @new_database,
190
- server_options)
191
- end
192
-
193
- class GroongaServer
194
- attr_reader :host, :port
195
- def initialize(groonga, groonga_options, database_path, options)
196
- @input_directory = options[:input_directory] || Pathname.new(".")
197
- @working_directory = options[:working_directory] || Pathname.new(".")
198
- @groonga = groonga
199
- @groonga_options = groonga_options
200
- @database_path = @working_directory + database_path
201
- @host = "127.0.0.1"
202
- @port = find_unused_port
203
- @options = options
204
- end
205
-
206
- def run
207
- return unless @options[:run_queries]
208
-
209
- arguments = @groonga_options.dup
210
- arguments.concat(["--bind-address", @host])
211
- arguments.concat(["--port", @port.to_s])
212
- arguments.concat(["--protocol", "http"])
213
- arguments.concat(["--log-path", log_path.to_s])
214
- if @options[:output_query_log]
215
- arguments.concat(["--query-log-path", query_log_path.to_s])
216
- end
217
- arguments << "-s"
218
- arguments << @database_path.to_s
219
- @pid = spawn(@groonga, *arguments)
220
-
221
- n_retries = 10
222
- begin
223
- send_command("status")
224
- rescue SystemCallError
225
- sleep(1)
226
- n_retries -= 1
227
- raise if n_retries.zero?
228
- retry
229
- end
230
-
231
- yield if block_given?
232
- end
233
-
234
- def ensure_database
235
- if @options[:recreate_database]
236
- FileUtils.rm_rf(@database_path.dirname.to_s)
237
- end
238
-
239
- return if @database_path.exist?
240
- FileUtils.mkdir_p(@database_path.dirname.to_s)
241
- system(@groonga, "-n", @database_path.to_s, "quit")
242
- grn_files.each do |grn_file|
243
- command = [
244
- @groonga,
245
- "--log-path", log_path.to_s,
246
- "--file", grn_file.to_s,
247
- @database_path.to_s,
248
- ]
249
- command_line = command.join(" ")
250
- puts("Running...: #{command_line}")
251
- pid = spawn(*command)
252
- begin
253
- pid, status = Process.waitpid2(pid)
254
- rescue Interrupt
255
- Process.kill(:TERM, pid)
256
- pid, status = Process.waitpid2(pid)
257
- end
258
- unless status.success?
259
- raise "Failed to run: #{command_line}"
260
- end
261
- end
262
- end
263
-
264
- def use_persistent_cache?
265
- @groonga_options.include?("--cache-base-path")
266
- end
267
-
268
- def shutdown
269
- begin
270
- send_command("shutdown")
271
- rescue SystemCallError
272
- end
273
- Process.waitpid(@pid)
274
- end
275
-
276
- private
277
- def find_unused_port
278
- server = TCPServer.new(@host, 0)
279
- begin
280
- server.addr[1]
281
- ensure
282
- server.close
283
- end
284
- end
285
-
286
- def log_path
287
- @database_path.dirname + "groonga.log"
288
- end
289
-
290
- def query_log_path
291
- @database_path.dirname + "query.log"
292
- end
293
-
294
- def send_command(name)
295
- Net::HTTP.start(@host, @port) do |http|
296
- response = http.get("/d/#{name}")
297
- response.body
298
- end
299
- end
300
-
301
- def grn_files
302
- files = schema_files
303
- files += data_files if @options[:load_data]
304
- files += index_files
305
- files
306
- end
307
-
308
- def schema_files
309
- Pathname.glob("#{@input_directory}/schema/**/*.grn").sort
310
- end
311
-
312
- def index_files
313
- Pathname.glob("#{@input_directory}/indexes/**/*.grn").sort
314
- end
315
-
316
- def data_files
317
- Pathname.glob("#{@input_directory}/data/**/*.grn").sort
318
- end
319
- end
320
-
321
- class Tester
322
- def initialize(old, new, options)
323
- @old = old
324
- @new = new
325
- @input_directory = options[:input_directory] || Pathname.new(".")
326
- @working_directory = options[:working_directory] || Pathname.new(".")
327
- @n_clients = options[:n_clients] || 1
328
- @options = options
329
- @n_ready_waits = 2
330
- end
331
-
332
- def run
333
- @old.ensure_database
334
- @new.ensure_database
335
-
336
- old_thread = Thread.new do
337
- @old.run do
338
- run_test
339
- end
340
- end
341
- new_thread = Thread.new do
342
- @new.run do
343
- run_test
344
- end
345
- end
346
-
347
- old_thread_success = old_thread.value
348
- new_thread_success = new_thread.value
349
-
350
- old_thread_success and new_thread_success
351
- end
352
-
353
- private
354
- def run_test
355
- @n_ready_waits -= 1
356
- return true unless @n_ready_waits.zero?
357
-
358
- query_log_paths.each do |query_log_path|
359
- log_path = test_log_path(query_log_path)
360
- if @options[:skip_finished_queries] and log_path.exist?
361
- puts("Skip query log: #{query_log_path}")
362
- next
363
- else
364
- puts("Running test against query log...: #{query_log_path}")
365
- end
366
- begin
367
- if use_persistent_cache?
368
- callback = lambda do
369
- if @old.use_persistent_cache?
370
- @old.shutdown
371
- @old.run
372
- end
373
- if @new.use_persistent_cache?
374
- @new.shutdown
375
- @new.run
376
- end
377
- end
378
- else
379
- callback = nil
380
- end
381
- verify_server(log_path, query_log_path, &callback)
382
- rescue Interrupt
383
- puts("Interrupt: #{query_log_path}")
384
- end
385
- end
386
-
387
- old_thread = Thread.new do
388
- @old.shutdown
389
- end
390
- new_thread = Thread.new do
391
- @new.shutdown
392
- end
393
- old_thread.join
394
- new_thread.join
395
-
396
- true
397
- end
398
-
399
- def verify_server(test_log_path, query_log_path, &callback)
400
- command_line = [
401
- "--n-clients=#{@n_clients}",
402
- "--groonga1-host=#{@old.host}",
403
- "--groonga1-port=#{@old.port}",
404
- "--groonga1-protocol=http",
405
- "--groonga2-host=#{@new.host}",
406
- "--groonga2-port=#{@new.port}",
407
- "--groonga2-protocol=http",
408
- "--output", test_log_path.to_s,
409
- ]
410
- command_line << "--no-care-order" if @options[:care_order] == false
411
- command_line << query_log_path.to_s
412
- if use_persistent_cache?
413
- command_line << "--verify-cache"
414
- end
415
- verify_server = VerifyServer.new
416
- verify_server.run(command_line, &callback)
417
- end
418
-
419
- def query_log_paths
420
- Pathname.glob("#{@input_directory}/query-logs/**/*.log").sort
421
- end
422
-
423
- def test_log_path(query_log_path)
424
- @working_directory + "results" + query_log_path.basename
425
- end
426
-
427
- def use_persistent_cache?
428
- @old.use_persistent_cache? or @new.use_persistent_cache?
429
- end
430
- end
431
- end
432
- end
433
- end
434
- end
18
+ require "groonga-query-log/command/run-regression-test"