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
152 changes: 151 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ on:
branches: [ master, main ]
pull_request:
branches: [ master, main ]
workflow_dispatch:

jobs:
tests:
lint:
name: PHP ${{ matrix.php }} - ${{ matrix.stability }}
runs-on: ubuntu-latest
strategy:
Expand All @@ -27,5 +28,154 @@ jobs:
tools: composer:v2, parallel-lint
coverage: none

- name: Install dependencies
run: composer install --prefer-dist --no-interaction --no-progress --no-suggest

- name: Lint PHP files
run: parallel-lint --show-deprecated --exclude src/proto src/ tests/

tests:
name: Run tests
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
tools: composer:v2
coverage: none

- name: Install dependencies
run: composer install --prefer-dist --no-interaction --no-progress --no-suggest

- name: Install jq and livekit-cli
run: |
sudo apt-get update && sudo apt-get install -y jq
curl -sSL https://get.livekit.io/cli | bash
echo "$HOME/.livekit/bin" >> $GITHUB_PATH

- name: Generate random room name
run: |
ROOM_NAME="testRoom-$(openssl rand -hex 8)"
echo "LIVEKIT_TEST_ROOM=$ROOM_NAME" >> $GITHUB_ENV
echo "Generated test room name: $ROOM_NAME"

- name: Create test room
env:
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
run: |
if [ -z "$LIVEKIT_URL" ] || [ -z "$LIVEKIT_API_KEY" ] || [ -z "$LIVEKIT_API_SECRET" ]; then
echo "::warning::LiveKit secrets not configured. Tests will be skipped."
exit 0
fi
lk room create ${{ env.LIVEKIT_TEST_ROOM }} || true

- name: Start load test
env:
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
run: |
if [ -z "$LIVEKIT_URL" ] || [ -z "$LIVEKIT_API_KEY" ] || [ -z "$LIVEKIT_API_SECRET" ]; then
exit 0
fi
lk load-test --room ${{ env.LIVEKIT_TEST_ROOM }} --video-publishers 3 --audio-publishers 5 > /tmp/loadtest.log 2>&1 &
echo $! > /tmp/loadtest.pid
sleep 5
echo "Load test started with PID $(cat /tmp/loadtest.pid)"

- name: Start RTMP test server
run: |
docker run -d --name rtmp-server -p 1935:1935 tiangolo/nginx-rtmp
sleep 5
# Verify RTMP server is running
docker ps | grep rtmp-server || (echo "RTMP server failed to start" && exit 1)

- name: Install bore (TCP tunnel)
run: |
curl -L https://github.com/ekzhang/bore/releases/download/v0.5.0/bore-v0.5.0-x86_64-unknown-linux-musl.tar.gz -o bore.tar.gz
tar -xzf bore.tar.gz
chmod +x bore
sudo mv bore /usr/local/bin/

- name: Start TCP tunnel for RTMP
run: |
bore local 1935 --to bore.pub > /tmp/bore.log 2>&1 &
BORE_PID=$!
sleep 5
# Extract public URL from bore output (format: Listening on bore.pub:port)
BORE_PORT=$(grep -oE 'bore\.pub:[0-9]+' /tmp/bore.log | head -1 | cut -d: -f2)
if [ -z "$BORE_PORT" ]; then
# Try alternative format: "Listening on bore.pub:12345"
BORE_PORT=$(grep -oE 'Listening on bore\.pub:[0-9]+' /tmp/bore.log | head -1 | cut -d: -f2)
fi
if [ -z "$BORE_PORT" ]; then
echo "Failed to extract bore tunnel port. Log:"
cat /tmp/bore.log
exit 1
fi
# Verify tunnel is working by checking if process is still running
if ! ps -p $BORE_PID > /dev/null 2>&1; then
echo "Bore tunnel process died. Log:"
cat /tmp/bore.log
exit 1
fi
# Generate short unique ID for RTMP stream keys (4 hex chars = 65536 combinations)
RTMP_ID=$(openssl rand -hex 2)
BORE_RTMP="rtmp://bore.pub:$BORE_PORT"
echo "RTMP_URL=$BORE_RTMP/live/test$RTMP_ID" >> $GITHUB_ENV
echo "RTMP_URL2=$BORE_RTMP/live/test2$RTMP_ID" >> $GITHUB_ENV
echo "Public RTMP URL: $BORE_RTMP"
echo "RTMP stream paths: /live/test$RTMP_ID and /live/test2$RTMP_ID"
echo "Bore PID: $BORE_PID"
echo "Waiting additional 5 seconds for tunnel to stabilize..."
sleep 5
cat /tmp/bore.log

