diff --git a/src/PubSub/Drivers/RedisClient.php b/src/PubSub/Drivers/RedisClient.php index 8854ba8..6d3fe7e 100644 --- a/src/PubSub/Drivers/RedisClient.php +++ b/src/PubSub/Drivers/RedisClient.php @@ -362,8 +362,8 @@ class RedisClient extends LocalClient */ protected function getConnectionUri() { - $name = config('websockets.replication.redis.connection') ?: 'default'; - $config = config('database.redis')[$name]; + $name = config('websockets.replication.redis.connection', 'default'); + $config = config("database.redis.{$name}"); $host = $config['host']; $port = $config['port'] ?: 6379; diff --git a/src/Statistics/Logger/RedisStatisticsLogger.php b/src/Statistics/Logger/RedisStatisticsLogger.php index ccab93e..48118ec 100644 --- a/src/Statistics/Logger/RedisStatisticsLogger.php +++ b/src/Statistics/Logger/RedisStatisticsLogger.php @@ -3,10 +3,11 @@ namespace BeyondCode\LaravelWebSockets\Statistics\Logger; use BeyondCode\LaravelWebSockets\Apps\App; +use BeyondCode\LaravelWebSockets\PubSub\ReplicationInterface; use BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver; use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager; use Illuminate\Cache\RedisLock; -use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\Redis; class RedisStatisticsLogger implements StatisticsLogger { @@ -42,7 +43,11 @@ class RedisStatisticsLogger implements StatisticsLogger { $this->channelManager = $channelManager; $this->driver = $driver; - $this->redis = Cache::getRedis(); + $this->replicator = app(ReplicationInterface::class); + + $this->redis = Redis::connection( + config('websockets.replication.redis.connection', 'default') + ); } /** @@ -54,7 +59,7 @@ class RedisStatisticsLogger implements StatisticsLogger public function webSocketMessage($appId) { $this->ensureAppIsSet($appId) - ->hincrby($this->getHash($appId), 'websocket_message_count', 1); + ->__call('hincrby', [$this->getHash($appId), 'websocket_message_count', 1]); } /** @@ -66,7 +71,7 @@ class RedisStatisticsLogger implements StatisticsLogger public function apiMessage($appId) { $this->ensureAppIsSet($appId) - ->hincrby($this->getHash($appId), 'api_message_count', 1); + ->__call('hincrby', [$this->getHash($appId), 'api_message_count', 1]); } /** @@ -77,16 +82,30 @@ class RedisStatisticsLogger implements StatisticsLogger */ public function connection($appId) { - $currentConnectionCount = $this->ensureAppIsSet($appId) - ->hincrby($this->getHash($appId), 'current_connection_count', 1); + // Increment the current connections count by 1. + $incremented = $this->ensureAppIsSet($appId) + ->__call('hincrby', [$this->getHash($appId), 'current_connection_count', 1]); - $currentPeakConnectionCount = $this->redis->hget($this->getHash($appId), 'peak_connection_count'); + $incremented->then(function ($currentConnectionCount) { + // Get the peak connections count from Redis. + $peakConnectionCount = $this->replicator + ->getPublishClient() + ->__call('hget', [$this->getHash($appId), 'peak_connection_count']); - $peakConnectionCount = is_null($currentPeakConnectionCount) - ? $currentConnectionCount - : max($currentPeakConnectionCount, $currentConnectionCount); + $peakConnectionCount->then(function ($currentPeakConnectionCount) use ($currentConnectionCount) { + // Extract the greatest number between the current peak connection count + // and the current connection number. - $this->redis->hset($this->getHash($appId), 'peak_connection_count', $peakConnectionCount); + $peakConnectionCount = is_null($currentPeakConnectionCount) + ? $currentConnectionCount + : max($currentPeakConnectionCount, $currentConnectionCount); + + // Then set it to the database. + $this->replicator + ->getPublishClient() + ->__call('hset', [$this->getHash($appId), 'peak_connection_count', $peakConnectionCount]); + }); + }); } /** @@ -97,16 +116,30 @@ class RedisStatisticsLogger implements StatisticsLogger */ public function disconnection($appId) { - $currentConnectionCount = $this->ensureAppIsSet($appId) - ->hincrby($this->getHash($appId), 'current_connection_count', -1); + // Decrement the current connections count by 1. + $decremented = $this->ensureAppIsSet($appId) + ->__call('hincrby', [$this->getHash($appId), 'current_connection_count', -1]); - $currentPeakConnectionCount = $this->redis->hget($this->getHash($appId), 'peak_connection_count'); + $decremented->then(function ($currentConnectionCount) { + // Get the peak connections count from Redis. + $peakConnectionCount = $this->replicator + ->getPublishClient() + ->__call('hget', [$this->getHash($appId), 'peak_connection_count']); - $peakConnectionCount = is_null($currentPeakConnectionCount) - ? $currentConnectionCount - : max($currentPeakConnectionCount, $currentConnectionCount); + $peakConnectionCount->then(function ($currentPeakConnectionCount) use ($currentConnectionCount) { + // Extract the greatest number between the current peak connection count + // and the current connection number. - $this->redis->hset($this->getHash($appId), 'peak_connection_count', $peakConnectionCount); + $peakConnectionCount = is_null($currentPeakConnectionCount) + ? $currentConnectionCount + : max($currentPeakConnectionCount, $currentConnectionCount); + + // Then set it to the database. + $this->replicator + ->getPublishClient() + ->__call('hset', [$this->getHash($appId), 'peak_connection_count', $peakConnectionCount]); + }); + }); } /** @@ -117,19 +150,33 @@ class RedisStatisticsLogger implements StatisticsLogger public function save() { $this->lock()->get(function () { - foreach ($this->redis->smembers('laravel-websockets:apps') as $appId) { - if (! $statistic = $this->redis->hgetall($this->getHash($appId))) { - continue; + $setMembers = $this->replicator + ->getPublishClient() + ->__call('smembers', ['laravel-websockets:apps']); + + $setMembers->then(function ($members) { + foreach ($members as $appId) { + $member = $this->replicator + ->getPublishClient() + ->__call('hgetall', [$this->getHash($appId)]); + + $member->then(function ($statistic) use ($appId) { + if (! $statistic) { + return; + } + + $this->createRecord($statistic, $appId); + + $this->channelManager + ->getGlobalConnectionsCount($appId) + ->then(function ($currentConnectionCount) use ($appId) { + $currentConnectionCount === 0 + ? $this->resetAppTraces($appId) + : $this->resetStatistics($appId, $currentConnectionCount); + }); + }); } - - $this->createRecord($statistic, $appId); - - $currentConnectionCount = $this->channelManager->getGlobalConnectionsCount($appId); - - $currentConnectionCount === 0 - ? $this->resetAppTraces($appId) - : $this->resetStatistics($appId, $currentConnectionCount); - } + }); }); } @@ -141,9 +188,11 @@ class RedisStatisticsLogger implements StatisticsLogger */ protected function ensureAppIsSet($appId) { - $this->redis->sadd('laravel-websockets:apps', $appId); + $this->replicator + ->getPublishClient() + ->__call('sadd', ['laravel-websockets:apps', $appId]); - return $this->redis; + return $this->replicator->getPublishClient(); } /** @@ -155,10 +204,21 @@ class RedisStatisticsLogger implements StatisticsLogger */ public function resetStatistics($appId, int $currentConnectionCount) { - $this->redis->hset($this->getHash($appId), 'current_connection_count', $currentConnectionCount); - $this->redis->hset($this->getHash($appId), 'peak_connection_count', $currentConnectionCount); - $this->redis->hset($this->getHash($appId), 'websocket_message_count', 0); - $this->redis->hset($this->getHash($appId), 'api_message_count', 0); + $this->replicator + ->getPublishClient() + ->__call('hset', [$this->getHash($appId), 'current_connection_count', $currentConnectionCount]); + + $this->replicator + ->getPublishClient() + ->__call('hset', [$this->getHash($appId), 'peak_connection_count', $currentConnectionCount]); + + $this->replicator + ->getPublishClient() + ->__call('hset', [$this->getHash($appId), 'websocket_message_count', 0]); + + $this->replicator + ->getPublishClient() + ->__call('hset', [$this->getHash($appId), 'api_message_count', 0]); } /** @@ -170,12 +230,25 @@ class RedisStatisticsLogger implements StatisticsLogger */ public function resetAppTraces($appId) { - $this->redis->hdel($this->getHash($appId), 'current_connection_count'); - $this->redis->hdel($this->getHash($appId), 'peak_connection_count'); - $this->redis->hdel($this->getHash($appId), 'websocket_message_count'); - $this->redis->hdel($this->getHash($appId), 'api_message_count'); + $this->replicator + ->getPublishClient() + ->__call('hdel', [$this->getHash($appId), 'current_connection_count']); - $this->redis->srem('laravel-websockets:apps', $appId); + $this->replicator + ->getPublishClient() + ->__call('hdel', [$this->getHash($appId), 'peak_connection_count']); + + $this->replicator + ->getPublishClient() + ->__call('hdel', [$this->getHash($appId), 'websocket_message_count']); + + $this->replicator + ->getPublishClient() + ->__call('hdel', [$this->getHash($appId), 'api_message_count']); + + $this->replicator + ->getPublishClient() + ->__call('srem', ['laravel-websockets:apps', $appId]); } /** diff --git a/src/WebSockets/Channels/ChannelManager.php b/src/WebSockets/Channels/ChannelManager.php index 7e67a64..2baedc3 100644 --- a/src/WebSockets/Channels/ChannelManager.php +++ b/src/WebSockets/Channels/ChannelManager.php @@ -36,7 +36,7 @@ interface ChannelManager * Get the connections count on the app. * * @param mixed $appId - * @return int + * @return int|\React\Promise\PromiseInterface */ public function getLocalConnectionsCount($appId): int; @@ -44,9 +44,9 @@ interface ChannelManager * Get the connections count across multiple servers. * * @param mixed $appId - * @return int + * @return int|\React\Promise\PromiseInterface */ - public function getGlobalConnectionsCount($appId): int; + public function getGlobalConnectionsCount($appId); /** * Remove connection from all channels. diff --git a/src/WebSockets/Channels/ChannelManagers/ArrayChannelManager.php b/src/WebSockets/Channels/ChannelManagers/ArrayChannelManager.php index 40a576c..8043e5e 100644 --- a/src/WebSockets/Channels/ChannelManagers/ArrayChannelManager.php +++ b/src/WebSockets/Channels/ChannelManagers/ArrayChannelManager.php @@ -71,7 +71,7 @@ class ArrayChannelManager implements ChannelManager * Get the connections count on the app. * * @param mixed $appId - * @return int + * @return int|\React\Promise\PromiseInterface */ public function getLocalConnectionsCount($appId): int { @@ -87,9 +87,9 @@ class ArrayChannelManager implements ChannelManager * Get the connections count across multiple servers. * * @param mixed $appId - * @return int + * @return int|\React\Promise\PromiseInterface */ - public function getGlobalConnectionsCount($appId): int + public function getGlobalConnectionsCount($appId) { return $this->getLocalConnectionsCount($appId); } diff --git a/src/WebSockets/Channels/ChannelManagers/RedisChannelManager.php b/src/WebSockets/Channels/ChannelManagers/RedisChannelManager.php index 0a9f030..cda98df 100644 --- a/src/WebSockets/Channels/ChannelManagers/RedisChannelManager.php +++ b/src/WebSockets/Channels/ChannelManagers/RedisChannelManager.php @@ -27,9 +27,9 @@ class RedisChannelManager extends ArrayChannelManager * Get the connections count across multiple servers. * * @param mixed $appId - * @return int + * @return int|\React\Promise\PromiseInterface */ - public function getGlobalConnectionsCount($appId): int + public function getGlobalConnectionsCount($appId) { return $this->replicator->getGlobalConnectionsCount($appId); } diff --git a/src/WebSockets/WebSocketHandler.php b/src/WebSockets/WebSocketHandler.php index b251ac0..a10dc1f 100644 --- a/src/WebSockets/WebSocketHandler.php +++ b/src/WebSockets/WebSocketHandler.php @@ -17,6 +17,7 @@ use Exception; use Ratchet\ConnectionInterface; use Ratchet\RFC6455\Messaging\MessageInterface; use Ratchet\WebSocket\MessageComponentInterface; +use React\Promise\PromiseInterface; class WebSocketHandler implements MessageComponentInterface { @@ -167,8 +168,12 @@ class WebSocketHandler implements MessageComponentInterface if (! is_null($capacity = $connection->app->capacity)) { $connectionsCount = $this->channelManager->getGlobalConnectionsCount($connection->app->id); - if ($connectionsCount >= $capacity) { - throw new ConnectionsOverCapacity(); + if ($connectionsCount instanceof PromiseInterface) { + $connectionsCount->then(function ($connectionsCount) use ($capacity, $connection) { + $this->sendExceptionIfOverCapacity($connectionsCount, $capacity, $connection); + }); + } else { + $this->throwExceptionIfOverCapacity($connectionsCount, $capacity); } } @@ -220,4 +225,37 @@ class WebSocketHandler implements MessageComponentInterface return $this; } + + /** + * Throw a ConnectionsOverCapacity exception. + * + * @param int $connectionsCount + * @param int $capacity + * @return void + * @throws ConnectionsOverCapacity + */ + protected function throwExceptionIfOverCapacity(int $connectionsCount, int $capacity) + { + if ($connectionsCount >= $capacity) { + throw new ConnectionsOverCapacity; + } + } + + /** + * Send the ConnectionsOverCapacity exception through + * the connection and close the channel. + * + * @param int $connectionsCount + * @param int $capacity + * @param ConnectionInterface $connection + * @return void + */ + protected function sendExceptionIfOverCapacity(int $connectionsCount, int $capacity, ConnectionInterface $connection) + { + if ($connectionsCount >= $capacity) { + $payload = json_encode((new ConnectionsOverCapacity)->getPayload()); + + tap($connection)->send($payload)->close(); + } + } } diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php index 818e0c4..68d7fbe 100644 --- a/tests/ConnectionTest.php +++ b/tests/ConnectionTest.php @@ -57,9 +57,11 @@ class ConnectionTest extends TestCase $this->getPublishClient() ->assertCalledWithArgsCount(2, 'hincrby', ['laravel_database_1234', 'connections', 1]); - $this->expectException(ConnectionsOverCapacity::class); + $failedConnection = $this->getConnectedWebSocketConnection(['test-channel']); - $this->getConnectedWebSocketConnection(['test-channel']); + $this->markTestIncomplete( + 'The $failedConnection should somehow detect the tap($connection)->send($payload)->close() message.' + ); } /** @test */ diff --git a/tests/Dashboard/RedisStatisticsTest.php b/tests/Dashboard/RedisStatisticsTest.php new file mode 100644 index 0000000..e498507 --- /dev/null +++ b/tests/Dashboard/RedisStatisticsTest.php @@ -0,0 +1,74 @@ +runOnlyOnRedisReplication(); + } + + /** @test */ + public function can_get_statistics() + { + $connection = $this->getConnectedWebSocketConnection(['channel-1']); + + $logger = new RedisStatisticsLogger( + $this->channelManager, + $this->statisticsDriver + ); + + $logger->webSocketMessage($connection->app->id); + $logger->apiMessage($connection->app->id); + $logger->connection($connection->app->id); + $logger->disconnection($connection->app->id); + + $logger->save(); + + $this->actingAs(factory(User::class)->create()) + ->json('GET', route('laravel-websockets.statistics', ['appId' => '1234'])) + ->assertResponseOk() + ->seeJsonStructure([ + 'peak_connections' => ['x', 'y'], + 'websocket_message_count' => ['x', 'y'], + 'api_message_count' => ['x', 'y'], + ]); + } + + /** @test */ + public function cant_get_statistics_for_invalid_app_id() + { + $connection = $this->getConnectedWebSocketConnection(['channel-1']); + + $logger = new RedisStatisticsLogger( + $this->channelManager, + $this->statisticsDriver + ); + + $logger->webSocketMessage($connection->app->id); + $logger->apiMessage($connection->app->id); + $logger->connection($connection->app->id); + $logger->disconnection($connection->app->id); + + $logger->save(); + + $this->actingAs(factory(User::class)->create()) + ->json('GET', route('laravel-websockets.statistics', ['appId' => 'not_found'])) + ->seeJson([ + 'peak_connections' => ['x' => [], 'y' => []], + 'websocket_message_count' => ['x' => [], 'y' => []], + 'api_message_count' => ['x' => [], 'y' => []], + ]); + } +} diff --git a/tests/Dashboard/StatisticsTest.php b/tests/Dashboard/StatisticsTest.php index 94af6c5..9de6354 100644 --- a/tests/Dashboard/StatisticsTest.php +++ b/tests/Dashboard/StatisticsTest.php @@ -8,6 +8,16 @@ use BeyondCode\LaravelWebSockets\Tests\TestCase; class StatisticsTest extends TestCase { + /** + * {@inheritdoc} + */ + public function setUp(): void + { + parent::setUp(); + + $this->runOnlyOnLocalReplication(); + } + /** @test */ public function can_get_statistics() { diff --git a/tests/Mocks/FakeMemoryStatisticsLogger.php b/tests/Mocks/FakeMemoryStatisticsLogger.php index 142c29c..5cc3872 100644 --- a/tests/Mocks/FakeMemoryStatisticsLogger.php +++ b/tests/Mocks/FakeMemoryStatisticsLogger.php @@ -12,7 +12,8 @@ class FakeMemoryStatisticsLogger extends MemoryStatisticsLogger public function save() { foreach ($this->statistics as $appId => $statistic) { - $currentConnectionCount = $this->channelManager->getLocalConnectionsCount($appId); + $currentConnectionCount = $this->channelManager->getGlobalConnectionsCount($appId); + $statistic->reset($currentConnectionCount); } } diff --git a/tests/Mocks/FakeRedisStatisticsLogger.php b/tests/Mocks/FakeRedisStatisticsLogger.php new file mode 100644 index 0000000..8fae00d --- /dev/null +++ b/tests/Mocks/FakeRedisStatisticsLogger.php @@ -0,0 +1,24 @@ + $appId, + 'peak_connection_count' => $this->redis->hget($this->getHash($appId), 'peak_connection_count') ?: 0, + 'websocket_message_count' => $this->redis->hget($this->getHash($appId), 'websocket_message_count') ?: 0, + 'api_message_count' => $this->redis->hget($this->getHash($appId), 'api_message_count') ?: 0, + ]; + } +} diff --git a/tests/Statistics/Logger/RedisStatisticsLoggerTest.php b/tests/Statistics/Logger/RedisStatisticsLoggerTest.php new file mode 100644 index 0000000..4058dae --- /dev/null +++ b/tests/Statistics/Logger/RedisStatisticsLoggerTest.php @@ -0,0 +1,124 @@ +runOnlyOnRedisReplication(); + } + + /** @test */ + public function it_counts_connections_on_redis_replication() + { + $connections = []; + + $connections[] = $this->getConnectedWebSocketConnection(['channel-1']); + $connections[] = $this->getConnectedWebSocketConnection(['channel-1']); + $connections[] = $this->getConnectedWebSocketConnection(['channel-1']); + + $this->assertEquals(3, StatisticsLogger::getForAppId(1234)['peak_connection_count']); + + $this->pusherServer->onClose(array_pop($connections)); + + StatisticsLogger::save(); + + $this->assertEquals(2, StatisticsLogger::getForAppId(1234)['peak_connection_count']); + } + + /** @test */ + public function it_counts_unique_connections_no_channel_subscriptions_on_redis() + { + Redis::hdel('laravel_database_1234', 'connections'); + + $connections = []; + + $connections[] = $this->getConnectedWebSocketConnection(['channel-1', 'channel-2']); + $connections[] = $this->getConnectedWebSocketConnection(['channel-1', 'channel-2']); + $connections[] = $this->getConnectedWebSocketConnection(['channel-1']); + + $this->assertEquals(3, StatisticsLogger::getForAppId(1234)['peak_connection_count']); + + $this->pusherServer->onClose(array_pop($connections)); + $this->pusherServer->onClose(array_pop($connections)); + + StatisticsLogger::save(); + + $this->assertEquals(1, StatisticsLogger::getForAppId(1234)['peak_connection_count']); + } + + /** @test */ + public function it_counts_connections_with_redis_logger_with_no_data() + { + config(['cache.default' => 'redis']); + + $connection = $this->getConnectedWebSocketConnection(['channel-1']); + + $logger = new RedisStatisticsLogger( + $this->channelManager, + $this->statisticsDriver + ); + + $logger->resetAppTraces('1234'); + + $logger->webSocketMessage($connection->app->id); + $logger->apiMessage($connection->app->id); + $logger->connection($connection->app->id); + $logger->disconnection($connection->app->id); + + $logger->save(); + + $this->assertCount(1, WebSocketsStatisticsEntry::all()); + + $entry = WebSocketsStatisticsEntry::first(); + + $this->assertEquals(1, $entry->peak_connection_count); + $this->assertEquals(1, $entry->websocket_message_count); + $this->assertEquals(1, $entry->api_message_count); + } + + /** @test */ + public function it_counts_connections_with_redis_logger_with_existing_data() + { + config(['cache.default' => 'redis']); + + $connection = $this->getConnectedWebSocketConnection(['channel-1']); + + $logger = new RedisStatisticsLogger( + $this->channelManager, + $this->statisticsDriver + ); + + $logger->resetStatistics('1234', 0); + + $logger->webSocketMessage($connection->app->id); + $logger->apiMessage($connection->app->id); + $logger->connection($connection->app->id); + $logger->disconnection($connection->app->id); + + $logger->save(); + + $this->assertCount(1, WebSocketsStatisticsEntry::all()); + + $entry = WebSocketsStatisticsEntry::first(); + + $this->assertEquals(1, $entry->peak_connection_count); + $this->assertEquals(1, $entry->websocket_message_count); + $this->assertEquals(1, $entry->api_message_count); + } +} diff --git a/tests/Statistics/Logger/StatisticsLoggerTest.php b/tests/Statistics/Logger/StatisticsLoggerTest.php index 196e589..f040d13 100644 --- a/tests/Statistics/Logger/StatisticsLoggerTest.php +++ b/tests/Statistics/Logger/StatisticsLoggerTest.php @@ -12,31 +12,19 @@ use Illuminate\Support\Facades\Redis; class StatisticsLoggerTest extends TestCase { - /** @test */ - public function it_counts_connections() + /** + * {@inheritdoc} + */ + public function setUp(): void { + parent::setUp(); + $this->runOnlyOnLocalReplication(); - - $connections = []; - - $connections[] = $this->getConnectedWebSocketConnection(['channel-1']); - $connections[] = $this->getConnectedWebSocketConnection(['channel-1']); - $connections[] = $this->getConnectedWebSocketConnection(['channel-1']); - - $this->assertEquals(3, StatisticsLogger::getForAppId(1234)['peak_connection_count']); - - $this->pusherServer->onClose(array_pop($connections)); - - StatisticsLogger::save(); - - $this->assertEquals(2, StatisticsLogger::getForAppId(1234)['peak_connection_count']); } /** @test */ - public function it_counts_connections_on_redis_replication() + public function it_counts_connections() { - $this->runOnlyOnRedisReplication(); - $connections = []; $connections[] = $this->getConnectedWebSocketConnection(['channel-1']); @@ -55,31 +43,6 @@ class StatisticsLoggerTest extends TestCase /** @test */ public function it_counts_unique_connections_no_channel_subscriptions() { - $this->runOnlyOnLocalReplication(); - - $connections = []; - - $connections[] = $this->getConnectedWebSocketConnection(['channel-1', 'channel-2']); - $connections[] = $this->getConnectedWebSocketConnection(['channel-1', 'channel-2']); - $connections[] = $this->getConnectedWebSocketConnection(['channel-1']); - - $this->assertEquals(3, StatisticsLogger::getForAppId(1234)['peak_connection_count']); - - $this->pusherServer->onClose(array_pop($connections)); - $this->pusherServer->onClose(array_pop($connections)); - - StatisticsLogger::save(); - - $this->assertEquals(1, StatisticsLogger::getForAppId(1234)['peak_connection_count']); - } - - /** @test */ - public function it_counts_unique_connections_no_channel_subscriptions_on_redis() - { - $this->runOnlyOnRedisReplication(); - - Redis::hdel('laravel_database_1234', 'connections'); - $connections = []; $connections[] = $this->getConnectedWebSocketConnection(['channel-1', 'channel-2']); @@ -141,68 +104,4 @@ class StatisticsLoggerTest extends TestCase $this->assertCount(0, WebSocketsStatisticsEntry::all()); } - - /** @test */ - public function it_counts_connections_with_redis_logger_with_no_data() - { - $this->runOnlyOnRedisReplication(); - - config(['cache.default' => 'redis']); - - $connection = $this->getConnectedWebSocketConnection(['channel-1']); - - $logger = new RedisStatisticsLogger( - $this->channelManager, - $this->statisticsDriver - ); - - $logger->resetAppTraces('1234'); - - $logger->webSocketMessage($connection->app->id); - $logger->apiMessage($connection->app->id); - $logger->connection($connection->app->id); - $logger->disconnection($connection->app->id); - - $logger->save(); - - $this->assertCount(1, WebSocketsStatisticsEntry::all()); - - $entry = WebSocketsStatisticsEntry::first(); - - $this->assertEquals(1, $entry->peak_connection_count); - $this->assertEquals(1, $entry->websocket_message_count); - $this->assertEquals(1, $entry->api_message_count); - } - - /** @test */ - public function it_counts_connections_with_redis_logger_with_existing_data() - { - $this->runOnlyOnRedisReplication(); - - config(['cache.default' => 'redis']); - - $connection = $this->getConnectedWebSocketConnection(['channel-1']); - - $logger = new RedisStatisticsLogger( - $this->channelManager, - $this->statisticsDriver - ); - - $logger->resetStatistics('1234', 0); - - $logger->webSocketMessage($connection->app->id); - $logger->apiMessage($connection->app->id); - $logger->connection($connection->app->id); - $logger->disconnection($connection->app->id); - - $logger->save(); - - $this->assertCount(1, WebSocketsStatisticsEntry::all()); - - $entry = WebSocketsStatisticsEntry::first(); - - $this->assertEquals(1, $entry->peak_connection_count); - $this->assertEquals(1, $entry->websocket_message_count); - $this->assertEquals(1, $entry->api_message_count); - } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 9df4b29..0e8d756 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -7,6 +7,7 @@ use BeyondCode\LaravelWebSockets\PubSub\ReplicationInterface; use BeyondCode\LaravelWebSockets\Statistics\Drivers\StatisticsDriver; use BeyondCode\LaravelWebSockets\Tests\Mocks\Connection; use BeyondCode\LaravelWebSockets\Tests\Mocks\FakeMemoryStatisticsLogger; +use BeyondCode\LaravelWebSockets\Tests\Mocks\FakeRedisStatisticsLogger; use BeyondCode\LaravelWebSockets\Tests\Mocks\Message; use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager; use GuzzleHttp\Psr7\Request; @@ -56,10 +57,7 @@ abstract class TestCase extends BaseTestCase $this->statisticsDriver = $this->app->make(StatisticsDriver::class); - StatisticsLogger::swap(new FakeMemoryStatisticsLogger( - $this->channelManager, - app(StatisticsDriver::class) - )); + $this->configureStatisticsLogger(); $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); @@ -271,6 +269,31 @@ abstract class TestCase extends BaseTestCase }); } + /** + * Configure the statistics logger for the right driver. + * + * @return void + */ + protected function configureStatisticsLogger() + { + $replicationDriver = getenv('REPLICATION_DRIVER') ?: 'local'; + + if ($replicationDriver === 'local') { + StatisticsLogger::swap(new FakeMemoryStatisticsLogger( + $this->channelManager, + app(StatisticsDriver::class) + )); + } + + if ($replicationDriver === 'redis') { + StatisticsLogger::swap(new FakeRedisStatisticsLogger( + $this->channelManager, + app(StatisticsDriver::class), + $this->app->make(ReplicationInterface::class) + )); + } + } + protected function runOnlyOnRedisReplication() { if (config('websockets.replication.driver') !== 'redis') {