1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-09-16 09:06:18 +02:00

Allow more tests to run outside of containers.

These tests required sudo to achieve complete coverage.

Add a new coverage exception, vm_covered, that applies to code that can only be covered in a container. When the test is run outside of a container code sections that require a container will be excluded with TEST_CONTAINER_REQUIRED and the coverage exception will be added to prevent a coverage error.

This does require marking up the core code with vm_covered, which in some modules (e.g. common/io/tls/client) can be extensive. It's possible that some of these tests can be rewritten to be less dependent on sudo but no attempt was made to do that here.

Only allow coverage summaries in a vm since coverage summaries outside a vm will not be complete, which was true even before this commit.
This commit is contained in:
David Steele
2020-05-09 09:17:33 -04:00
parent b4fc1804a8
commit 22d260ad53
11 changed files with 217 additions and 148 deletions

View File

@@ -607,11 +607,11 @@ restoreManifestOwner(Manifest *manifest)
StorageInfo pathInfo = storageInfoP(storagePg(), manifestTargetBase(manifest)->path);
// If user/group is null then set it to root
if (pathInfo.user == NULL)
pathInfo.user = userName();
if (pathInfo.user == NULL) // {vm_covered}
pathInfo.user = userName(); // {vm_covered}
if (pathInfo.group == NULL)
pathInfo.group = groupName();
if (pathInfo.group == NULL) // {vm_covered}
pathInfo.group = groupName(); // {vm_covered}
if (userNull || groupNull)
{

View File

@@ -101,11 +101,11 @@ tlsClientNew(SocketClient *socket, TimeMSec timeout, bool verifyPeer, const Stri
if (this->verifyPeer)
{
// If the user specified a location
if (caFile != NULL || caPath != NULL)
if (caFile != NULL || caPath != NULL) // {vm_covered}
{
cryptoError(
SSL_CTX_load_verify_locations(this->context, strPtr(caFile), strPtr(caPath)) != 1,
"unable to set user-defined CA certificate location");
cryptoError( // {vm_covered}
SSL_CTX_load_verify_locations(this->context, strPtr(caFile), strPtr(caPath)) != 1, // {vm_covered}
"unable to set user-defined CA certificate location"); // {vm_covered}
}
// Else use the defaults
else
@@ -130,10 +130,10 @@ asn1ToStr(ASN1_STRING *nameAsn1)
FUNCTION_TEST_END();
// The name should not be null
if (nameAsn1 == NULL)
if (nameAsn1 == NULL) // {vm_covered}
THROW(CryptoError, "TLS certificate name entry is missing");
FUNCTION_TEST_RETURN(
FUNCTION_TEST_RETURN( // {vm_covered}
strNewN(
#if OPENSSL_VERSION_NUMBER < 0x10100000L
(const char *)ASN1_STRING_data(nameAsn1),
@@ -166,9 +166,9 @@ tlsClientHostVerifyName(const String *host, const String *name)
bool result = false;
// Try an exact match
if (strcasecmp(strPtr(name), strPtr(host)) == 0)
if (strcasecmp(strPtr(name), strPtr(host)) == 0) // {vm_covered}
{
result = true;
result = true; // {vm_covered}
}
// Else check if a wildcard certificate matches the host name
//
@@ -180,11 +180,12 @@ tlsClientHostVerifyName(const String *host, const String *name)
//
// This is roughly in line with RFC2818, but contrary to what most browsers appear to be implementing (point 3 being the
// difference)
else if (strPtr(name)[0] == '*' && strPtr(name)[1] == '.' && strSize(name) > 2 && strSize(name) < strSize(host) &&
strcasecmp(strPtr(name) + 1, strPtr(host) + strSize(host) - strSize(name) + 1) == 0 &&
strChr(host, '.') >= (int)(strSize(host) - strSize(name)))
else if (strPtr(name)[0] == '*' && strPtr(name)[1] == '.' && strSize(name) > 2 && // {vm_covered}
strSize(name) < strSize(host) && // {vm_covered}
strcasecmp(strPtr(name) + 1, strPtr(host) + strSize(host) - strSize(name) + 1) == 0 && // {vm_covered}
strChr(host, '.') >= (int)(strSize(host) - strSize(name))) // {vm_covered}
{
result = true;
result = true; // {vm_covered}
}
FUNCTION_LOG_RETURN(BOOL, result);
@@ -208,50 +209,51 @@ tlsClientHostVerify(const String *host, X509 *certificate)
bool result = false;
// Error if the certificate is NULL
if (certificate == NULL)
THROW(CryptoError, "No certificate presented by the TLS server");
if (certificate == NULL) // {vm_covered}
THROW(CryptoError, "No certificate presented by the TLS server"); // {vm_covered}
MEM_CONTEXT_TEMP_BEGIN()
MEM_CONTEXT_TEMP_BEGIN() // {vm_covered}
{
// First get the subject alternative names from the certificate and compare them against the hostname
STACK_OF(GENERAL_NAME) *altNameStack = (STACK_OF(GENERAL_NAME) *)X509_get_ext_d2i(
certificate, NID_subject_alt_name, NULL, NULL);
bool altNameFound = false;
STACK_OF(GENERAL_NAME) *altNameStack = (STACK_OF(GENERAL_NAME) *)X509_get_ext_d2i( // {vm_covered}
certificate, NID_subject_alt_name, NULL, NULL); // {vm_covered}
bool altNameFound = false; // {vm_covered}
if (altNameStack)
if (altNameStack) // {vm_covered}
{
for (int altNameIdx = 0; altNameIdx < sk_GENERAL_NAME_num(altNameStack); altNameIdx++)
for (int altNameIdx = 0; altNameIdx < sk_GENERAL_NAME_num(altNameStack); altNameIdx++) // {vm_covered}
{
const GENERAL_NAME *name = sk_GENERAL_NAME_value(altNameStack, altNameIdx);
altNameFound = true;
const GENERAL_NAME *name = sk_GENERAL_NAME_value(altNameStack, altNameIdx); // {vm_covered}
altNameFound = true; // {vm_covered}
if (name->type == GEN_DNS)
result = tlsClientHostVerifyName(host, asn1ToStr(name->d.dNSName));
if (name->type == GEN_DNS) // {vm_covered}
result = tlsClientHostVerifyName(host, asn1ToStr(name->d.dNSName)); // {vm_covered}
if (result != false)
break;
if (result != false) // {vm_covered}
break; // {vm_covered}
}
sk_GENERAL_NAME_pop_free(altNameStack, GENERAL_NAME_free);
sk_GENERAL_NAME_pop_free(altNameStack, GENERAL_NAME_free); // {vm_covered}
}
// If no subject alternative name was found then check the common name. Per RFC 2818 and RFC 6125, if the subjectAltName
// extension of type dNSName is present the CN must be ignored.
if (!altNameFound)
if (!altNameFound) // {vm_covered}
{
X509_NAME *subjectName = X509_get_subject_name(certificate);
CHECK(subjectName != NULL);
X509_NAME *subjectName = X509_get_subject_name(certificate); // {vm_covered}
CHECK(subjectName != NULL); // {vm_covered}
int commonNameIndex = X509_NAME_get_index_by_NID(subjectName, NID_commonName, -1);
CHECK(commonNameIndex >= 0);
int commonNameIndex = X509_NAME_get_index_by_NID(subjectName, NID_commonName, -1); // {vm_covered}
CHECK(commonNameIndex >= 0); // {vm_covered}
result = tlsClientHostVerifyName(
host, asn1ToStr(X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjectName, commonNameIndex))));
result = tlsClientHostVerifyName( // {vm_covered}
host, // {vm_covered}
asn1ToStr(X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjectName, commonNameIndex)))); // {vm_covered}
}
}
MEM_CONTEXT_TEMP_END();
MEM_CONTEXT_TEMP_END(); // {vm_covered}
FUNCTION_LOG_RETURN(BOOL, result);
FUNCTION_LOG_RETURN(BOOL, result); // {vm_covered}
}
/***********************************************************************************************************************************
@@ -322,30 +324,30 @@ tlsClientOpen(TlsClient *this)
tlsClientStatLocal.session++;
// Verify that the certificate presented by the server is valid
if (this->verifyPeer)
if (this->verifyPeer) // {vm_covered}
{
// Verify that the chain of trust leads to a valid CA
long int verifyResult = SSL_get_verify_result(session);
long int verifyResult = SSL_get_verify_result(session); // {vm_covered}
if (verifyResult != X509_V_OK)
if (verifyResult != X509_V_OK) // {vm_covered}
{
THROW_FMT(
CryptoError, "unable to verify certificate presented by '%s:%u': [%ld] %s",
strPtr(sckClientHost(this->socketClient)), sckClientPort(this->socketClient), verifyResult,
X509_verify_cert_error_string(verifyResult));
THROW_FMT( // {vm_covered}
CryptoError, "unable to verify certificate presented by '%s:%u': [%ld] %s", // {vm_covered}
strPtr(sckClientHost(this->socketClient)), sckClientPort(this->socketClient), verifyResult, // {vm_covered}
X509_verify_cert_error_string(verifyResult)); // {vm_covered}
}
// Verify that the hostname appears in the certificate
X509 *certificate = SSL_get_peer_certificate(session);
bool nameResult = tlsClientHostVerify(sckClientHost(this->socketClient), certificate);
X509_free(certificate);
X509 *certificate = SSL_get_peer_certificate(session); // {vm_covered}
bool nameResult = tlsClientHostVerify(sckClientHost(this->socketClient), certificate); // {vm_covered}
X509_free(certificate); // {vm_covered}
if (!nameResult)
if (!nameResult) // {vm_covered}
{
THROW_FMT(
CryptoError,
"unable to find hostname '%s' in certificate common name or subject alternative names",
strPtr(sckClientHost(this->socketClient)));
THROW_FMT( // {vm_covered}
CryptoError, // {vm_covered}
"unable to find hostname '%s' in certificate common name or subject alternative names", // {vm_covered}
strPtr(sckClientHost(this->socketClient))); // {vm_covered}
}
}

View File

@@ -74,13 +74,13 @@ storageReadPosixOpen(THIS_VOID)
// Handle errors
if (this->handle == -1)
{
if (errno == ENOENT)
if (errno == ENOENT) // {vm_covered}
{
if (!this->interface.ignoreMissing)
THROW_FMT(FileMissingError, STORAGE_ERROR_READ_MISSING, strPtr(this->interface.name));
}
else
THROW_SYS_ERROR_FMT(FileOpenError, STORAGE_ERROR_READ_OPEN, strPtr(this->interface.name));
THROW_SYS_ERROR_FMT(FileOpenError, STORAGE_ERROR_READ_OPEN, strPtr(this->interface.name)); // {vm_covered}
}
// On success set free callback to ensure file handle is freed
if (this->handle != -1)

View File

@@ -65,8 +65,8 @@ storagePosixInfo(THIS_VOID, const String *file, StorageInfoLevel level, StorageI
if ((param.followLink ? stat(strPtr(file), &statFile) : lstat(strPtr(file), &statFile)) == -1)
{
if (errno != ENOENT)
THROW_SYS_ERROR_FMT(FileOpenError, STORAGE_ERROR_INFO, strPtr(file));
if (errno != ENOENT) // {vm_covered}
THROW_SYS_ERROR_FMT(FileOpenError, STORAGE_ERROR_INFO, strPtr(file)); // {vm_covered}
}
// On success the file exists
else
@@ -180,8 +180,8 @@ storagePosixInfoList(
// If the directory could not be opened process errors and report missing directories
if (dir == NULL)
{
if (errno != ENOENT)
THROW_SYS_ERROR_FMT(PathOpenError, STORAGE_ERROR_LIST_INFO, strPtr(path));
if (errno != ENOENT) // {vm_covered}
THROW_SYS_ERROR_FMT(PathOpenError, STORAGE_ERROR_LIST_INFO, strPtr(path)); // {vm_covered}
}
else
{
@@ -277,12 +277,15 @@ storagePosixMove(THIS_VOID, StorageRead *source, StorageWrite *destination, Stor
result = storageInterfaceMoveP(this, source, destination);
}
// Else the destination is on a different device so a copy will be needed
else if (errno == EXDEV)
else if (errno == EXDEV) // {vm_covered}
{
result = false;
}
else
THROW_SYS_ERROR_FMT(FileMoveError, "unable to move '%s' to '%s'", strPtr(sourceFile), strPtr(destinationFile));
{
THROW_SYS_ERROR_FMT( // {vm_covered}
FileMoveError, "unable to move '%s' to '%s'", strPtr(sourceFile), strPtr(destinationFile)); // {vm_covered}
}
}
// Sync paths on success
else
@@ -411,7 +414,7 @@ storagePosixPathRemoveCallback(void *callbackData, const StorageInfo *info)
String *file = strNewFmt("%s/%s", strPtr(data->path), strPtr(info->name));
// Rather than stat the file to discover what type it is, just try to unlink it and see what happens
if (unlink(strPtr(file)) == -1)
if (unlink(strPtr(file)) == -1) // {vm_covered}
{
// These errors indicate that the entry is actually a path so we'll try to delete it that way
if (errno == EPERM || errno == EISDIR) // {uncovered_branch - no EPERM on tested systems}
@@ -420,7 +423,7 @@ storagePosixPathRemoveCallback(void *callbackData, const StorageInfo *info)
}
// Else error
else
THROW_SYS_ERROR_FMT(PathRemoveError, STORAGE_ERROR_PATH_REMOVE_FILE, strPtr(file));
THROW_SYS_ERROR_FMT(PathRemoveError, STORAGE_ERROR_PATH_REMOVE_FILE, strPtr(file)); // {vm_covered}
}
}
@@ -462,8 +465,8 @@ storagePosixPathRemove(THIS_VOID, const String *path, bool recurse, StorageInter
// Delete the path
if (rmdir(strPtr(path)) == -1)
{
if (errno != ENOENT)
THROW_SYS_ERROR_FMT(PathRemoveError, STORAGE_ERROR_PATH_REMOVE, strPtr(path));
if (errno != ENOENT) // {vm_covered}
THROW_SYS_ERROR_FMT(PathRemoveError, STORAGE_ERROR_PATH_REMOVE, strPtr(path)); // {vm_covered}
// Path does not exist
result = false;
@@ -495,10 +498,10 @@ storagePosixPathSync(THIS_VOID, const String *path, StorageInterfacePathSyncPara
// Handle errors
if (handle == -1)
{
if (errno == ENOENT)
if (errno == ENOENT) // {vm_covered}
THROW_FMT(PathMissingError, STORAGE_ERROR_PATH_SYNC_MISSING, strPtr(path));
else
THROW_SYS_ERROR_FMT(PathOpenError, STORAGE_ERROR_PATH_SYNC_OPEN, strPtr(path));
THROW_SYS_ERROR_FMT(PathOpenError, STORAGE_ERROR_PATH_SYNC_OPEN, strPtr(path)); // {vm_covered}
}
else
{
@@ -537,8 +540,8 @@ storagePosixRemove(THIS_VOID, const String *file, StorageInterfaceRemoveParam pa
// Attempt to unlink the file
if (unlink(strPtr(file)) == -1)
{
if (param.errorOnMissing || errno != ENOENT)
THROW_SYS_ERROR_FMT(FileRemoveError, "unable to remove '%s'", strPtr(file));
if (param.errorOnMissing || errno != ENOENT) // {vm_covered}
THROW_SYS_ERROR_FMT(FileRemoveError, "unable to remove '%s'", strPtr(file)); // {vm_covered}
}
FUNCTION_LOG_RETURN_VOID();

View File

@@ -78,8 +78,8 @@ storageWritePosixOpen(THIS_VOID)
// Open the file
this->handle = open(strPtr(this->nameTmp), FILE_OPEN_FLAGS, this->interface.modeFile);
// Attempt the create the path if it is missing
if (this->handle == -1 && errno == ENOENT && this->interface.createPath)
// Attempt to create the path if it is missing
if (this->handle == -1 && errno == ENOENT && this->interface.createPath) // {vm_covered}
{
// Create the path
storageInterfacePathCreateP(this->storage, this->path, false, false, this->interface.modePath);
@@ -91,10 +91,10 @@ storageWritePosixOpen(THIS_VOID)
// Handle errors
if (this->handle == -1)
{
if (errno == ENOENT)
if (errno == ENOENT) // {vm_covered}
THROW_FMT(FileMissingError, STORAGE_ERROR_WRITE_MISSING, strPtr(this->interface.name));
else
THROW_SYS_ERROR_FMT(FileOpenError, STORAGE_ERROR_WRITE_OPEN, strPtr(this->interface.name));
THROW_SYS_ERROR_FMT(FileOpenError, STORAGE_ERROR_WRITE_OPEN, strPtr(this->interface.name)); // {vm_covered}
}
// Set free callback to ensure file handle is freed

View File

@@ -240,7 +240,6 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: io-tls
total: 5
containerReq: true
coverage:
common/io/tls/client: full
@@ -411,7 +410,6 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: posix
total: 21
containerReq: true
coverage:
storage/posix/read: full
@@ -652,7 +650,6 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: restore
total: 12
containerReq: true
binReq: true
coverage:

View File

@@ -35,12 +35,14 @@ sub coverageLCovConfigGenerate
{
my $oStorage = shift;
my $strOutFile = shift;
my $bContainer = shift;
my $bCoverageSummary = shift;
my $strBranchFilter =
'OBJECT_DEFINE_[A-Z0-9_]+\(|\s{4}[A-Z][A-Z0-9_]+\([^\?]*\)|\s{4}(ASSERT|assert|switch\s)\(|\{\+{0,1}' .
($bCoverageSummary ? 'uncoverable_branch' : 'uncover(ed|able)_branch');
my $strLineFilter = '\{\+{0,1}uncover' . ($bCoverageSummary ? 'able' : '(ed|able)') . '[^_]';
my $strLineFilter =
'\{\+{0,1}' . ($bCoverageSummary ? 'uncoverable' : '(uncover(ed|able)' . ($bContainer ? '' : '|vm_covered') . ')') . '[^_]';
my $strConfig =
"# LCOV Settings\n" .
@@ -80,6 +82,7 @@ sub coverageExtract
my $oStorage = shift;
my $strModule = shift;
my $strTest = shift;
my $bContainer = shift;
my $bSummary = shift;
my $strContainerImage = shift;
my $strWorkPath = shift;
@@ -87,6 +90,12 @@ sub coverageExtract
my $strWorkUnitPath = shift;
my $strTestResultCoveragePath = shift . '/coverage';
# Coverage summary must be run in a container
if ($bSummary && !$bContainer)
{
confess &log(ERROR, "coverage summary must be run on containers for full coverage");
}
# Generate a list of files to cover
my $hTestCoverage = (testDefModuleTest($strModule, $strTest))->{&TESTDEF_COVERAGE};
@@ -101,7 +110,7 @@ sub coverageExtract
# Generate coverage reports for the modules
my $strLCovConf = "${strTestResultCoveragePath}/raw/lcov.conf";
coverageLCovConfigGenerate($oStorage, $strLCovConf, $bSummary);
coverageLCovConfigGenerate($oStorage, $strLCovConf, $bContainer, $bSummary);
my $strLCovExe = "lcov --config-file=${strLCovConf}";
my $strLCovOut = "${strWorkUnitPath}/test.lcov";

View File

@@ -501,6 +501,7 @@ sub run
(($self->{bOptimize} && ($self->{bProfile} || $bPerformance)) ? '-O2' : $strNoOptimizeFlags) .
(!$self->{bDebugTestTrace} && $self->{bDebug} ? ' -DDEBUG_TEST_TRACE' : '') .
(vmCoverageC($self->{oTest}->{&TEST_VM}) && $self->{bCoverageUnit} ? ' -fprofile-arcs -ftest-coverage' : '') .
($self->{oTest}->{&TEST_VM} eq VM_NONE ? '' : " -DTEST_CONTAINER_REQUIRED") .
($self->{oTest}->{&TEST_CTESTDEF} ? " $self->{oTest}->{&TEST_CTESTDEF}" : '');
buildPutDiffers(
@@ -638,7 +639,8 @@ sub end
if ($iExitStatus == 0 && $self->{oTest}->{&TEST_C} && vmCoverageC($self->{oTest}->{&TEST_VM}) && $self->{bCoverageUnit})
{
coverageExtract(
$self->{oStorageTest}, $self->{oTest}->{&TEST_MODULE}, $self->{oTest}->{&TEST_NAME}, $self->{bCoverageSummary},
$self->{oStorageTest}, $self->{oTest}->{&TEST_MODULE}, $self->{oTest}->{&TEST_NAME},
$self->{oTest}->{&TEST_VM} ne VM_NONE, $self->{bCoverageSummary},
$self->{oTest}->{&TEST_VM} eq VM_NONE ? undef : $strImage, $self->{strTestPath}, "$self->{strTestPath}/temp",
$self->{strGCovPath}, $self->{strBackRestBase} . '/test/result');
}

View File

@@ -919,24 +919,23 @@ testRun(void)
TEST_RESULT_LOG("P00 WARN: unknown user in backup manifest mapped to '{[user]}'");
// -------------------------------------------------------------------------------------------------------------------------
if (testContainer())
{
TEST_TITLE("owner is root and ownership of pg_data is bad");
#ifdef TEST_CONTAINER_REQUIRED
TEST_TITLE("owner is root and ownership of pg_data is bad");
manifestPathAdd(manifest, &path);
manifestFileAdd(manifest, &file);
manifestPathAdd(manifest, &path);
manifestFileAdd(manifest, &file);
TEST_SYSTEM_FMT("sudo chown 77777:77777 %s", strPtr(pgPath));
TEST_SYSTEM_FMT("sudo chown 77777:77777 %s", strPtr(pgPath));
userLocalData.userName = STRDEF("root");
userLocalData.groupName = STRDEF("root");
userLocalData.userName = STRDEF("root");
userLocalData.groupName = STRDEF("root");
TEST_RESULT_VOID(restoreManifestOwner(manifest), "check ownership");
TEST_RESULT_VOID(restoreManifestOwner(manifest), "check ownership");
TEST_RESULT_LOG(
"P00 WARN: unknown user in backup manifest mapped to 'root'\n"
"P00 WARN: unknown group in backup manifest mapped to 'root'");
}
TEST_RESULT_LOG(
"P00 WARN: unknown user in backup manifest mapped to 'root'\n"
"P00 WARN: unknown group in backup manifest mapped to 'root'");
#endif // TEST_CONTAINER_REQUIRED
}
// *****************************************************************************************************************************

View File

@@ -12,6 +12,8 @@ Test Tls Client
/***********************************************************************************************************************************
Test server with subject alternate names
***********************************************************************************************************************************/
#ifdef TEST_CONTAINER_REQUIRED
static void
testTlsServerAltName(void)
{
@@ -26,20 +28,17 @@ testTlsServerAltName(void)
harnessTlsServerAccept();
harnessTlsServerClose();
if (testContainer())
{
// Success on valid ca file and match common name
harnessTlsServerAccept();
harnessTlsServerClose();
// Success on valid ca file and match common name
harnessTlsServerAccept();
harnessTlsServerClose();
// Success on valid ca file and match alt name
harnessTlsServerAccept();
harnessTlsServerClose();
// Success on valid ca file and match alt name
harnessTlsServerAccept();
harnessTlsServerClose();
// Unable to find matching hostname in certificate
harnessTlsServerAccept();
harnessTlsServerClose();
}
// Unable to find matching hostname in certificate
harnessTlsServerAccept();
harnessTlsServerClose();
// Certificate error
harnessTlsServerAccept();
@@ -52,6 +51,8 @@ testTlsServerAltName(void)
FUNCTION_HARNESS_RESULT_VOID();
}
#endif // TEST_CONTAINER_REQUIRED
/***********************************************************************************************************************************
Test server
***********************************************************************************************************************************/
@@ -226,10 +227,12 @@ testRun(void)
// ---------------------------------------------------------------------------------------------------------------------
TEST_TITLE("unable to connect to blocking socket");
SocketClient *socketClient = sckClientNew(STR(hostLocal), 7777, 0);
TEST_RESULT_UINT(sckClientPort(socketClient), 7777, " check port");
socketLocal.block = true;
TEST_ERROR(
sckClientOpen(sckClientNew(STR(hostLocal), 7777, 0)), HostConnectError,
"unable to connect to '127.0.0.1:7777': [111] Connection refused");
sckClientOpen(socketClient), HostConnectError, "unable to connect to '127.0.0.1:7777': [111] Connection refused");
socketLocal.block = false;
// ---------------------------------------------------------------------------------------------------------------------
@@ -304,14 +307,12 @@ testRun(void)
// Certificate location and validation errors
// -------------------------------------------------------------------------------------------------------------------------
// Add test hosts
if (testContainer())
#ifdef TEST_CONTAINER_REQUIRED
if (system( // {uncoverable_branch}
"echo \"127.0.0.1 test.pgbackrest.org host.test2.pgbackrest.org test3.pgbackrest.org\" |"
" sudo tee -a /etc/hosts > /dev/null") != 0)
{
if (system( // {uncoverable_branch}
"echo \"127.0.0.1 test.pgbackrest.org host.test2.pgbackrest.org test3.pgbackrest.org\" |"
" sudo tee -a /etc/hosts > /dev/null") != 0)
{
THROW(AssertError, "unable to add test hosts to /etc/hosts"); // {uncovered+}
}
THROW(AssertError, "unable to add test hosts to /etc/hosts"); // {uncovered+}
}
HARNESS_FORK_BEGIN()
@@ -331,6 +332,7 @@ testRun(void)
sckClientNew(strNew("localhost"), harnessTlsTestPort(), 5000), 0, true, strNew("bogus.crt"),
strNew("/bogus"))),
CryptoError, "unable to set user-defined CA certificate location: [33558530] No such file or directory");
TEST_ERROR_FMT(
tlsClientOpen(
tlsClientNew(
@@ -339,28 +341,25 @@ testRun(void)
"unable to verify certificate presented by 'localhost:%u': [20] unable to get local issuer certificate",
harnessTlsTestPort());
if (testContainer())
{
TEST_RESULT_VOID(
tlsClientOpen(
tlsClientNew(
sckClientNew(strNew("test.pgbackrest.org"), harnessTlsTestPort(), 5000), 0, true,
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)),
"success on valid ca file and match common name");
TEST_RESULT_VOID(
tlsClientOpen(
tlsClientNew(
sckClientNew(strNew("host.test2.pgbackrest.org"), harnessTlsTestPort(), 5000), 0, true,
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)),
"success on valid ca file and match alt name");
TEST_ERROR(
tlsClientOpen(
tlsClientNew(
sckClientNew(strNew("test3.pgbackrest.org"), harnessTlsTestPort(), 5000), 0, true,
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)),
CryptoError,
"unable to find hostname 'test3.pgbackrest.org' in certificate common name or subject alternative names");
}
TEST_RESULT_VOID(
tlsClientOpen(
tlsClientNew(
sckClientNew(strNew("test.pgbackrest.org"), harnessTlsTestPort(), 5000), 0, true,
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)),
"success on valid ca file and match common name");
TEST_RESULT_VOID(
tlsClientOpen(
tlsClientNew(
sckClientNew(strNew("host.test2.pgbackrest.org"), harnessTlsTestPort(), 5000), 0, true,
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)),
"success on valid ca file and match alt name");
TEST_ERROR(
tlsClientOpen(
tlsClientNew(
sckClientNew(strNew("test3.pgbackrest.org"), harnessTlsTestPort(), 5000), 0, true,
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)),
CryptoError,
"unable to find hostname 'test3.pgbackrest.org' in certificate common name or subject alternative names");
TEST_ERROR_FMT(
tlsClientOpen(
@@ -380,6 +379,7 @@ testRun(void)
HARNESS_FORK_PARENT_END();
}
HARNESS_FORK_END();
#endif // TEST_CONTAINER_REQUIRED
}
// *****************************************************************************************************************************

View File

@@ -53,8 +53,10 @@ testRun(void)
ioBufferSizeSet(2);
// Directory and file that cannot be accessed to test permissions errors
#ifdef TEST_CONTAINER_REQUIRED
String *fileNoPerm = strNewFmt("%s/noperm/noperm", testPath());
String *pathNoPerm = strPath(fileNoPerm);
#endif // TEST_CONTAINER_REQUIRED
// Write file for testing if storage is read-only
String *writeFile = strNewFmt("%s/writefile", testPath());
@@ -115,7 +117,9 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("storageExists() and storagePathExists()"))
{
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_BOOL(storageExistsP(storageTest, strNew("missing")), false, "file does not exist");
@@ -126,12 +130,14 @@ testRun(void)
TEST_RESULT_BOOL(storagePathExistsP(storageTest, NULL), true, "test path exists");
// -------------------------------------------------------------------------------------------------------------------------
#ifdef TEST_CONTAINER_REQUIRED
TEST_ERROR_FMT(
storageExistsP(storageTest, fileNoPerm), FileOpenError,
"unable to get info for path/file '%s': [13] Permission denied", strPtr(fileNoPerm));
TEST_ERROR_FMT(
storagePathExistsP(storageTest, fileNoPerm), FileOpenError,
"unable to get info for path/file '%s': [13] Permission denied", strPtr(fileNoPerm));
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
String *fileExists = strNewFmt("%s/exists", testPath());
@@ -142,7 +148,7 @@ testRun(void)
TEST_RESULT_BOOL(storageExistsP(storageTest, fileExists), true, "file exists");
TEST_RESULT_BOOL(storageExistsP(storageTest, pathExists), false, "not a file");
TEST_RESULT_BOOL(storagePathExistsP(storageTest, fileExists), false, "not a path");
TEST_RESULT_INT(system(strPtr(strNewFmt("sudo rm %s", strPtr(fileExists)))), 0, "remove exists file");
TEST_RESULT_INT(system(strPtr(strNewFmt("rm %s", strPtr(fileExists)))), 0, "remove exists file");
// -------------------------------------------------------------------------------------------------------------------------
HARNESS_FORK_BEGIN()
@@ -162,17 +168,19 @@ testRun(void)
}
HARNESS_FORK_END();
TEST_RESULT_INT(system(strPtr(strNewFmt("sudo rm %s", strPtr(fileExists)))), 0, "remove exists file");
TEST_RESULT_INT(system(strPtr(strNewFmt("rm %s", strPtr(fileExists)))), 0, "remove exists file");
}
// *****************************************************************************************************************************
if (testBegin("storageInfo()"))
{
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
TEST_ERROR_FMT(
storageInfoP(storageTest, fileNoPerm), FileOpenError, STORAGE_ERROR_INFO ": [13] Permission denied",
strPtr(fileNoPerm));
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
String *fileName = strNewFmt("%s/fileinfo", testPath());
@@ -220,7 +228,9 @@ testRun(void)
utimeTest.modtime = 1555155555;
THROW_ON_SYS_ERROR_FMT(utime(strPtr(fileName), &utimeTest) != 0, FileWriteError, "unable to set time for '%s'", testPath());
#ifdef TEST_CONTAINER_REQUIRED
TEST_RESULT_INT(system(strPtr(strNewFmt("sudo chown 99999:99999 %s", strPtr(fileName)))), 0, "set invalid user/group");
#endif // TEST_CONTAINER_REQUIRED
TEST_ASSIGN(info, storageInfoP(storageTest, fileName), "get file info");
TEST_RESULT_PTR(info.name, NULL, " name is not set");
@@ -230,8 +240,10 @@ testRun(void)
TEST_RESULT_INT(info.mode, 0640, " check mode");
TEST_RESULT_INT(info.timeModified, 1555155555, " check mod time");
TEST_RESULT_PTR(info.linkDestination, NULL, " no link destination");
#ifdef TEST_CONTAINER_REQUIRED
TEST_RESULT_STR(info.user, NULL, " check user");
TEST_RESULT_STR(info.group, NULL, " check group");
#endif // TEST_CONTAINER_REQUIRED
storageRemoveP(storageTest, fileName, .errorOnMissing = true);
@@ -281,7 +293,9 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("storageInfoList()"))
{
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR_FMT(
@@ -291,6 +305,7 @@ testRun(void)
TEST_RESULT_BOOL(
storageInfoListP(storageTest, strNew(BOGUS_STR), (StorageInfoListCallback)1, NULL), false, "ignore missing dir");
#ifdef TEST_CONTAINER_REQUIRED
TEST_ERROR_FMT(
storageInfoListP(storageTest, pathNoPerm, (StorageInfoListCallback)1, NULL), PathOpenError,
STORAGE_ERROR_LIST_INFO ": [13] Permission denied", strPtr(pathNoPerm));
@@ -299,6 +314,7 @@ testRun(void)
TEST_ERROR_FMT(
storageInfoListP(storageTest, pathNoPerm, (StorageInfoListCallback)1, NULL), PathOpenError,
STORAGE_ERROR_LIST_INFO ": [13] Permission denied", strPtr(pathNoPerm));
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
HarnessStorageInfoListCallbackData callbackData =
@@ -326,8 +342,10 @@ testRun(void)
" check content");
// -------------------------------------------------------------------------------------------------------------------------
#ifdef TEST_CONTAINER_REQUIRED
storagePathCreateP(storageTest, strNew("pg/.include"), .mode = 0755);
ASSERT(system(strPtr(strNewFmt("sudo chown 77777:77777 %s/pg/.include", testPath()))) == 0);
#endif // TEST_CONTAINER_REQUIRED
storagePutP(storageNewWriteP(storageTest, strNew("pg/file"), .modeFile = 0660), BUFSTRDEF("TESTDATA"));
@@ -351,14 +369,19 @@ testRun(void)
TEST_RESULT_STR_Z(
callbackData.content,
". {path}\n"
#ifdef TEST_CONTAINER_REQUIRED
".include {path, m=0755, u=77777, g=77777}\n"
#endif // TEST_CONTAINER_REQUIRED
"file {file, s=8, m=0660}\n"
"link {link, d=../file}\n"
"pipe {special}\n",
" check content");
// -------------------------------------------------------------------------------------------------------------------------
#ifdef TEST_CONTAINER_REQUIRED
ASSERT(system(strPtr(strNewFmt("sudo rmdir %s/pg/.include", testPath()))) == 0);
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
storagePathCreateP(storageTest, strNew("pg/path"), .mode = 0700);
storagePutP(storageNewWriteP(storageTest, strNew("pg/path/file"), .modeFile = 0600), BUFSTRDEF("TESTDATA"));
@@ -395,7 +418,9 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("storageList()"))
{
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR_FMT(
@@ -406,6 +431,7 @@ testRun(void)
TEST_RESULT_UINT(strLstSize(storageListP(storageTest, strNew(BOGUS_STR))), 0, "empty list for missing dir");
// -------------------------------------------------------------------------------------------------------------------------
#ifdef TEST_CONTAINER_REQUIRED
TEST_ERROR_FMT(
storageListP(storageTest, pathNoPerm), PathOpenError,
STORAGE_ERROR_LIST_INFO ": [13] Permission denied", strPtr(pathNoPerm));
@@ -414,12 +440,18 @@ testRun(void)
TEST_ERROR_FMT(
storageListP(storageTest, pathNoPerm), PathOpenError,
STORAGE_ERROR_LIST_INFO ": [13] Permission denied", strPtr(pathNoPerm));
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_VOID(
storagePutP(storageNewWriteP(storageTest, strNew(".aaa.txt")), BUFSTRDEF("aaa")), "write aaa.text");
TEST_RESULT_STR_Z(
strLstJoin(strLstSort(storageListP(storageTest, NULL), sortOrderAsc), ", "), ".aaa.txt, noperm", "dir list");
strLstJoin(strLstSort(storageListP(storageTest, NULL), sortOrderAsc), ", "),
".aaa.txt"
#ifdef TEST_CONTAINER_REQUIRED
", noperm"
#endif // TEST_CONTAINER_REQUIRED
, "dir list");
TEST_RESULT_VOID(
storagePutP(storageNewWriteP(storageTest, strNew("bbb.txt")), BUFSTRDEF("bbb")), "write bbb.text");
@@ -458,7 +490,9 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("storageMove()"))
{
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
#endif // TEST_CONTAINER_REQUIRED
String *sourceFile = strNewFmt("%s/source.txt", testPath());
String *destinationFile = strNewFmt("%s/sub/destination.txt", testPath());
@@ -471,11 +505,13 @@ testRun(void)
"unable to move missing source '%s': [2] No such file or directory", strPtr(sourceFile));
// -------------------------------------------------------------------------------------------------------------------------
#ifdef TEST_CONTAINER_REQUIRED
source = storageNewReadP(storageTest, fileNoPerm);
TEST_ERROR_FMT(
storageMoveP(storageTest, source, destination), FileMoveError,
"unable to move '%s' to '%s': [13] Permission denied", strPtr(fileNoPerm), strPtr(destinationFile));
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
const Buffer *buffer = BUFSTRDEF("TESTFILE");
@@ -620,6 +656,8 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
String *pathRemove2 = strNewFmt("%s/remove2", strPtr(pathRemove1));
#ifdef TEST_CONTAINER_REQUIRED
TEST_RESULT_INT(system(strPtr(strNewFmt("sudo mkdir -p -m 700 %s", strPtr(pathRemove2)))), 0, "create noperm paths");
TEST_ERROR_FMT(
@@ -656,6 +694,7 @@ testRun(void)
storagePathRemoveP(storageTest, pathRemove1, .recurse = true), "remove path");
TEST_RESULT_BOOL(
storageExistsP(storageTest, pathRemove1), false, "path is removed");
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_INT(system(strPtr(strNewFmt("mkdir -p %s", strPtr(pathRemove2)))), 0, "create subpaths");
@@ -669,11 +708,13 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("storagePathSync()"))
{
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
TEST_ERROR_FMT(
storagePathSyncP(storageTest, fileNoPerm), PathOpenError, STORAGE_ERROR_PATH_SYNC_OPEN ": [13] Permission denied",
strPtr(fileNoPerm));
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
String *pathName = strNewFmt("%s/testpath", testPath());
@@ -713,14 +754,16 @@ testRun(void)
if (testBegin("storageNewWrite()"))
{
String *fileName = strNewFmt("%s/sub1/testfile", testPath());
TEST_CREATE_NOPERM();
StorageWrite *file = NULL;
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileNoPerm, .noAtomic = true), "new write file (defaults)");
TEST_ERROR_FMT(
ioWriteOpen(storageWriteIo(file)), FileOpenError, STORAGE_ERROR_WRITE_OPEN ": [13] Permission denied",
strPtr(fileNoPerm));
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
TEST_ASSIGN(
@@ -829,7 +872,9 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("storageRemove()"))
{
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_VOID(storageRemoveP(storageTest, strNew("missing")), "remove missing file");
@@ -844,26 +889,32 @@ testRun(void)
TEST_RESULT_VOID(storageRemoveP(storageTest, fileExists), "remove exists file");
// -------------------------------------------------------------------------------------------------------------------------
#ifdef TEST_CONTAINER_REQUIRED
TEST_ERROR_FMT(
storageRemoveP(storageTest, fileNoPerm), FileRemoveError,
"unable to remove '%s': [13] Permission denied", strPtr(fileNoPerm));
#endif // TEST_CONTAINER_REQUIRED
}
// *****************************************************************************************************************************
if (testBegin("StorageRead"))
{
TEST_CREATE_NOPERM();
StorageRead *file = NULL;
TEST_ASSIGN(file, storageNewReadP(storageTest, fileNoPerm, .ignoreMissing = true, .limit = VARUINT64(44)), "new read file");
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
TEST_ASSIGN(file, storageNewReadP(storageTest, fileNoPerm, .ignoreMissing = true), "new read file");
TEST_RESULT_BOOL(storageReadIgnoreMissing(file), true, " check ignore missing");
TEST_RESULT_STR(storageReadName(file), fileNoPerm, " check name");
TEST_RESULT_UINT(varUInt64(storageReadLimit(file)), 44, " check limit");
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
#ifdef TEST_CONTAINER_REQUIRED
TEST_ASSIGN(file, storageNewReadP(storageTest, fileNoPerm), "new no perm read file");
TEST_ERROR_FMT(
ioReadOpen(storageReadIo(file)), FileOpenError, STORAGE_ERROR_READ_OPEN ": [13] Permission denied", strPtr(fileNoPerm));
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
String *fileName = strNewFmt("%s/test.file", testPath());
@@ -898,13 +949,16 @@ testRun(void)
MEM_CONTEXT_TEMP_BEGIN()
{
TEST_ASSIGN(file, storageReadMove(storageNewReadP(storageTest, fileName), memContextPrior()), "new read file");
TEST_ASSIGN(
file, storageReadMove(storageNewReadP(storageTest, fileName, .limit = VARUINT64(44)), memContextPrior()),
"new read file");
}
MEM_CONTEXT_TEMP_END();
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, " open file");
TEST_RESULT_STR(storageReadName(file), fileName, " check file name");
TEST_RESULT_STR_Z(storageReadType(file), "posix", " check file type");
TEST_RESULT_UINT(varUInt64(storageReadLimit(file)), 44, " check limit");
TEST_RESULT_VOID(ioRead(storageReadIo(file), outBuffer), " load data");
bufCat(buffer, outBuffer);
@@ -945,9 +999,11 @@ testRun(void)
// *****************************************************************************************************************************
if (testBegin("StorageWrite"))
{
TEST_CREATE_NOPERM();
StorageWrite *file = NULL;
#ifdef TEST_CONTAINER_REQUIRED
TEST_CREATE_NOPERM();
TEST_ASSIGN(
file,
storageNewWriteP(
@@ -968,6 +1024,7 @@ testRun(void)
TEST_ERROR_FMT(
ioWriteOpen(storageWriteIo(file)), FileOpenError, STORAGE_ERROR_WRITE_OPEN ": [13] Permission denied",
strPtr(fileNoPerm));
#endif // TEST_CONTAINER_REQUIRED
// -------------------------------------------------------------------------------------------------------------------------
String *fileName = strNewFmt("%s/sub1/test.file", testPath());