#!/usr/bin/perl

BEGIN {
   die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
      unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
   unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
   $ENV{PTTEST_PRETTY_JSON} = 0;

};

use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use JSON;
use File::Slurp;

use Data::Dumper;
$Data::Dumper::Indent    = 1;
$Data::Dumper::Sortkeys  = 1;
$Data::Dumper::Quotekeys = 0;

use JSONReportFormatter;
use OptionParser;
use DSNParser;
use EventAggregator;
use QueryRewriter;
use QueryParser;
use Quoter;
use PerconaTest;

my ($result, $events, $expected);

my $o  = new OptionParser(description=>'JSONReportFormatter');
my $q  = new Quoter();
my $qp = new QueryParser();
my $qr = new QueryRewriter(QueryParser=>$qp);

$o->get_specs("$trunk/bin/pt-query-digest");

my $j = new JSONReportFormatter(
   OptionParser  => $o,
   QueryRewriter => $qr,
   QueryParser   => $qp,
   Quoter        => $q, 
);

my $ea = new EventAggregator(
   groupby => 'fingerprint',
   worst   => 'Query_time',
   attributes => {
      Query_time    => [qw(Query_time)],
      Lock_time     => [qw(Lock_time)],
      user          => [qw(user)],
      ts            => [qw(ts)],
      Rows_sent     => [qw(Rows_sent)],
      Rows_examined => [qw(Rows_examined)],
      db            => [qw(db)],
   },
);

isa_ok(
   $j,
   'JSONReportFormatter'
) or die "Cannot create a JSONReportFormatter";

$events = [
   {  ts            => '071015 21:43:52',
      cmd           => 'Query',
      user          => 'root',
      host          => 'localhost',
      ip            => '',
      arg           => "SELECT id FROM users WHERE name='foo'",
      Query_time    => '8.000652',
      Lock_time     => '0.000109',
      Rows_sent     => 1,
      Rows_examined => 1,
      pos_in_log    => 1,
      db            => 'test3',
   },
   {  ts   => '071015 21:43:52',
      cmd  => 'Query',
      user => 'root',
      host => 'localhost',
      ip   => '',
      arg =>
         "INSERT IGNORE INTO articles (id, body,)VALUES(3558268,'sample text')",
      Query_time    => '1.001943',
      Lock_time     => '0.000145',
      Rows_sent     => 0,
      Rows_examined => 0,
      pos_in_log    => 2,
      db            => 'test1',
   },
   {  ts            => '071015 21:43:53',
      cmd           => 'Query',
      user          => 'bob',
      host          => 'localhost',
      ip            => '',
      arg           => "SELECT id FROM users WHERE name='bar'",
      Query_time    => '1.000682',
      Lock_time     => '0.000201',
      Rows_sent     => 1,
      Rows_examined => 2,
      pos_in_log    => 5,
      db            => 'test1',
   }
];

# Here's the breakdown of values for those three events:
# 
# ATTRIBUTE     VALUE     BUCKET  VALUE        RANGE
# Query_time => 8.000652  326     7.700558026  range [7.700558026, 8.085585927)
# Query_time => 1.001943  284     0.992136979  range [0.992136979, 1.041743827)
# Query_time => 1.000682  284     0.992136979  range [0.992136979, 1.041743827)
#               --------          -----------
#               10.003277         9.684831984
#
# Lock_time  => 0.000109  97      0.000108186  range [0.000108186, 0.000113596)
# Lock_time  => 0.000145  103     0.000144980  range [0.000144980, 0.000152229)
# Lock_time  => 0.000201  109     0.000194287  range [0.000194287, 0.000204002)
#               --------          -----------
#               0.000455          0.000447453
#
# Rows_sent  => 1         284     0.992136979  range [0.992136979, 1.041743827)
# Rows_sent  => 0         0       0
# Rows_sent  => 1         284     0.992136979  range [0.992136979, 1.041743827)
#               --------          -----------
#               2                 1.984273958
#
# Rows_exam  => 1         284     0.992136979  range [0.992136979, 1.041743827)
# Rows_exam  => 0         0       0 
# Rows_exam  => 2         298     1.964363355, range [1.964363355, 2.062581523) 
#               --------          -----------
#               3                 2.956500334

# I hand-checked these values with my TI-83 calculator.
# They are, without a doubt, correct.

foreach my $event (@$events) {
   $event->{fingerprint} = $qr->fingerprint( $event->{arg} );
   $ea->aggregate($event);
}
$ea->calculate_statistical_metrics(apdex_t=>1);
my %top_spec = (
   attrib  => 'Query_time',
   orderby => 'sum',
   total   => 100,
   count   => undef,
);
@top_spec{qw(ol_attrib ol_limit ol_freq)} = split(/:/, "Query_time:1:10");
my ($worst, $other) = $ea->top_events(%top_spec);
$result = $j->query_report(
   ea      => $ea,
   worst   => $worst,
   orderby => 'Query_time',
   groupby => 'fingerprint',
);

my $sample_file = "t/lib/samples/JSONReportFormatter/report001.json";
my $want_text = read_file($sample_file);
my $want = decode_json $want_text;
my $got = decode_json $result;


# I've change the original test because it was comparing JSONs as strings
# but it is hard (or impossible) to ensure in all environments the output
# will have a particular order.
# I prefer to decode_json($result) and compare it against the struct I am
# expecting as a result for 2 reasons:
# 1) using decode_json ensures that the json syntax is valid, but comparing 
# strings cannot ensure that since the sample json may contain syntax errors.
# 2) Using structs (hashes) and is_deeply makes this test to work regarding
# of the sort order during the encoding process.

is_deeply(
           $got,
           $want,
           'Basic output',
);

# #############################################################################
# Done.
# #############################################################################
done_testing;
