Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ add_executable(moqx_relay_test
MoqxRelayTrackStatusTests.cpp
MoqxRelayNGRTests.cpp
MoqxRelayPeerTests.cpp
MoqxRelayTestModes.cpp
)
target_link_libraries(moqx_relay_test PRIVATE
moqx_test_fixture
Expand Down
6 changes: 3 additions & 3 deletions test/MoqxRelayDataPlaneTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace moxygen::test {
// new ones.
// Sequence: publish, 2 subscribers, beginSubgroup, beginSubgroup again ->
// first consumers get reset, both subscribers get new consumers.
TEST_F(MoQRelayTest, DuplicateSubgroupReplacesActiveConsumers) {
TEST_P(MoQRelayTest, DuplicateSubgroupReplacesActiveConsumers) {
auto publisherSession = createMockSession();
auto sub1 = createMockSession();
auto sub2 = createMockSession();
Expand Down Expand Up @@ -75,7 +75,7 @@ TEST_F(MoQRelayTest, DuplicateSubgroupReplacesActiveConsumers) {

// Test: Duplicate beginSubgroup after all subscribers have stop_sending'd
// returns CANCELLED to propagate the signal back to the publisher.
TEST_F(MoQRelayTest, DuplicateSubgroupCancelledWhenNoActiveConsumers) {
TEST_P(MoQRelayTest, DuplicateSubgroupCancelledWhenNoActiveConsumers) {
auto publisherSession = createMockSession();
auto subscriber = createMockSession();

Expand Down Expand Up @@ -114,7 +114,7 @@ TEST_F(MoQRelayTest, DuplicateSubgroupCancelledWhenNoActiveConsumers) {

// Test: Duplicate beginSubgroup with partial stop_sending - active subscriber
// gets reset and new consumer; tombstoned subscriber is skipped.
TEST_F(MoQRelayTest, DuplicateSubgroupSkipsTombstonedSubscriber) {
TEST_P(MoQRelayTest, DuplicateSubgroupSkipsTombstonedSubscriber) {
auto publisherSession = createMockSession();
auto subA = createMockSession();
auto subB = createMockSession();
Expand Down
2 changes: 1 addition & 1 deletion test/MoqxRelayFetchTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace moxygen::test {
// crash. When findPublishNamespaceSession returns null (no publishNamespace),
// fetch falls back to subscriptions_. After onPublishDone, upstream is null
// but the subscription entry remains if the forwarder has subscribers.
TEST_F(MoQRelayTest, FetchAfterPublisherTermination) {
TEST_P(MoQRelayTest, FetchAfterPublisherTermination) {
auto publisherSession = createMockSession();
auto subSession = createMockSession();
auto fetchSession = createMockSession();
Expand Down
12 changes: 6 additions & 6 deletions test/MoqxRelayNGRTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace moxygen::test {

// Test: relay PUBLISH path – dynamic groups from PublishRequest extensions
// is stored in the forwarder and forwarded to every downstream subscriber
TEST_F(MoQRelayTest, RelayPublishPropagatesDynamicGroupsToSubscribers) {
TEST_P(MoQRelayTest, RelayPublishPropagatesDynamicGroupsToSubscribers) {
auto publisherSession = createMockSession();
auto subscriberSession = createMockSession();

Expand Down Expand Up @@ -45,7 +45,7 @@ TEST_F(MoQRelayTest, RelayPublishPropagatesDynamicGroupsToSubscribers) {
// Test: relay SUBSCRIBE path – dynamic groups from the upstream SubscribeOk is
// stored in the forwarder and forwarded to both the first and late-joining
// downstream subscribers
TEST_F(MoQRelayTest, RelaySubscribePropagatesDynamicGroupsToAllSubscribers) {
TEST_P(MoQRelayTest, RelaySubscribePropagatesDynamicGroupsToAllSubscribers) {
auto publisherSession = createMockSession();
auto subscriber1 = createMockSession();
auto subscriber2 = createMockSession();
Expand Down Expand Up @@ -92,7 +92,7 @@ TEST_F(MoQRelayTest, RelaySubscribePropagatesDynamicGroupsToAllSubscribers) {

// Relay test: When a late-joining subscriber sends NEW_GROUP_REQUEST in its
// SUBSCRIBE, the relay forwards it upstream via REQUEST_UPDATE
TEST_F(MoQRelayTest, RelaySubscribeLateJoinerNGRForwardedUpstream) {
TEST_P(MoQRelayTest, RelaySubscribeLateJoinerNGRForwardedUpstream) {
auto publisherSession = createMockSession();
auto subscriber1 = createMockSession();
auto subscriber2 = createMockSession();
Expand Down Expand Up @@ -163,7 +163,7 @@ TEST_F(MoQRelayTest, RelaySubscribeLateJoinerNGRForwardedUpstream) {

// Relay test: A downstream subscriber sending REQUEST_UPDATE with
// NEW_GROUP_REQUEST causes the relay to cascade the NGR upstream
TEST_F(MoQRelayTest, RelayRequestUpdateNGRCascadedUpstream) {
TEST_P(MoQRelayTest, RelayRequestUpdateNGRCascadedUpstream) {
auto publisherSession = createMockSession();
auto subscriberSession = createMockSession();

Expand Down Expand Up @@ -218,7 +218,7 @@ TEST_F(MoQRelayTest, RelayRequestUpdateNGRCascadedUpstream) {

// Relay test: downstream subscriber returns PublishOk carrying NEW_GROUP_REQUEST;
// relay cascades NGR to the publisher handle upstream via REQUEST_UPDATE
TEST_F(MoQRelayTest, PublishOkNewNGRForwardedUpstream) {
TEST_P(MoQRelayTest, PublishOkNewNGRForwardedUpstream) {
auto publisherSession = createMockSession();
auto subscriberSession = createMockSession();

Expand Down Expand Up @@ -279,7 +279,7 @@ TEST_F(MoQRelayTest, PublishOkNewNGRForwardedUpstream) {
// Relay test: a second subscriber returning the same NEW_GROUP_REQUEST value in
// its PublishOk is deduplicated; the upstream handle receives exactly one
// REQUEST_UPDATE
TEST_F(MoQRelayTest, PublishOkDuplicateNGRNotForwardedUpstream) {
TEST_P(MoQRelayTest, PublishOkDuplicateNGRNotForwardedUpstream) {
auto publisherSession = createMockSession();
auto subscriber1 = createMockSession();
auto subscriber2 = createMockSession();
Expand Down
14 changes: 7 additions & 7 deletions test/MoqxRelayPeerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace moxygen::test {

// Test: makeNamespaceBridgeHandle routes namespaceMsg to doPublishNamespace
TEST_F(MoQRelayTest, NamespaceBridgeHandleForwardsNamespaceMsg) {
TEST_P(MoQRelayTest, NamespaceBridgeHandleForwardsNamespaceMsg) {
auto peerSession = createMockSession();

// Bridge handle routes NAMESPACE messages from peerSession into the relay.
Expand All @@ -32,7 +32,7 @@ TEST_F(MoQRelayTest, NamespaceBridgeHandleForwardsNamespaceMsg) {
}

// Test: makeNamespaceBridgeHandle routes namespaceDoneMsg to doPublishNamespaceDone
TEST_F(MoQRelayTest, NamespaceBridgeHandleForwardsDoneMsg) {
TEST_P(MoQRelayTest, NamespaceBridgeHandleForwardsDoneMsg) {
auto peerSession = createMockSession();
auto handle = makeNamespaceBridgeHandle(relay_, peerSession);

Expand Down Expand Up @@ -65,7 +65,7 @@ TEST_F(MoQRelayTest, NamespaceBridgeHandleForwardsDoneMsg) {
//
// Production relays negotiate draft-16 (empty prefix allowed). The delivery
// path for draft-16 is synchronous: namespacePublishHandle->namespaceMsg().
TEST_F(MoQRelayTest, PeerNamespaceNotEchoedBackOnReconnect) {
TEST_P(MoQRelayTest, PeerNamespaceNotEchoedBackOnReconnect) {
// Relay must have a relayID for peer detection to activate.
resetRelay(std::make_shared<MoqxRelay>(config::CacheConfig{.maxCachedTracks = 0}, "sg-sin-2-1"));
relay_->setAllowedNamespacePrefix(kAllowedPrefix);
Expand Down Expand Up @@ -107,7 +107,7 @@ TEST_F(MoQRelayTest, PeerNamespaceNotEchoedBackOnReconnect) {

// Complement: namespaces from LOCAL publishers (not from the peer) must still
// be delivered when that peer subscribes.
TEST_F(MoQRelayTest, LocalNamespaceDeliveredToPeerOnReconnect) {
TEST_P(MoQRelayTest, LocalNamespaceDeliveredToPeerOnReconnect) {
resetRelay(std::make_shared<MoqxRelay>(config::CacheConfig{.maxCachedTracks = 0}, "sg-sin-2-1"));
relay_->setAllowedNamespacePrefix(kAllowedPrefix);

Expand Down Expand Up @@ -183,7 +183,7 @@ class PeerAnnounceSession : public NiceMock<MockMoQSession> {
// directly via makeNamespaceBridgeHandle), this test goes through the full
// publisherInterface()->subscribeNamespace() production path so the bug in the call-site is
// exercised.
TEST_F(MoQRelayTest, PeerNamespaceNotEchoedBack_FullProductionPath) {
TEST_P(MoQRelayTest, PeerNamespaceNotEchoedBack_FullProductionPath) {
resetRelay(std::make_shared<MoqxRelay>(config::CacheConfig{.maxCachedTracks = 0}, "sg-sin-2-1"));
relay_->setAllowedNamespacePrefix(kAllowedPrefix);

Expand Down Expand Up @@ -237,7 +237,7 @@ TEST_F(MoQRelayTest, PeerNamespaceNotEchoedBack_FullProductionPath) {
// without graceful namespaceDoneMsg calls, tree entries it created must be
// cleaned up so stale sourceSession shared_ptrs don't keep dead session objects
// alive and downstream subscribers receive NAMESPACE_DONE.
TEST_F(MoQRelayTest, BridgeHandleDestructorCleansUpNamespaces) {
TEST_P(MoQRelayTest, BridgeHandleDestructorCleansUpNamespaces) {
auto upstreamSession = createMockSession();

// Simulate the bridge path: create a handle and announce a namespace through
Expand All @@ -264,7 +264,7 @@ TEST_F(MoQRelayTest, BridgeHandleDestructorCleansUpNamespaces) {
// Verify that when a new publisher takes over a namespace before the old
// bridge handle is destroyed, the stale handle's destructor does NOT evict
// the new publisher's entry (doPublishNamespaceDone guards on sourceSession).
TEST_F(MoQRelayTest, BridgeHandleDestructorDoesNotEvictNewPublisher) {
TEST_P(MoQRelayTest, BridgeHandleDestructorDoesNotEvictNewPublisher) {
auto session1 = createMockSession();
auto session2 = createMockSession();

Expand Down
20 changes: 10 additions & 10 deletions test/MoqxRelayPublishTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
namespace moxygen::test {

// Test: Verify allowed namespace prefix is set correctly
TEST_F(MoQRelayTest, AllowedNamespacePrefix) {
TEST_P(MoQRelayTest, AllowedNamespacePrefix) {
// This just verifies the relay can be constructed with a namespace prefix
// More detailed testing requires full session setup
auto relay2 = std::make_shared<MoqxRelay>(config::CacheConfig{
Expand All @@ -23,7 +23,7 @@ TEST_F(MoQRelayTest, AllowedNamespacePrefix) {
}

// Test: Publish a track through the relay
TEST_F(MoQRelayTest, PublishSuccess) {
TEST_P(MoQRelayTest, PublishSuccess) {
auto publisherSession = createMockSession();

// Publish the namespace
Expand All @@ -48,7 +48,7 @@ TEST_F(MoQRelayTest, PublishSuccess) {

// Test: Extensions from publish are forwarded to subscribers via
// subscribeNamespace
TEST_F(MoQRelayTest, PublishExtensionsForwardedToSubscribers) {
TEST_P(MoQRelayTest, PublishExtensionsForwardedToSubscribers) {
auto publisherSession = createMockSession();
auto subscriber = createMockSession();

Expand Down Expand Up @@ -107,7 +107,7 @@ TEST_F(MoQRelayTest, PublishExtensionsForwardedToSubscribers) {
// ============================================================

// Test: Extensions from publish are forwarded to late-joining subscribers
TEST_F(MoQRelayTest, PublishExtensionsForwardedToLateJoiners) {
TEST_P(MoQRelayTest, PublishExtensionsForwardedToLateJoiners) {
auto publisherSession = createMockSession();
auto subscriber1 = createMockSession();
auto subscriber2 = createMockSession();
Expand Down Expand Up @@ -199,7 +199,7 @@ TEST_F(MoQRelayTest, PublishExtensionsForwardedToLateJoiners) {
// 4. Session A reconnects and re-publishes the same track. The multipublisher
// check finds the surviving entry and calls it->second.handle->unsubscribe()
// — null-pointer dereference, SIGSEGV.
TEST_F(MoQRelayTest, PublisherReconnectWithOpenSubgroupNoSegfault) {
TEST_P(MoQRelayTest, PublisherReconnectWithOpenSubgroupNoSegfault) {
auto publisherSession = createMockSession();
auto subscriberSession = createMockSession();

Expand Down Expand Up @@ -260,7 +260,7 @@ TEST_F(MoQRelayTest, PublisherReconnectWithOpenSubgroupNoSegfault) {
// old forwarder's subscribers must receive publishDone, and the new
// publish-path subscription must be fully functional (accepting data from the
// new publisher).
TEST_F(MoQRelayTest, PublishReplacesSubscribeDrainsOldAndServesNew) {
TEST_P(MoQRelayTest, PublishReplacesSubscribeDrainsOldAndServesNew) {
auto publisherSession = createMockSession();
auto subscriberSession = createMockSession();

Expand Down Expand Up @@ -334,7 +334,7 @@ TEST_F(MoQRelayTest, PublishReplacesSubscribeDrainsOldAndServesNew) {
// ScopeGuardImplBase::terminate() → std::terminate (exit code 139).
//
// Without the fix: crashes. With the fix: subscribe returns an error cleanly.
TEST_F(MoQRelayTest, PublishReconnectDuringSubscribeScopeGuardCrash) {
TEST_P(MoQRelayTest, PublishReconnectDuringSubscribeScopeGuardCrash) {
auto publisherSession1 = createMockSession();
auto publisherSession2 = createMockSession();
auto subscriberSession = createMockSession();
Expand Down Expand Up @@ -423,7 +423,7 @@ TEST_F(MoQRelayTest, PublishReconnectDuringSubscribeScopeGuardCrash) {
// entry (promise already satisfied), and rsub.promise.setValue() throws
// PromiseAlreadySatisfied, which propagates as an unhandled coroutine exception.
// With the fix: subscribe returns SUBSCRIBE_ERROR "publisher reconnected".
TEST_F(MoQRelayTest, PublishReconnectDuringSubscribeSuccessPathCrash) {
TEST_P(MoQRelayTest, PublishReconnectDuringSubscribeSuccessPathCrash) {
auto publisherSession1 = createMockSession();
auto publisherSession2 = createMockSession();
auto subscriberSession = createMockSession();
Expand Down Expand Up @@ -498,7 +498,7 @@ TEST_F(MoQRelayTest, PublishReconnectDuringSubscribeSuccessPathCrash) {
// Regression: after publishDone the namespace-tree node must be pruned when
// the track was the only remaining content. (Was a bug before unpublishTrack
// gained a NodeMutationGuard; kept as a regression guard.)
TEST_F(MoQRelayTest, PublishDonePrunesNamespaceTreeNode) {
TEST_P(MoQRelayTest, PublishDonePrunesNamespaceTreeNode) {
auto publisher = createMockSession();

doPublishNamespace(publisher, kTestNamespace);
Expand Down Expand Up @@ -541,7 +541,7 @@ TEST_F(MoQRelayTest, PublishDonePrunesNamespaceTreeNode) {
}

// Empty namespace: publishNamespace with an empty TrackNamespace must not crash.
TEST_F(MoQRelayTest, EmptyNamespacePublishNamespaceDone) {
TEST_P(MoQRelayTest, EmptyNamespacePublishNamespaceDone) {
auto publisher = createMockSession();

TrackNamespace emptyNs{{}};
Expand Down
12 changes: 6 additions & 6 deletions test/MoqxRelaySubNsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace moxygen::test {

TEST_F(MoQRelayTest, SubscribeNamespaceDoesntAddDrainingPublish) {
TEST_P(MoQRelayTest, SubscribeNamespaceDoesntAddDrainingPublish) {
auto publisherSession = createMockSession();
auto subscriber1 = createMockSession();
auto subscriber2 = createMockSession();
Expand Down Expand Up @@ -89,7 +89,7 @@ TEST_F(MoQRelayTest, SubscribeNamespaceDoesntAddDrainingPublish) {
removeSession(subscriber2);
}

TEST_F(MoQRelayTest, SubscribeNamespaceEmptyPrefixRejectedPreV16) {
TEST_P(MoQRelayTest, SubscribeNamespaceEmptyPrefixRejectedPreV16) {
// Default session uses kVersionDraftCurrent (draft-14, which is < 16)
auto session = createMockSession();

Expand All @@ -109,7 +109,7 @@ TEST_F(MoQRelayTest, SubscribeNamespaceEmptyPrefixRejectedPreV16) {
removeSession(session);
}

TEST_F(MoQRelayTest, SubscribeNamespaceEmptyPrefixAllowedV16) {
TEST_P(MoQRelayTest, SubscribeNamespaceEmptyPrefixAllowedV16) {
auto session = createMockSession();
// Override the negotiated version to draft-16
ON_CALL(*session, getNegotiatedVersion())
Expand All @@ -121,7 +121,7 @@ TEST_F(MoQRelayTest, SubscribeNamespaceEmptyPrefixAllowedV16) {
removeSession(session);
}

TEST_F(MoQRelayTest, ExactNamespaceSubscriberReceivesPublishNamespace) {
TEST_P(MoQRelayTest, ExactNamespaceSubscriberReceivesPublishNamespace) {
auto subscriber = createMockSession();
auto publisher = createMockSession();

Expand Down Expand Up @@ -156,7 +156,7 @@ TEST_F(MoQRelayTest, ExactNamespaceSubscriberReceivesPublishNamespace) {
// forwarder is empty, the relay fires REQUEST_UPDATE twice — once explicitly
// at the if(forwarder->empty()) site and once via forwardChanged() when
// addSubscriber() increments numForwardingSubscribers from 0 to 1.
TEST_F(MoQRelayTest, SubscribeNs_ForwardTrue_EmptyForwarder_SingleRequestUpdate) {
TEST_P(MoQRelayTest, SubscribeNs_ForwardTrue_EmptyForwarder_SingleRequestUpdate) {
auto pubSession = createMockSession();
doPublishNamespace(pubSession, kTestNamespace);
auto mockHandle = makePublishHandle();
Expand Down Expand Up @@ -192,7 +192,7 @@ TEST_F(MoQRelayTest, SubscribeNs_ForwardTrue_EmptyForwarder_SingleRequestUpdate)
// forwarder is empty, the relay fires a spurious REQUEST_UPDATE(forward=false)
// at the if(forwarder->empty()) site — even though the upstream is already at
// forward=false (set by publish() which found no subscribers).
TEST_F(MoQRelayTest, SubscribeNs_ForwardFalse_EmptyForwarder_NoRequestUpdate) {
TEST_P(MoQRelayTest, SubscribeNs_ForwardFalse_EmptyForwarder_NoRequestUpdate) {
auto pubSession = createMockSession();
doPublishNamespace(pubSession, kTestNamespace);
auto mockHandle = makePublishHandle();
Expand Down
4 changes: 2 additions & 2 deletions test/MoqxRelaySubscribeTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace moxygen::test {
// terminated (onPublishDone clears handle/upstream). We trigger forwardChanged
// via Subscriber::requestUpdate changing forward from true→false (1→0
// transition). The subscriber survives drain because it has an open subgroup.
TEST_F(MoQRelayTest, ForwardChangedAfterPublisherTermination) {
TEST_P(MoQRelayTest, ForwardChangedAfterPublisherTermination) {
auto publisherSession = createMockSession();
auto subSession = createMockSession();

Expand Down Expand Up @@ -68,7 +68,7 @@ TEST_F(MoQRelayTest, ForwardChangedAfterPublisherTermination) {
// twice — once via forwardChanged() (which fires synchronously inside addSubscriber
// via addForwardingSubscriber) and once via the explicit block at the end of the
// subscribe() else-branch. Analogous to the subscribeNamespace bug fixed in this PR.
TEST_F(MoQRelayTest, Subscribe_SecondForwardingSubscriber_SingleRequestUpdate) {
TEST_P(MoQRelayTest, Subscribe_SecondForwardingSubscriber_SingleRequestUpdate) {
auto pubSession = createMockSession();
doPublishNamespace(pubSession, kTestNamespace);
auto mockHandle = makePublishHandle();
Expand Down
16 changes: 15 additions & 1 deletion test/MoqxRelayTestFixture.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ using namespace openmoq::moqx;

namespace moxygen::test {

enum class RelayMode {
SingleThread,
};

inline void PrintTo(RelayMode mode, std::ostream* os) {
switch (mode) {
case RelayMode::SingleThread:
*os << "SingleThread";
return;
}
}

inline const TrackNamespace kTestNamespace{{"test", "namespace"}};
inline const TrackNamespace kAllowedPrefix{{"test"}};
inline const FullTrackName kTestTrackName{kTestNamespace, "track1"};
Expand All @@ -48,8 +60,10 @@ class TestMoQExecutor : public MoQFollyExecutorImpl, public folly::DrivableExecu
};

// Test fixture for MoqxRelay and NamespaceTree tests.
class MoQRelayTest : public ::testing::Test {
class MoQRelayTest : public ::testing::TestWithParam<RelayMode> {
protected:
virtual RelayMode relayMode() const { return GetParam(); }

void SetUp() override;
void TearDown() override;

Expand Down
22 changes: 22 additions & 0 deletions test/MoqxRelayTestModes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) OpenMOQ contributors.
*/

#include "MoqxRelayTestFixture.h"

namespace moxygen::test {

INSTANTIATE_TEST_SUITE_P(
AllModes,
MoQRelayTest,
::testing::Values(RelayMode::SingleThread),
[](const ::testing::TestParamInfo<RelayMode>& info) -> std::string {
switch (info.param) {
case RelayMode::SingleThread:
return "SingleThread";
}
return "Unknown";
}
);

} // namespace moxygen::test
Loading
Loading