diff --git a/test/integration/framework/base.h b/test/integration/framework/base.h index 795c5910..92ca9532 100644 --- a/test/integration/framework/base.h +++ b/test/integration/framework/base.h @@ -40,6 +40,8 @@ class IO { * Have to use second param as the ASSERT_*'s return a non-QByteArray. */ void ReadUntilAndGet(QByteArray pattern, QByteArray& match); + // Can be used to check that something was not sent. Slow. + QByteArray ReadRemainder(); void Write(QByteArray s = "", bool new_line = true); void Close(); @@ -140,6 +142,9 @@ void IO::ReadUntilAndGet(QByteArray pattern, QByteArray& match) { if (search != -1) { match += m_readed.mid(start, search - start); m_readed.remove(0, search + 1); + if (match.endsWith('\r')) { + match.chop(1); + } return; } /* No newline yet, add to retvalue and trunc output */ @@ -162,6 +167,23 @@ void IO::ReadUntilAndGet(QByteArray pattern, QByteArray& match) { } } +template +QByteArray IO::ReadRemainder() { + auto deadline = QDateTime::currentDateTime().addSecs(2); + while (QDateTime::currentDateTime() < deadline) { + const int timeout_ms =QDateTime::currentDateTime().msecsTo(deadline); + m_device->waitForReadyRead(std::max(1, timeout_ms)); + QByteArray chunk = m_device->readAll(); + if (m_verbose) { + std::cout << chunk.toStdString() << std::flush; + } + m_readed += chunk; + } + QByteArray result = std::move(m_readed); + m_readed.clear(); + return result; +} + template void IO::Write(QByteArray s, bool new_line) { if (!m_device) return; diff --git a/test/integration/tests/modules.cpp b/test/integration/tests/modules.cpp index 7fb55bac..7ec0d74e 100644 --- a/test/integration/tests/modules.cpp +++ b/test/integration/tests/modules.cpp @@ -14,8 +14,10 @@ * limitations under the License. */ -#include "znctest.h" #include +#include + +#include "znctest.h" using testing::HasSubstr; @@ -138,8 +140,8 @@ TEST_F(ZNCTest, AutoAttachModule) { auto ircd = ConnectIRCd(); auto client = LoginClient(); InstallModule("testmod.cpp", R"( - #include #include + #include class TestModule : public CModule { public: MODCONSTRUCTOR(TestModule) {} @@ -192,12 +194,79 @@ TEST_F(ZNCTest, ModuleCSRFOverride) { auto client = LoginClient(); client.Write("znc loadmod samplewebapi"); client.ReadUntil("Loaded module"); - auto request = QNetworkRequest(QUrl("http://127.0.0.1:12345/mods/global/samplewebapi/")); - auto reply = HttpPost(request, { - {"text", "ipsum"} - })->readAll().toStdString(); + auto request = QNetworkRequest( + QUrl("http://127.0.0.1:12345/mods/global/samplewebapi/")); + auto reply = + HttpPost(request, {{"text", "ipsum"}})->readAll().toStdString(); EXPECT_THAT(reply, HasSubstr("ipsum")); } +class SaslModuleTest : public ZNCTest, + public testing::WithParamInterface< + std::pair>> { + public: + static std::string Prefix() { + std::string s; + for (int i = 0; i < 33; ++i) s += "YWFh"; + s += "YQBh"; + for (int i = 0; i < 33; ++i) s += "YWFh"; + s += "AGJi"; + for (int i = 0; i < 31; ++i) s += "YmJi"; + EXPECT_EQ(s.length(), 396); + return s; + } + + protected: + int PassLen() { return std::get<0>(GetParam()); } + void ExpectPlainAuth(Socket& ircd) { + for (const auto& str : std::get<1>(GetParam())) { + QByteArray line; + ircd.ReadUntilAndGet("AUTHENTICATE ", line); + ASSERT_EQ(line.toStdString(), "AUTHENTICATE " + str); + } + ASSERT_EQ(ircd.ReadRemainder().indexOf("AUTHENTICATE"), -1); + } +}; + +TEST_P(SaslModuleTest, Test) { + QFile conf(m_dir.path() + "/configs/znc.conf"); + ASSERT_TRUE(conf.open(QIODevice::Append | QIODevice::Text)); + QTextStream(&conf) << "ServerThrottle = 1\n"; + auto znc = Run(); + auto ircd = ConnectIRCd(); + auto client = LoginClient(); + client.Write("znc loadmod sasl"); + QByteArray sUser(100, 'a'); + QByteArray sPass(PassLen(), 'b'); + client.Write("PRIVMSG *sasl :set " + sUser + " " + sPass); + client.Write("znc jump"); + ircd = ConnectIRCd(); + ircd.ReadUntil("CAP LS"); + ircd.Write("CAP * LS :sasl"); + ircd.ReadUntil("CAP REQ :sasl"); + ircd.Write("CAP * ACK :sasl"); + ircd.ReadUntil("AUTHENTICATE EXTERNAL"); + ircd.Write(":server 904 *"); + ircd.ReadUntil("AUTHENTICATE PLAIN"); + ircd.Write("AUTHENTICATE +"); + ExpectPlainAuth(ircd); + ircd.Write(":server 903 user :Logged in"); + ircd.ReadUntil("CAP END"); +} + +INSTANTIATE_TEST_CASE_P(SaslInst, SaslModuleTest, + testing::Values( + std::pair>{ + 95, {SaslModuleTest::Prefix()}}, + std::pair>{ + 96, {SaslModuleTest::Prefix() + "Yg==", "+"}}, + std::pair>{ + 97, {SaslModuleTest::Prefix() + "YmI=", "+"}}, + std::pair>{ + 98, {SaslModuleTest::Prefix() + "YmJi", "+"}}, + std::pair>{ + 99, + {SaslModuleTest::Prefix() + "YmJi", "Yg=="}})); + } // namespace } // namespace znc_inttest