Fix/improve CLI tests
* Adapt to interleaved output previously enabled in SyncthingTestInstance * Make it work when verbose output for debugging is enabled * Show which status line didn't match in case of an failure * Disable flaky rescan tests in release mode
This commit is contained in:
parent
1c6bd37b9d
commit
703225b410
|
@ -1,3 +1,12 @@
|
|||
Overall statistics
|
||||
Status idle
|
||||
Global 0 file\(s\), 0 dir\(s\), 0 bytes
|
||||
Local 0 file\(s\), 0 dir\(s\), 0 bytes
|
||||
Incoming traffic 0 bytes
|
||||
Outgoing traffic 0 bytes
|
||||
Connected to no other devices
|
||||
Version syncthing v.*
|
||||
|
||||
Directories
|
||||
- test2
|
||||
Label Test dir 2
|
||||
|
@ -34,7 +43,7 @@ Devices
|
|||
- Test dev 2
|
||||
ID MMGUI6U-WUEZQCP-XZZ6VYB-LCT4TVC-ER2HAVX-QYT6X7D-S6ZSG2B-323KLQ7
|
||||
Status paused
|
||||
Addresses tcp://.*22000
|
||||
Addresses tcp://.*22001
|
||||
Compression metadata
|
||||
|
||||
- .*
|
||||
|
|
|
@ -76,6 +76,7 @@ void ApplicationTests::tearDown()
|
|||
#ifdef PLATFORM_UNIX
|
||||
/*!
|
||||
* \brief Tests the overall CLI application.
|
||||
* \remarks Tests for rescan are currently disabled for release mode because they sometimes fail.
|
||||
*/
|
||||
void ApplicationTests::test()
|
||||
{
|
||||
|
@ -88,8 +89,14 @@ void ApplicationTests::test()
|
|||
setenv("ENABLE_ESCAPE_CODES", "0", true);
|
||||
|
||||
// load expected status
|
||||
const auto expectedStatusData(readFile(testFilePath("expected-status.txt"), 2048));
|
||||
const regex expectedStatus(expectedStatusData);
|
||||
const auto expectedStatusData(readFile(testFilePath("expected-status.txt"), 4000));
|
||||
const auto expectedStatusLines(splitString<vector<string>>(expectedStatusData, "\n"));
|
||||
vector<regex> expectedStatusPatterns;
|
||||
expectedStatusPatterns.reserve(expectedStatusLines.size());
|
||||
for (const auto &line : expectedStatusLines) {
|
||||
expectedStatusPatterns.emplace_back(line);
|
||||
}
|
||||
CPPUNIT_ASSERT(!expectedStatusPatterns.empty());
|
||||
|
||||
// save cwd (to restore later)
|
||||
char cwd[1024];
|
||||
|
@ -112,13 +119,28 @@ void ApplicationTests::test()
|
|||
syncthingOutput.append(syncthingProcess().readAll());
|
||||
} while (!syncthingOutput.contains("Access the GUI via the following URL"));
|
||||
|
||||
setInterleavedOutputEnabledFromEnv();
|
||||
|
||||
// test status for all dirs and devs
|
||||
const char *const statusArgs[] = { "syncthingctl", "status", "--api-key", apiKey.data(), "--url", url.data(), nullptr };
|
||||
const char *const statusArgs[] = { "syncthingctl", "status", "--api-key", apiKey.data(), "--url", url.data(), "--no-color", nullptr };
|
||||
TESTUTILS_ASSERT_EXEC(statusArgs);
|
||||
cout << stdout;
|
||||
if (!regex_search(stdout, expectedStatus)) {
|
||||
cout << "expected status: " << expectedStatusData << '\n';
|
||||
CPPUNIT_FAIL("Actual status does not match expected status.");
|
||||
const auto statusLines(splitString(stdout, "\n"));
|
||||
auto currentStatusLine = statusLines.cbegin();
|
||||
auto currentPattern = 0_st;
|
||||
for (const auto &expectedPattern : expectedStatusPatterns) {
|
||||
bool patternFound = false;
|
||||
while (currentStatusLine != statusLines.cend()) {
|
||||
patternFound = regex_search(*currentStatusLine, expectedPattern);
|
||||
++currentStatusLine;
|
||||
if (patternFound) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!patternFound) {
|
||||
CPPUNIT_FAIL(argsToString("Line ", expectedStatusLines[currentPattern], " could not be found in output."));
|
||||
}
|
||||
++currentPattern;
|
||||
}
|
||||
|
||||
// test log
|
||||
|
@ -139,16 +161,18 @@ void ApplicationTests::test()
|
|||
const char *const statusDirsOnlyArgs[] = { "syncthingctl", "status", "--all-dirs", nullptr };
|
||||
TESTUTILS_ASSERT_EXEC(resumeArgs);
|
||||
TESTUTILS_ASSERT_EXEC(statusDirsOnlyArgs);
|
||||
CPPUNIT_ASSERT(stdout.find("test2") != string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find(" - test2") != string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find("paused") == string::npos);
|
||||
|
||||
// test pause, verify via status on specific dir
|
||||
const char *const pauseArgs[] = { "syncthingctl", "pause", "--dir", "test2", nullptr };
|
||||
const char *const statusTest2Args[] = { "syncthingctl", "status", "--dir", "test2", nullptr };
|
||||
TESTUTILS_ASSERT_EXEC(pauseArgs);
|
||||
cout << stdout;
|
||||
TESTUTILS_ASSERT_EXEC(statusTest2Args);
|
||||
CPPUNIT_ASSERT(stdout.find("test1") == string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find("test2") != string::npos);
|
||||
cout << stdout;
|
||||
CPPUNIT_ASSERT(stdout.find(" - test1") == string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find(" - test2") != string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find("paused") != string::npos);
|
||||
|
||||
// test cat
|
||||
|
@ -171,19 +195,20 @@ void ApplicationTests::test()
|
|||
cout << stdout;
|
||||
TESTUTILS_ASSERT_EXEC(statusTest1Args);
|
||||
cout << stdout;
|
||||
CPPUNIT_ASSERT(stdout.find("test1") != string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find("test2") == string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find(" - test1") != string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find(" - test2") == string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find("Rescan interval file system watcher and periodic rescan disabled") != string::npos);
|
||||
#endif
|
||||
|
||||
// test rescan: create new file, trigger rescan, check status
|
||||
#ifdef DEBUG_BUILD
|
||||
CPPUNIT_ASSERT(ofstream("/tmp/some/path/1/new-file.txt") << "foo");
|
||||
const char *const rescanArgs[] = { "syncthingctl", "rescan", "test1", nullptr };
|
||||
TESTUTILS_ASSERT_EXEC(rescanArgs);
|
||||
cout << stdout;
|
||||
TESTUTILS_ASSERT_EXEC(statusTest1Args);
|
||||
cout << stdout;
|
||||
CPPUNIT_ASSERT(stdout.find("test1") != string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find(" - test1") != string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find("Local 1 file(s), 0 dir(s), 3 bytes") != string::npos);
|
||||
|
||||
// test pwd
|
||||
|
@ -209,12 +234,13 @@ void ApplicationTests::test()
|
|||
const char *const pwdStatusArgs[] = { "syncthingctl", "pwd", "status", nullptr };
|
||||
TESTUTILS_ASSERT_EXEC(pwdStatusArgs);
|
||||
cout << stdout;
|
||||
CPPUNIT_ASSERT(stdout.find("test1") != string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find(" - test1") != string::npos);
|
||||
CPPUNIT_ASSERT(stdout.find("Local 2 file(s), 1 dir(s)") != string::npos);
|
||||
|
||||
// switch back to initial working dir
|
||||
if (hasCwd) {
|
||||
chdir(cwd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -458,7 +458,7 @@ QNetworkReply *SyncthingConnection::requestData(const QString &path, const QUrlQ
|
|||
#ifndef LIB_SYNCTHING_CONNECTOR_CONNECTION_MOCKED
|
||||
auto *const reply = networkAccessManager().get(prepareRequest(path, query, rest));
|
||||
#ifdef LIB_SYNCTHING_CONNECTOR_LOG_API_CALLS
|
||||
cout << Phrases::Info << "GETing: " << reply->url().toString().toStdString() << Phrases::EndFlush;
|
||||
cerr << Phrases::Info << "GETing: " << reply->url().toString().toStdString() << Phrases::EndFlush;
|
||||
#endif
|
||||
reply->ignoreSslErrors(m_expectedSslErrors);
|
||||
return reply;
|
||||
|
@ -474,7 +474,7 @@ QNetworkReply *SyncthingConnection::postData(const QString &path, const QUrlQuer
|
|||
{
|
||||
auto *const reply = networkAccessManager().post(prepareRequest(path, query), data);
|
||||
#ifdef LIB_SYNCTHING_CONNECTOR_LOG_API_CALLS
|
||||
cout << Phrases::Info << "POSTing: " << reply->url().toString().toStdString() << Phrases::End << data.data() << endl;
|
||||
cerr << Phrases::Info << "POSTing: " << reply->url().toString().toStdString() << Phrases::End << data.data() << endl;
|
||||
#endif
|
||||
reply->ignoreSslErrors(m_expectedSslErrors);
|
||||
return reply;
|
||||
|
@ -1550,7 +1550,7 @@ void SyncthingConnection::readEvents()
|
|||
|
||||
#ifdef LIB_SYNCTHING_CONNECTOR_LOG_SYNCTHING_EVENTS
|
||||
if (!replyArray.isEmpty()) {
|
||||
cout << Phrases::Info << "Received " << replyArray.size() << " Syncthing events:" << Phrases::End
|
||||
cerr << Phrases::Info << "Received " << replyArray.size() << " Syncthing events:" << Phrases::End
|
||||
<< replyDoc.toJson(QJsonDocument::Indented).data() << endl;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -115,6 +115,7 @@ ConnectionTests::ConnectionTests()
|
|||
*/
|
||||
void ConnectionTests::setUp()
|
||||
{
|
||||
setInterleavedOutputEnabledFromEnv();
|
||||
SyncthingTestInstance::start();
|
||||
|
||||
cerr << "\n - Preparing connection ..." << endl;
|
||||
|
|
|
@ -19,6 +19,7 @@ static char *dummy2;
|
|||
SyncthingTestInstance::SyncthingTestInstance()
|
||||
: m_apiKey(QStringLiteral("syncthingtestinstance"))
|
||||
, m_app(dummy1, &dummy2)
|
||||
, m_interleavedOutput(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -73,11 +74,6 @@ void SyncthingTestInstance::start()
|
|||
const int syncthingPortFromEnv(qEnvironmentVariableIntValue("SYNCTHING_PORT"));
|
||||
m_syncthingPort = !syncthingPortFromEnv ? QStringLiteral("4001") : QString::number(syncthingPortFromEnv);
|
||||
|
||||
// forward Syncthing's output to see what Syncthing is doing and what the test is doing at the same time
|
||||
if (qEnvironmentVariableIsEmpty("SYNCTHING_TEST_NO_INTERLEAVED_OUTPUT")) {
|
||||
m_syncthingProcess.setReadChannelMode(QProcess::ForwardedChannels);
|
||||
}
|
||||
|
||||
// start st
|
||||
// clang-format off
|
||||
const QStringList args{
|
||||
|
@ -121,4 +117,26 @@ void SyncthingTestInstance::stop()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets whether Syncthing's output should be forwarded to see what Syncthing and the test is doing at the same time.
|
||||
*/
|
||||
void SyncthingTestInstance::setInterleavedOutputEnabled(bool interleavedOutputEnabled)
|
||||
{
|
||||
if (interleavedOutputEnabled == m_interleavedOutput) {
|
||||
return;
|
||||
}
|
||||
m_interleavedOutput = interleavedOutputEnabled;
|
||||
m_syncthingProcess.setReadChannelMode(interleavedOutputEnabled ? QProcess::ForwardedChannels : QProcess::SeparateChannels);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies the default for isInterleavedOutputEnabled() considering environment variable SYNCTHING_TEST_NO_INTERLEAVED_OUTPUT.
|
||||
*/
|
||||
void SyncthingTestInstance::setInterleavedOutputEnabledFromEnv()
|
||||
{
|
||||
if (qEnvironmentVariableIsEmpty("SYNCTHING_TEST_NO_INTERLEAVED_OUTPUT")) {
|
||||
setInterleavedOutputEnabled(true);
|
||||
}
|
||||
}
|
||||
} // namespace TestUtilities
|
||||
|
|
|
@ -30,12 +30,16 @@ public:
|
|||
public Q_SLOTS:
|
||||
void start();
|
||||
void stop();
|
||||
bool isInterleavedOutputEnabled() const;
|
||||
void setInterleavedOutputEnabled(bool interleavedOutputEnabled);
|
||||
void setInterleavedOutputEnabledFromEnv();
|
||||
|
||||
private:
|
||||
QString m_apiKey;
|
||||
QString m_syncthingPort;
|
||||
QCoreApplication m_app;
|
||||
Data::SyncthingProcess m_syncthingProcess;
|
||||
bool m_interleavedOutput;
|
||||
};
|
||||
|
||||
inline const QString &SyncthingTestInstance::apiKey() const
|
||||
|
@ -57,6 +61,14 @@ inline QProcess &SyncthingTestInstance::syncthingProcess()
|
|||
{
|
||||
return m_syncthingProcess;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Whether Syncthing's output should be forwarded to see what Syncthing and the test is doing at the same time.
|
||||
*/
|
||||
inline bool SyncthingTestInstance::isInterleavedOutputEnabled() const
|
||||
{
|
||||
return m_interleavedOutput;
|
||||
}
|
||||
} // namespace TestUtilities
|
||||
|
||||
#endif // SYNCTHINGTESTHELPER_SYNCTHINGTESTINSTANCE_H
|
||||
|
|
Loading…
Reference in New Issue