From 89db22894ec2bcd10d444e1b8a66b217583c5418 Mon Sep 17 00:00:00 2001 From: Daniel Nichter Date: Fri, 19 Apr 2013 14:49:01 -0600 Subject: [PATCH] Test get_services(). Need to fix/update other tests. --- bin/pt-agent | 34 ++- lib/Percona/WebAPI/Resource/Service.pm | 7 + lib/Percona/WebAPI/Resource/Task.pm | 6 - t/pt-agent/get_services.t | 394 +++++++++++++++++++++++++ t/pt-agent/make_new_crontab.t | 1 + t/pt-agent/run_agent.t | 2 + t/pt-agent/run_service.t | 6 + t/pt-agent/schedule_services.t | 2 + t/pt-agent/write_services.t | 1 + 9 files changed, 432 insertions(+), 21 deletions(-) create mode 100644 t/pt-agent/get_services.t diff --git a/bin/pt-agent b/bin/pt-agent index b07ac577..af2af0af 100755 --- a/bin/pt-agent +++ b/bin/pt-agent @@ -1386,6 +1386,13 @@ has 'meta' => ( default => sub { return 0 }, ); +has 'run_once' => ( + is => 'ro', + isa => 'Bool', + required => 0, + default => sub { return 0 }, +); + has 'links' => ( is => 'rw', isa => 'Maybe[HashRef]', @@ -1444,12 +1451,6 @@ has 'program' => ( required => 0, ); -has 'options' => ( - is => 'ro', - isa => 'Maybe[Str]', - required => 0, -); - has 'query' => ( is => 'ro', isa => 'Maybe[Str]', @@ -5629,6 +5630,7 @@ sub get_services { services => $sorted_services->{removed}, lib_dir => $lib_dir, bin_dir => $args{bin_dir}, # optional, for testing + exec_cmd => $args{exec_cmd}, # optional, for testing ); # Second, save each service in --lib/services/. Do this before @@ -5654,6 +5656,7 @@ sub get_services { services => $sorted_services->{added}, lib_dir => $lib_dir, bin_dir => $args{bin_dir}, # optional, for testing + exec_cmd => $args{exec_cmd}, # optional, for testing ); # Restart existing updated services. @@ -5662,6 +5665,7 @@ sub get_services { services => $sorted_services->{updated}, lib_dir => $lib_dir, bin_dir => $args{bin_dir}, # optional, for testing + exec_cmd => $args{exec_cmd}, # optional, for testing ); # Run services with the run_once flag. Unlike run_services(), @@ -5672,6 +5676,7 @@ sub get_services { services => $sorted_services->{services}, lib_dir => $lib_dir, bin_dir => $args{bin_dir}, # optional, for testing + exec_cmd => $args{exec_cmd}, # optional, for testing ); # Schedule any services with a run_schedule or spool_schedule. @@ -5684,6 +5689,7 @@ sub get_services { services => $sorted_services->{services}, lib_dir => $lib_dir, bin_dir => $args{bin_dir}, # optional, for testing + exec_cmd => $args{exec_cmd}, # optional, for testing ); $prev_services = $sorted_services->{services}; @@ -5806,7 +5812,8 @@ sub schedule_services { my $lib_dir = $args{lib_dir}; # Optional args - my $quiet = $args{quiet}; + my $quiet = $args{quiet}; + my $exec_cmd = $args{exec_cmd} || sub { return system(@_) }; _info("Scheduling services") unless $quiet; @@ -5831,8 +5838,8 @@ sub schedule_services { or die "Error closing $crontab_file: $OS_ERROR"; my $err_file = "$lib_dir/crontab.err"; - system("crontab $crontab_file > $err_file 2>&1"); - if ( $CHILD_ERROR ) { + my $retval = $exec_cmd->("crontab $crontab_file > $err_file 2>&1"); + if ( $retval ) { my $error = `cat $err_file`; die "Error setting new crontab: $error\n"; } @@ -5926,8 +5933,7 @@ sub run_services { if ( -f "$lib_dir/services/stop-$name" ) { my $cmd = sprintf $cmd_fmt, "stop-$name"; _info("Stopping $name: $cmd"); - $exec_cmd->($cmd); - my $cmd_exit_status = $CHILD_ERROR >> 8; + my $cmd_exit_status = $exec_cmd->($cmd); if ( $cmd_exit_status != 0 ) { _warn("Error stopping $name, check $log and " . "$lib_dir/logs/$name.run"); @@ -5959,8 +5965,7 @@ sub run_services { if ( -f "$lib_dir/services/start-$name" ) { my $cmd = sprintf $cmd_fmt, "start-$name"; _info("Starting $name: $cmd"); - $exec_cmd->($cmd); - my $cmd_exit_status = $CHILD_ERROR >> 8; + my $cmd_exit_status = $exec_cmd->($cmd); if ( $cmd_exit_status != 0 ) { _warn("Error starting $name, check $log and " ."$lib_dir/logs/$name.run"); @@ -6003,8 +6008,7 @@ sub run_services_once { my $cmd = sprintf $cmd_fmt, "start-$name"; _info("Running $name: $cmd"); - $exec_cmd->($cmd); - my $cmd_exit_status = $CHILD_ERROR >> 8; + my $cmd_exit_status = $exec_cmd->($cmd); if ( $cmd_exit_status != 0 ) { _warn("Error starting $name, check $log and " ."$lib_dir/logs/$name.run"); diff --git a/lib/Percona/WebAPI/Resource/Service.pm b/lib/Percona/WebAPI/Resource/Service.pm index 2a5fe565..1bac2fec 100644 --- a/lib/Percona/WebAPI/Resource/Service.pm +++ b/lib/Percona/WebAPI/Resource/Service.pm @@ -59,6 +59,13 @@ has 'meta' => ( default => sub { return 0 }, ); +has 'run_once' => ( + is => 'ro', + isa => 'Bool', + required => 0, + default => sub { return 0 }, +); + has 'links' => ( is => 'rw', isa => 'Maybe[HashRef]', diff --git a/lib/Percona/WebAPI/Resource/Task.pm b/lib/Percona/WebAPI/Resource/Task.pm index db9bf86f..782ca40d 100644 --- a/lib/Percona/WebAPI/Resource/Task.pm +++ b/lib/Percona/WebAPI/Resource/Task.pm @@ -40,12 +40,6 @@ has 'program' => ( required => 0, ); -has 'options' => ( - is => 'ro', - isa => 'Maybe[Str]', - required => 0, -); - has 'query' => ( is => 'ro', isa => 'Maybe[Str]', diff --git a/t/pt-agent/get_services.t b/t/pt-agent/get_services.t new file mode 100644 index 00000000..860ae090 --- /dev/null +++ b/t/pt-agent/get_services.t @@ -0,0 +1,394 @@ +#!/usr/bin/env 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"; +}; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use Test::More; + +use JSON; +use File::Temp qw(tempdir); + +use Percona::Test; +use Percona::Test::Mock::UserAgent; +require "$trunk/bin/pt-agent"; + +Percona::Toolkit->import(qw(Dumper)); +Percona::WebAPI::Representation->import(qw(as_hashref)); + +# Fake --lib and --spool dirs. +my $tmpdir = tempdir("/tmp/pt-agent.$PID.XXXXXX", CLEANUP => 1); +output( sub { + pt_agent::init_lib_dir(lib_dir => $tmpdir); +}); + +# ############################################################################# +# Create mock client and Agent +# ############################################################################# + +# These aren't the real tests yet: to run_agent, first we need +# a client and Agent, so create mock ones. + +my $output; +my $json = JSON->new->canonical([1])->pretty; +$json->allow_blessed([]); +$json->convert_blessed([]); + +my $ua = Percona::Test::Mock::UserAgent->new( + encode => sub { my $c = shift; return $json->encode($c || {}) }, +); + +my $client = eval { + Percona::WebAPI::Client->new( + api_key => '123', + ua => $ua, + ); +}; + +is( + $EVAL_ERROR, + '', + 'Create mock client' +) or die; + +my $agent = Percona::WebAPI::Resource::Agent->new( + uuid => '123', + hostname => 'host', + username => 'user', + links => { + self => '/agents/123', + config => '/agents/123/config', + }, +); + +my @cmds; +my $exec_cmd = sub { + my $cmd = shift; + push @cmds, $cmd; + return 0; +}; + +# ############################################################################# +# Test get_services() +# ############################################################################# + +# query-history + +my $run0 = Percona::WebAPI::Resource::Task->new( + name => 'query-history', + number => '0', + program => 'pt-query-digest --output json', + output => 'spool', +); + +my $qh = Percona::WebAPI::Resource::Service->new( + ts => '100', + name => 'query-history', + run_schedule => '1 * * * *', + spool_schedule => '2 * * * *', + tasks => [ $run0 ], + links => { + self => '/query-history', + data => '/query-history/data', + }, +); + +$ua->{responses}->{get} = [ + { + headers => { 'X-Percona-Resource-Type' => 'Service' }, + content => [ as_hashref($qh, with_links => 1) ], + }, +]; + +my $services = {}; +my $success = 0; + +$output = output( + sub { + ($services, $success) = pt_agent::get_services( + # Required args + link => '/agents/123/services', + agent => $agent, + client => $client, + lib_dir => $tmpdir, + services => $services, + # Optional args, for testing + json => $json, + bin_dir => "$trunk/bin/", + exec_cmd => $exec_cmd, + ); + }, + stderr => 1, +); + +is( + $success, + 1, + "Success" +); + +is( + ref $services, + 'HASH', + "Return services as hashref" +) or diag(Dumper($services)); + +is( + scalar keys %$services, + 1, + 'Only 1 service' +) or diag(Dumper($services)); + +ok( + exists $services->{'query-history'}, + "services hashref keyed on service name" +) or diag(Dumper($services)); + +isa_ok( + ref $services->{'query-history'}, + 'Percona::WebAPI::Resource::Service', + 'services->{query-history}' +); + +my $crontab = slurp_file("$tmpdir/crontab"); +is( + $crontab, + "1 * * * * $trunk/bin/pt-agent --run-service query-history +2 * * * * $trunk/bin/pt-agent --send-data query-history +", + "crontab file" +) or diag($output); + +is_deeply( + \@cmds, + [ + "crontab $tmpdir/crontab > $tmpdir/crontab.err 2>&1", + ], + "Only ran crontab" +) or diag(Dumper(\@cmds)); + +ok( + -f "$tmpdir/services/query-history", + "Wrote --lib/services/query-history" +); + +# ############################################################################# +# A more realistic transaction +# ############################################################################# + +# services/query-history should exist from the previous tests. For these +# tests, get_services() should update the file, so we empty it and check +# that it's re-created, i.e. updated. +diag(`echo -n > $tmpdir/services/query-history`); +is( + -s "$tmpdir/services/query-history", + 0, + "Start: empty --lib/services/query-history" +); + +# start-query-history + +my $task1 = Percona::WebAPI::Resource::Task->new( + name => 'disable-slow-query-log', + number => '0', + query => "SET GLOBAL slow_query_log=0", +); + +my $task2 = Percona::WebAPI::Resource::Task->new( + name => 'set-slow-query-log-file', + number => '1', + query => "SET GLOBAL slow_query_log_file='/tmp/slow.log'", +); + +my $task3 = Percona::WebAPI::Resource::Task->new( + name => 'set-long-query-time', + number => '2', + query => "SET GLOBAL long_query_time=0.01", +); + +my $task4 = Percona::WebAPI::Resource::Task->new( + name => 'enable-slow-query-log', + number => '3', + query => "SET GLOBAL slow_query_log=1", +); + +my $start_qh = Percona::WebAPI::Resource::Service->new( + ts => '100', + name => 'start-query-history', + tasks => [ $task1, $task2, $task3, $task4 ], + meta => 1, + links => { + self => '/query-history', + data => '/query-history/data', + }, +); + +# stop-query-history + +my $task5 = Percona::WebAPI::Resource::Task->new( + name => 'disable-slow-query-log', + number => '0', + query => "SET GLOBAL slow_query_log=0", +); + +my $stop_qh = Percona::WebAPI::Resource::Service->new( + ts => '100', + name => 'stop-query-history', + tasks => [ $task5 ], + meta => 1, + links => { + self => '/query-history', + data => '/query-history/data', + }, +); + +# We'll use query-history from the previous tests. + +$ua->{responses}->{get} = [ + { + headers => { 'X-Percona-Resource-Type' => 'Service' }, + content => [ + as_hashref($start_qh, with_links => 1), + as_hashref($stop_qh, with_links => 1), + as_hashref($qh, with_links => 1), # from previous tests + ], + }, +]; + +@cmds = (); +$services = {}; +$success = 0; + +$output = output( + sub { + ($services, $success) = pt_agent::get_services( + # Required args + link => '/agents/123/services', + agent => $agent, + client => $client, + lib_dir => $tmpdir, + services => $services, + # Optional args, for testing + json => $json, + bin_dir => "$trunk/bin/", + exec_cmd => $exec_cmd, + ); + }, + stderr => 1, +); + +is_deeply( + \@cmds, + [ + "$trunk/bin/pt-agent --run-service start-query-history >> $tmpdir/logs/start-stop.log 2>&1", + "crontab $tmpdir/crontab > $tmpdir/crontab.err 2>&1", + ], + "Start: ran start-query-history" +) or diag(Dumper(\@cmds), $output); + +ok( + -f "$tmpdir/services/start-query-history", + "Start: added --lib/services/start-query-history" +) or diag($output); + +ok( + -f "$tmpdir/services/stop-query-history", + "Start: added --lib/services/stop-query-history" +) or diag($output); + +my $contents = slurp_file("$tmpdir/services/query-history"); +like( + $contents, + qr/query-history/, + "Start: updated --lib/services/query-history" +) or diag($output); + +$crontab = slurp_file("$tmpdir/crontab"); +is( + $crontab, + "1 * * * * $trunk/bin/pt-agent --run-service query-history +2 * * * * $trunk/bin/pt-agent --send-data query-history +", + "Start: only scheduled query-history" +) or diag($output); + +# ############################################################################# +# Update and restart a service +# ############################################################################# + +# pt-agent should remove a service's --lib/meta/ files when restarting, +# so create one and check that it's removed. +diag(`touch $tmpdir/meta/query-history.foo`); +ok( + -f "$tmpdir/meta/query-history.foo", + "Restart: meta file exists" +); + +$qh = Percona::WebAPI::Resource::Service->new( + ts => '200', # was 100 + name => 'query-history', + run_schedule => '1 * * * *', + spool_schedule => '2 * * * *', + tasks => [ $run0 ], + links => { + self => '/query-history', + data => '/query-history/data', + }, +); + +$ua->{responses}->{get} = [ + { + headers => { 'X-Percona-Resource-Type' => 'Service' }, + content => [ + as_hashref($start_qh, with_links => 1), # has not changed + as_hashref($stop_qh, with_links => 1), # has not changed + as_hashref($qh, with_links => 1), + ], + }, +]; + +@cmds = (); +$success = 0; + +$output = output( + sub { + ($services, $success) = pt_agent::get_services( + # Required args + link => '/agents/123/services', + agent => $agent, + client => $client, + lib_dir => $tmpdir, + services => $services, # retval from previous call + # Optional args, for testing + json => $json, + bin_dir => "$trunk/bin/", + exec_cmd => $exec_cmd, + ); + }, + stderr => 1, +); + +is_deeply( + \@cmds, + [ + "$trunk/bin/pt-agent --run-service stop-query-history >> $tmpdir/logs/start-stop.log 2>&1", + "$trunk/bin/pt-agent --run-service start-query-history >> $tmpdir/logs/start-stop.log 2>&1", + "crontab $tmpdir/crontab > $tmpdir/crontab.err 2>&1", + ], + "Restart: ran stop-query-history then start-query-history" +) or diag(Dumper(\@cmds), $output); + +ok( + !-f "$tmpdir/meta/query-history.foo", + "Restart: meta file removed" +) or diag($output); + +# ############################################################################# +# Done. +# ############################################################################# +done_testing; diff --git a/t/pt-agent/make_new_crontab.t b/t/pt-agent/make_new_crontab.t index 699409a1..05c90b46 100644 --- a/t/pt-agent/make_new_crontab.t +++ b/t/pt-agent/make_new_crontab.t @@ -56,6 +56,7 @@ my $run0 = Percona::WebAPI::Resource::Task->new( ); my $svc0 = Percona::WebAPI::Resource::Service->new( + ts => '100', name => 'query-history', run_schedule => '* 8 * * 1,2,3,4,5', spool_schedule => '* 9 * * 1,2,3,4,5', diff --git a/t/pt-agent/run_agent.t b/t/pt-agent/run_agent.t index dc6ebbeb..f07f3c91 100644 --- a/t/pt-agent/run_agent.t +++ b/t/pt-agent/run_agent.t @@ -132,6 +132,7 @@ my $run0 = Percona::WebAPI::Resource::Task->new( ); my $svc0 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'query-history', run_schedule => '1 * * * *', spool_schedule => '2 * * * *', @@ -384,6 +385,7 @@ $run0 = Percona::WebAPI::Resource::Task->new( ); $svc0 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'test-run-at-start', run_schedule => '0 0 1 1 *', run_once => 1, # here's the magic diff --git a/t/pt-agent/run_service.t b/t/pt-agent/run_service.t index e5a451ac..682ed6b8 100644 --- a/t/pt-agent/run_service.t +++ b/t/pt-agent/run_service.t @@ -74,6 +74,7 @@ my $run0 = Percona::WebAPI::Resource::Task->new( ); my $svc0 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'query-history', run_schedule => '1 * * * *', spool_schedule => '2 * * * *', @@ -96,6 +97,7 @@ my $output = output( ); }, stderr => 1, + debug =>1, ); ok( @@ -147,6 +149,7 @@ my $run1 = Percona::WebAPI::Resource::Task->new( ); $svc0 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'query-history', run_schedule => '3 * * * *', spool_schedule => '4 * * * *', @@ -232,6 +235,7 @@ SKIP: { query => "SET GLOBAL general_log=ON", ); my $svc0 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'enable-gen-log', run_schedule => '1 * * * *', spool_schedule => '2 * * * *', @@ -247,6 +251,7 @@ SKIP: { output => 'spool', ); my $svc1 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'query-history', run_schedule => '3 * * * *', spool_schedule => '4 * * * *', @@ -270,6 +275,7 @@ SKIP: { query => "SET GLOBAL general_log=ON", ); my $svc2 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'disable-gen-log', run_schedule => '5 * * * *', spool_schedule => '6 * * * *', diff --git a/t/pt-agent/schedule_services.t b/t/pt-agent/schedule_services.t index d70f7489..1814ae82 100644 --- a/t/pt-agent/schedule_services.t +++ b/t/pt-agent/schedule_services.t @@ -39,6 +39,7 @@ my $run0 = Percona::WebAPI::Resource::Task->new( ); my $svc0 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'query-history', run_schedule => '* 8 * * 1,2,3,4,5', spool_schedule => '* 9 * * 1,2,3,4,5', @@ -129,6 +130,7 @@ is( # ############################################################################# $svc0 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'query-history', run_schedule => '* * * * Foo', # "foo":0: bad day-of-week spool_schedule => '* 8 * * Mon', diff --git a/t/pt-agent/write_services.t b/t/pt-agent/write_services.t index 3a17736c..0b5f3712 100644 --- a/t/pt-agent/write_services.t +++ b/t/pt-agent/write_services.t @@ -72,6 +72,7 @@ my $run0 = Percona::WebAPI::Resource::Task->new( ); my $svc0 = Percona::WebAPI::Resource::Service->new( + ts => 100, name => 'query-history', run_schedule => '1 * * * *', spool_schedule => '2 * * * *',