Skip to content
Closed
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
24 changes: 16 additions & 8 deletions bin/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,24 @@ echo "Ensuring services are running"

docker-compose up -d

if docker run -it --rm "registry.gitlab.com/grahamcampbell/php:$php-base" -r "\$tries = 0; while (true) { try { \$tries++; if (\$tries > 30) { throw new RuntimeException('MySQL never became available'); } sleep(1); new PDO('mysql:host=docker.for.mac.localhost;dbname=forge', 'root', '', [PDO::ATTR_TIMEOUT => 3]); break; } catch (PDOException \$e) {} }"; then
if docker run --add-host=host.docker.internal:host-gateway -it --rm "registry.gitlab.com/grahamcampbell/php:$php-base" -r "\$tries = 0; while (true) { try { \$tries++; if (\$tries > 30) { throw new RuntimeException('MySQL never became available'); } sleep(1); new PDO('mysql:host=host.docker.internal;dbname=forge', 'root', '', [PDO::ATTR_TIMEOUT => 3]); break; } catch (PDOException \$e) {} }"; then
echo "Running tests"

if docker run -it -w /data -v ${PWD}:/data:delegated \
--user "www-data" --entrypoint vendor/bin/phpunit \
--env CI=1 --env DB_HOST=docker.for.mac.localhost --env DB_USERNAME=root \
--env DB_HOST=docker.for.mac.localhost --env DB_PORT=3306 \
--env DYNAMODB_ENDPOINT=docker.for.mac.localhost:8000 --env DYNAMODB_CACHE_TABLE=cache --env AWS_ACCESS_KEY_ID=dummy --env AWS_SECRET_ACCESS_KEY=dummy \
--env REDIS_HOST=docker.for.mac.localhost --env REDIS_PORT=6379 \
--env MEMCACHED_HOST=docker.for.mac.localhost --env MEMCACHED_PORT=11211 \
if docker run -it -w /data -v ${PWD}:/data:delegated -u $(id -u ${USER}):$(id -g ${USER}) \
--entrypoint vendor/bin/phpunit \
--add-host=host.docker.internal:host-gateway \
--env CI=1 \
--env DB_HOST=host.docker.internal \
--env DB_PORT=3306 \
--env DB_USERNAME=root \
--env DYNAMODB_ENDPOINT=host.docker.internal:8000 \
--env DYNAMODB_CACHE_TABLE=cache \
--env AWS_ACCESS_KEY_ID=dummy \
--env AWS_SECRET_ACCESS_KEY=dummy \
--env REDIS_HOST=host.docker.internal \
--env REDIS_PORT=6379 \
--env MEMCACHED_HOST=host.docker.internal \
--env MEMCACHED_PORT=11211 \
--rm "registry.gitlab.com/grahamcampbell/php:$php-base" "$@"; then
exit 0
else
Expand Down
299 changes: 247 additions & 52 deletions src/Illuminate/Foundation/Testing/Concerns/InteractsWithRedis.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

namespace Illuminate\Foundation\Testing\Concerns;

use Exception;
use Illuminate\Foundation\Application;
use Illuminate\Redis\RedisManager;
use Illuminate\Support\Collection;
use Illuminate\Support\Env;
use Redis;
use Throwable;
use UnexpectedValueException;

