Skip to content
This repository was archived by the owner on Feb 7, 2024. It is now read-only.

Commit 38b2e4d

Browse files
authored
Merge pull request #450 from beyondcode/refactor/tests
[2.x] Test Refactoring
2 parents d76d7bb + 942f492 commit 38b2e4d

27 files changed

+871
-212
lines changed

.github/workflows/run-tests.yml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ jobs:
2424
- name: Checkout code
2525
uses: actions/checkout@v1
2626

27+
- name: Setup Redis
28+
uses: supercharge/[email protected]
29+
with:
30+
redis-version: 6
31+
if: ${{ matrix.os == 'ubuntu-latest' }}
32+
2733
- name: Cache dependencies
2834
uses: actions/cache@v1
2935
with:
@@ -35,16 +41,25 @@ jobs:
3541
with:
3642
php-version: ${{ matrix.php }}
3743
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick
38-
coverage: pcov
44+
coverage: xdebug
3945

4046
- name: Install dependencies
4147
run: |
4248
composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
4349
composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
4450
45-
- name: Execute tests
46-
run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml
51+
- name: Execute tests with Local driver
52+
run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage_local.xml
53+
env:
54+
REPLICATION_DRIVER: local
55+
56+
- name: Execute tests with Redis driver
57+
run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage_redis.xml
58+
if: ${{ matrix.os == 'ubuntu-latest' }}
59+
env:
60+
REPLICATION_DRIVER: redis
4761

4862
- uses: codecov/codecov-action@v1
4963
with:
5064
fail_ci_if_error: false
65+
file: '*.xml'

config/websockets.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,23 +143,21 @@
143143

144144
/*
145145
|--------------------------------------------------------------------------
146-
| Broadcasting Replication
146+
| Broadcasting Replication PubSub
147147
|--------------------------------------------------------------------------
148148
|
149149
| You can enable replication to publish and subscribe to
150150
| messages across the driver.
151-
|
152-
| By default, it is disabled, but you can configure it to use drivers
151+
152+
| By default, it is set to 'local', but you can configure it to use drivers
153153
| like Redis to ensure connection between multiple instances of
154-
| WebSocket servers.
154+
| WebSocket servers. Just set the driver to 'redis' to enable the PubSub using Redis.
155155
|
156156
*/
157157

158158
'replication' => [
159159

160-
'enabled' => false,
161-
162-
'driver' => 'redis',
160+
'driver' => 'local',
163161

164162
'redis' => [
165163

resources/views/dashboard.blade.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,14 @@
7070
<thead>
7171
<tr>
7272
<th>Type</th>
73-
<th>Socket</th>
7473
<th>Details</th>
7574
<th>Time</th>
7675
</tr>
7776
</thead>
7877
<tbody>
7978
<tr v-for="log in logs.slice().reverse()">
8079
<td><span class="badge" :class="getBadgeClass(log)">@{{ log.type }}</span></td>
81-
<td>@{{ log.socketId }}</td>
82-
<td>@{{ log.details }}</td>
80+
<td><pre>@{{ log.details }}</pre></td>
8381
<td>@{{ log.time }}</td>
8482
</tr>
8583
</tbody>
@@ -207,6 +205,8 @@
207205
'subscribed',
208206
'client-message',
209207
'api-message',
208+
'replicator-subscribed',
209+
'replicator-unsubscribed',
210210
].forEach(channelName => this.subscribeToChannel(channelName))
211211
},
212212

src/Console/StartWebSocketServer.php

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use BeyondCode\LaravelWebSockets\Facades\StatisticsLogger;
66
use BeyondCode\LaravelWebSockets\Facades\WebSocketsRouter;
7+
use BeyondCode\LaravelWebSockets\PubSub\Drivers\LocalClient;
8+
use BeyondCode\LaravelWebSockets\PubSub\Drivers\RedisClient;
79
use BeyondCode\LaravelWebSockets\PubSub\ReplicationInterface;
810
use BeyondCode\LaravelWebSockets\Server\Logger\ConnectionLogger;
911
use BeyondCode\LaravelWebSockets\Server\Logger\HttpLogger;
@@ -23,7 +25,12 @@
2325

