Skip to content

Commit e541387

Browse files
fix tests
1 parent c2bd1be commit e541387

1 file changed

Lines changed: 120 additions & 30 deletions

File tree

src/tests/integration/test_room_event_deduplication.cpp

Lines changed: 120 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@
1818
#include <chrono>
1919
#include <condition_variable>
2020
#include <map>
21+
#include <memory>
2122
#include <mutex>
23+
#include <sstream>
2224
#include <string>
2325
#include <thread>
26+
#include <vector>
2427

2528
#include "../common/audio_utils.h"
2629
#include "../common/test_common.h"
@@ -42,6 +45,7 @@ struct RoomEventCounts {
4245
std::map<std::string, int> participant_disconnected;
4346
std::map<std::string, int> track_published;
4447
std::map<std::string, int> track_subscribed;
48+
std::map<std::string, int> track_unsubscribed;
4549
std::map<std::string, int> track_unpublished;
4650
int disconnected = 0;
4751
};
@@ -51,6 +55,7 @@ struct RoomEventCountsSnapshot {
5155
std::map<std::string, int> participant_disconnected;
5256
std::map<std::string, int> track_published;
5357
std::map<std::string, int> track_subscribed;
58+
std::map<std::string, int> track_unsubscribed;
5459
std::map<std::string, int> track_unpublished;
5560
int disconnected = 0;
5661
};
@@ -62,6 +67,7 @@ RoomEventCountsSnapshot snapshotCounts(RoomEventCounts& counts) {
6267
snapshot.participant_disconnected = counts.participant_disconnected;
6368
snapshot.track_published = counts.track_published;
6469
snapshot.track_subscribed = counts.track_subscribed;
70+
snapshot.track_unsubscribed = counts.track_unsubscribed;
6571
snapshot.track_unpublished = counts.track_unpublished;
6672
snapshot.disconnected = counts.disconnected;
6773
return snapshot;
@@ -101,6 +107,13 @@ class RoomEventCounterDelegate : public RoomDelegate {
101107
notify([&]() { incrementMap(counts_.track_subscribed, event.publication->name()); });
102108
}
103109

110+
void onTrackUnsubscribed(Room&, const TrackUnsubscribedEvent& event) override {
111+
if (event.publication == nullptr) {
112+
return;
113+
}
114+
notify([&]() { incrementMap(counts_.track_unsubscribed, event.publication->name()); });
115+
}
116+
104117
void onTrackUnpublished(Room&, const TrackUnpublishedEvent& event) override {
105118
if (event.publication == nullptr) {
106119
return;
@@ -178,13 +191,97 @@ void expectCountsUnchangedAfterGrace(RoomEventCounts& counts, const RoomEventCou
178191
(std::string(phase) + " track_published duplicate").c_str());
179192
expectMapCountsExact(after.track_subscribed, before.track_subscribed,
180193
(std::string(phase) + " track_subscribed duplicate").c_str());
194+
expectMapCountsExact(after.track_unsubscribed, before.track_unsubscribed,
195+
(std::string(phase) + " track_unsubscribed duplicate").c_str());
181196
expectMapCountsExact(after.track_unpublished, before.track_unpublished,
182197
(std::string(phase) + " track_unpublished duplicate").c_str());
183198
EXPECT_EQ(after.disconnected, before.disconnected) << phase << " onDisconnected duplicate";
184199
}
185200

186201
std::string makeUniqueTrackName(const std::string& prefix) { return prefix + "-" + std::to_string(getTimestampUs()); }
187202

203+
std::string describeCounts(const std::map<std::string, int>& counts) {
204+
std::ostringstream out;
205+
bool first = true;
206+
out << "{";
207+
for (const auto& [key, count] : counts) {
208+
if (!first) {
209+
out << ", ";
210+
}
211+
first = false;
212+
out << key << ": " << count;
213+
}
214+
out << "}";
215+
return out.str();
216+
}
217+
218+
class MediaLoopGuard {
219+
public:
220+
MediaLoopGuard() = default;
221+
MediaLoopGuard(const MediaLoopGuard&) = delete;
222+
MediaLoopGuard& operator=(const MediaLoopGuard&) = delete;
223+
224+
~MediaLoopGuard() { stop(); }
225+
226+
void addAudioSource(const std::shared_ptr<AudioSource>& source) {
227+
threads_.emplace_back([this, source]() {
228+
runToneLoop(source, running_, 440.0, false, kDefaultAudioSampleRate, kDefaultAudioChannels);
229+
});
230+
}
231+
232+
void addVideoSource(const std::shared_ptr<VideoSource>& source) {
233+
threads_.emplace_back([this, source]() { runVideoLoop(source, running_, fillWebcamWrapper); });
234+
}
235+
236+
void stop() {
237+
running_.store(false, std::memory_order_relaxed);
238+
for (auto& thread : threads_) {
239+
if (thread.joinable()) {
240+
thread.join();
241+
}
242+
}
243+
}
244+
245+
private:
246+
std::atomic<bool> running_{true};
247+
std::vector<std::thread> threads_;
248+
};
249+
250+
class PublishedTrackGuard {
251+
public:
252+
explicit PublishedTrackGuard(LocalParticipant* participant) : participant_(participant) {}
253+
PublishedTrackGuard(const PublishedTrackGuard&) = delete;
254+
PublishedTrackGuard& operator=(const PublishedTrackGuard&) = delete;
255+
256+
~PublishedTrackGuard() noexcept {
257+
try {
258+
unpublishAll();
259+
} catch (...) {
260+
}
261+
}
262+
263+
void addTrackSid(const std::string& sid) {
264+
if (!sid.empty()) {
265+
track_sids_.push_back(sid);
266+
}
267+
}
268+
269+
void unpublishAll() {
270+
if (participant_ != nullptr) {
271+
for (const auto& sid : track_sids_) {
272+
if (!sid.empty()) {
273+
participant_->unpublishTrack(sid);
274+
}
275+
}
276+
}
277+
track_sids_.clear();
278+
}
279+
280+
private:
281+
LocalParticipant* participant_ = nullptr;
282+
std::vector<std::string> track_sids_;
283+
};
284+
188285
} // namespace
189286

190287
class RoomEventDeduplicationIntegrationTest : public LiveKitTestBase, public ::testing::WithParamInterface<bool> {
@@ -222,6 +319,7 @@ TEST_P(RoomEventDeduplicationIntegrationTest, RoomLifecycleDelegateCallbacksFire
222319
const std::map<std::string, int> peer_identity_expected{{peer_identity, 1}};
223320
ASSERT_TRUE(waitForMapCountAtLeast(observer_counts, peer_identity_expected, 1, kEventWaitTimeout))
224321
<< "Timed out waiting for onParticipantConnected";
322+
ASSERT_TRUE(waitForParticipant(&observer_room, peer_identity, 10s)) << "Peer not visible to observer room";
225323
{
226324
const RoomEventCountsSnapshot snapshot = snapshotCounts(observer_counts);
227325
expectMapCountsExact(snapshot.participant_connected, peer_identity_expected, "onParticipantConnected");
@@ -241,54 +339,46 @@ TEST_P(RoomEventDeduplicationIntegrationTest, RoomLifecycleDelegateCallbacksFire
241339
TrackPublishOptions video_opts;
242340
video_opts.source = TrackSource::SOURCE_CAMERA;
243341

244-
lockLocalParticipant(peer_room)->publishTrack(audio_track, audio_opts);
245-
lockLocalParticipant(peer_room)->publishTrack(video_track, video_opts);
342+
auto peer_participant = lockLocalParticipant(peer_room);
343+
PublishedTrackGuard published_tracks(peer_participant.get());
344+
MediaLoopGuard media_loops;
345+
346+
ASSERT_NO_THROW(peer_participant->publishTrack(audio_track, audio_opts));
246347
ASSERT_NE(audio_track->publication(), nullptr);
247-
ASSERT_NE(video_track->publication(), nullptr);
348+
published_tracks.addTrackSid(audio_track->publication()->sid());
349+
media_loops.addAudioSource(audio_source);
248350

249-
std::atomic<bool> media_running{true};
250-
std::thread audio_thread([&]() {
251-
runToneLoop(audio_source, media_running, 440.0, false, kDefaultAudioSampleRate, kDefaultAudioChannels);
252-
});
253-
std::thread video_thread([&]() { runVideoLoop(video_source, media_running, fillWebcamWrapper); });
351+
ASSERT_NO_THROW(peer_participant->publishTrack(video_track, video_opts));
352+
ASSERT_NE(video_track->publication(), nullptr);
353+
published_tracks.addTrackSid(video_track->publication()->sid());
354+
media_loops.addVideoSource(video_source);
254355

255-
const std::map<std::string, int> expected_published_counts{{audio_track_name, 1}, {video_track_name, 1}};
256356
const std::map<std::string, int> expected_subscribed_counts{{audio_track_name, 1}, {video_track_name, 1}};
257357

258-
ASSERT_TRUE(waitForMapCountAtLeastTrack(observer_counts, expected_published_counts, &RoomEventCounts::track_published,
259-
kEventWaitTimeout))
260-
<< "Timed out waiting for onTrackPublished";
261358
ASSERT_TRUE(waitForMapCountAtLeastTrack(observer_counts, expected_subscribed_counts,
262359
&RoomEventCounts::track_subscribed, kEventWaitTimeout))
263-
<< "Timed out waiting for onTrackSubscribed";
360+
<< "Timed out waiting for onTrackSubscribed; observed track_subscribed="
361+
<< describeCounts(snapshotCounts(observer_counts).track_subscribed);
264362

265363
{
266364
const RoomEventCountsSnapshot snapshot = snapshotCounts(observer_counts);
267-
expectMapCountsExact(snapshot.track_published, expected_published_counts, "onTrackPublished");
268365
expectMapCountsExact(snapshot.track_subscribed, expected_subscribed_counts, "onTrackSubscribed");
269366
expectCountsUnchangedAfterGrace(observer_counts, snapshot, "after track subscribe");
270367
}
271368

272-
media_running.store(false, std::memory_order_relaxed);
273-
if (audio_thread.joinable()) {
274-
audio_thread.join();
275-
}
276-
if (video_thread.joinable()) {
277-
video_thread.join();
278-
}
279-
280-
lockLocalParticipant(peer_room)->unpublishTrack(audio_track->publication()->sid());
281-
lockLocalParticipant(peer_room)->unpublishTrack(video_track->publication()->sid());
369+
media_loops.stop();
370+
published_tracks.unpublishAll();
282371

283-
const std::map<std::string, int> expected_unpublished_counts{{audio_track_name, 1}, {video_track_name, 1}};
284-
ASSERT_TRUE(waitForMapCountAtLeastTrack(observer_counts, expected_unpublished_counts,
285-
&RoomEventCounts::track_unpublished, kEventWaitTimeout))
286-
<< "Timed out waiting for onTrackUnpublished";
372+
const std::map<std::string, int> expected_unsubscribed_counts{{audio_track_name, 1}, {video_track_name, 1}};
373+
ASSERT_TRUE(waitForMapCountAtLeastTrack(observer_counts, expected_unsubscribed_counts,
374+
&RoomEventCounts::track_unsubscribed, kEventWaitTimeout))
375+
<< "Timed out waiting for onTrackUnsubscribed; observed track_unsubscribed="
376+
<< describeCounts(snapshotCounts(observer_counts).track_unsubscribed);
287377

288378
{
289379
const RoomEventCountsSnapshot snapshot = snapshotCounts(observer_counts);
290-
expectMapCountsExact(snapshot.track_unpublished, expected_unpublished_counts, "onTrackUnpublished");
291-
expectCountsUnchangedAfterGrace(observer_counts, snapshot, "after track unpublished");
380+
expectMapCountsExact(snapshot.track_unsubscribed, expected_unsubscribed_counts, "onTrackUnsubscribed");
381+
expectCountsUnchangedAfterGrace(observer_counts, snapshot, "after track unsubscribed");
292382
}
293383

294384
peer_room.disconnect();

0 commit comments

Comments
 (0)