set up tests

This commit is contained in:
Alex Renoki 2020-08-13 16:18:14 +03:00
parent 64b0fa8382
commit 51f84e3c40
10 changed files with 55 additions and 36 deletions

View File

@ -43,8 +43,11 @@ jobs:
composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest
- name: Execute tests
run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml
run: |
REPLICATION_DRIVER=local phpunit --coverage-text --coverage-clover=coverage_local.xml
REPLICATION_DRIVER=redis phpunit --coverage-text --coverage-clover=coverage_redis.xml
- uses: codecov/codecov-action@v1
with:
fail_ci_if_error: false
file: '*.xml'

View File

@ -143,23 +143,21 @@ return [
/*
|--------------------------------------------------------------------------
| Broadcasting Replication
| Broadcasting Replication PubSub
|--------------------------------------------------------------------------
|
| You can enable replication to publish and subscribe to
| messages across the driver.
|
| By default, it is disabled, but you can configure it to use drivers
| By default, it is set to 'local', but you can configure it to use drivers
| like Redis to ensure connection between multiple instances of
| WebSocket servers.
| WebSocket servers. Just set the driver to 'redis' to enable the PubSub using Redis.
|
*/
'replication' => [
'enabled' => false,
'driver' => 'redis',
'driver' => 'local',
'redis' => [

View File

@ -166,7 +166,9 @@ class StartWebSocketServer extends Command
protected function configurePubSubReplication()
{
$this->laravel->get(ReplicationInterface::class)->boot($this->loop);
$this->laravel
->get(ReplicationInterface::class)
->boot($this->loop);
return $this;
}

View File

@ -13,13 +13,13 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
class FetchChannelsController extends Controller
{
/** @var ReplicationInterface */
protected $replication;
protected $pubsub;
public function __construct(ChannelManager $channelManager, ReplicationInterface $replication)
public function __construct(ChannelManager $channelManager, ReplicationInterface $pubsub)
{
parent::__construct($channelManager);
$this->replication = $replication;
$this->pubsub = $pubsub;
}
public function __invoke(Request $request)
@ -51,7 +51,7 @@ class FetchChannelsController extends Controller
// We ask the replication backend to get us the member count per channel.
// We get $counts back as a key-value array of channel names and their member count.
return $this->replication
return $this->pubsub
->channelMemberCounts($request->appId, $channelNames)
->then(function (array $counts) use ($channels, $attributes) {
return [

View File

@ -38,7 +38,6 @@ class LocalClient implements ReplicationInterface
*/
public function publish(string $appId, string $channel, stdClass $payload): bool
{
// Nothing to do, nobody to publish to
return true;
}

View File

@ -257,20 +257,24 @@ class RedisClient implements ReplicationInterface
*/
protected function getConnectionUri()
{
$name = config('websockets.replication.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'] ? (':'.$config['port']) : ':6379';
$port = $config['port'] ?: 6379;
$query = [];
if ($config['password']) {
$query['password'] = $config['password'];
}
if ($config['database']) {
$query['database'] = $config['database'];
}
$query = http_build_query($query);
return "redis://$host$port".($query ? '?'.$query : '');
return "redis://{$host}:{$port}".($query ? "?{$query}" : '');
}
}

View File

@ -15,7 +15,7 @@ class Channel
protected $channelName;
/** @var ReplicationInterface */
protected $replication;
protected $pubsub;
/** @var \Ratchet\ConnectionInterface[] */
protected $subscribedConnections = [];
@ -23,7 +23,7 @@ class Channel
public function __construct(string $channelName)
{
$this->channelName = $channelName;
$this->replication = app(ReplicationInterface::class);
$this->pubsub = app(ReplicationInterface::class);
}
public function getChannelName(): string
@ -68,7 +68,7 @@ class Channel
$this->saveConnection($connection);
// Subscribe to broadcasted messages from the pub/sub backend
$this->replication->subscribe($connection->app->id, $this->channelName);
$this->pubsub->subscribe($connection->app->id, $this->channelName);
$connection->send(json_encode([
'event' => 'pusher_internal:subscription_succeeded',
@ -81,7 +81,7 @@ class Channel
unset($this->subscribedConnections[$connection->socketId]);
// Unsubscribe from the pub/sub backend
$this->replication->unsubscribe($connection->app->id, $this->channelName);
$this->pubsub->unsubscribe($connection->app->id, $this->channelName);
if (! $this->hasConnections()) {
DashboardLogger::vacated($connection, $this->channelName);
@ -120,7 +120,7 @@ class Channel
// in this case. If this came from TriggerEventController, then we still want
// to publish to get the message out to other server instances.
if ($publish) {
$this->replication->publish($appId, $this->channelName, $payload);
$this->pubsub->publish($appId, $this->channelName, $payload);
}
// Performance optimization, if we don't have a socket ID,

View File

@ -28,7 +28,7 @@ class PresenceChannel extends Channel
public function getUsers(string $appId)
{
// Get the members list from the replication backend
return $this->replication
return $this->pubsub
->channelMembers($appId, $this->channelName);
}
@ -49,7 +49,7 @@ class PresenceChannel extends Channel
$this->users[$connection->socketId] = $channelData;
// Add the connection as a member of the channel
$this->replication
$this->pubsub
->joinChannel(
$connection->app->id,
$this->channelName,
@ -59,7 +59,7 @@ class PresenceChannel extends Channel
// We need to pull the channel data from the replication backend,
// otherwise we won't be sending the full details of the channel
$this->replication
$this->pubsub
->channelMembers($connection->app->id, $this->channelName)
->then(function ($users) use ($connection) {
// Send the success event
@ -86,7 +86,7 @@ class PresenceChannel extends Channel
}
// Remove the connection as a member of the channel
$this->replication
$this->pubsub
->leaveChannel(
$connection->app->id,
$this->channelName,
@ -110,7 +110,7 @@ class PresenceChannel extends Channel
*/
public function toArray(string $appId = null)
{
return $this->replication
return $this->pubsub
->channelMembers($appId, $this->channelName)
->then(function ($users) {
return array_merge(parent::toArray(), [

View File

@ -24,6 +24,7 @@ use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Psr\Log\LoggerInterface;
use Pusher\Pusher;
use React\EventLoop\Factory as LoopFactory;
class WebSocketsServiceProvider extends ServiceProvider
{
@ -56,19 +57,19 @@ class WebSocketsServiceProvider extends ServiceProvider
protected function configurePubSub()
{
if (config('websockets.replication.enabled') !== true || config('websockets.replication.driver') !== 'redis') {
if (config('websockets.replication.driver') === 'local') {
$this->app->singleton(ReplicationInterface::class, function () {
return new LocalClient();
return new LocalClient;
});
return;
}
$this->app->singleton(ReplicationInterface::class, function () {
return (new RedisClient())->boot($this->loop);
});
if (config('websockets.replication.driver') === 'redis') {
$this->app->singleton(ReplicationInterface::class, function () {
return (new RedisClient)->boot($this->loop ?? LoopFactory::create());
});
}
$this->app->get(BroadcastManager::class)->extend('redis-pusher', function ($app, array $config) {
$this->app->get(BroadcastManager::class)->extend('websockets', function ($app, array $config) {
$pusher = new Pusher(
$config['key'], $config['secret'],
$config['app_id'], $config['options'] ?? []

View File

@ -56,6 +56,18 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
],
]);
$app['config']->set('database.redis.default', [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
]);
$app['config']->set(
'websockets.replication.driver',
getenv('REPLICATION_DRIVER') ?: 'local'
);
include_once __DIR__.'/../database/migrations/create_websockets_statistics_entries_table.php.stub';
(new \CreateWebSocketsStatisticsEntriesTable())->up();