- name: Run tests
env:
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
LIVEKIT_EGRESS_RTMP_URL: ${{ env.RTMP_URL || secrets.LIVEKIT_EGRESS_RTMP_URL }}
LIVEKIT_EGRESS_RTMP_URL2: ${{ env.RTMP_URL2 || secrets.LIVEKIT_EGRESS_RTMP_URL2 }}
run: |
if [ -z "$LIVEKIT_URL" ] || [ -z "$LIVEKIT_API_KEY" ] || [ -z "$LIVEKIT_API_SECRET" ]; then
echo "::warning::LiveKit secrets not configured. Tests will be skipped."
echo "Please set LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET in repository secrets."
exit 0
fi
vendor/bin/phpunit --testdox --configuration phpunit.xml

- name: Stop load test and cleanup
if: always()
env:
LIVEKIT_URL: ${{ secrets.LIVEKIT_URL }}
LIVEKIT_API_KEY: ${{ secrets.LIVEKIT_API_KEY }}
LIVEKIT_API_SECRET: ${{ secrets.LIVEKIT_API_SECRET }}
LIVEKIT_TEST_ROOM: ${{ env.LIVEKIT_TEST_ROOM }}
run: |
if [ -z "$LIVEKIT_URL" ] || [ -z "$LIVEKIT_API_KEY" ] || [ -z "$LIVEKIT_API_SECRET" ]; then
exit 0
fi
# Stop load test if it's still running
if [ -f /tmp/loadtest.pid ]; then
LOADTEST_PID=$(cat /tmp/loadtest.pid)
if ps -p $LOADTEST_PID > /dev/null 2>&1; then
echo "Stopping load test (PID: $LOADTEST_PID)"
kill $LOADTEST_PID || true
sleep 2
# Force kill if still running
kill -9 $LOADTEST_PID 2>/dev/null || true
fi
fi
# Delete test room
if [ -n "$LIVEKIT_TEST_ROOM" ]; then
echo "Deleting test room $LIVEKIT_TEST_ROOM"
lk room delete "$LIVEKIT_TEST_ROOM" || true
fi
105 changes: 103 additions & 2 deletions .lando.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,105 @@ services:
image: php:8.1-apache
command: docker-php-entrypoint apache2-foreground
build_as_root:
- apt-get update && apt-get install -y jq
- apt-get update && apt-get install -y jq curl socat
- curl -sSL https://get.livekit.io/cli | bash
- curl -L https://github.com/ekzhang/bore/releases/download/v0.5.0/bore-v0.5.0-x86_64-unknown-linux-musl.tar.gz -o /tmp/bore.tar.gz
- tar -xzf /tmp/bore.tar.gz -C /usr/local/bin/ && chmod +x /usr/local/bin/bore && rm /tmp/bore.tar.gz
overrides:
environment:
# Support debugging CLI with Xdebug.
PHP_IDE_CONFIG: "serverName=appserver"
XDEBUG_SESSION_START: lando
XDEBUG_CONFIG: "client_host=host.docker.internal"
rtmp:
type: compose
services:
image: tiangolo/nginx-rtmp
command: nginx -g "daemon off;"
ports:
- "1935:1935"
tooling:
test:
service: appserver
description: Run tests with RTMP tunnel setup
cmd:
- vendor/bin/phpunit --testdox
- |
# Generate random room name if not set
if [ -z "$LIVEKIT_TEST_ROOM" ]; then
export LIVEKIT_TEST_ROOM="testRoom-$(openssl rand -hex 8)"
echo "Generated test room name: $LIVEKIT_TEST_ROOM"
fi

# Set up RTMP URLs: use env vars if set, otherwise fall back to bore tunnel
if [ -n "$LIVEKIT_EGRESS_RTMP_URL" ]; then
echo "Using RTMP URLs from environment:"
echo " $LIVEKIT_EGRESS_RTMP_URL"
echo " $LIVEKIT_EGRESS_RTMP_URL2"
else
echo "Starting RTMP tunnel via bore..."
bore local 1935 --local-host rtmp --to bore.pub > /tmp/bore.log 2>&1 &
BORE_PID=$!
sleep 10

BORE_PORT=$(grep -oE 'bore\.pub:[0-9]+' /tmp/bore.log | head -1 | cut -d: -f2)
if [ -z "$BORE_PORT" ]; then
BORE_PORT=$(grep -oE 'Listening on bore\.pub:[0-9]+' /tmp/bore.log | head -1 | cut -d: -f2)
fi

