1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2026-05-22 10:15:16 +02:00
Files
pgbackrest/test/src/module/storage/sftpTest.c
T
2023-12-27 12:53:53 -03:00

7806 lines
523 KiB
C

/***********************************************************************************************************************************
Test SFTP Storage
***********************************************************************************************************************************/
#include "common/io/io.h"
#include "common/io/session.h"
#include "common/io/socket/client.h"
#include "common/time.h"
#include "storage/cifs/storage.h"
#include "storage/read.h"
#include "storage/sftp/storage.h"
#include "storage/write.h"
#include "common/harnessConfig.h"
#include "common/harnessFd.h"
#include "common/harnessFork.h"
#include "common/harnessLibSsh2.h"
#include "common/harnessSocket.h"
#include "common/harnessStorage.h"
/***********************************************************************************************************************************
Constants
***********************************************************************************************************************************/
#define HANDSHAKE_PARAM "["STRINGIFY(HRN_SCK_FILE_DESCRIPTOR)"]"
#define SSH2_NO_BLOCK_READING_WRITING 0
#define SSH2_BLOCK_READING 1
#define SSH2_BLOCK_WRITING 2
#define SSH2_BLOCK_READING_WRITING 3
/***********************************************************************************************************************************
Test function for path expression
***********************************************************************************************************************************/
#ifdef HAVE_LIBSSH2
static String *
storageTestPathExpression(const String *expression, const String *path)
{
String *result = NULL;
if (strcmp(strZ(expression), "<TEST>") == 0)
{
result = strCatZ(strNew(), "test");
if (path != NULL)
strCatFmt(result, "/%s", strZ(path));
}
else if (strcmp(strZ(expression), "<NULL>") != 0)
THROW_FMT(AssertError, "invalid expression '%s'", strZ(expression));
return result;
}
#endif // HAVE_LIBSSH2
/***********************************************************************************************************************************
Test Run
***********************************************************************************************************************************/
static void
testRun(void)
{
FUNCTION_HARNESS_VOID();
#ifdef HAVE_LIBSSH2
// Install shim to return defined fd
hrnSckClientOpenShimInstall();
// Install shim to manage true/false return for fdReady
hrnFdReadyShimInstall();
// Directory and file that cannot be accessed to test permissions errors
const String *fileNoPerm = STRDEF(TEST_PATH "/noperm/noperm");
String *pathNoPerm = strPath(fileNoPerm);
// Write file for testing if storage is read-only
const String *writeFile = STRDEF(TEST_PATH "/writefile");
unsigned int repoIdx = 0;
#endif // HAVE_LIBSSH2
// *****************************************************************************************************************************
if (testBegin("storageNew()"))
{
#ifdef HAVE_LIBSSH2
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("ssh2 init failure");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = -1},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 5, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB,
.hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT),
ServiceError, "unable to init libssh2");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("driver session failure");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]", .resultNull = true},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 5, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB,
.hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT),
ServiceError, "unable to init libssh2 session");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("handshake failure");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_WRITING},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = -1},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB,
.hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT),
ServiceError, "libssh2 handshake failed [-1]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("handshake failure - timeout during libssh2 handshake");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 100, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB,
.hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT),
ServiceError, "timeout during libssh2 handshake [-37]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("hostkey hash fail");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB,
.hostFingerprint = STRDEF("3132333435363738393039383736353433323130"),
.hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_FINGERPRINT),
ServiceError, "libssh2 hostkey hash failed: libssh2 errno [-7]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("invalid hostkey hash");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 20, KEYPRIV, cipherTypeAes256Cbc, .keyPub = KEYPUB,
.write = true, .hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT),
ServiceError, "requested ssh2 hostkey hash type (aes-256-cbc) not available");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("public key from file auth failure leading - tilde key paths");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", .resultInt = -16},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK},
{.function = NULL}
});
// Load configuration
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, "~/.ssh/id_rsa");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, "~/.ssh/id_rsa.pub");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "fingerprint");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"public key authentication failed: libssh2 error [-16]\n"
"HINT: libssh2 compiled against non-openssl libraries requires --repo-sftp-private-key-file and"
" --repo-sftp-public-key-file to be provided\n"
"HINT: libssh2 versions before 1.9.0 expect a PEM format keypair, try ssh-keygen -m PEM -t rsa -P \"\" to generate the"
" keypair");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("fingerprint mismatch");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"},
{.function = NULL}
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, "~/.ssh/id_rsa");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, "~/.ssh/id_rsa.pub");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "fingerprint");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "9132333435363738393039383736353433323130");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"host [3132333435363738393039383736353433323130] and configured fingerprint (repo-sftp-host-fingerprint)"
" [9132333435363738393039383736353433323130] do not match");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("known host init failure");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT, .resultNull = true},
{.function = NULL}
});
// Load configuration
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"failure during libssh2_knownhost_init");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("libssh2_session_hostkey fail - return NULL - hostKeyCheckType = yes");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = NULL}
});
// Load configuration
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"libssh2_session_hostkey failed to get hostkey: libssh2 error [-7]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_MISMATCH");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MISMATCH},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"known hosts failure: 'localhost' mismatch in known hosts files: LIBSSH2_KNOWNHOST_CHECK_MISMATCH [1]: check type "
"[strict]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_FAILURE");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_FAILURE},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError, "known hosts failure: 'localhost' LIBSSH2_KNOWNHOST_CHECK_FAILURE [3]: check type [strict]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_NOTFOUND");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"known hosts failure: 'localhost' not found in known hosts files: LIBSSH2_KNOWNHOST_CHECK_NOTFOUND [2]: check type"
" [strict]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("read known_hosts file failure - empty files - log INFO on empty known_hosts files");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 0},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", .resultInt = 0},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 0},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]", .resultInt = 0},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = NULL}
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"known hosts failure: 'localhost' not found in known hosts files: LIBSSH2_KNOWNHOST_CHECK_NOTFOUND [2]: check type"
" [strict]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_checkp unknown failure type");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = 5},
{.function = NULL}
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError, "known hosts failure: 'localhost' unknown failure [5]: check type [strict]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("public key from file auth failure, no public key");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",null,\"" KEYPRIV_CSTR "\",null]", .resultInt = -16},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"public key authentication failed: libssh2 error [-16]\n"
"HINT: libssh2 compiled against non-openssl libraries requires --repo-sftp-private-key-file and"
" --repo-sftp-public-key-file to be provided\n"
"HINT: libssh2 versions before 1.9.0 expect a PEM format keypair, try ssh-keygen -m PEM -t rsa -P \"\" to generate the"
" keypair");
TEST_RESULT_BOOL(
unsetenv("PGBACKREST_REPO1_SFTP_PRIVATE_KEY_PASSPHRASE"), 0, "unset PGBACKREST_REPO1_SFTP_PRIVATE_KEY_PASSPHRASE");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("public key from file LIBSSH2_ERROR_EAGAIN, failure");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = NULL}
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"timeout during public key authentication");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init failure ssh2 error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_INIT, .resultNull = true},
// storageSftpWaitFd returns false
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"unable to init libssh2_sftp session");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init fail && timeout");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_INIT, .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
// fdReady shim returns false --> storageSftpWaitFd returns false
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"timeout during init of libssh2_sftp session");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init fail no timeout");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_INIT, .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
// fdReady shim returns true --> storageSftpWaitFd returns true
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING},
{.function = HRNLIBSSH2_SFTP_INIT, .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = NULL}
});
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"unable to init libssh2_sftp session");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init success");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
HRNLIBSSH2_MACRO_SHUTDOWN()
});
Storage *storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_BOOL(storageTest->write, false, "check write");
// Free context, otherwise callbacks to storageSftpLibSsh2SessionFreeResource() accumulate
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_init WARN host key checking disabled, unsecure connections, hostKeyCheckType = no");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "none");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
// Free context, otherwise callbacks to storageSftpLibSsh2SessionFreeResource() accumulate
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_init WARN init fail for user's known_hosts file for update, hostKeyCheckType = accept-new");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT, .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERROR, .resultInt = LIBSSH2_ERROR_ALLOC,
.errMsg = (char *)"Unable to allocate memory for known-hosts collection"},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: libssh2_knownhost_init failed for '/home/" TEST_USER "/.ssh/known_hosts' for update: libssh2 errno [-6] "
"Unable to allocate memory for known-hosts collection");
// Free context, otherwise callbacks to storageSftpLibSsh2SessionFreeResource() accumulate
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_init WARN missing user's known_host file for update - hostKeyCheckType = accept-new");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: libssh2 unable to read '/home/" TEST_USER "/.ssh/known_hosts' for update: libssh2 errno [-16] Failed "
"to open file\n"
" HINT: does '/home/" TEST_USER "/.ssh/known_hosts' exist with proper permissions?");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_init WARN unable to read user's known_host file for update - hostKeyCheckType = accept-new");
// Create known_hosts file so it can be found by storageExistsP(), i.e. file exists but is unreadable
HRN_SYSTEM_FMT("touch %s", strZ(strNewFmt("%s/.ssh/known_hosts", strZ(userHome()))));
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: libssh2 unable to read '/home/" TEST_USER "/.ssh/known_hosts' for update: libssh2 errno [-16] Failed "
"to open file\n"
" HINT: does '/home/" TEST_USER "/.ssh/known_hosts' exist with proper permissions?");
// Remove known_hosts file
HRN_SYSTEM_FMT("rm %s", strZ(strNewFmt("%s/.ssh/known_hosts", strZ(userHome()))));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_init WARN fail to load user's known_host file with error other than LIBSSH2_ERROR_FILE");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_KNOWN_HOSTS},
{.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to parse known hosts file",
.resultInt = LIBSSH2_ERROR_KNOWN_HOSTS},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: libssh2 unable to read '/home/" TEST_USER "/.ssh/known_hosts' for update: libssh2 errno [-46] Failed to "
"parse known hosts file\n"
" HINT: does '/home/" TEST_USER "/.ssh/known_hosts' exist with proper permissions?");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init success - hostKeyCheckType = accept-new - add host to user's known_hosts file RSA");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_ADDC,
.param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"},
{.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init success - hostKeyCheckType = accept-new - add host to user's known_hosts file DSS");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_DSS, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_ADDC,
.param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,851969]"},
{.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init success - hostKeyCheckType = accept-new - add host to user's known_hosts ECDSA_256");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_ECDSA_256, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_ADDC,
.param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,1114113]"},
{.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#endif
#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init success - hostKeyCheckType = accept_new - add host to user's known_hosts ECDSA_384");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_ECDSA_384, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_ADDC,
.param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,1376257]"},
{.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#endif
#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init success - hostKeyCheckType = accept-new - add host to user's known_hosts ECDSA_521");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_ECDSA_521, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_ADDC,
.param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,1638401]"},
{.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#endif
#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init success - hostKeyCheckType = accept-new - add host to user's known_hosts ED25519");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_ED25519, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_ADDC,
.param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,1900545]"},
{.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#endif
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init WARN - hostKeyCheckType = accept-new - fail to write user's known_hosts file");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_ADDC,
.param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"},
{.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_FILE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: pgBackRest unable to write '/home/" TEST_USER "/.ssh/known_hosts' for update");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init WARN - hostKeyCheckType = accept-new, add to user's known_hosts - unknown key type");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = 9, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: unsupported key type [9], unable to update knownhosts for 'localhost'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init WARN - hostKeyCheckType = accept-new - add host to user's known_hosts failure");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_ADDC, .resultInt = LIBSSH2_ERROR_KNOWN_HOSTS,
.param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: pgBackRest failed to add 'localhost' to known_hosts internal list");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_FAILURE hostKeyCheckType = accept-new");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_FAILURE},
{.function = NULL},
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError, "known hosts failure: 'localhost': LIBSSH2_KNOWNHOST_CHECK_FAILURE [3]: check type [accept-new]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_MISMATCH hostKeyCheckType = accept-new");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MISMATCH},
{.function = NULL},
});
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"known hosts failure: 'localhost': mismatch in known hosts files: LIBSSH2_KNOWNHOST_CHECK_MISMATCH [1]: check type"
" [accept-new]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init success LIBSSH2_KNOWNHOST_CHECK_MISMATCH hostKeyCheckType = accept-new");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",null,\"" KEYPRIV_CSTR "\",null]", .resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init WARN - hostKeyCheckType = accept-new - add host to user's known_hosts");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_ADDC,
.param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"},
{.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
storageTest = NULL;
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx),
.keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_LOG(
"P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to "
"'/home/" TEST_USER "/.ssh/known_hosts'\n"
"P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session failure - libssh2_session_hostkey fail - hostKeyCheckType = accept-new");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = NULL}
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"libssh2_session_hostkey failed to get hostkey: libssh2 error [-7]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp session init success timeout");
// Shim sets FD for tests.
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_INIT, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_BOOL(storageTest->write, false, "check write");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("create new storage with defaults && a single known_hosts file with leading tilde");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"/home/" TEST_USER "/.ssh/pgbackrest_known_hosts\",1]",
.resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_INIT, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, "/tmp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, "~/.ssh/pgbackrest_known_hosts");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "strict");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (defaults)");
TEST_RESULT_STR_Z(storageTest->path, "/tmp", "check path");
TEST_RESULT_INT(storageTest->modeFile, 0640, "check file mode");
TEST_RESULT_INT(storageTest->modePath, 0750, "check path mode");
TEST_RESULT_BOOL(storageTest->write, false, "check write");
TEST_RESULT_STR_Z(
strLstGet(strLstNewVarLst(cfgOptionLst(cfgOptRepoSftpKnownHost)), 0), "~/.ssh/pgbackrest_known_hosts",
"check known hosts path");
TEST_RESULT_BOOL(storageTest->pathExpressionFunction == NULL, true, "check expression function is not set");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("create new storage - override defaults");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, "/path/to");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, "~/.ssh/known_hosts");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = 0600,
.modePath = 0700, .write = true, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage (non-default)");
TEST_RESULT_STR_Z(storageTest->path, "/path/to", "check path");
TEST_RESULT_INT(storageTest->modeFile, 0600, "check file mode");
TEST_RESULT_INT(storageTest->modePath, 0700, "check path mode");
TEST_RESULT_BOOL(storageTest->write, true, "check write");
TEST_RESULT_BOOL(storageTest->pathExpressionFunction == NULL, true, "check expression function is empty");
TEST_RESULT_PTR(storageInterface(storageTest).info, storageTest->pub.interface.info, "check interface");
TEST_RESULT_PTR(storageDriver(storageTest), storageTest->pub.driver, "check driver");
TEST_RESULT_UINT(storageType(storageTest), storageTest->pub.type, "check type");
TEST_RESULT_BOOL(storageFeature(storageTest, storageFeaturePath), true, "check path feature");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("public key from file auth failure, key passphrase");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",\"keyPassphrase\"]",
.resultInt = -16},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK},
{.function = NULL}
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgEnvKeyRawZ(cfgOptRepoSftpPrivateKeyPassphrase, 1, "keyPassphrase");
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ERROR(
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
ServiceError,
"public key authentication failed: libssh2 error [-16]\n"
"HINT: libssh2 compiled against non-openssl libraries requires --repo-sftp-private-key-file and"
" --repo-sftp-public-key-file to be provided\n"
"HINT: libssh2 versions before 1.9.0 expect a PEM format keypair, try ssh-keygen -m PEM -t rsa -P \"\" to generate the"
" keypair");
TEST_RESULT_BOOL(
unsetenv("PGBACKREST_REPO1_SFTP_PRIVATE_KEY_PASSPHRASE"), 0, "unset PGBACKREST_REPO1_SFTP_PRIVATE_KEY_PASSPHRASE");
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageExists() and storagePathExists()"))
{
#ifdef HAVE_LIBSSH2
// Mimic creation of /noperm/noperm for permission denied
// drwx------ 2 root root 3 Dec 5 15:30 noperm
// noperm/:
// total 1
// -rw------- 1 root root 0 Dec 5 15:30 noperm
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// File missing
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/missing\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/missing\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE, .sleep = 100},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/missing\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/missing\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/missing\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Path missing
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "\",0]",
.attrPerms = LIBSSH2_SFTP_S_IFDIR, .resultInt = LIBSSH2_ERROR_NONE},
// Permission denied
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
// File and path
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/exists\",0]",
.attrPerms = LIBSSH2_SFTP_S_IFREG, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pathExists\",0]",
.attrPerms = LIBSSH2_SFTP_S_IFDIR, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/exists\",0]",
.attrPerms = LIBSSH2_SFTP_S_IFREG, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pathExists\",0]",
.attrPerms = LIBSSH2_SFTP_S_IFDIR, .resultInt = LIBSSH2_ERROR_NONE},
// File exists after wait
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/exists\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/exists\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/exists\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/exists\",0]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/exists\",0]",
.attrPerms = LIBSSH2_SFTP_S_IFREG, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "strict");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
Storage *storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("file");
TEST_RESULT_BOOL(storageExistsP(storageTest, STRDEF("missing")), false, "file does not exist");
TEST_RESULT_BOOL(storageExistsP(storageTest, STRDEF("missing"), .timeout = 100), false, "file does not exist");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path");
TEST_RESULT_BOOL(storagePathExistsP(storageTest, STRDEF("missing")), false, "path does not exist");
TEST_RESULT_BOOL(storagePathExistsP(storageTest, NULL), true, "test path exists");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("permission denied");
TEST_ERROR_FMT(storageExistsP(storageTest, fileNoPerm), FileOpenError, STORAGE_ERROR_INFO, strZ(fileNoPerm));
TEST_ERROR_FMT(storagePathExistsP(storageTest, fileNoPerm), FileOpenError, STORAGE_ERROR_INFO, strZ(fileNoPerm));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("file and path");
const String *fileExists = STRDEF(TEST_PATH "/exists");
const String *pathExists = STRDEF(TEST_PATH "/pathExists");
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_BOOL(storagePathExistsP(storageTest, pathExists), true, "path exists");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("file after wait");
HRN_FORK_BEGIN()
{
HRN_FORK_CHILD_BEGIN()
{
sleepMSec(250);
// Mimic HRN_SYSTEM_FMT("touch %s", strZ(fileExists));
}
HRN_FORK_CHILD_END();
HRN_FORK_PARENT_BEGIN()
{
TEST_RESULT_BOOL(storageExistsP(storageTest, fileExists, .timeout = 1000), true, "file exists after wait");
}
HRN_FORK_PARENT_END();
}
HRN_FORK_END();
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageInfo()"))
{
#ifdef HAVE_LIBSSH2
// File open error via permission denied sftp error
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",1]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
Storage *storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR_FMT(storageInfoP(storageTest, fileNoPerm), FileOpenError, STORAGE_ERROR_INFO, strZ(fileNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// File open error via ssh error - covers storageSftpLibSsh2FxNoSuchFile where rc != LIBSSH2_ERROR_SFTP_PROTOCOL
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",1]", .resultInt = LIBSSH2_ERROR_INVAL},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR_FMT(storageInfoP(storageTest, fileNoPerm), FileOpenError, STORAGE_ERROR_INFO, strZ(fileNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info for / exists");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"/\",1]", .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, strZ(FSLASH_STR));
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "strict");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_RESULT_BOOL(storageInfoP(storageTest, NULL).exists, true, "info for /");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info for / does not exist with no path feature");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
HRNLIBSSH2_MACRO_SHUTDOWN()
});
Storage *storageRootNoPath = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
storageRootNoPath->pub.interface.feature ^= 1 << storageFeaturePath;
TEST_RESULT_BOOL(storageInfoP(storageRootNoPath, NULL, .ignoreMissing = true).exists, false, "no info for /");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageRootNoPath)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("directory does not exist");
const String *fileName = STRDEF(TEST_PATH "/fileinfo");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// File does not exist
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/fileinfo\",1]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/fileinfo\",1]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Info out of base path - first test libssh2_sftp_stat_ex throws error before reaching libssh2 code second test
// libssh2_sftp_stat_stat_ex reaches libssh2 code
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"/etc\",1]", .resultInt = LIBSSH2_ERROR_NONE},
// Info - path
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// Info - path exists only
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// Info basic - path
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// Info - file
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/fileinfo\",1]",
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1555155555, .uid = 99999, .gid = 99999, .filesize = 8},
// Info - link
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/testlink\",1]",
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG | LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/testlink\",\"\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .symlinkExTarget = STRDEF("/tmp")},
// Info - link .followLink = true
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/testlink\",0]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/testlink\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG | LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.uid = 0, .gid = 0},
// Info - link .followLink = true, timeout EAGAIN in followLink
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/testlink\",0]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
// Info - link .followLink = false, timeout EAGAIN
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/testlink\",1]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
// Info - link .followLink = false, libssh2_sftp_symlink_ex link destination size timeout
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/testlink\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG | LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/testlink\",\"\",1]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
// Info - link .followLink = false, libssh2_sftp_symlink_ex link destination size fail
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/testlink\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG | LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/testlink\",\"\",1]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/testlink\",\"\",1]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
// Info - pipe
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/testpipe\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP | LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IWOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "strict");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR_FMT(storageInfoP(storageTest, fileName), FileOpenError, STORAGE_ERROR_INFO_MISSING, strZ(fileName));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("file does not exist");
StorageInfo info = {0};
TEST_ASSIGN(info, storageInfoP(storageTest, fileName, .ignoreMissing = true), "get file info (missing)");
TEST_RESULT_BOOL(info.exists, false, "check not exists");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info outside of base path");
TEST_ERROR(
storageInfoP(storageTest, STRDEF("/etc"), .ignoreMissing = true), AssertError,
"absolute path '/etc' is not in base path '" TEST_PATH "'");
TEST_RESULT_BOOL(
storageInfoP(storageTest, STRDEF("/etc"), .ignoreMissing = true, .noPathEnforce = true).exists, true,
"path not enforced");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info - path");
HRN_STORAGE_TIME(storageTest, TEST_PATH, 1555160000);
TEST_ASSIGN(info, storageInfoP(storageTest, TEST_PATH_STR), "get path info");
TEST_RESULT_STR(info.name, NULL, "name is not set");
TEST_RESULT_BOOL(info.exists, true, "check exists");
TEST_RESULT_INT(info.type, storageTypePath, "check type");
TEST_RESULT_UINT(info.size, 0, "check size");
TEST_RESULT_INT(info.mode, 0770, "check mode");
TEST_RESULT_INT(info.timeModified, 1555160000, "check mod time");
TEST_RESULT_STR(info.linkDestination, NULL, "no link destination");
TEST_RESULT_UINT(info.userId, TEST_USER_ID, "check user id");
TEST_RESULT_STR(info.user, NULL, "check user");
TEST_RESULT_UINT(info.groupId, TEST_GROUP_ID, "check group id");
TEST_RESULT_STR(info.group, NULL, "check group");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info - path existence only");
TEST_ASSIGN(info, storageInfoP(storageTest, TEST_PATH_STR, .level = storageInfoLevelExists), "path exists");
TEST_RESULT_BOOL(info.exists, true, "check exists");
TEST_RESULT_UINT(info.size, 0, "check exists");
TEST_RESULT_INT(info.timeModified, 0, "check time");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info basic - path");
storageTest->pub.interface.feature ^= 1 << storageFeatureInfoDetail;
TEST_ASSIGN(info, storageInfoP(storageTest, TEST_PATH_STR), "get path info");
TEST_RESULT_STR(info.name, NULL, "name is not set");
TEST_RESULT_BOOL(info.exists, true, "check exists");
TEST_RESULT_INT(info.type, storageTypePath, "check type");
TEST_RESULT_UINT(info.size, 0, "check size");
TEST_RESULT_INT(info.mode, 0, "check mode");
TEST_RESULT_INT(info.timeModified, 1555160000, "check mod time");
TEST_RESULT_STR(info.linkDestination, NULL, "no link destination");
TEST_RESULT_UINT(info.userId, 0, "check user id");
TEST_RESULT_STR(info.user, NULL, "check user");
TEST_RESULT_UINT(info.groupId, 0, "check group id");
TEST_RESULT_STR(info.group, NULL, "check group");
storageTest->pub.interface.feature ^= 1 << storageFeatureInfoDetail;
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info - file");
// Mimic file chown'd 99999:99999, timestamp 1555155555, containing "TESTFILE"
TEST_ASSIGN(info, storageInfoP(storageTest, fileName), "get file info");
TEST_RESULT_STR(info.name, NULL, "name is not set");
TEST_RESULT_BOOL(info.exists, true, "check exists");
TEST_RESULT_INT(info.type, storageTypeFile, "check type");
TEST_RESULT_UINT(info.size, 8, "check size");
TEST_RESULT_INT(info.mode, 0640, "check mode");
TEST_RESULT_INT(info.timeModified, 1555155555, "check mod time");
TEST_RESULT_STR(info.linkDestination, NULL, "no link destination");
TEST_RESULT_STR(info.user, NULL, "check user");
TEST_RESULT_STR(info.group, NULL, "check group");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info - link");
const String *linkName = STRDEF(TEST_PATH "/testlink");
// Mimic link testlink to /tmp
TEST_ASSIGN(info, storageInfoP(storageTest, linkName), "get link info");
TEST_RESULT_STR(info.name, NULL, "name is not set");
TEST_RESULT_BOOL(info.exists, true, "check exists");
TEST_RESULT_INT(info.type, storageTypeLink, "check type");
TEST_RESULT_UINT(info.size, 0, "check size");
TEST_RESULT_INT(info.mode, 0777, "check mode");
TEST_RESULT_STR_Z(info.linkDestination, "/tmp", "check link destination");
TEST_RESULT_STR(info.user, NULL, "check user");
TEST_RESULT_STR(info.group, NULL, "check group");
TEST_ASSIGN(info, storageInfoP(storageTest, linkName, .followLink = true), "get info from path pointed to by link");
TEST_RESULT_STR(info.name, NULL, "name is not set");
TEST_RESULT_BOOL(info.exists, true, "check exists");
TEST_RESULT_INT(info.type, storageTypePath, "check type");
TEST_RESULT_UINT(info.size, 0, "check size");
TEST_RESULT_INT(info.mode, 0777, "check mode");
TEST_RESULT_STR(info.linkDestination, NULL, "check link destination");
TEST_RESULT_STR_Z(info.user, NULL, "check user");
TEST_RESULT_STR_Z(info.group, NULL, "check group");
// Exercise paths/branches
// libssh2_sftp_stat_ex timeout EAGAIN followLink true
TEST_ERROR_FMT(
storageInfoP(storageTest, linkName, .followLink = true), FileOpenError, "timeout opening '" TEST_PATH "/testlink'");
// libssh2_sftp_stat_ex timeout EAGAIN followLink false
TEST_ERROR_FMT(
storageInfoP(storageTest, linkName, .followLink = false), FileOpenError, "timeout opening '" TEST_PATH "/testlink'");
// libssh2_sftp_symlink_ex link destination timeout EAGAIN followLink false
TEST_ERROR_FMT(
storageInfoP(storageTest, linkName, .followLink = false), FileReadError,
"timeout getting destination for link '" TEST_PATH "/testlink'");
// libssh2_sftp_symlink_ex fail link destination followLink false
TEST_ERROR_FMT(
storageInfoP(storageTest, linkName, .followLink = false), FileReadError,
"unable to get destination for link '" TEST_PATH "/testlink'");
// --------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info - pipe");
const String *pipeName = STRDEF(TEST_PATH "/testpipe");
// Mimic pipe "/testpipe" with mode 0666
TEST_ASSIGN(info, storageInfoP(storageTest, pipeName), "get info from pipe (special file)");
TEST_RESULT_STR(info.name, NULL, "name is not set");
TEST_RESULT_BOOL(info.exists, true, "check exists");
TEST_RESULT_INT(info.type, storageTypeSpecial, "check type");
TEST_RESULT_UINT(info.size, 0, "check size");
TEST_RESULT_INT(info.mode, 0666, "check mode");
TEST_RESULT_STR(info.linkDestination, NULL, "check link destination");
TEST_RESULT_STR(info.user, NULL, "check user");
TEST_RESULT_STR(info.group, NULL, "check group");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageNewItrP()"))
{
#ifdef HAVE_LIBSSH2
// Mimic creation of /noperm/noperm
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Path missing errorOnMissing true
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/BOGUS\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/BOGUS\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Ignore missing dir
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/BOGUS\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Path no perm
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
// Path no perm ignore missing
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
// Helper function storageSftpListEntry()
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"pg/missing\",1]", .resultNull = true},
// Path with only dot
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IWOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IWOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// Path with file, link, pipe, dot dotdot
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IWOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg\",0,0,1]"},
// readdir returns .
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns ..
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".\",4095,null,0]", .fileName = STRDEF(".."),
.resultInt = 8, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns .include
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"..\",4095,null,0]", .fileName = STRDEF(".include"),
.resultInt = 8, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/.include\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".include\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns link
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF("link"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/pg/link\",\"\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .symlinkExTarget = STRDEF("../file")},
// readdir returns pipe
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"link\",4095,null,0]", .fileName = STRDEF("pipe"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/pipe\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"pipe\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/.include\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IWOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/pg/link\",\"\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .symlinkExTarget = STRDEF("../file")},
// Helper function - storageSftpListEntry() info doesn't exist
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"pg/missing\",1]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"pg/missing\",1]", .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "strict");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
// Create storage object for testing
Storage *storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path missing");
TEST_ERROR_FMT(
storageNewItrP(storageTest, STRDEF(BOGUS_STR), .errorOnMissing = true), PathMissingError,
STORAGE_ERROR_LIST_INFO_MISSING, TEST_PATH "/BOGUS");
TEST_RESULT_PTR(storageNewItrP(storageTest, STRDEF(BOGUS_STR), .nullOnMissing = true), NULL, "ignore missing dir");
TEST_ERROR_FMT(
storageNewItrP(storageTest, pathNoPerm, .errorOnMissing = true), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathNoPerm));
// Should still error even when ignore missing
TEST_ERROR_FMT(
storageNewItrP(storageTest, pathNoPerm), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathNoPerm));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("helper function - storageSftpListEntry()");
TEST_RESULT_VOID(
storageSftpListEntry(
(StorageSftp *)storageDriver(storageTest), storageLstNew(storageInfoLevelBasic), STRDEF("pg"), "missing",
storageInfoLevelBasic),
"missing path");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path with only dot");
// Mimic creation of TEST_PATH "/pg" mode 0766
// NOTE: if operating against an actual sftp server, a neutral umask is required to get the proper permissions.
// Without the neutral umask, permissions were 0764.
TEST_STORAGE_LIST(
storageTest, "pg",
"./ {u=" TEST_USER_ID_Z ", g=" TEST_GROUP_ID_Z ", m=0766}\n",
.level = storageInfoLevelDetail, .includeDot = true);
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path with file, link, pipe");
// Mimic creation of TEST_PATH "/pg/.include" mode 0755 chown'd 77777:77777
// Mimic creation of TEST_PATH "pg/file" mode 0660 timemodified 1656433838 containing "TESTDATA"
// Mimic creation of TEST_PATH "/pg/link" linked to "../file"
// Mimic creation of TEST_PATH "/pg/pipe" mode 777
TEST_STORAGE_LIST(
storageTest, "pg",
"./ {u=" TEST_USER_ID_Z ", g=" TEST_GROUP_ID_Z ", m=0766}\n"
".include/ {u=77777, g=77777, m=0755}\n"
"file {s=8, t=1656433838, u=" TEST_USER_ID_Z ", g=" TEST_GROUP_ID_Z ", m=0660}\n"
"link> {d=../file, u=" TEST_USER_ID_Z ", g=" TEST_GROUP_ID_Z "}\n"
"pipe*\n",
.level = storageInfoLevelDetail, .includeDot = true);
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("helper function - storageSftpListEntry() info doesn't exist");
TEST_RESULT_VOID(
storageSftpListEntry(
(StorageSftp *)storageDriver(storageTest), storageLstNew(storageInfoLevelBasic), STRDEF("pg"), "missing",
storageInfoLevelBasic),
"missing path");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageItrMore() twice in a row");
StorageIterator *storageItr = NULL;
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".\",4095,null,0]", .fileName = STRDEF(".include"),
.resultInt = 8, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/.include\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".include\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns link
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF("link"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/pg/link\",\"\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .symlinkExTarget = STRDEF("../file")},
// readdir returns pipe
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"link\",4095,null,0]", .fileName = STRDEF("pipe"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/pipe\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"pipe\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)));
TEST_ASSIGN(storageItr, storageNewItrP(storageTest, STRDEF("pg")), "new iterator");
TEST_RESULT_BOOL(storageItrMore(storageItr), true, "check more");
TEST_RESULT_BOOL(storageItrMore(storageItr), true, "check more again");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path - recurse desc");
// Mimic creation of "pg/path" mode 0700
// Mimic creation of "pg/path/file" mode 0600 timemodified 1656434296 containing "TESTDATA"
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".\",4095,null,0]", .fileName = STRDEF("path"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"path\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns link
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF("link"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
// readdir returns pipe
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"link\",4095,null,0]", .fileName = STRDEF("pipe"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/pipe\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"pipe\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse readdir path
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/path\",0,0,1]"},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/pg/link\",\"\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .symlinkExTarget = STRDEF("../file")},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)));
TEST_STORAGE_LIST(
storageTest, "pg",
"pipe*\n"
"path/file {s=8, t=1656434296}\n"
"path/\n"
"link> {d=../file}\n"
"file {s=8, t=1656433838}\n"
"./\n",
.level = storageInfoLevelBasic, .includeDot = true, .sortOrder = sortOrderDesc);
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path - recurse asc");
// Create a path with a subpath that will always be last to make sure lists are not freed too early in the iterator
// Mimic creation of "pg/zzz/yyy" mode 0700
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg\",0,0,1]"},
// readdir returns dot
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns path
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".\",4095,null,0]", .fileName = STRDEF("path"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"path\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns link
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF("link"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
// readdir returns pipe
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"link\",4095,null,0]", .fileName = STRDEF("pipe"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/pipe\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns zzz
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"pipe\",4095,null,0]", .fileName = STRDEF("zzz"),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/zzz\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir return empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"zzz\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse readdir path
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/path\",0,0,1]"},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse zzz
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/zzz\",0,0,1]"},
// readdir returns yyy
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("yyy"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/zzz/yyy\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"yyy\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse yyy
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/zzz/yyy\",0,0,1]"},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/pg/link\",\"\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .symlinkExTarget = STRDEF("../file")},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)));
TEST_STORAGE_LIST(
storageTest, "pg",
"./\n"
"file {s=8, t=1656433838}\n"
"link> {d=../file}\n"
"path/\n"
"path/file {s=8, t=1656434296}\n"
"pipe*\n"
"zzz/\n"
"zzz/yyy/\n",
.level = storageInfoLevelBasic, .includeDot = true);
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path basic info - recurse");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg\",0,0,1]"},
// readdir returns dot
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns path
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".\",4095,null,0]", .fileName = STRDEF("path"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"path\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns link
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF("link"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
// readdir returns pipe
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"link\",4095,null,0]", .fileName = STRDEF("pipe"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/pipe\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns zzz
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"pipe\",4095,null,0]", .fileName = STRDEF("zzz"),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/zzz\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir return empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"zzz\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse zzz
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/zzz\",0,0,1]"},
// readdir returns yyy
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("yyy"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/zzz/yyy\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"yyy\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse yyy
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/zzz/yyy\",0,0,1]"},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse path
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/path\",0,0,1]"},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
{.function = HRNLIBSSH2_SFTP_SYMLINK_EX, .param = "[\"" TEST_PATH "/pg/link\",\"\",1]",
.resultInt = LIBSSH2_ERROR_NONE, .symlinkExTarget = STRDEF("../file")},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)));
storageTest->pub.interface.feature ^= 1 << storageFeatureInfoDetail;
TEST_STORAGE_LIST(
storageTest, "pg",
"zzz/yyy/\n"
"zzz/\n"
"pipe*\n"
"path/file {s=8, t=1656434296}\n"
"path/\n"
"link> {d=../file}\n"
"file {s=8, t=1656433838}\n"
"./\n",
.levelForce = true, .includeDot = true, .sortOrder = sortOrderDesc);
storageTest->pub.interface.feature ^= 1 << storageFeatureInfoDetail;
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("empty path - filter");
// Mimic "pg/empty" mode 0700
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg\",0,0,1]"},
// readdir returns dot
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".\",4095,null,0]", .fileName = STRDEF("empty"),
.resultInt = 5, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/empty\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
// readdir returns path
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"empty\",4095,null,0]", .fileName = STRDEF("path"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"path\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns link
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF("link"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
// readdir returns pipe
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"link\",4095,null,0]", .fileName = STRDEF("pipe"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/pipe\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns zzz
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"pipe\",4095,null,0]", .fileName = STRDEF("zzz"),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/zzz\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir return empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"zzz\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse empty
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/empty\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse path
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/path\",0,0,1]"},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse zzz
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/zzz\",0,0,1]"},
// readdir returns yyy
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("yyy"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/zzz/yyy\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"yyy\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse yyy
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/zzz/yyy\",0,0,1]"},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)));
TEST_STORAGE_LIST(
storageTest, "pg",
"empty/\n",
.level = storageInfoLevelType, .expression = "^empty");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("filter in subpath during recursion");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg\",0,0,1]"},
// readdir returns dot
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns path
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".\",4095,null,0]", .fileName = STRDEF("path"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = 77777, .gid = 77777},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"path\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns link
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF("link"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/link\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFLNK | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .symlinkExTarget = STRDEF("../file")},
// readdir returns pipe
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"link\",4095,null,0]", .fileName = STRDEF("pipe"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/pipe\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFIFO | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns zzz
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"pipe\",4095,null,0]", .fileName = STRDEF("zzz"),
.resultInt = 3, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/zzz\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir return empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"zzz\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse path
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/path\",0,0,1]"},
// readdir returns file
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("file"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/path/file\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IWGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID, .filesize = 8},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"file\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse zzz
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/zzz\",0,0,1]"},
// readdir returns yyy
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("yyy"),
.resultInt = 4, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/pg/zzz/yyy\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IWGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"yyy\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656433838, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Recurse yyy
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/pg/zzz/yyy\",0,0,1]"},
// readdir returns empty
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)));
TEST_STORAGE_LIST(
storageTest, "pg",
"path/file {s=8, t=1656434296}\n",
.level = storageInfoLevelBasic, .expression = "\\/file$");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageList()"))
{
#ifdef HAVE_LIBSSH2
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path missing");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/BOGUS\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/BOGUS\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Empty list
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/BOGUS\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Timeout on sftp_open_ex
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/BOGUS\",0,0,1]", .resultNull = true,
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/BOGUS\",0,0,1]", .resultNull = true,
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
// Error on missing, regardless of errorOnMissing setting
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
// Ignore missing
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
Storage *storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)));
TEST_ERROR_FMT(
storageListP(storageTest, STRDEF(BOGUS_STR), .errorOnMissing = true), PathMissingError, STORAGE_ERROR_LIST_INFO_MISSING,
TEST_PATH "/BOGUS");
TEST_RESULT_PTR(storageListP(storageTest, STRDEF(BOGUS_STR), .nullOnMissing = true), NULL, "null for missing dir");
TEST_RESULT_UINT(strLstSize(storageListP(storageTest, STRDEF(BOGUS_STR))), 0, "empty list for missing dir");
// Timeout on sftp_open_ex
TEST_ERROR_FMT(
storageListP(storageTest, STRDEF(BOGUS_STR), .errorOnMissing = true), FileReadError,
"timeout opening directory '" TEST_PATH "/BOGUS'");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("error on missing, regardless of errorOnMissing setting");
TEST_ERROR_FMT(
storageListP(storageTest, pathNoPerm, .errorOnMissing = true), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathNoPerm));
// Should still error even when ignore missing
TEST_ERROR_FMT(
storageListP(storageTest, pathNoPerm), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("list - path with files");
ioBufferSizeSet(65536);
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// storagePutP(storageNewWriteP())
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/.aaa.txt.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[14]", .resultInt = 14},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX, .resultInt = LIBSSH2_ERROR_EAGAIN,
.param = "[\"" TEST_PATH "/.aaa.txt.pgbackrest.tmp\",\"" TEST_PATH "/.aaa.txt\",7]"},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_RENAME_EX, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL,
.param = "[\"" TEST_PATH "/.aaa.txt.pgbackrest.tmp\",\"" TEST_PATH "/.aaa.txt\",7]"},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/.aaa.txt\"]", .resultUInt = LIBSSH2_FX_OK},
{.function = HRNLIBSSH2_SFTP_RENAME_EX, .resultInt = LIBSSH2_ERROR_NONE,
.param = "[\"" TEST_PATH "/.aaa.txt.pgbackrest.tmp\",\"" TEST_PATH "/.aaa.txt\",7]"},
// strListSort(storageListP())
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF(".aaa.txt"),
.resultInt = 8, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/.aaa.txt\",1]", .fileName = STRDEF(".aaa.txt"),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\".aaa.txt\",4095,null,0]", .fileName = STRDEF("noperm"),
.resultInt = 6, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/noperm\",1]", .fileName = STRDEF("noperm"),
.resultInt = LIBSSH2_ERROR_NONE, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"noperm\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// bbb.txt
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/bbb.txt.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[7]", .resultInt = 7},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/bbb.txt.pgbackrest.tmp\",\"" TEST_PATH "/bbb.txt\",7]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("bbb.txt"),
.resultInt = 7, .attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/bbb.txt\",1]", .fileName = STRDEF("bbb.txt"),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"bbb.txt\",4095,null,0]", .fileName = STRDEF("noperm"),
.resultInt = 6, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/noperm\",1]", .fileName = STRDEF("noperm"),
.resultInt = LIBSSH2_ERROR_NONE, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"noperm\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Path with only dot, readdir timeout EAGAIN
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .resultInt = LIBSSH2_ERROR_EAGAIN, .param = "[\"\",4095,null,0]"},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .resultInt = LIBSSH2_ERROR_EAGAIN, .param = "[\"\",4095,null,0]"},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// Fail to close path after listing timeout EAGAIN
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
// Fail to close path after listing
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("."),
.resultInt = LIBSSH2_ERROR_NONE, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1555160000, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_SOCKET_RECV},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Create storage object for testing
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_RESULT_VOID(
storagePutP(storageNewWriteP(storageTest, STRDEF(".aaa.txt")), BUFSTRDEF("aaaaaaaaaaaaaa")), "write aaa.text");
TEST_RESULT_STRLST_Z(strLstSort(storageListP(storageTest, NULL), sortOrderAsc), ".aaa.txt\n" "noperm\n", "dir list");
TEST_RESULT_VOID(storagePutP(storageNewWriteP(storageTest, STRDEF("bbb.txt")), BUFSTRDEF("bbb.txt")), "write bbb.text");
TEST_RESULT_STRLST_Z(storageListP(storageTest, NULL, .expression = STRDEF("^bbb")), "bbb.txt\n", "dir list");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpList() readdir EAGAIN timeout");
TEST_RESULT_VOID(storageListP(storageTest, NULL, .errorOnMissing = true), "storageSftpList readdir EAGAIN timeout");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpList() fail to close path after listing EAGAIN timeout");
TEST_ERROR_FMT(
storageListP(storageTest, NULL, .errorOnMissing = true), PathCloseError,
"timeout closing path '" TEST_PATH "' after listing");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpList() fail to close path after listing");
TEST_ERROR_FMT(
storageListP(storageTest, NULL, .errorOnMissing = true), PathCloseError,
"unable to close path '" TEST_PATH "' after listing");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storagePath()"))
{
#ifdef HAVE_LIBSSH2
Storage *storageTest = NULL;
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path - root path");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
HRNLIBSSH2_MACRO_SHUTDOWN()
});
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, strZ(FSLASH_STR));
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "strict");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))),
"new storage /");
TEST_RESULT_STR_Z(storagePathP(storageTest, NULL), "/", "root dir");
TEST_RESULT_STR_Z(storagePathP(storageTest, STRDEF("/")), "/", "same as root dir");
TEST_RESULT_STR_Z(storagePathP(storageTest, STRDEF("subdir")), "/subdir", "simple subdir");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path - expressions");
TEST_ERROR(
storagePathP(storageTest, STRDEF("<TEST>")), AssertError, "expression '<TEST>' not valid without callback function");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, "/path/to");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "strict");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)),
.pathExpressionFunction = storageTestPathExpression),
"new storage /path/to");
TEST_RESULT_STR_Z(storagePathP(storageTest, NULL), "/path/to", "root dir");
TEST_RESULT_STR_Z(storagePathP(storageTest, STRDEF("/path/to")), "/path/to", "absolute root dir");
TEST_RESULT_STR_Z(storagePathP(storageTest, STRDEF("is/a/subdir")), "/path/to/is/a/subdir", "subdir");
TEST_ERROR(
storagePathP(storageTest, STRDEF("/bogus")), AssertError, "absolute path '/bogus' is not in base path '/path/to'");
TEST_ERROR(
storagePathP(storageTest, STRDEF("/path/toot")), AssertError,
"absolute path '/path/toot' is not in base path '/path/to'");
// Path enforcement disabled for a single call
TEST_RESULT_STR_Z(storagePathP(storageTest, STRDEF("/bogus"), .noEnforce = true), "/bogus", "path enforce disabled");
TEST_ERROR(storagePathP(storageTest, STRDEF("<TEST")), AssertError, "end > not found in path expression '<TEST'");
TEST_ERROR(
storagePathP(storageTest, STRDEF("<TEST>" BOGUS_STR)), AssertError,
"'/' should separate expression and path '<TEST>BOGUS'");
TEST_RESULT_STR_Z(storagePathP(storageTest, STRDEF("<TEST>")), "/path/to/test", "expression");
TEST_ERROR(strZ(storagePathP(storageTest, STRDEF("<TEST>/"))), AssertError, "path '<TEST>/' should not end in '/'");
TEST_RESULT_STR_Z(
storagePathP(storageTest, STRDEF("<TEST>/something")), "/path/to/test/something", "expression with path");
TEST_ERROR(storagePathP(storageTest, STRDEF("<NULL>")), AssertError, "evaluated path '<NULL>' cannot be null");
TEST_ERROR(storagePathP(storageTest, STRDEF("<WHATEVS>")), AssertError, "invalid expression '<WHATEVS>'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storagePathCreate()"))
{
#ifdef HAVE_LIBSSH2
Storage *storageTest = NULL;
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Create /sub1
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub1\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// create /sub1 again fails mkdir_ex ssh error
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]",
.resultInt = LIBSSH2_ERROR_SOCKET_SEND},
// create /sub1 again no error on file already exists, file already exists
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub1\",0]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub1\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// create /sub1 again fails stat_ex, file doesn't already exist
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub1\",0]", .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
// create /sub1 again fail timeout EAGAIN on stat_ex
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub1\",0]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
// create /sub1 again fail with .errorOnExists, file already exists
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub1\",0]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// sub2 custom mode
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub2\",511]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub2\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG | LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// sub3/sub4 .noParentCreate fail
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub3/sub4\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// sub3/sub4 success
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub3/sub4\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub3\",488]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub3/sub4\",488]",
.resultInt = LIBSSH2_ERROR_NONE},
// subfail EAGAIN timeout
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/subfail\",488]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/subfail\",488]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage /");
TEST_RESULT_VOID(storagePathCreateP(storageTest, STRDEF("sub1")), "create sub1");
TEST_RESULT_INT(storageInfoP(storageTest, STRDEF("sub1")).mode, 0750, "check sub1 dir mode");
TEST_ERROR(
storagePathCreateP(storageTest, STRDEF("sub1")), PathCreateError,
"ssh2 error [-7] unable to create path '" TEST_PATH "/sub1'");
TEST_RESULT_VOID(storagePathCreateP(storageTest, STRDEF("sub1")), "create sub1 again no .errorOnExists fail EAGAIN");
TEST_RESULT_VOID(
storagePathCreateP(storageTest, STRDEF("sub1")), "create sub1 again no .errorOnExists fail other than EAGAIN");
TEST_ERROR(storagePathCreateP(storageTest, STRDEF("sub1")), PathCreateError, "timeout stating path '" TEST_PATH "/sub1'");
TEST_ERROR(
storagePathCreateP(storageTest, STRDEF("sub1"), .errorOnExists = true), PathCreateError,
"unable to create path '" TEST_PATH "/sub1': path already exists");
// NOTE: if operating against an actual sftp server, a neutral umask is required to get the proper permissions.
// Without the neutral umask, permissions were 0775.
TEST_RESULT_VOID(storagePathCreateP(storageTest, STRDEF("sub2"), .mode = 0777), "create sub2 with custom mode");
TEST_RESULT_INT(storageInfoP(storageTest, STRDEF("sub2")).mode, 0777, "check sub2 dir mode");
TEST_ERROR(
storagePathCreateP(storageTest, STRDEF("sub3/sub4"), .noParentCreate = true), PathCreateError,
"sftp error unable to create path '" TEST_PATH "/sub3/sub4'");
TEST_RESULT_VOID(storagePathCreateP(storageTest, STRDEF("sub3/sub4")), "create sub3/sub4");
// LIBSSH2_ERROR_EAGAIN timeout fail
TEST_ERROR(
storagePathCreateP(storageTest, STRDEF("subfail")), PathCreateError,
"timeout creating path '" TEST_PATH "/subfail'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path create, timeout success on stat");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Timeout success
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/subfail\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/subfail\",0]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/subfail\",0]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/subfail\",0]", .resultInt = LIBSSH2_ERROR_NONE},
// Error other than no such file && no parent create LIBSSH2_FX_PERMISSION_DENIED}
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/subfail\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
// No error on already exists
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/subfail\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FILE_ALREADY_EXISTS},
// Error on already exists
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/subfail\",488]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FILE_ALREADY_EXISTS},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage /");
TEST_RESULT_VOID(storagePathCreateP(storageTest, STRDEF("subfail")), "timeout success");
TEST_ERROR(
storagePathCreateP(storageTest, STRDEF("subfail"), .noParentCreate = true), PathCreateError,
"sftp error unable to create path '" TEST_PATH "/subfail'");
TEST_RESULT_VOID(storagePathCreateP(storageTest, STRDEF("subfail")), "do not throw error on already exists");
TEST_ERROR(
storagePathCreateP(storageTest, STRDEF("subfail"), .errorOnExists = true), PathCreateError,
"sftp error unable to create path '" TEST_PATH "/subfail'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storagePathRemove()"))
{
#ifdef HAVE_LIBSSH2
Storage *storageTest = NULL;
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Path remove missing errorOnMissing
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Recurse - ignore missing path
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Recurse parent/subpath permission denied
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
// Recurse subpath permission denied
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1/remove2\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1/remove2\",0,0,1]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
// Path remove - file in subpath, permission denied
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("remove2"),
.resultInt = 7, .attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"remove2\",4095,null,0]", .fileName = STRDEF("remove.txt"),
.resultInt = 10,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"remove.txt\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1/remove2\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("remove.txt"),
.resultInt = 10,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG | LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"remove.txt\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2/remove.txt\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1/remove2/remove.txt\",0,0,1]",
.resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1/remove2/remove.txt\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
// Path remove - path with subpath and file removed
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("remove2"), .resultInt = 7,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG| LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"remove2\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1/remove2\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("remove.txt"),
.resultInt = 10,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG | LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"remove.txt\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2/remove.txt\"]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1\"]", .resultInt = LIBSSH2_ERROR_NONE},
// Path remove - path with subpath ssh fail on libssh2_sftp_unlink_ex
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("remove2"), .resultInt = 7,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG| LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"remove2\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_SOCKET_SEND},
// unlink SFTP failure other than LIBSSH2_FX_FAILURE / LIBSSH2_FX_PERMISSION_DENIED
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("remove2"), .resultInt = 7,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG| LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"remove2\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_CONNECTION_LOST},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage /");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - missing");
const String *pathRemove1 = STRDEF(TEST_PATH "/remove1");
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove1, .errorOnMissing = true), PathRemoveError,
STORAGE_ERROR_PATH_REMOVE_MISSING, strZ(pathRemove1));
TEST_RESULT_VOID(storagePathRemoveP(storageTest, pathRemove1, .recurse = true), "ignore missing path");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - parent/subpath permission denied");
String *pathRemove2 = strNewFmt("%s/remove2", strZ(pathRemove1));
// Mimic creation of pathRemove2 mode 700
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove2), PathRemoveError, STORAGE_ERROR_PATH_REMOVE " sftp error [3]",
strZ(pathRemove2));
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove2, .recurse = true), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathRemove2));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - subpath permission denied");
// Mimic chmod 777 pathRemove1
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove2, .recurse = true), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathRemove2));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - file in subpath, permission denied");
String *fileRemove = strNewFmt("%s/remove.txt", strZ(pathRemove2));
// Mimic "sudo chmod 755 %s && sudo touch %s && sudo chmod 777 %s", strZ(pathRemove2), strZ(fileRemove), strZ(fileRemove));
TEST_ERROR_FMT(
storagePathRemoveP(
storageTest, pathRemove1, .recurse = true), PathRemoveError, STORAGE_ERROR_PATH_REMOVE " sftp error [3]",
strZ(pathRemove2));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - path with subpath and file removed");
// Mimic chmod 777 pathRemove2
TEST_RESULT_VOID(storagePathRemoveP(storageTest, pathRemove1, .recurse = true), "remove path");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - path with subpath ssh fail on unlink");
TEST_ERROR_FMT(
storagePathRemoveP(
storageTest, pathRemove1, .recurse = true), PathRemoveError, STORAGE_ERROR_PATH_REMOVE_FILE " libssh ssh [-7]",
strZ(pathRemove2));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - other than LIBSSH2_FX_FAILURE/LIBSSH2_FX_PERMISSION_DENIED");
TEST_ERROR_FMT(
storagePathRemoveP(
storageTest, pathRemove1, .recurse = true), PathRemoveError, STORAGE_ERROR_PATH_REMOVE_FILE " libssh sftp [7]",
strZ(pathRemove2));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - unlink LIBSSH2_ERROR_EAGAIN timeout");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("remove2"), .resultInt = 7,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG| LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"remove2\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1/remove2\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF("remove.txt"),
.resultInt = 10,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRWXG | LIBSSH2_SFTP_S_IRWXO,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"remove.txt\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
LIBSSH2_SFTP_S_IROTH,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = 0, .gid = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2/remove.txt\"]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove1/remove2/remove.txt\"]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage /");
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove1, .recurse = true), PathRemoveError, "timeout removing file '%s'",
strZ(fileRemove));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - rmdir LIBSSH2_ERROR_EAGAIN timeout");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage /");
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove1, .recurse = true), PathRemoveError, "timeout removing path '%s'",
strZ(pathRemove1));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - rmdir ssh error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/remove1\",0,0,1]"},
{.function = HRNLIBSSH2_SFTP_READDIR_EX, .param = "[\"\",4095,null,0]", .fileName = STRDEF(""),
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RMDIR_EX, .param = "[\"" TEST_PATH "/remove1\"]", .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage /");
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove1, .recurse = true), PathRemoveError, "unable to remove path '%s'",
strZ(pathRemove1));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageNewRead()"))
{
#ifdef HAVE_LIBSSH2
Storage *storageTest = NULL;
StorageRead *file = NULL;
const String *fileName = STRDEF(TEST_PATH "/readtest.txt");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Missing sftp error no such file
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Timeout EAGAIN
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_WRITING},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK},
// Error not sftp, not EAGAIN
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_METHOD_NOT_SUPPORTED},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_METHOD_NOT_SUPPORTED},
// Read success
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage /");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("read missing");
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new read file (defaults)");
// Missing no such file
TEST_ERROR_FMT(ioReadOpen(storageReadIo(file)), FileMissingError, STORAGE_ERROR_READ_MISSING, strZ(fileName));
// Missing EAGAIN timeout
TEST_ERROR_FMT(ioReadOpen(storageReadIo(file)), FileOpenError, STORAGE_ERROR_READ_OPEN, strZ(fileName));
// Missing not sftp, not EAGAIN
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), false, "not sftp, not EAGAIN");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("read success");
// Mimic creation of TEST_PATH "/readtest.txt"
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, "open file");
TEST_RESULT_INT(ioReadFd(storageReadIo(file)), -1, "check read fd");
TEST_RESULT_VOID(ioReadClose(storageReadIo(file)), "close file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageReadClose()"))
{
#ifdef HAVE_LIBSSH2
// ------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("close success via storageReadSftpClose()");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// storageReadSftpClose
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
// close(ioSessionFd()...)
HRNLIBSSH2_MACRO_SHUTDOWN()
});
Storage *storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
StorageRead *file = NULL;
const String *fileName = STRDEF(TEST_PATH "/readtest.txt");
// Mimic creation of fileName
Buffer *outBuffer = bufNew(2);
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new read file (defaults)");
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, "open file");
TEST_RESULT_VOID(storageReadSftpClose((StorageReadSftp *)file->driver), "close file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// ------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("close success via close()");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// close(ioSessionFd()...)
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]"},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new read file (defaults)");
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, "open file");
close(ioSessionFd(((StorageReadSftp *)file->driver)->storage->ioSession));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// ------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("close, null sftpHandle");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// storageReadSftpClose null sftpHandle
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]"},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new read file (defaults)");
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, "open file");
((StorageReadSftp *)file->driver)->sftpHandle = NULL;
TEST_RESULT_VOID(storageReadSftpClose((StorageReadSftp *)file->driver), "close file null sftpHandle");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// ------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("close fail via storageReadSftpClose() EAGAIN");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// storageReadSftpClose
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
// close(ioSessionFd()...)
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new read file (defaults)");
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, "open file");
TEST_ERROR(
storageReadSftpClose((StorageReadSftp *)file->driver), FileCloseError,
"timeout closing file '" TEST_PATH "/readtest.txt'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// ------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("close fail via storageReadSftpClose() sftp error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// storageReadSftpClose
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new read file (defaults)");
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, "open file");
TEST_ERROR(
storageReadSftpClose((StorageReadSftp *)file->driver), FileCloseError,
"unable to close file '" TEST_PATH "/readtest.txt' after read: libssh2 errno [-31]: sftp errno [4]");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// ------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("close fail via storageReadSftpClose() ssh error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// storageReadSftpClose
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_ZLIB},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new read file (defaults)");
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, "open file");
TEST_ERROR(
storageReadSftpClose((StorageReadSftp *)file->driver), FileCloseError,
"unable to close file '" TEST_PATH "/readtest.txt' after read: libssh2 errno [-29]");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// ------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageReadSftp() sftp error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// storageReadSftpClose
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new read file (defaults)");
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, "open file");
TEST_ERROR(
storageReadSftp(((StorageReadSftp *)file->driver), outBuffer, false), FileReadError,
"unable to read '" TEST_PATH "/readtest.txt': sftp errno [4]");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// ------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageReadSftp() ssh error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// storageReadSftpClose
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/readtest.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = LIBSSH2_ERROR_ZLIB},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new read file (defaults)");
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), true, "open file");
TEST_ERROR(
storageReadSftp(((StorageReadSftp *)file->driver), outBuffer, false), FileReadError,
"unable to read '" TEST_PATH "/readtest.txt'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageNewWrite()"))
{
#ifdef HAVE_LIBSSH2
const String *fileName = STRDEF(TEST_PATH "/sub1/testfile");
StorageWrite *file = NULL;
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("permission denied");
// Mimic creation of /noperm/noperm
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Permission denied
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",26,416,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",26,416,0]", .resultNull = true,
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
Storage *storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileNoPerm, .noAtomic = true, .noCreatePath = false), "new write file");
TEST_ERROR_FMT(
ioWriteOpen(storageWriteIo(file)), FileOpenError,
STORAGE_ERROR_WRITE_OPEN ": libssh2 error [-31]: sftp error [3]", strZ(fileNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("timeout");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Timeout
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",26,416,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",26,416,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileNoPerm, .noAtomic = true, .noCreatePath = false), "new write file");
TEST_ERROR_FMT(ioWriteOpen(storageWriteIo(file)), FileOpenError, "timeout while opening file '%s'", strZ(fileNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("missing");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Missing
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/missing\",26,416,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "\",488]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/missing\",26,416,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(
file, storageNewWriteP(storageTest, STRDEF("missing"), .noAtomic = true, .noCreatePath = false), "new write file");
TEST_ERROR_FMT(ioWriteOpen(storageWriteIo(file)), FileMissingError, STORAGE_ERROR_WRITE_MISSING, TEST_PATH "/missing");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("write file - defaults");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",\"" TEST_PATH "/sub1/testfile\",7]",
.resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_RESULT_VOID(ioWriteClose(storageWriteIo(file)), "close file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageWriteSftpClose timeout on fsync");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
const String *fileNameTmp = STRDEF(TEST_PATH "/sub1/testfile.pgbackrest.tmp");
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_ERROR_FMT(ioWriteClose(storageWriteIo(file)), FileSyncError, "timeout syncing file '%s'", strZ(fileNameTmp));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageWriteSftpClose error on fsync");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
fileNameTmp = STRDEF(TEST_PATH "/sub1/testfile.pgbackrest.tmp");
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_ERROR_FMT(
ioWriteClose(storageWriteIo(file)), FileSyncError, "unable to sync file '%s' after write", strZ(fileNameTmp));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageWriteSftpClose error on close");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_ERROR_FMT(
ioWriteClose(storageWriteIo(file)), FileCloseError,
"unable to close file '%s' after write: libssh2 error [-7]", strZ(fileNameTmp));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("timeout on rename");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",\"" TEST_PATH "/sub1/testfile\",7]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_ERROR_FMT(ioWriteClose(storageWriteIo(file)), FileCloseError, "timeout renaming file '%s'", strZ(fileNameTmp));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sftp error on rename, other than LIBSSH2_FX_FAILURE");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",\"" TEST_PATH "/sub1/testfile\",7]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_CONNECTION_LOST},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_CONNECTION_LOST},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_ERROR_FMT(
ioWriteClose(storageWriteIo(file)), FileCloseError,
"unable to move '%s' to '%s': libssh2 error [-31]: sftp error [7]", strZ(fileNameTmp), strZ(fileName));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("ssh error on rename");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",\"" TEST_PATH "/sub1/testfile\",7]",
.resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_ERROR_FMT(
ioWriteClose(storageWriteIo(file)), FileCloseError,
"unable to move '%s' to '%s': libssh2 error [-7]", strZ(fileNameTmp), strZ(fileName));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageWriteSftpClose() timeout EAGAIN on libssh2_sftp_close");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_ERROR_FMT(ioWriteClose(storageWriteIo(file)), FileCloseError, "timeout closing file '%s'", strZ(fileNameTmp));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("write file - noAtomic = true");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName, .noAtomic = true), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_RESULT_VOID(ioWriteClose(storageWriteIo(file)), "close file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("write file - syncPath not NULL, .noSyncPath = true");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true, .param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
// Make interface.pathSync != NULL
((StorageSftp *)storageDriver(storageTest))->interface.pathSync = malloc(1);
TEST_ASSIGN(
file, storageNewWriteP(storageTest, fileName, .noAtomic = true, .noSyncPath = true), "new write file (defaults)");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_RESULT_VOID(ioWriteClose(storageWriteIo(file)), "close file");
free(((StorageSftp *)storageDriver(storageTest))->interface.pathSync);
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("write file - syncPath not NULL, .noSyncPath = false");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true, .param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
// Make interface.pathSync != NULL
((StorageSftp *)storageDriver(storageTest))->interface.pathSync = malloc(1);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName, .noAtomic = true, .noSyncPath = false), "new write file");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_RESULT_VOID(ioWriteClose(storageWriteIo(file)), "close file");
free(((StorageSftp *)storageDriver(storageTest))->interface.pathSync);
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("write file - syncFile false");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true, .param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
((StorageSftp *)storageDriver(storageTest))->interface.pathSync = malloc(1);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName, .noAtomic = true, .noSyncPath = false), "new write file");
((StorageWriteSftp *)file->driver)->interface.syncFile = false;
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_RESULT_VOID(ioWriteClose(storageWriteIo(file)), "close file");
free(((StorageSftp *)storageDriver(storageTest))->interface.pathSync);
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageWriteSftpClose() - null sftpHandle");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true, .param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/testfile\",26,416,0]"},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName, .noAtomic = true, .noSyncPath = false), "new write file");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
// Make sftpHandle NULL
((StorageWriteSftp *)file->driver)->sftpHandle = NULL;
TEST_RESULT_VOID(ioWriteClose(storageWriteIo(file)), "close file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storagePut() and storageGet()"))
{
#ifdef HAVE_LIBSSH2
ioBufferSizeSet(65536);
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[65536]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[65536]", .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
Storage *storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("get error - attempt to get directory");
TEST_ERROR(
storageGetP(storageNewReadP(storageTest, TEST_PATH_STR, .ignoreMissing = false)), FileReadError,
"unable to read '" TEST_PATH "': sftp errno [4]");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("put - empty file");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",\"" TEST_PATH "/test.empty\",7]",
.resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
const String *emptyFile = STRDEF(TEST_PATH "/test.empty");
TEST_RESULT_VOID(storagePutP(storageNewWriteP(storageTest, emptyFile), NULL), "put empty file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("put - empty file, already exists");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",\"" TEST_PATH "/test.empty\",7]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/test.empty\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/test.empty\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storagePutP(storageNewWriteP(storageTest, emptyFile), NULL), FileRemoveError,
"unable to remove existing '" TEST_PATH "/test.empty': libssh2 error [-31]: sftp error [0]");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("put - empty file, remove already existing file, storageWriteSftpRename timeout EAGAIN");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",\"" TEST_PATH "/test.empty\",7]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/test.empty\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/test.empty\"]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",\"" TEST_PATH "/test.empty\",7]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",\"" TEST_PATH "/test.empty\",7]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storagePutP(storageNewWriteP(storageTest, emptyFile), NULL), FileWriteError,
"timeout moving '" TEST_PATH "/test.empty.pgbackrest.tmp' to '" TEST_PATH "/test.empty'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("put - empty file, remove already existing file, storageWriteSftpRename ssh error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",\"" TEST_PATH "/test.empty\",7]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/test.empty\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/test.empty\"]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",\"" TEST_PATH "/test.empty\",7]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",\"" TEST_PATH "/test.empty\",7]",
.resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storagePutP(storageNewWriteP(storageTest, emptyFile), NULL), FileRemoveError,
"unable to move '" TEST_PATH "/test.empty.pgbackrest.tmp' to '" TEST_PATH "/test.empty': libssh2 error [-7]");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("put - empty file, EAGAIN fail on remove already existing file");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.empty.pgbackrest.tmp\",\"" TEST_PATH "/test.empty\",7]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_FAILURE},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/test.empty\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/test.empty\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storagePutP(storageNewWriteP(storageTest, emptyFile), NULL), FileWriteError,
"timeout unlinking '" TEST_PATH "/test.empty'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("put - file with contents - timeout EAGAIN libssh2_sftp_write");
ioBufferSizeSet(2);
const Buffer *failBuffer = BUFSTRDEF("FAIL\n");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[2]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[2]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storagePutP(storageNewWriteP(storageTest, STRDEF(TEST_PATH "/test.txt")), failBuffer), FileWriteError,
"timeout writing '" TEST_PATH "/test.txt.pgbackrest.tmp'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("put - file with contents - error other than EAGAIN libssh2_sftp_write");
failBuffer = BUFSTRDEF("FAIL\n");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[2]", .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storagePutP(storageNewWriteP(storageTest, STRDEF(TEST_PATH "/test.txt")), failBuffer), FileWriteError,
"unable to write '" TEST_PATH "/test.txt.pgbackrest.tmp'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("put - file with contents");
const Buffer *buffer = BUFSTRDEF("TESTFILE\n");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt.pgbackrest.tmp\",26,416,0]"},
// Not passing buffer param, see shim function, initial passed buffer contains random data
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[2]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[2]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[2]", .resultInt = 2},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[2]", .resultInt = 2},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[2]", .resultInt = 2},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[2]", .resultInt = 1},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[1]", .resultInt = 1},
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[1]", .resultInt = 1},
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/test.txt.pgbackrest.tmp\",\"" TEST_PATH "/test.txt\",7]",
.resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_RESULT_VOID(storagePutP(storageNewWriteP(storageTest, STRDEF(TEST_PATH "/test.txt")), buffer), "put test file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("get - ignore missing");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/BOGUS\",1,0,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_RESULT_PTR(
storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/" BOGUS_STR), .ignoreMissing = true)), NULL,
"get missing file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("get - empty file");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.empty\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(buffer, storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.empty"))), "get empty");
TEST_RESULT_UINT(bufSize(buffer), 0, "size is 0");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("get - file with contents");
const Buffer *outBuffer = bufNew(2);
ioBufferSizeSet(65536);
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt\",1,0,0]"},
// Not passing buffer param, see shim function, initial passed buffer contains random data
{.function = HRNLIBSSH2_SFTP_READ, .param = "[65536]", .resultInt = 9, .readBuffer = STRDEF("TESTFILE\n")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[65527]", .resultInt = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(outBuffer, storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.txt"))), "get text");
TEST_RESULT_UINT(bufSize(outBuffer), 9, "check size");
TEST_RESULT_BOOL(memcmp(bufPtrConst(outBuffer), "TESTFILE\n", bufSize(outBuffer)) == 0, true, "check content");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("get - exact size smaller");
ioBufferSizeSet(2);
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("TE")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("ST")},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(buffer, storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.txt")), .exactSize = 4), "get exact");
TEST_RESULT_UINT(bufSize(buffer), 4, "check size");
TEST_RESULT_BOOL(memcmp(bufPtrConst(buffer), "TEST", bufSize(buffer)) == 0, true, "check content");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("get - exact size larger");
ioBufferSizeSet(4);
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[4]", .resultInt = 4, .readBuffer = STRDEF("TEST")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[4]", .resultInt = 4, .readBuffer = STRDEF("FILE")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[4]", .resultInt = 1, .readBuffer = STRDEF("\n")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[3]", .resultInt = 0},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.txt")), .exactSize = 64), FileReadError,
"unable to read 64 byte(s) from '" TEST_PATH "/test.txt'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("get - smaller buffer size");
ioBufferSizeSet(2);
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("TE")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("ST")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("FI")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("LE")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 1, .readBuffer = STRDEF("\n")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[1]", .resultInt = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(buffer, storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.txt"))), "get text");
TEST_RESULT_UINT(bufSize(buffer), 9, "check size");
TEST_RESULT_BOOL(memcmp(bufPtrConst(buffer), "TESTFILE\n", bufSize(buffer)) == 0, true, "check content");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("error on invalid read offset bytes");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_SEEK64, .param = "[18446744073709551615]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_BAD_MESSAGE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.txt"), .offset = UINT64_MAX)), FileOpenError,
"unable to seek to 18446744073709551615 in file '" TEST_PATH "/test.txt'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("error on invalid read");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_BAD_MESSAGE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.txt"))), FileReadError,
"unable to read '" TEST_PATH "/test.txt': sftp errno [5]");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("read limited bytes");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("TE")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("ST")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("FI")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[1]", .resultInt = 1, .readBuffer = STRDEF("LE")},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(buffer, storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.txt"), .limit = VARUINT64(7))), "get");
TEST_RESULT_UINT(bufSize(buffer), 7, "check size");
TEST_RESULT_BOOL(memcmp(bufPtrConst(buffer), "TESTFIL", bufSize(buffer)) == 0, true, "check content");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("read offset bytes");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_SEEK64, .param = "[4]"},
// Simulate seeking offset 4
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("FI")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 2, .readBuffer = STRDEF("LE")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = 1, .readBuffer = STRDEF("\n")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[1]", .resultInt = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(buffer, storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.txt"), .offset = 4)), "get");
TEST_RESULT_UINT(bufSize(buffer), 5, "check size");
TEST_RESULT_BOOL(memcmp(bufPtrConst(buffer), "FILE\n", bufSize(buffer)) == 0, true, "check content");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("get - read timeout EAGAIN");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.txt\",1,0,0]"},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[2]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storageGetP(storageNewReadP(storageTest, STRDEF(TEST_PATH "/test.txt"))), FileReadError,
"timeout reading '" TEST_PATH "/test.txt'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageRemove()"))
{
#ifdef HAVE_LIBSSH2
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("remove - file missing");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, strZ(FSLASH_STR));
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
Storage *storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_RESULT_VOID(storageRemoveP(storageTest, STRDEF("missing")), "remove missing file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("remove - file missing, .errorOnMissing = true, sftp error LIBSSH2_FX_NO_SUCH_FILE");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(storageRemoveP(storageTest, STRDEF("missing"), .errorOnMissing = true), FileRemoveError,
"unable to remove '/missing': libssh2 error [-31]: sftp error [2]");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("remove - file missing, sftp error other than LIBSSH2_FX_NO_SUCH_FILE");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_CONNECTION_LOST},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_CONNECTION_LOST},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(storageRemoveP(storageTest, STRDEF("missing")), FileRemoveError,
"unable to remove '/missing': libssh2 error [-31]: sftp error [7]");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("remove - file missing, ssh error, .errorOnMissing = true");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_BAD_SOCKET},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(storageRemoveP(storageTest, STRDEF("missing"), .errorOnMissing = true), FileRemoveError,
"unable to remove '/missing'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("remove - file missing, timeout EAGAIN, .errorOnMissing = true");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"/missing\"]", .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(
storageRemoveP(storageTest, STRDEF("missing"), .errorOnMissing = true), FileRemoveError, "timeout removing '/missing'");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("remove - LIBSSH2_ERROR_SOCKET_SEND");
const String *fileRemove1 = STRDEF(TEST_PATH "/remove.txt");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/remove.txt\"]",
.resultInt = LIBSSH2_ERROR_SOCKET_SEND},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage /");
TEST_RESULT_VOID(storageRemoveP(storageTest, fileRemove1), "remove file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageWriteSftpOpen libssh2_sftp_open_ex timeout EAGAIN");
StorageWrite *file = NULL;
const String *fileName = STRDEF(TEST_PATH "/sub1/testfile");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true, .resultInt = LIBSSH2_ERROR_EAGAIN,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true, .resultInt = LIBSSH2_ERROR_EAGAIN,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName, .noSyncFile = true), "storageWriteSftpOpen timeout EAGAIN");
TEST_ERROR_FMT(ioWriteOpen(storageWriteIo(file)), FileOpenError, "timeout while opening file '%s'", strZ(fileName));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageWriteSftpOpen libssh2_sftp_open_ex sftp error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName, .noSyncFile = true), "storageWriteSftpOpen sftp error");
TEST_ERROR_FMT(
ioWriteOpen(storageWriteIo(file)), FileOpenError,
STORAGE_ERROR_WRITE_OPEN ": libssh2 error [-31]: sftp error [3]", strZ(fileName));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageWriteSftpOpen libssh2_sftp_open_ex ssh error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .resultNull = true,
.param = "[\"" TEST_PATH "/sub1/testfile.pgbackrest.tmp\",26,416,0]"},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_ZLIB},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_ZLIB},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_ZLIB},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName, .noSyncFile = true), "storageWriteSftpOpen ssh error");
TEST_ERROR_FMT(ioWriteOpen(storageWriteIo(file)), FileOpenError, STORAGE_ERROR_WRITE_OPEN, strZ(fileName));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("StorageRead"))
{
#ifdef HAVE_LIBSSH2
Storage *storageTest = NULL;
StorageRead *file = NULL;
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Ignore missing - file with no permission to read
// New read file, check ignore missing, check name require no libssh2 calls
// Permission denied
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",1,0,0]", .resultNull = true,
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
// File missing
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.file\",1,0,0]", .resultNull = true,
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
// Ignore missing
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.file\",1,0,0]", .resultNull = true,
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("ignore missing - file with no permission to read");
// Mimic creation of /noperm/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_TITLE("permission denied");
TEST_ASSIGN(file, storageNewReadP(storageTest, fileNoPerm), "new no perm read file");
TEST_ERROR_FMT(ioReadOpen(storageReadIo(file)), FileOpenError, STORAGE_ERROR_READ_OPEN, strZ(fileNoPerm));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("file missing");
const String *fileName = STRDEF(TEST_PATH "/test.file");
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName), "new missing read file");
TEST_ERROR_FMT(ioReadOpen(storageReadIo(file)), FileMissingError, STORAGE_ERROR_READ_MISSING, strZ(fileName));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("ignore missing");
TEST_ASSIGN(file, storageNewReadP(storageTest, fileName, .ignoreMissing = true), "new missing read file");
TEST_RESULT_BOOL(ioReadOpen(storageReadIo(file)), false, "missing file ignored");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("incremental load, storageReadSftp(), storageReadSftpEof()");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
// Open file
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/test.file\",1,0,0]",
.resultInt = LIBSSH2_ERROR_NONE},
// Check file name, check file type, check offset, check limit require no libssh2 calls
{.function = HRNLIBSSH2_SFTP_READ, .param = "[44]", .resultInt = 2, .readBuffer = STRDEF("TE")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[42]", .resultInt = 2, .readBuffer = STRDEF("ST")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[40]", .resultInt = 2, .readBuffer = STRDEF("FI")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[38]", .resultInt = 2, .readBuffer = STRDEF("LE")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[36]", .resultInt = 1, .readBuffer = STRDEF("\n")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[35]", .resultInt = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, strZ(FSLASH_STR));
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
Buffer *buffer = bufNew(0);
Buffer *outBuffer = bufNew(2);
const Buffer *expectedBuffer = BUFSTRDEF("TESTFILE\n");
MEM_CONTEXT_TEMP_BEGIN()
{
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_UINT(storageReadType(file), STORAGE_SFTP_TYPE, "check file type");
TEST_RESULT_UINT(storageReadOffset(file), 0, "check offset");
TEST_RESULT_UINT(varUInt64(storageReadLimit(file)), 44, "check limit");
TEST_RESULT_VOID(ioRead(storageReadIo(file), outBuffer), "load data");
bufCat(buffer, outBuffer);
bufUsedZero(outBuffer);
TEST_RESULT_VOID(ioRead(storageReadIo(file), outBuffer), "load data");
bufCat(buffer, outBuffer);
bufUsedZero(outBuffer);
TEST_RESULT_VOID(ioRead(storageReadIo(file), outBuffer), "load data");
bufCat(buffer, outBuffer);
bufUsedZero(outBuffer);
TEST_RESULT_VOID(ioRead(storageReadIo(file), outBuffer), "load data");
bufCat(buffer, outBuffer);
bufUsedZero(outBuffer);
TEST_RESULT_BOOL(bufEq(buffer, expectedBuffer), false, "check file contents (not all loaded yet)");
TEST_RESULT_VOID(ioRead(storageReadIo(file), outBuffer), "load data");
bufCat(buffer, outBuffer);
bufUsedZero(outBuffer);
TEST_RESULT_VOID(ioRead(storageReadIo(file), outBuffer), "no data to load");
TEST_RESULT_UINT(bufUsed(outBuffer), 0, "buffer is empty");
TEST_RESULT_VOID(storageReadSftp(file->driver, outBuffer, true), "no data to load from driver either");
TEST_RESULT_UINT(bufUsed(outBuffer), 0, "buffer is empty");
TEST_RESULT_BOOL(bufEq(buffer, expectedBuffer), true, "check file contents (all loaded)");
TEST_RESULT_BOOL(ioReadEof(storageReadIo(file)), true, "eof");
TEST_RESULT_BOOL(ioReadEof(storageReadIo(file)), true, "still eof");
TEST_RESULT_BOOL(storageReadSftpEof((StorageReadSftp *)file->driver), true, "storageReadSftpEof eof true");
TEST_RESULT_VOID(ioReadClose(storageReadIo(file)), "close file");
TEST_RESULT_VOID(storageReadFree(storageNewReadP(storageTest, fileName)), "free file");
TEST_RESULT_VOID(storageReadMove(NULL, memContextTop()), "move null file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("StorageWrite"))
{
#ifdef HAVE_LIBSSH2
Storage *storageTest = NULL;
StorageWrite *file = NULL;
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("check getters");
// mimic creation of /noperm/noperm
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
HRNLIBSSH2_MACRO_SHUTDOWN()
});
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(
file,
storageNewWriteP(
storageTest, fileNoPerm, .modeFile = 0444, .modePath = 0555, .noSyncFile = true, .noSyncPath = true,
.noAtomic = true),
"new write file");
TEST_RESULT_BOOL(storageWriteAtomic(file), false, "check atomic");
TEST_RESULT_BOOL(storageWriteCreatePath(file), true, "check create path");
TEST_RESULT_INT(storageWriteModeFile(file), 0444, "check mode file");
TEST_RESULT_INT(storageWriteModePath(file), 0555, "check mode path");
TEST_RESULT_STR(storageWriteName(file), fileNoPerm, "check name");
TEST_RESULT_BOOL(storageWriteSyncPath(file), false, "check sync path");
TEST_RESULT_BOOL(storageWriteSyncFile(file), false, "check sync file");
TEST_RESULT_BOOL(storageWriteTruncate(file), true, "file will be truncated");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("permission denied");
// mimic creation of /noperm/noperm
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
// Permission denied
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/noperm/noperm\",26,416,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_PERMISSION_DENIED},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha256");
#else
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
#endif
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileNoPerm, .noAtomic = true), "new write file");
TEST_ERROR_FMT(
ioWriteOpen(storageWriteIo(file)),
FileOpenError, STORAGE_ERROR_WRITE_OPEN ": libssh2 error [-31]: sftp error [3]", strZ(fileNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("file missing");
const String *fileName = STRDEF(TEST_PATH "/sub1/test.file");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", .resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
// Missing
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/test.file\",26,416,0]", .resultNull = true},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/test.file\",26,416,0]", .resultNull = true,
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
{.function = HRNLIBSSH2_SFTP_MKDIR_EX, .param = "[\"" TEST_PATH "/sub1\",488]"},
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/test.file\",26,416,0]", .resultNull = true,
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_NO_SUCH_FILE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha256");
#else
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
#endif
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, "~/.ssh/known_hosts");
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, "/home/" TEST_USER "/.ssh/known_hosts2");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName, .noAtomic = true), "new write file");
TEST_ERROR_FMT(ioWriteOpen(storageWriteIo(file)), FileMissingError, STORAGE_ERROR_WRITE_MISSING, strZ(fileName));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("write file success");
const Buffer *buffer = BUFSTRDEF("TESTFILE\n");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
// Open file
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/test.file.pgbackrest.tmp\",26,416,0]"},
// Write null and zero size buffers are noops
// Write filled buffer to file
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[9]", .resultInt = 9},
// Close file
{.function = HRNLIBSSH2_SFTP_FSYNC, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_RENAME_EX,
.param = "[\"" TEST_PATH "/sub1/test.file.pgbackrest.tmp\",\"" TEST_PATH "/sub1/test.file\",7]",
.resultInt = LIBSSH2_ERROR_NONE},
// Move context
// Open file
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub1/test.file\",1,0,0]"},
// Read file
{.function = HRNLIBSSH2_SFTP_READ, .param = "[65536]", .resultInt = 9, .readBuffer = STRDEF("TESTFILE\n")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[65527]", .resultInt = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
// Check path mode
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub1\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// Check file mode
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub1/test.file\",1]",
.fileName = STRDEF("test.file"), .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// Remove filename
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/sub1/test.file\"]",
.resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "md5");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
ioBufferSizeSet(65536);
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
MEM_CONTEXT_TEMP_BEGIN()
{
TEST_ASSIGN(file, storageWriteMove(storageNewWriteP(storageTest, fileName), memContextPrior()), "new write file");
}
MEM_CONTEXT_TEMP_END();
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_VOID(ioWrite(storageWriteIo(file), NULL), "write null buffer to file");
TEST_RESULT_VOID(ioWrite(storageWriteIo(file), bufNew(0)), "write zero buffer to file");
TEST_RESULT_VOID(ioWrite(storageWriteIo(file), buffer), "write to file");
TEST_RESULT_VOID(ioWriteClose(storageWriteIo(file)), "close file");
TEST_RESULT_VOID(storageWriteFree(storageNewWriteP(storageTest, fileName)), "free file");
TEST_RESULT_VOID(storageWriteMove(NULL, memContextTop()), "move null file");
Buffer *expectedBuffer = storageGetP(storageNewReadP(storageTest, fileName));
TEST_RESULT_BOOL(bufEq(buffer, expectedBuffer), true, "check file contents");
TEST_RESULT_INT(storageInfoP(storageTest, strPath(fileName)).mode, 0750, "check path mode");
TEST_RESULT_INT(storageInfoP(storageTest, fileName).mode, 0640, "check file mode");
storageRemoveP(storageTest, fileName, .errorOnMissing = true);
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("write subpath and file success");
fileName = STRDEF(TEST_PATH "/sub2/test.file");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = 0},
{.function = HRNLIBSSH2_SFTP_INIT},
// Open file
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub2/test.file\",26,384,0]"},
// Write filled buffer to file
{.function = HRNLIBSSH2_SFTP_WRITE, .param = "[9]", .resultInt = 9},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
// Open file
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "/sub2/test.file\",1,0,0]"},
// Read file
{.function = HRNLIBSSH2_SFTP_READ, .param = "[65536]", .resultInt = 9, .readBuffer = STRDEF("TESTFILE\n")},
{.function = HRNLIBSSH2_SFTP_READ, .param = "[65527]", .resultInt = 0},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
// Check path mode
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub2\",1]", .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFDIR | LIBSSH2_SFTP_S_IRWXU,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID |
LIBSSH2_SFTP_ATTR_SIZE,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// Check file mode
{.function = HRNLIBSSH2_SFTP_STAT_EX, .param = "[\"" TEST_PATH "/sub2/test.file\",1]",
.fileName = STRDEF("test.file"), .resultInt = LIBSSH2_ERROR_NONE,
.attrPerms = LIBSSH2_SFTP_S_IFREG | LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR,
.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME | LIBSSH2_SFTP_ATTR_UIDGID,
.mtime = 1656434296, .uid = TEST_USER_ID, .gid = TEST_GROUP_ID},
// Remove filename
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/sub2/test.file\"]",
.resultInt = LIBSSH2_ERROR_NONE},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepo, "1");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, "/home/" TEST_USER "/.ssh/known_hosts ");
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, " /home/" TEST_USER "/.ssh/known_hosts2");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
ioBufferSizeSet(65536);
storageTest = storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ASSIGN(
file,
storageNewWriteP(
storageTest, fileName, .modePath = 0700, .modeFile = 0600, .noSyncPath = true, .noSyncFile = true,
.noAtomic = true),
"new write file");
TEST_RESULT_VOID(ioWriteOpen(storageWriteIo(file)), "open file");
TEST_RESULT_VOID(ioWrite(storageWriteIo(file), buffer), "write to file");
TEST_RESULT_VOID(ioWriteClose(storageWriteIo(file)), "close file");
expectedBuffer = storageGetP(storageNewReadP(storageTest, fileName));
TEST_RESULT_BOOL(bufEq(buffer, expectedBuffer), true, "check file contents");
TEST_RESULT_INT(storageInfoP(storageTest, strPath(fileName)).mode, 0700, "check path mode");
TEST_RESULT_INT(storageInfoP(storageTest, fileName).mode, 0600, "check file mode");
TEST_RESULT_STR_Z(
strLstGet(strLstNewVarLst(cfgOptionLst(cfgOptRepoSftpKnownHost)), 0), "/home/" TEST_USER "/.ssh/known_hosts ",
"check known hosts path trailing spaces");
TEST_RESULT_STR_Z(
strLstGet(strLstNewVarLst(cfgOptionLst(cfgOptRepoSftpKnownHost)), 1), " /home/" TEST_USER "/.ssh/known_hosts2",
"check known hosts path leading spaces");
storageRemoveP(storageTest, fileName, .errorOnMissing = true);
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageRepo*()"))
{
#ifdef HAVE_LIBSSH2
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Load configuration to set repo-path and stanza
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "db");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, " ~/.ssh/id_rsa");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, " ~/.ssh/id_rsa.pub");
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
const Storage *storage = NULL;
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageRepo() - cached/not cached");
// Set storage helper
static const StorageHelper storageHelperList[] = {STORAGE_SFTP_HELPER, STORAGE_END_HELPER};
storageHelperInit(storageHelperList);
TEST_RESULT_PTR(storageHelper.storageRepo, NULL, "repo storage not cached");
TEST_ASSIGN(storage, storageRepo(), "new storage");
TEST_RESULT_PTR(storageHelper.storageRepo[0], storage, "repo storage cached");
TEST_RESULT_PTR(storageRepo(), storage, "get cached storage");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageRepo() - confirm settings");
TEST_ERROR(storagePathP(storage, STRDEF("<BOGUS>/path")), AssertError, "invalid expression '<BOGUS>'");
TEST_ERROR(storageNewWriteP(storage, writeFile), AssertError, "assertion 'this->write' failed");
TEST_RESULT_STR_Z(storagePathP(storage, NULL), TEST_PATH, "check base path");
TEST_RESULT_STR_Z(
storagePathP(storage, STORAGE_REPO_ARCHIVE_STR), TEST_PATH "/archive/db", "check archive path");
TEST_RESULT_STR_Z(
storagePathP(storage, STRDEF(STORAGE_REPO_ARCHIVE "/simple")), TEST_PATH "/archive/db/simple",
"check simple path");
TEST_RESULT_STR_Z(
storagePathP(storage, STRDEF(STORAGE_REPO_ARCHIVE "/9.4-1/700000007000000070000000")),
TEST_PATH "/archive/db/9.4-1/7000000070000000/700000007000000070000000", "check segment path");
TEST_RESULT_STR_Z(
storagePathP(storage, STRDEF(STORAGE_REPO_ARCHIVE "/9.4-1/00000008.history")),
TEST_PATH "/archive/db/9.4-1/00000008.history", "check history path");
TEST_RESULT_STR_Z(
storagePathP(storage, STRDEF(STORAGE_REPO_ARCHIVE "/9.4-1/000000010000014C0000001A.00000028.backup")),
TEST_PATH "/archive/db/9.4-1/000000010000014C/000000010000014C0000001A.00000028.backup",
"check archive backup path");
TEST_RESULT_STR_Z(storagePathP(storage, STORAGE_REPO_BACKUP_STR), TEST_PATH "/backup/db", "check backup path");
memContextFree(objMemContext((StorageSftp *)storageDriver(storage)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageRepo() - helper does not fail when stanza option not set");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Change the stanza to NULL with the stanzaInit flag still true, make sure helper does not fail when stanza option not set
argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, "/home/" TEST_USER "/.ssh/known_hosts");
HRN_CFG_LOAD(cfgCmdInfo, argList);
TEST_ASSIGN(storage, storageRepo(), "new repo storage no stanza");
TEST_RESULT_STR(storageHelper.stanza, NULL, "stanza NULL");
TEST_RESULT_STR_Z(
storagePathP(storage, STORAGE_REPO_ARCHIVE_STR), TEST_PATH "/archive", "check archive path - NULL stanza");
TEST_RESULT_STR_Z(
storagePathP(storage, STRDEF(STORAGE_REPO_ARCHIVE "/simple")), TEST_PATH "/archive/simple",
"check simple archive path - NULL stanza");
TEST_RESULT_STR_Z(storagePathP(storage, STORAGE_REPO_BACKUP_STR), TEST_PATH "/backup", "check backup path - NULL stanza");
TEST_RESULT_STR_Z(
storagePathP(storage, STRDEF(STORAGE_REPO_BACKUP "/simple")), TEST_PATH "/backup/simple",
"check simple backup path - NULL stanza");
memContextFree(objMemContext((StorageSftp *)storageDriver(storage)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageRepoWrite() - confirm write enabled");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
TEST_RESULT_PTR(storageHelper.storageRepoWrite, NULL, "repo write storage not cached");
TEST_ASSIGN(storage, storageRepoWrite(), "new write storage");
TEST_RESULT_PTR(storageHelper.storageRepoWrite[0], storage, "repo write storage cached");
TEST_RESULT_PTR(storageRepoWrite(), storage, "get cached storage");
TEST_RESULT_BOOL(storage->write, true, "get write enabled");
TEST_RESULT_UINT(storageType(storage), storage->pub.type, "check type");
TEST_RESULT_STR_Z(strIdToStr(storageType(storage)), "sftp", "storage type is sftp");
memContextFree(objMemContext((StorageSftp *)storageDriver(storage)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageRepoGet() and StorageDriverCifs"))
{
#ifdef HAVE_LIBSSH2
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
{.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"},
{.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_KNOWNHOST_INIT},
{.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5},
{.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY},
{.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]",
.resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH},
{.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX,
.param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_INIT},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
// Load configuration
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("error on invalid storage type");
static const StorageHelper storageHelperListError[] = {{.type = STORAGE_CIFS_TYPE}, STORAGE_END_HELPER};
storageHelperInit(storageHelperListError);
TEST_ERROR(storageRepoGet(0, true), AssertError, "invalid storage type");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storage configuration");
// Set storage helper
static const StorageHelper storageHelperList[] = {STORAGE_SFTP_HELPER, STORAGE_END_HELPER};
storageHelperInit(storageHelperList);
const Storage *storage = NULL;
TEST_ASSIGN(storage, storageRepoGet(0, true), "get sftp repo storage");
TEST_RESULT_UINT(storageType(storage), STORAGE_SFTP_TYPE, "check storage type");
TEST_RESULT_BOOL(storageFeature(storage, storageFeaturePath), true, "check path feature");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("write object path sync false");
// Create a FileWrite object with path sync enabled and ensure that path sync is false in the write object
StorageWrite *file = NULL;
TEST_ASSIGN(file, storageNewWriteP(storage, STRDEF("somefile"), .noSyncPath = false), "new file write");
TEST_RESULT_BOOL(storageWriteSyncPath(file), false, "path sync is disabled");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path sync result is noop");
// Test the path sync function -- pass a bogus path to ensure that this is a noop
TEST_RESULT_VOID(storagePathSyncP(storage, STRDEF(BOGUS_STR)), "path sync is a noop");
memContextFree(objMemContext((StorageSftp *)storageDriver(storage)));
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageSftpLibSsh2SessionFreeResource()"))
{
#ifdef HAVE_LIBSSH2
Storage *storageTest = NULL;
StorageSftp *storageSftp = NULL;
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() sftpHandle, sftpSession, session not NULL, branch tests, EAGAIN");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",1,0,1]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgBackRest instance shutdown\",\"\"]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgBackRest instance shutdown\",\"\"]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_FREE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SESSION_FREE, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE},
HRNLIBSSH2_MACRO_SHUTDOWN(),
});
StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH);
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER);
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR);
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
// Populate sftpHandle, NULL sftpSession and session
storageSftp->sftpHandle = libssh2_sftp_open_ex(storageSftp->sftpSession, TEST_PATH, 25, 1, 0, 1);
TEST_RESULT_VOID(storageSftpLibSsh2SessionFreeResource(storageSftp), "freeResource not NULL sftpHandle");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() sftpHandle, sftpSession, session all NULL");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = NULL}
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
// NULL out sftpSession and session
storageSftp->sftpSession = NULL;
storageSftp->session = NULL;
TEST_RESULT_VOID(memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))), "free resource all NULL");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() sftp close handle failure, sftpHandle not NULL, libssh2 error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",1,0,1]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = NULL}
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
// Populate sftpHandle, NULL out sftpSession and session
storageSftp->sftpHandle = libssh2_sftp_open_ex(storageSftp->sftpSession, TEST_PATH, 25, 1, 0, 1);
storageSftp->sftpSession = NULL;
storageSftp->session = NULL;
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))),
ServiceError, "failed to close sftpHandle: libssh2 errno [-7]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() sftp close handle failure, sftpHandle not NULL, EAGAIN");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",1,0,1]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = NULL}
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
// Populate sftpHandle, NULL out sftpSession and session
storageSftp->sftpHandle = libssh2_sftp_open_ex(storageSftp->sftpSession, TEST_PATH, 25, 1, 0, 1);
storageSftp->sftpSession = NULL;
storageSftp->session = NULL;
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))),
ServiceError, "timeout closing sftpHandle: libssh2 errno [-37]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() sftp close handle failure, sftpHandle not NULL, libssh2 sftp error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_OPEN_EX, .param = "[\"" TEST_PATH "\",1,0,1]"},
{.function = HRNLIBSSH2_SFTP_CLOSE_HANDLE, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_CONNECTION_LOST},
{.function = NULL}
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
// Populate sftpHandle, NULL out sftpSession and session
storageSftp->sftpHandle = libssh2_sftp_open_ex(storageSftp->sftpSession, TEST_PATH, 25, 1, 0, 1);
storageSftp->sftpSession = NULL;
storageSftp->session = NULL;
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))),
ServiceError, "failed to close sftpHandle: libssh2 errno [-31]: sftp errno [7]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() sftp shutdown failure libssh2 error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_SOCKET_SEND},
{.function = NULL},
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))), ServiceError,
"failed to shutdown sftpSession: libssh2 errno [-7]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() sftp shutdown failure libssh2 sftp error");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_CONNECTION_LOST},
{.function = NULL},
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))), ServiceError,
"failed to shutdown sftpSession: libssh2 errno [-31]: sftp errno [7]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() sftp shutdown failure EAGAIN");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = NULL},
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))), ServiceError,
"timeout shutting down sftpSession: libssh2 errno [-37]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() session disconnect failure");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgBackRest instance shutdown\",\"\"]",
.resultInt = LIBSSH2_ERROR_SOCKET_DISCONNECT},
{.function = NULL},
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))),
ServiceError, "failed to disconnect libssh2 session: libssh2 errno [-13]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() session disconnect failure EAGAIN");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgBackRest instance shutdown\",\"\"]",
.resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = NULL},
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))),
ServiceError, "timeout disconnecting libssh2 session: libssh2 errno [-37]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() session free failure");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgBackRest instance shutdown\",\"\"]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_FREE, .resultInt = LIBSSH2_ERROR_SOCKET_DISCONNECT},
{.function = NULL},
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))), ServiceError,
"failed to free libssh2 session: libssh2 errno [-13]");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() session free failure EAGAIN");
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
{
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgBackRest instance shutdown\",\"\"]",
.resultInt = LIBSSH2_ERROR_NONE},
{.function = HRNLIBSSH2_SESSION_FREE, .resultInt = LIBSSH2_ERROR_EAGAIN},
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING},
{.function = NULL},
});
TEST_ASSIGN(
storageTest,
storageSftpNewP(
cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx),
cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx),
cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT,
.modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx),
.keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx),
.hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx),
.hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx),
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true),
"new storage (defaults)");
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))), ServiceError,
"timeout freeing libssh2 session: libssh2 errno [-37]");
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("storageSftpEvalLibSsh2Error()"))
{
#ifdef HAVE_LIBSSH2
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpEvalLibSsh2Error()");
TEST_ERROR_FMT(
storageSftpEvalLibSsh2Error(
-11, 16, &FileRemoveError, strNewFmt("unable to move '%s' to '%s'", "BOGUS", "NOT BOGUS"), STRDEF("HINT")),
FileRemoveError,
"unable to move 'BOGUS' to 'NOT BOGUS': libssh2 error [-11]\n"
"HINT");
TEST_ERROR_FMT(
storageSftpEvalLibSsh2Error(
LIBSSH2_ERROR_SFTP_PROTOCOL, 16, &FileRemoveError,
strNewFmt("unable to move '%s' to '%s'", "BOGUS", "NOT BOGUS"), STRDEF("HINT")),
FileRemoveError,
"unable to move 'BOGUS' to 'NOT BOGUS': libssh2 error [-31]: sftp error [16]\n"
"HINT");
TEST_ERROR_FMT(
storageSftpEvalLibSsh2Error(
LIBSSH2_ERROR_SFTP_PROTOCOL, 16, &FileRemoveError,
strNewFmt("unable to move '%s' to '%s'", "BOGUS", "NOT BOGUS"), NULL),
FileRemoveError,
"unable to move 'BOGUS' to 'NOT BOGUS': libssh2 error [-31]: sftp error [16]");
TEST_ERROR_FMT(
storageSftpEvalLibSsh2Error(
LIBSSH2_ERROR_SFTP_PROTOCOL, 16, &FileRemoveError, NULL, NULL),
FileRemoveError,
"libssh2 error [-31]: sftp error [16]");
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
#ifdef HAVE_LIBSSH2
hrnFdReadyShimUninstall();
hrnSckClientOpenShimUninstall();
#endif // HAVE_LIBSSH2
FUNCTION_HARNESS_RETURN_VOID();
}