trait InteractsWithRedis
{
/**
* Indicate connection failed if redis is not available.
* Indicates connection failed if redis is not available.
*
* @var bool
*/
Expand All @@ -21,97 +24,289 @@ trait InteractsWithRedis
*
* @var \Illuminate\Redis\RedisManager[]
*/
private $redis;
private $redisManagers = [];

/**
* Setup redis connection.
* Teardown redis connection.
*
* @return void
*/
public function setUpRedis()
public function tearDownRedis()
{
/** @var \Illuminate\Redis\RedisManager $redisManager */
foreach ($this->redisManagers as $label => $redisManager) {
$redisManager->connection()->flushdb();
$redisManager->connection()->disconnect();
}
}

/**
* Builds a redis manager from a predefined list of available connection
* configurations.
*
* If a driver and a config are given, they are used to create a new redis
* connection instead of the defaulting to a predefined list of connections.
* This way you can also create for example cluster or a very customized
* redis connection.
*
* @param string $connection Connection label.
* @param string $driver Optional driver to use together with a config.
* @param array $config Optional config to use for the connection.
* @return \Illuminate\Redis\RedisManager
*/
public function getRedisManager($connection, $driver = 'phpredis', $config = [])
{
if (! extension_loaded('redis')) {
$this->markTestSkipped('The redis extension is not installed. Please install the extension to enable '.__CLASS__);
$this->markTestSkipped(
'The redis extension is not installed. Please install the extension to enable '.__CLASS__
);
}

if (static::$connectionFailedOnceWithDefaultsSkip) {
$this->markTestSkipped('Trying default host/port failed, please set environment variable REDIS_HOST & REDIS_PORT to enable '.__CLASS__);
$this->markTestSkipped(
'Trying default host/port failed, please set environment variable '.
'REDIS_HOST & REDIS_PORT to enable '.__CLASS__
);
}

$app = $this->app ?? new Application;
$host = Env::get('REDIS_HOST', '127.0.0.1');
$port = Env::get('REDIS_PORT', 6379);
if (! empty($config)) {
return $this->redisManagers[$connection] = $this->initializeRedisManager($driver, $config);
}

if (array_key_exists($connection, $this->redisManagers)) {
return $this->redisManagers[$connection];
}

foreach ($this->redisDriverProvider() as $driver) {
$this->redis[$driver[0]] = new RedisManager($app, $driver[0], [
'cluster' => false,
$config = [
'cluster' => false,
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'port' => (int) env('REDIS_PORT', 6379),
'timeout' => 0.5,
'database' => 5,
'options' => [
'prefix' => 'test_',
'name' => 'base',
],
'default' => [
'host' => $host,
'port' => $port,
'database' => 5,
'timeout' => 0.5,
'name' => 'default',
],
]);
],
];

switch ($connection) {
case 'predis':
$driver = 'predis';
$config['default']['options']['name'] = 'predis';
break;
case 'phpredis':
$config['default']['options']['name'] = 'phpredis';
break;
case 'phpredis_prefix':
$config['default']['options']['name'] = 'phpredis_prefix';
$config['default']['options']['prefix'] = 'laravel:';
break;
case 'phpredis_scan_noretry':
$config['default']['options']['name'] = 'phpredis_scan_noretry';
$config['default']['options']['scan'] = Redis::SCAN_NORETRY;
break;
case 'phpredis_scan_retry':
$config['default']['options']['name'] = 'phpredis_scan_retry';
$config['default']['options']['scan'] = Redis::SCAN_RETRY;
break;
case 'phpredis_scan_prefix':
$config['default']['options']['name'] = 'phpredis_scan_prefix';
$config['default']['options']['scan'] = Redis::SCAN_PREFIX;
break;
case 'phpredis_scan_noprefix':
$config['default']['options']['name'] = 'phpredis_scan_noprefix';
$config['default']['options']['scan'] = Redis::SCAN_NOPREFIX;
break;
case 'phpredis_serializer_php':
$config['default']['options']['name'] = 'phpredis_serializer_php';
$config['default']['options']['serializer'] = Redis::SERIALIZER_PHP;
break;
case 'phpredis_serializer_igbinary':
$config['default']['options']['name'] = 'phpredis_serializer_igbinary';
$config['default']['options']['serializer'] = Redis::SERIALIZER_IGBINARY;
break;
case 'phpredis_serializer_json':
$config['default']['options']['name'] = 'phpredis_serializer_json';
$config['default']['options']['serializer'] = Redis::SERIALIZER_JSON;
break;
case 'phpredis_serializer_msgpack':
$config['default']['options']['name'] = 'phpredis_serializer_msgpack';
$config['default']['options']['serializer'] = Redis::SERIALIZER_MSGPACK;
break;
case 'phpredis_compression_lzf':
$config['default']['options']['name'] = 'phpredis_compression_lzf';
$config['default']['options']['compression'] = Redis::COMPRESSION_LZF;
break;
case 'phpredis_compression_zstd':
$config['default']['options']['name'] = 'phpredis_compression_zstd';
$config['default']['options']['compression'] = Redis::COMPRESSION_ZSTD;
$config['default']['options']['compression_level'] = Redis::COMPRESSION_ZSTD_DEFAULT;
break;
case 'phpredis_compression_lz4':
$config['default']['options']['name'] = 'phpredis_compression_lz4';
$config['default']['options']['compression'] = Redis::COMPRESSION_LZ4;
$config['default']['options']['compression_level'] = 0;
break;
case 'phpredis_msgpack_and_lz4':
$config['default']['options']['name'] = 'phpredis_msgpack_and_lz4';
$config['default']['options']['serializer'] = Redis::SERIALIZER_MSGPACK;
$config['default']['options']['compression'] = Redis::COMPRESSION_LZ4;
$config['default']['options']['compression_level'] = 12;
break;
default:
throw new UnexpectedValueException(sprintf(
'Redis manager connection configuration %s is not defined.',
$connection,
));
}

try {
$this->redis['phpredis']->connection()->flushdb();
} catch (Exception $e) {
if ($host === '127.0.0.1' && $port === 6379 && Env::get('REDIS_HOST') === null) {
static::$connectionFailedOnceWithDefaultsSkip = true;
return $this->redisManagers[$connection] = $this->initializeRedisManager($driver, $config);
}

$this->markTestSkipped('Trying default host/port failed, please set environment variable REDIS_HOST & REDIS_PORT to enable '.__CLASS__);
}
}
/**
* Returns a list of available redis connections.
*
* @return array
*/
public function getRedisConnections()
{
return [
'predis',
'phpredis',
];
}

/**
* Teardown redis connection.
* Returns an extended list of available redis connections.
*
* @return void
* @return array
*/
public function tearDownRedis()
public function getExtendedRedisConnections()
{
if (isset($this->redis['phpredis'])) {
$this->redis['phpredis']->connection()->flushdb();
$connections = [
'predis',
'phpredis',
'phpredis_prefix',
];

if (defined('Redis::SCAN_NORETRY')) {
$connections[] = 'phpredis_scan_noretry';
}

foreach ($this->redisDriverProvider() as $driver) {
if (isset($this->redis[$driver[0]])) {
$this->redis[$driver[0]]->connection()->disconnect();
}
if (defined('Redis::SCAN_RETRY')) {
$connections[] = 'phpredis_scan_retry';
}

if (defined('Redis::SCAN_PREFIX')) {
$connections[] = 'phpredis_scan_prefix';
}

if (defined('Redis::SCAN_NOPREFIX')) {
$connections[] = 'phpredis_scan_noprefix';
}

if (defined('Redis::SERIALIZER_PHP')) {
$connections[] = 'phpredis_serializer_php';
}

if (defined('Redis::SERIALIZER_IGBINARY')) {
$connections[] = 'phpredis_serializer_igbinary';
}

if (defined('Redis::SERIALIZER_JSON')) {
$connections[] = 'phpredis_serializer_json';
}

if (defined('Redis::SERIALIZER_MSGPACK')) {
$connections[] = 'phpredis_serializer_msgpack';
}

if (defined('Redis::COMPRESSION_LZF')) {
$connections[] = 'phpredis_compression_lzf';
}

if (defined('Redis::COMPRESSION_ZSTD')) {
$connections[] = 'phpredis_compression_zstd';
}

if (defined('Redis::COMPRESSION_LZ4')) {
$connections[] = 'phpredis_compression_lz4';
}

if (defined('Redis::SERIALIZER_MSGPACK') && defined('Redis::COMPRESSION_LZ4')) {
$connections[] = 'phpredis_msgpack_and_lz4';
}

return $connections;
}

/**
* Get redis driver provider.
* Data provider for tests that lists a default set of redis connections.
*
* @return array
*/
public function redisDriverProvider()
public function redisConnectionDataProvider()
{
return [
['predis'],
['phpredis'],
];
return (new Collection($this->getRedisConnections()))->mapWithKeys(function ($label) {
return [
$label => [
$label,
],
];
})->all();
}

/**
* Run test if redis is available.
* Extended data provider for tests that also lists special configurations
* like serialization and compression support on phpredis.
*
* @param callable $callback
* @return void
* @return array
*/
public function extendedRedisConnectionDataProvider()
{
return (new Collection($this->getExtendedRedisConnections()))->mapWithKeys(function ($label) {
return [
$label => [
$label,
],
];
})->all();
}

/**
* Initializes a new RedisManager with the given driver and config.
*
* @param string $driver
* @param array $config
* @return \Illuminate\Redis\RedisManager
*/
public function ifRedisAvailable($callback)
private function initializeRedisManager($driver, $config)
{
$this->setUpRedis();
$app = $this->app ?? new Application();
$redisManager = new RedisManager($app, $driver, $config);

$callback();
try {
$redisManager->connection()->flushdb();
} catch (Throwable $exception) {
if (
array_key_exists('host', $config['default']) &&
$config['default']['host'] === '127.0.0.1' &&
array_key_exists('port', $config['default']) &&
$config['default']['port'] === 6379 &&
Env::get('REDIS_HOST') === null
) {
static::$connectionFailedOnceWithDefaultsSkip = true;

$this->markTestSkipped(
'Trying default host/port failed, please set environment variable '.
'REDIS_HOST & REDIS_PORT to enable '.__CLASS__
);
}

throw $exception;
}

$this->tearDownRedis();
return $redisManager;
}
}
Loading