if [ -n "$BORE_PORT" ] && ps -p $BORE_PID > /dev/null 2>&1; then
RTMP_ID=$(openssl rand -hex 2)
export LIVEKIT_EGRESS_RTMP_URL="rtmp://bore.pub:$BORE_PORT/live/test$RTMP_ID"
export LIVEKIT_EGRESS_RTMP_URL2="rtmp://bore.pub:$BORE_PORT/live/test2$RTMP_ID"
echo "Public RTMP URLs:"
echo " $LIVEKIT_EGRESS_RTMP_URL"
echo " $LIVEKIT_EGRESS_RTMP_URL2"
else
echo "Warning: Bore tunnel failed. Check /tmp/bore.log"
cat /tmp/bore.log
fi
fi

# Create test room if LiveKit credentials are available
if [ -n "$LIVEKIT_URL" ] && [ -n "$LIVEKIT_API_KEY" ] && [ -n "$LIVEKIT_API_SECRET" ]; then
echo "Creating test room: $LIVEKIT_TEST_ROOM"
lk room create "$LIVEKIT_TEST_ROOM" || true

# Start load test in background
echo "Starting load test..."
lk load-test --room "$LIVEKIT_TEST_ROOM" --video-publishers 3 --audio-publishers 5 > /tmp/loadtest.log 2>&1 &
LOADTEST_PID=$!
echo $LOADTEST_PID > /tmp/loadtest.pid
echo "Load test started with PID: $LOADTEST_PID"
sleep 5
fi

# Run tests
vendor/bin/phpunit --testdox --configuration phpunit.xml
TEST_EXIT_CODE=$?

# Cleanup
if [ -f /tmp/loadtest.pid ]; then
LOADTEST_PID=$(cat /tmp/loadtest.pid)
if ps -p $LOADTEST_PID > /dev/null 2>&1; then
echo "Stopping load test..."
kill $LOADTEST_PID 2>/dev/null || true
sleep 2
kill -9 $LOADTEST_PID 2>/dev/null || true
fi
fi

if [ -n "$LIVEKIT_TEST_ROOM" ] && [ -n "$LIVEKIT_URL" ]; then
echo "Deleting test room: $LIVEKIT_TEST_ROOM"
lk room delete "$LIVEKIT_TEST_ROOM" || true
fi

# Cleanup bore tunnel
if [ -n "$BORE_PID" ]; then
echo "Stopping bore tunnel (PID: $BORE_PID)"
kill $BORE_PID 2>/dev/null || true
fi

exit $TEST_EXIT_CODE
xdebug-on:
service: appserver
description: Enable Xdebug.
Expand Down Expand Up @@ -51,3 +138,17 @@ tooling:
service: appserver
cmd:
- lk load-test --room testRoomParticipants --video-publishers 3 --audio-publishers 5
rtmp-tunnel:
service: appserver
description: Start RTMP tunnel with bore
cmd:
- |
bore local 1935 --to bore.pub
rtmp-tunnel-bg:
service: appserver
description: Start RTMP tunnel in background
cmd:
- |
bore local 1935 --to bore.pub > /tmp/bore.log 2>&1 &
echo "Bore tunnel started. PID: $!"
echo "Check /tmp/bore.log for the public URL"
3 changes: 2 additions & 1 deletion example.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ LIVEKIT_URL=https://{YOUR-PROJECT}.livekit.cloud
LIVEKIT_API_KEY={API_KEY}
LIVEKIT_API_SECRET={API_SECRET}
LIVEKIT_EGRESS_RTMP_URL=rtmp://a.rtmp.youtube.com/live2/{STREAM_KEY}
LIVEKIT_EGRESS_RTMP_URL2=rtmp://live.twitch.tv/app/{STREAM_KEY}
LIVEKIT_EGRESS_RTMP_URL2=rtmp://live.twitch.tv/app/{STREAM_KEY}
LIVEKIT_TEST_ROOM=testRoomParticipants
6 changes: 4 additions & 2 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" colors="true" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.4/phpunit.xsd" cacheDirectory=".phpunit.cache">
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php"
colors="true" stopOnFailure="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd">
<testsuites>
<testsuite name="Livekit Server SDK - Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
</phpunit>
</phpunit>
13 changes: 11 additions & 2 deletions tests/AccessTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,21 @@ class AccessTokenTest extends TestCase {
/**
* The test API key.
*/
protected string $testApiKey = 'abcdefg';
protected string $testApiKey;

/**
* The test API secret.
*/
protected string $testSecret = 'abababa';
protected string $testSecret;

/**
* {@inheritDoc}
*/
public function setUp(): void {
parent::setUp();
$this->testApiKey = base64_encode(random_bytes(64));
$this->testSecret = base64_encode(random_bytes(64));
}

/**
* Test that encoded tokens are valid and can be decoded.
Expand Down
Loading
Loading