Fix memory leaks & data races in tests (#4772)

* Add a few pre-made sanitizer suppressions

* Test Sanitization: Fix threading issues

* Test Sanitization: Allow deletion of PubSub

We still don't delete it in main code, but this allows us to try
deleting it in tests.

* Test Sanitization: Fix some memory leaks

* fix gtest clang-tidy warning

* const emojis test :-)
This commit is contained in:
pajlada 2023-08-27 14:07:46 +02:00 committed by GitHub
parent ac6708b3a2
commit 3f7671000a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 360 additions and 296 deletions

View file

@ -36,8 +36,12 @@ CheckOptions:
value: CamelCase value: CamelCase
- key: readability-identifier-naming.EnumCase - key: readability-identifier-naming.EnumCase
value: CamelCase value: CamelCase
- key: readability-identifier-naming.FunctionCase - key: readability-identifier-naming.FunctionCase
value: camelBack value: camelBack
- key: readability-identifier-naming.FunctionIgnoredRegexp
value: ^TEST$
- key: readability-identifier-naming.MemberCase - key: readability-identifier-naming.MemberCase
value: camelBack value: camelBack
- key: readability-identifier-naming.PrivateMemberIgnoredRegexp - key: readability-identifier-naming.PrivateMemberIgnoredRegexp

View file

@ -0,0 +1,2 @@
# Ignore openssl issues
interceptor_via_lib:libcrypto.so.3

View file

@ -0,0 +1,3 @@
# Ignore openssl issues
leak:libcrypto.so.3
leak:CRYPTO_zalloc

View file

@ -0,0 +1,17 @@
race:libdbus-1.so.3
deadlock:libdbus-1.so.3
race:libglib-2.0.so.0
race:libgio-2.0.so.0
# Not sure about these suppression
# race:qscopedpointer.h
# race:qarraydata.cpp
# race:qarraydata.h
# race:qarraydataops.h
# race:libQt6Core.so.6
# race:libQt6Gui.so.6
# race:libQt6XcbQpa.so.6
# race:libQt6Network.so.6
# very not sure about this one
# race:qstring.h

View file

@ -0,0 +1,2 @@
enum:NetworkResult.hpp
enum:gtest.h

View file

