xcat-core/xCAT-test/restapitest

623 lines
18 KiB
Perl
Executable File

#!/usr/bin/env perl
###############################################################################
# This script is used for rest-api automation test
# Flags are used for test input:
# -m method. Should be GET, POST, PUT, DELETE
# -r resource
# -t token
# -h host
# -u user
# -p passwd
# -P port (BC)
# -d data
# -c cert
# -n hostname
# Flags are used for check output:
# -o expected output
# -O logical operator
#
# Expected result format is '{ANY:{ANY:content}}'
# These steps are used to explain how to scan result
# step 1. go through to see if content can be found
# step 2. compare content if found
# options are used as followed:
# == returns 0 if found and equal, returns 1 if not found or found but not equal
# != returns 0 if found, returns 1 if not found
# =~ returns 0 if match, returns 1 if not match
# !=~ returns 0 if not match, returns 1 if match
################################################################################
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use Getopt::Long qw{:config bundling no_ignore_case};
use Data::Dumper;
use strict;
my $help;
my $method;
my $token;
my $resource;
my $host;
my $user;
my $passwd;
my $port;
my $data;
my $cert;
my $hostname;
my $output;
my $loperator;
my $debug;
my $defaulthash;
my $defaulthttpresult = 0;
my $outputfile = "/tmp/testrestapiresult";
if (
!GetOptions("h|?" => \$help,
"m=s" => \$method,
"t=s" => \$token,
"r=s" => \$resource,
"h=s" => \$host,
"u=s" => \$user,
"p=s" => \$passwd,
"P=s" => \$port,
"d=s" => \$data,
"c=s" => \$cert,
"n=s" => \$hostname,
"o=s" => \$output,
"O=s" => \$loperator,
"debug" => \$debug,
)
) {
&usage;
exit 1;
}
##############################################################
# return help
##############################################################
if ($help) {
&usage;
exit 0;
}
##############################################################
# flag check
##############################################################
if ($method ) {
unless( $resource ) {
print "-m must be used with -r \n";
&usage;
exit 0;
}
}
if ($resource ) {
unless($method) {
print "-r must be used with -m \n";
&usage;
exit 0;
}
}
##############################################################
# ONLY check result,exit immediately
##############################################################
if ($output and !defined($method)) {
my $res = check_result($output,$loperator,$outputfile);
log_debug(2, "check result runs with $output and $loperator, result is $res\n" );
exit $res;
}
##############################################################
# Give default values for optional vars.
###############################################################
my $rootdir = "$::XCATROOT/share/xcat/tools/autotest";
my $resultdir = "$rootdir/result";
my $logfile = "$rootdir/result/restapitest.log";
#/opt/xcat/share/xcat/tools/autotest/result/restapitest.log
my $confile = "$rootdir/default.conf";
# read configuration file
if (!open (CONF, "<$confile")) {
log_debug(1,"can't open configuration file $confile");
exit 1;
}
my %confhash;
while (<CONF>){
if (/restapi-(\w+)=(\S+)/) {
$confhash{$1}=$2;
}
}
# get token
my $defaultserver = $confhash{DefaultServer};
my $defaultuser = $confhash{DefaultUser1};
my $DefaultPasswd = $confhash{DefaultPasswd1};
my $gettoken = `curl -X POST -k 'https://$defaultserver/xcatws/tokens?userName=$defaultuser&password=$DefaultPasswd' -H Content-Type:application/json --data '{"userName":"$defaultuser","password":"$DefaultPasswd"}' 2>/dev/null`;
my $reshash = parse_json($gettoken);
my $token1 = $$reshash{token}{id};
# get hostname
unless ($hostname) {
$hostname = `hostname`;
chomp($hostname);
}
unless ($defaultserver) {
$host = "127.0.0.1";
} else {
$host = $defaultserver;
}
# keey default test result for save
my $res = run_restapi($method, $resource, $data, "", $port, "$host", "$defaultuser", "$DefaultPasswd");
$defaulthash = parse_json($res);
$defaulthttpresult = check_errcode();
# debug and log info
log_debug(3, "get token $token1. \n" );
log_debug(3, "get first default user $confhash{DefaultUser1} \n" );
log_debug(3, "get first default user's passwd is $confhash{DefaultPasswd1} \n" );
log_debug(3, "get second default user $confhash{DefaultUser2} \n" );
log_debug(3, "get second default user's passwd is $confhash{DefaultPasswd2} \n" );
log_debug(3, "get path of ca $confhash{Cert} \n" );
log_debug(3, "get server $defaultserver from configuration file and it is $host\n" );
log_debug(3, "get hostname $hostname.\n");
log_debug(3, "default result is $res. \n" );
log_debug(3, "default resulthash is: \n" );
log_debug(3,$defaulthash);
log_debug(3, "default errcode is $defaulthttpresult \n" );
log_debug(3,"**************begin to run more restapi test, stop when post***************");
####################################################
# Begin to run test cases
####################################################
my @users = ($confhash{DefaultUser1},$confhash{DefaultUser2}, $user);
my @passwds = ($confhash{DefaultPasswd1},$confhash{DefaultPasswd2}, $passwd);
my @tokens = ("", $token1, $token);
my @certs = ("", $confhash{Cert}, $cert);
my $i = 0;
unless ($method eq "POST") { # Should not post sevral times
for my $u (@users) {
next unless($u);
my $p = $passwds[$i];
$i++;
for my $t (@tokens) {
for my $c (@certs){
#if ($method eq "POST" and ($resource =~ /^\/nodes\/(\w+)$/)) {
# `/opt/xcat/bin/rmdef $1`;
# log_debug(2,"restapi test rmdef $1\n");
#}
my $res = run_restapi($method, $resource, $data, $c, $port, $host, $u, $p, $t);
if($res){
my $reshash = parse_json($res);
log_debug(2,"parse curl result and got:\n");
log_debug(2,$reshash);
if (%$reshash != %$defaulthash) {
log_debug(3, "restapi test cases run different result with $method, $resource, $data, $c, $port, $host, $u, $p, $t\n" );
exit 1;
}
}
my $errcode = check_errcode();
log_debug(2,"get curl error code: $errcode\n");
if ($errcode != $defaulthttpresult) {
log_debug(3, "restapi test cases run different error code with $method, $resource, $data, $c, $port, $host, $u, $p, $t\n" );
exit 1;
}
}
}
}
}
##############################################################
# check result
##############################################################
if ($output) {
my $res = check_result($output,$loperator,$res);
log_debug(2, "check result runs with $output and $loperator, result is $res\n" );
exit $res;
}
exit $defaulthttpresult;
################################################
# begin subroutine
################################################
##########
# usage #
##########
sub usage
{
print "Usage:testrestapi - Run xcat test cases.\n";
print " testrestapi [-?|-h]\n";
print " testrestapi [-m method] [-r resource] [-t tocken]\n";
print " [-h host] [-P port][-u user] [-p passwd]\n";
print " [-d data] [-c cert] [-n hostname]\n";
print " [-o expect_output] [-O logical_operator] \n";
print " [--debug]\n";
print "\n";
return;
}
#######################
# print debug infor #
# 1 for only log #
# 2 for only debug #
# 3 for log and debug #
#######################
sub log_debug
{
my $flag = shift;
my $msg = shift;
if ($flag & 0x2) {
if($debug){
if(ref($msg) eq 'HASH') {
print Dumper($msg);
} elsif( ref($msg) eq 'ARRAY') {
print Dumper($msg);
} else {
print "$msg";
}
}
}
if ($flag & 0x1) {
open (LOG, ">>$logfile")
or return 1;
my $date = `date`;
print LOG "$date\: $msg\n";
}
}
#########################
# run rest-api command #
#########################
sub run_restapi
{
my ($m,$r,$d,$c,$p,$h,$u,$a,$t) = @_;
my $cmd = "curl";
$cmd .= " -X $m";
unless ($c) {
$cmd .= " -k ";
}else {
$cmd .= " --cacert $c";
}
if($t){
$cmd .= " -H X-Auth-Token:$t ";
}
if($t or $c){
$cmd .= " 'https://$hostname";
} else {
$cmd .= " 'https://$h";
}
if ($p) {
$cmd .= ":$p";
}
$cmd .= "/xcatws";
$cmd .= "$r?";
unless($t){
$cmd .= "userName=$u&password=$a'";
}else {
$cmd .= "'";
}
if($d) {
$cmd .= " -H Content-Type:application/json --data '$d'";
}
$cmd .= " -D /tmp/err.log";
log_debug(1,"Begin to run restapi test with $cmd");
my $res = `$cmd 2>/dev/null`;
log_debug(2,"run curl: $cmd\n");
log_debug(2,"result is $res\n");
if (!open (RESULT, ">$outputfile")) {
log_debug(1,"wirte outputfile error");
}
print RESULT $res;
close RESULT;
return $res;
}
############################
# transfer json into hash #
############################
sub parse_json
{
my $input = shift;
my %hash;
if ($input =~ /:/) {
# for those who look like:
# {"networks":[{"mgtifname":"eth1","mask":"255.255.255.0"},{"mgtifname":"eth1","mask":"255.255.255.0"}]}
if ($input =~ /^\[(.*)\]$/s) {
my $content = $1;
log_debug(2, "[:] content is $content \n" );
parse_json($content);
}
# for those who look like:
# {"Vc68m4hsp01":{"parent":"Server-9119-590-SN02C5F9E","pprofile":"Vc68m4hsp01"},"p5ih_c75vios":{"parent":"P5IH-SN02012EB-A","mgt":"hmc","id":"2"},"p5ih_lpar04":{"parent":"P5IH-SN02013EB-A","pprofile":"p5ih_lpar04"}}
elsif($input =~ /^"(\S+?)\":{\S+},/){
$input =~ s/},/}%/;
my @contents = split /%/, $input;
my @reval;
# record result
foreach my $t (@contents) {
log_debug(2, ":{}, content is $t \n" );
my $re = parse_json($t);
push @reval, $re;
}
# merge hash
foreach my $t (@reval) {
if(ref($t) =~ "HASH") {
foreach my $k (keys %$t){
$hash{$k} = $$t{$k};
}
}
}
return \%hash;
}
elsif( $input =~ /^{\S+},{\S+}/ and !($input =~ /]/)){
$input =~ s/},{/}%{/;
my @contents = split /%/, $input;
my @reval;
# record result
foreach my $t (@contents) {
log_debug(2, "{},{}, content is $t \n" );
my $re = parse_json($t);
push @reval, $re;
}
# merge hash
foreach my $t (@reval) {
if(ref($t) =~ "HASH") {
foreach my $k (keys %$t){
$hash{$k} = $$t{$k};
}
}
}
return \%hash;
}
# for those who look like
# {"clustersite":{"domain":"cluster.com","master":"192.168.1.15"}}
elsif ($input =~ /^\s*{(.*)}\s*$/s) {
my $content = $1;
log_debug(2, "{} content is $content \n" );
parse_json($content);
}
elsif( $input =~ /],\"\S+\":/){
$input =~ s/],\"(\S+)\":/]%\"$1\":/;
my @contents = split /%/, $input;
my @reval;
# record result
foreach my $t (@contents) {
log_debug(2, "],:, content is $t \n" );
my $re = parse_json($t);
push @reval, $re;
}
# merge hash
foreach my $t (@reval) {
if(ref($t) =~ "HASH") {
foreach my $k (keys %$t){
$hash{$k} = $$t{$k};
}
}
}
return \%hash;
}
# for those who look like
# "domain":"cluster.com","master":"192.168.1.15"
elsif ($input =~ /,/ and !($input =~ /}/)) {
my @contents = split /,/, $input;
my @reval;
# record result
foreach my $t (@contents) {
log_debug(2, ", content is $t \n");
my $re = parse_json($t);
push @reval, $re;
}
# merge hash
foreach my $t (@reval) {
if(ref($t) =~ "HASH") {
foreach my $k (keys %$t){
$hash{$k} = $$t{$k};
}
}
}
return \%hash;
}
# for those who look like:
# "clustersite":{"domain":"cluster.com","master":"192.168.1.15"}
# "domain":"cluster.com"
elsif ($input =~ /\"(\S+?)\":(.+)/s) {
my $key = $1;
my $value = $2;
if ($value =~ /{/) {
# "clustersite":{"domain":"cluster.com","master":"192.168.1.15"}
log_debug(2, "{ content is $value \n" );
$hash{$key} = parse_json($value, $key);
return \%hash;
} else {
# "domain":"cluster.com"
$value =~ /\"(\S+)\"/;
$hash{$key} = $1;
return \%hash;
}
}
}
# for those who look like
# ["10.1.255.250","192.168.200.16","192.168.200.19","192.168.200.22"]
else {
if ($input =~ /^\[(.*)\]/s) {
my $content = $1;
log_debug(2, "[] content is $content \n");
my @all = split /,/, $content;
foreach my $n (@all) {
$n =~ /\"(.*)\"/;
$hash{$1} = "restapiarray";
}
return \%hash;
}
}
}
############################
# check curl running code #
############################
sub check_errcode
{
if(!open (ERRLOG, "</tmp/err.log")) {
log_debug(1,"can't open err.log in tmp");
return 1;
}
my $num;
while (<ERRLOG>){
if (/HTTP\/\w*\.*\w* (\w+) (\w+)/) {
$num = $1;
last;
}
}
close ERRLOG;
log_debug(2,"can't get errorcode\n") unless($num);
return $num;
}
############################
# check curl return result #
############################
sub check_result
{
my $data = shift;
my $opterator = shift;
my $output = shift;
if ( !open (OUTPUT, "<$output")) {
log_debug(1,"can't read output file");
return 1;
}
my $res;
while (<OUTPUT>) {
$res .= $_;
}
close OUTPUT;
log_debug(2, "\nbegin to parse json for expected value: \n");
my $expects = transf_hash(parse_json($data)); # one entry
log_debug(2, "\nbegin to parse json for actual result: \n");
my $actuals = transf_hash(parse_json($res)); # serval entries
log_debug(2,"expected result is:\n");
log_debug(2,$expects);
log_debug(2,"testcase run result is \n");
log_debug(2,$actuals);
my $flag = 0;
my %flaghash;
my $expect = $$expects[0]; # $expect = ANY:ANY:x86_64
my @expectvalue = split /:/, $expect; #@expectvalue = ANY, ANY, x86_64
$flag = 0;
foreach my $expval (@expectvalue) { # $expval = ANY
foreach my $actual (@$actuals) { # $actual = nodetype:arch:x86_64
if($flaghash{$actual} eq "none"){
next;
}
my @actualvalue = split /:/, $actual; # @actualvalue = nodetype, arch, x86_64
log_debug(2,"begin to compare $expval and $actualvalue[$flag]");
if(($expval eq "restapiarray" ) and ($actualvalue[$flag] eq "restapiarray")){
next;
}
if(($expval eq $actualvalue[$flag]) or ($expval eq "ANY")) { #ANY =~ nodetype
$flaghash{$actual} = "eq";
} elsif (($actualvalue[$flag] =~ $expval) or ($expval eq "ANY")) {
$flaghash{$actual} = "match";
} else {
$flaghash{$actual} = "none";
}
log_debug(2,", compare result is $flaghash{$actual}\n");
}
$flag++;
}
log_debug(2,"search result is \n");
log_debug(2,\%flaghash);
if ($opterator eq "!="){
foreach my $val (keys %flaghash) {
if ($flaghash{$val} eq "eq") {
log_debug(2,"compare result: failed\n");
return 1; # fail
}
}
log_debug(2,"compare result: succeed\n");
return 0; #succeed
}
if ($opterator eq "=="){
foreach my $val (keys %flaghash) {
if ($flaghash{$val} eq "eq") {
log_debug(2,"compare result: succeed\n");
return 0; # succeed
}
}
log_debug(2,"compare result: failed\n");
return 1; #fail
}
if ($opterator eq "=~"){
foreach my $val (keys %flaghash) {
if ($flaghash{$val} eq "match") {
log_debug(2,"compare result: succeed\n");
return 0; # succeed
}
}
log_debug(2,"compare result: failed\n");
return 1; #fail
}
if ($opterator eq "!=~"){
foreach my $val (keys %flaghash) {
if ($flaghash{$val} eq "match") {
log_debug(2,"compare result: failed\n");
return 1; # fail
}
}
log_debug(2,"compare result: succeed\n");
return 0; #succeed
}
}
####################################
# help to transfer hash into array #
####################################
sub find_key
{
my $input = shift;
my $en = shift;
my $ou = shift;
if( ref($input) =~ "HASH") {
foreach my $val (keys %$input) {
my $tmp = $$en; # keey head
$$en .= "$val:";
my $t1 = find_key($$input{$val}, $en, $ou);
if ($$en == ""){
$$en = $tmp; #restore head
}
}
} else {
$$en .= $input;
push @$ou, $$en;
$$en = ""; # clear entry;
}
}
############################
# transfer hash into array #
############################
sub transf_hash
{
my $input = shift;
my $entry;
my @array;
find_key($input, \$entry, \@array);
return \@array;
}