You've already forked pgbackrest
							
							
				mirror of
				https://github.com/pgbackrest/pgbackrest.git
				synced 2025-10-30 23:37:45 +02:00 
			
		
		
		
	Text execution improvements:
1) Tests for all operating systems can now be run with a single command. 2) Tests can be run in parallel with --process-max. 3) Container generation now integrated into test.pl 4) Some basic test documentation.
This commit is contained in:
		| @@ -184,7 +184,6 @@ if (@stryOutput == 0) | ||||
|     if ($oManifest->isBackRest()) | ||||
|     { | ||||
|         push(@stryOutput, 'help'); | ||||
|         push(@stryOutput, 'markdown'); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -203,7 +202,8 @@ for my $strOutput (@stryOutput) | ||||
|         docProcess("${strBasePath}/xml/index.xml", "${strBasePath}/../README.md", $oManifest); | ||||
|         docProcess("${strBasePath}/xml/change-log.xml", "${strBasePath}/../CHANGELOG.md", $oManifest); | ||||
|     } | ||||
|     elsif ($strOutput eq 'markdown') | ||||
|  | ||||
|     if ($strOutput eq 'markdown') | ||||
|     { | ||||
|         my $oMarkdown = | ||||
|             new BackRestDoc::Markdown::DocMarkdown | ||||
|   | ||||
| @@ -198,6 +198,8 @@ sub sectionProcess | ||||
|  | ||||
|     my $strMarkdown = '#' . ('#' x $iDepth) . ' ' . $self->processText($oSection->nodeGet('title')->textGet()); | ||||
|  | ||||
|     my $strLastChild = undef; | ||||
|  | ||||
|     foreach my $oChild ($oSection->nodeList()) | ||||
|     { | ||||
|         &log(DEBUG, ('    ' x ($iDepth + 2)) . 'process child ' . $oChild->nameGet()); | ||||
| @@ -288,14 +290,22 @@ sub sectionProcess | ||||
|         # Add code block | ||||
|         elsif ($oChild->nameGet() eq 'code-block') | ||||
|         { | ||||
|             # $oSectionBodyElement-> | ||||
|             #     addNew(HTML_DIV, 'code-block', | ||||
|             #            {strContent => $oChild->valueGet()}); | ||||
|             if ($oChild->paramTest('title')) | ||||
|             { | ||||
|                 $strMarkdown .= "\n\n_" . $oChild->paramGet('title') . "_:"; | ||||
|             } | ||||
|  | ||||
|             $strMarkdown .= "\n```\n" . trim($oChild->valueGet()) . "\n```"; | ||||
|         } | ||||
|         # Add descriptive text | ||||
|         elsif ($oChild->nameGet() eq 'p') | ||||
|         { | ||||
|             $strMarkdown .= "\n\n" . $self->processText($oChild->textGet()); | ||||
|             if (defined($strLastChild) && $strLastChild ne 'code-block') | ||||
|             { | ||||
|                 $strMarkdown .= "\n"; | ||||
|             } | ||||
|  | ||||
|             $strMarkdown .= "\n" . $self->processText($oChild->textGet()); | ||||
|         } | ||||
|         # Add option descriptive text | ||||
|         elsif ($oChild->nameGet() eq 'option-description') | ||||
| @@ -342,6 +352,8 @@ sub sectionProcess | ||||
|         { | ||||
|             # $self->sectionChildProcess($oSection, $oChild, $iDepth + 1); | ||||
|         } | ||||
|  | ||||
|         $strLastChild = $oChild->nameGet(); | ||||
|     } | ||||
|  | ||||
|     # Return from function and log return values if any | ||||
|   | ||||
| @@ -29,6 +29,7 @@ | ||||
|         <source key="index"/> | ||||
|         <source key="user-guide"/> | ||||
|         <source key="reference" type="custom"/> | ||||
|         <source key="test"/> | ||||
|     </source-list> | ||||
|  | ||||
|     <render-list> | ||||
| @@ -42,5 +43,9 @@ | ||||
|         <render type="pdf" file="{[pdf-file]}"> | ||||
|             <render-source key="user-guide"/> | ||||
|         </render> | ||||
|  | ||||
|         <render type="markdown"> | ||||
|             <render-source key="test" file="../../../test/README.md"/> | ||||
|         </render> | ||||
|     </render-list> | ||||
| </doc> | ||||
|   | ||||
							
								
								
									
										60
									
								
								doc/xml/test.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								doc/xml/test.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE doc SYSTEM "doc.dtd"> | ||||
| <doc subtitle="Regression, Unit, & Integration Testing" toc="y"> | ||||
|  | ||||
|     <section id="introduction"> | ||||
|         <title>Introduction</title> | ||||
|  | ||||
|         <p><backrest/> uses Docker to run tests and generate documentation.  Docker's light-weight virualization provides the a good balance between proper OS emulation and performance (especially startup)</p> | ||||
|  | ||||
|         <p>A `Vagrantfile` is provided that contains the complete configuration required to run <backrest/> tests and build documentation.  If Vagrant is not suitable then the `Vagrantfile` still contains the configuration steps required to build a test system.</p> | ||||
|  | ||||
|         <p>Note that this is not required for normal operation of <backrest/>.</p> | ||||
|     </section> | ||||
|  | ||||
|     <section id="testing"> | ||||
|         <title>Testing</title> | ||||
|  | ||||
|         <p>The easiest way to start testing <backrest/> is with the included `Vagrantfile`.</p> | ||||
|  | ||||
|         <code-block title="Build Vagrant and Logon"> | ||||
| cd test | ||||
| vagrant up | ||||
| vagrant ssh | ||||
|         </code-block> | ||||
|  | ||||
|         <p>The <code>vagrant up</code> step could take some time as a number of Docker containers must also be built.  The <code>vagrant up</code> command automatically logs onto the VM.</p> | ||||
|  | ||||
|         <code-block title="Run All Tests"> | ||||
| /backrest/test/test.pl | ||||
|         </code-block> | ||||
|  | ||||
|         <code-block title="Run Tests for a Specific OS"> | ||||
| /backrest/test/test.pl --vm=co6 | ||||
|         </code-block> | ||||
|  | ||||
|         <code-block title="Run Tests for a Specific OS and Module"> | ||||
| /backrest/test/test.pl --vm=co6 --module=backup | ||||
|         </code-block> | ||||
|  | ||||
|         <code-block title="Run Tests for a Specific OS, Module, and Test"> | ||||
| /backrest/test/test.pl --vm=co6 --module=backup --full | ||||
|         </code-block> | ||||
|  | ||||
|         <code-block title="Run Tests for a Specific OS, Module, Test, and Thread Max"> | ||||
| /backrest/test/test.pl --vm=co6 --module=backup --full --thread-max=4 | ||||
|         </code-block> | ||||
|  | ||||
|         <p>Note that thread-max is only applicable to the <id>synthetic</id> and <id>full</id> tests in the <id>backup</id> module.</p> | ||||
|  | ||||
|         <code-block title="Run Tests for a Specific OS, Module, Test, Thread Max, and Database Version"> | ||||
| /backrest/test/test.pl --vm=co6 --module=backup --full --thread-max=4 --db-version=9.4 | ||||
|         </code-block> | ||||
|  | ||||
|         <p>Note that db-version is only applicable to the <id>full</id> test in the <id>backup</id> module.</p> | ||||
|  | ||||
|         <code-block title="Iterate All Possible Test Combinations"> | ||||
| /backrest/test/test.pl --dry-run | ||||
|         </code-block> | ||||
|     </section> | ||||
| </doc> | ||||
| @@ -425,6 +425,7 @@ sub log | ||||
|     my $strMessage = shift; | ||||
|     my $iCode = shift; | ||||
|     my $bSuppressLog = shift; | ||||
|     my $iIndent = shift; | ||||
|  | ||||
|     # Set defaults | ||||
|     $bSuppressLog = defined($bSuppressLog) ? $bSuppressLog : false; | ||||
| @@ -459,7 +460,15 @@ sub log | ||||
|     $strMessageFormat = (defined($iCode) ? "[${iCode}]: " : '') . $strMessageFormat; | ||||
|  | ||||
|     # Indent subsequent lines of the message if it has more than one line - makes the log more readable | ||||
|     $strMessageFormat =~ s/\n/\n                                    /g; | ||||
|     if (defined($iIndent)) | ||||
|     { | ||||
|         my $strIndent = ' ' x $iIndent; | ||||
|         $strMessageFormat =~ s/\n/\n${strIndent}/g; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         $strMessageFormat =~ s/\n/\n                                    /g; | ||||
|     } | ||||
|  | ||||
|     if ($strLevel eq TRACE || $strLevel eq TEST) | ||||
|     { | ||||
|   | ||||
| @@ -251,7 +251,7 @@ sub lineRead | ||||
|                     $self->waitPid(); | ||||
|  | ||||
|                     # Only error if reading from the input stream | ||||
|                     if (!defined($bInRead) || $bInRead) | ||||
|                     if (defined($bError) && $bError) | ||||
|                     { | ||||
|                         confess &log(ERROR, "unexpected EOF", ERROR_FILE_READ); | ||||
|                     } | ||||
| @@ -297,7 +297,8 @@ sub lineRead | ||||
|     } | ||||
|  | ||||
|     # Return the line that was found and adjust the buffer position | ||||
|     my $strLine = substr($self->{strBuffer}, $self->{iBufferPos}, $iLineFeedPos - $self->{iBufferPos}); | ||||
|     my $strLine = $iLineFeedPos - $self->{iBufferPos} == 0 ? '' : | ||||
|                       substr($self->{strBuffer}, $self->{iBufferPos}, $iLineFeedPos - $self->{iBufferPos}); | ||||
|     $self->{iBufferPos} = $iLineFeedPos + 1; | ||||
|  | ||||
|     return $strLine; | ||||
|   | ||||
							
								
								
									
										58
									
								
								test/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								test/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| # pgBackRest - Regression, Unit, & Integration Testing | ||||
|  | ||||
| ## Introduction | ||||
|  | ||||
| pgBackRest uses Docker to run tests and generate documentation. Docker's light-weight virualization provides the a good balance between proper OS emulation and performance (especially startup) | ||||
|  | ||||
| A `Vagrantfile` is provided that contains the complete configuration required to run pgBackRest tests and build documentation. If Vagrant is not suitable then the `Vagrantfile` still contains the configuration steps required to build a test system. | ||||
|  | ||||
| Note that this is not required for normal operation of pgBackRest. | ||||
|  | ||||
| ## Testing | ||||
|  | ||||
| The easiest way to start testing pgBackRest is with the included `Vagrantfile`. | ||||
|  | ||||
| _Build Vagrant and Logon_: | ||||
| ``` | ||||
| cd test | ||||
| vagrant up | ||||
| vagrant ssh | ||||
| ``` | ||||
| The `vagrant up` step could take some time as a number of Docker containers must also be built. The `vagrant up` command automatically logs onto the VM. | ||||
|  | ||||
| _Run All Tests_: | ||||
| ``` | ||||
| /backrest/test/test.pl | ||||
| ``` | ||||
|  | ||||
| _Run Tests for a Specific OS_: | ||||
| ``` | ||||
| /backrest/test/test.pl --vm=co6 | ||||
| ``` | ||||
|  | ||||
| _Run Tests for a Specific OS and Module_: | ||||
| ``` | ||||
| /backrest/test/test.pl --vm=co6 --module=backup | ||||
| ``` | ||||
|  | ||||
| _Run Tests for a Specific OS, Module, and Test_: | ||||
| ``` | ||||
| /backrest/test/test.pl --vm=co6 --module=backup --full | ||||
| ``` | ||||
|  | ||||
| _Run Tests for a Specific OS, Module, Test, and Thread Max_: | ||||
| ``` | ||||
| /backrest/test/test.pl --vm=co6 --module=backup --full --thread-max=4 | ||||
| ``` | ||||
| Note that thread-max is only applicable to the `synthetic` and `full` tests in the `backup` module. | ||||
|  | ||||
| _Run Tests for a Specific OS, Module, Test, Thread Max, and Database Version_: | ||||
| ``` | ||||
| /backrest/test/test.pl --vm=co6 --module=backup --full --thread-max=4 --db-version=9.4 | ||||
| ``` | ||||
| Note that db-version is only applicable to the `full` test in the `backup` module. | ||||
|  | ||||
| _Iterate All Possible Test Combinations_: | ||||
| ``` | ||||
| /backrest/test/test.pl --dry-run | ||||
| ``` | ||||
							
								
								
									
										4
									
								
								test/Vagrantfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								test/Vagrantfile
									
									
									
									
										vendored
									
									
								
							| @@ -30,8 +30,8 @@ Vagrant.configure(2) do |config| | ||||
|         /usr/local/texlive/2015/bin/x86_64-linux/tlmgr install caption xcolor listings parskip helvetic ltablex titlesec \ | ||||
|             epstopdf courier sectsty pgf ms | ||||
|  | ||||
|         # Build docker images | ||||
|         /backrest/test/container.pl | ||||
|         # Build vm images | ||||
|         /backrest/test/test.pl --vm-build | ||||
|     SHELL | ||||
|  | ||||
|   # Don't share the default vagrant folder | ||||
|   | ||||
| @@ -21,6 +21,7 @@ use Symbol 'gensym'; | ||||
| use lib dirname($0) . '/../lib'; | ||||
| use BackRest::Common::Log; | ||||
| use BackRest::Common::Wait; | ||||
| use BackRest::Protocol::IO; | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Operation constants | ||||
| @@ -121,6 +122,9 @@ sub begin | ||||
|  | ||||
|     $self->{pId} = open3(undef, $self->{hOut}, $self->{hError}, $self->{strCommand}); | ||||
|  | ||||
|     # Create select objects | ||||
|     $self->{oIO} = new BackRest::Protocol::IO($self->{hOut}, undef, $self->{hError}, undef, 30, 65536); | ||||
|  | ||||
|     if (!defined($self->{hError})) | ||||
|     { | ||||
|         confess 'STDERR handle is undefined'; | ||||
| @@ -138,67 +142,67 @@ sub endRetry | ||||
|     my | ||||
|     ( | ||||
|         $strOperation, | ||||
|         $strTest | ||||
|         $strTest, | ||||
|         $bWait | ||||
|     ) = | ||||
|         logDebugParam | ||||
|         ( | ||||
|             OP_EXECUTE_TEST_END_RETRY, \@_, | ||||
|             {name => 'strTest', required => false, trace => true} | ||||
|             {name => 'strTest', required => false, trace => true}, | ||||
|             {name => 'bWait', required => false, default => true, trace => true} | ||||
|         ); | ||||
|  | ||||
|     # Create select objects | ||||
|     my $oErrorSelect = IO::Select->new(); | ||||
|     $oErrorSelect->add($self->{hError}); | ||||
|     my $oOutSelect = IO::Select->new(); | ||||
|     $oOutSelect->add($self->{hOut}); | ||||
|  | ||||
|     # Drain the output and error streams and look for test points | ||||
|     # my $iWait = $bWait ? .05 : 0; | ||||
|  | ||||
|     while(waitpid($self->{pId}, WNOHANG) == 0) | ||||
|     { | ||||
|         # Drain the stderr stream | ||||
|         if ($oErrorSelect->can_read(0)) | ||||
|         my $bFound = false; | ||||
|         # # Drain the stderr stream | ||||
|         # !!! This is a good idea but can only be done with the IO object has separate buffers for stdin and stderr | ||||
|         # while (my $strLine = $self->{oIO}->lineRead(0, false, false)) | ||||
|         # { | ||||
|         #     $bFound = true; | ||||
|         #     $self->{strErrorLog} .= "$strLine\n"; | ||||
|         # } | ||||
|  | ||||
|         # Drain the stdout stream and look for test points | ||||
|         while (defined(my $strLine = $self->{oIO}->lineRead(0, true, false))) | ||||
|         { | ||||
|             while (my $strLine = readline($self->{hError})) | ||||
|             $self->{strOutLog} .= "$strLine\n"; | ||||
|             $bFound = true; | ||||
|  | ||||
|             if (defined($strTest) && testCheck($strLine, $strTest)) | ||||
|             { | ||||
|                 $self->{strErrorLog} .= $strLine; | ||||
|                 &log(DEBUG, "Found test ${strTest}"); | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         # Drain the stdout stream and look for test points | ||||
|         if ($oOutSelect->can_read(.05)) | ||||
|         if (!$bWait) | ||||
|         { | ||||
|             while (my $strLine = readline($self->{hOut})) | ||||
|             { | ||||
|                 $self->{strOutLog} .= $strLine; | ||||
|             return undef; | ||||
|         } | ||||
|  | ||||
|                 if (defined($strTest) && testCheck($strLine, $strTest)) | ||||
|                 { | ||||
|                     &log(DEBUG, "Found test ${strTest}"); | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|         if (!$bFound) | ||||
|         { | ||||
|             waitHiRes(.05); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # Check the exit status | ||||
|     my $iExitStatus = ${^CHILD_ERROR_NATIVE} >> 8; | ||||
|  | ||||
|     # Drain the stderr stream | ||||
|     if ($oErrorSelect->can_read(0)) | ||||
|     # Drain the stdout stream | ||||
|     while (defined(my $strLine = $self->{oIO}->lineRead(0, true, false))) | ||||
|     { | ||||
|         while (my $strLine = readline($self->{hError})) | ||||
|         { | ||||
|             $self->{strErrorLog} .= $strLine; | ||||
|         } | ||||
|         $self->{strOutLog} .= "$strLine\n"; | ||||
|     } | ||||
|  | ||||
|     # Drain the stdout stream | ||||
|     if ($oOutSelect->can_read(0)) | ||||
|     # Drain the stderr stream | ||||
|     while (defined(my $strLine = $self->{oIO}->lineRead(0, false, false))) | ||||
|     { | ||||
|         while (my $strLine = readline($self->{hOut})) | ||||
|         { | ||||
|             $self->{strOutLog} .= $strLine; | ||||
|         } | ||||
|         $self->{strErrorLog} .= "$strLine\n"; | ||||
|     } | ||||
|  | ||||
|     # Pass the log to the LogTest object | ||||
| @@ -278,12 +282,14 @@ sub end | ||||
|     my | ||||
|     ( | ||||
|         $strOperation, | ||||
|         $strTest | ||||
|         $strTest, | ||||
|         $bWait | ||||
|     ) = | ||||
|         logDebugParam | ||||
|         ( | ||||
|             OP_EXECUTE_TEST_END, \@_, | ||||
|             {name => 'strTest', required => false} | ||||
|             {name => 'strTest', required => false, trace => true}, | ||||
|             {name => 'bWait', required => false, default => true, trace => true} | ||||
|         ); | ||||
|  | ||||
|     # If retry is not defined then run endRetry() one time | ||||
| @@ -291,7 +297,7 @@ sub end | ||||
|  | ||||
|     if (!defined($self->{iRetrySeconds})) | ||||
|     { | ||||
|         $iExitStatus = $self->endRetry($strTest); | ||||
|         $iExitStatus = $self->endRetry($strTest, $bWait); | ||||
|     } | ||||
|     # Else loop until success or timeout | ||||
|     else | ||||
| @@ -302,7 +308,7 @@ sub end | ||||
|         { | ||||
|             $self->{bRetry} = false; | ||||
|             $self->begin(); | ||||
|             $iExitStatus = $self->endRetry($strTest); | ||||
|             $iExitStatus = $self->endRetry($strTest, $bWait); | ||||
|  | ||||
|             if ($self->{bRetry}) | ||||
|             { | ||||
| @@ -314,7 +320,7 @@ sub end | ||||
|         if ($self->{bRetry}) | ||||
|         { | ||||
|             $self->begin(); | ||||
|             $iExitStatus = $self->endRetry($strTest); | ||||
|             $iExitStatus = $self->endRetry($strTest, $bWait); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -258,10 +258,13 @@ sub BackRestTestConfig_Test | ||||
|     #------------------------------------------------------------------------------------------------------------------------------- | ||||
|     # Test command-line options | ||||
|     #------------------------------------------------------------------------------------------------------------------------------- | ||||
|     if ($strTest eq 'all' || $strTest eq 'option') | ||||
|     my $strThisTest = 'option'; | ||||
|  | ||||
|     if ($strTest eq 'all' || $strTest eq $strThisTest) | ||||
|     { | ||||
|         $iRun = 0; | ||||
|         &log(INFO, "Option module\n"); | ||||
|  | ||||
|         &log(INFO, "Test ${strThisTest}\n"); | ||||
|  | ||||
|         if (BackRestTestCommon_Run(++$iRun, 'backup with no stanza')) | ||||
|         { | ||||
| @@ -543,10 +546,13 @@ sub BackRestTestConfig_Test | ||||
|     #------------------------------------------------------------------------------------------------------------------------------- | ||||
|     # Test mixed command-line/config | ||||
|     #------------------------------------------------------------------------------------------------------------------------------- | ||||
|     if ($strTest eq 'all' || $strTest eq 'config') | ||||
|     $strThisTest = 'config'; | ||||
|  | ||||
|     if ($strTest eq 'all' || $strTest eq $strThisTest) | ||||
|     { | ||||
|         $iRun = 0; | ||||
|         &log(INFO, "Config module\n"); | ||||
|  | ||||
|         &log(INFO, "Test ${strThisTest}\n"); | ||||
|  | ||||
|         BackRestTestCommon_Create(); | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #!/usr/bin/perl | ||||
| #################################################################################################################################### | ||||
| # container.pl - Build docker containers for testing and documentation | ||||
| # Container.pm - Build docker containers for testing and documentation | ||||
| #################################################################################################################################### | ||||
| package BackRestTest::Docker::Container; | ||||
| 
 | ||||
| #################################################################################################################################### | ||||
| # Perl includes | ||||
| @@ -10,112 +10,18 @@ use strict; | ||||
| use warnings FATAL => qw(all); | ||||
| use Carp qw(confess longmess); | ||||
| 
 | ||||
| # Convert die to confess to capture the stack trace | ||||
| $SIG{__DIE__} = sub { Carp::confess @_ }; | ||||
| 
 | ||||
| use Cwd qw(abs_path); | ||||
| use Exporter qw(import); | ||||
|     our @EXPORT = qw(); | ||||
| use File::Basename qw(dirname); | ||||
| use Getopt::Long qw(GetOptions); | ||||
| use Scalar::Util qw(blessed); | ||||
| # use Cwd qw(abs_path); | ||||
| # use Pod::Usage qw(pod2usage); | ||||
| # use Scalar::Util qw(blessed); | ||||
| 
 | ||||
| use lib dirname($0) . '/../lib'; | ||||
| use BackRest::Common::Ini; | ||||
| # use BackRest::Common::Ini; | ||||
| use BackRest::Common::Log; | ||||
| use BackRest::FileCommon; | ||||
| # use BackRest::Db; | ||||
| 
 | ||||
| use lib dirname($0) . '/lib'; | ||||
| use BackRestTest::Common::ExecuteTest; | ||||
| # use BackRestTest::CommonTest; | ||||
| # use BackRestTest::CompareTest; | ||||
| # use BackRestTest::ConfigTest; | ||||
| # use BackRestTest::FileTest; | ||||
| # use BackRestTest::HelpTest; | ||||
| 
 | ||||
| #################################################################################################################################### | ||||
| # Usage | ||||
| #################################################################################################################################### | ||||
| 
 | ||||
| =head1 NAME | ||||
| 
 | ||||
| container.pl - Docker Container Build | ||||
| 
 | ||||
| =head1 SYNOPSIS | ||||
| 
 | ||||
| container.pl [options] | ||||
| 
 | ||||
|  Build Options: | ||||
|    --os                 os to build (defaults to all) | ||||
| 
 | ||||
|  Configuration Options: | ||||
|    --log-level          log level to use for tests (defaults to info) | ||||
|    --quiet, -q          equivalent to --log-level=off | ||||
| 
 | ||||
|  General Options: | ||||
|    --version            display version and exit | ||||
|    --help               display usage and exit | ||||
| =cut | ||||
| 
 | ||||
| #################################################################################################################################### | ||||
| # Command line parameters | ||||
| #################################################################################################################################### | ||||
| my $strLogLevel = 'info'; | ||||
| my $bVersion = false; | ||||
| my $bHelp = false; | ||||
| my $bQuiet = false; | ||||
| 
 | ||||
| GetOptions ('q|quiet' => \$bQuiet, | ||||
|             'version' => \$bVersion, | ||||
|             'help' => \$bHelp, | ||||
|             'log-level=s' => \$strLogLevel) | ||||
|     or pod2usage(2); | ||||
| 
 | ||||
| # Display version and exit if requested | ||||
| if ($bVersion || $bHelp) | ||||
| { | ||||
|     syswrite(*STDOUT, 'pgBackRest ' . BACKREST_VERSION . " Docker Container Build\n"); | ||||
| 
 | ||||
|     if ($bHelp) | ||||
|     { | ||||
|         syswrite(*STDOUT, "\n"); | ||||
|         pod2usage(); | ||||
|     } | ||||
| 
 | ||||
|     exit 0; | ||||
| } | ||||
| 
 | ||||
| if (@ARGV > 0) | ||||
| { | ||||
|     syswrite(*STDOUT, "invalid parameter\n\n"); | ||||
|     pod2usage(); | ||||
| } | ||||
| 
 | ||||
| #################################################################################################################################### | ||||
| # Setup | ||||
| #################################################################################################################################### | ||||
| # Set a neutral umask so tests work as expected | ||||
| umask(0); | ||||
| 
 | ||||
| # Set console log level | ||||
| if ($bQuiet) | ||||
| { | ||||
|     $strLogLevel = 'off'; | ||||
| } | ||||
| 
 | ||||
| logLevelSet(undef, uc($strLogLevel)); | ||||
| 
 | ||||
| # Create temp path | ||||
| my $strTempPath = dirname(abs_path($0)) . '/.vagrant/docker'; | ||||
| 
 | ||||
| if (!-e $strTempPath) | ||||
| { | ||||
|     mkdir $strTempPath | ||||
|         or confess &log(ERROR, "unable to create ${strTempPath}"); | ||||
| } | ||||
| 
 | ||||
| #################################################################################################################################### | ||||
| # Valid OS list | ||||
| @@ -285,8 +191,17 @@ sub perlInstall | ||||
| #################################################################################################################################### | ||||
| # Build containers | ||||
| #################################################################################################################################### | ||||
| eval | ||||
| sub containerBuild | ||||
| { | ||||
|     # Create temp path | ||||
|     my $strTempPath = dirname(abs_path($0)) . '/.vagrant/docker'; | ||||
| 
 | ||||
|     if (!-e $strTempPath) | ||||
|     { | ||||
|         mkdir $strTempPath | ||||
|             or confess &log(ERROR, "unable to create ${strTempPath}"); | ||||
|     } | ||||
| 
 | ||||
|     # Create SSH key (if it does not already exist) | ||||
|     if (-e "${strTempPath}/id_rsa") | ||||
|     { | ||||
| @@ -296,7 +211,7 @@ eval | ||||
|     { | ||||
|         &log(INFO, "Building SSH keys..."); | ||||
| 
 | ||||
|         executeTest("ssh-keygen -f ${strTempPath}/id_rsa -t rsa -b 768 -N ''"); | ||||
|         executeTest("ssh-keygen -f ${strTempPath}/id_rsa -t rsa -b 768 -N ''", {bSuppressStdErr => true}); | ||||
|     } | ||||
| 
 | ||||
|     foreach my $strOS (@stryOS) | ||||
| @@ -337,7 +252,9 @@ eval | ||||
|         } | ||||
|         elsif ($strOS eq OS_U12 || $strOS eq OS_U14) | ||||
|         { | ||||
|             $strImage .= "RUN apt-get -y install openssh-server\n"; | ||||
|             $strImage .= | ||||
|                 "RUN apt-get update\n" . | ||||
|                 "RUN apt-get -y install openssh-server\n"; | ||||
|         } | ||||
| 
 | ||||
|         $strImage .= | ||||
| @@ -441,7 +358,8 @@ eval | ||||
| 
 | ||||
|         # Write the image | ||||
|         fileStringWrite("${strTempPath}/${strImageName}", "$strImage\n", false); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}"); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}", | ||||
|                     {bSuppressStdErr => true}); | ||||
| 
 | ||||
|         # Db image | ||||
|         ########################################################################################################################### | ||||
| @@ -512,7 +430,9 @@ eval | ||||
| 
 | ||||
|         # Write the image | ||||
|         fileStringWrite("${strTempPath}/${strImageName}", "${strImage}\n", false); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}"); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}", | ||||
|                     {bSuppressStdErr => true}); | ||||
| 
 | ||||
| 
 | ||||
|         # Db Doc image | ||||
|         ########################################################################################################################### | ||||
| @@ -527,7 +447,9 @@ eval | ||||
| 
 | ||||
|         # Write the image | ||||
|         fileStringWrite("${strTempPath}/${strImageName}", "${strImage}\n", false); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}"); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}", | ||||
|                     {bSuppressStdErr => true}); | ||||
| 
 | ||||
| 
 | ||||
|         # Backup image | ||||
|         ########################################################################################################################### | ||||
| @@ -545,7 +467,9 @@ eval | ||||
| 
 | ||||
|         # Write the image | ||||
|         fileStringWrite("${strTempPath}/${strImageName}", "${strImage}\n", false); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}"); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}", | ||||
|                     {bSuppressStdErr => true}); | ||||
| 
 | ||||
| 
 | ||||
|         # Backup Doc image | ||||
|         ########################################################################################################################### | ||||
| @@ -568,7 +492,9 @@ eval | ||||
| 
 | ||||
|         # Write the image | ||||
|         fileStringWrite("${strTempPath}/${strImageName}", "${strImage}\n", false); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}"); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}", | ||||
|                     {bSuppressStdErr => true}); | ||||
| 
 | ||||
| 
 | ||||
|         # Test image | ||||
|         ########################################################################################################################### | ||||
| @@ -605,21 +531,12 @@ eval | ||||
| 
 | ||||
|         # Write the image | ||||
|         fileStringWrite("${strTempPath}/${strImageName}", "${strImage}\n", false); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}"); | ||||
|         executeTest("docker build -f ${strTempPath}/${strImageName} -t backrest/${strImageName} ${strTempPath}", | ||||
|                     {bSuppressStdErr => true}); | ||||
| 
 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| if ($@) | ||||
| { | ||||
|     my $oMessage = $@; | ||||
| 
 | ||||
|     # If a backrest exception then return the code - don't confess | ||||
|     if (blessed($oMessage) && $oMessage->isa('BackRest::Common::Exception')) | ||||
|     { | ||||
|         syswrite(*STDOUT, $oMessage->trace()); | ||||
|         exit $oMessage->code(); | ||||
|     } | ||||
| 
 | ||||
|     syswrite(*STDOUT, $oMessage); | ||||
|     exit 255;; | ||||
| } | ||||
| 
 | ||||
| push @EXPORT, qw(containerBuild); | ||||
| 
 | ||||
| 1; | ||||
							
								
								
									
										510
									
								
								test/test.pl
									
									
									
									
									
								
							
							
						
						
									
										510
									
								
								test/test.pl
									
									
									
									
									
								
							| @@ -17,11 +17,15 @@ use File::Basename qw(dirname); | ||||
| use Getopt::Long qw(GetOptions); | ||||
| use Cwd qw(abs_path); | ||||
| use Pod::Usage qw(pod2usage); | ||||
| use POSIX qw(ceil); | ||||
| use Time::HiRes qw(gettimeofday); | ||||
| use Scalar::Util qw(blessed); | ||||
|  | ||||
| use lib dirname($0) . '/../lib'; | ||||
| use BackRest::Common::Ini; | ||||
| use BackRest::Common::Log; | ||||
| use BackRest::Common::String; | ||||
| use BackRest::Common::Wait; | ||||
| use BackRest::Db; | ||||
|  | ||||
| use lib dirname($0) . '/lib'; | ||||
| @@ -30,9 +34,9 @@ use BackRestTest::Common::ExecuteTest; | ||||
| use BackRestTest::CommonTest; | ||||
| use BackRestTest::CompareTest; | ||||
| use BackRestTest::ConfigTest; | ||||
| use BackRestTest::Docker::Container; | ||||
| use BackRestTest::FileTest; | ||||
| use BackRestTest::HelpTest; | ||||
| # use BackRestTest::IniTest; | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Usage | ||||
| @@ -47,7 +51,7 @@ test.pl - pgBackRest Unit Tests | ||||
| test.pl [options] | ||||
|  | ||||
|  Test Options: | ||||
|    --module             test module to execute: | ||||
|    --module             test module to execute | ||||
|    --test               execute the specified test in a module | ||||
|    --run                execute only the specified test run | ||||
|    --thread-max         max threads to run for backup/restore (default 4) | ||||
| @@ -58,12 +62,18 @@ test.pl [options] | ||||
|    --log-force          force overwrite of current test log files | ||||
|  | ||||
|  Configuration Options: | ||||
|    --exe                backup executable | ||||
|    --exe                pgBackRest executable | ||||
|    --psql-bin           path to the psql executables (e.g. /usr/lib/postgresql/9.3/bin/) | ||||
|    --test-path          path where tests are executed (defaults to ./test) | ||||
|    --log-level          log level to use for tests (defaults to INFO) | ||||
|    --quiet, -q          equivalent to --log-level=off | ||||
|  | ||||
|  VM Options: | ||||
|    --vm-build           build Docker containers | ||||
|    --vm                 execute in a docker container (u12, u14, co6, co7) | ||||
|    --vm-out             Show VM output (default false) | ||||
|    --process-max        max VMs to run in parallel (default 1) | ||||
|  | ||||
|  General Options: | ||||
|    --version            display version and exit | ||||
|    --help               display usage and exit | ||||
| @@ -73,11 +83,13 @@ test.pl [options] | ||||
| # Command line parameters | ||||
| #################################################################################################################################### | ||||
| my $strLogLevel = 'info'; | ||||
| my $strOS = undef; | ||||
| my $strOS = 'all'; | ||||
| my $bVmOut = false; | ||||
| my $strModule = 'all'; | ||||
| my $strModuleTest = 'all'; | ||||
| my $iModuleTestRun = undef; | ||||
| my $iThreadMax = undef; | ||||
| my $iProcessMax = 1; | ||||
| my $bDryRun = false; | ||||
| my $bNoCleanup = false; | ||||
| my $strPgSqlBin; | ||||
| @@ -89,6 +101,7 @@ my $bQuiet = false; | ||||
| my $bInfinite = false; | ||||
| my $strDbVersion = 'all'; | ||||
| my $bLogForce = false; | ||||
| my $bVmBuild = false; | ||||
|  | ||||
| my $strCommandLine = join(' ', @ARGV); | ||||
|  | ||||
| @@ -99,11 +112,14 @@ GetOptions ('q|quiet' => \$bQuiet, | ||||
|             'exes=s' => \$strExe, | ||||
|             'test-path=s' => \$strTestPath, | ||||
|             'log-level=s' => \$strLogLevel, | ||||
|             'os=s' => \$strOS, | ||||
|             'vm=s' => \$strOS, | ||||
|             'vm-out' => \$bVmOut, | ||||
|             'vm-build' => \$bVmBuild, | ||||
|             'module=s' => \$strModule, | ||||
|             'test=s' => \$strModuleTest, | ||||
|             'run=s' => \$iModuleTestRun, | ||||
|             'thread-max=s' => \$iThreadMax, | ||||
|             'process-max=s' => \$iProcessMax, | ||||
|             'dry-run' => \$bDryRun, | ||||
|             'no-cleanup' => \$bNoCleanup, | ||||
|             'infinite' => \$bInfinite, | ||||
| @@ -131,27 +147,6 @@ if (@ARGV > 0) | ||||
|     pod2usage(); | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Start OS VM and run | ||||
| #################################################################################################################################### | ||||
| if (defined($strOS)) | ||||
| { | ||||
|     executeTest("docker rm -f ${strOS}-test", {bSuppressError => true}); | ||||
|     executeTest("docker run -itd -h ${strOS}-test --name=${strOS}-test -v /backrest:/backrest backrest/${strOS}-test"); | ||||
|  | ||||
|     $strCommandLine =~ s/\-\-os\=\S*//g; | ||||
|     $strCommandLine =~ s/\-\-test-path\=\S*//g; | ||||
|  | ||||
|     system("docker exec -it -u vagrant ${strOS}-test $0 ${strCommandLine} --test-path=/home/vagrant/test"); | ||||
|  | ||||
|     if (!$bNoCleanup) | ||||
|     { | ||||
|         executeTest("docker rm -f ${strOS}-test"); | ||||
|     } | ||||
|  | ||||
|     exit 0; | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Setup | ||||
| #################################################################################################################################### | ||||
| @@ -181,55 +176,21 @@ if (defined($iModuleTestRun) && $strModuleTest eq 'all') | ||||
|     confess "--test must be provided for --run=\"${iModuleTestRun}\""; | ||||
| } | ||||
|  | ||||
| # Search for psql bin | ||||
| my @stryTestVersion; | ||||
| my @stryVersionSupport = versionSupport(); | ||||
|  | ||||
| if (!defined($strPgSqlBin)) | ||||
| { | ||||
|     # Distribution-specific paths where the PostgreSQL binaries may be located | ||||
|     my @strySearchPath = | ||||
|     ( | ||||
|         '/usr/lib/postgresql/VERSION/bin',  # Debian/Ubuntu | ||||
|         '/usr/pgsql-VERSION/bin',           # CentOS/RHEL/Fedora | ||||
|         '/Library/PostgreSQL/VERSION/bin',  # OSX | ||||
|         '/usr/local/bin'                    # BSD | ||||
|     ); | ||||
|  | ||||
|     foreach my $strSearchPath (@strySearchPath) | ||||
|     { | ||||
|         for (my $iVersionIdx = @stryVersionSupport - 1; $iVersionIdx >= 0; $iVersionIdx--) | ||||
|         { | ||||
|             if ($strDbVersion eq 'all' || $strDbVersion eq 'max' && @stryTestVersion == 0 || | ||||
|                 $strDbVersion eq $stryVersionSupport[$iVersionIdx]) | ||||
|             { | ||||
|                 my $strVersionPath = $strSearchPath; | ||||
|                 $strVersionPath =~ s/VERSION/$stryVersionSupport[$iVersionIdx]/g; | ||||
|  | ||||
|                 if (-e "${strVersionPath}/initdb") | ||||
|                 { | ||||
|                     &log(INFO, "FOUND pgsql-bin at ${strVersionPath}"); | ||||
|                     push @stryTestVersion, $strVersionPath; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # Make sure at least one version of postgres was found | ||||
|     @stryTestVersion > 0 | ||||
|         or confess 'pgsql-bin was not defined and postgres could not be located automatically'; | ||||
| } | ||||
| else | ||||
| { | ||||
|     push @stryTestVersion, $strPgSqlBin; | ||||
| } | ||||
|  | ||||
| # Check thread total | ||||
| if (defined($iThreadMax) && ($iThreadMax < 1 || $iThreadMax > 32)) | ||||
| { | ||||
|     confess 'thread-max must be between 1 and 32'; | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Build Docker containers | ||||
| #################################################################################################################################### | ||||
| if ($bVmBuild) | ||||
| { | ||||
|     containerBuild(); | ||||
|     exit 0; | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Make sure version number matches in the change log. | ||||
| #################################################################################################################################### | ||||
| @@ -257,28 +218,396 @@ if (!$bMatch) | ||||
|     confess 'unable to find version ' . BACKREST_VERSION . " as last revision in ${strChangeLogFile}"; | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Clean whitespace only if test.pl is being run from the test directory in the backrest repo | ||||
| #################################################################################################################################### | ||||
| if (-e './test.pl' && -e '../bin/pg_backrest') | ||||
| { | ||||
|     BackRestTestCommon_Execute( | ||||
|         "find .. -type f -not -path \"../.git/*\" -not -path \"*.DS_Store\" -not -path \"../test/test/*\" " . | ||||
|         "-not -path \"../test/data/*\" " . | ||||
|         "-exec sh -c 'for i;do echo \"\$i\" && sed 's/[[:space:]]*\$//' \"\$i\">/tmp/.\$\$ && cat /tmp/.\$\$ " . | ||||
|         "> \"\$i\";done' arg0 {} + > /dev/null", false, true); | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Runs tests | ||||
| #################################################################################################################################### | ||||
| # &log(INFO, "Testing with test_path = " . BackRestTestCommon_TestPathGet() . ", host = {strHost}, user = {strUser}, " . | ||||
| #            "group = {strGroup}"); | ||||
|  | ||||
| my $iRun = 0; | ||||
|  | ||||
| eval | ||||
| { | ||||
|     ################################################################################################################################ | ||||
|     # Define tests | ||||
|     ################################################################################################################################ | ||||
|     my $oTestDefinition = | ||||
|     { | ||||
|         module => | ||||
|         [ | ||||
|             # Help tests | ||||
|             { | ||||
|                 name => 'help', | ||||
|                 test => | ||||
|                 [ | ||||
|                     { | ||||
|                         name => 'help' | ||||
|                     } | ||||
|                 ] | ||||
|             }, | ||||
|             # Config tests | ||||
|             { | ||||
|                 name => 'config', | ||||
|                 test => | ||||
|                 [ | ||||
|                     { | ||||
|                         name => 'option' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'config' | ||||
|                     } | ||||
|                 ] | ||||
|             }, | ||||
|             # File tests | ||||
|             { | ||||
|                 name => 'file', | ||||
|                 test => | ||||
|                 [ | ||||
|                     { | ||||
|                         name => 'path_create' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'move' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'compress' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'wait' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'manifest' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'list' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'remove' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'hash' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'exists' | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'copy' | ||||
|                     } | ||||
|                 ] | ||||
|             }, | ||||
|             # Backup tests | ||||
|             { | ||||
|                 name => 'backup', | ||||
|                 test => | ||||
|                 [ | ||||
|                     { | ||||
|                         name => 'archive-push', | ||||
|                         total => 8 | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'archive-stop', | ||||
|                         total => 6 | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'archive-get', | ||||
|                         total => 8 | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'expire', | ||||
|                         total => 1 | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'synthetic', | ||||
|                         total => 8, | ||||
|                         thread => true | ||||
|                     }, | ||||
|                     { | ||||
|                         name => 'full', | ||||
|                         total => 8, | ||||
|                         thread => true | ||||
|                     } | ||||
|                 ] | ||||
|             } | ||||
|         ] | ||||
|     }; | ||||
|  | ||||
|     my $oyTestRun = []; | ||||
|  | ||||
|     ################################################################################################################################ | ||||
|     # Start VM and run | ||||
|     ################################################################################################################################ | ||||
|     if ($strOS ne 'none') | ||||
|     { | ||||
|         # Determine which tests to run | ||||
|         my $iTestsToRun = 0; | ||||
|  | ||||
|         foreach my $oModule (@{$$oTestDefinition{module}}) | ||||
|         { | ||||
|             if ($strModule eq $$oModule{name} || $strModule eq 'all') | ||||
|             { | ||||
|                 &log(DEBUG, "Select Module $$oModule{name}"); | ||||
|  | ||||
|                 foreach my $oTest (@{$$oModule{test}}) | ||||
|                 { | ||||
|                     if ($strModuleTest eq $$oTest{name} || $strModuleTest eq 'all') | ||||
|                     { | ||||
|                         &log(DEBUG, "    Select Test $$oTest{name}"); | ||||
|  | ||||
|                         my $iTestRunMin = defined($iModuleTestRun) ? $iModuleTestRun : (defined($$oTest{total}) ? 1 : -1); | ||||
|                         my $iTestRunMax = defined($iModuleTestRun) ? $iModuleTestRun : (defined($$oTest{total}) ? $$oTest{total} : -1); | ||||
|  | ||||
|                         if (defined($$oTest{total}) && $iTestRunMax > $$oTest{total}) | ||||
|                         { | ||||
|                             confess &log(ERROR, "invalid run - must be >= 1 and <= $$oTest{total}") | ||||
|                         } | ||||
|  | ||||
|                         for (my $iTestRunIdx = $iTestRunMin; $iTestRunIdx <= $iTestRunMax; $iTestRunIdx++) | ||||
|                         { | ||||
|                             &log(DEBUG, "        Select Run $iTestRunIdx"); | ||||
|  | ||||
|                             my $stryTestOS = []; | ||||
|  | ||||
|                             if ($strOS eq 'all') | ||||
|                             { | ||||
|                                 $stryTestOS = ['u12', 'u14', 'co6', 'co7']; | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 $stryTestOS = [$strOS]; | ||||
|                             } | ||||
|  | ||||
|                             my $iyThreadMax = [defined($iThreadMax) ? $iThreadMax : 1]; | ||||
|  | ||||
|                             if (defined($$oTest{thread}) && $$oTest{thread} && !defined($iThreadMax)) | ||||
|                             { | ||||
|                                 $iyThreadMax = [1, 4]; | ||||
|                             } | ||||
|  | ||||
|                             foreach my $iThreadTestMax (@{$iyThreadMax}) | ||||
|                             { | ||||
|                                 foreach my $strTestOS (@{$stryTestOS}) | ||||
|                                 { | ||||
|                                     my $oTestRun = | ||||
|                                     { | ||||
|                                         os => $strTestOS, | ||||
|                                         module => $$oModule{name}, | ||||
|                                         test => $$oTest{name}, | ||||
|                                         run => $iTestRunIdx == -1 ? undef : $iTestRunIdx, | ||||
|                                         thread => $iThreadTestMax | ||||
|                                     }; | ||||
|  | ||||
|                                     push(@{$oyTestRun}, $oTestRun); | ||||
|                                     $iTestsToRun++; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if ($iTestsToRun == 0) | ||||
|         { | ||||
|             confess &log(ERROR, 'no tests were selected'); | ||||
|         } | ||||
|  | ||||
|         my $iTestFail = 0; | ||||
|         my $oyProcess = []; | ||||
|  | ||||
|         if (!$bDryRun) | ||||
|         { | ||||
|             for (my $iProcessIdx = 0; $iProcessIdx < 8; $iProcessIdx++) | ||||
|             { | ||||
|                 # &log(INFO, "stop test-${iProcessIdx}"); | ||||
|                 push(@{$oyProcess}, undef); | ||||
|                 executeTest("docker rm -f test-${iProcessIdx}", {bSuppressError => true}); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         my $iTestIdx = 0; | ||||
|         my $iProcessTotal; | ||||
|         my $iTestMax = @{$oyTestRun}; | ||||
|         my $lStartTime = time(); | ||||
|  | ||||
|         # foreach my $oTest (@{$oyTestRun}) | ||||
|         do | ||||
|         { | ||||
|             do | ||||
|             { | ||||
|                 $iProcessTotal = 0; | ||||
|  | ||||
|                 for (my $iProcessIdx = 0; $iProcessIdx < $iProcessMax; $iProcessIdx++) | ||||
|                 { | ||||
|                     if (defined($$oyProcess[$iProcessIdx])) | ||||
|                     { | ||||
|                         my $oExecDone = $$oyProcess[$iProcessIdx]{exec}; | ||||
|                         my $strTestDone = $$oyProcess[$iProcessIdx]{test}; | ||||
|                         my $iTestDoneIdx = $$oyProcess[$iProcessIdx]{idx}; | ||||
|  | ||||
|                         my $iExitStatus = $oExecDone->end(undef, $iProcessMax == 1); | ||||
|  | ||||
|                         if (defined($iExitStatus)) | ||||
|                         { | ||||
|                             my $fTestElapsedTime = ceil((gettimeofday() - $$oyProcess[$iProcessIdx]{start_time}) * 100) / 100; | ||||
|  | ||||
|                             if (!($iExitStatus == 0 || $iExitStatus == 255)) | ||||
|                             { | ||||
|                                 &log(ERROR, "${strTestDone} (err${iExitStatus}-${fTestElapsedTime}s)" . | ||||
|                                      (defined($oExecDone->{strOutLog}) ? ":\n\n" . trim($oExecDone->{strOutLog}) . "\n" : ''), | ||||
|                                      undef, undef, 4); | ||||
|                                 $iTestFail++; | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 &log( INFO, "${strTestDone} (${fTestElapsedTime}s)". | ||||
|                                             ($bVmOut ? ":\n\n" . trim($oExecDone->{strOutLog}) . "\n" : ''), undef, undef, 4); | ||||
|                             } | ||||
|  | ||||
|                             if (!$bNoCleanup) | ||||
|                             { | ||||
|                                 executeTest("docker rm -f test-${iProcessIdx}"); | ||||
|                             } | ||||
|  | ||||
|                             $$oyProcess[$iProcessIdx] = undef; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             $iProcessTotal++; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if ($iProcessTotal == $iProcessMax) | ||||
|                 { | ||||
|                     waitHiRes(.1); | ||||
|                 } | ||||
|             } | ||||
|             while ($iProcessTotal == $iProcessMax); | ||||
|  | ||||
|             for (my $iProcessIdx = 0; $iProcessIdx < $iProcessMax; $iProcessIdx++) | ||||
|             { | ||||
|                 if (!defined($$oyProcess[$iProcessIdx]) && $iTestIdx < @{$oyTestRun}) | ||||
|                 { | ||||
|                     my $oTest = $$oyTestRun[$iTestIdx]; | ||||
|                     $iTestIdx++; | ||||
|  | ||||
|                     my $strTest = sprintf('P%0' . length($iProcessMax) . 'd-T%0' . length($iTestMax) . 'd/%0' . | ||||
|                                           length($iTestMax) . "d - ", $iProcessIdx, $iTestIdx, $iTestMax) . | ||||
|                                           "vm=$$oTest{os}, module=$$oTest{module}, test=$$oTest{test}" . | ||||
|                                           (defined($$oTest{run}) ? ", run=$$oTest{run}" : '') . | ||||
|                                           (defined($$oTest{thread}) ? ", thread-max=$$oTest{thread}" : ''); | ||||
|  | ||||
|                     my $strImage = 'test-' . $iProcessIdx; | ||||
|  | ||||
|                     &log($bDryRun ? INFO : DEBUG, $strTest); | ||||
|  | ||||
|                     if (!$bDryRun) | ||||
|                     { | ||||
|                         executeTest("docker run -itd -h $$oTest{os}-test --name=${strImage}" . | ||||
|                                     " -v /backrest:/backrest backrest/$$oTest{os}-test"); | ||||
|                     } | ||||
|  | ||||
|                     $strCommandLine =~ s/\-\-os\=\S*//g; | ||||
|                     $strCommandLine =~ s/\-\-test-path\=\S*//g; | ||||
|                     $strCommandLine =~ s/\-\-module\=\S*//g; | ||||
|                     $strCommandLine =~ s/\-\-test\=\S*//g; | ||||
|                     $strCommandLine =~ s/\-\-run\=\S*//g; | ||||
|  | ||||
|                     my $strCommand = "docker exec -i -u vagrant ${strImage} $0 ${strCommandLine} --test-path=/home/vagrant/test" . | ||||
|                                      " --vm=none --module=$$oTest{module} --test=$$oTest{test}" . | ||||
|                                      (defined($$oTest{run}) ? " --run=$$oTest{run}" : '') . | ||||
|                                      (defined($$oTest{thread}) ? " --thread-max=$$oTest{thread}" : '') . | ||||
|                                      " --no-cleanup"; | ||||
|  | ||||
|                     &log(DEBUG, $strCommand); | ||||
|  | ||||
|                     if (!$bDryRun) | ||||
|                     { | ||||
|                         my $fTestStartTime = gettimeofday(); | ||||
|                         my $oExec = new BackRestTest::Common::ExecuteTest($strCommand, {bSuppressError => true}); | ||||
|  | ||||
|                         $oExec->begin(); | ||||
|  | ||||
|                         my $oProcess = | ||||
|                         { | ||||
|                             exec => $oExec, | ||||
|                             test => $strTest, | ||||
|                             idx => $iTestIdx, | ||||
|                             start_time => $fTestStartTime | ||||
|                         }; | ||||
|  | ||||
|                         $$oyProcess[$iProcessIdx] = $oProcess; | ||||
|                     } | ||||
|  | ||||
|                     $iProcessTotal++; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         while ($iProcessTotal > 0); | ||||
|  | ||||
|         &log(INFO, 'TESTS COMPLETED ' . ($iTestFail == 0 ? 'SUCCESSFULLY' : "WITH ${iTestFail} FAILURE(S)") . | ||||
|                    ' (' . (time() - $lStartTime) . 's)'); | ||||
|  | ||||
|         exit 0; | ||||
|     } | ||||
|  | ||||
|     ################################################################################################################################ | ||||
|     # Search for psql | ||||
|     ################################################################################################################################ | ||||
|     my @stryTestVersion; | ||||
|     my @stryVersionSupport = versionSupport(); | ||||
|  | ||||
|     if (!defined($strPgSqlBin)) | ||||
|     { | ||||
|         # Distribution-specific paths where the PostgreSQL binaries may be located | ||||
|         my @strySearchPath = | ||||
|         ( | ||||
|             '/usr/lib/postgresql/VERSION/bin',  # Debian/Ubuntu | ||||
|             '/usr/pgsql-VERSION/bin',           # CentOS/RHEL/Fedora | ||||
|             '/Library/PostgreSQL/VERSION/bin',  # OSX | ||||
|             '/usr/local/bin'                    # BSD | ||||
|         ); | ||||
|  | ||||
|         foreach my $strSearchPath (@strySearchPath) | ||||
|         { | ||||
|             for (my $iVersionIdx = @stryVersionSupport - 1; $iVersionIdx >= 0; $iVersionIdx--) | ||||
|             { | ||||
|                 if ($strDbVersion eq 'all' || $strDbVersion eq 'max' && @stryTestVersion == 0 || | ||||
|                     $strDbVersion eq $stryVersionSupport[$iVersionIdx]) | ||||
|                 { | ||||
|                     my $strVersionPath = $strSearchPath; | ||||
|                     $strVersionPath =~ s/VERSION/$stryVersionSupport[$iVersionIdx]/g; | ||||
|  | ||||
|                     if (-e "${strVersionPath}/initdb") | ||||
|                     { | ||||
|                         &log(INFO, "FOUND pgsql-bin at ${strVersionPath}"); | ||||
|                         push @stryTestVersion, $strVersionPath; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         # Make sure at least one version of postgres was found | ||||
|         @stryTestVersion > 0 | ||||
|             or confess 'pgsql-bin was not defined and postgres could not be located automatically'; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         push @stryTestVersion, $strPgSqlBin; | ||||
|     } | ||||
|  | ||||
|     ################################################################################################################################ | ||||
|     # Clean whitespace only if test.pl is being run from the test directory in the backrest repo | ||||
|     ################################################################################################################################ | ||||
|     # if (-e './test.pl' && -e '../bin/pg_backrest') | ||||
|     # { | ||||
|     #     BackRestTestCommon_Execute( | ||||
|     #         "find .. -type f -not -path \"../.git/*\" -not -path \"*.DS_Store\" -not -path \"../test/test/*\" " . | ||||
|     #         "-not -path \"../test/data/*\" " . | ||||
|     #         "-exec sh -c 'for i;do echo \"\$i\" && sed 's/[[:space:]]*\$//' \"\$i\">/tmp/.\$\$ && cat /tmp/.\$\$ " . | ||||
|     #         "> \"\$i\";done' arg0 {} + > /dev/null", false, true); | ||||
|     # } | ||||
|  | ||||
|     ################################################################################################################################ | ||||
|     # Runs tests | ||||
|     ################################################################################################################################ | ||||
|     # &log(INFO, "Testing with test_path = " . BackRestTestCommon_TestPathGet() . ", host = {strHost}, user = {strUser}, " . | ||||
|     #            "group = {strGroup}"); | ||||
|  | ||||
|     my $iRun = 0; | ||||
|  | ||||
|     do | ||||
|     { | ||||
|         if (BackRestTestCommon_Setup($strExe, $strTestPath, $stryTestVersion[0], $iModuleTestRun, | ||||
| @@ -357,10 +686,9 @@ if ($@) | ||||
|     } | ||||
|  | ||||
|     syswrite(*STDOUT, $oMessage); | ||||
|     exit 255;; | ||||
|     exit 250; | ||||
| } | ||||
|  | ||||
|  | ||||
| if (!$bDryRun) | ||||
| { | ||||
|     &log(INFO, 'TESTS COMPLETED SUCCESSFULLY (DESPITE ANY ERROR MESSAGES YOU SAW)'); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user