@ -7,6 +7,8 @@ namespace chatterino::mock {
class EmptyApplication : public IApplication class EmptyApplication : public IApplication
{ {
public: public:
virtual ~EmptyApplication() = default;
Theme *getThemes() override Theme *getThemes() override
{ {
return nullptr; return nullptr;

View file

@ -33,6 +33,7 @@ inline QDebug operator<<(QDebug dbg, const ActionUser &user)
} }
struct PubSubAction { struct PubSubAction {
PubSubAction() = default;
PubSubAction(const QJsonObject &data, const QString &_roomID); PubSubAction(const QJsonObject &data, const QString &_roomID);
ActionUser source; ActionUser source;

View file

@ -77,8 +77,6 @@ public:
void setAccountData(QString token, QString userID); void setAccountData(QString token, QString userID);
~PubSub() = delete;
enum class State { enum class State {
Connected, Connected,
Disconnected, Disconnected,

View file

@ -31,7 +31,8 @@ struct PubSubAutoModQueueMessage {
QString senderUserDisplayName; QString senderUserDisplayName;
QColor senderUserChatColor; QColor senderUserChatColor;
PubSubAutoModQueueMessage(const QJsonObject &root); PubSubAutoModQueueMessage() = default;
explicit PubSubAutoModQueueMessage(const QJsonObject &root);
}; };
} // namespace chatterino } // namespace chatterino

View file

@ -28,7 +28,8 @@ struct PubSubWhisperMessage {
QString fromUserDisplayName; QString fromUserDisplayName;
QColor fromUserColor; QColor fromUserColor;
PubSubWhisperMessage(const QJsonObject &root); PubSubWhisperMessage() = default;
explicit PubSubWhisperMessage(const QJsonObject &root);
}; };
} // namespace chatterino } // namespace chatterino

View file

@ -5,6 +5,7 @@ option(CHATTERINO_TEST_USE_PUBLIC_HTTPBIN "Use public httpbin for testing networ
set(test_SOURCES set(test_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/main.cpp ${CMAKE_CURRENT_LIST_DIR}/src/main.cpp
${CMAKE_CURRENT_LIST_DIR}/resources/test-resources.qrc ${CMAKE_CURRENT_LIST_DIR}/resources/test-resources.qrc
${CMAKE_CURRENT_LIST_DIR}/src/TestHelpers.hpp
${CMAKE_CURRENT_LIST_DIR}/src/ChannelChatters.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ChannelChatters.cpp
${CMAKE_CURRENT_LIST_DIR}/src/AccessGuard.cpp ${CMAKE_CURRENT_LIST_DIR}/src/AccessGuard.cpp
${CMAKE_CURRENT_LIST_DIR}/src/NetworkCommon.cpp ${CMAKE_CURRENT_LIST_DIR}/src/NetworkCommon.cpp

View file

@ -116,33 +116,33 @@ private:
TEST(BasicPubSub, SubscriptionCycle) TEST(BasicPubSub, SubscriptionCycle)
{ {
const QString host("wss://127.0.0.1:9050/liveupdates/sub-unsub"); const QString host("wss://127.0.0.1:9050/liveupdates/sub-unsub");
auto *manager = new MyManager(host); MyManager manager(host);
manager->start(); manager.start();
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
manager->sub({1, "foo"}); manager.sub({1, "foo"});
std::this_thread::sleep_for(500ms); std::this_thread::sleep_for(500ms);
ASSERT_EQ(manager->diag.connectionsOpened, 1); ASSERT_EQ(manager.diag.connectionsOpened, 1);
ASSERT_EQ(manager->diag.connectionsClosed, 0); ASSERT_EQ(manager.diag.connectionsClosed, 0);
ASSERT_EQ(manager->diag.connectionsFailed, 0); ASSERT_EQ(manager.diag.connectionsFailed, 0);
ASSERT_EQ(manager->messagesReceived, 1); ASSERT_EQ(manager.messagesReceived, 1);
ASSERT_EQ(manager->popMessage(), QString("ack-sub-1-foo")); ASSERT_EQ(manager.popMessage(), QString("ack-sub-1-foo"));
manager->unsub({1, "foo"}); manager.unsub({1, "foo"});
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(manager->diag.connectionsOpened, 1); ASSERT_EQ(manager.diag.connectionsOpened, 1);
ASSERT_EQ(manager->diag.connectionsClosed, 0); ASSERT_EQ(manager.diag.connectionsClosed, 0);
ASSERT_EQ(manager->diag.connectionsFailed, 0); ASSERT_EQ(manager.diag.connectionsFailed, 0);
ASSERT_EQ(manager->messagesReceived, 2); ASSERT_EQ(manager.messagesReceived, 2);
ASSERT_EQ(manager->popMessage(), QString("ack-unsub-1-foo")); ASSERT_EQ(manager.popMessage(), QString("ack-unsub-1-foo"));
manager->stop(); manager.stop();
ASSERT_EQ(manager->diag.connectionsOpened, 1); ASSERT_EQ(manager.diag.connectionsOpened, 1);
ASSERT_EQ(manager->diag.connectionsClosed, 1); ASSERT_EQ(manager.diag.connectionsClosed, 1);
ASSERT_EQ(manager->diag.connectionsFailed, 0); ASSERT_EQ(manager.diag.connectionsFailed, 0);
ASSERT_EQ(manager->messagesReceived, 2); ASSERT_EQ(manager.messagesReceived, 2);
} }

View file

@ -4,6 +4,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <QString> #include <QString>
#include <tuple>
using namespace chatterino; using namespace chatterino;
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -13,30 +15,30 @@ const QString TARGET_USER_NAME = "Alien";
TEST(BttvLiveUpdates, AllEvents) TEST(BttvLiveUpdates, AllEvents)
{ {
const QString host("wss://127.0.0.1:9050/liveupdates/bttv/all-events"); const QString host("wss://127.0.0.1:9050/liveupdates/bttv/all-events");
auto *liveUpdates = new BttvLiveUpdates(host); chatterino::BttvLiveUpdates liveUpdates(host);
liveUpdates->start(); liveUpdates.start();
boost::optional<BttvLiveUpdateEmoteUpdateAddMessage> addMessage; boost::optional<BttvLiveUpdateEmoteUpdateAddMessage> addMessage;
boost::optional<BttvLiveUpdateEmoteUpdateAddMessage> updateMessage; boost::optional<BttvLiveUpdateEmoteUpdateAddMessage> updateMessage;
boost::optional<BttvLiveUpdateEmoteRemoveMessage> removeMessage; boost::optional<BttvLiveUpdateEmoteRemoveMessage> removeMessage;
liveUpdates->signals_.emoteAdded.connect([&](const auto &m) { std::ignore = liveUpdates.signals_.emoteAdded.connect([&](const auto &m) {
addMessage = m; addMessage = m;
}); });
liveUpdates->signals_.emoteUpdated.connect([&](const auto &m) { std::ignore = liveUpdates.signals_.emoteUpdated.connect([&](const auto &m) {
updateMessage = m; updateMessage = m;
}); });
liveUpdates->signals_.emoteRemoved.connect([&](const auto &m) { std::ignore = liveUpdates.signals_.emoteRemoved.connect([&](const auto &m) {
removeMessage = m; removeMessage = m;
}); });
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
liveUpdates->joinChannel(TARGET_USER_ID, TARGET_USER_NAME); liveUpdates.joinChannel(TARGET_USER_ID, TARGET_USER_NAME);
std::this_thread::sleep_for(500ms); std::this_thread::sleep_for(500ms);
ASSERT_EQ(liveUpdates->diag.connectionsOpened, 1); ASSERT_EQ(liveUpdates.diag.connectionsOpened, 1);
ASSERT_EQ(liveUpdates->diag.connectionsClosed, 0); ASSERT_EQ(liveUpdates.diag.connectionsClosed, 0);
ASSERT_EQ(liveUpdates->diag.connectionsFailed, 0); ASSERT_EQ(liveUpdates.diag.connectionsFailed, 0);
auto add = *addMessage; auto add = *addMessage;
ASSERT_EQ(add.channelID, TARGET_USER_ID); ASSERT_EQ(add.channelID, TARGET_USER_ID);
@ -52,8 +54,8 @@ TEST(BttvLiveUpdates, AllEvents)
ASSERT_EQ(rem.channelID, TARGET_USER_ID); ASSERT_EQ(rem.channelID, TARGET_USER_ID);
ASSERT_EQ(rem.emoteID, QString("55898e122612142e6aaa935b")); ASSERT_EQ(rem.emoteID, QString("55898e122612142e6aaa935b"));
liveUpdates->stop(); liveUpdates.stop();
ASSERT_EQ(liveUpdates->diag.connectionsOpened, 1); ASSERT_EQ(liveUpdates.diag.connectionsOpened, 1);
ASSERT_EQ(liveUpdates->diag.connectionsClosed, 1); ASSERT_EQ(liveUpdates.diag.connectionsClosed, 1);
ASSERT_EQ(liveUpdates->diag.connectionsFailed, 0); ASSERT_EQ(liveUpdates.diag.connectionsFailed, 0);
} }

View file

@ -17,7 +17,7 @@ TEST(Emojis, ShortcodeParsing)
QString expectedOutput; QString expectedOutput;
}; };
std::vector<TestCase> tests{ const std::vector<TestCase> tests{
{ {
// input // input
"foo :penguin: bar", "foo :penguin: bar",

View file

@ -19,34 +19,34 @@ const QString TARGET_USER_ID = "60b39e943e203cc169dfc106";
TEST(SeventvEventAPI, AllEvents) TEST(SeventvEventAPI, AllEvents)
{ {
const QString host("wss://127.0.0.1:9050/liveupdates/seventv/all-events"); const QString host("wss://127.0.0.1:9050/liveupdates/seventv/all-events");
auto *eventAPI = new SeventvEventAPI(host, std::chrono::milliseconds(1000)); SeventvEventAPI eventAPI(host, std::chrono::milliseconds(1000));
eventAPI->start(); eventAPI.start();
boost::optional<EmoteAddDispatch> addDispatch; boost::optional<EmoteAddDispatch> addDispatch;
boost::optional<EmoteUpdateDispatch> updateDispatch; boost::optional<EmoteUpdateDispatch> updateDispatch;
boost::optional<EmoteRemoveDispatch> removeDispatch; boost::optional<EmoteRemoveDispatch> removeDispatch;
boost::optional<UserConnectionUpdateDispatch> userDispatch; boost::optional<UserConnectionUpdateDispatch> userDispatch;
eventAPI->signals_.emoteAdded.connect([&](const auto &d) { eventAPI.signals_.emoteAdded.connect([&](const auto &d) {
addDispatch = d; addDispatch = d;
}); });
eventAPI->signals_.emoteUpdated.connect([&](const auto &d) { eventAPI.signals_.emoteUpdated.connect([&](const auto &d) {
updateDispatch = d; updateDispatch = d;
}); });
eventAPI->signals_.emoteRemoved.connect([&](const auto &d) { eventAPI.signals_.emoteRemoved.connect([&](const auto &d) {
removeDispatch = d; removeDispatch = d;
}); });
eventAPI->signals_.userUpdated.connect([&](const auto &d) { eventAPI.signals_.userUpdated.connect([&](const auto &d) {
userDispatch = d; userDispatch = d;
}); });
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
eventAPI->subscribeUser("", EMOTE_SET_A); eventAPI.subscribeUser("", EMOTE_SET_A);
std::this_thread::sleep_for(500ms); std::this_thread::sleep_for(500ms);
ASSERT_EQ(eventAPI->diag.connectionsOpened, 1); ASSERT_EQ(eventAPI.diag.connectionsOpened, 1);
ASSERT_EQ(eventAPI->diag.connectionsClosed, 0); ASSERT_EQ(eventAPI.diag.connectionsClosed, 0);
ASSERT_EQ(eventAPI->diag.connectionsFailed, 0); ASSERT_EQ(eventAPI.diag.connectionsFailed, 0);
auto add = *addDispatch; auto add = *addDispatch;
ASSERT_EQ(add.emoteSetID, EMOTE_SET_A); ASSERT_EQ(add.emoteSetID, EMOTE_SET_A);
@ -71,7 +71,7 @@ TEST(SeventvEventAPI, AllEvents)
updateDispatch = boost::none; updateDispatch = boost::none;
removeDispatch = boost::none; removeDispatch = boost::none;
eventAPI->subscribeUser(TARGET_USER_ID, ""); eventAPI.subscribeUser(TARGET_USER_ID, "");
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(addDispatch.has_value(), false); ASSERT_EQ(addDispatch.has_value(), false);
@ -85,24 +85,24 @@ TEST(SeventvEventAPI, AllEvents)
ASSERT_EQ(user.emoteSetID, EMOTE_SET_B); ASSERT_EQ(user.emoteSetID, EMOTE_SET_B);
ASSERT_EQ(user.connectionIndex, 0); ASSERT_EQ(user.connectionIndex, 0);
eventAPI->stop(); eventAPI.stop();
ASSERT_EQ(eventAPI->diag.connectionsOpened, 1); ASSERT_EQ(eventAPI.diag.connectionsOpened, 1);
ASSERT_EQ(eventAPI->diag.connectionsClosed, 1); ASSERT_EQ(eventAPI.diag.connectionsClosed, 1);
ASSERT_EQ(eventAPI->diag.connectionsFailed, 0); ASSERT_EQ(eventAPI.diag.connectionsFailed, 0);
} }
TEST(SeventvEventAPI, NoHeartbeat) TEST(SeventvEventAPI, NoHeartbeat)
{ {
const QString host("wss://127.0.0.1:9050/liveupdates/seventv/no-heartbeat"); const QString host("wss://127.0.0.1:9050/liveupdates/seventv/no-heartbeat");
auto *eventApi = new SeventvEventAPI(host, std::chrono::milliseconds(1000)); SeventvEventAPI eventApi(host, std::chrono::milliseconds(1000));
eventApi->start(); eventApi.start();
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
eventApi->subscribeUser("", EMOTE_SET_A); eventApi.subscribeUser("", EMOTE_SET_A);
std::this_thread::sleep_for(1250ms); std::this_thread::sleep_for(1250ms);
ASSERT_EQ(eventApi->diag.connectionsOpened, 2); ASSERT_EQ(eventApi.diag.connectionsOpened, 2);
ASSERT_EQ(eventApi->diag.connectionsClosed, 1); ASSERT_EQ(eventApi.diag.connectionsClosed, 1);
ASSERT_EQ(eventApi->diag.connectionsFailed, 0); ASSERT_EQ(eventApi.diag.connectionsFailed, 0);
eventApi->stop(); eventApi.stop();
} }

44
tests/src/TestHelpers.hpp Normal file
View file

@ -0,0 +1,44 @@
#pragma once
#include <mutex>
template <typename T>
class ReceivedMessage
{
mutable std::mutex mutex;
bool isSet{false};
T t;
public:
ReceivedMessage() = default;
explicit operator bool() const
{
std::unique_lock lock(this->mutex);
return this->isSet;
}
ReceivedMessage &operator=(const T &newT)
{
std::unique_lock lock(this->mutex);
this->isSet = true;
this->t = newT;
return *this;
}
bool operator==(const T &otherT) const
{
std::unique_lock lock(this->mutex);
return this->t == otherT;
}
const T *operator->() const
{
return &this->t;
}
};

View file

@ -154,7 +154,7 @@ TEST(TwitchMessageBuilder, BadgeInfoParsing)
for (const auto &test : testCases) for (const auto &test : testCases)
{ {
auto privmsg = auto *privmsg =
Communi::IrcPrivateMessage::fromData(test.input, nullptr); Communi::IrcPrivateMessage::fromData(test.input, nullptr);
auto outputBadgeInfo = auto outputBadgeInfo =
@ -166,6 +166,8 @@ TEST(TwitchMessageBuilder, BadgeInfoParsing)
SharedMessageBuilder::parseBadgeTag(privmsg->tags()); SharedMessageBuilder::parseBadgeTag(privmsg->tags());
EXPECT_EQ(outputBadges, test.expectedBadges) EXPECT_EQ(outputBadges, test.expectedBadges)
<< "Input for badges " << test.input.toStdString() << " failed"; << "Input for badges " << test.input.toStdString() << " failed";
delete privmsg;
} }
} }
@ -343,5 +345,7 @@ TEST_F(TestTwitchMessageBuilder, ParseTwitchEmotes)
EXPECT_EQ(actualTwitchEmotes, test.expectedTwitchEmotes) EXPECT_EQ(actualTwitchEmotes, test.expectedTwitchEmotes)
<< "Input for twitch emotes " << test.input.toStdString() << "Input for twitch emotes " << test.input.toStdString()
<< " failed"; << " failed";
delete privmsg;
} }
} }

View file

@ -3,11 +3,13 @@
#include "providers/twitch/PubSubManager.hpp" #include "providers/twitch/PubSubManager.hpp"
#include "providers/twitch/pubsubmessages/AutoMod.hpp" #include "providers/twitch/pubsubmessages/AutoMod.hpp"
#include "providers/twitch/pubsubmessages/Whisper.hpp" #include "providers/twitch/pubsubmessages/Whisper.hpp"
#include "TestHelpers.hpp"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <QString> #include <QString>
#include <chrono> #include <chrono>
#include <optional>
using namespace chatterino; using namespace chatterino;
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -30,415 +32,395 @@ using namespace std::chrono_literals;
#ifdef RUN_PUBSUB_TESTS #ifdef RUN_PUBSUB_TESTS
class FTest : public PubSub
{
public:
explicit FTest(const char *path, std::chrono::seconds pingInterval)
: PubSub(QString("wss://127.0.0.1:9050%1").arg(path), pingInterval)
{
}
};
TEST(TwitchPubSubClient, ServerRespondsToPings) TEST(TwitchPubSubClient, ServerRespondsToPings)
{ {
auto pingInterval = std::chrono::seconds(1); FTest pubSub("", 1s);
const QString host("wss://127.0.0.1:9050");
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("token", "123456");
pubSub->setAccountData("token", "123456"); pubSub.start();
pubSub->start();
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 0); ASSERT_EQ(pubSub.diag.connectionsOpened, 0);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 0); ASSERT_EQ(pubSub.diag.messagesReceived, 0);
pubSub->listenToTopic("test"); pubSub.listenToTopic("test");
std::this_thread::sleep_for(150ms); std::this_thread::sleep_for(150ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 2); ASSERT_EQ(pubSub.diag.messagesReceived, 2);
ASSERT_EQ(pubSub->diag.listenResponses, 1); ASSERT_EQ(pubSub.diag.listenResponses, 1);
std::this_thread::sleep_for(2s); std::this_thread::sleep_for(2s);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 4); ASSERT_EQ(pubSub.diag.messagesReceived, 4);
pubSub->stop(); pubSub.stop();
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 1); ASSERT_EQ(pubSub.diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 4); ASSERT_EQ(pubSub.diag.messagesReceived, 4);
ASSERT_EQ(pubSub->diag.listenResponses, 1); ASSERT_EQ(pubSub.diag.listenResponses, 1);
} }
TEST(TwitchPubSubClient, ServerDoesntRespondToPings) TEST(TwitchPubSubClient, ServerDoesntRespondToPings)
{ {
auto pingInterval = std::chrono::seconds(1); FTest pubSub("/dont-respond-to-ping", 1s);
const QString host("wss://127.0.0.1:9050/dont-respond-to-ping");
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("token", "123456");
pubSub->setAccountData("token", "123456"); pubSub.start();
pubSub->start(); pubSub.listenToTopic("test");
pubSub->listenToTopic("test");
std::this_thread::sleep_for(750ms); std::this_thread::sleep_for(750ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 1); ASSERT_EQ(pubSub.diag.messagesReceived, 1);
std::this_thread::sleep_for(500ms); std::this_thread::sleep_for(500ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 2); ASSERT_EQ(pubSub.diag.connectionsOpened, 2);
ASSERT_EQ(pubSub->diag.connectionsClosed, 1); ASSERT_EQ(pubSub.diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 2); ASSERT_EQ(pubSub.diag.messagesReceived, 2);
pubSub->stop(); pubSub.stop();
ASSERT_EQ(pubSub->diag.connectionsOpened, 2); ASSERT_EQ(pubSub.diag.connectionsOpened, 2);
ASSERT_EQ(pubSub->diag.connectionsClosed, 2); ASSERT_EQ(pubSub.diag.connectionsClosed, 2);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 2); ASSERT_EQ(pubSub.diag.messagesReceived, 2);
} }
TEST(TwitchPubSubClient, DisconnectedAfter1s) TEST(TwitchPubSubClient, DisconnectedAfter1s)
{ {
auto pingInterval = std::chrono::seconds(10); FTest pubSub("/disconnect-client-after-1s", 10s);
const QString host("wss://127.0.0.1:9050/disconnect-client-after-1s");
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("token", "123456");
pubSub->setAccountData("token", "123456"); pubSub.start();
pubSub->start();
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 0); ASSERT_EQ(pubSub.diag.connectionsOpened, 0);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 0); ASSERT_EQ(pubSub.diag.messagesReceived, 0);
ASSERT_EQ(pubSub->diag.listenResponses, 0); ASSERT_EQ(pubSub.diag.listenResponses, 0);
pubSub->listenToTopic("test"); pubSub.listenToTopic("test");
std::this_thread::sleep_for(500ms); std::this_thread::sleep_for(500ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 2); // Listen RESPONSE & Pong ASSERT_EQ(pubSub.diag.messagesReceived, 2); // Listen RESPONSE & Pong
ASSERT_EQ(pubSub->diag.listenResponses, 1); ASSERT_EQ(pubSub.diag.listenResponses, 1);
std::this_thread::sleep_for(350ms); std::this_thread::sleep_for(350ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 2); ASSERT_EQ(pubSub.diag.messagesReceived, 2);
std::this_thread::sleep_for(600ms); std::this_thread::sleep_for(600ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 2); ASSERT_EQ(pubSub.diag.connectionsOpened, 2);
ASSERT_EQ(pubSub->diag.connectionsClosed, 1); ASSERT_EQ(pubSub.diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.listenResponses, 2); ASSERT_EQ(pubSub.diag.listenResponses, 2);
ASSERT_EQ(pubSub->diag.messagesReceived, 4); // new listen & new pong ASSERT_EQ(pubSub.diag.messagesReceived, 4); // new listen & new pong
pubSub->stop(); pubSub.stop();
} }
TEST(TwitchPubSubClient, ExceedTopicLimit) TEST(TwitchPubSubClient, ExceedTopicLimit)
{ {
auto pingInterval = std::chrono::seconds(1); FTest pubSub("", 1s);
const QString host("wss://127.0.0.1:9050");
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("token", "123456");
pubSub->setAccountData("token", "123456"); pubSub.start();
pubSub->start();
ASSERT_EQ(pubSub->diag.connectionsOpened, 0); ASSERT_EQ(pubSub.diag.connectionsOpened, 0);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 0); ASSERT_EQ(pubSub.diag.messagesReceived, 0);
for (auto i = 0; i < PubSubClient::MAX_LISTENS; ++i) for (auto i = 0; i < PubSubClient::MAX_LISTENS; ++i)
{ {
pubSub->listenToTopic(QString("test-1.%1").arg(i)); pubSub.listenToTopic(QString("test-1.%1").arg(i));
} }
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
for (auto i = 0; i < PubSubClient::MAX_LISTENS; ++i) for (auto i = 0; i < PubSubClient::MAX_LISTENS; ++i)
{ {
pubSub->listenToTopic(QString("test-2.%1").arg(i)); pubSub.listenToTopic(QString("test-2.%1").arg(i));
} }
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 2); ASSERT_EQ(pubSub.diag.connectionsOpened, 2);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
pubSub->stop(); pubSub.stop();
ASSERT_EQ(pubSub->diag.connectionsOpened, 2); ASSERT_EQ(pubSub.diag.connectionsOpened, 2);
ASSERT_EQ(pubSub->diag.connectionsClosed, 2); ASSERT_EQ(pubSub.diag.connectionsClosed, 2);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
} }
TEST(TwitchPubSubClient, ExceedTopicLimitSingleStep) TEST(TwitchPubSubClient, ExceedTopicLimitSingleStep)
{ {
auto pingInterval = std::chrono::seconds(1); FTest pubSub("", 1s);
const QString host("wss://127.0.0.1:9050");
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("token", "123456");
pubSub->setAccountData("token", "123456"); pubSub.start();
pubSub->start();
ASSERT_EQ(pubSub->diag.connectionsOpened, 0); ASSERT_EQ(pubSub.diag.connectionsOpened, 0);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 0); ASSERT_EQ(pubSub.diag.messagesReceived, 0);
for (auto i = 0; i < PubSubClient::MAX_LISTENS * 2; ++i) for (auto i = 0; i < PubSubClient::MAX_LISTENS * 2; ++i)
{ {
pubSub->listenToTopic("test"); pubSub.listenToTopic("test");
} }
std::this_thread::sleep_for(150ms); std::this_thread::sleep_for(150ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 2); ASSERT_EQ(pubSub.diag.connectionsOpened, 2);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
pubSub->stop(); pubSub.stop();
ASSERT_EQ(pubSub->diag.connectionsOpened, 2); ASSERT_EQ(pubSub.diag.connectionsOpened, 2);
ASSERT_EQ(pubSub->diag.connectionsClosed, 2); ASSERT_EQ(pubSub.diag.connectionsClosed, 2);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
} }
TEST(TwitchPubSubClient, ReceivedWhisper) TEST(TwitchPubSubClient, ReceivedWhisper)
{ {
auto pingInterval = std::chrono::seconds(1); FTest pubSub("/receive-whisper", 1s);
const QString host("wss://127.0.0.1:9050/receive-whisper");
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("token", "123456");
pubSub->setAccountData("token", "123456"); pubSub.start();
pubSub->start();
boost::optional<PubSubWhisperMessage> oReceivedWhisper; ReceivedMessage<PubSubWhisperMessage> aReceivedWhisper;
pubSub->signals_.whisper.received.connect( pubSub.signals_.whisper.received.connect(
[&oReceivedWhisper](const auto &whisperMessage) { [&aReceivedWhisper](const auto &whisperMessage) {
oReceivedWhisper = whisperMessage; aReceivedWhisper = whisperMessage;
}); });
pubSub->listenToTopic("whispers.123456"); pubSub.listenToTopic("whispers.123456");
std::this_thread::sleep_for(150ms); std::this_thread::sleep_for(150ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 3); ASSERT_EQ(pubSub.diag.messagesReceived, 3);
ASSERT_EQ(pubSub->diag.listenResponses, 1); ASSERT_EQ(pubSub.diag.listenResponses, 1);
ASSERT_TRUE(oReceivedWhisper); ASSERT_TRUE(aReceivedWhisper);
auto receivedWhisper = *oReceivedWhisper; ASSERT_EQ(aReceivedWhisper->body, QString("me Kappa"));
ASSERT_EQ(aReceivedWhisper->fromUserLogin, QString("pajbot"));
ASSERT_EQ(aReceivedWhisper->fromUserID, QString("82008718"));
ASSERT_EQ(receivedWhisper.body, QString("me Kappa")); pubSub.stop();
ASSERT_EQ(receivedWhisper.fromUserLogin, QString("pajbot"));
ASSERT_EQ(receivedWhisper.fromUserID, QString("82008718"));
pubSub->stop(); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub.diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0);
} }
TEST(TwitchPubSubClient, ModeratorActionsUserBanned) TEST(TwitchPubSubClient, ModeratorActionsUserBanned)
{ {
auto pingInterval = std::chrono::seconds(1); FTest pubSub("/moderator-actions-user-banned", 1s);
const QString host("wss://127.0.0.1:9050/moderator-actions-user-banned");
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("token", "123456");
pubSub->setAccountData("token", "123456"); pubSub.start();
pubSub->start();
boost::optional<BanAction> oReceivedAction; ReceivedMessage<BanAction> received;
pubSub->signals_.moderation.userBanned.connect( pubSub.signals_.moderation.userBanned.connect(
[&oReceivedAction](const auto &action) { [&received](const auto &action) {
oReceivedAction = action; received = action;
}); });
ASSERT_EQ(pubSub->diag.listenResponses, 0); ASSERT_EQ(pubSub.diag.listenResponses, 0);
pubSub->listenToTopic("chat_moderator_actions.123456.123456"); pubSub.listenToTopic("chat_moderator_actions.123456.123456");
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 3); ASSERT_EQ(pubSub.diag.messagesReceived, 3);
ASSERT_EQ(pubSub->diag.listenResponses, 1); ASSERT_EQ(pubSub.diag.listenResponses, 1);
ASSERT_TRUE(oReceivedAction); ASSERT_TRUE(received);
auto receivedAction = *oReceivedAction;
ActionUser expectedTarget{"140114344", "1xelerate", "", QColor()}; ActionUser expectedTarget{"140114344", "1xelerate", "", QColor()};
ActionUser expectedSource{"117691339", "mm2pl", "", QColor()}; ActionUser expectedSource{"117691339", "mm2pl", "", QColor()};
ASSERT_EQ(receivedAction.reason, QString()); ASSERT_EQ(received->reason, QString());
ASSERT_EQ(receivedAction.duration, 0); ASSERT_EQ(received->duration, 0);
ASSERT_EQ(receivedAction.target, expectedTarget); ASSERT_EQ(received->target, expectedTarget);
ASSERT_EQ(receivedAction.source, expectedSource); ASSERT_EQ(received->source, expectedSource);
pubSub->stop(); pubSub.stop();
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 1); ASSERT_EQ(pubSub.diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
} }
TEST(TwitchPubSubClient, MissingToken) TEST(TwitchPubSubClient, MissingToken)
{ {
auto pingInterval = std::chrono::seconds(1);
// The token that's required is "xD" // The token that's required is "xD"
const QString host("wss://127.0.0.1:9050/authentication-required"); FTest pubSub("/authentication-required", 1s);
auto *pubSub = new PubSub(host, pingInterval); // pubSub.setAccountData("", "123456");
// pubSub->setAccountData("", "123456"); pubSub.start();
pubSub->start();
pubSub->listenToTopic("chat_moderator_actions.123456.123456"); pubSub.listenToTopic("chat_moderator_actions.123456.123456");
std::this_thread::sleep_for(150ms); std::this_thread::sleep_for(150ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 2); ASSERT_EQ(pubSub.diag.messagesReceived, 2);
ASSERT_EQ(pubSub->diag.listenResponses, 0); ASSERT_EQ(pubSub.diag.listenResponses, 0);
ASSERT_EQ(pubSub->diag.failedListenResponses, 1); ASSERT_EQ(pubSub.diag.failedListenResponses, 1);
pubSub->stop(); pubSub.stop();
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 1); ASSERT_EQ(pubSub.diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
} }
TEST(TwitchPubSubClient, WrongToken) TEST(TwitchPubSubClient, WrongToken)
{ {
auto pingInterval = std::chrono::seconds(1);
// The token that's required is "xD" // The token that's required is "xD"
const QString host("wss://127.0.0.1:9050/authentication-required"); FTest pubSub("/authentication-required", 1s);
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("wrongtoken", "123456");
pubSub->setAccountData("wrongtoken", "123456"); pubSub.start();
pubSub->start();
pubSub->listenToTopic("chat_moderator_actions.123456.123456"); pubSub.listenToTopic("chat_moderator_actions.123456.123456");
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 2); ASSERT_EQ(pubSub.diag.messagesReceived, 2);
ASSERT_EQ(pubSub->diag.listenResponses, 0); ASSERT_EQ(pubSub.diag.listenResponses, 0);
ASSERT_EQ(pubSub->diag.failedListenResponses, 1); ASSERT_EQ(pubSub.diag.failedListenResponses, 1);
pubSub->stop(); pubSub.stop();
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 1); ASSERT_EQ(pubSub.diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
} }
TEST(TwitchPubSubClient, CorrectToken) TEST(TwitchPubSubClient, CorrectToken)
{ {
auto pingInterval = std::chrono::seconds(1);
// The token that's required is "xD" // The token that's required is "xD"
const QString host("wss://127.0.0.1:9050/authentication-required"); FTest pubSub("/authentication-required", 1s);
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("xD", "123456");
pubSub->setAccountData("xD", "123456"); pubSub.start();
pubSub->start();
pubSub->listenToTopic("chat_moderator_actions.123456.123456"); pubSub.listenToTopic("chat_moderator_actions.123456.123456");
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 2); ASSERT_EQ(pubSub.diag.messagesReceived, 2);
ASSERT_EQ(pubSub->diag.listenResponses, 1); ASSERT_EQ(pubSub.diag.listenResponses, 1);
ASSERT_EQ(pubSub->diag.failedListenResponses, 0); ASSERT_EQ(pubSub.diag.failedListenResponses, 0);
pubSub->stop(); pubSub.stop();
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 1); ASSERT_EQ(pubSub.diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
} }
TEST(TwitchPubSubClient, AutoModMessageHeld) TEST(TwitchPubSubClient, AutoModMessageHeld)
{ {
auto pingInterval = std::chrono::seconds(1); FTest pubSub("/automod-held", 1s);
const QString host("wss://127.0.0.1:9050/automod-held");
auto *pubSub = new PubSub(host, pingInterval); pubSub.setAccountData("xD", "123456");
pubSub->setAccountData("xD", "123456"); pubSub.start();
pubSub->start();
boost::optional<PubSubAutoModQueueMessage> oReceived; ReceivedMessage<PubSubAutoModQueueMessage> received;
boost::optional<QString> oChannelID; ReceivedMessage<QString> channelID;
pubSub->signals_.moderation.autoModMessageCaught.connect( pubSub.signals_.moderation.autoModMessageCaught.connect(
[&](const auto &msg, const QString &channelID) { [&](const auto &msg, const QString &incomingChannelID) {
oReceived = msg; received = msg;
oChannelID = channelID; channelID = incomingChannelID;
}); });
pubSub->listenToTopic("automod-queue.117166826.117166826"); pubSub.listenToTopic("automod-queue.117166826.117166826");
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 0); ASSERT_EQ(pubSub.diag.connectionsClosed, 0);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
ASSERT_EQ(pubSub->diag.messagesReceived, 3); ASSERT_EQ(pubSub.diag.messagesReceived, 3);
ASSERT_EQ(pubSub->diag.listenResponses, 1); ASSERT_EQ(pubSub.diag.listenResponses, 1);
ASSERT_EQ(pubSub->diag.failedListenResponses, 0); ASSERT_EQ(pubSub.diag.failedListenResponses, 0);
ASSERT_TRUE(oReceived); ASSERT_TRUE(received);
ASSERT_TRUE(oChannelID); ASSERT_TRUE(channelID);
auto received = *oReceived;
auto channelID = *oChannelID;
ASSERT_EQ(channelID, "117166826"); ASSERT_EQ(channelID, "117166826");
ASSERT_EQ(received.messageText, "kurwa"); ASSERT_EQ(received->messageText, "kurwa");
pubSub->stop(); pubSub.stop();
ASSERT_EQ(pubSub->diag.connectionsOpened, 1); ASSERT_EQ(pubSub.diag.connectionsOpened, 1);
ASSERT_EQ(pubSub->diag.connectionsClosed, 1); ASSERT_EQ(pubSub.diag.connectionsClosed, 1);
ASSERT_EQ(pubSub->diag.connectionsFailed, 0); ASSERT_EQ(pubSub.diag.connectionsFailed, 0);
} }
#endif #endif