qt5base-lts/tests/auto/android/runtests_androiddeployqt.pl
Jani Heikkinen 83a5694dc2 Update copyright headers
Qt copyrights are now in The Qt Company, so we could update the source
code headers accordingly. In the same go we should also fix the links to
point to qt.io.

Outdated header.LGPL removed (use header.LGPL21 instead)

Old header.LGPL3 renamed to header.LGPL3-COMM to match actual licensing
combination. New header.LGPL-COMM taken in the use file which were
using old header.LGPL3 (src/plugins/platforms/android/extract.cpp)

Added new header.LGPL3 containing Commercial + LGPLv3 + GPLv2 license
combination

Change-Id: I6f49b819a8a20cc4f88b794a8f6726d975e8ffbe
Reviewed-by: Matti Paaso <matti.paaso@theqtcompany.com>
2015-02-11 06:49:51 +00:00

556 lines
18 KiB
Perl
Executable File

#!/usr/bin/perl -w
#############################################################################
##
## Copyright (C) 2012-2013 BogDan Vatra <bogdan@kde.org>
## Copyright (C) 2015 The Qt Company Ltd.
## Contact: http://www.qt.io/licensing/
##
## This file is part of the test suite of the Qt Toolkit.
##
## $QT_BEGIN_LICENSE:LGPL21$
## Commercial License Usage
## Licensees holding valid commercial Qt licenses may use this file in
## accordance with the commercial license agreement provided with the
## Software or, alternatively, in accordance with the terms contained in
## a written agreement between you and The Qt Company. For licensing terms
## and conditions see http://www.qt.io/terms-conditions. For further
## information use the contact form at http://www.qt.io/contact-us.
##
## GNU Lesser General Public License Usage
## Alternatively, this file may be used under the terms of the GNU Lesser
## General Public License version 2.1 or version 3 as published by the Free
## Software Foundation and appearing in the file LICENSE.LGPLv21 and
## LICENSE.LGPLv3 included in the packaging of this file. Please review the
## following information to ensure the GNU Lesser General Public License
## requirements will be met: https://www.gnu.org/licenses/lgpl.html and
## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
##
## As a special exception, The Qt Company gives you certain additional
## rights. These rights are described in The Qt Company LGPL Exception
## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
##
## $QT_END_LICENSE$
##
#############################################################################
use Cwd;
use Cwd 'abs_path';
use File::Basename;
use File::Temp 'tempdir';
use File::Path 'remove_tree';
use Getopt::Long;
use Pod::Usage;
use XML::Simple;
use Term::ANSIColor;
### default options
my @stack = cwd;
my $device_serial=""; # "-s device_serial";
my $deployqt_device_serial=""; # "-device device_serial";
my $log_out="xml";
my $max_runtime = 5;
my $className="org.qtproject.qt5.android.bindings.QtActivity";
my $jobs = 4;
my $testsubset = "";
my $man = 0;
my $help = 0;
my $make_clean = 0;
my $stop_on_fail = 0;
my $time_out=400;
my $android_toolchain_version = "4.8";
my $host_arch = "linux-x86";
my $android_sdk_dir = "$ENV{'ANDROID_SDK_ROOT'}";
my $android_ndk_dir = "$ENV{'ANDROID_NDK_ROOT'}";
my $android_to_connect = "$ENV{'ANDROID_DEVICE'}";
my $ant_tool = `which ant`;
my $silent = 0;
chomp $ant_tool;
my $strip_tool="";
my $readelf_tool="";
# for ci usage
my @failures = '';
my $total_tests = 0;
my $total_failed = 0;
my $failed_insignificants = 0;
my $ci_use = 0;
my $start = time();
my $uninstall = 0;
GetOptions('h|help' => \$help
, man => \$man
, 's|serial=s' => \$device_serial
, 't|test=s' => \$testsubset
, 'c|clean' => \$make_clean
, 'j|jobs=i' => \$jobs
, 'logtype=s' => \$log_out
, 'runtime=i' => \$max_runtime
, 'sdk=s' => \$android_sdk_dir
, 'ndk=s' => \$android_ndk_dir
, 'toolchain=s' => \$android_toolchain_version
, 'host=s' => \$host_arch
, 'ant=s' => \$ant_tool
, 'strip=s' => \$strip_tool
, 'readelf=s' => \$readelf_tool
, 'testcase=s' => \$testcase
, 'f|fail' => sub { $stop_on_fail = 1 }
, 'silent' => sub { $silent = 1 }
, 'ci' => sub { $ci_use = 1 }
, 'uninstall' => sub { $uninstall = 1 }
) or pod2usage(2);
pod2usage(1) if $help;
pod2usage(-verbose => 2) if $man;
if ($ci_use){
use QMake::Project;
}
my $adb_tool="$android_sdk_dir/platform-tools/adb";
# For CI. Nodes are connecting to test devices over IP, which is stored to env variable
if ($android_to_connect ne ""){
print " Found device to be connected from env: $android_to_connect \n";
system("$adb_tool disconnect $android_to_connect");
system("$adb_tool connect $android_to_connect");
sleep(2);# let it connect
system("$adb_tool -s $android_to_connect reboot &");# adb bug, it blocks forever
sleep(15); # wait for the device to come up again
system("$adb_tool disconnect $android_to_connect");# cleans up the left adb reboot process
system("$adb_tool connect $android_to_connect");
$device_serial =$android_to_connect;
}
system("$adb_tool devices") == 0 or die "No device found, please plug/start at least one device/emulator\n"; # make sure we have at least on device attached
$deployqt_device_serial = "--device $device_serial" if ($device_serial);
$device_serial = "-s $device_serial" if ($device_serial);
$testsubset="/$testsubset" if ($testsubset);
$strip_tool="$android_ndk_dir/toolchains/arm-linux-androideabi-$android_toolchain_version/prebuilt/$host_arch/bin/arm-linux-androideabi-strip" unless($strip_tool);
$readelf_tool="$android_ndk_dir/toolchains/arm-linux-androideabi-$android_toolchain_version/prebuilt/$host_arch/bin/arm-linux-androideabi-readelf" unless($readelf_tool);
$readelf_tool="$readelf_tool -d -w ";
sub dir
{
# print "@stack\n";
}
sub pushd ($)
{
unless ( chdir $_[0] )
{
warn "Error: $!\n";
return;
}
unshift @stack, cwd;
dir;
}
sub popd ()
{
@stack > 1 and shift @stack;
chdir $stack[0];
dir;
}
##############################
# Read possible insignificance
# from pro file
##############################
sub check_if_insignificant
{
return 0 if ( !$ci_use );
my $case = shift;
my $insignificant = 0;
my $prj = QMake::Project->new( 'Makefile' );
$insignificant = $prj->test( 'insignificant_test' );
return $insignificant;
}
##############################
# Print output from given
# $testresult.txt file
##############################
sub print_output
{
my $res_file = shift;
my $case = shift;
my $insignificant = shift;
my $print_all = 0;
$total_tests++;
if (-e $res_file) {
open my $file, $res_file or die "Could not open $res_file: $!";
while (my $line = <$file>) {
if ($line =~ m/^FAIL/) {
print "$line";
# Pretend to be like the "real" testrunner and print out
# all steps
$print_all = 1;
}
}
close $file;
if ($print_all) {
# In case we are printing all, the test failed
system("cat $res_file");
if ($insignificant) {
print " Testrunner: $case failed, but it is marked with insignificant_test\n";
push (@failures ,(basename($case)." [insignificant]"));
$failed_insignificants++;
} else {
$total_failed++;
push (@failures ,(basename($case)));
}
} else {
my $cmd = "sed -n 'x;\$p' ${res_file}";
my $summary = qx(${cmd});
if ($summary =~ m/^Totals/) {
print "$summary";
} else {
print "Error: The log is incomplete. Looks like you have to increase the timeout.";
# The test log seems inclomplete, considering the test as failed.
if ($insignificant) {
print " Testrunner: $case failed, but it is marked with insignificant_test\n";
push (@failures ,(basename($case)." [insignificant]"));
$failed_insignificants++;
} else {
$total_failed++;
push (@failures ,(basename($case)));
}
}
}
} else {
if ($insignificant) {
print " Failed to execute $case, but it is marked with insignificant_test\n";
push (@failures ,(basename($case)." [insignificant]"));
$failed_insignificants++;
} else {
print "Failed to execute $case \n";
$total_failed++;
push (@failures ,(basename($case)));
}
}
}
##############################
# Print summary of test run
##############################
sub print_summary
{
my $total = time()-$start;
my $h = 0;
my $m = 0;
my $s = 0;
my $exit = 0;
print "=== Timing: =================== TEST RUN COMPLETED! ============================\n";
if ($total > 60*60) {
$h = int($total/60/60);
$s = int($total - $h*60*60);
$m = int($s/60);
$s = 0;
print "Total: $h hours $m minutes\n";
} elsif ($total > 60) {
$m = int($total/60);
$s = int($total - $m*60);
print "Total: $m minutes $s seconds\n";
} else {
$s = int($total);
print "Total: $s seconds\n";
}
print "=== Failures: ==================================================================";
foreach my $failed (@failures) {
print $failed."\n";
$exit = 1;
}
print "=== Totals: ".$total_tests." tests, ".($total_tests-$total_failed).
" passes, ".$failed_insignificants.
" insignificant fails ======================\n";
return $exit;
}
sub waitForProcess
{
my $process=shift;
my $action=shift;
my $timeout=shift;
my $sleepPeriod=shift;
$sleepPeriod=1 if !defined($sleepPeriod);
print "Waiting for $process ".$timeout*$sleepPeriod." seconds to" if (!$silent);
print $action?" start...\n":" die...\n" if (!$silent);
while ($timeout--)
{
my $output = `$adb_tool $device_serial shell ps 2>&1`; # get current processes
#FIXME check why $output is not matching m/.*S $process\n/ or m/.*S $process$/ (eol)
my $res=($output =~ m/.*S $process/)?1:0; # check the procress
if ($action == $res)
{
print "... succeed\n" if (!$silent);
return 1;
}
sleep($sleepPeriod);
print "timeount in ".$timeout*$sleepPeriod." seconds\n" if (!$silent);
}
print "... failed\n" if (!$silent);
return 0;
}
my $src_dir_qt=abs_path(dirname($0)."/../../..");
my $quadruplor_dir="$src_dir_qt/tests/auto/android";
my $qmake_path="$src_dir_qt/bin/qmake";
my $androiddeployqt_path="$src_dir_qt/bin/androiddeployqt";
my $tests_dir="$src_dir_qt/tests$testsubset";
my $temp_dir=tempdir(CLEANUP => 1);
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $output_dir=$stack[0]."/".(1900+$year)."-$mon-$mday-$hour:$min";
mkdir($output_dir);
unlink("latest");
system(" ln -s $output_dir latest");
my $sdk_api=0;
my $output = `$adb_tool $device_serial shell getprop`; # get device properties
if ($output =~ m/.*\[ro.build.version.sdk\]: \[(\d+)\]/)
{
$sdk_api=int($1);
$sdk_api=5 if ($sdk_api>5 && $sdk_api<8);
$sdk_api=9 if ($sdk_api>9);
}
sub checkXMLOutput
{
print color 'bold red';
my $fileName = shift;
my $XMLOutput = eval { XMLin($fileName, ForceArray => 1) };
if (!defined($XMLOutput)) {
print "Can't parse the $fileName file, probably the test crased.\n";
print color 'reset';
die "Stopping\n" if $stop_on_fail;
return;
}
my $testName = $XMLOutput->{name};
my $fail = 0;
while (my($node_key, $node_valule) = each (%{$XMLOutput})) {
next if $node_key ne "TestFunction";
while (my($function_key, $function_valule) = each (%{$node_valule})) {
while (my($test_key, $test_valule) = each (%{$function_valule})) {
next if $test_key ne "Incident";
for my $incident (@{$test_valule}) {
if (($incident->{type} ne "pass") && ($incident->{type} ne "xfail")) {
print "test $testName::$function_key failed $incident->{file}:$incident->{line}\n";
$fail = 1;
}
}
}
}
}
print color 'reset';
die "Stopping\n" if $stop_on_fail and $fail;
}
sub startTest
{
my $testName = shift;
my $packageName = "org.qtproject.example.tst_$testName";
my $intentName = "$packageName/org.qtproject.qt5.android.bindings.QtActivity";
my $output_file = shift;
my $insignificance = shift;
my $get_xml= 0;
my $get_txt= 0;
my $testLib ="";
if ($log_out eq "xml") {
$testLib="-o /data/data/$packageName/output.xml,xml";
$get_xml = 1;
} elsif ($log_out eq "txt") {
$testLib="-o /data/data/$packageName/output.txt,txt";
$get_txt = 1;
} else {
$testLib="-o /data/data/$packageName/output.xml,xml -o /data/data/$packageName/output.txt,txt";
$get_xml = 1;
$get_txt = 1;
}
my $cmd="${adb_tool} ${device_serial} shell am start -e applicationArguments \"${testLib}\" -n ${intentName}";
my $res = qx(${cmd});
print $res if (!$silent);
#wait to start (if it has not started and quit already)
waitForProcess($packageName,1,10);
#wait to stop
unless(waitForProcess($packageName,0,$time_out,5))
{
#killProcess($packageName);
print "Someone should kill $packageName\n";
system("$adb_tool $device_serial uninstall $packageName") if ($uninstall);
return 1;
}
# Wait for three seconds to allow process to write all data
sleep(3);
system("$adb_tool $device_serial pull /data/data/$packageName/output.xml $output_dir/$output_file.xml") if ($get_xml);
system("$adb_tool $device_serial pull /data/data/$packageName/output.txt $output_dir/$output_file.txt") if ($get_txt);
if ($get_txt){
print "Tesresults for $packageName:\n";
my $insig =
print_output("$output_dir/$output_file.txt", $packageName, $insignificance);
}
system("$adb_tool $device_serial uninstall $packageName") if ($uninstall);
checkXMLOutput("$output_dir/$output_file.xml") if ($get_xml);
return 1;
}
########### build qt tests and benchmarks ###########
pushd($tests_dir);
print "Building $tests_dir \n";
system("make distclean") if ($make_clean);
system("$qmake_path -r") == 0 or die "Can't run qmake\n"; #exec qmake
system("make -j$jobs") == 0 or warn "Can't build all tests\n"; #exec make
my $testsFiles = "";
if ($testcase) {
$testsFiles=`find . -name libtst_$testcase.so`; # only tests
} else {
$testsFiles=`find . -name libtst_*.so`; # only tests
}
foreach (split("\n",$testsFiles))
{
chomp; #remove white spaces
pushd(abs_path(dirname($_))); # cd to application dir
my $insig = check_if_insignificant();
my $cmd="make INSTALL_ROOT=${temp_dir} install";
my $res = qx(${cmd});
print $res if (!$silent);
my $application=basename(cwd);
if ($silent) {
$cmd="$androiddeployqt_path --install ${deployqt_device_serial} --output ${temp_dir} --deployment debug --verbose --input android-libtst_${application}.so-deployment-settings.json >/dev/null 2>&1";
} else {
$cmd="$androiddeployqt_path --install ${deployqt_device_serial} --output ${temp_dir} --deployment debug --verbose --input android-libtst_${application}.so-deployment-settings.json";
}
$res = qx(${cmd});
print $res if (!$silent);
my $output_name=dirname($_);
$output_name =~ s/\.//; # remove first "." character
$output_name =~ s/\///; # remove first "/" character
$output_name =~ s/\//_/g; # replace all "/" with "_"
$output_name=$application unless($output_name);
$time_out=$max_runtime*60/5; # 5 minutes time out for a normal test
$applicationLibrary = `find $temp_dir -name libtst_bench_$application.so`;
if ($applicationLibrary)
{
$time_out=5*60/5; # 10 minutes for a benchmark
$application = "bench_$application";
}
else
{
$applicationLibrary = `find $temp_dir -name libtst_$application.so`;
}
if (!$applicationLibrary)
{
print "Can't find application binary libtst_$application.so in $temp_dir!\n";
}
else
{
startTest($application, "$output_name", $insig) or warn "Can't run $application ...\n";
}
popd();
remove_tree( $temp_dir, {keep_root => 1} );
}
print_summary() if ($ci_use);
popd();
__END__
=head1 NAME
Script to run all qt tests/benchmarks to an android device/emulator
=head1 SYNOPSIS
runtests.pl [options]
=head1 OPTIONS
=over 8
=item B<-f --fail>
Stop the script when test fails. Default 0
=item B<-s --serial = serial>
Device serial number. May be empty if only one device is attached.
=item B<-t --test = test_subset>
Tests subset (e.g. benchmarks, auto, auto/qbuffer, etc.).
=item B<-c --clean>
Clean tests before building them.
=item B<-j --jobs = number>
Make jobs when building tests.
=item B<--sdk = sdk_path>
Android SDK path.
=item B<--ndk = ndk_path>
Android NDK path.
=item B<--ant = ant_tool_path>
Ant tool path.
=item B<--strip = strip_tool_path>
Android strip tool path, used to deploy qt libs.
=item B<--readelf = readelf_tool_path>
Android readelf tool path, used to check if a test application uses qt OpenGL.
=item B<--logtype = xml|txt|both>
The format of log file, default is xml.
=item B<--runtime = minutes>
The timeout period before stopping individual tests from running.
=item B<-silent>
Suppress output of system commands.
=item B<-ci>
Enables checking if test is insignificant or not. Also prints test
summary after all tests has been executed.
=item B<-uninstall>
Uninstalls the test after has been executed.
=item B<-h --help>
Print a brief help message and exits.
=item B<--man>
Prints the manual page and exits.
=back
=head1 DESCRIPTION
B<This program> will run all qt tests/benchmarks to an android device/emulator.
=cut