Merge branch 'master' into sasl

Conflicts:
	include/znc/Client.h
	src/Client.cpp
	src/Modules.cpp
	test/integration/tests/modules.cpp
This commit is contained in:
Alexey Sokolov
2025-02-13 20:37:32 +00:00
381 changed files with 12248 additions and 4121 deletions
+12 -5
View File
@@ -1,5 +1,5 @@
#
# Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
# Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,17 +14,23 @@
# limitations under the License.
#
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.13)
project(ZNCIntegrationTest LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED true)
set(CMAKE_THREAD_PREFER_PTHREAD true)
set(THREADS_PREFER_PTHREAD_FLAG true)
find_package(Threads REQUIRED)
find_package(Qt5Network 5.4 REQUIRED HINTS ${Qt5_HINTS})
if(DEFINED ENV{ZNC_QT_VER})
set(ZNC_QT_VER $ENV{ZNC_QT_VER})
else()
set(ZNC_QT_VER 6)
endif()
find_package(Qt${ZNC_QT_VER}Network 5.4 REQUIRED HINTS ${Qt_HINTS})
# Force the simple internal regex engine to get consistent behavior on all
# platforms. See
@@ -42,9 +48,10 @@ add_executable(inttest
"${GTEST_ROOT}/src/gtest-all.cc"
"${GMOCK_ROOT}/src/gmock-all.cc")
target_link_libraries(inttest Qt5::Network Threads::Threads)
target_link_libraries(inttest Qt${ZNC_QT_VER}::Network Threads::Threads)
target_include_directories(inttest PUBLIC
"${PROJECT_SOURCE_DIR}/framework"
"${PROJECT_BINARY_DIR}"
"${GTEST_ROOT}" "${GTEST_ROOT}/include"
"${GMOCK_ROOT}" "${GMOCK_ROOT}/include")
target_compile_definitions(inttest PRIVATE
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+18 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <QRegularExpression>
#include "znctest.h"
#ifndef ZNC_BIN_DIR
@@ -48,6 +49,14 @@ void WriteConfig(QString path) {
p.ReadUntil("Launch ZNC now?"); p.Write("no");
p.ShouldFinishItself();
// clang-format on
// Default 30s is too slow for the test
QFile conf(path + "/configs/znc.conf");
ASSERT_TRUE(conf.open(QIODevice::Append | QIODevice::Text));
QTextStream out(&conf);
out << R"(
ServerThrottle = 5
)";
}
void ZNCTest::SetUp() {
@@ -111,6 +120,12 @@ std::unique_ptr<QNetworkReply> ZNCTest::HandleHttp(QNetworkReply* reply) {
std::cout << "Got HTTP reply" << std::endl;
loop.quit();
});
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QObject::connect(reply, &QNetworkReply::errorOccurred,
[&](QNetworkReply::NetworkError e) {
ADD_FAILURE() << reply->errorString().toStdString();
});
#else
QObject::connect(
reply,
static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(
@@ -118,6 +133,7 @@ std::unique_ptr<QNetworkReply> ZNCTest::HandleHttp(QNetworkReply* reply) {
[&](QNetworkReply::NetworkError e) {
ADD_FAILURE() << reply->errorString().toStdString();
});
#endif
QTimer::singleShot(30000 /* msec */, &loop, [&]() {
ADD_FAILURE() << "connection timeout";
loop.quit();
@@ -152,7 +168,7 @@ void ZNCTest::InstallModule(QString name, QString content) {
QStringList lines = content.split("\n");
int maxoffset = -1;
for (const QString& line : lines) {
int nonspace = line.indexOf(QRegExp("\\S"));
int nonspace = line.indexOf(QRegularExpression("\\S"));
if (nonspace == -1) continue;
if (nonspace < maxoffset || maxoffset == -1) maxoffset = nonspace;
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+398 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,11 +14,14 @@
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "znctest.h"
#include "znctestconfig.h"
using testing::HasSubstr;
using testing::ContainsRegex;
namespace znc_inttest {
namespace {
@@ -165,6 +168,7 @@ TEST_F(ZNCTest, InvalidConfigInChan) {
auto znc = Run();
znc->ShouldFinishItself(1);
}
TEST_F(ZNCTest, Encoding) {
auto znc = Run();
auto ircd = ConnectIRCd();
@@ -269,6 +273,55 @@ TEST_F(ZNCTest, AwayNotify) {
client.Write("znc shutdown");
}
TEST_F(ZNCTest, ExtendedJoin) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
ircd.Write(":server 001 user :welcome");
client.ReadUntil(" 001 ");
ircd.Write(":nick!user@host JOIN #channel account :Real Name");
// Not sure why it is like this when server sends such format unexpectedly.
client.ReadUntil("JOIN #channel account :Real Name");
ircd.Write("CAP nick ACK extended-join");
ircd.Write(":nick!user@host JOIN #channel2 account :Real Name");
QByteArray line;
client.ReadUntilAndGet("JOIN", line);
EXPECT_EQ(line.toStdString(), "JOIN #channel2");
client.Write("CAP REQ extended-join");
client.ReadUntil("CAP user ACK :extended-join");
ircd.Write(":nick!user@host JOIN #channel3 account :Real Name");
client.ReadUntil("JOIN #channel3 account :Real Name");
}
TEST_F(ZNCTest, CAP302LSWaitFull) {
auto znc = Run();
auto ircd = ConnectIRCd();
ircd.ReadUntil("CAP LS 302");
ircd.Write("CAP user LS * :away-notify");
ASSERT_THAT(ircd.ReadRemainder().toStdString(), Not(HasSubstr("away-notify")));
ircd.Write("CAP user LS :blahblah");
ircd.ReadUntil("CAP REQ :away-notify");
}
TEST_F(ZNCTest, CAP302NewDel) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
ircd.Write("CAP nick LS :blahblah");
ircd.ReadUntil("CAP END");
ircd.Write(":server 001 nick :Hello");
client.Write("CAP REQ :away-notify");
client.ReadUntil("NAK :away-notify");
client.Write("CAP REQ :cap-notify");
client.ReadUntil("ACK :cap-notify");
ircd.Write("CAP nick NEW :away-notify");
ircd.ReadUntil("CAP REQ :away-notify");
ircd.Write("CAP nick ACK :away-notify");
client.ReadUntil("CAP nick NEW :away-notify");
ircd.Write("CAP nick DEL :away-notify");
client.ReadUntil("CAP nick DEL :away-notify");
}
TEST_F(ZNCTest, JoinKey) {
QFile conf(m_dir.path() + "/configs/znc.conf");
ASSERT_TRUE(conf.open(QIODevice::Append | QIODevice::Text));
@@ -296,15 +349,15 @@ TEST_F(ZNCTest, StatusEchoMessage) {
client.Write("CAP REQ :echo-message");
client.Write("PRIVMSG *status :blah");
client.ReadUntil(":nick!user@irc.znc.in PRIVMSG *status :blah");
client.ReadUntil(":*status!znc@znc.in PRIVMSG nick :Unknown command");
client.ReadUntil(":*status!status@znc.in PRIVMSG nick :Unknown command");
client.Write("znc delnetwork test");
client.ReadUntil("Network deleted");
auto client2 = LoginClient();
client2.Write("PRIVMSG *status :blah2");
client2.ReadUntil(":*status!znc@znc.in PRIVMSG nick :Unknown command");
client2.ReadUntil(":*status!status@znc.in PRIVMSG nick :Unknown command");
auto client3 = LoginClient();
client3.Write("PRIVMSG *status :blah3");
client3.ReadUntil(":*status!znc@znc.in PRIVMSG nick :Unknown command");
client3.ReadUntil(":*status!status@znc.in PRIVMSG nick :Unknown command");
}
TEST_F(ZNCTest, MoveChannels) {
@@ -430,5 +483,346 @@ TEST_F(ZNCTest, DenyOptions) {
client2.ReadUntil("Access denied!");
}
TEST_F(ZNCTest, CAP302MultiLS) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
InstallModule("testmod.cpp", R"(
#include <znc/Client.h>
#include <znc/Modules.h>
class TestModule : public CModule {
public:
MODCONSTRUCTOR(TestModule) {}
void OnClientCapLs(CClient* pClient, SCString& ssCaps) override {
for (int i = 0; i < 100; ++i) {
ssCaps.insert("testcap-" + CString(i));
}
}
};
GLOBALMODULEDEFS(TestModule, "Test")
)");
client.Write("znc loadmod testmod");
client.ReadUntil("Loaded module testmod");
auto client2 = ConnectClient();
client2.Write("CAP LS");
client2.ReadUntil("LS :");
auto rem = client2.ReadRemainder();
ASSERT_GT(rem.indexOf("testcap-10"), 10);
ASSERT_EQ(rem.indexOf("testcap-80"), -1);
ASSERT_EQ(rem.indexOf("LS"), -1);
client2 = ConnectClient();
client2.Write("CAP LS 302");
client2.ReadUntil("LS * :");
rem = client2.ReadRemainder();
int w = 0;
ASSERT_GT(w = rem.indexOf("testcap-10"), 1);
ASSERT_GT(w = rem.indexOf("testcap-22", w), 1);
ASSERT_GT(w = rem.indexOf("LS * :", w), 1);
ASSERT_GT(rem.indexOf("testcap-80", w), 1);
ASSERT_GT(rem.indexOf("LS :", w), 1);
}
TEST_F(ZNCTest, CAP302LSValue) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
InstallModule("testmod.cpp", R"(
#include <znc/Client.h>
#include <znc/Modules.h>
class TestModule : public CModule {
public:
MODCONSTRUCTOR(TestModule) {}
void OnClientCapLs(CClient* pClient, SCString& ssCaps) override {
if (pClient->HasCap302()) {
ssCaps.insert("testcap=blah");
} else {
ssCaps.insert("testcap");
}
}
};
GLOBALMODULEDEFS(TestModule, "Test")
)");
client.Write("znc loadmod testmod");
client.ReadUntil("Loaded module testmod");
auto client2 = ConnectClient();
client2.Write("CAP LS");
client2.ReadUntil("testcap ");
client2 = ConnectClient();
client2.Write("CAP LS 302");
client2.ReadUntil("testcap=");
}
class AllLanguages : public ZNCTest, public testing::WithParamInterface<int> {};
INSTANTIATE_TEST_CASE_P(LanguagesTests, AllLanguages, testing::Values(1, 2, 3));
TEST_P(AllLanguages, ServerDependentCapInModule) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
switch (GetParam()) {
case 1:
InstallModule("testmod.cpp", R"(
#include <znc/Modules.h>
class TestModule : public CModule {
class TestCap : public CCapability {
void OnServerChangedSupport(CIRCNetwork* pNetwork, bool bState) override {
GetModule()->PutModule("Server changed support: " + CString(bState));
}
void OnClientChangedSupport(CClient* pClient, bool bState) override {
GetModule()->PutModule("Client changed support: " + CString(bState));
}
};
public:
MODCONSTRUCTOR(TestModule) {
AddServerDependentCapability("testcap", std::make_unique<TestCap>());
}
};
MODULEDEFS(TestModule, "Test")
)");
break;
case 2:
#ifndef WANT_PYTHON
GTEST_SKIP() << "Modpython is disabled";
#endif
znc->CanLeak();
InstallModule("testmod.py", R"(
import znc
class testmod(znc.Module):
def OnLoad(self, args, ret):
def server_change(net, state):
self.PutModule('Server changed support: ' + ('true' if state else 'false'))
def client_change(client, state):
self.PutModule('Client changed support: ' + ('true' if state else 'false'))
self.AddServerDependentCapability('testcap', server_change, client_change)
return True
)");
client.Write("znc loadmod modpython");
break;
case 3:
#ifndef WANT_PERL
GTEST_SKIP() << "Modperl is disabled";
#endif
znc->CanLeak();
InstallModule("testmod.pm", R"(
package testmod;
use base 'ZNC::Module';
sub OnLoad {
my $self = shift;
$self->AddServerDependentCapability('testcap', sub {
my ($net, $state) = @_;
$self->PutModule('Server changed support: ' . ($state ? 'true' : 'false'));
}, sub {
my ($client, $state) = @_;
$self->PutModule('Client changed support: ' . ($state ? 'true' : 'false'));
});
return 1;
}
1;
)");
client.Write("znc loadmod modperl");
break;
}
client.Write("znc loadmod testmod");
client.ReadUntil("Loaded module testmod");
client.Write("znc addnetwork net2");
client.Close();
client = ConnectClient();
client.Write("CAP LS 302");
client.Write("PASS :hunter2");
client.Write("NICK nick");
client.Write("USER user/test x x :x");
client.Write("CAP END");
client.ReadUntil("Welcome");
ircd.Write("001 nick Welcome");
ircd.Write("CAP nick NEW testcap=value");
ircd.ReadUntil("CAP REQ :testcap");
ircd.Write("CAP nick ACK :testcap");
client.ReadUntil(":Server changed support: true");
client.ReadUntil("CAP nick NEW :testcap=value");
client.Write("CAP REQ testcap");
client.ReadUntil(":Client changed support: true");
client.ReadUntil("CAP nick ACK :testcap");
client.Write("CAP LS");
client.ReadUntil(" testcap=value ");
ircd.Write("CAP nick DEL testcap");
client.ReadUntil(":Server changed support: false");
client.ReadUntil("CAP nick DEL :testcap");
client.ReadUntil(":Client changed support: false");
ircd.Close();
// TODO combine multiple DELs to single line
client.ReadUntil("CAP nick DEL :testcap");
client.ReadUntil(":Client changed support: false");
ircd = ConnectIRCd();
ircd.ReadUntil("CAP LS 302");
ircd.Write("CAP nick LS :testcap=new");
ircd.ReadUntil("CAP REQ :testcap");
ircd.Write("CAP nick ACK :testcap");
client.ReadUntil(":Server changed support: true");
ircd.ReadUntil("CAP END");
// NEW waits until 001
ASSERT_THAT(ircd.ReadRemainder().toStdString(), Not(HasSubstr("testcap")));
ircd.Write("001 nick Welcome");
// TODO combine multiple NEWs to single line
client.ReadUntil("CAP nick NEW :testcap=new");
client.ReadUntil("Welcome");
// NEW with new value without DEL
ircd.Write("CAP nick NEW testcap=another");
client.ReadUntil("CAP nick NEW :testcap=another");
client.Write("znc jumpnetwork net2");
client.ReadUntil("CAP nick DEL :testcap");
client.ReadUntil(":Client changed support: false");
client.Write("znc jumpnetwork test");
client.ReadUntil("CAP nick NEW :testcap=another");
}
TEST_F(ZNCTest, HashUpgrade) {
QFile conf(m_dir.path() + "/configs/znc.conf");
ASSERT_TRUE(conf.open(QIODevice::Append | QIODevice::Text));
QTextStream out(&conf);
out << R"(
<User foo>
<Pass pass>
Method = MD5
Salt = abc
Hash = defdf93cef7fa7a8ee88e65d0e277b99
</Pass>
</User>
)";
out.flush();
conf.close();
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = ConnectClient();
client.Write("PASS :hunter2");
client.Write("NICK nick");
client.Write("USER foo x x :x");
client.ReadUntil("Welcome");
client.Close();
client = LoginClient();
client.Write("znc saveconfig");
client.ReadUntil("Wrote config");
ASSERT_TRUE(conf.open(QIODevice::ReadOnly | QIODevice::Text));
QTextStream in(&conf);
QString config = in.readAll();
// It was upgraded to either Argon2 or SHA256
EXPECT_THAT(config.toStdString(), Not(ContainsRegex("Method.*MD5")));
// Check that still can login after the upgrade
client = ConnectClient();
client.Write("PASS :hunter2");
client.Write("NICK nick");
client.Write("USER foo x x :x");
client.ReadUntil("Welcome");
client.Close();
}
TEST_F(ZNCTest, CapReqWithoutLs) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = ConnectClient();
client.Write("CAP REQ nonono");
client.Write("PASS :hunter2");
client.Write("NICK nick");
client.Write("USER foo x x :x");
ASSERT_THAT(client.ReadRemainder().toStdString(), Not(HasSubstr("Welcome")));
}
TEST_F(ZNCTest, ChgHostEmulation) {
auto znc = Run();
auto ircd = ConnectIRCd();
ircd.Write("CAP user LS :chghost");
ircd.ReadUntil("CAP REQ :chghost");
ircd.Write("CAP user ACK :chghost");
auto client1 = LoginClient();
auto client2 = LoginClient();
client2.Write("CAP REQ :chghost");
client2.ReadUntil("ACK");
ircd.Write(":user!oldident@oldhost JOIN #chan");
ircd.Write(":user!oldident@oldhost CHGHOST newident newhost");
client1.ReadUntil(":user!oldident@oldhost QUIT :Changing hostname");
client1.ReadUntil(":user!newident@newhost JOIN #chan");
ASSERT_THAT(client1.ReadRemainder().toStdString(), Not(HasSubstr("MODE")));
client2.ReadUntil(":user!oldident@oldhost CHGHOST newident newhost");
client2.Close();
ircd.Write(":server MODE #chan +v user");
client1.ReadUntil("MODE");
ircd.Write(":user!newident@newhost CHGHOST ident-2 host-2");
client1.ReadUntil(":irc.znc.in MODE #chan +v user");
ircd.Write(":server MODE #chan +o user");
client1.ReadUntil("MODE");
ircd.Write(":user!ident-2@host-2 CHGHOST ident-3 host-3");
client1.ReadUntil(":irc.znc.in MODE #chan +ov user user");
// Only attached channel should receive emulation
ircd.Write(":user!ident-3@host-3 JOIN #chan2");
client1.ReadUntil("JOIN #chan2");
client1.Write("DETACH #chan2");
client1.ReadUntil("Detached 1 channel");
ircd.Write(":user!ident-3@host-3 CHGHOST ident host");
ASSERT_THAT(client1.ReadRemainder().toStdString(),
Not(HasSubstr("#chan2")));
}
TEST_F(ZNCTest, ChgHostOnce) {
auto znc = Run();
auto ircd = ConnectIRCd();
ircd.Write("CAP user LS :chghost");
ircd.ReadUntil("CAP REQ :chghost");
ircd.Write("CAP user ACK :chghost");
auto client = LoginClient();
client.Write("CAP REQ :chghost");
client.ReadUntil("ACK");
ircd.Write(":user!oldident@oldhost JOIN #chan");
ircd.Write(":user!oldident@oldhost JOIN #chan2");
ircd.Write(":user!oldident@oldhost CHGHOST newident newhost");
client.ReadUntil("CHGHOST");
ASSERT_THAT(client.ReadRemainder().toStdString(),
Not(HasSubstr("CHGHOST")));
}
TEST_F(ZNCTest, ChgHostOnlyNicksAlreadyOnChannels) {
auto znc = Run();
auto ircd = ConnectIRCd();
ircd.Write("CAP user LS :chghost");
ircd.ReadUntil("CAP REQ :chghost");
ircd.Write("CAP user ACK :chghost");
auto client = LoginClient();
ircd.Write(":user!ident@host JOIN #chan1");
ircd.Write(":user!ident@host JOIN #chan2");
ircd.Write(":another!ident@host JOIN #chan1");
client.ReadUntil("another");
ircd.Write(":another!ident@host CHGHOST i2 h2");
ASSERT_THAT(client.ReadRemainder().toStdString(),
AllOf(HasSubstr("JOIN #chan1"),
Not(HasSubstr("#chan2"))));
}
} // namespace
} // namespace znc_inttest
+18 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -234,7 +234,7 @@ TEST_F(ZNCTest, KeepNickModule) {
ircd.ReadUntil("NICK user");
ircd.Write(":server 435 user_ user #error :Nope :-P");
client.ReadUntil(
":*keepnick!znc@znc.in PRIVMSG user_ "
":*keepnick!keepnick@znc.in PRIVMSG user_ "
":Unable to obtain nick user: Nope :-P, #error");
}
@@ -350,5 +350,21 @@ TEST_F(ZNCTest, SaslPlainModule) {
client2.ReadUntil(":irc.znc.in 903 foo :SASL authentication successful");
}
TEST_F(ZNCTest, SaslRequire) {
auto znc = Run();
auto ircd = ConnectIRCd();
auto client = LoginClient();
client.Write("znc loadmod sasl");
client.Write("PRIVMSG *sasl :set * *");
client.Write("PRIVMSG *sasl :requireauth yes");
client.ReadUntil("Password has been set");
client.Write("znc jump");
ircd = ConnectIRCd();
ircd.ReadUntil("CAP LS");
ircd.Write(":server 001 nick :Hello");
ircd.ReadUntil("QUIT :SASL not available");
auto ircd2 = ConnectIRCd();
}
} // namespace
} // namespace znc_inttest
+46 -48
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2023 ZNC, see the NOTICE file for details.
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,15 @@
*/
#include "znctest.h"
#include "znctestconfig.h"
namespace znc_inttest {
namespace {
TEST_F(ZNCTest, Modperl) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PERL
GTEST_SKIP() << "Modperl is disabled";
#endif
auto znc = Run();
znc->CanLeak();
auto ircd = ConnectIRCd();
@@ -31,16 +31,15 @@ TEST_F(ZNCTest, Modperl) {
client.Write("znc loadmod modperl");
client.Write("znc loadmod perleval");
client.Write("PRIVMSG *perleval :2+2");
client.ReadUntil(":*perleval!znc@znc.in PRIVMSG nick :Result: 4");
client.ReadUntil(":*perleval!perleval@znc.in PRIVMSG nick :Result: 4");
client.Write("PRIVMSG *perleval :$self->GetUser->GetUsername");
client.ReadUntil("Result: user");
}
TEST_F(ZNCTest, Modpython) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PYTHON
GTEST_SKIP() << "Modpython is disabled";
#endif
auto znc = Run();
znc->CanLeak();
auto ircd = ConnectIRCd();
@@ -48,7 +47,7 @@ TEST_F(ZNCTest, Modpython) {
client.Write("znc loadmod modpython");
client.Write("znc loadmod pyeval");
client.Write("PRIVMSG *pyeval :2+2");
client.ReadUntil(":*pyeval!znc@znc.in PRIVMSG nick :4");
client.ReadUntil(":*pyeval!pyeval@znc.in PRIVMSG nick :4");
client.Write("PRIVMSG *pyeval :module.GetUser().GetUsername()");
client.ReadUntil("nick :'user'");
ircd.Write(":server 001 nick :Hello");
@@ -60,15 +59,14 @@ TEST_F(ZNCTest, Modpython) {
client.Write("PRIVMSG *controlpanel :Set ClientEncoding $me Western");
client.Write("JOIN #a\342");
client.ReadUntil(
":*controlpanel!znc@znc.in PRIVMSG nick :ClientEncoding = UTF-8");
":*controlpanel!controlpanel@znc.in PRIVMSG nick :ClientEncoding = UTF-8");
ircd.ReadUntil("JOIN #a\xEF\xBF\xBD");
}
TEST_F(ZNCTest, ModpythonSocket) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PYTHON
GTEST_SKIP() << "Modpython is disabled";
#endif
auto znc = Run();
znc->CanLeak();
@@ -107,10 +105,9 @@ TEST_F(ZNCTest, ModpythonSocket) {
}
TEST_F(ZNCTest, ModperlSocket) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PERL
GTEST_SKIP() << "Modperl is disabled";
#endif
auto znc = Run();
znc->CanLeak();
@@ -160,10 +157,9 @@ TEST_F(ZNCTest, ModperlSocket) {
}
TEST_F(ZNCTest, ModpythonVCString) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PYTHON
GTEST_SKIP() << "Modpython is disabled";
#endif
auto znc = Run();
znc->CanLeak();
@@ -185,10 +181,9 @@ TEST_F(ZNCTest, ModpythonVCString) {
}
TEST_F(ZNCTest, ModperlVCString) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PERL
GTEST_SKIP() << "Modperl is disabled";
#endif
auto znc = Run();
znc->CanLeak();
@@ -214,10 +209,9 @@ TEST_F(ZNCTest, ModperlVCString) {
}
TEST_F(ZNCTest, ModperlNV) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PERL
GTEST_SKIP() << "Modperl is disabled";
#endif
auto znc = Run();
znc->CanLeak();
@@ -244,10 +238,9 @@ TEST_F(ZNCTest, ModperlNV) {
}
TEST_F(ZNCTest, ModpythonPackage) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PYTHON
GTEST_SKIP() << "Modpython is disabled";
#endif
auto znc = Run();
znc->CanLeak();
@@ -277,13 +270,20 @@ TEST_F(ZNCTest, ModpythonPackage) {
client.Write("znc updatemod packagetest");
client.Write("PRIVMSG *packagetest :foo");
client.ReadUntil("value = b");
// Test if python modules are viewable via *status.
// https://github.com/znc/znc/issues/1884
client.Write("znc listavailmods");
client.ReadUntil(":*status!status@znc.in PRIVMSG nick :\x02 packagetest");
client.ReadUntil(":*status!status@znc.in PRIVMSG nick :\x02 pyeval\x0F: Evaluates python code");
}
TEST_F(ZNCTest, ModpythonModperl) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PYTHON
GTEST_SKIP() << "Modpython is disabled";
#endif
#ifndef WANT_PERL
GTEST_SKIP() << "Modperl is disabled";
#endif
auto znc = Run();
znc->CanLeak();
@@ -297,11 +297,9 @@ TEST_F(ZNCTest, ModpythonModperl) {
}
TEST_F(ZNCTest, ModpythonCommand) {
if (QProcessEnvironment::systemEnvironment().value(
"DISABLED_ZNC_PERL_PYTHON_TEST") == "1") {
return;
}
#ifndef WANT_PYTHON
GTEST_SKIP() << "Modpython is disabled";
#endif
auto znc = Run();
znc->CanLeak();
@@ -328,7 +326,7 @@ TEST_F(ZNCTest, ModpythonCommand) {
client.Write("znc loadmod modpython");
client.Write("znc loadmod cmdtest");
client.Write("PRIVMSG *cmdtest :ping or");
client.ReadUntil(":*cmdtest!znc@znc.in PRIVMSG nick :ping or pong");
client.ReadUntil(":*cmdtest!cmdtest@znc.in PRIVMSG nick :ping or pong");
InstallTranslation("cmdtest", "ru_RU", R"(
msgid ""
@@ -352,9 +350,9 @@ TEST_F(ZNCTest, ModpythonCommand) {
client.Write("PRIVMSG *controlpanel :set language $me ru-RU");
client.Write("PRIVMSG *cmdtest :help");
client.ReadUntil(":*cmdtest!znc@znc.in PRIVMSG nick :\x02ping аргумент\x0F: бла");
client.ReadUntil(":*cmdtest!cmdtest@znc.in PRIVMSG nick :\x02ping аргумент\x0F: бла");
client.Write("PRIVMSG *cmdtest :ping");
client.ReadUntil(":*cmdtest!znc@znc.in PRIVMSG nick :ping понг");
client.ReadUntil(":*cmdtest!cmdtest@znc.in PRIVMSG nick :ping понг");
}
} // namespace
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2004-2025 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ZNCTESTCONFIG_H
#define ZNCTESTCONFIG_H
#cmakedefine WANT_PYTHON 1
#cmakedefine WANT_PERL 1
#endif /* ZNCTESTCONFIG_H */