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

Add facility for reading and writing adhoc protocol output.

Pushing output through a JSON blob is not practical if the output is extremely large, e.g. a backup manifest with 100K+ files.

Add read/write routines so that output can be returned in chunks but errors will still be detected.
This commit is contained in:
David Steele
2019-11-16 17:05:34 -05:00
parent 90e19d99ba
commit 6827a13f3a
7 changed files with 172 additions and 28 deletions

View File

@ -43,7 +43,8 @@ testServerProtocol(const String *command, const VariantList *paramList, Protocol
else if (strEq(command, strNew("request-complex")))
{
protocolServerResponse(server, varNewBool(false));
ioWriteStrLine(protocolServerIoWrite(server), strNew("LINEOFTEXT"));
protocolServerWriteLine(server, strNew("LINEOFTEXT"));
protocolServerWriteLine(server, NULL);
ioWriteFlush(protocolServerIoWrite(server));
}
else
@ -403,9 +404,31 @@ testRun(void)
// Send output
TEST_RESULT_STR(strPtr(ioReadLine(read)), "{\"cmd\":\"test\"}", "test command");
ioWriteStrLine(write, strNew(".OUTPUT"));
ioWriteStrLine(write, strNew("{\"out\":[\"value1\",\"value2\"]}"));
ioWriteFlush(write);
// invalid line
TEST_RESULT_STR(strPtr(ioReadLine(read)), "{\"cmd\":\"invalid-line\"}", "invalid line command");
ioWrite(write, LF_BUF);
ioWriteFlush(write);
// error instead of output
TEST_RESULT_STR(
strPtr(ioReadLine(read)), "{\"cmd\":\"error-instead-of-output\"}", "error instead of output command");
ioWriteStrLine(write, strNew("{\"err\":255}"));
ioWriteFlush(write);
// unexpected output
TEST_RESULT_STR(strPtr(ioReadLine(read)), "{\"cmd\":\"unexpected-output\"}", "unexpected output");
ioWriteStrLine(write, strNew("{}"));
ioWriteFlush(write);
// invalid prefix
TEST_RESULT_STR(strPtr(ioReadLine(read)), "{\"cmd\":\"invalid-prefix\"}", "invalid prefix");
ioWriteStrLine(write, strNew("~line"));
ioWriteFlush(write);
// Wait for exit
TEST_RESULT_STR(strPtr(ioReadLine(read)), "{\"cmd\":\"exit\"}", "exit command");
}
@ -472,14 +495,38 @@ testRun(void)
// Get command output
const VariantList *output = NULL;
TEST_ASSIGN(
output,
varVarLst(protocolClientExecute(client, protocolCommandNew(strNew("test")), true)),
"execute command with output");
TEST_RESULT_VOID(
protocolClientWriteCommand(client, protocolCommandNew(strNew("test"))), "execute command with output");
TEST_RESULT_STR_Z(protocolClientReadLine(client), "OUTPUT", "check output");
TEST_ASSIGN(output, varVarLst(protocolClientReadOutput(client, true)), "execute command with output");
TEST_RESULT_UINT(varLstSize(output), 2, "check output size");
TEST_RESULT_STR(strPtr(varStr(varLstGet(output, 0))), "value1", "check value1");
TEST_RESULT_STR(strPtr(varStr(varLstGet(output, 1))), "value2", "check value2");
// Invalid line
TEST_RESULT_VOID(
protocolClientWriteCommand(client, protocolCommandNew(strNew("invalid-line"))),
"execute command that returns invalid line");
TEST_ERROR(protocolClientReadLine(client), FormatError, "unexpected empty line");
// Error instead of output
TEST_RESULT_VOID(
protocolClientWriteCommand(client, protocolCommandNew(strNew("error-instead-of-output"))),
"execute command that returns error instead of output");
TEST_ERROR(protocolClientReadLine(client), UnknownError, "raised from test client: no details available");
// Unexpected output
TEST_RESULT_VOID(
protocolClientWriteCommand(client, protocolCommandNew(strNew("unexpected-output"))),
"execute command that returns unexpected output");
TEST_ERROR(protocolClientReadLine(client), FormatError, "expected error but got output");
// Invalid prefix
TEST_RESULT_VOID(
protocolClientWriteCommand(client, protocolCommandNew(strNew("invalid-prefix"))),
"execute command that returns an invalid prefix");
TEST_ERROR(protocolClientReadLine(client), FormatError, "invalid prefix in '~line'");
// Free client
TEST_RESULT_VOID(protocolClientFree(client), "free client");
}
@ -537,7 +584,8 @@ testRun(void)
TEST_RESULT_VOID(ioWriteStrLine(write, strNew("{\"cmd\":\"request-complex\"}")), "write complex request");
TEST_RESULT_VOID(ioWriteFlush(write), "flush complex request");
TEST_RESULT_STR(strPtr(ioReadLine(read)), "{\"out\":false}", "complex request result");
TEST_RESULT_STR(strPtr(ioReadLine(read)), "LINEOFTEXT", "complex request result");
TEST_RESULT_STR_Z(ioReadLine(read), ".LINEOFTEXT", "complex request result");
TEST_RESULT_STR_Z(ioReadLine(read), ".", "complex request result");
// Exit
TEST_RESULT_VOID(ioWriteStrLine(write, strNew("{\"cmd\":\"exit\"}")), "write exit");