From 6218a3f85be89db93132c481cfffebd3da60faed Mon Sep 17 00:00:00 2001 From: Michele Pagot <101880010+mpagot@users.noreply.github.com> Date: Wed, 2 Aug 2023 08:56:20 +0200 Subject: [PATCH] Manage failok in all qesap_ansible functions (#17518) Always provide a 0 default for failok. Export qesap_upload_crm_report. Create an utility function to download the fetch and command playbooks. Remove some argument to local variable translations. Remove not necessary tests on mandatory arguments. Add all relevant unit testing. --- lib/qesapdeployment.pm | 124 +++++---- t/09_qesapdeployment.t | 251 +++++++++++++++--- .../sles4sap/qesapdeployment/test_cluster.pm | 5 +- 3 files changed, 284 insertions(+), 96 deletions(-) diff --git a/lib/qesapdeployment.pm b/lib/qesapdeployment.pm index ced5729c7e3b..34e084cad46a 100644 --- a/lib/qesapdeployment.pm +++ b/lib/qesapdeployment.pm @@ -76,6 +76,7 @@ our @EXPORT = qw( qesap_wait_for_ssh qesap_cluster_log_cmds qesap_cluster_logs + qesap_upload_crm_report qesap_az_get_vnet qesap_az_get_resource_group qesap_az_calculate_address_range @@ -211,11 +212,11 @@ sub qesap_venv_cmd_exec { my (%args) = @_; croak 'Missing mandatory cmd argument' unless $args{cmd}; $args{timeout} //= bmwqemu::scale_timeout(90); - my $failok = $args{failok} // 0; + $args{failok} //= 0; my $ret; assert_script_run('source ' . QESAPDEPLOY_VENV . '/bin/activate'); - $failok ? $ret = script_run($args{cmd}, timeout => $args{timeout}) : + $args{failok} ? $ret = script_run($args{cmd}, timeout => $args{timeout}) : assert_script_run($args{cmd}, timeout => $args{timeout}); # deactivate python virtual environment script_run('deactivate'); @@ -260,10 +261,10 @@ sub qesap_pip_install { sub qesap_upload_logs { my (%args) = @_; - my $failok = $args{failok} || 0; - record_info("Uploading logfiles failok:$failok", join("\n", @log_files)); + $args{failok} //= 0; + record_info("Uploading logfiles failok:$args{failok}", join("\n", @log_files)); while (my $file = pop @log_files) { - upload_logs($file, failok => $failok); + upload_logs($file, failok => $args{failok}); } } @@ -533,6 +534,25 @@ sub qesap_prepare_env { return; } +=head3 qesap_ansible_get_playbook + + Download the playbook from the test code repo + that is on the worker within the running JompHost. + +=cut + +sub qesap_ansible_get_playbook { + my (%args) = @_; + croak 'Missing mandatory playbook argument' unless $args{playbook}; + if (script_run("test -e $args{playbook}")) { + my $cmd = join(' ', + 'curl', '-v', '-fL', + data_url("sles4sap/$args{playbook}"), + '-o', $args{playbook}); + assert_script_run($cmd); + } +} + =head3 qesap_ansible_cmd Use Ansible to run a command remotely on some or all @@ -565,10 +585,11 @@ sub qesap_prepare_env { sub qesap_ansible_cmd { my (%args) = @_; - croak 'Missing mandatory cmd argument' unless $args{cmd}; + foreach (qw(provider cmd)) { croak "Missing mandatory $_ argument" unless $args{$_}; } $args{user} ||= 'cloudadmin'; $args{filter} ||= 'all'; $args{timeout} //= bmwqemu::scale_timeout(90); + $args{failok} //= 0; my $verbose = $args{verbose} ? ' -vvvv' : ''; my $inventory = qesap_get_inventory($args{provider}); @@ -594,7 +615,7 @@ sub qesap_ansible_cmd { Use Ansible to run a command remotely and get the stdout. Command could be executed with elevated privileges - qesap_ansible_script_output(cmd => 'crm status', provider => 'aws', host => 'vmhana01', root => 1); + qesap_ansible_script_output_file(cmd => 'crm status', provider => 'aws', host => 'vmhana01', root => 1); It uses playbook data/sles4sap/script_output.yaml @@ -631,45 +652,35 @@ sub qesap_ansible_cmd { sub qesap_ansible_script_output_file { my (%args) = @_; - foreach (qw(provider cmd host file out_path)) { croak "Missing mandatory $_ argument" unless $args{$_}; } + foreach (qw(provider cmd host)) { croak "Missing mandatory $_ argument" unless $args{$_}; } $args{user} ||= 'cloudadmin'; $args{root} ||= 0; - - my $inventory = qesap_get_inventory($args{provider}); - - my $playbook = 'script_output.yaml'; - my $path = $args{remote_path} // '/tmp/'; + $args{failok} //= 0; + my $remote_path = $args{remote_path} // '/tmp/'; my $out_path = $args{out_path} // '/tmp/ansible_script_output/'; my $file = $args{file} // 'testout.txt'; - my $failok = $args{failok} // 1; - # Download the playbook from the test code repo copy on the worker - # within the running JompHost. - if (script_run "test -e $playbook") { - my $cmd = join(' ', - 'curl', '-v', '-fL', - data_url("sles4sap/$playbook"), - '-o', $playbook); - assert_script_run($cmd); - } + my $inventory = qesap_get_inventory($args{provider}); + my $playbook = 'script_output.yaml'; + qesap_ansible_get_playbook(playbook => $playbook); my @ansible_cmd = ('ansible-playbook', '-vvvv', $playbook); - push @ansible_cmd, ('-l', $args{host}, '-i', $inventory); - push @ansible_cmd, ('-u', $args{user}); + push @ansible_cmd, ('-l', $args{host}, '-i', $inventory, '-u', $args{user}); push @ansible_cmd, ('-b', '--become-user', 'root') if ($args{root}); push @ansible_cmd, ('-e', qq("cmd='$args{cmd}'"), - '-e', "out_file='$file'", '-e', "remote_path='$path'"); + '-e', "out_file='$file'", '-e', "remote_path='$remote_path'"); push @ansible_cmd, ('-e', "failok=yes") if ($args{failok}); + # ignore the ret value for the moment qesap_venv_cmd_exec(cmd => join(' ', @ansible_cmd), failok => $args{failok}); # Grab the file from the remote return qesap_ansible_fetch_file(provider => $args{provider}, host => $args{host}, - failok => $failok, + failok => $args{failok}, user => $args{user}, root => $args{root}, - remote_path => $path, + remote_path => $remote_path, out_path => $out_path, file => $file); } @@ -706,19 +717,16 @@ sub qesap_ansible_script_output { foreach (qw(provider cmd host)) { croak "Missing mandatory $_ argument" unless $args{$_}; } $args{user} ||= 'cloudadmin'; $args{root} ||= 0; - my $cmd = $args{cmd}; - my $prov = $args{provider}; - my $host = $args{host}; + $args{failok} //= 0; my $path = $args{remote_path} // '/tmp/'; my $out_path = $args{out_path} // '/tmp/ansible_script_output/'; my $file = $args{file} // 'testout.txt'; - my $failok = $args{failok} // 1; # Grab command output as file - my $local_tmp = qesap_ansible_script_output_file(cmd => $cmd, - provider => $prov, - host => $host, - failok => 1, + my $local_tmp = qesap_ansible_script_output_file(cmd => $args{cmd}, + provider => $args{provider}, + host => $args{host}, + failok => $args{failok}, user => $args{user}, root => $args{root}, remote_path => $path, @@ -771,23 +779,17 @@ sub qesap_ansible_fetch_file { foreach (qw(provider host remote_path)) { croak "Missing mandatory $_ argument" unless $args{$_}; } $args{user} ||= 'cloudadmin'; $args{root} ||= 0; + $args{failok} //= 0; + my $local_path = $args{out_path} // '/tmp/ansible_script_output/'; + my $local_file = $args{file} // 'testout.txt'; my $inventory = qesap_get_inventory($args{provider}); - my $fetch_playbook = 'fetch_file.yaml'; - my $local_path = $args{out_path} // '/tmp/ansible_script_output/'; - my $local_file = $args{file} // 'testout.txt'; # reflect the same logic implement in the playbook my $local_tmp = $local_path . $local_file; - if (script_run "test -e $fetch_playbook") { - my $cmd = join(' ', - 'curl', '-v', '-fL', - data_url("sles4sap/$fetch_playbook"), - '-o', $fetch_playbook); - assert_script_run($cmd); - } + qesap_ansible_get_playbook(playbook => $fetch_playbook); my @ansible_fetch_cmd = ('ansible-playbook', '-vvvv', $fetch_playbook); push @ansible_fetch_cmd, ('-l', $args{host}, '-i', $inventory); @@ -889,32 +891,36 @@ sub qesap_wait_for_ssh { Run crm report on a host and upload the resulting tarball to openqa -=over 1 +=over 3 =item B - host to get the report from +=item B - Cloud provider name, used to find the inventory + +=item B - if not set, Ansible failure result in die =back =cut sub qesap_upload_crm_report { my (%args) = @_; - croak 'Missing mandatory host argument' unless $args{host}; - my $host = $args{host}; - my $crm_log = "/var/log/$host-crm_report"; + foreach (qw(provider host)) { croak "Missing mandatory $_ argument" unless $args{$_}; } + $args{failok} //= 0; + + my $crm_log = "/var/log/$args{host}-crm_report"; my $report_opt = !is_sle('12-sp4+') ? '-f0' : ''; - my $prov = get_required_var('PUBLIC_CLOUD_PROVIDER'); qesap_ansible_cmd(cmd => "crm report $report_opt -E /var/log/ha-cluster-bootstrap.log $crm_log", - provider => $prov, - filter => $host, + provider => $args{provider}, + filter => $args{host}, host_keys_check => 1, - verbose => 1); - my $local_path = qesap_ansible_fetch_file(provider => $prov, - host => $host, - failok => 1, + verbose => 1, + failok => $args{failok}); + my $local_path = qesap_ansible_fetch_file(provider => $args{provider}, + host => $args{host}, + failok => $args{failok}, root => 1, remote_path => '/var/log/', out_path => '/tmp/ansible_script_output/', - file => "$host-crm_report.tar.gz"); + file => "$args{host}-crm_report.tar.gz"); upload_logs($local_path, failok => 1); } @@ -985,7 +991,7 @@ sub qesap_cluster_logs { upload_logs($out, failok => 1); } # Upload crm report - qesap_upload_crm_report(host => $host); + qesap_upload_crm_report(host => $host, provider => $prov, failok => 1); } } } diff --git a/t/09_qesapdeployment.t b/t/09_qesapdeployment.t index 40af6b7eb542..9ee819c6217f 100644 --- a/t/09_qesapdeployment.t +++ b/t/09_qesapdeployment.t @@ -339,7 +339,11 @@ subtest '[qesap_execute] simple call' => sub { my $expected_log_name = "qesap_exec_$cmd.log.txt"; $qesap->redefine(record_info => sub { note(join(' # ', 'RECORD_INFO -->', @_)); }); $qesap->redefine(upload_logs => sub { push @logs, $_[0]; note("UPLOAD_LOGS:$_[0]") }); - $qesap->redefine(qesap_venv_cmd_exec => sub { my (%args) = @_; push @calls, $args{cmd}; return $expected_res }); + $qesap->redefine(qesap_venv_cmd_exec => sub { + my (%args) = @_; + push @calls, $args{cmd}; + return $expected_res; + }); $qesap->redefine(qesap_get_file_paths => sub { my %paths; $paths{deployment_dir} = '/BRUCE'; @@ -363,7 +367,11 @@ subtest '[qesap_execute] cmd_options' => sub { my $expected_log_name = 'qesap_exec_' . $cmd . '__tankgang.log.txt'; $qesap->redefine(record_info => sub { note(join(' # ', 'RECORD_INFO -->', @_)); }); $qesap->redefine(upload_logs => sub { push @logs, $_[0]; note("UPLOAD_LOGS:$_[0]") }); - $qesap->redefine(qesap_venv_cmd_exec => sub { my (%args) = @_; push @calls, $args{cmd}; return $expected_res }); + $qesap->redefine(qesap_venv_cmd_exec => sub { + my (%args) = @_; + push @calls, $args{cmd}; + return $expected_res; + }); $qesap->redefine(qesap_get_file_paths => sub { my %paths; $paths{deployment_dir} = '/BRUCE'; @@ -384,7 +392,11 @@ subtest '[qesap_execute] failure' => sub { my $expected_res = 1; $qesap->redefine(record_info => sub { note(join(' # ', 'RECORD_INFO -->', @_)); }); $qesap->redefine(upload_logs => sub { push @logs, $_[0]; note("UPLOAD_LOGS:$_[0]") }); - $qesap->redefine(qesap_venv_cmd_exec => sub { my (%args) = @_; push @calls, $args{cmd}; return $expected_res }); + $qesap->redefine(qesap_venv_cmd_exec => sub { + my (%args) = @_; + push @calls, $args{cmd}; + return $expected_res; + }); $qesap->redefine(qesap_get_file_paths => sub { my %paths; $paths{deployment_dir} = '/BRUCE'; @@ -404,7 +416,11 @@ subtest '[qesap_execute] check_logs' => sub { my $expected_res = 1; $qesap->redefine(record_info => sub { note(join(' # ', 'RECORD_INFO -->', @_)); }); $qesap->redefine(upload_logs => sub { push @logs, $_[0]; note("UPLOAD_LOGS:$_[0]") }); - $qesap->redefine(qesap_venv_cmd_exec => sub { my (%args) = @_; push @calls, $args{cmd}; return $expected_res }); + $qesap->redefine(qesap_venv_cmd_exec => sub { + my (%args) = @_; + push @calls, $args{cmd}; + return $expected_res; + }); $qesap->redefine(qesap_get_file_paths => sub { my %paths; $paths{deployment_dir} = '/BRUCE'; @@ -514,13 +530,106 @@ subtest '[qesap_ansible_script_output]' => sub { }; subtest '[qesap_ansible_script_output_file]' => sub { + # Call qesap_ansible_script_output_file with the bare minimal set of arguments + # and mock all the dependency. + my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); + my @calls; + my $fetch_remote_path; + my $fetch_out_path; + + $qesap->redefine(qesap_get_inventory => sub { return '/CRUSH'; }); + $qesap->redefine(script_run => sub { push @calls, $_[0]; return 0; }); + $qesap->redefine(data_url => sub { return '/BRUCE'; }); + $qesap->redefine(assert_script_run => sub { push @calls, $_[0]; }); + $qesap->redefine(qesap_venv_cmd_exec => sub { + my (%args) = @_; + push @calls, $args{cmd}; + return 0; + }); + $qesap->redefine(qesap_ansible_fetch_file => sub { + my (%args) = @_; + $fetch_remote_path = $args{remote_path}; + $fetch_out_path = $args{out_path}; + return '/BAY'; + }); + + my $out = qesap_ansible_script_output_file( + provider => 'NEMO', + cmd => 'SWIM', + host => 'REEF'); + + note("\n out=$out"); + note("\n fetch_remote_path=$fetch_remote_path"); + note("\n fetch_out_path=$fetch_out_path"); + note("\n C--> " . join("\n C--> ", @calls)); + ok((any { /test -e script_output\.yaml/ } @calls), 'Verify for the local existence of script_output.yaml'); + ok((any { /ansible-playbook/ } @calls), 'ansible-playbook is called at least one'); + ok((any { /ansible-playbook.*-l REEF/ } @calls), 'host is used to configure -l'); + ok((any { /ansible-playbook.*-i \/CRUSH/ } @calls), 'inventory calculated with qesap_get_inventory is used to configure -i'); + ok((any { /ansible-playbook.*-e.*cmd='SWIM'/ } @calls), 'cmd is used to populate -e cmd'); + like($out, qr/\/BAY/, 'The return is what returned by qesap_ansible_fetch_file'); +}; + +subtest '[qesap_ansible_script_output_file] call with all arguments' => sub { + # Call qesap_ansible_script_output_file with all possible arguments + # and mock all the dependency. + my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); + my @calls; + my $fetch_remote_path; + my $fetch_out_path; + my $fetch_file; + + $qesap->redefine(qesap_get_inventory => sub { return '/CRUSH'; }); + $qesap->redefine(script_run => sub { push @calls, $_[0]; return 0; }); + $qesap->redefine(data_url => sub { return '/BRUCE'; }); + $qesap->redefine(assert_script_run => sub { push @calls, $_[0]; }); + $qesap->redefine(qesap_venv_cmd_exec => sub { + my (%args) = @_; + push @calls, $args{cmd}; + return 0; + }); + $qesap->redefine(qesap_ansible_fetch_file => sub { + my (%args) = @_; + $fetch_remote_path = $args{remote_path}; + $fetch_out_path = $args{out_path}; + $fetch_file = $args{file}; + return '/BAY'; + }); + + my $out = qesap_ansible_script_output_file( + provider => 'NEMO', + cmd => 'SWIM', + host => 'REEF', + user => 'NEMO', + root => 1, + remote_path => '/ADRIATIC_SEE', + out_path => '/TIRRENO_SEE', + file => 'JELLY.fish'); + + note("\n out=$out"); + note("\n fetch_remote_path=$fetch_remote_path"); + note("\n fetch_out_path=$fetch_out_path"); + note("\n fetch_file=$fetch_file"); + note("\n C--> " . join("\n C--> ", @calls)); + + ok($fetch_remote_path eq '/ADRIATIC_SEE', 'remote_path is used as argument for qesap_ansible_fetch_file'); + ok($fetch_out_path eq '/TIRRENO_SEE', 'out_path is used as argument for qesap_ansible_fetch_file'); + ok($fetch_file eq 'JELLY.fish', 'file is used as argument for qesap_ansible_fetch_file'); + + # fails for an unknown reason, it should not + #ok((any { /ansible-playbook.*-u NEMO'/ } @calls), 'user is used as ansible-playbook -u'); + #ok((any { /ansible-playbook.*--become-user root'/ } @calls), 'root activate ansible-playbook --become-user'); + ok((any { /ansible-playbook.*-e.*remote_path='\/ADRIATIC_SEE'/ } @calls), 'remote_path is used as ansible-playbook -e remote_path'); +}; + +subtest '[qesap_ansible_script_output_file] integrate with qesap_venv_cmd_exec' => sub { + # This test does not mock qesap_venv_cmd_exec so also test it implicitly my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); my @calls; $qesap->redefine(qesap_get_inventory => sub { return '/CRUSH'; }); $qesap->redefine(script_run => sub { push @calls, $_[0]; return 0; }); $qesap->redefine(assert_script_run => sub { push @calls, $_[0]; }); - $qesap->redefine(enter_cmd => sub { push @calls, $_[0]; }); $qesap->redefine(data_url => sub { return '/BRUCE'; }); $qesap->redefine(script_output => sub { push @calls, $_[0]; }); @@ -533,72 +642,119 @@ subtest '[qesap_ansible_script_output_file]' => sub { note("\n out=$out"); note("\n C--> " . join("\n C--> ", @calls)); - ok((any { /ansible-playbook.*-e.*local_path='\/BERMUDA_TRIAGLE\/'/ } @calls), 'proper ansible-playbooks local_path'); - ok((any { /ansible-playbook.*-e.*file='SUBMARINE.TXT'/ } @calls), 'proper ansible-playbooks local_file'); + ok((any { /ansible-playbook.*-e.*local_path='\/BERMUDA_TRIAGLE\/'/ } @calls), 'proper ansible-playbook local_path'); + ok((any { /ansible-playbook.*-e.*file='SUBMARINE.TXT'/ } @calls), 'proper ansible-playbook local_file'); like($out, qr/^\/BERMUDA_TRIAGLE\/SUBMARINE\.TXT/, 'the return is the path of the file stored by Ansible'); }; -subtest '[qesap_ansible_script_output_file] failok' => sub { +subtest '[qesap_ansible_script_output_file] no curl if test true' => sub { + # Call qesap_ansible_script_output_file with the bare minimal set of arguments + # and mock all the dependency. my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); my @calls; - my @calls_scriptrun; + my $test_e_result; $qesap->redefine(qesap_get_inventory => sub { return '/CRUSH'; }); - $qesap->redefine(script_run => sub { push @calls_scriptrun, $_[0]; return 0; }); - $qesap->redefine(assert_script_run => sub { push @calls, $_[0]; }); - $qesap->redefine(enter_cmd => sub { push @calls, $_[0]; }); + # script_run only used for 'test -e' + $qesap->redefine(script_run => sub { + push @calls, $_[0]; + if ($_[0] =~ /test.*-e/) { + return $test_e_result; + } + return 0; + }); $qesap->redefine(data_url => sub { return '/BRUCE'; }); - $qesap->redefine(script_output => sub { push @calls, $_[0]; return 'patate'; }); + $qesap->redefine(assert_script_run => sub { push @calls, $_[0]; }); + $qesap->redefine(qesap_venv_cmd_exec => sub { return 0; }); + $qesap->redefine(qesap_ansible_fetch_file => sub { return 0; }); - my $cmr_status = qesap_ansible_script_output_file(cmd => 'SWIM', provider => 'NEMO', host => 'REEF', out_path => '/BERMUDA_TRIAGLE/', file => 'SUBMARINE.TXT', failok => 1); + $test_e_result = 1; + qesap_ansible_script_output_file( + provider => 'NEMO', + cmd => 'SWIM', + host => 'REEF'); + note("\n test_e_result=$test_e_result"); note("\n C--> " . join("\n C--> ", @calls)); - note("\n C--> " . join("\n C--> ", @calls_scriptrun)); - ok((any { /ansible-playbook.*failok=yes.*/ } @calls_scriptrun), 'ansible-playbooks executed with script_run'); + ok((any { /test -e script_output\.yaml/ } @calls), 'Verify for the local existence of script_output.yaml'); + ok((any { /curl/ } @calls), 'curl is called as the yaml is not available'); + + $test_e_result = 0; + @calls = (); + qesap_ansible_script_output_file( + provider => 'NEMO', + cmd => 'SWIM', + host => 'REEF'); + + note("\n test_e_result=$test_e_result"); + note("\n C--> " . join("\n C--> ", @calls)); + ok((any { /test -e script_output\.yaml/ } @calls), 'Verify for the local existence of script_output.yaml'); + ok((none { /curl/ } @calls), 'curl is not called as the yaml is already available'); }; -subtest '[qesap_ansible_script_output_file] cmd with spaces' => sub { +subtest '[qesap_ansible_script_output_file] failok' => sub { my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); my @calls; + my $fetch_failok; $qesap->redefine(qesap_get_inventory => sub { return '/CRUSH'; }); $qesap->redefine(script_run => sub { push @calls, $_[0]; return 0; }); - $qesap->redefine(assert_script_run => sub { push @calls, $_[0]; }); - $qesap->redefine(enter_cmd => sub { push @calls, $_[0]; }); $qesap->redefine(data_url => sub { return '/BRUCE'; }); - $qesap->redefine(script_output => sub { push @calls, $_[0]; return 'patate'; }); + $qesap->redefine(assert_script_run => sub { push @calls, $_[0]; }); + $qesap->redefine(qesap_venv_cmd_exec => sub { + my (%args) = @_; + push @calls, $args{cmd}; + return 0; + }); + $qesap->redefine(qesap_ansible_fetch_file => sub { + my (%args) = @_; + $fetch_failok = $args{failok}; + return '/BAY'; + }); - qesap_ansible_script_output_file(cmd => 'SWIM SWIM SWIM', provider => 'NEMO', host => 'REEF', out_path => '/BERMUDA_TRIAGLE/', file => 'SUBMARINE.TXT'); + my $out = qesap_ansible_script_output_file( + provider => 'NEMO', + cmd => 'SWIM', + host => 'REEF', + failok => 1); + note("\n out=$out"); + note("\n fetch_failok=$fetch_failok"); note("\n C--> " . join("\n C--> ", @calls)); - ok((any { /ansible-playbook.*REEF.*"cmd='SWIM SWIM SWIM'"/ } @calls), 'proper ansible-playbooks command'); + ok((any { /ansible-playbook.*-e.*failok=yes/ } @calls), 'ansible called with failok=yes'); }; -subtest '[qesap_ansible_script_output_file] download the playbook' => sub { +subtest '[qesap_ansible_script_output_file] cmd with spaces' => sub { + # Call qesap_ansible_script_output_file with the bare minimal set of arguments + # and mock all the dependency. my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); my @calls; $qesap->redefine(qesap_get_inventory => sub { return '/CRUSH'; }); - $qesap->redefine(script_run => sub { - push @calls, $_[0]; - if ($_[0] =~ /test.*-e/) { - return 1; - } + $qesap->redefine(script_run => sub { push @calls, $_[0]; return 0; }); + $qesap->redefine(data_url => sub { return '/BRUCE'; }); + $qesap->redefine(assert_script_run => sub { push @calls, $_[0]; }); + $qesap->redefine(qesap_venv_cmd_exec => sub { + my (%args) = @_; + push @calls, $args{cmd}; return 0; }); - $qesap->redefine(assert_script_run => sub { push @calls, $_[0]; }); - $qesap->redefine(enter_cmd => sub { push @calls, $_[0]; }); - $qesap->redefine(data_url => sub { return '/BRUCE'; }); - $qesap->redefine(script_output => sub { push @calls, $_[0]; return 'patate'; }); + $qesap->redefine(qesap_ansible_fetch_file => sub { + my (%args) = @_; + return '/BAY'; + }); - qesap_ansible_script_output_file(cmd => 'SWIM', provider => 'NEMO', host => 'REEF', out_path => '/BERMUDA_TRIAGLE/', file => 'SUBMARINE.TXT'); + qesap_ansible_script_output_file( + provider => 'NEMO', + cmd => 'SWIM SWIM SWIM', + host => 'REEF'); note("\n C--> " . join("\n C--> ", @calls)); - ok((any { /curl.*BRUCE/ } @calls), 'Playbook download with curl'); + ok((any { /ansible-playbook.*-e.*cmd='SWIM SWIM SWIM'/ } @calls), 'cmd with spaces is properly escaped when used to populate -e cmd'); }; -subtest '[qesap_ansible_script_output_file] custom user' => sub { +subtest '[qesap_ansible_script_output_file] custom user integrate with qesap_venv_cmd_exec' => sub { my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); my @calls; @@ -615,7 +771,7 @@ subtest '[qesap_ansible_script_output_file] custom user' => sub { ok((any { /ansible-playbook.*-u GERALD/ } @calls), 'Custom ansible with user'); }; -subtest '[qesap_ansible_script_output_file] root' => sub { +subtest '[qesap_ansible_script_output_file] root integrate with qesap_venv_cmd_exec' => sub { my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); my @calls; @@ -909,6 +1065,29 @@ subtest '[qesap_cluster_logs] multi log command' => sub { ok((none { /.*ignore_me_too\.txt/ } @logfile_calls), 'ignore_me_too.txt is expected to be ignored'); }; +subtest '[qesap_upload_crm_report] die for missing mandatory arguments' => sub { + dies_ok { qesap_upload_crm_report(); } "Expected die if called without arguments"; + dies_ok { qesap_upload_crm_report(provider => 'SAND'); } "Expected die if called without host"; + dies_ok { qesap_upload_crm_report(host => 'SALT'); } "Expected die if called without provider"; +}; + +subtest '[qesap_upload_crm_report]' => sub { + my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); + my @calls; + + $qesap->redefine(is_sle => sub { return 0; }); + $qesap->redefine(qesap_ansible_cmd => sub { + my (%args) = @_; + push @calls, $args{cmd}; + return 0; }); + $qesap->redefine(qesap_ansible_fetch_file => sub { return 0; }); + $qesap->redefine(upload_logs => sub { return 0; }); + qesap_upload_crm_report(provider => 'SAND', host => 'SALT'); + + note("\n C--> " . join("\n C--> ", @calls)); + ok 1; +}; + subtest '[qesap_az_get_resource_group]' => sub { my $qesap = Test::MockModule->new('qesapdeployment', no_auto => 1); my @calls; diff --git a/tests/sles4sap/qesapdeployment/test_cluster.pm b/tests/sles4sap/qesapdeployment/test_cluster.pm index 74a5df5c87c8..33126e3c8b10 100644 --- a/tests/sles4sap/qesapdeployment/test_cluster.pm +++ b/tests/sles4sap/qesapdeployment/test_cluster.pm @@ -29,7 +29,10 @@ sub run { ); qesap_ansible_cmd(cmd => $_, provider => $prov) for @remote_cmd; qesap_ansible_cmd(cmd => 'ls -lai /hana/', provider => $prov, filter => 'hana'); - my $cmr_status = qesap_ansible_script_output(cmd => 'crm status', provider => $prov, host => '"hana[0]"', root => 1); + my $cmr_status = qesap_ansible_script_output(cmd => 'crm status', + provider => $prov, + host => '"hana[0]"', + root => 1); record_info("crm status", $cmr_status); qesap_ansible_cmd(cmd => $crm_mon_cmd, provider => $prov, filter => '"hana[0]"'); qesap_cluster_logs();