blob: 520fec295d019a4ef6162d2d6184239ca1224cc7 [file] [log] [blame] [edit]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* 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.
*/
#include "chre/util/system/message_router.h"
#include "chre/util/dynamic_vector.h"
#include "chre/util/system/callback_allocator.h"
#include "chre/util/system/message_common.h"
#include "chre/util/system/message_router_mocks.h"
#include "chre_api/chre.h"
#include "pw_allocator/libc_allocator.h"
#include "pw_allocator/unique_ptr.h"
#include "pw_intrusive_ptr/intrusive_ptr.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <cstddef>
#include <cstdint>
#include <optional>
#include <utility>
using ::testing::_;
namespace chre::message {
namespace {
constexpr size_t kMaxMessageHubs = 3;
constexpr size_t kMaxSessions = 10;
constexpr size_t kMaxFreeCallbackRecords = kMaxSessions * 2;
constexpr size_t kNumEndpoints = 3;
const EndpointInfo kEndpointInfos[kNumEndpoints] = {
EndpointInfo(/* id= */ 1, /* name= */ "endpoint1", /* version= */ 1,
EndpointType::NANOAPP, CHRE_MESSAGE_PERMISSION_NONE),
EndpointInfo(/* id= */ 2, /* name= */ "endpoint2", /* version= */ 10,
EndpointType::HOST_NATIVE, CHRE_MESSAGE_PERMISSION_BLE),
EndpointInfo(/* id= */ 3, /* name= */ "endpoint3", /* version= */ 100,
EndpointType::GENERIC, CHRE_MESSAGE_PERMISSION_AUDIO)};
const char kServiceDescriptorForEndpoint2[] = "TEST_SERVICE.TEST";
class MessageRouterTest : public ::testing::Test {};
//! Iterates over the endpoints
void forEachEndpoint(const pw::Function<bool(const EndpointInfo &)> &function) {
for (const EndpointInfo &endpointInfo : kEndpointInfos) {
if (function(endpointInfo)) {
return;
}
}
}
//! Base class for MessageHubCallbacks used in tests
class MessageHubCallbackBase : public MessageRouter::MessageHubCallback {
public:
void forEachEndpoint(
const pw::Function<bool(const EndpointInfo &)> &function) override {
::chre::message::forEachEndpoint(function);
}
std::optional<EndpointInfo> getEndpointInfo(EndpointId endpointId) override {
for (const EndpointInfo &endpointInfo : kEndpointInfos) {
if (endpointInfo.id == endpointId) {
return endpointInfo;
}
}
return std::nullopt;
}
void onSessionOpenRequest(const Session & /* session */) override {}
std::optional<EndpointId> getEndpointForService(
const char *serviceDescriptor) override {
if (serviceDescriptor != nullptr &&
std::strcmp(serviceDescriptor, kServiceDescriptorForEndpoint2) == 0) {
return kEndpointInfos[1].id;
}
return std::nullopt;
}
bool doesEndpointHaveService(EndpointId endpointId,
const char *serviceDescriptor) override {
return serviceDescriptor != nullptr && endpointId == kEndpointInfos[1].id &&
std::strcmp(serviceDescriptor, kServiceDescriptorForEndpoint2) == 0;
}
void forEachService(
const pw::Function<bool(const EndpointInfo &, const ServiceInfo &)>
&function) override {
function(kEndpointInfos[1],
ServiceInfo(kServiceDescriptorForEndpoint2, /* majorVersion= */ 1,
/* minorVersion= */ 0, RpcFormat::CUSTOM));
}
void onHubRegistered(const MessageHubInfo & /* info */) override {}
void onHubUnregistered(MessageHubId /* id */) override {}
void onEndpointRegistered(MessageHubId /* messageHubId */,
EndpointId /* endpointId */) override {}
void onEndpointUnregistered(MessageHubId /* messageHubId */,
EndpointId /* endpointId */) override {}
void pw_recycle() override {
delete this;
}
};
//! MessageHubCallback that stores the data passed to onMessageReceived and
//! onSessionClosed
class MessageHubCallbackStoreData : public MessageHubCallbackBase {
public:
MessageHubCallbackStoreData(Message *message, Session *session,
Reason *reason = nullptr,
Session *openedSession = nullptr)
: mMessage(message),
mSession(session),
mReason(reason),
mOpenedSession(openedSession) {}
bool onMessageReceived(pw::UniquePtr<std::byte[]> &&data,
uint32_t messageType, uint32_t messagePermissions,
const Session &session,
bool sentBySessionInitiator) override {
if (mMessage != nullptr) {
mMessage->sender = sentBySessionInitiator ? session.initiator
: session.peer;
mMessage->recipient =
sentBySessionInitiator ? session.peer : session.initiator;
mMessage->sessionId = session.sessionId;
mMessage->data = std::move(data);
mMessage->messageType = messageType;
mMessage->messagePermissions = messagePermissions;
}
return true;
}
void onSessionClosed(const Session &session, Reason reason) override {
if (mSession != nullptr) {
*mSession = session;
}
if (mReason != nullptr) {
*mReason = reason;
}
}
void onSessionOpened(const Session &session) override {
if (mOpenedSession != nullptr) {
*mOpenedSession = session;
}
}
void onEndpointRegistered(MessageHubId messageHubId,
EndpointId endpointId) override {
mRegisteredEndpoints.insert(std::make_pair(messageHubId, endpointId));
}
void onEndpointUnregistered(MessageHubId messageHubId,
EndpointId endpointId) override {
mRegisteredEndpoints.erase(std::make_pair(messageHubId, endpointId));
}
bool hasEndpointBeenRegistered(MessageHubId messageHubId,
EndpointId endpointId) {
return mRegisteredEndpoints.find(std::make_pair(
messageHubId, endpointId)) != mRegisteredEndpoints.end();
}
private:
Message *mMessage;
Session *mSession;
Reason *mReason;
Session *mOpenedSession;
std::set<std::pair<MessageHubId, EndpointId>> mRegisteredEndpoints;
};
//! MessageHubCallback that always fails to process messages
class MessageHubCallbackAlwaysFails : public MessageHubCallbackBase {
public:
MessageHubCallbackAlwaysFails(bool *wasMessageReceivedCalled,
bool *wasSessionClosedCalled)
: mWasMessageReceivedCalled(wasMessageReceivedCalled),
mWasSessionClosedCalled(wasSessionClosedCalled) {}
bool onMessageReceived(pw::UniquePtr<std::byte[]> && /* data */,
uint32_t /* messageType */,
uint32_t /* messagePermissions */,
const Session & /* session */,
bool /* sentBySessionInitiator */) override {
if (mWasMessageReceivedCalled != nullptr) {
*mWasMessageReceivedCalled = true;
}
return false;
}
void onSessionClosed(const Session & /* session */,
Reason /* reason */) override {
if (mWasSessionClosedCalled != nullptr) {
*mWasSessionClosedCalled = true;
}
}
void onSessionOpened(const Session & /* session */) override {}
private:
bool *mWasMessageReceivedCalled;
bool *mWasSessionClosedCalled;
};
//! MessageHubCallback that tracks open session requests calls
class MessageHubCallbackOpenSessionRequest : public MessageHubCallbackBase {
public:
MessageHubCallbackOpenSessionRequest(bool *wasSessionOpenRequestCalled)
: mWasSessionOpenRequestCalled(wasSessionOpenRequestCalled) {}
void onSessionOpenRequest(const Session & /* session */) override {
if (mWasSessionOpenRequestCalled != nullptr) {
*mWasSessionOpenRequestCalled = true;
}
}
bool onMessageReceived(pw::UniquePtr<std::byte[]> && /* data */,
uint32_t /* messageType */,
uint32_t /* messagePermissions */,
const Session & /* session */,
bool /* sentBySessionInitiator */) override {
return true;
}
void onSessionClosed(const Session & /* session */,
Reason /* reason */) override {}
void onSessionOpened(const Session & /* session */) override {}
private:
bool *mWasSessionOpenRequestCalled;
};
//! MessageHubCallback that calls MessageHub APIs during callbacks
class MessageHubCallbackCallsMessageHubApisDuringCallback
: public MessageHubCallbackBase {
public:
bool onMessageReceived(pw::UniquePtr<std::byte[]> && /* data */,
uint32_t /* messageType */,
uint32_t /* messagePermissions */,
const Session & /* session */,
bool /* sentBySessionInitiator */) override {
if (mMessageHub != nullptr) {
// Call a function that locks the MessageRouter mutex
mMessageHub->openSession(kEndpointInfos[0].id, mMessageHub->getId(),
kEndpointInfos[1].id);
}
return true;
}
void onSessionClosed(const Session & /* session */,
Reason /* reason */) override {
if (mMessageHub != nullptr) {
// Call a function that locks the MessageRouter mutex
mMessageHub->openSession(kEndpointInfos[0].id, mMessageHub->getId(),
kEndpointInfos[1].id);
}
}
void onSessionOpened(const Session & /* session */) override {
if (mMessageHub != nullptr) {
// Call a function that locks the MessageRouter mutex
mMessageHub->openSession(kEndpointInfos[0].id, mMessageHub->getId(),
kEndpointInfos[1].id);
}
}
void setMessageHub(MessageRouter::MessageHub *messageHub) {
mMessageHub = messageHub;
}
private:
MessageRouter::MessageHub *mMessageHub = nullptr;
};
TEST_F(MessageRouterTest, RegisterMessageHubNameIsUnique) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub1 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub1.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_FALSE(messageHub3.has_value());
}
TEST_F(MessageRouterTest, RegisterMessageHubIdIsUnique) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub1 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub1.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 1, callback);
EXPECT_FALSE(messageHub3.has_value());
}
TEST_F(MessageRouterTest, RegisterMessageHubGetListOfHubs) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub1 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub1.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback);
EXPECT_TRUE(messageHub3.has_value());
DynamicVector<MessageHubInfo> messageHubs;
router.forEachMessageHub(
[&messageHubs](const MessageHubInfo &messageHubInfo) {
messageHubs.push_back(messageHubInfo);
return false;
});
EXPECT_EQ(messageHubs.size(), 3);
EXPECT_EQ(messageHubs[0].name, "hub1");
EXPECT_EQ(messageHubs[1].name, "hub2");
EXPECT_EQ(messageHubs[2].name, "hub3");
EXPECT_EQ(messageHubs[0].id, 1);
EXPECT_EQ(messageHubs[1].id, 2);
EXPECT_EQ(messageHubs[2].id, 3);
EXPECT_EQ(messageHubs[0].id, messageHub1->getId());
EXPECT_EQ(messageHubs[1].id, messageHub2->getId());
EXPECT_EQ(messageHubs[2].id, messageHub3->getId());
}
TEST_F(MessageRouterTest, RegisterMessageHubGetListOfHubsWithUnregister) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub1 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub1.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback);
EXPECT_TRUE(messageHub3.has_value());
DynamicVector<MessageHubInfo> messageHubs;
router.forEachMessageHub(
[&messageHubs](const MessageHubInfo &messageHubInfo) {
messageHubs.push_back(messageHubInfo);
return false;
});
EXPECT_EQ(messageHubs.size(), 3);
EXPECT_EQ(messageHubs[0].name, "hub1");
EXPECT_EQ(messageHubs[1].name, "hub2");
EXPECT_EQ(messageHubs[2].name, "hub3");
EXPECT_EQ(messageHubs[0].id, 1);
EXPECT_EQ(messageHubs[1].id, 2);
EXPECT_EQ(messageHubs[2].id, 3);
EXPECT_EQ(messageHubs[0].id, messageHub1->getId());
EXPECT_EQ(messageHubs[1].id, messageHub2->getId());
EXPECT_EQ(messageHubs[2].id, messageHub3->getId());
// Clear messageHubs and reset messageHub2
messageHubs.clear();
messageHub2.reset();
router.forEachMessageHub(
[&messageHubs](const MessageHubInfo &messageHubInfo) {
messageHubs.push_back(messageHubInfo);
return false;
});
EXPECT_EQ(messageHubs.size(), 2);
EXPECT_EQ(messageHubs[0].name, "hub1");
EXPECT_EQ(messageHubs[1].name, "hub3");
EXPECT_EQ(messageHubs[0].id, 1);
EXPECT_EQ(messageHubs[1].id, 3);
EXPECT_EQ(messageHubs[0].id, messageHub1->getId());
EXPECT_EQ(messageHubs[1].id, messageHub3->getId());
}
TEST_F(MessageRouterTest, RegisterMessageHubTooManyFails) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
static_assert(kMaxMessageHubs == 3);
constexpr const char *kNames[3] = {"hub1", "hub2", "hub3"};
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
MessageRouter::MessageHub messageHubs[kMaxMessageHubs];
for (size_t i = 0; i < kMaxMessageHubs; ++i) {
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub(kNames[i], /* id= */ i, callback);
EXPECT_TRUE(messageHub.has_value());
messageHubs[i] = std::move(*messageHub);
}
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("shouldfail", /* id= */ kMaxMessageHubs * 2,
callback);
EXPECT_FALSE(messageHub.has_value());
}
TEST_F(MessageRouterTest, GetEndpointInfo) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub1 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub1.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback);
EXPECT_TRUE(messageHub3.has_value());
for (size_t i = 0; i < kNumEndpoints; ++i) {
EXPECT_EQ(
router.getEndpointInfo(messageHub1->getId(), kEndpointInfos[i].id),
kEndpointInfos[i]);
EXPECT_EQ(
router.getEndpointInfo(messageHub2->getId(), kEndpointInfos[i].id),
kEndpointInfos[i]);
EXPECT_EQ(
router.getEndpointInfo(messageHub3->getId(), kEndpointInfos[i].id),
kEndpointInfos[i]);
}
}
TEST_F(MessageRouterTest, GetEndpointForService) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub1 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub1.has_value());
std::optional<Endpoint> endpoint = router.getEndpointForService(
MESSAGE_HUB_ID_INVALID, kServiceDescriptorForEndpoint2);
EXPECT_TRUE(endpoint.has_value());
EXPECT_EQ(endpoint->messageHubId, messageHub1->getId());
EXPECT_EQ(endpoint->endpointId, kEndpointInfos[1].id);
}
TEST_F(MessageRouterTest, DoesEndpointHaveService) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub1 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub1.has_value());
EXPECT_TRUE(router.doesEndpointHaveService(messageHub1->getId(),
kEndpointInfos[1].id,
kServiceDescriptorForEndpoint2));
}
TEST_F(MessageRouterTest, ForEachService) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub1 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub1.has_value());
router.forEachService([](const MessageHubInfo &hub,
const EndpointInfo &endpoint,
const ServiceInfo &service) {
EXPECT_EQ(hub.id, 1);
EXPECT_EQ(endpoint.id, kEndpointInfos[1].id);
EXPECT_STREQ(service.serviceDescriptor, kServiceDescriptorForEndpoint2);
EXPECT_EQ(service.majorVersion, 1);
EXPECT_EQ(service.minorVersion, 0);
EXPECT_EQ(service.format, RpcFormat::CUSTOM);
return true;
});
}
TEST_F(MessageRouterTest, GetEndpointForServiceBadServiceDescriptor) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub1 =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub1.has_value());
std::optional<Endpoint> endpoint = router.getEndpointForService(
MESSAGE_HUB_ID_INVALID, "SERVICE_THAT_DOES_NOT_EXIST");
EXPECT_FALSE(endpoint.has_value());
std::optional<Endpoint> endpoint2 = router.getEndpointForService(
MESSAGE_HUB_ID_INVALID, /* serviceDescriptor= */ nullptr);
EXPECT_FALSE(endpoint2.has_value());
}
TEST_F(MessageRouterTest, RegisterSessionTwoDifferentMessageHubs) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionFromCallback1;
Session sessionFromCallback2;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
// Get session from messageHub and compare it with messageHub2
std::optional<Session> sessionAfterRegistering =
messageHub->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering.has_value());
EXPECT_EQ(sessionAfterRegistering->sessionId, sessionId);
EXPECT_EQ(sessionAfterRegistering->initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionAfterRegistering->initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionAfterRegistering->peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionAfterRegistering->peer.endpointId, kEndpointInfos[1].id);
std::optional<Session> sessionAfterRegistering2 =
messageHub2->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering2.has_value());
EXPECT_EQ(*sessionAfterRegistering, *sessionAfterRegistering2);
// Close the session and verify it is closed on both message hubs
EXPECT_NE(*sessionAfterRegistering, sessionFromCallback1);
EXPECT_NE(*sessionAfterRegistering, sessionFromCallback2);
EXPECT_TRUE(messageHub->closeSession(sessionId));
EXPECT_EQ(*sessionAfterRegistering, sessionFromCallback1);
EXPECT_EQ(*sessionAfterRegistering, sessionFromCallback2);
EXPECT_FALSE(messageHub->getSessionWithId(sessionId).has_value());
EXPECT_FALSE(messageHub2->getSessionWithId(sessionId).has_value());
}
TEST_F(MessageRouterTest, RegisterSessionVerifyAllCallbacksAreCalled) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionClosedFromCallback1;
Session sessionClosedFromCallback2;
Session sessionOpenedFromCallback1;
Session sessionOpenedFromCallback2;
Reason sessionCloseReason1;
Reason sessionCloseReason2;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(
/* message= */ nullptr, &sessionClosedFromCallback1,
&sessionCloseReason1, &sessionOpenedFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(
/* message= */ nullptr, &sessionClosedFromCallback2,
&sessionCloseReason2, &sessionOpenedFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
// Verify that onSessionOpened is called on both message hubs
EXPECT_EQ(sessionOpenedFromCallback1.sessionId, sessionId);
EXPECT_EQ(sessionOpenedFromCallback1.initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionOpenedFromCallback1.initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionOpenedFromCallback1.peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionOpenedFromCallback1.peer.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(sessionOpenedFromCallback2.sessionId, sessionId);
EXPECT_EQ(sessionOpenedFromCallback2.initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionOpenedFromCallback2.initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionOpenedFromCallback2.peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionOpenedFromCallback2.peer.endpointId, kEndpointInfos[1].id);
// Close the session with a reason
Reason reason = Reason::TIMEOUT;
EXPECT_TRUE(messageHub->closeSession(sessionId, reason));
// Verify that onSessionClosed is called on both message hubs
EXPECT_EQ(sessionClosedFromCallback1.sessionId, sessionId);
EXPECT_EQ(sessionClosedFromCallback1.initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionClosedFromCallback1.initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionClosedFromCallback1.peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionClosedFromCallback1.peer.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(sessionCloseReason1, reason);
EXPECT_EQ(sessionClosedFromCallback2.sessionId, sessionId);
EXPECT_EQ(sessionClosedFromCallback2.initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionClosedFromCallback2.initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionClosedFromCallback2.peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionClosedFromCallback2.peer.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(sessionCloseReason2, reason);
}
TEST_F(MessageRouterTest, RegisterSessionGetsRejectedAndClosed) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionFromCallback1;
Session sessionFromCallback2;
Reason sessionCloseReason;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(
/* message= */ nullptr, &sessionFromCallback1, &sessionCloseReason);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
Reason reason = Reason::OPEN_ENDPOINT_SESSION_REQUEST_REJECTED;
messageHub2->closeSession(sessionId, reason);
// Get session from messageHub and ensure it is deleted
std::optional<Session> sessionAfterRegistering =
messageHub->getSessionWithId(sessionId);
EXPECT_FALSE(sessionAfterRegistering.has_value());
std::optional<Session> sessionAfterRegistering2 =
messageHub2->getSessionWithId(sessionId);
EXPECT_FALSE(sessionAfterRegistering2.has_value());
// Close the session and verify it is closed on both message hubs
EXPECT_EQ(sessionFromCallback1.sessionId, sessionId);
EXPECT_EQ(sessionFromCallback1.initiator.messageHubId, messageHub->getId());
EXPECT_EQ(sessionFromCallback1.initiator.endpointId, kEndpointInfos[0].id);
EXPECT_EQ(sessionFromCallback1.peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionFromCallback1.peer.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(sessionCloseReason, reason);
}
TEST_F(MessageRouterTest, RegisterSessionSecondHubDoesNotRespond) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
bool wasOpenSessionRequestCalled = false;
bool wasOpenSessionRequestCalled2 = false;
pw::IntrusivePtr<MessageHubCallbackOpenSessionRequest> callback =
pw::MakeRefCounted<MessageHubCallbackOpenSessionRequest>(
&wasOpenSessionRequestCalled);
pw::IntrusivePtr<MessageHubCallbackOpenSessionRequest> callback2 =
pw::MakeRefCounted<MessageHubCallbackOpenSessionRequest>(
&wasOpenSessionRequestCalled2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
// Message Hub 2 does not respond - verify the callback was called once
EXPECT_FALSE(wasOpenSessionRequestCalled);
EXPECT_TRUE(wasOpenSessionRequestCalled2);
// Open session from messageHub:1 to messageHub2:2 - try again
wasOpenSessionRequestCalled = false;
SessionId sessionId2 = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
EXPECT_EQ(sessionId, sessionId2);
EXPECT_FALSE(wasOpenSessionRequestCalled);
EXPECT_TRUE(wasOpenSessionRequestCalled2);
// Respond then close the session
messageHub2->onSessionOpenComplete(sessionId2);
EXPECT_TRUE(messageHub->closeSession(sessionId));
}
TEST_F(MessageRouterTest, RegisterSessionWithServiceDescriptor) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionFromCallback1;
Session sessionFromCallback2;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id,
kServiceDescriptorForEndpoint2);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
// Get session from messageHub and compare it with messageHub2
std::optional<Session> sessionAfterRegistering =
messageHub->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering.has_value());
EXPECT_EQ(sessionAfterRegistering->sessionId, sessionId);
EXPECT_EQ(sessionAfterRegistering->initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionAfterRegistering->initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionAfterRegistering->peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionAfterRegistering->peer.endpointId, kEndpointInfos[1].id);
EXPECT_TRUE(sessionAfterRegistering->hasServiceDescriptor);
EXPECT_STREQ(sessionAfterRegistering->serviceDescriptor,
kServiceDescriptorForEndpoint2);
std::optional<Session> sessionAfterRegistering2 =
messageHub2->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering2.has_value());
EXPECT_EQ(*sessionAfterRegistering, *sessionAfterRegistering2);
// Close the session and verify it is closed on both message hubs
EXPECT_NE(*sessionAfterRegistering, sessionFromCallback1);
EXPECT_NE(*sessionAfterRegistering, sessionFromCallback2);
EXPECT_TRUE(messageHub->closeSession(sessionId));
EXPECT_EQ(*sessionAfterRegistering, sessionFromCallback1);
EXPECT_EQ(*sessionAfterRegistering, sessionFromCallback2);
EXPECT_FALSE(messageHub->getSessionWithId(sessionId).has_value());
EXPECT_FALSE(messageHub2->getSessionWithId(sessionId).has_value());
}
TEST_F(MessageRouterTest,
RegisterSessionWithAndWithoutServiceDescriptorSameEndpoints) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionFromCallback1;
Session sessionFromCallback2;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub2:2 with service descriptor
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id,
kServiceDescriptorForEndpoint2);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
// Open session from messageHub:1 to messageHub2:2 without service descriptor
SessionId sessionId2 = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId2, SESSION_ID_INVALID);
EXPECT_NE(sessionId2, sessionId);
// Get the first session from messageHub and compare it with messageHub2
std::optional<Session> sessionAfterRegistering =
messageHub->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering.has_value());
EXPECT_EQ(sessionAfterRegistering->sessionId, sessionId);
EXPECT_EQ(sessionAfterRegistering->initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionAfterRegistering->initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionAfterRegistering->peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionAfterRegistering->peer.endpointId, kEndpointInfos[1].id);
EXPECT_TRUE(sessionAfterRegistering->hasServiceDescriptor);
EXPECT_STREQ(sessionAfterRegistering->serviceDescriptor,
kServiceDescriptorForEndpoint2);
std::optional<Session> sessionAfterRegistering2 =
messageHub2->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering2.has_value());
EXPECT_EQ(*sessionAfterRegistering, *sessionAfterRegistering2);
// Get the second session from messageHub and compare it with messageHub2
std::optional<Session> sessionAfterRegistering3 =
messageHub->getSessionWithId(sessionId2);
EXPECT_TRUE(sessionAfterRegistering3.has_value());
EXPECT_EQ(sessionAfterRegistering3->sessionId, sessionId2);
EXPECT_EQ(sessionAfterRegistering3->initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionAfterRegistering3->initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionAfterRegistering3->peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionAfterRegistering3->peer.endpointId, kEndpointInfos[1].id);
EXPECT_FALSE(sessionAfterRegistering3->hasServiceDescriptor);
EXPECT_STREQ(sessionAfterRegistering3->serviceDescriptor, "");
std::optional<Session> sessionAfterRegistering4 =
messageHub2->getSessionWithId(sessionId2);
EXPECT_TRUE(sessionAfterRegistering4.has_value());
EXPECT_EQ(*sessionAfterRegistering3, *sessionAfterRegistering4);
}
TEST_F(MessageRouterTest, RegisterSessionWithBadServiceDescriptor) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionFromCallback1;
Session sessionFromCallback2;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[2].id,
kServiceDescriptorForEndpoint2);
EXPECT_EQ(sessionId, SESSION_ID_INVALID);
}
TEST_F(MessageRouterTest, UnregisterMessageHubCausesSessionClosed) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionFromCallback1;
Session sessionFromCallback2;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
// Get session from messageHub and compare it with messageHub2
std::optional<Session> sessionAfterRegistering =
messageHub->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering.has_value());
EXPECT_EQ(sessionAfterRegistering->sessionId, sessionId);
EXPECT_EQ(sessionAfterRegistering->initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionAfterRegistering->initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionAfterRegistering->peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionAfterRegistering->peer.endpointId, kEndpointInfos[1].id);
std::optional<Session> sessionAfterRegistering2 =
messageHub2->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering2.has_value());
EXPECT_EQ(*sessionAfterRegistering, *sessionAfterRegistering2);
// Close the session and verify it is closed on the other hub
EXPECT_NE(*sessionAfterRegistering, sessionFromCallback1);
messageHub2.reset();
EXPECT_EQ(*sessionAfterRegistering, sessionFromCallback1);
EXPECT_FALSE(messageHub->getSessionWithId(sessionId).has_value());
}
TEST_F(MessageRouterTest, RegisterSessionSameMessageHubIsValid) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionFromCallback1;
Session sessionFromCallback2;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:2 to messageHub:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[1].id, messageHub->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
// Open session from messageHub:1 to messageHub:3
sessionId = messageHub->openSession(kEndpointInfos[0].id, messageHub->getId(),
kEndpointInfos[2].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
}
TEST_F(MessageRouterTest, RegisterSessionReservedSessionIdAreRespected) {
constexpr SessionId kReservedSessionId = 25;
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router(
kReservedSessionId);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub:2 more than the max number of
// sessions - should wrap around
for (size_t i = 0; i < kReservedSessionId * 2; ++i) {
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
EXPECT_TRUE(messageHub->closeSession(sessionId));
}
}
TEST_F(MessageRouterTest, RegisterSessionOpenSessionNotReservedRegionRejected) {
constexpr SessionId kReservedSessionId = 25;
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router(
kReservedSessionId);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub:2 and provide an invalid
// session ID (not in the reserved range)
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id,
/* serviceDescriptor= */ nullptr, kReservedSessionId / 2);
EXPECT_EQ(sessionId, SESSION_ID_INVALID);
}
TEST_F(MessageRouterTest, RegisterSessionOpenSessionWithReservedSessionId) {
constexpr SessionId kReservedSessionId = 25;
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router(
kReservedSessionId);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub:2 and provide a reserved
// session ID
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id,
/* serviceDescriptor= */ nullptr, kReservedSessionId);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
EXPECT_TRUE(messageHub->closeSession(sessionId));
}
TEST_F(MessageRouterTest, RegisterSessionDifferentMessageHubsSameEndpoints) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionFromCallback1;
Session sessionFromCallback2;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[0].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
}
TEST_F(MessageRouterTest,
RegisterSessionTwoDifferentMessageHubsInvalidEndpoint) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub with other non-registered endpoint - not
// valid
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), /* toEndpointId= */ 10);
EXPECT_EQ(sessionId, SESSION_ID_INVALID);
}
TEST_F(MessageRouterTest, ThirdMessageHubTriesToFindOthersSession) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
Session sessionFromCallback1;
Session sessionFromCallback2;
Session sessionFromCallback3;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback2);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback3 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
&sessionFromCallback3);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback3);
EXPECT_TRUE(messageHub3.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
// Get session from messageHub and compare it with messageHub2
std::optional<Session> sessionAfterRegistering =
messageHub->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering.has_value());
EXPECT_EQ(sessionAfterRegistering->sessionId, sessionId);
EXPECT_EQ(sessionAfterRegistering->initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionAfterRegistering->initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionAfterRegistering->peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionAfterRegistering->peer.endpointId, kEndpointInfos[1].id);
std::optional<Session> sessionAfterRegistering2 =
messageHub2->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering2.has_value());
EXPECT_EQ(*sessionAfterRegistering, *sessionAfterRegistering2);
// Third message hub tries to find the session - not found
EXPECT_FALSE(messageHub3->getSessionWithId(sessionId).has_value());
// Third message hub tries to close the session - not found
EXPECT_FALSE(messageHub3->closeSession(sessionId));
// Get session from messageHub and compare it with messageHub2 again
sessionAfterRegistering = messageHub->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering.has_value());
EXPECT_EQ(sessionAfterRegistering->sessionId, sessionId);
EXPECT_EQ(sessionAfterRegistering->initiator.messageHubId,
messageHub->getId());
EXPECT_EQ(sessionAfterRegistering->initiator.endpointId,
kEndpointInfos[0].id);
EXPECT_EQ(sessionAfterRegistering->peer.messageHubId, messageHub2->getId());
EXPECT_EQ(sessionAfterRegistering->peer.endpointId, kEndpointInfos[1].id);
sessionAfterRegistering2 = messageHub2->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering2.has_value());
EXPECT_EQ(*sessionAfterRegistering, *sessionAfterRegistering2);
// Close the session and verify it is closed on both message hubs
EXPECT_NE(*sessionAfterRegistering, sessionFromCallback1);
EXPECT_NE(*sessionAfterRegistering, sessionFromCallback2);
EXPECT_TRUE(messageHub->closeSession(sessionId));
EXPECT_EQ(*sessionAfterRegistering, sessionFromCallback1);
EXPECT_EQ(*sessionAfterRegistering, sessionFromCallback2);
EXPECT_NE(*sessionAfterRegistering, sessionFromCallback3);
EXPECT_FALSE(messageHub->getSessionWithId(sessionId).has_value());
EXPECT_FALSE(messageHub2->getSessionWithId(sessionId).has_value());
}
TEST_F(MessageRouterTest, ThreeMessageHubsAndThreeSessions) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback3 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback3);
EXPECT_TRUE(messageHub3.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
// Open session from messageHub2:2 to messageHub3:3
SessionId sessionId2 = messageHub2->openSession(
kEndpointInfos[1].id, messageHub3->getId(), kEndpointInfos[2].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub3->onSessionOpenComplete(sessionId2);
// Open session from messageHub3:3 to messageHub1:1
SessionId sessionId3 = messageHub3->openSession(
kEndpointInfos[2].id, messageHub->getId(), kEndpointInfos[0].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub->onSessionOpenComplete(sessionId3);
// Get sessions and compare
// Find session: MessageHub1:1 -> MessageHub2:2
std::optional<Session> sessionAfterRegistering =
messageHub->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering.has_value());
std::optional<Session> sessionAfterRegistering2 =
messageHub2->getSessionWithId(sessionId);
EXPECT_TRUE(sessionAfterRegistering2.has_value());
EXPECT_FALSE(messageHub3->getSessionWithId(sessionId).has_value());
EXPECT_EQ(*sessionAfterRegistering, *sessionAfterRegistering2);
// Find session: MessageHub2:2 -> MessageHub3:3
sessionAfterRegistering = messageHub2->getSessionWithId(sessionId2);
EXPECT_TRUE(sessionAfterRegistering.has_value());
sessionAfterRegistering2 = messageHub3->getSessionWithId(sessionId2);
EXPECT_TRUE(sessionAfterRegistering2.has_value());
EXPECT_FALSE(messageHub->getSessionWithId(sessionId2).has_value());
EXPECT_EQ(*sessionAfterRegistering, *sessionAfterRegistering2);
// Find session: MessageHub3:3 -> MessageHub1:1
sessionAfterRegistering = messageHub3->getSessionWithId(sessionId3);
EXPECT_TRUE(sessionAfterRegistering.has_value());
sessionAfterRegistering2 = messageHub->getSessionWithId(sessionId3);
EXPECT_TRUE(sessionAfterRegistering2.has_value());
EXPECT_FALSE(messageHub2->getSessionWithId(sessionId3).has_value());
EXPECT_EQ(*sessionAfterRegistering, *sessionAfterRegistering2);
// Close sessions from receivers and verify they are closed on all hubs
EXPECT_TRUE(messageHub2->closeSession(sessionId));
EXPECT_TRUE(messageHub3->closeSession(sessionId2));
EXPECT_TRUE(messageHub->closeSession(sessionId3));
for (SessionId id : {sessionId, sessionId2, sessionId3}) {
EXPECT_FALSE(messageHub->getSessionWithId(id).has_value());
EXPECT_FALSE(messageHub2->getSessionWithId(id).has_value());
EXPECT_FALSE(messageHub3->getSessionWithId(id).has_value());
}
}
TEST_F(MessageRouterTest, SendMessageToSession) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
constexpr size_t kMessageSize = 5;
pw::allocator::LibCAllocator allocator = pw::allocator::GetLibCAllocator();
pw::UniquePtr<std::byte[]> messageData =
allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
Message messageFromCallback1;
Message messageFromCallback2;
Message messageFromCallback3;
Session sessionFromCallback1;
Session sessionFromCallback2;
Session sessionFromCallback3;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback1,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback2,
&sessionFromCallback2);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback3 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback3,
&sessionFromCallback3);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback3);
EXPECT_TRUE(messageHub3.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
// Open session from messageHub2:2 to messageHub3:3
SessionId sessionId2 = messageHub2->openSession(
kEndpointInfos[1].id, messageHub3->getId(), kEndpointInfos[2].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub3->onSessionOpenComplete(sessionId2);
// Open session from messageHub3:3 to messageHub1:1
SessionId sessionId3 = messageHub3->openSession(
kEndpointInfos[2].id, messageHub->getId(), kEndpointInfos[0].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub->onSessionOpenComplete(sessionId3);
// Send message from messageHub:1 to messageHub2:2
ASSERT_TRUE(messageHub->sendMessage(std::move(messageData),
/* messageType= */ 1,
/* messagePermissions= */ 0, sessionId));
EXPECT_EQ(messageFromCallback2.sessionId, sessionId);
EXPECT_EQ(messageFromCallback2.sender.messageHubId, messageHub->getId());
EXPECT_EQ(messageFromCallback2.sender.endpointId, kEndpointInfos[0].id);
EXPECT_EQ(messageFromCallback2.recipient.messageHubId, messageHub2->getId());
EXPECT_EQ(messageFromCallback2.recipient.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(messageFromCallback2.messageType, 1);
EXPECT_EQ(messageFromCallback2.messagePermissions, 0);
EXPECT_EQ(messageFromCallback2.data.size(), kMessageSize);
for (size_t i = 0; i < kMessageSize; ++i) {
EXPECT_EQ(messageFromCallback2.data[i], static_cast<std::byte>(i + 1));
}
messageData = allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
// Send message from messageHub2:2 to messageHub:1
ASSERT_TRUE(messageHub2->sendMessage(std::move(messageData),
/* messageType= */ 2,
/* messagePermissions= */ 3, sessionId));
EXPECT_EQ(messageFromCallback1.sessionId, sessionId);
EXPECT_EQ(messageFromCallback1.sender.messageHubId, messageHub2->getId());
EXPECT_EQ(messageFromCallback1.sender.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(messageFromCallback1.recipient.messageHubId, messageHub->getId());
EXPECT_EQ(messageFromCallback1.recipient.endpointId, kEndpointInfos[0].id);
EXPECT_EQ(messageFromCallback1.messageType, 2);
EXPECT_EQ(messageFromCallback1.messagePermissions, 3);
EXPECT_EQ(messageFromCallback1.data.size(), kMessageSize);
for (size_t i = 0; i < kMessageSize; ++i) {
EXPECT_EQ(messageFromCallback1.data[i], static_cast<std::byte>(i + 1));
}
}
TEST_F(MessageRouterTest, SendMessageOnHalfOpenSessionIsRejected) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
constexpr size_t kMessageSize = 5;
pw::allocator::LibCAllocator allocator = pw::allocator::GetLibCAllocator();
pw::UniquePtr<std::byte[]> messageData =
allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
Message messageFromCallback1;
Message messageFromCallback2;
Session sessionFromCallback1;
Session sessionFromCallback2;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback1,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback2,
&sessionFromCallback2);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
// Open session from messageHub:1 to messageHub2:2 but do not complete it
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
// Try to send a message from messageHub:1 to messageHub2:2 - should fail
EXPECT_FALSE(messageHub->sendMessage(std::move(messageData),
/* messageType= */ 1,
/* messagePermissions= */ 0, sessionId));
// Now complete the session
messageHub2->onSessionOpenComplete(sessionId);
// Send message from messageHub:1 to messageHub2:2
messageData = allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
ASSERT_TRUE(messageHub->sendMessage(std::move(messageData),
/* messageType= */ 1,
/* messagePermissions= */ 0, sessionId));
EXPECT_EQ(messageFromCallback2.sessionId, sessionId);
EXPECT_EQ(messageFromCallback2.sender.messageHubId, messageHub->getId());
EXPECT_EQ(messageFromCallback2.sender.endpointId, kEndpointInfos[0].id);
EXPECT_EQ(messageFromCallback2.recipient.messageHubId, messageHub2->getId());
EXPECT_EQ(messageFromCallback2.recipient.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(messageFromCallback2.messageType, 1);
EXPECT_EQ(messageFromCallback2.messagePermissions, 0);
EXPECT_EQ(messageFromCallback2.data.size(), kMessageSize);
for (size_t i = 0; i < kMessageSize; ++i) {
EXPECT_EQ(messageFromCallback2.data[i], static_cast<std::byte>(i + 1));
}
messageData = allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
// Send message from messageHub2:2 to messageHub:1
ASSERT_TRUE(messageHub2->sendMessage(std::move(messageData),
/* messageType= */ 2,
/* messagePermissions= */ 3, sessionId));
EXPECT_EQ(messageFromCallback1.sessionId, sessionId);
EXPECT_EQ(messageFromCallback1.sender.messageHubId, messageHub2->getId());
EXPECT_EQ(messageFromCallback1.sender.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(messageFromCallback1.recipient.messageHubId, messageHub->getId());
EXPECT_EQ(messageFromCallback1.recipient.endpointId, kEndpointInfos[0].id);
EXPECT_EQ(messageFromCallback1.messageType, 2);
EXPECT_EQ(messageFromCallback1.messagePermissions, 3);
EXPECT_EQ(messageFromCallback1.data.size(), kMessageSize);
for (size_t i = 0; i < kMessageSize; ++i) {
EXPECT_EQ(messageFromCallback1.data[i], static_cast<std::byte>(i + 1));
}
}
TEST_F(MessageRouterTest, SendMessageToSessionUsingPointerAndFreeCallback) {
struct FreeCallbackContext {
bool *freeCallbackCalled;
std::byte *message;
size_t length;
};
pw::Vector<CallbackAllocator<FreeCallbackContext>::CallbackRecord, 10>
freeCallbackRecords;
CallbackAllocator<FreeCallbackContext> allocator(
[](std::byte *message, size_t length, FreeCallbackContext &&context) {
*context.freeCallbackCalled =
message == context.message && length == context.length;
},
freeCallbackRecords);
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
constexpr size_t kMessageSize = 5;
std::byte messageData[kMessageSize];
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
Message messageFromCallback1;
Message messageFromCallback2;
Message messageFromCallback3;
Session sessionFromCallback1;
Session sessionFromCallback2;
Session sessionFromCallback3;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback1,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback2,
&sessionFromCallback2);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback3 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback3,
&sessionFromCallback3);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback3);
EXPECT_TRUE(messageHub3.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
// Open session from messageHub2:2 to messageHub3:3
SessionId sessionId2 = messageHub2->openSession(
kEndpointInfos[1].id, messageHub3->getId(), kEndpointInfos[2].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub3->onSessionOpenComplete(sessionId2);
// Open session from messageHub3:3 to messageHub1:1
SessionId sessionId3 = messageHub3->openSession(
kEndpointInfos[2].id, messageHub->getId(), kEndpointInfos[0].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub->onSessionOpenComplete(sessionId3);
// Send message from messageHub:1 to messageHub2:2
bool freeCallbackCalled = false;
FreeCallbackContext freeCallbackContext = {
.freeCallbackCalled = &freeCallbackCalled,
.message = messageData,
.length = kMessageSize,
};
pw::UniquePtr<std::byte[]> data = allocator.MakeUniqueArrayWithCallback(
messageData, kMessageSize, std::move(freeCallbackContext));
ASSERT_NE(data.get(), nullptr);
ASSERT_TRUE(messageHub->sendMessage(std::move(data),
/* messageType= */ 1,
/* messagePermissions= */ 0, sessionId));
EXPECT_EQ(messageFromCallback2.sessionId, sessionId);
EXPECT_EQ(messageFromCallback2.sender.messageHubId, messageHub->getId());
EXPECT_EQ(messageFromCallback2.sender.endpointId, kEndpointInfos[0].id);
EXPECT_EQ(messageFromCallback2.recipient.messageHubId, messageHub2->getId());
EXPECT_EQ(messageFromCallback2.recipient.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(messageFromCallback2.messageType, 1);
EXPECT_EQ(messageFromCallback2.messagePermissions, 0);
EXPECT_EQ(messageFromCallback2.data.size(), kMessageSize);
for (size_t i = 0; i < kMessageSize; ++i) {
EXPECT_EQ(messageFromCallback2.data[i], static_cast<std::byte>(i + 1));
}
// Check if free callback was called
EXPECT_FALSE(freeCallbackCalled);
EXPECT_EQ(messageFromCallback2.data.get(), messageData);
messageFromCallback2.data.Reset();
EXPECT_TRUE(freeCallbackCalled);
// Send message from messageHub2:2 to messageHub:1
freeCallbackCalled = false;
FreeCallbackContext freeCallbackContext2 = {
.freeCallbackCalled = &freeCallbackCalled,
.message = messageData,
.length = kMessageSize,
};
data = allocator.MakeUniqueArrayWithCallback(messageData, kMessageSize,
std::move(freeCallbackContext2));
ASSERT_NE(data.get(), nullptr);
ASSERT_TRUE(messageHub2->sendMessage(std::move(data),
/* messageType= */ 2,
/* messagePermissions= */ 3, sessionId));
EXPECT_EQ(messageFromCallback1.sessionId, sessionId);
EXPECT_EQ(messageFromCallback1.sender.messageHubId, messageHub2->getId());
EXPECT_EQ(messageFromCallback1.sender.endpointId, kEndpointInfos[1].id);
EXPECT_EQ(messageFromCallback1.recipient.messageHubId, messageHub->getId());
EXPECT_EQ(messageFromCallback1.recipient.endpointId, kEndpointInfos[0].id);
EXPECT_EQ(messageFromCallback1.messageType, 2);
EXPECT_EQ(messageFromCallback1.messagePermissions, 3);
EXPECT_EQ(messageFromCallback1.data.size(), kMessageSize);
for (size_t i = 0; i < kMessageSize; ++i) {
EXPECT_EQ(messageFromCallback1.data[i], static_cast<std::byte>(i + 1));
}
// Check if free callback was called
EXPECT_FALSE(freeCallbackCalled);
EXPECT_EQ(messageFromCallback1.data.get(), messageData);
messageFromCallback1.data.Reset();
EXPECT_TRUE(freeCallbackCalled);
}
TEST_F(MessageRouterTest, SendMessageToSessionInvalidHubAndSession) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
constexpr size_t kMessageSize = 5;
pw::allocator::LibCAllocator allocator = pw::allocator::GetLibCAllocator();
pw::UniquePtr<std::byte[]> messageData =
allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
Message messageFromCallback1;
Message messageFromCallback2;
Message messageFromCallback3;
Session sessionFromCallback1;
Session sessionFromCallback2;
Session sessionFromCallback3;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback1,
&sessionFromCallback1);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback2,
&sessionFromCallback2);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback3 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(&messageFromCallback3,
&sessionFromCallback3);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback3);
EXPECT_TRUE(messageHub3.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
// Open session from messageHub2:2 to messageHub3:3
SessionId sessionId2 = messageHub2->openSession(
kEndpointInfos[1].id, messageHub3->getId(), kEndpointInfos[2].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub3->onSessionOpenComplete(sessionId2);
// Open session from messageHub3:3 to messageHub1:1
SessionId sessionId3 = messageHub3->openSession(
kEndpointInfos[2].id, messageHub->getId(), kEndpointInfos[0].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub->onSessionOpenComplete(sessionId3);
// Send message from messageHub:1 to messageHub2:2
EXPECT_FALSE(messageHub->sendMessage(std::move(messageData),
/* messageType= */ 1,
/* messagePermissions= */ 0,
sessionId2));
EXPECT_FALSE(messageHub2->sendMessage(std::move(messageData),
/* messageType= */ 2,
/* messagePermissions= */ 3,
sessionId3));
EXPECT_FALSE(messageHub3->sendMessage(std::move(messageData),
/* messageType= */ 2,
/* messagePermissions= */ 3,
sessionId));
}
TEST_F(MessageRouterTest, SendMessageToSessionCallbackFailureClosesSession) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
constexpr size_t kMessageSize = 5;
pw::allocator::LibCAllocator allocator = pw::allocator::GetLibCAllocator();
pw::UniquePtr<std::byte[]> messageData =
allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
bool wasMessageReceivedCalled1 = false;
bool wasMessageReceivedCalled2 = false;
bool wasMessageReceivedCalled3 = false;
pw::IntrusivePtr<MessageHubCallbackAlwaysFails> callback1 =
pw::MakeRefCounted<MessageHubCallbackAlwaysFails>(
&wasMessageReceivedCalled1,
/* wasSessionClosedCalled= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackAlwaysFails> callback2 =
pw::MakeRefCounted<MessageHubCallbackAlwaysFails>(
&wasMessageReceivedCalled2,
/* wasSessionClosedCalled= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackAlwaysFails> callback3 =
pw::MakeRefCounted<MessageHubCallbackAlwaysFails>(
&wasMessageReceivedCalled3,
/* wasSessionClosedCalled= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback1);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback3);
EXPECT_TRUE(messageHub3.has_value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
// Open session from messageHub2:2 to messageHub3:3
SessionId sessionId2 = messageHub2->openSession(
kEndpointInfos[1].id, messageHub3->getId(), kEndpointInfos[2].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub3->onSessionOpenComplete(sessionId2);
// Open session from messageHub3:3 to messageHub1:1
SessionId sessionId3 = messageHub3->openSession(
kEndpointInfos[2].id, messageHub->getId(), kEndpointInfos[0].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub->onSessionOpenComplete(sessionId3);
// Send message from messageHub2:2 to messageHub3:3
EXPECT_FALSE(wasMessageReceivedCalled1);
EXPECT_FALSE(wasMessageReceivedCalled2);
EXPECT_FALSE(wasMessageReceivedCalled3);
EXPECT_FALSE(messageHub->getSessionWithId(sessionId2).has_value());
EXPECT_TRUE(messageHub2->getSessionWithId(sessionId2).has_value());
EXPECT_TRUE(messageHub3->getSessionWithId(sessionId2).has_value());
EXPECT_FALSE(messageHub2->sendMessage(std::move(messageData),
/* messageType= */ 1,
/* messagePermissions= */ 0,
sessionId2));
EXPECT_FALSE(wasMessageReceivedCalled1);
EXPECT_FALSE(wasMessageReceivedCalled2);
EXPECT_TRUE(wasMessageReceivedCalled3);
EXPECT_FALSE(messageHub->getSessionWithId(sessionId2).has_value());
EXPECT_FALSE(messageHub2->getSessionWithId(sessionId2).has_value());
EXPECT_FALSE(messageHub3->getSessionWithId(sessionId2).has_value());
// Try to send a message on the same session - should fail
wasMessageReceivedCalled1 = false;
wasMessageReceivedCalled2 = false;
wasMessageReceivedCalled3 = false;
messageData = allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
EXPECT_FALSE(messageHub2->sendMessage(std::move(messageData),
/* messageType= */ 1,
/* messagePermissions= */ 0,
sessionId2));
messageData = allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
EXPECT_FALSE(messageHub3->sendMessage(std::move(messageData),
/* messageType= */ 1,
/* messagePermissions= */ 0,
sessionId2));
EXPECT_FALSE(wasMessageReceivedCalled1);
EXPECT_FALSE(wasMessageReceivedCalled2);
EXPECT_FALSE(wasMessageReceivedCalled3);
}
TEST_F(MessageRouterTest, MessageHubCallbackCanCallOtherMessageHubAPIs) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
constexpr size_t kMessageSize = 5;
pw::allocator::LibCAllocator allocator = pw::allocator::GetLibCAllocator();
pw::UniquePtr<std::byte[]> messageData =
allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
pw::IntrusivePtr<MessageHubCallbackCallsMessageHubApisDuringCallback>
callback = pw::MakeRefCounted<
MessageHubCallbackCallsMessageHubApisDuringCallback>();
pw::IntrusivePtr<MessageHubCallbackCallsMessageHubApisDuringCallback>
callback2 = pw::MakeRefCounted<
MessageHubCallbackCallsMessageHubApisDuringCallback>();
pw::IntrusivePtr<MessageHubCallbackCallsMessageHubApisDuringCallback>
callback3 = pw::MakeRefCounted<
MessageHubCallbackCallsMessageHubApisDuringCallback>();
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
callback->setMessageHub(&messageHub.value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub2.has_value());
callback2->setMessageHub(&messageHub2.value());
std::optional<MessageRouter::MessageHub> messageHub3 =
router.registerMessageHub("hub3", /* id= */ 3, callback3);
EXPECT_TRUE(messageHub3.has_value());
callback3->setMessageHub(&messageHub3.value());
// Open session from messageHub:1 to messageHub2:2
SessionId sessionId = messageHub->openSession(
kEndpointInfos[0].id, messageHub2->getId(), kEndpointInfos[1].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub2->onSessionOpenComplete(sessionId);
// Open session from messageHub2:2 to messageHub3:3
SessionId sessionId2 = messageHub2->openSession(
kEndpointInfos[1].id, messageHub3->getId(), kEndpointInfos[2].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub3->onSessionOpenComplete(sessionId2);
// Open session from messageHub3:3 to messageHub1:1
SessionId sessionId3 = messageHub3->openSession(
kEndpointInfos[2].id, messageHub->getId(), kEndpointInfos[0].id);
EXPECT_NE(sessionId, SESSION_ID_INVALID);
messageHub->onSessionOpenComplete(sessionId3);
// Send message from messageHub:1 to messageHub2:2
EXPECT_TRUE(messageHub->sendMessage(std::move(messageData),
/* messageType= */ 1,
/* messagePermissions= */ 0, sessionId));
// Send message from messageHub2:2 to messageHub:1
messageData = allocator.MakeUniqueArray<std::byte>(kMessageSize);
for (size_t i = 0; i < 5; ++i) {
messageData[i] = static_cast<std::byte>(i + 1);
}
EXPECT_TRUE(messageHub2->sendMessage(std::move(messageData),
/* messageType= */ 2,
/* messagePermissions= */ 3, sessionId));
// Close all sessions
EXPECT_TRUE(messageHub->closeSession(sessionId));
EXPECT_TRUE(messageHub2->closeSession(sessionId2));
EXPECT_TRUE(messageHub3->closeSession(sessionId3));
// If we finish the test, both callbacks should have been called
// If the router holds the lock during the callback, this test will timeout
}
TEST_F(MessageRouterTest, ForEachEndpointOfHub) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
DynamicVector<EndpointInfo> endpoints;
EXPECT_TRUE(router.forEachEndpointOfHub(
/* messageHubId= */ 1, [&endpoints](const EndpointInfo &info) {
endpoints.push_back(info);
return false;
}));
EXPECT_EQ(endpoints.size(), kNumEndpoints);
for (size_t i = 0; i < endpoints.size(); ++i) {
EXPECT_EQ(endpoints[i].id, kEndpointInfos[i].id);
EXPECT_STREQ(endpoints[i].name, kEndpointInfos[i].name);
EXPECT_EQ(endpoints[i].version, kEndpointInfos[i].version);
EXPECT_EQ(endpoints[i].type, kEndpointInfos[i].type);
EXPECT_EQ(endpoints[i].requiredPermissions,
kEndpointInfos[i].requiredPermissions);
}
}
TEST_F(MessageRouterTest, ForEachEndpoint) {
const char *kHubName = "hub1";
constexpr MessageHubId kHubId = 1;
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub(kHubName, kHubId, callback);
EXPECT_TRUE(messageHub.has_value());
DynamicVector<std::pair<MessageHubInfo, EndpointInfo>> endpoints;
router.forEachEndpoint(
[&endpoints](const MessageHubInfo &hubInfo, const EndpointInfo &info) {
endpoints.push_back(std::make_pair(hubInfo, info));
});
EXPECT_EQ(endpoints.size(), kNumEndpoints);
for (size_t i = 0; i < endpoints.size(); ++i) {
EXPECT_EQ(endpoints[i].first.id, kHubId);
EXPECT_STREQ(endpoints[i].first.name, kHubName);
EXPECT_EQ(endpoints[i].second.id, kEndpointInfos[i].id);
EXPECT_STREQ(endpoints[i].second.name, kEndpointInfos[i].name);
EXPECT_EQ(endpoints[i].second.version, kEndpointInfos[i].version);
EXPECT_EQ(endpoints[i].second.type, kEndpointInfos[i].type);
EXPECT_EQ(endpoints[i].second.requiredPermissions,
kEndpointInfos[i].requiredPermissions);
}
}
TEST_F(MessageRouterTest, ForEachEndpointOfHubInvalidHub) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
DynamicVector<EndpointInfo> endpoints;
EXPECT_FALSE(router.forEachEndpointOfHub(
/* messageHubId= */ 2, [&endpoints](const EndpointInfo &info) {
endpoints.push_back(info);
return false;
}));
EXPECT_EQ(endpoints.size(), 0);
}
TEST_F(MessageRouterTest, RegisterEndpointCallbacksAreCalled) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub.has_value());
// Register the endpoint and verify that the callbacks were called
EXPECT_TRUE(messageHub->registerEndpoint(kEndpointInfos[0].id));
EXPECT_TRUE(callback2->hasEndpointBeenRegistered(messageHub->getId(),
kEndpointInfos[0].id));
}
TEST_F(MessageRouterTest, UnregisterEndpointCallbacksAreCalled) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MessageHubCallbackStoreData> callback =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
pw::IntrusivePtr<MessageHubCallbackStoreData> callback2 =
pw::MakeRefCounted<MessageHubCallbackStoreData>(/* message= */ nullptr,
/* session= */ nullptr);
std::optional<MessageRouter::MessageHub> messageHub =
router.registerMessageHub("hub1", /* id= */ 1, callback);
EXPECT_TRUE(messageHub.has_value());
std::optional<MessageRouter::MessageHub> messageHub2 =
router.registerMessageHub("hub2", /* id= */ 2, callback2);
EXPECT_TRUE(messageHub.has_value());
// Register the endpoint and verify that the callbacks were called
// only on the other hub
EXPECT_TRUE(messageHub->registerEndpoint(kEndpointInfos[0].id));
EXPECT_FALSE(callback->hasEndpointBeenRegistered(messageHub->getId(),
kEndpointInfos[0].id));
EXPECT_TRUE(callback2->hasEndpointBeenRegistered(messageHub->getId(),
kEndpointInfos[0].id));
// Unregister the endpoint and verify that the callbacks were called
// only on the other hub
EXPECT_TRUE(messageHub->unregisterEndpoint(kEndpointInfos[0].id));
EXPECT_FALSE(callback->hasEndpointBeenRegistered(messageHub->getId(),
kEndpointInfos[0].id));
EXPECT_FALSE(callback2->hasEndpointBeenRegistered(messageHub->getId(),
kEndpointInfos[0].id));
}
MATCHER_P(HubMatcher, id, "Matches id in MessageHubInfo") {
return arg.id == id;
}
TEST_F(MessageRouterTest, OnRegisterAndUnregisterHub) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MockMessageHubCallback> hub1Callback =
pw::MakeRefCounted<MockMessageHubCallback>();
pw::IntrusivePtr<MockMessageHubCallback> hub2Callback =
pw::MakeRefCounted<MockMessageHubCallback>();
MessageHubId hub1Id = 1, hub2Id = 2;
std::optional<MessageRouter::MessageHub> hub1 =
router.registerMessageHub("hub1", hub1Id, hub1Callback);
ASSERT_TRUE(hub1.has_value());
EXPECT_CALL(*hub1Callback, onHubRegistered(HubMatcher(hub2Id)));
std::optional<MessageRouter::MessageHub> hub2 =
router.registerMessageHub("hub2", hub2Id, hub2Callback);
ASSERT_TRUE(hub2.has_value());
EXPECT_CALL(*hub1Callback, onHubUnregistered(hub2Id));
hub2.reset();
}
MATCHER_P(SessionIdMatcher, id, "Matches id in Session") {
return arg.sessionId == id;
}
TEST_F(MessageRouterTest, SessionCallbacksAreCalledOnceSameHub) {
MessageRouterWithStorage<kMaxMessageHubs, kMaxSessions> router;
pw::IntrusivePtr<MockMessageHubCallback> hub1Callback =
pw::MakeRefCounted<MockMessageHubCallback>();
MessageHubId hub1Id = 1;
std::optional<MessageRouter::MessageHub> hub1 =
router.registerMessageHub("hub1", hub1Id, hub1Callback);
ASSERT_TRUE(hub1.has_value());
ON_CALL(*hub1Callback, forEachEndpoint).WillByDefault(forEachEndpoint);
// Try with different endpoints
SessionId sessionId = hub1->openSession(kEndpointInfos[0].id, hub1->getId(),
kEndpointInfos[1].id);
ASSERT_NE(sessionId, SESSION_ID_INVALID);
EXPECT_CALL(*hub1Callback, onSessionOpened(_)).Times(1);
hub1->onSessionOpenComplete(sessionId);
EXPECT_CALL(*hub1Callback, onSessionClosed(SessionIdMatcher(sessionId), _))
.Times(1);
hub1->closeSession(sessionId);
// Try with the same endpoint
SessionId sessionId2 = hub1->openSession(kEndpointInfos[1].id, hub1->getId(),
kEndpointInfos[1].id);
ASSERT_NE(sessionId2, SESSION_ID_INVALID);
EXPECT_CALL(*hub1Callback, onSessionOpened(_)).Times(1);
hub1->onSessionOpenComplete(sessionId2);
EXPECT_CALL(*hub1Callback, onSessionClosed(SessionIdMatcher(sessionId2), _))
.Times(1);
hub1->closeSession(sessionId2);
}
} // namespace
} // namespace chre::message