2426
class StartWebSocketServer extends Command
2527
{
26-
protected $signature = 'websockets:serve {--host=0.0.0.0} {--port=6001} {--debug : Forces the loggers to be enabled and thereby overriding the app.debug config setting } ';
28+
protected $signature = 'websockets:serve
29+
{--host=0.0.0.0}
30+
{--port=6001}
31+
{--debug : Forces the loggers to be enabled and thereby overriding the APP_DEBUG setting.}
32+
{--test : Prepare the server, but do not start it.}
33+
';
2734

2835
protected $description = 'Start the Laravel WebSocket Server';
2936

@@ -48,6 +55,7 @@ public function handle()
4855
->configureMessageLogger()
4956
->configureConnectionLogger()
5057
->configureRestartTimer()
58+
->configurePubSub()
5159
->registerEchoRoutes()
5260
->registerCustomRoutes()
5361
->configurePubSubReplication()
@@ -66,7 +74,10 @@ protected function configureStatisticsLogger()
6674
$this->laravel->singleton(StatisticsLoggerInterface::class, function () use ($browser) {
6775
$class = config('websockets.statistics.logger', \BeyondCode\LaravelWebSockets\Statistics\Logger\HttpStatisticsLogger::class);
6876

69-
return new $class(app(ChannelManager::class), $browser);
77+
return new $class(
78+
$this->laravel->make(ChannelManager::class),
79+
$browser
80+
);
7081
});
7182

7283
$this->loop->addPeriodicTimer(config('websockets.statistics.interval_in_seconds'), function () {
@@ -122,6 +133,28 @@ public function configureRestartTimer()
122133
return $this;
123134
}
124135

136+
/**
137+
* Configure the replicators.
138+
*
139+
* @return void
140+
*/
141+
public function configurePubSub()
142+
{
143+
if (config('websockets.replication.driver', 'local') === 'local') {
144+
$this->laravel->singleton(ReplicationInterface::class, function () {
145+
return new LocalClient;
146+
});
147+
}
148+
149+
if (config('websockets.replication.driver', 'local') === 'redis') {
150+
$this->laravel->singleton(ReplicationInterface::class, function () {
151+
return (new RedisClient)->boot($this->loop);
152+
});
153+
}
154+
155+
return $this;
156+
}
157+
125158
protected function registerEchoRoutes()
126159
{
127160
WebSocketsRouter::echo();
@@ -142,20 +175,25 @@ protected function startWebSocketServer()
142175

143176
$routes = WebSocketsRouter::getRoutes();
144177

145-
/* 🛰 Start the server 🛰 */
146-
(new WebSocketServerFactory())
178+
$server = (new WebSocketServerFactory())
147179
->setLoop($this->loop)
148180
->useRoutes($routes)
149181
->setHost($this->option('host'))
150182
->setPort($this->option('port'))
151183
->setConsoleOutput($this->output)
152-
->createServer()
153-
->run();
184+
->createServer();
185+
186+
if (! $this->option('test')) {
187+
/* 🛰 Start the server 🛰 */
188+
$server->run();
189+
}
154190
}
155191

156192
protected function configurePubSubReplication()
157193
{
158-
$this->laravel->get(ReplicationInterface::class)->boot($this->loop);
194+
$this->laravel
195+
->get(ReplicationInterface::class)
196+
->boot($this->loop);
159197

160198
return $this;
161199
}

src/Dashboard/DashboardLogger.php

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,68 +9,116 @@
99
class DashboardLogger
1010
{
1111
const LOG_CHANNEL_PREFIX = 'private-websockets-dashboard-';
12+
1213
const TYPE_DISCONNECTION = 'disconnection';
14+
1315
const TYPE_CONNECTION = 'connection';
16+
1417
const TYPE_VACATED = 'vacated';
18+
1519
const TYPE_OCCUPIED = 'occupied';
20+
1621
const TYPE_SUBSCRIBED = 'subscribed';
22+
1723
const TYPE_CLIENT_MESSAGE = 'client-message';
24+
1825
const TYPE_API_MESSAGE = 'api-message';
1926

27+
const TYPE_REPLICATOR_SUBSCRIBED = 'replicator-subscribed';
28+
29+
const TYPE_REPLICATOR_UNSUBSCRIBED = 'replicator-unsubscribed';
30+
2031
public static function connection(ConnectionInterface $connection)
2132
{
2233
/** @var \GuzzleHttp\Psr7\Request $request */
2334
$request = $connection->httpRequest;
2435

2536
static::log($connection->app->id, static::TYPE_CONNECTION, [
26-
'details' => "Origin: {$request->getUri()->getScheme()}://{$request->getUri()->getHost()}",
27-
'socketId' => $connection->socketId,
37+
'details' => [
38+
'origin' => "{$request->getUri()->getScheme()}://{$request->getUri()->getHost()}",
39+
'socketId' => $connection->socketId,
40+
],
2841
]);
2942
}
3043

3144
public static function occupied(ConnectionInterface $connection, string $channelName)
3245
{
3346
static::log($connection->app->id, static::TYPE_OCCUPIED, [
34-
'details' => "Channel: {$channelName}",
47+
'details' => [
48+
'channel' => $channelName,
49+
],
3550
]);
3651
}
3752

3853
public static function subscribed(ConnectionInterface $connection, string $channelName)
3954
{
4055
static::log($connection->app->id, static::TYPE_SUBSCRIBED, [
41-
'socketId' => $connection->socketId,
42-
'details' => "Channel: {$channelName}",
56+
'details' => [
57+
'socketId' => $connection->socketId,
58+
'channel' => $channelName,
59+
],
4360
]);
4461
}
4562

4663
public static function clientMessage(ConnectionInterface $connection, stdClass $payload)
4764
{
4865
static::log($connection->app->id, static::TYPE_CLIENT_MESSAGE, [
49-
'details' => "Channel: {$payload->channel}, Event: {$payload->event}",
50-
'socketId' => $connection->socketId,
51-
'data' => json_encode($payload),
66+
'details' => [
67+
'socketId' => $connection->socketId,
68+
'channel' => $payload->channel,
69+
'event' => $payload->event,
70+
'data' => $payload,
71+
],
5272
]);
5373
}
5474

5575
public static function disconnection(ConnectionInterface $connection)
5676
{
5777
static::log($connection->app->id, static::TYPE_DISCONNECTION, [
58-
'socketId' => $connection->socketId,
78+
'details' => [
79+
'socketId' => $connection->socketId,
80+
],
5981
]);
6082
}
6183

6284
public static function vacated(ConnectionInterface $connection, string $channelName)
6385
{
6486
static::log($connection->app->id, static::TYPE_VACATED, [
65-
'details' => "Channel: {$channelName}",
87+
'details' => [
88+
'socketId' => $connection->socketId,
89+
'channel' => $channelName,
90+
],
6691
]);
6792
}
6893

6994
public static function apiMessage($appId, string $channel, string $event, string $payload)
7095
{
7196
static::log($appId, static::TYPE_API_MESSAGE, [
72-
'details' => "Channel: {$channel}, Event: {$event}",
73-
'data' => $payload,
97+
'details' => [
98+
'channel' => $connection,
99+
'event' => $event,
100+
'payload' => $payload,
101+
],
102+
]);
103+
}
104+
105+
public static function replicatorSubscribed(string $appId, string $channel, string $serverId)
106+
{
107+
static::log($appId, static::TYPE_REPLICATOR_SUBSCRIBED, [
108+
'details' => [
109+
'serverId' => $serverId,
110+
'channel' => $channel,
111+
],
112+
]);
113+
}
114+
115+
public static function replicatorUnsubscribed(string $appId, string $channel, string $serverId)
116+
{
117+
static::log($appId, static::TYPE_REPLICATOR_UNSUBSCRIBED, [
118+
'details' => [
119+
'serverId' => $serverId,
120+
'channel' => $channel,
121+
],
74122
]);
75123
}
76124

src/HttpApi/Controllers/FetchChannelsController.php

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,19 @@
88
use Illuminate\Http\Request;
99
use Illuminate\Support\Collection;
1010
use Illuminate\Support\Str;
11+
use stdClass;
1112
use Symfony\Component\HttpKernel\Exception\HttpException;
1213

1314
class FetchChannelsController extends Controller
1415
{
1516
/** @var ReplicationInterface */
16-
protected $replication;
17+
protected $replicator;
1718

18-
public function __construct(ChannelManager $channelManager, ReplicationInterface $replication)
19+
public function __construct(ChannelManager $channelManager, ReplicationInterface $replicator)
1920
{
2021
parent::__construct($channelManager);
2122

22-
$this->replication = $replication;
23+
$this->replicator = $replicator;
2324
}
2425

2526
public function __invoke(Request $request)
@@ -51,18 +52,21 @@ public function __invoke(Request $request)
5152

5253
// We ask the replication backend to get us the member count per channel.
5354
// We get $counts back as a key-value array of channel names and their member count.
54-
return $this->replication
55+
return $this->replicator
5556
->channelMemberCounts($request->appId, $channelNames)
5657
->then(function (array $counts) use ($channels, $attributes) {
57-
return [
58-
'channels' => $channels->map(function (PresenceChannel $channel) use ($counts, $attributes) {
59-
$info = new \stdClass;
60-
if (in_array('user_count', $attributes)) {
61-
$info->user_count = $counts[$channel->getChannelName()];
62-
}
58+
$channels = $channels->map(function (PresenceChannel $channel) use ($counts, $attributes) {
59+
$info = new stdClass;
60+
61+
if (in_array('user_count', $attributes)) {
62+
$info->user_count = $counts[$channel->getChannelName()];
63+
}
6364

64-
return $info;
65-
})->toArray() ?: new \stdClass,
65+
return $info;
66+
})->toArray();
67+
68+
return [
69+
'channels' => $channels ?: new stdClass,
6670
];
6771
});
6872
}

0 commit comments

Comments
 (0)