class GroongaQueryLog::Command::FormatRegressionTestLogs

Public Class Methods

new(options={}) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 36
def initialize(options={})
  @output = options[:output] || $stdout
end

Public Instance Methods

run(command_line) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 40
def run(command_line)
  parser = OptionParser.new
  parser.banner += " PATH1 PATH2 ..."
  parser.version = VERSION
  paths = parser.parse!(command_line)

  if paths.empty?
    format_log($stdin, "-")
  else
    paths.each do |path|
      if File.directory?(path)
        Find.find(path) do |sub_path|
          next unless File.file?(sub_path)
          File.open(sub_path, encoding: "UTF-8") do |file|
            format_log(file, sub_path)
          end
        end
      else
        File.open(path, encoding: "UTF-8") do |file|
          format_log(file, path)
        end
      end
    end
  end
  true
end

Private Instance Methods

format_log(input, path) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 68
def format_log(input, path)
  command = nil
  response_old = nil
  response_new = nil
  backtrace = []
  error_message = nil
  elapsed_time_old = nil
  elapsed_time_new = nil
  elapsed_time_ratio = nil
  elapsed_times_old = nil
  elapsed_times_new = nil

  input.each_line do |line|
    unless line.valid_encoding?
      @output.puts("invalid encoding line")
      @output.puts("#{path}:#{input.lineno}:#{line}")
      next
    end
    case line
    when /\Acommand: /
      command = $POSTMATCH.chomp
    when /\Aresponse1: /
      response_old = $POSTMATCH.chomp
    when /\Aresponse2: /
      response_new = $POSTMATCH.chomp
      next unless valid_entry?(command, response_old, response_new)
      report_diff(command, response_old, response_new)
    when /\Aerror: /
      error_message = $POSTMATCH.chomp
      report_error(command, error_message, backtrace)
      backtrace.clear
    when /\Abacktrace: /
      backtrace.unshift($POSTMATCH.chomp)
    when /\Aelapsed_time_old: /
      elapsed_time_old = Float($POSTMATCH.chomp)
    when /\Aelapsed_time_new: /
      elapsed_time_new = Float($POSTMATCH.chomp)
    when /\Aelapsed_times_old: /
      elapsed_times_old = $POSTMATCH.chomp.split.collect do |value|
        Float(value)
      end
    when /\Aelapsed_times_new: /
      elapsed_times_new = $POSTMATCH.chomp.split.collect do |value|
        Float(value)
      end
    when /\Aelapsed_time_ratio: /
      elapsed_time_ratio = Float($POSTMATCH.chomp)
      report_slow(command,
                  elapsed_time_old,
                  elapsed_time_new,
                  elapsed_times_old,
                  elapsed_times_new,
                  elapsed_time_ratio)
    end
  end
end
report_command(command) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 229
def report_command(command)
  @output.puts("Command:")
  @output.puts(command)
  parsed_command = Groonga::Command::Parser.parse(command)
  @output.puts("Name: #{parsed_command.name}")
  @output.puts("Arguments:")
  sorted_arguments = parsed_command.arguments.sort_by do |key, value|
    key
  end
  sorted_arguments.each do |key, value|
    @output.puts("  #{key}: #{value}")
  end
end
report_diff(command, response_old, response_new) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 155
def report_diff(command, response_old, response_new)
  return if response_old == response_new

  report_command(command)

  lines_old = response_to_lines(response_old)
  lines_new = response_to_lines(response_new)
  diffs = Diff::LCS.diff(lines_old, lines_new)

  @output.puts("--- old")
  @output.puts("+++ new")

  old_hunk = nil
  n_lines = 3
  format = :unified
  file_length_difference = 0
  diffs.each do |piece|
    begin
      hunk = Diff::LCS::Hunk.new(lines_old,
                                 lines_new,
                                 piece,
                                 n_lines,
                                 file_length_difference)
      file_length_difference = hunk.file_length_difference

      next unless old_hunk

      if (n_lines > 0) && hunk.overlaps?(old_hunk)
        hunk.merge(old_hunk)
      else
        @output.puts(old_hunk.diff(format))
      end
    ensure
      old_hunk = hunk
    end
  end

  if old_hunk
    @output.puts(old_hunk.diff(format))
  end
end
report_error(command, message, backtrace) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 201
def report_error(command, message, backtrace)
  report_command(command)
  @output.puts("Error: #{message}")
  @output.puts("Backtrace:")
  @output.puts(backtrace)
end
report_slow(command, elapsed_time_old, elapsed_time_new, elapsed_times_old, elapsed_times_new, elapsed_time_ratio) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 208
def report_slow(command,
                elapsed_time_old,
                elapsed_time_new,
                elapsed_times_old,
                elapsed_times_new,
                elapsed_time_ratio)
  report_command(command)
  elapsed_times_old ||= [elapsed_time_old]
  elapsed_times_new ||= [elapsed_time_new]
  @output.puts("Slow:")
  @output.puts("  Old: %s (%s)" % [
                 format_elapsed_time(elapsed_time_old),
                 format_elapsed_times(elapsed_times_old),
               ])
  @output.puts("  New: %s (%s)" % [
                 format_elapsed_time(elapsed_time_new),
                 format_elapsed_times(elapsed_times_new),
               ])
  @output.puts("  Ratio: +%.1f%%" % ((elapsed_time_ratio * 100) - 100))
end
response_to_lines(response) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 197
def response_to_lines(response)
  PP.pp(JSON.parse(response), "").lines.collect(&:chomp)
end
valid_entry?(command, response_old, response_new) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 125
def valid_entry?(command, response_old, response_new)
  valid = true
  unless validate_response(command, "old", response_old)
    valid = false
  end
  unless validate_response(command, "new", response_new)
    valid = false
  end
  valid
end
validate_response(command, type, response) click to toggle source
# File lib/groonga-query-log/command/format-regression-test-logs.rb, line 136
def validate_response(command, type, response)
  if response.nil?
    @output.puts(command)
    @output.puts("no #{type} response")
    return false
  end

  begin
    JSON.parse(response)
  rescue JSON::ParserError
    @output.puts(command)
    @output.puts("failed to parse #{type} response: #{$!.message}")
    @output.puts(response)
    return false
  end

  true
end