100 lines
3.1 KiB
C++
100 lines
3.1 KiB
C++
/*
|
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
|
*
|
|
* Live round-trip against a running plan9port plumber. This is the real proof
|
|
* that our native C++ 9P2000 client speaks the protocol correctly: it sends a
|
|
* plumb message through the "send" port and receives the routed message back on
|
|
* the "edit" port via the Plumber reader thread.
|
|
*
|
|
* If no plumb socket is reachable (no plumber, no $NAMESPACE), the test skips
|
|
* itself and PASSES, so it is safe to run in headless/CI environments.
|
|
*/
|
|
#include "ninep.h"
|
|
#include "plumber.h"
|
|
|
|
#include <QCoreApplication>
|
|
#include <QFileInfo>
|
|
#include <QObject>
|
|
#include <QSignalSpy>
|
|
#include <QTemporaryFile>
|
|
#include <QTest>
|
|
|
|
using namespace deft;
|
|
|
|
class TestPlumbLive : public QObject
|
|
{
|
|
Q_OBJECT
|
|
private Q_SLOTS:
|
|
void connectAttach();
|
|
void sendThenReceiveOnEditPort();
|
|
};
|
|
|
|
static bool plumberReachable()
|
|
{
|
|
const QString path = Plumber::socketPath();
|
|
if (path.isEmpty() || !QFileInfo::exists(path)) {
|
|
return false;
|
|
}
|
|
NineP n;
|
|
const bool ok = n.connectAndAttach(path, QStringLiteral("tester"));
|
|
return ok;
|
|
}
|
|
|
|
void TestPlumbLive::connectAttach()
|
|
{
|
|
if (!plumberReachable()) {
|
|
QSKIP("no reachable plumber (socketPath empty/absent) — skipping live test");
|
|
}
|
|
NineP n;
|
|
QVERIFY2(n.connectAndAttach(Plumber::socketPath(), QStringLiteral("tester")),
|
|
qPrintable(n.errorString()));
|
|
QVERIFY(n.isConnected());
|
|
// We can walk to the well-known ports.
|
|
QVERIFY2(n.walk(2, QStringLiteral("send")), qPrintable(n.errorString()));
|
|
QVERIFY2(n.walk(3, QStringLiteral("edit")), qPrintable(n.errorString()));
|
|
}
|
|
|
|
void TestPlumbLive::sendThenReceiveOnEditPort()
|
|
{
|
|
if (!plumberReachable()) {
|
|
QSKIP("no reachable plumber — skipping live round-trip");
|
|
}
|
|
|
|
// A real, existing file so the plumber's "existing file -> edit" rule fires.
|
|
QTemporaryFile tmp;
|
|
tmp.setAutoRemove(true);
|
|
QVERIFY(tmp.open());
|
|
tmp.write("line1\nline2\nline3\n");
|
|
tmp.flush();
|
|
const QString file = tmp.fileName();
|
|
const QFileInfo fi(file);
|
|
const QString wdir = fi.absolutePath();
|
|
|
|
Plumber plumber;
|
|
QSignalSpy editSpy(&plumber, &Plumber::edit);
|
|
QSignalSpy errSpy(&plumber, &Plumber::readerError);
|
|
plumber.startReader();
|
|
|
|
// Give the reader thread a moment to attach + open the edit port before we
|
|
// send, so the routed message isn't delivered before anyone is listening.
|
|
QTest::qWait(300);
|
|
if (errSpy.count() > 0) {
|
|
QSKIP(qPrintable(QStringLiteral("reader could not open edit port: %1")
|
|
.arg(errSpy.first().first().toString())));
|
|
}
|
|
|
|
// Send "<file>:2" — the plumber resolves it and routes it to the edit port.
|
|
QVERIFY2(plumber.send(file + QStringLiteral(":2"), wdir),
|
|
qPrintable(plumber.errorString()));
|
|
|
|
// The reader should surface the routed message as an edit() signal.
|
|
QVERIFY(editSpy.wait(3000));
|
|
QCOMPARE(editSpy.count(), 1);
|
|
const QList<QVariant> args = editSpy.first();
|
|
QCOMPARE(args.at(0).toString(), file);
|
|
QCOMPARE(args.at(1).toString(), QStringLiteral("2"));
|
|
}
|
|
|
|
QTEST_MAIN(TestPlumbLive)
|
|
#include "test_plumb_live.moc"
|