Skip to content

Commit 9effbcb

Browse files
Add integration test
1 parent 0b9ea06 commit 9effbcb

2 files changed

Lines changed: 59 additions & 5 deletions

File tree

.token_helpers/set_data_track_test_tokens.bash

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
# eval "$(bash .token_helpers/set_data_track_test_tokens.bash)"
2222
#
2323
# Exports:
24+
# LIVEKIT_ROOM
2425
# LIVEKIT_TOKEN_A
2526
# LIVEKIT_TOKEN_B
2627
# LIVEKIT_URL=ws://localhost:7880
@@ -107,12 +108,14 @@ LIVEKIT_TOKEN_A="$(_create_token "$LIVEKIT_IDENTITY_A")"
107108
LIVEKIT_TOKEN_B="$(_create_token "$LIVEKIT_IDENTITY_B")"
108109

109110
_apply() {
111+
export LIVEKIT_ROOM
110112
export LIVEKIT_TOKEN_A
111113
export LIVEKIT_TOKEN_B
112114
export LIVEKIT_URL
113115
}
114116

115117
_emit_eval() {
118+
printf 'export LIVEKIT_ROOM=%q\n' "$LIVEKIT_ROOM"
116119
printf 'export LIVEKIT_TOKEN_A=%q\n' "$LIVEKIT_TOKEN_A"
117120
printf 'export LIVEKIT_TOKEN_B=%q\n' "$LIVEKIT_TOKEN_B"
118121
printf 'export LIVEKIT_URL=%q\n' "$LIVEKIT_URL"

src/tests/integration/test_room.cpp

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <atomic>
2222
#include <chrono>
2323
#include <condition_variable>
24+
#include <cstdlib>
2425
#include <future>
2526
#include <memory>
2627
#include <mutex>
@@ -139,12 +140,30 @@ namespace {
139140
class DisconnectTrackingDelegate : public RoomDelegate {
140141
public:
141142
void onDisconnected(Room&, const DisconnectedEvent& ev) override {
142-
++count;
143-
last_reason = ev.reason;
143+
{
144+
const std::scoped_lock<std::mutex> lock(mutex_);
145+
last_reason_ = ev.reason;
146+
}
147+
count.fetch_add(1);
148+
cv_.notify_all();
149+
}
150+
151+
bool waitForDisconnect(std::chrono::milliseconds timeout) {
152+
std::unique_lock<std::mutex> lock(mutex_);
153+
return cv_.wait_for(lock, timeout, [this]() { return count.load() > 0; });
154+
}
155+
156+
DisconnectReason lastReason() const {
157+
const std::scoped_lock<std::mutex> lock(mutex_);
158+
return last_reason_;
144159
}
145160

146161
std::atomic<int> count{0};
147-
DisconnectReason last_reason = DisconnectReason::Unknown;
162+
163+
private:
164+
mutable std::mutex mutex_;
165+
std::condition_variable cv_;
166+
DisconnectReason last_reason_ = DisconnectReason::Unknown;
148167
};
149168

150169
class TokenRefreshTrackingDelegate : public RoomDelegate {
@@ -221,7 +240,7 @@ TEST_F(RoomTest, UserDisconnect) {
221240
EXPECT_EQ(room.connectionState(), ConnectionState::Disconnected);
222241
EXPECT_EQ(room.localParticipant().lock(), nullptr) << "local participant should be cleared after disconnect";
223242
EXPECT_EQ(delegate.count.load(), 1) << "onDisconnected should fire exactly once";
224-
EXPECT_EQ(delegate.last_reason, DisconnectReason::ClientInitiated);
243+
EXPECT_EQ(delegate.lastReason(), DisconnectReason::ClientInitiated);
225244

226245
// Calling again on an already-disconnected room is a no-op
227246
EXPECT_NO_THROW(room.disconnect()) << "second disconnect should not throw on an already-disconnected room";
@@ -243,7 +262,39 @@ TEST_F(RoomTest, DestructorDisconnect) {
243262
room.reset(); // invokes destructor which calls disconnect()
244263

245264
EXPECT_EQ(delegate.count.load(), 1) << "destructor should fire onDisconnected exactly once";
246-
EXPECT_EQ(delegate.last_reason, DisconnectReason::ClientInitiated);
265+
EXPECT_EQ(delegate.lastReason(), DisconnectReason::ClientInitiated);
266+
}
267+
268+
// Case: server deletes the room while the client is connected.
269+
TEST_F(RoomTest, ServerDeletedRoomDisconnectsAndTearsDownLocally) {
270+
ASSERT_TRUE(server_available_) << "LIVEKIT_URL and LIVEKIT_TOKEN_A not set";
271+
if (server_url_ != kLocalTestLiveKitUrl) {
272+
GTEST_SKIP() << "server-delete integration test requires local livekit-server";
273+
}
274+
const char* room_name = std::getenv("LIVEKIT_ROOM");
275+
ASSERT_NE(room_name, nullptr) << "LIVEKIT_ROOM not set";
276+
ASSERT_NE(std::string(room_name), "") << "LIVEKIT_ROOM must be non-empty";
277+
278+
Room room;
279+
DisconnectTrackingDelegate delegate;
280+
room.setDelegate(&delegate);
281+
282+
RoomOptions options;
283+
ASSERT_TRUE(room.connect(server_url_, token_, options)) << "connect failed";
284+
ASSERT_EQ(room.connectionState(), ConnectionState::Connected);
285+
ASSERT_NE(room.localParticipant().lock(), nullptr);
286+
287+
const std::string delete_command = std::string("lk --dev room delete --yes ") + room_name;
288+
ASSERT_EQ(std::system(delete_command.c_str()), 0) << "failed to delete local test room";
289+
290+
ASSERT_TRUE(delegate.waitForDisconnect(10s)) << "server room deletion should disconnect the client";
291+
EXPECT_EQ(room.connectionState(), ConnectionState::Disconnected);
292+
EXPECT_EQ(room.localParticipant().lock(), nullptr) << "local participant should be cleared after server disconnect";
293+
EXPECT_EQ(delegate.count.load(), 1) << "onDisconnected should fire exactly once";
294+
EXPECT_EQ(delegate.lastReason(), DisconnectReason::RoomDeleted);
295+
296+
EXPECT_FALSE(room.disconnect()) << "disconnect after server teardown should be a no-op";
297+
EXPECT_EQ(delegate.count.load(), 1) << "delegate must not double-fire";
247298
}
248299

249300
// Verifies that participant handles handed out by Room expire once the Room is

0 commit comments

Comments
 (0)