You've already forked pgbackrest
							
							
				mirror of
				https://github.com/pgbackrest/pgbackrest.git
				synced 2025-10-30 23:37:45 +02:00 
			
		
		
		
	Coverage testing always enabled on Debian-based containers.
* Full coverage is verified when specified. * Modules marked with partial coverage will error if they are actually fully covered. * Simplified test representation is DefineTest. * Added new representation for queries in DefineTest and added API functions. * Update modules using DefineTest to use new API.
This commit is contained in:
		
							
								
								
									
										42
									
								
								test/Vagrantfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								test/Vagrantfile
									
									
									
									
										vendored
									
									
								
							| @@ -13,6 +13,7 @@ Vagrant.configure(2) do |config| | ||||
|  | ||||
|     # Provision the VM | ||||
|     config.vm.provision "shell", inline: <<-SHELL | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Build Begin' && date | ||||
|  | ||||
|         # Suppress "dpkg-reconfigure: unable to re-open stdin: No file or directory" warning | ||||
| @@ -22,18 +23,32 @@ Vagrant.configure(2) do |config| | ||||
|         sed -i 's/^127\.0\.0\.1\t.*/127\.0\.0\.1\tlocalhost pgbackrest-test/' /etc/hosts | ||||
|         hostnamectl set-hostname pgbackrest-test | ||||
|  | ||||
|         # Update Apt | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Update Apt' && date | ||||
|         apt-get update | ||||
|  | ||||
|         # Install build tools | ||||
|         apt-get install -y devscripts build-essential lintian git txt2man debhelper | ||||
|  | ||||
|         # Synchronize date | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Synchronize Date' && date | ||||
|         apt-get install -y ntpdate | ||||
|         ntpdate pool.ntp.org | ||||
|  | ||||
|         # Install Docker | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Install Perl Modules' && date | ||||
|         apt-get install -y libdbd-pg-perl libxml-checker-perl libperl-critic-perl libdevel-nytprof-perl | ||||
|  | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Install Build Tools' && date | ||||
|         apt-get install -y devscripts build-essential lintian git txt2man debhelper | ||||
|  | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Build Devel::Cover' && date | ||||
|         apt-get install -y libpod-coverage-perl libtest-differences-perl libhtml-parser-perl libtemplate-perl | ||||
|         git clone --branch debian/1.23-2 \ | ||||
|             https://anonscm.debian.org/git/pkg-perl/packages/libdevel-cover-perl.git /root/libdevel-cover-perl | ||||
|         cd /root/libdevel-cover-perl && debuild --no-lintian -i -us -uc -b > /dev/null | ||||
|         dpkg -i /root/libdevel-cover-perl_1.23-2_amd64.deb | ||||
|  | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Install Docker' && date | ||||
|         apt-get install -y apt-transport-https ca-certificates | ||||
|         apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D | ||||
| @@ -44,31 +59,28 @@ Vagrant.configure(2) do |config| | ||||
|         service docker start | ||||
|         sudo usermod -aG docker ubuntu | ||||
|  | ||||
|         # Install Perl modules | ||||
|         echo 'Install Perl Modules' && date | ||||
|         apt-get install -y libdbd-pg-perl libxml-checker-perl libperl-critic-perl libdevel-nytprof-perl libdevel-cover-perl | ||||
|  | ||||
|         # Install utilities | ||||
|         echo 'Install Utilities' && date | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Install Dev Utilities' && date | ||||
|         apt-get install -y vim htop | ||||
|  | ||||
|         # Install TeX Live | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Install TeX Live' && date | ||||
|         apt-get install -y --no-install-recommends texlive-latex-base texlive-latex-extra texlive-fonts-recommended | ||||
|         apt-get install -y texlive-font-utils | ||||
|  | ||||
|         # Create backrest user and postgres group | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Create Postgres Group & pgBackRest User' && date | ||||
|         groupadd -g5000 postgres | ||||
|         adduser --uid=5001 --ingroup=ubuntu --disabled-password --gecos "" backrest | ||||
|  | ||||
|         # Build VM images | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Build VM Images' && date | ||||
|         rm -rf /backrest/test/.vagrant/docker/* | ||||
|         rm -rf /backrest/test/.vagrant/libc/* | ||||
|         rm -rf /backrest/test/.vagrant/package/* | ||||
|         sudo su - ubuntu -c '/backrest/test/test.pl --vm-build' | ||||
|  | ||||
|         #--------------------------------------------------------------------------------------------------------------------------- | ||||
|         echo 'Build End' && date | ||||
|     SHELL | ||||
|  | ||||
|   | ||||
| @@ -94,23 +94,20 @@ sub process | ||||
|     # Iterate each OS | ||||
|     foreach my $strVm (VM_LIST) | ||||
|     { | ||||
|         my $hTestDef = testDefGet(); | ||||
|         my $hVm = vmGet(); | ||||
|         my @stryModule; | ||||
|         my $hFullModule = undef; | ||||
|         my $strFullModule = undef; | ||||
|  | ||||
|         # Get all modules but full to break up the tests | ||||
|         foreach my $hModule (@{$hTestDef->{&TESTDEF_MODULE}}) | ||||
|         foreach my $strModule (testDefModuleList()) | ||||
|         { | ||||
|             my $strModule = $hModule->{&TESTDEF_MODULE_NAME}; | ||||
|  | ||||
|             if ($strModule ne 'full') | ||||
|             { | ||||
|                 push(@stryModule, $strModule); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 $hFullModule = $hModule; | ||||
|                 $strFullModule = $strModule; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -124,20 +121,18 @@ sub process | ||||
|         $bFirst = false; | ||||
|  | ||||
|         # Now generate full tests | ||||
|         my $hRealTest = undef; | ||||
|         my $strRealTest = undef; | ||||
|  | ||||
|         if (!defined($hFullModule)) | ||||
|         if (!defined($strFullModule)) | ||||
|         { | ||||
|             confess "the full module is not defined, has the name changed?"; | ||||
|             confess "${strFullModule} module not found, has the name changed?"; | ||||
|         } | ||||
|  | ||||
|         foreach my $hTest (@{$hFullModule->{&TESTDEF_TEST}}) | ||||
|         foreach my $strTest (testDefModuleTestList($strFullModule)) | ||||
|         { | ||||
|             my $strTest = $hTest->{&TESTDEF_TEST_NAME}; | ||||
|  | ||||
|             if ($strTest eq 'real') | ||||
|             { | ||||
|                 $hRealTest = $hTest; | ||||
|                 $strRealTest = $strTest; | ||||
|  | ||||
|                 foreach my $strDbVersion (sort {$b cmp $a} @{$hVm->{$strVm}{&VM_DB_MINIMAL}}) | ||||
|                 { | ||||
| @@ -155,9 +150,9 @@ sub process | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (!defined($hRealTest)) | ||||
|         if (!defined($strRealTest)) | ||||
|         { | ||||
|             confess 'real test not found in full module, has the name changed?'; | ||||
|             confess "${strRealTest} test not found in ${strFullModule} module, has the name changed?"; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -166,7 +161,12 @@ sub process | ||||
|         "\n" . | ||||
|         "before_install:\n" . | ||||
|         "  - sudo apt-get -qq update\n" . | ||||
|         "  - sudo apt-get install libxml-checker-perl libdbd-pg-perl libperl-critic-perl libdevel-cover-perl\n" . | ||||
|         "  - sudo apt-get install libxml-checker-perl libdbd-pg-perl libperl-critic-perl libtemplate-perl libpod-coverage-perl" . | ||||
|             " libtest-differences-perl libhtml-parser-perl lintian debhelper txt2man devscripts libjson-perl\n" . | ||||
|         "  - git clone https://anonscm.debian.org/git/pkg-perl/packages/libdevel-cover-perl.git ~/libdevel-cover-perl\n" . | ||||
|         '  - cd ~/libdevel-cover-perl && git checkout debian/' . LIB_COVER_VERSION . " && debuild -i -us -uc -b\n" . | ||||
|         '  - sudo dpkg -i ~/' . LIB_COVER_PACKAGE . "\n" . | ||||
|         '  - ' . LIB_COVER_EXE . " -v\n" . | ||||
|         "\n" . | ||||
|         "install:\n" . | ||||
|         "  - sudo adduser --ingroup=\${USER?} --disabled-password --gecos \"\" " . BACKREST_USER . "\n" . | ||||
|   | ||||
| @@ -46,6 +46,16 @@ use constant BACKREST_USER                                          => 'backrest | ||||
|     push @EXPORT, qw(BACKREST_USER); | ||||
| use constant BACKREST_USER_ID                                       => getpwnam(BACKREST_USER) . ''; | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Package constants | ||||
| #################################################################################################################################### | ||||
| use constant LIB_COVER_VERSION                                      => '1.23-2'; | ||||
|     push @EXPORT, qw(LIB_COVER_VERSION); | ||||
| use constant LIB_COVER_PACKAGE                                      => 'libdevel-cover-perl_' . LIB_COVER_VERSION . '_amd64.deb'; | ||||
|     push @EXPORT, qw(LIB_COVER_PACKAGE); | ||||
| use constant LIB_COVER_EXE                                          => '/usr/bin/cover'; | ||||
|     push @EXPORT, qw(LIB_COVER_EXE); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Container repo | ||||
| #################################################################################################################################### | ||||
| @@ -257,6 +267,27 @@ sub sudoSetup | ||||
|     return $strScript; | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Devel::Cover setup | ||||
| #################################################################################################################################### | ||||
| sub coverSetup | ||||
| { | ||||
|     my $strOS = shift; | ||||
|  | ||||
|     my $strScript = ''; | ||||
|     my $oVm = vmGet(); | ||||
|  | ||||
|     if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_DEBIAN) | ||||
|     { | ||||
|         $strScript .= | ||||
|             "\n\n# Install Devel::Cover\n" . | ||||
|             "COPY ${strOS}-" . LIB_COVER_PACKAGE . ' /tmp/' . LIB_COVER_PACKAGE . "\n" . | ||||
|             'RUN dpkg -i /tmp/' . LIB_COVER_PACKAGE; | ||||
|     } | ||||
|  | ||||
|     return $strScript; | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Install Perl packages | ||||
| #################################################################################################################################### | ||||
| @@ -269,27 +300,30 @@ sub perlInstall | ||||
|  | ||||
|     if ($strOS eq VM_CO6) | ||||
|     { | ||||
|         return $strImage . | ||||
|         $strImage .= | ||||
|             'RUN yum install -y perl perl-Time-HiRes perl-parent perl-JSON perl-Digest-SHA perl-DBD-Pg'; | ||||
|     } | ||||
|     elsif ($strOS eq VM_CO7) | ||||
|     { | ||||
|         return $strImage . | ||||
|         $strImage .= | ||||
|             'RUN yum install -y perl perl-JSON-PP perl-Digest-SHA perl-DBD-Pg'; | ||||
|     } | ||||
|     elsif ($strOS eq VM_U12 || $strOS eq VM_U14) | ||||
|     { | ||||
|         return $strImage . | ||||
|             'RUN apt-get install -y libdbd-pg-perl libdbi-perl libnet-daemon-perl libplrpc-perl'; | ||||
|         $strImage .= | ||||
|             'RUN apt-get install -y libdbd-pg-perl libdbi-perl libnet-daemon-perl libplrpc-perl libhtml-parser-perl'; | ||||
|     } | ||||
|     elsif ($strOS eq VM_U16 || $strOS eq VM_D8) | ||||
|     { | ||||
|         return $strImage . | ||||
|             'RUN apt-get install -y libdbd-pg-perl libdbi-perl' . | ||||
|             ($strOS eq VM_U16 ? ' libdevel-cover-perl libtest-pod-coverage-perl' : ''); | ||||
|         $strImage .= | ||||
|             'RUN apt-get install -y libdbd-pg-perl libdbi-perl libhtml-parser-perl'; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         confess &log(ERROR, "unable to install perl for os '${strOS}'"); | ||||
|     } | ||||
|  | ||||
|     confess &log(ERROR, "unable to install perl for os '${strOS}'"); | ||||
|     return $strImage; | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| @@ -487,8 +521,12 @@ sub containerBuild | ||||
|         { | ||||
|             $strScript = | ||||
|                 "# Install package build tools and package source\n" . | ||||
|                 "RUN apt-get install -y devscripts build-essential lintian git libxml-checker-perl txt2man debhelper && \\\n" . | ||||
|                 "    git clone https://anonscm.debian.org/git/pkg-postgresql/pgbackrest.git /root/package-src\n"; | ||||
|                 "RUN apt-get install -y devscripts build-essential lintian git libxml-checker-perl txt2man debhelper" . | ||||
|                     " libpod-coverage-perl libppi-html-perl libtemplate-perl libtest-differences-perl && \\\n" . | ||||
|                 "    git clone https://anonscm.debian.org/git/pkg-postgresql/pgbackrest.git /root/package-src && \\\n" . | ||||
|                 "    git clone https://anonscm.debian.org/git/pkg-perl/packages/libdevel-cover-perl.git" . | ||||
|                     " /root/libdevel-cover-perl && \\\n" . | ||||
|                 '    cd /root/libdevel-cover-perl && git checkout debian/' . LIB_COVER_VERSION . ' && debuild -i -us -uc -b'; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
| @@ -500,6 +538,20 @@ sub containerBuild | ||||
|         # Write the image | ||||
|         containerWrite($strTempPath, $strOS, 'Build', $strImageParent, $strImage, $strScript, $bVmForce, false); | ||||
|  | ||||
|         # Copy Devel::Cover to host so it can be installed in other containers | ||||
|         if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_DEBIAN) | ||||
|         { | ||||
|             executeTest('docker rm -f test-build', {bSuppressError => true}); | ||||
|             executeTest( | ||||
|                 "docker run -itd -h test-build --name=test-build" . | ||||
|                 " -v ${strTempPath}:${strTempPath} " . containerRepo() . ":${strOS}-build", | ||||
|                 {bSuppressStdErr => true}); | ||||
|             executeTest( | ||||
|                 "docker exec -i test-build " . | ||||
|                 "bash -c 'cp /root/" . LIB_COVER_PACKAGE . " ${strTempPath}/${strOS}-" . LIB_COVER_PACKAGE . "'"); | ||||
|             executeTest('docker rm -f test-build'); | ||||
|         } | ||||
|  | ||||
|         # Db image | ||||
|         ########################################################################################################################### | ||||
|         my @stryDbBuild; | ||||
| @@ -588,6 +640,9 @@ sub containerBuild | ||||
|             # Install SSH key | ||||
|             $strScript = sshSetup($strOS, TEST_USER, TEST_GROUP, $$oVm{$strOS}{&VM_CONTROL_MASTER}); | ||||
|  | ||||
|             # Setup Devel::Cover | ||||
|             $strScript .= coverSetup($strOS); | ||||
|  | ||||
|             # Write the image | ||||
|             containerWrite($strTempPath, $strOS, "${strTitle} Test", $strImageParent, $strImage, $strScript, $bVmForce, true, true); | ||||
|         } | ||||
| @@ -600,6 +655,9 @@ sub containerBuild | ||||
|         # Install SSH key | ||||
|         $strScript = sshSetup($strOS, TEST_USER, TEST_GROUP, $$oVm{$strOS}{&VM_CONTROL_MASTER}); | ||||
|  | ||||
|         # Setup Devel::Cover | ||||
|         $strScript .= coverSetup($strOS); | ||||
|  | ||||
|         # Write the image | ||||
|         containerWrite($strTempPath, $strOS, 'Db Synthetic Test', $strImageParent, $strImage, $strScript, $bVmForce, true, true); | ||||
|  | ||||
| @@ -627,6 +685,9 @@ sub containerBuild | ||||
|         # Setup sudo | ||||
|         $strScript .= "\n\n" . sudoSetup($strOS, TEST_GROUP); | ||||
|  | ||||
|         # Setup Devel::Cover | ||||
|         $strScript .= coverSetup($strOS); | ||||
|  | ||||
|         # Write the image | ||||
|         containerWrite($strTempPath, $strOS, 'Loop Test', $strImageParent, $strImage, $strScript, $bVmForce, true, true); | ||||
|  | ||||
| @@ -680,6 +741,9 @@ sub containerBuild | ||||
|             "\n\n# Make " . TEST_USER . " home dir readable\n" . | ||||
|             'RUN chmod g+r,g+x /home/' . TEST_USER; | ||||
|  | ||||
|         # Setup Devel::Cover | ||||
|         $strScript .= coverSetup($strOS); | ||||
|  | ||||
|         # Write the image | ||||
|         containerWrite($strTempPath, $strOS, "${strTitle} Test", $strImageParent, $strImage, $strScript, $bVmForce, true, true); | ||||
|     } | ||||
|   | ||||
| @@ -14,41 +14,50 @@ use Exporter qw(import); | ||||
|     our @EXPORT = qw(); | ||||
|  | ||||
| use pgBackRest::Common::Log; | ||||
| use pgBackRest::Common::String; | ||||
|  | ||||
| ################################################################################################################################ | ||||
| # Test definition constants | ||||
| ################################################################################################################################ | ||||
| use constant TESTDEF_MODULE                                         => 'module'; | ||||
|     push @EXPORT, qw(TESTDEF_MODULE); | ||||
| use constant TESTDEF_MODULE_NAME                                    => 'name'; | ||||
|     push @EXPORT, qw(TESTDEF_MODULE_NAME); | ||||
|  | ||||
| use constant TESTDEF_EXPECT                                         => 'expect'; | ||||
|     push @EXPORT, qw(TESTDEF_EXPECT); | ||||
| use constant TESTDEF_NAME                                           => 'name'; | ||||
|     push @EXPORT, qw(TESTDEF_NAME); | ||||
| use constant TESTDEF_TEST                                           => 'test'; | ||||
|     push @EXPORT, qw(TESTDEF_TEST); | ||||
| use constant TESTDEF_TEST_ALL                                       => 'all'; | ||||
|     push @EXPORT, qw(TESTDEF_TEST_ALL); | ||||
| use constant TESTDEF_TEST_COVERAGE                                  => 'coverage'; | ||||
|     push @EXPORT, qw(TESTDEF_TEST_COVERAGE); | ||||
| use constant TESTDEF_TEST_INDIVIDUAL                                => 'individual'; | ||||
|     push @EXPORT, qw(TESTDEF_TEST_INDIVIDUAL); | ||||
| use constant TESTDEF_TEST_NAME                                      => 'name'; | ||||
|     push @EXPORT, qw(TESTDEF_TEST_NAME); | ||||
| use constant TESTDEF_TEST_TOTAL                                     => 'total'; | ||||
|     push @EXPORT, qw(TESTDEF_TEST_TOTAL); | ||||
| use constant TESTDEF_TEST_CONTAINER                                 => 'container'; | ||||
|     push @EXPORT, qw(TESTDEF_TEST_CONTAINER); | ||||
| use constant TESTDEF_TEST_PROCESS                                   => 'process'; | ||||
|     push @EXPORT, qw(TESTDEF_TEST_PROCESS); | ||||
| use constant TESTDEF_TEST_DB                                        => 'db'; | ||||
|     push @EXPORT, qw(TESTDEF_TEST_DB); | ||||
|  | ||||
| # Determines if the test will be run against multiple db versions | ||||
| use constant TESTDEF_DB                                             => 'db'; | ||||
|     push @EXPORT, qw(TESTDEF_DB); | ||||
| # Determines if the test will be run in a container or will create containers itself | ||||
| use constant TESTDEF_CONTAINER                                      => 'container'; | ||||
|     push @EXPORT, qw(TESTDEF_CONTAINER); | ||||
| # Determines coverage for the test | ||||
| use constant TESTDEF_COVERAGE                                       => 'coverage'; | ||||
|     push @EXPORT, qw(TESTDEF_COVERAGE); | ||||
| # Should expect log tests be run | ||||
| use constant TESTDEF_EXPECT                                         => 'expect'; | ||||
|     push @EXPORT, qw(TESTDEF_EXPECT); | ||||
| # Determines if each run in a test will be run in a new container | ||||
| use constant TESTDEF_INDIVIDUAL                                     => 'individual'; | ||||
|     push @EXPORT, qw(TESTDEF_INDIVIDUAL); | ||||
| # Determines if the test will be run with multiple processes | ||||
| use constant TESTDEF_PROCESS                                        => 'process'; | ||||
|     push @EXPORT, qw(TESTDEF_PROCESS); | ||||
| # Total runs in the test | ||||
| use constant TESTDEF_TOTAL                                          => 'total'; | ||||
|     push @EXPORT, qw(TESTDEF_TOTAL); | ||||
|  | ||||
| # The test provides full coverage for the module | ||||
| use constant TESTDEF_COVERAGE_FULL                                  => true; | ||||
|     push @EXPORT, qw(TESTDEF_COVERAGE_FULL); | ||||
| # The test provides partial coverage for the module | ||||
| use constant TESTDEF_COVERAGE_PARTIAL                               => false; | ||||
|     push @EXPORT, qw(TESTDEF_COVERAGE_PARTIAL); | ||||
|  | ||||
| ################################################################################################################################ | ||||
| # Code modules | ||||
| ################################################################################################################################ | ||||
| use constant TESTDEF_MODULE_FILE                                    => 'File'; | ||||
|     push @EXPORT, qw(TESTDEF_MODULE_FILE); | ||||
| use constant TESTDEF_MODULE_FILE_COMMON                             => TESTDEF_MODULE_FILE . 'Common'; | ||||
| @@ -86,218 +95,211 @@ my $oTestDef = | ||||
|     [ | ||||
|         # Help tests | ||||
|         { | ||||
|             &TESTDEF_MODULE_NAME => 'help', | ||||
|             &TESTDEF_TEST_CONTAINER => true, | ||||
|             &TESTDEF_NAME => 'help', | ||||
|             &TESTDEF_CONTAINER => true, | ||||
|             &TESTDEF_EXPECT => true, | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'help', | ||||
|                     &TESTDEF_TEST_TOTAL => 1, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'help', | ||||
|                     &TESTDEF_TOTAL => 1, | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         # Config tests | ||||
|         { | ||||
|             &TESTDEF_MODULE_NAME => 'config', | ||||
|             &TESTDEF_TEST_CONTAINER => true, | ||||
|             &TESTDEF_NAME => 'config', | ||||
|             &TESTDEF_CONTAINER => true, | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'unit', | ||||
|                     &TESTDEF_TEST_TOTAL => 7, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'unit', | ||||
|                     &TESTDEF_TOTAL => 7, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'option', | ||||
|                     &TESTDEF_TEST_TOTAL => 34, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'option', | ||||
|                     &TESTDEF_TOTAL => 34, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'config', | ||||
|                     &TESTDEF_TEST_TOTAL => 25, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'config', | ||||
|                     &TESTDEF_TOTAL => 25, | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         # File tests | ||||
|         { | ||||
|             &TESTDEF_MODULE_NAME => 'file', | ||||
|             &TESTDEF_TEST_CONTAINER => true, | ||||
|             &TESTDEF_NAME => 'file', | ||||
|             &TESTDEF_CONTAINER => true, | ||||
|  | ||||
|             &TESTDEF_TEST_COVERAGE => | ||||
|             &TESTDEF_COVERAGE => | ||||
|             { | ||||
|                 &TESTDEF_MODULE_FILE => TESTDEF_COVERAGE_FULL, | ||||
|                 &TESTDEF_MODULE_FILE_COMMON => TESTDEF_COVERAGE_FULL, | ||||
|                 &TESTDEF_MODULE_FILE => TESTDEF_COVERAGE_PARTIAL, | ||||
|                 &TESTDEF_MODULE_FILE_COMMON => TESTDEF_COVERAGE_PARTIAL, | ||||
|             }, | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'unit', | ||||
|                     &TESTDEF_TEST_TOTAL => 1, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'unit', | ||||
|                     &TESTDEF_TOTAL => 1, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'owner', | ||||
|                     &TESTDEF_TEST_TOTAL => 8, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'owner', | ||||
|                     &TESTDEF_TOTAL => 8, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'path-create', | ||||
|                     &TESTDEF_TEST_TOTAL => 8, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'path-create', | ||||
|                     &TESTDEF_TOTAL => 8, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'move', | ||||
|                     &TESTDEF_TEST_TOTAL => 24, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'move', | ||||
|                     &TESTDEF_TOTAL => 24, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'compress', | ||||
|                     &TESTDEF_TEST_TOTAL => 4, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'compress', | ||||
|                     &TESTDEF_TOTAL => 4, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'wait', | ||||
|                     &TESTDEF_TEST_TOTAL => 2, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'wait', | ||||
|                     &TESTDEF_TOTAL => 2, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'link', | ||||
|                     &TESTDEF_TEST_TOTAL => 1, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'link', | ||||
|                     &TESTDEF_TOTAL => 1, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'stat', | ||||
|                     &TESTDEF_TEST_TOTAL => 1, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'stat', | ||||
|                     &TESTDEF_TOTAL => 1, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'manifest', | ||||
|                     &TESTDEF_TEST_TOTAL => 5, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'manifest', | ||||
|                     &TESTDEF_TOTAL => 5, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'list', | ||||
|                     &TESTDEF_TEST_TOTAL => 72, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'list', | ||||
|                     &TESTDEF_TOTAL => 72, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'remove', | ||||
|                     &TESTDEF_TEST_TOTAL => 32, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'remove', | ||||
|                     &TESTDEF_TOTAL => 32, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'hash', | ||||
|                     &TESTDEF_TEST_TOTAL => 16, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'hash', | ||||
|                     &TESTDEF_TOTAL => 16, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'exists', | ||||
|                     &TESTDEF_TEST_TOTAL => 6, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'exists', | ||||
|                     &TESTDEF_TOTAL => 6, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'copy', | ||||
|                     &TESTDEF_TEST_TOTAL => 144, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'copy', | ||||
|                     &TESTDEF_TOTAL => 144, | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         # Info tests | ||||
|         { | ||||
|             &TESTDEF_NAME => 'info', | ||||
|             &TESTDEF_CONTAINER => true, | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_NAME => 'unit', | ||||
|                     &TESTDEF_TOTAL => 1, | ||||
|  | ||||
|                     &TESTDEF_COVERAGE => | ||||
|                     { | ||||
|                         &TESTDEF_MODULE_INFO => TESTDEF_COVERAGE_PARTIAL, | ||||
|                     }, | ||||
|                 }, | ||||
|             ] | ||||
|         }, | ||||
|         # Stanza tests | ||||
|         { | ||||
|             &TESTDEF_MODULE_NAME => 'stanza', | ||||
|             &TESTDEF_TEST_CONTAINER => false, | ||||
|             &TESTDEF_EXPECT => true, | ||||
|             &TESTDEF_NAME => 'stanza', | ||||
|  | ||||
|             &TESTDEF_TEST_COVERAGE => | ||||
|             &TESTDEF_COVERAGE => | ||||
|             { | ||||
|                 &TESTDEF_MODULE_STANZA => TESTDEF_COVERAGE_FULL, | ||||
|                 &TESTDEF_MODULE_STANZA => TESTDEF_COVERAGE_PARTIAL, | ||||
|             }, | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'unit', | ||||
|                     &TESTDEF_EXPECT => false, | ||||
|                     &TESTDEF_TEST_TOTAL => 2, | ||||
|                     &TESTDEF_NAME => 'unit', | ||||
|                     &TESTDEF_TOTAL => 2, | ||||
|                     &TESTDEF_CONTAINER => true, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'create', | ||||
|                     &TESTDEF_TEST_TOTAL => 2 | ||||
|                     &TESTDEF_NAME => 'create', | ||||
|                     &TESTDEF_TOTAL => 2, | ||||
|                     &TESTDEF_EXPECT => true, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'upgrade', | ||||
|                     &TESTDEF_TEST_TOTAL => 2 | ||||
|                     &TESTDEF_NAME => 'upgrade', | ||||
|                     &TESTDEF_TOTAL => 2, | ||||
|                     &TESTDEF_EXPECT => true, | ||||
|                 }, | ||||
|             ] | ||||
|         }, | ||||
|         # Archive tests | ||||
|         { | ||||
|             &TESTDEF_MODULE_NAME => 'archive', | ||||
|             &TESTDEF_TEST_CONTAINER => false, | ||||
|             &TESTDEF_EXPECT => true, | ||||
|             &TESTDEF_NAME => 'archive', | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'unit', | ||||
|                     &TESTDEF_TEST_TOTAL => 4, | ||||
|                     &TESTDEF_TEST_CONTAINER => true, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_EXPECT => false, | ||||
|                     &TESTDEF_NAME => 'unit', | ||||
|                     &TESTDEF_TOTAL => 4, | ||||
|                     &TESTDEF_CONTAINER => true, | ||||
|  | ||||
|                     &TESTDEF_TEST_COVERAGE => | ||||
|                     &TESTDEF_COVERAGE => | ||||
|                     { | ||||
|                         &TESTDEF_TEST_ALL => | ||||
|                         { | ||||
|                             &TESTDEF_MODULE_ARCHIVE_COMMON => TESTDEF_COVERAGE_PARTIAL, | ||||
|                         } | ||||
|                         &TESTDEF_MODULE_ARCHIVE_COMMON => TESTDEF_COVERAGE_PARTIAL, | ||||
|                     }, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'push-unit', | ||||
|                     &TESTDEF_TEST_TOTAL => 7, | ||||
|                     &TESTDEF_TEST_CONTAINER => true, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_EXPECT => false, | ||||
|                     &TESTDEF_NAME => 'push-unit', | ||||
|                     &TESTDEF_TOTAL => 7, | ||||
|                     &TESTDEF_CONTAINER => true, | ||||
|  | ||||
|                     &TESTDEF_TEST_COVERAGE => | ||||
|                     &TESTDEF_COVERAGE => | ||||
|                     { | ||||
|                         &TESTDEF_TEST_ALL => | ||||
|                         { | ||||
|                             &TESTDEF_MODULE_ARCHIVE_PUSH => TESTDEF_COVERAGE_FULL, | ||||
|                             &TESTDEF_MODULE_ARCHIVE_PUSH_ASYNC => TESTDEF_COVERAGE_FULL, | ||||
|                             &TESTDEF_MODULE_ARCHIVE_PUSH_FILE => TESTDEF_COVERAGE_PARTIAL, | ||||
|                         } | ||||
|                         &TESTDEF_MODULE_ARCHIVE_PUSH => TESTDEF_COVERAGE_FULL, | ||||
|                         &TESTDEF_MODULE_ARCHIVE_PUSH_ASYNC => TESTDEF_COVERAGE_FULL, | ||||
|                         &TESTDEF_MODULE_ARCHIVE_PUSH_FILE => TESTDEF_COVERAGE_FULL, | ||||
|                     }, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'push', | ||||
|                     &TESTDEF_TEST_TOTAL => 8, | ||||
|                     &TESTDEF_TEST_PROCESS => true, | ||||
|                     &TESTDEF_NAME => 'push', | ||||
|                     &TESTDEF_TOTAL => 8, | ||||
|                     &TESTDEF_PROCESS => true, | ||||
|                     &TESTDEF_INDIVIDUAL => true, | ||||
|                     &TESTDEF_EXPECT => true, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'stop', | ||||
|                     &TESTDEF_TEST_TOTAL => 6 | ||||
|                     &TESTDEF_NAME => 'stop', | ||||
|                     &TESTDEF_TOTAL => 6, | ||||
|                     &TESTDEF_INDIVIDUAL => true, | ||||
|                     &TESTDEF_EXPECT => true, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'get', | ||||
|                     &TESTDEF_TEST_TOTAL => 8 | ||||
|                     &TESTDEF_NAME => 'get', | ||||
|                     &TESTDEF_TOTAL => 8, | ||||
|                     &TESTDEF_INDIVIDUAL => true, | ||||
|                     &TESTDEF_EXPECT => true, | ||||
|                 }, | ||||
|             ] | ||||
|         }, | ||||
|         # Backup tests | ||||
|         { | ||||
|             &TESTDEF_MODULE_NAME => 'backup', | ||||
|             &TESTDEF_TEST_CONTAINER => false, | ||||
|             &TESTDEF_EXPECT => false, | ||||
|             &TESTDEF_NAME => 'backup', | ||||
|             &TESTDEF_CONTAINER => true, | ||||
|  | ||||
|             &TESTDEF_TEST_COVERAGE => | ||||
|             &TESTDEF_COVERAGE => | ||||
|             { | ||||
|                 &TESTDEF_MODULE_BACKUP_COMMON => TESTDEF_COVERAGE_FULL, | ||||
|             }, | ||||
| @@ -305,79 +307,51 @@ my $oTestDef = | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'unit', | ||||
|                     &TESTDEF_TEST_TOTAL => 3, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'unit', | ||||
|                     &TESTDEF_TOTAL => 3, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'info-unit', | ||||
|                     &TESTDEF_TEST_TOTAL => 1, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_NAME => 'info-unit', | ||||
|                     &TESTDEF_TOTAL => 1, | ||||
|                 }, | ||||
|             ] | ||||
|         }, | ||||
|         # Expire tests | ||||
|         { | ||||
|             &TESTDEF_MODULE_NAME => 'expire', | ||||
|             &TESTDEF_TEST_CONTAINER => false, | ||||
|             &TESTDEF_NAME => 'expire', | ||||
|             &TESTDEF_EXPECT => true, | ||||
|             &TESTDEF_INDIVIDUAL => true, | ||||
|  | ||||
|             &TESTDEF_TEST_COVERAGE => | ||||
|             &TESTDEF_COVERAGE => | ||||
|             { | ||||
|                 &TESTDEF_MODULE_EXPIRE => TESTDEF_COVERAGE_FULL, | ||||
|                 &TESTDEF_MODULE_EXPIRE => TESTDEF_COVERAGE_PARTIAL, | ||||
|             }, | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'expire', | ||||
|                     &TESTDEF_TEST_TOTAL => 2, | ||||
|                 }, | ||||
|             ] | ||||
|         }, | ||||
|         # Info tests | ||||
|         { | ||||
|             &TESTDEF_MODULE_NAME => 'info', | ||||
|             &TESTDEF_TEST_CONTAINER => false, | ||||
|             &TESTDEF_EXPECT => true, | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'unit', | ||||
|                     &TESTDEF_TEST_CONTAINER => true, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                     &TESTDEF_EXPECT => false, | ||||
|                     &TESTDEF_TEST_TOTAL => 1, | ||||
|  | ||||
|                     &TESTDEF_TEST_COVERAGE => | ||||
|                     { | ||||
|                         &TESTDEF_TEST_ALL => | ||||
|                         { | ||||
|                             &TESTDEF_MODULE_INFO => TESTDEF_COVERAGE_FULL, | ||||
|                         } | ||||
|                     }, | ||||
|                     &TESTDEF_NAME => 'expire', | ||||
|                     &TESTDEF_TOTAL => 2, | ||||
|                 }, | ||||
|             ] | ||||
|         }, | ||||
|         # Full tests | ||||
|         { | ||||
|             &TESTDEF_MODULE_NAME => 'full', | ||||
|             &TESTDEF_TEST_CONTAINER => false, | ||||
|             &TESTDEF_NAME => 'full', | ||||
|             &TESTDEF_EXPECT => true, | ||||
|             &TESTDEF_INDIVIDUAL => true, | ||||
|             &TESTDEF_PROCESS => true, | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'synthetic', | ||||
|                     &TESTDEF_TEST_TOTAL => 8, | ||||
|                     &TESTDEF_TEST_PROCESS => true | ||||
|                     &TESTDEF_NAME => 'synthetic', | ||||
|                     &TESTDEF_TOTAL => 8, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'real', | ||||
|                     &TESTDEF_TEST_TOTAL => 11, | ||||
|                     &TESTDEF_TEST_PROCESS => true, | ||||
|                     &TESTDEF_TEST_DB => true | ||||
|                     &TESTDEF_NAME => 'real', | ||||
|                     &TESTDEF_TOTAL => 11, | ||||
|                     &TESTDEF_DB => true, | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
| @@ -385,55 +359,154 @@ my $oTestDef = | ||||
| }; | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # testDefGet | ||||
| # Process normalized data into a more queryable form | ||||
| #################################################################################################################################### | ||||
| sub testDefGet | ||||
| my $hTestDefHash;                                                   # An easier way to query hash version of the above | ||||
| my @stryModule;                                                     # Ordered list of modules | ||||
| my $hModuleTest;                                                    # Ordered list of tests for each module | ||||
| my $hCoverageType;                                                  # Coverage type for each code module (full/partial) | ||||
| my $hCoverageList;                                                  # Tests required for full code module coverage (if type full) | ||||
|  | ||||
| # Iterate each module | ||||
| foreach my $hModule (@{$oTestDef->{&TESTDEF_MODULE}}) | ||||
| { | ||||
|     return $oTestDef; | ||||
| } | ||||
|     # Push the module onto the ordered list | ||||
|     my $strModule = $hModule->{&TESTDEF_NAME}; | ||||
|     push(@stryModule, $strModule); | ||||
|  | ||||
| push @EXPORT, qw(testDefGet); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # testDefModuleGet | ||||
| #################################################################################################################################### | ||||
| sub testDefModuleGet | ||||
| { | ||||
|     my $strModule = shift; | ||||
|  | ||||
|     # Find the module | ||||
|     foreach my $hModule (@{$oTestDef->{&TESTDEF_MODULE}}) | ||||
|     { | ||||
|         if ($hModule->{&TESTDEF_MODULE_NAME} eq $strModule) | ||||
|         { | ||||
|             return $hModule; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     confess &log(ASSERT, "unable to find module ${strModule}"); | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(testDefModuleGet); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # testDefModuleTestGet | ||||
| #################################################################################################################################### | ||||
| sub testDefModuleTestGet | ||||
| { | ||||
|     my $hModule = shift; | ||||
|     my $strModuleTest = shift; | ||||
|     # Iterate each test | ||||
|     my @stryModuleTest; | ||||
|  | ||||
|     foreach my $hModuleTest (@{$hModule->{&TESTDEF_TEST}}) | ||||
|     { | ||||
|         if ($hModuleTest->{&TESTDEF_TEST_NAME} eq $strModuleTest) | ||||
|         # Push the test on the order list | ||||
|         my $strTest = $hModuleTest->{&TESTDEF_NAME}; | ||||
|         push(@stryModuleTest, $strTest); | ||||
|  | ||||
|         # Resolve variables that can be set in the module or the test | ||||
|         foreach my $strVar ( | ||||
|             TESTDEF_CONTAINER, TESTDEF_EXPECT, TESTDEF_PROCESS, TESTDEF_DB, TESTDEF_INDIVIDUAL) | ||||
|         { | ||||
|             return $hModuleTest; | ||||
|             $hTestDefHash->{$strModule}{$strTest}{$strVar} = coalesce( | ||||
|                 $hModuleTest->{$strVar}, coalesce($hModule->{$strVar}, false)); | ||||
|         } | ||||
|  | ||||
|         # Set test count | ||||
|         $hTestDefHash->{$strModule}{$strTest}{&TESTDEF_TOTAL} = $hModuleTest->{&TESTDEF_TOTAL}; | ||||
|  | ||||
|         # Concatenate coverage for modules and tests | ||||
|         foreach my $hCoverage ($hModule->{&TESTDEF_COVERAGE}, $hModuleTest->{&TESTDEF_COVERAGE}) | ||||
|         { | ||||
|             foreach my $strCodeModule (sort(keys(%{$hCoverage}))) | ||||
|             { | ||||
|                 if (defined($hTestDefHash->{$strModule}{$strTest}{&TESTDEF_COVERAGE}{$strCodeModule})) | ||||
|                 { | ||||
|                     confess &log(ASSERT, | ||||
|                         "${strCodeModule} is defined for coverage in both module ${strModule} and test ${strTest}"); | ||||
|                 } | ||||
|  | ||||
|                 $hTestDefHash->{$strModule}{$strTest}{&TESTDEF_COVERAGE}{$strCodeModule} = $hCoverage->{$strCodeModule}; | ||||
|  | ||||
|                 # Build coverage type hash and make sure coverage type does not change | ||||
|                 if (!defined($hCoverageType->{$strCodeModule})) | ||||
|                 { | ||||
|                     $hCoverageType->{$strCodeModule} = $hCoverage->{$strCodeModule}; | ||||
|                 } | ||||
|                 elsif ($hCoverageType->{$strCodeModule} != $hCoverage->{$strCodeModule}) | ||||
|                 { | ||||
|                     confess &log(ASSERT, "cannot mix full/partial coverage for ${strCodeModule}"); | ||||
|                 } | ||||
|  | ||||
|                 # Add to coverage list | ||||
|                 push(@{$hCoverageList->{$strCodeModule}}, {strModule=> $strModule, strTest => $strTest}); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     confess &log(ASSERT, "unable to find module test ${strModuleTest}"); | ||||
|     $hModuleTest->{$strModule} = \@stryModuleTest; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(testDefModuleTestGet); | ||||
| #################################################################################################################################### | ||||
| # testDefModuleList | ||||
| #################################################################################################################################### | ||||
| sub testDefModuleList | ||||
| { | ||||
|     return @stryModule; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(testDefModuleList); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # testDefModule | ||||
| #################################################################################################################################### | ||||
| sub testDefModule | ||||
| { | ||||
|     my $strModule = shift; | ||||
|  | ||||
|     if (!defined($hTestDefHash->{$strModule})) | ||||
|     { | ||||
|         confess &log(ASSERT, "unable to find module ${strModule}"); | ||||
|     } | ||||
|  | ||||
|     return $hTestDefHash->{$strModule}; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(testDefModule); | ||||
|  | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # testDefModuleTestList | ||||
| #################################################################################################################################### | ||||
| sub testDefModuleTestList | ||||
| { | ||||
|     my $strModule = shift; | ||||
|  | ||||
|     if (!defined($hModuleTest->{$strModule})) | ||||
|     { | ||||
|         confess &log(ASSERT, "unable to find module ${strModule}"); | ||||
|     } | ||||
|  | ||||
|     return @{$hModuleTest->{$strModule}}; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(testDefModuleTestList); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # testDefModuleTest | ||||
| #################################################################################################################################### | ||||
| sub testDefModuleTest | ||||
| { | ||||
|     my $strModule = shift; | ||||
|     my $strModuleTest = shift; | ||||
|  | ||||
|     if (!defined($hTestDefHash->{$strModule}{$strModuleTest})) | ||||
|     { | ||||
|         confess &log(ASSERT, "unable to find module ${strModule}, test ${strModuleTest}"); | ||||
|     } | ||||
|  | ||||
|     return $hTestDefHash->{$strModule}{$strModuleTest}; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(testDefModuleTest); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # testDefCoverageType | ||||
| #################################################################################################################################### | ||||
| sub testDefCoverageType | ||||
| { | ||||
|     return $hCoverageType; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(testDefCoverageType); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # testDefCoverageList | ||||
| #################################################################################################################################### | ||||
| sub testDefCoverageList | ||||
| { | ||||
|     return $hCoverageList; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(testDefCoverageList); | ||||
|  | ||||
| 1; | ||||
|   | ||||
| @@ -28,6 +28,7 @@ use pgBackRestTest::Common::ContainerTest; | ||||
| use pgBackRestTest::Common::ExecuteTest; | ||||
| use pgBackRestTest::Common::ListTest; | ||||
| use pgBackRestTest::Common::RunTest; | ||||
| use pgBackRestTest::Common::VmTest; | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # new | ||||
| @@ -56,7 +57,6 @@ sub new | ||||
|         $self->{strLogLevel}, | ||||
|         $self->{bLogForce}, | ||||
|         $self->{bShowOutputAsync}, | ||||
|         $self->{bCoverage}, | ||||
|         $self->{bNoCleanup}, | ||||
|         $self->{iRetry}, | ||||
|     ) = | ||||
| @@ -76,7 +76,6 @@ sub new | ||||
|             {name => 'strLogLevel'}, | ||||
|             {name => 'bLogForce'}, | ||||
|             {name => 'bShowOutputAsync'}, | ||||
|             {name => 'bCoverage'}, | ||||
|             {name => 'bNoCleanup'}, | ||||
|             {name => 'iRetry'}, | ||||
|         ); | ||||
| @@ -166,7 +165,7 @@ sub run | ||||
|         # Create command | ||||
|         my $strCommand = | ||||
|             ($self->{oTest}->{&TEST_CONTAINER} ? 'docker exec -i -u ' . TEST_USER . " ${strImage} " : '') . | ||||
|             ($self->{bCoverage} ? testRunExe( | ||||
|             (vmCoverage($self->{oTest}->{&TEST_VM}) ? testRunExe( | ||||
|                 abs_path($0), dirname($self->{strCoveragePath}), $self->{strBackRestBase}, $self->{oTest}->{&TEST_MODULE}, | ||||
|                 $self->{oTest}->{&TEST_NAME}, defined($self->{oTest}->{&TEST_RUN}) ? $self->{oTest}->{&TEST_RUN} : 'all') : | ||||
|                 abs_path($0)) . | ||||
| @@ -180,7 +179,6 @@ sub run | ||||
|             (defined($self->{oTest}->{&TEST_PROCESS}) ? ' --process-max=' . $self->{oTest}->{&TEST_PROCESS} : '') . | ||||
|             ($self->{strLogLevel} ne lc(INFO) ? " --log-level=$self->{strLogLevel}" : '') . | ||||
|             ' --pgsql-bin=' . $self->{oTest}->{&TEST_PGSQL_BIN} . | ||||
|             ($self->{bCoverage} ? ' --coverage' : '') . | ||||
|             ($self->{bLogForce} ? ' --log-force' : '') . | ||||
|             ($self->{bDryRun} ? ' --dry-run' : '') . | ||||
|             ($self->{bDryRun} ? ' --vm-out' : '') . | ||||
|   | ||||
| @@ -51,9 +51,8 @@ sub testListGet | ||||
|     my $iyModuleTestRun = shift; | ||||
|     my $strDbVersion = shift; | ||||
|     my $iProcessMax = shift; | ||||
|     my $bCoverage = shift; | ||||
|     my $bCoverageOnly = shift; | ||||
|  | ||||
|     my $oTestDef = testDefGet(); | ||||
|     my $oyVm = vmGet(); | ||||
|     my $oyTestRun = []; | ||||
|  | ||||
| @@ -71,13 +70,17 @@ sub testListGet | ||||
|  | ||||
|     foreach my $strTestOS (@stryTestOS) | ||||
|     { | ||||
|         foreach my $oModule (@{$$oTestDef{&TESTDEF_MODULE}}) | ||||
|         foreach my $strModule (testDefModuleList()) | ||||
|         { | ||||
|             if (@{$stryModule} == 0 || grep(/^$$oModule{&TESTDEF_MODULE_NAME}$/i, @{$stryModule})) | ||||
|             my $hModule = testDefModule($strModule); | ||||
|  | ||||
|             if (@{$stryModule} == 0 || grep(/^$strModule$/i, @{$stryModule})) | ||||
|             { | ||||
|                 foreach my $oTest (@{$$oModule{test}}) | ||||
|                 foreach my $strModuleTest (testDefModuleTestList($strModule)) | ||||
|                 { | ||||
|                     if (@{$stryModuleTest} == 0 || grep(/^$$oTest{&TESTDEF_TEST_NAME}$/i, @{$stryModuleTest})) | ||||
|                     my $hTest = testDefModuleTest($strModule, $strModuleTest); | ||||
|  | ||||
|                     if (@{$stryModuleTest} == 0 || grep(/^$strModuleTest$/i, @{$stryModuleTest})) | ||||
|                     { | ||||
|                         my $iDbVersionMin = -1; | ||||
|                         my $iDbVersionMax = -1; | ||||
| @@ -91,7 +94,7 @@ sub testListGet | ||||
|                             $strDbVersionKey = &VM_DB_MINIMAL; | ||||
|                         } | ||||
|  | ||||
|                         if (defined($$oTest{&TESTDEF_TEST_DB}) && $$oTest{&TESTDEF_TEST_DB}) | ||||
|                         if (defined($hTest->{&TESTDEF_DB}) && $hTest->{&TESTDEF_DB}) | ||||
|                         { | ||||
|                             $iDbVersionMin = 0; | ||||
|                             $iDbVersionMax = @{$$oyVm{$strTestOS}{$strDbVersionKey}} - 1; | ||||
| @@ -107,10 +110,10 @@ sub testListGet | ||||
|                             { | ||||
|                                 # Individual tests will be each be run in a separate container.  This is the default. | ||||
|                                 my $bTestIndividual = | ||||
|                                     !defined($$oTest{&TESTDEF_TEST_INDIVIDUAL}) || $$oTest{&TESTDEF_TEST_INDIVIDUAL} ? true : false; | ||||
|                                     !defined($hTest->{&TESTDEF_INDIVIDUAL}) || $hTest->{&TESTDEF_INDIVIDUAL} ? true : false; | ||||
|  | ||||
|                                 my $iTestRunMin = $bTestIndividual ? 1 : -1; | ||||
|                                 my $iTestRunMax = $bTestIndividual ? $$oTest{&TESTDEF_TEST_TOTAL} : -1; | ||||
|                                 my $iTestRunMax = $bTestIndividual ? $hTest->{&TESTDEF_TOTAL} : -1; | ||||
|  | ||||
|                                 for (my $iTestRunIdx = $iTestRunMin; $iTestRunIdx <= $iTestRunMax; $iTestRunIdx++) | ||||
|                                 { | ||||
| @@ -119,16 +122,12 @@ sub testListGet | ||||
|                                         $bTestIndividual && @{$iyModuleTestRun} != 0 && | ||||
|                                             !grep(/^$iTestRunIdx$/i, @{$iyModuleTestRun})); | ||||
|  | ||||
|                                     # Skip this run if coverage is requested and this test does not provide coverage | ||||
|                                     next if ( | ||||
|                                         $bCoverage && | ||||
|                                         (($bTestIndividual && !defined($oTest->{&TESTDEF_TEST_COVERAGE}{$iTestRunIdx})) || | ||||
|                                          (!$bTestIndividual && !defined($oTest->{&TESTDEF_TEST_COVERAGE}{&TESTDEF_TEST_ALL}))) && | ||||
|                                         !defined($oModule->{&TESTDEF_TEST_COVERAGE})); | ||||
|                                     # Skip this run if only coverage tests are requested and this test does not provide coverage | ||||
|                                     next if ($bCoverageOnly && !defined($hTest->{&TESTDEF_COVERAGE})); | ||||
|  | ||||
|                                     my $iyProcessMax = [defined($iProcessMax) ? $iProcessMax : 1]; | ||||
|  | ||||
|                                     if (defined($$oTest{&TESTDEF_TEST_PROCESS}) && $$oTest{&TESTDEF_TEST_PROCESS} && | ||||
|                                     if (defined($hTest->{&TESTDEF_PROCESS}) && $hTest->{&TESTDEF_PROCESS} && | ||||
|                                         !defined($iProcessMax) && $bFirstDbVersion) | ||||
|                                     { | ||||
|                                         $iyProcessMax = [1, 4]; | ||||
| @@ -153,12 +152,12 @@ sub testListGet | ||||
|                                         my $oTestRun = | ||||
|                                         { | ||||
|                                             &TEST_VM => $strTestOS, | ||||
|                                             &TEST_CONTAINER => defined($oTest->{&TESTDEF_TEST_CONTAINER}) ? | ||||
|                                                 $oTest->{&TESTDEF_TEST_CONTAINER} : $oModule->{&TESTDEF_TEST_CONTAINER}, | ||||
|                                             &TEST_CONTAINER => defined($hTest->{&TESTDEF_CONTAINER}) ? | ||||
|                                                 $hTest->{&TESTDEF_CONTAINER} : $hModule->{&TESTDEF_CONTAINER}, | ||||
|                                             &TEST_PGSQL_BIN => $strPgSqlBin, | ||||
|                                             &TEST_PERL_ARCH_PATH => $$oyVm{$strTestOS}{&VMDEF_PERL_ARCH_PATH}, | ||||
|                                             &TEST_MODULE => $$oModule{&TESTDEF_MODULE_NAME}, | ||||
|                                             &TEST_NAME => $$oTest{&TESTDEF_TEST_NAME}, | ||||
|                                             &TEST_MODULE => $strModule, | ||||
|                                             &TEST_NAME => $strModuleTest, | ||||
|                                             &TEST_RUN => | ||||
|                                                 $iTestRunIdx == -1 ? (@{$iyModuleTestRun} == 0 ? undef : $iyModuleTestRun) : | ||||
|                                                     [$iTestRunIdx], | ||||
|   | ||||
| @@ -22,6 +22,7 @@ use pgBackRest::Common::Wait; | ||||
| use pgBackRestTest::Common::DefineTest; | ||||
| use pgBackRestTest::Common::ExecuteTest; | ||||
| use pgBackRestTest::Common::LogTest; | ||||
| use pgBackRestTest::Common::VmTest; | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Constant to use when bogus data is required | ||||
| @@ -118,7 +119,6 @@ sub process | ||||
|         $self->{bDryRun}, | ||||
|         $self->{bCleanup}, | ||||
|         $self->{bLogForce}, | ||||
|         $self->{bCoverage}, | ||||
|         $self->{strPgUser}, | ||||
|         $self->{strBackRestUser}, | ||||
|         $self->{strGroup}, | ||||
| @@ -141,7 +141,6 @@ sub process | ||||
|             {name => 'bDryRun'}, | ||||
|             {name => 'bCleanup'}, | ||||
|             {name => 'bLogForce'}, | ||||
|             {name => 'bCoverage'}, | ||||
|             {name => 'strPgUser'}, | ||||
|             {name => 'strBackRestUser'}, | ||||
|             {name => 'strGroup'}, | ||||
| @@ -157,12 +156,11 @@ sub process | ||||
|     $self->cleanModule(); | ||||
|  | ||||
|     # Make sure the correct number of tests ran | ||||
|     my $hModule = testDefModuleGet($self->{strModule}); | ||||
|     my $hModuleTest = testDefModuleTestGet($hModule, $self->{strModuleTest}); | ||||
|     my $hModuleTest = testDefModuleTest($self->{strModule}, $self->{strModuleTest}); | ||||
|  | ||||
|     if ($hModuleTest->{&TESTDEF_TEST_TOTAL} != $self->runCurrent()) | ||||
|     if ($hModuleTest->{&TESTDEF_TOTAL} != $self->runCurrent()) | ||||
|     { | ||||
|         confess &log(ASSERT, "expected $hModuleTest->{&TESTDEF_TEST_TOTAL} tests to run but $self->{iRun} ran"); | ||||
|         confess &log(ASSERT, "expected $hModuleTest->{&TESTDEF_TOTAL} tests to run but $self->{iRun} ran"); | ||||
|     } | ||||
|  | ||||
|     # Return from function and log return values if any | ||||
| @@ -205,14 +203,7 @@ sub begin | ||||
|     # Else get the default expect setting | ||||
|     else | ||||
|     { | ||||
|         my $hModule = testDefModuleGet($self->{strModule}); | ||||
|         my $hModuleTest = testDefModuleTestGet($hModule, $self->{strModuleTest}); | ||||
|         $self->{bExpect} = | ||||
|             defined($hModuleTest->{&TESTDEF_EXPECT}) ? | ||||
|                 ($hModuleTest->{&TESTDEF_EXPECT} ? true : false) : | ||||
|                 (defined($hModule->{&TESTDEF_EXPECT}) ? | ||||
|                     ($hModule->{&TESTDEF_EXPECT} ? true : false) : | ||||
|                     false); | ||||
|         $self->{bExpect} = (testDefModuleTest($self->{strModule}, $self->{strModuleTest}))->{&TESTDEF_EXPECT}; | ||||
|     } | ||||
|  | ||||
|     # Increment the run counter; | ||||
| @@ -494,33 +485,9 @@ sub testRunExe | ||||
|     my $bLog = shift; | ||||
|  | ||||
|     # Limit Perl modules tested to what is defined in the test coverage (if it exists) | ||||
|     my $hTestCoverage = (testDefModuleTest($strModule, $strTest))->{&TESTDEF_COVERAGE}; | ||||
|     my $strPerlModule; | ||||
|     my $strPerlModuleLog; | ||||
|     my $hTestCoverage; | ||||
|     my $hTestDef = testDefGet(); | ||||
|  | ||||
|     foreach my $hTestModule (@{$hTestDef->{&TESTDEF_MODULE}}) | ||||
|     { | ||||
|         if ($hTestModule->{&TESTDEF_MODULE_NAME} eq $strModule) | ||||
|         { | ||||
|             $hTestCoverage = $hTestModule->{&TESTDEF_TEST_COVERAGE}; | ||||
|  | ||||
|             foreach my $hTest (@{$hTestModule->{&TESTDEF_TEST}}) | ||||
|             { | ||||
|                 if (defined($strTest) && $hTest->{&TESTDEF_TEST_NAME} eq $strTest) | ||||
|                 { | ||||
|                     $hTestCoverage = | ||||
|                         defined($hTest->{&TESTDEF_TEST_COVERAGE}{$iRun}) ? $hTest->{&TESTDEF_TEST_COVERAGE}{$iRun} : | ||||
|                             $hTest->{&TESTDEF_TEST_COVERAGE}{&TESTDEF_TEST_ALL}; | ||||
|  | ||||
|                     if (!defined($hTestCoverage)) | ||||
|                     { | ||||
|                         $hTestCoverage = $hTestModule->{&TESTDEF_TEST_COVERAGE}; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (defined($hTestCoverage)) | ||||
|     { | ||||
| @@ -535,9 +502,8 @@ sub testRunExe | ||||
|     if (defined($strPerlModule)) | ||||
|     { | ||||
|         $strExe = | ||||
|             'perl -MDevel::Cover=-silent,1,-dir,' . $strCoveragePath . ',-subs_only,1' . | ||||
|             ",-select${strPerlModule},+inc," . $strBackRestBasePath . | ||||
|             ',-coverage,statement,branch,condition,path,subroutine' . " ${strExe}"; | ||||
|             "perl -MDevel::Cover=-silent,1,-dir,${strCoveragePath},-select${strPerlModule},+inc,${strBackRestBasePath}" . | ||||
|             ",-coverage,statement,branch,condition,path,subroutine ${strExe}"; | ||||
|  | ||||
|         if (defined($bLog) && $bLog) | ||||
|         { | ||||
| @@ -559,7 +525,7 @@ sub backrestExe {return shift->{strBackRestExe}} | ||||
| sub backrestExeOriginal {return shift->{strBackRestExeOriginal}} | ||||
| sub backrestUser {return shift->{strBackRestUser}} | ||||
| sub basePath {return shift->{strBasePath}} | ||||
| sub coverage {return shift->{bCoverage}} | ||||
| sub coverage {vmBaseTest(shift->{strVm}, VM_OS_BASE_DEBIAN)} | ||||
| sub dataPath {return shift->basePath() . '/test/data'} | ||||
| sub doCleanup {return shift->{bCleanup}} | ||||
| sub doExpect {return shift->{bExpect}} | ||||
|   | ||||
| @@ -275,4 +275,29 @@ sub vmGet | ||||
|  | ||||
| push @EXPORT, qw(vmGet); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # vmBaseTest | ||||
| #################################################################################################################################### | ||||
| sub vmBaseTest | ||||
| { | ||||
|     my $strVm = shift; | ||||
|     my $strDistroTest = shift; | ||||
|  | ||||
|     return $oyVm->{$strVm}{&VM_OS_BASE} eq $strDistroTest ? true : false; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(vmBaseTest); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # vmCoverage | ||||
| #################################################################################################################################### | ||||
| sub vmCoverage | ||||
| { | ||||
|     my $strVm = shift; | ||||
|  | ||||
|     return $strVm eq VM_ALL ? false : vmBaseTest($strVm, VM_OS_BASE_DEBIAN); | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(vmCoverage); | ||||
|  | ||||
| 1; | ||||
|   | ||||
							
								
								
									
										181
									
								
								test/test.pl
									
									
									
									
									
								
							
							
						
						
									
										181
									
								
								test/test.pl
									
									
									
									
									
								
							| @@ -17,6 +17,7 @@ $SIG{__DIE__} = sub { Carp::confess @_ }; | ||||
| use File::Basename qw(dirname); | ||||
| use Getopt::Long qw(GetOptions); | ||||
| use Cwd qw(abs_path cwd); | ||||
| use JSON::PP; | ||||
| use Pod::Usage qw(pod2usage); | ||||
| use POSIX qw(ceil strftime); | ||||
| use Time::HiRes qw(gettimeofday); | ||||
| @@ -39,6 +40,7 @@ use BackRestDoc::Custom::DocCustomRelease; | ||||
|  | ||||
| use pgBackRestTest::Common::ContainerTest; | ||||
| use pgBackRestTest::Common::CiTest; | ||||
| use pgBackRestTest::Common::DefineTest; | ||||
| use pgBackRestTest::Common::ExecuteTest; | ||||
| use pgBackRestTest::Common::HostGroupTest; | ||||
| use pgBackRestTest::Common::JobTest; | ||||
| @@ -69,11 +71,11 @@ test.pl [options] | ||||
|    --log-force          force overwrite of current test log files | ||||
|    --no-lint            disable static source code analysis | ||||
|    --build-only         compile the C library / packages and run tests only | ||||
|    --coverage           perform coverage analysis | ||||
|    --coverage-only      only run coverage tests (as a subset of selected tests) | ||||
|    --smart              perform libc/package builds only when source timestamps have changed | ||||
|    --no-package         do not build packages | ||||
|    --no-ci-config       don't overwrite the current continuous integration config | ||||
|    --dev                --no-lint --smart --no-package --vm-out --process-max=1 --retry=0 --ci-no-config | ||||
|    --dev                --no-lint --smart --no-package --vm-out --process-max=1 | ||||
|  | ||||
|  Configuration Options: | ||||
|    --psql-bin           path to the psql executables (e.g. /usr/lib/postgresql/9.3/bin/) | ||||
| @@ -113,13 +115,13 @@ my $bHelp = false; | ||||
| my $bQuiet = false; | ||||
| my $strDbVersion = 'minimal'; | ||||
| my $bLogForce = false; | ||||
| my $strVm = VM_ALL; | ||||
| my $strVm; | ||||
| my $strVmHost = VM_HOST_DEFAULT; | ||||
| my $bVmBuild = false; | ||||
| my $bVmForce = false; | ||||
| my $bNoLint = false; | ||||
| my $bBuildOnly = false; | ||||
| my $bCoverage = false; | ||||
| my $bCoverageOnly = false; | ||||
| my $bSmart = false; | ||||
| my $bNoPackage = false; | ||||
| my $bNoCiConfig = false; | ||||
| @@ -151,7 +153,7 @@ GetOptions ('q|quiet' => \$bQuiet, | ||||
|             'build-only' => \$bBuildOnly, | ||||
|             'no-package' => \$bNoPackage, | ||||
|             'no-ci-config' => \$bNoCiConfig, | ||||
|             'coverage' => \$bCoverage, | ||||
|             'coverage-only' => \$bCoverageOnly, | ||||
|             'smart' => \$bSmart, | ||||
|             'dev' => \$bDev, | ||||
|             'retry=s' => \$iRetry) | ||||
| @@ -190,7 +192,6 @@ eval | ||||
|         $bNoLint = true; | ||||
|         $bSmart = true; | ||||
|         $bNoPackage = true; | ||||
|         $bNoCiConfig = true; | ||||
|         $bVmOut = true; | ||||
|         $iProcessMax = 1; | ||||
|     } | ||||
| @@ -231,18 +232,27 @@ eval | ||||
|         $strTestPath = cwd() . '/test'; | ||||
|     } | ||||
|  | ||||
|     # Coverage can only be run with u16 containers due to version compatibility issues | ||||
|     if ($bCoverage) | ||||
|     if ($bCoverageOnly) | ||||
|     { | ||||
|         if ($strVm eq VM_ALL) | ||||
|         if (!defined($strVm)) | ||||
|         { | ||||
|             &log(INFO, "Set --vm=${strVmHost} for coverage testing"); | ||||
|             $strVm = $strVmHost; | ||||
|         } | ||||
|         elsif ($strVm ne $strVmHost) | ||||
|         elsif ($strVm eq VM_ALL) | ||||
|         { | ||||
|             confess &log(ERROR, "only --vm=${strVmHost} can be used for coverage testing"); | ||||
|             confess &log(ERROR, "select a single Debian-based VM for coverage testing"); | ||||
|         } | ||||
|         elsif (!vmCoverage($strVm)) | ||||
|         { | ||||
|             confess &log(ERROR, "only Debian-based VMs can be used for coverage testing"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # If VM is not defined then set it to all | ||||
|     if (!defined($strVm)) | ||||
|     { | ||||
|         $strVm = VM_ALL; | ||||
|     } | ||||
|  | ||||
|     # Get the base backrest path | ||||
| @@ -572,7 +582,7 @@ eval | ||||
|         # Determine which tests to run | ||||
|         #----------------------------------------------------------------------------------------------------------------------- | ||||
|         my $oyTestRun = testListGet( | ||||
|             $strVm, \@stryModule, \@stryModuleTest, \@iyModuleTestRun, $strDbVersion, $iProcessMax, $bCoverage); | ||||
|             $strVm, \@stryModule, \@stryModuleTest, \@iyModuleTestRun, $strDbVersion, $iProcessMax, $bCoverageOnly); | ||||
|  | ||||
|         if (@{$oyTestRun} == 0) | ||||
|         { | ||||
| @@ -650,8 +660,7 @@ eval | ||||
|                 { | ||||
|                     my $oJob = new pgBackRestTest::Common::JobTest( | ||||
|                         $strBackRestBase, $strTestPath, $strCoveragePath, $$oyTestRun[$iTestIdx], $bDryRun, $bVmOut, $iVmIdx, | ||||
|                         $iVmMax, $iTestIdx, $iTestMax, $strLogLevel, $bLogForce, $bShowOutputAsync, $bCoverage, $bNoCleanup, | ||||
|                         $iRetry); | ||||
|                         $iVmMax, $iTestIdx, $iTestMax, $strLogLevel, $bLogForce, $bShowOutputAsync, $bNoCleanup, $iRetry); | ||||
|                     $iTestIdx++; | ||||
|  | ||||
|                     if ($oJob->run()) | ||||
| @@ -665,18 +674,133 @@ eval | ||||
|         } | ||||
|         while ($iVmTotal > 0); | ||||
|  | ||||
|         # Write out coverage info | ||||
|         # Write out coverage info and test coverage | ||||
|         #----------------------------------------------------------------------------------------------------------------------- | ||||
|         if ($bCoverage) | ||||
|         my $iUncoveredCodeModuleTotal = 0; | ||||
|  | ||||
|         if (vmCoverage($strVm) && !$bDryRun) | ||||
|         { | ||||
|             &log(INFO, 'Writing coverage report'); | ||||
|             &log(INFO, 'writing coverage report'); | ||||
|             executeTest("rm -rf ${strBackRestBase}/test/coverage"); | ||||
|             executeTest("cp -rp ${strCoveragePath} ${strCoveragePath}_temp"); | ||||
|             executeTest("cover -report json -outputdir ${strBackRestBase}/test/coverage ${strCoveragePath}_temp"); | ||||
|             executeTest("rm -rf ${strCoveragePath}_temp"); | ||||
|             executeTest("cp -rp ${strCoveragePath} ${strCoveragePath}_temp"); | ||||
|             executeTest("cover -outputdir ${strBackRestBase}/test/coverage ${strCoveragePath}_temp"); | ||||
|             executeTest("rm -rf ${strCoveragePath}_temp"); | ||||
|             executeTest( | ||||
|                 LIB_COVER_EXE . " -report json -outputdir ${strBackRestBase}/test/coverage ${strCoveragePath}_temp", | ||||
|                 {bSuppressStdErr => true}); | ||||
|             executeTest("sudo rm -rf ${strCoveragePath}_temp"); | ||||
|             executeTest("sudo cp -rp ${strCoveragePath} ${strCoveragePath}_temp"); | ||||
|             executeTest( | ||||
|                 LIB_COVER_EXE . " -outputdir ${strBackRestBase}/test/coverage ${strCoveragePath}_temp", | ||||
|                 {bSuppressStdErr => true}); | ||||
|             executeTest("sudo rm -rf ${strCoveragePath}_temp"); | ||||
|  | ||||
|             # Determine which modules were covered (only check coverage if all tests were successful) | ||||
|             #----------------------------------------------------------------------------------------------------------------------- | ||||
|             if ($iTestFail == 0) | ||||
|             { | ||||
|                 my $hModuleTest;                                        # Everything that was run | ||||
|  | ||||
|                 # Build a hash of all modules, tests, and runs that were executed | ||||
|                 foreach my $hTestRun (@{$oyTestRun}) | ||||
|                 { | ||||
|                     # Get coverage for the module | ||||
|                     my $strModule = $hTestRun->{&TEST_MODULE}; | ||||
|                     my $hModule = testDefModule($strModule); | ||||
|  | ||||
|                     # Get coverage for the test | ||||
|                     my $strTest = $hTestRun->{&TEST_NAME}; | ||||
|                     my $hTest = testDefModuleTest($strModule, $strTest); | ||||
|  | ||||
|                     # If no tests are listed it means all of them were run | ||||
|                     if (@{$hTestRun->{&TEST_RUN}} == 0) | ||||
|                     { | ||||
|                         $hModuleTest->{$strModule}{$strTest} = true; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 # Load the results of coverage testing from JSON | ||||
|                 my $oJSON = JSON::PP->new()->allow_nonref(); | ||||
|                 my $hCoverageResult = $oJSON->decode(fileStringRead("${strBackRestBase}/test/coverage/cover.json")); | ||||
|  | ||||
|                 # Now compare against code modules that should have full coverage | ||||
|                 my $hCoverageList = testDefCoverageList(); | ||||
|                 my $hCoverageType = testDefCoverageType(); | ||||
|                 my $hCoverageActual; | ||||
|  | ||||
|                 foreach my $strCodeModule (sort(keys(%{$hCoverageList}))) | ||||
|                 { | ||||
|                     if (@{$hCoverageList->{$strCodeModule}} > 0) | ||||
|                     { | ||||
|                         my $iCoverageTotal = 0; | ||||
|  | ||||
|                         foreach my $hTest (@{$hCoverageList->{$strCodeModule}}) | ||||
|                         { | ||||
|                             if (!defined($hModuleTest->{$hTest->{strModule}}{$hTest->{strTest}})) | ||||
|                             { | ||||
|                                 next; | ||||
|                             } | ||||
|  | ||||
|                             $iCoverageTotal++; | ||||
|                         } | ||||
|  | ||||
|                         if (@{$hCoverageList->{$strCodeModule}} == $iCoverageTotal) | ||||
|                         { | ||||
|                             $hCoverageActual->{$strCodeModule} = $hCoverageType->{$strCodeModule}; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (keys(%{$hCoverageActual}) > 0) | ||||
|                 { | ||||
|                     &log(INFO, 'test coverage for: ' . join(', ', sort(keys(%{$hCoverageActual})))); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     &log(INFO, 'no code modules had all tests run required for coverage'); | ||||
|                 } | ||||
|  | ||||
|                 foreach my $strCodeModule (sort(keys(%{$hCoverageActual}))) | ||||
|                 { | ||||
|                     # Get summary results (??? Need to fix this for coverage testing on bin/pgbackrest since .pm is required) | ||||
|                     my $hCoverageResultAll = | ||||
|                         $hCoverageResult->{'summary'} | ||||
|                             {"${strBackRestBase}/lib/" . BACKREST_NAME . "/${strCodeModule}.pm"}{total}; | ||||
|  | ||||
|                     if (!defined($hCoverageResultAll)) | ||||
|                     { | ||||
|                         confess &log(ERROR, "unable to find coverage results for ${strCodeModule}"); | ||||
|                     } | ||||
|  | ||||
|                     # Check that all code has been covered | ||||
|                     if ($hCoverageActual->{$strCodeModule} == TESTDEF_COVERAGE_FULL) | ||||
|                     { | ||||
|                         my $iUncoveredLines = | ||||
|                             $hCoverageResultAll->{total} - $hCoverageResultAll->{covered} - $hCoverageResultAll->{uncoverable}; | ||||
|  | ||||
|                         if ($iUncoveredLines != 0) | ||||
|                         { | ||||
|                             &log(ERROR, "code module ${strCodeModule} is not fully covered"); | ||||
|                             $iUncoveredCodeModuleTotal++; | ||||
|                         } | ||||
|                     } | ||||
|                     # Else test how much partial coverage where was | ||||
|                     else | ||||
|                     { | ||||
|                         my $iCoveragePercent = int( | ||||
|                             ($hCoverageResultAll->{covered} + $hCoverageResultAll->{uncoverable}) * 100 / | ||||
|                                 $hCoverageResultAll->{total}); | ||||
|  | ||||
|                         if ($iCoveragePercent == 100) | ||||
|                         { | ||||
|                             &log(ERROR, "code module ${strCodeModule} has 100% coverage but is not marked fully covered"); | ||||
|                             $iUncoveredCodeModuleTotal++; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             &log(INFO, "code module ${strCodeModule} has (expected) partial coverage of ${iCoveragePercent}%"); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         # Print test info and exit | ||||
| @@ -687,12 +811,16 @@ eval | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             &log(INFO, 'TESTS COMPLETED ' . ($iTestFail == 0 ? 'SUCCESSFULLY' : "WITH ${iTestFail} FAILURE(S)") . | ||||
|                        ($iTestRetry == 0 ? '' : ", ${iTestRetry} RETRY(IES)") . | ||||
|                        ' (' . (time() - $lStartTime) . 's)'); | ||||
|             &log(INFO, | ||||
|                 'TESTS COMPLETED ' . ($iTestFail == 0 ? 'SUCCESSFULLY' . | ||||
|                     ($iUncoveredCodeModuleTotal == 0 ? '' : " WITH ${iUncoveredCodeModuleTotal} MODULE(S) MISSING COVERAGE") : | ||||
|                 "WITH ${iTestFail} FAILURE(S)") . ($iTestRetry == 0 ? '' : ", ${iTestRetry} RETRY(IES)") . | ||||
|                     ' (' . (time() - $lStartTime) . 's)'); | ||||
|  | ||||
|             exit 1 if ($iTestFail > 0 || $iUncoveredCodeModuleTotal > 0); | ||||
|         } | ||||
|  | ||||
|         exit $iTestFail == 0 ? 0 : 1; | ||||
|         exit 0; | ||||
|     } | ||||
|  | ||||
|     ################################################################################################################################ | ||||
| @@ -713,7 +841,6 @@ eval | ||||
|         $strDbVersion ne 'minimal' ? $strDbVersion: undef,          # Db version | ||||
|         $stryModule[0], $stryModuleTest[0], \@iyModuleTestRun,      # Module info | ||||
|         $iProcessMax, $bVmOut, $bDryRun, $bNoCleanup, $bLogForce,   # Test options | ||||
|         $bCoverage,                                                 # Test options | ||||
|         TEST_USER, BACKREST_USER, TEST_GROUP);                      # User/group info | ||||
|  | ||||
|     if (!$bNoCleanup) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user