Skip to content

Commit e8e9b20

Browse files
Xoncolinmollenhour
authored andcommitted
Unit tests & multi/exec fixes (#89)
* Suppress errors on cleanup (and avoid potentially deleting the config files) * The pubsub test crassh on phpredis 3.13 and below, but works with 3.1.4RCx. * All basic tests pass (except pubsub with phpredis which explicitly fails) * Fix-up testMasterSlave test * Give Redis time to exit * Fixup testGetHostAndPort test * Allow php7.x opcache to optimize the array to be vastly more compact, and use an O(1) lookup rater than a array scan of strings. * When in standalone multi() mode, exec() now decodes the result, and discard() destroys any pipelining or multi setup. * Rearange testPipeline & testPipelineTransaction to have the same test functionality. Add tests for zrangebyscore/zrevrangebyscore * Fix pipeline/multi modes for more commands * Shim zRange/zRevRange arguments before they are sent to phpredis & expand test coverage * remove unneeded variable * In fluent mode, credis returns itself * Add test for watch/unwatch, ensure the connection is closed/cleaned up when a pipeline&multi or watch fails. * Use diskless replication and add some delays for initial setup time. * Implement info() command for Sentinel * sentinel tests now wait for replication setup to finish * Run all tests * Restore php5.6 support in Credis_cluster * Compile redis from source so redis-sentinel is available * Tweak travis build * Move binaries to the right directory * Update PATH environment variable rather than move binaries around. * Remove debugging code * Better tolerance of slop in the timeout * Push common code into CredisTestCommon * Use role() instead of info() to reliably get the slave connecting state * Move sleep after connect check * Add waitForSlaveReplication for reliable waiting for master-slave replication
1 parent e0a208d commit e8e9b20

12 files changed

+668
-361
lines changed

.travis.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ matrix:
1212
- php: 7.1
1313
- php: 7.2
1414

15-
services:
16-
- redis-server
17-
1815
install:
1916
- yes '' | pecl install -f redis
17+
- wget http://download.redis.io/releases/redis-3.2.11.tar.gz
18+
- tar -xzf redis-3.2.11.tar.gz
19+
- make -s -C redis-3.2.11 -j4
20+
- export PATH=$PATH:$PWD/redis-3.2.11/src/
2021

2122
script:
22-
- phpunit --testsuite Basic --exclude-group Auth,UnixSocket
23+
- phpunit

Client.php

Lines changed: 218 additions & 163 deletions
Large diffs are not rendered by default.

Cluster.php

Lines changed: 60 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,19 @@ class Credis_Cluster
3131
* @var array
3232
*/
3333
protected $aliases;
34-
34+
3535
/**
3636
* Hash ring of Redis server nodes
3737
* @var array
3838
*/
3939
protected $ring;
40-
40+
4141
/**
4242
* Individual nodes of pointers to Redis servers on the hash ring
4343
* @var array
4444
*/
4545
protected $nodes;
46-
46+
4747
/**
4848
* The commands that are not subject to hashing
4949
* @var array
@@ -276,64 +276,65 @@ public function hash($key)
276276
return $this->ring[$server];
277277
}
278278

279+
const readOnlyCommands = array(
280+
'DBSIZE' => true,
281+
'INFO' => true,
282+
'MONITOR' => true,
283+
'EXISTS' => true,
284+
'TYPE' => true,
285+
'KEYS' => true,
286+
'SCAN' => true,
287+
'RANDOMKEY' => true,
288+
'TTL' => true,
289+
'GET' => true,
290+
'MGET' => true,
291+
'SUBSTR' => true,
292+
'STRLEN' => true,
293+
'GETRANGE' => true,
294+
'GETBIT' => true,
295+
'LLEN' => true,
296+
'LRANGE' => true,
297+
'LINDEX' => true,
298+
'SCARD' => true,
299+
'SISMEMBER' => true,
300+
'SINTER' => true,
301+
'SUNION' => true,
302+
'SDIFF' => true,
303+
'SMEMBERS' => true,
304+
'SSCAN' => true,
305+
'SRANDMEMBER' => true,
306+
'ZRANGE' => true,
307+
'ZREVRANGE' => true,
308+
'ZRANGEBYSCORE' => true,
309+
'ZREVRANGEBYSCORE' => true,
310+
'ZCARD' => true,
311+
'ZSCORE' => true,
312+
'ZCOUNT' => true,
313+
'ZRANK' => true,
314+
'ZREVRANK' => true,
315+
'ZSCAN' => true,
316+
'HGET' => true,
317+
'HMGET' => true,
318+
'HEXISTS' => true,
319+
'HLEN' => true,
320+
'HKEYS' => true,
321+
'HVALS' => true,
322+
'HGETALL' => true,
323+
'HSCAN' => true,
324+
'PING' => true,
325+
'AUTH' => true,
326+
'SELECT' => true,
327+
'ECHO' => true,
328+
'QUIT' => true,
329+
'OBJECT' => true,
330+
'BITCOUNT' => true,
331+
'TIME' => true,
332+
'SORT' => true,
333+
);
334+
279335
public function isReadOnlyCommand($command)
280336
{
281-
$readOnlyCommands = array(
282-
'DBSIZE',
283-
'INFO',
284-
'MONITOR',
285-
'EXISTS',
286-
'TYPE',
287-
'KEYS',
288-
'SCAN',
289-
'RANDOMKEY',
290-
'TTL',
291-
'GET',
292-
'MGET',
293-
'SUBSTR',
294-
'STRLEN',
295-
'GETRANGE',
296-
'GETBIT',
297-
'LLEN',
298-
'LRANGE',
299-
'LINDEX',
300-
'SCARD',
301-
'SISMEMBER',
302-
'SINTER',
303-
'SUNION',
304-
'SDIFF',
305-
'SMEMBERS',
306-
'SSCAN',
307-
'SRANDMEMBER',
308-
'ZRANGE',
309-
'ZREVRANGE',
310-
'ZRANGEBYSCORE',
311-
'ZREVRANGEBYSCORE',
312-
'ZCARD',
313-
'ZSCORE',
314-
'ZCOUNT',
315-
'ZRANK',
316-
'ZREVRANK',
317-
'ZSCAN',
318-
'HGET',
319-
'HMGET',
320-
'HEXISTS',
321-
'HLEN',
322-
'HKEYS',
323-
'HVALS',
324-
'HGETALL',
325-
'HSCAN',
326-
'PING',
327-
'AUTH',
328-
'SELECT',
329-
'ECHO',
330-
'QUIT',
331-
'OBJECT',
332-
'BITCOUNT',
333-
'TIME',
334-
'SORT'
335-
);
336-
return in_array(strtoupper($command),$readOnlyCommands);
337+
return array_key_exists(strtoupper($command), static::readOnlyCommands);
337338
}
338339
}
339340

Sentinel.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,22 @@ public function __call($name, $args)
268268
return call_user_func(array($this->_client,'sentinel'),$args);
269269
}
270270

271+
/**
272+
* get information block for the sentinel instance
273+
*
274+
* @param string|NUll $section
275+
*
276+
* @return array
277+
*/
278+
public function info($section = null)
279+
{
280+
if ($section)
281+
{
282+
return $this->_client->info($section);
283+
}
284+
return $this->_client->info();
285+
}
286+
271287
/**
272288
* Return information about all registered master servers
273289
* @return mixed

tests/CredisClusterTest.php

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,23 @@
66

77
class CredisClusterTest extends CredisTestCommon
88
{
9-
109
/** @var Credis_Cluster */
1110
protected $cluster;
1211

13-
protected $config;
14-
15-
protected $useStandalone = FALSE;
16-
1712
protected function setUp()
1813
{
19-
if($this->config === NULL) {
20-
$configFile = dirname(__FILE__).'/redis_config.json';
21-
if( ! file_exists($configFile) || ! ($config = file_get_contents($configFile))) {
22-
$this->markTestSkipped('Could not load '.$configFile);
23-
return;
24-
}
25-
$this->config = json_decode($config);
26-
$arrayConfig = array();
27-
foreach($this->config as $config) {
28-
$arrayConfig[] = (array)$config;
29-
}
30-
$this->config = $arrayConfig;
31-
if(count($this->config) < 6) {
32-
$this->markTestSkipped('Config file '.$configFile.' should contain at least 6 entries');
33-
return;
34-
}
35-
}
14+
parent::setUp();
3615

37-
if($this->useStandalone && !extension_loaded('redis')) {
38-
$this->fail('The Redis extension is not loaded.');
39-
}
40-
$clients = array_slice($this->config,0,4);
16+
$clients = array_slice($this->redisConfig,0,4);
4117
$this->cluster = new Credis_Cluster($clients,2,$this->useStandalone);
4218
}
4319

4420
protected function tearDown()
4521
{
4622
if($this->cluster) {
23+
$this->cluster->flushAll();
4724
foreach($this->cluster->clients() as $client){
4825
if($client->isConnected()) {
49-
$client->flushAll();
5026
$client->close();
5127
}
5228
}
@@ -57,7 +33,7 @@ protected function tearDown()
5733
public function testKeyHashing()
5834
{
5935
$this->tearDown();
60-
$this->cluster = new Credis_Cluster(array_slice($this->config,0,3),2,$this->useStandalone);
36+
$this->cluster = new Credis_Cluster(array_slice($this->redisConfig, 0, 3), 2, $this->useStandalone);
6137
$keys = array();
6238
$lines = explode("\n", file_get_contents("keys.test"));
6339
foreach ($lines as $line) {
@@ -69,7 +45,7 @@ public function testKeyHashing()
6945
foreach ($keys as $key => $value) {
7046
$this->assertTrue($this->cluster->set($key, $value));
7147
}
72-
$this->cluster = new Credis_Cluster(array_slice($this->config,0,4),2,true,$this->useStandalone);
48+
$this->cluster = new Credis_Cluster(array_slice($this->redisConfig, 0, 4), 2, true, $this->useStandalone);
7349
$hits = 0;
7450
foreach ($keys as $key => $value) {
7551
if ($this->cluster->all('get',$key)) {
@@ -80,7 +56,7 @@ public function testKeyHashing()
8056
}
8157
public function testAlias()
8258
{
83-
$slicedConfig = array_slice($this->config,0,4);
59+
$slicedConfig = array_slice($this->redisConfig, 0, 4);
8460
foreach($slicedConfig as $config) {
8561
$this->assertEquals($config['port'],$this->cluster->client($config['alias'])->getPort());
8662
}
@@ -94,8 +70,9 @@ public function testAlias()
9470
public function testMasterSlave()
9571
{
9672
$this->tearDown();
97-
$this->cluster = new Credis_Cluster(array($this->config[0],$this->config[6]),2,$this->useStandalone);
73+
$this->cluster = new Credis_Cluster(array($this->redisConfig[0],$this->redisConfig[6]), 2, $this->useStandalone);
9874
$this->assertTrue($this->cluster->client('master')->set('key','value'));
75+
$this->waitForSlaveReplication();
9976
$this->assertEquals('value',$this->cluster->client('slave')->get('key'));
10077
$this->assertEquals('value',$this->cluster->get('key'));
10178
try
@@ -108,18 +85,20 @@ public function testMasterSlave()
10885
}
10986

11087
$this->tearDown();
111-
$writeOnlyConfig = $this->config[0];
88+
$writeOnlyConfig = $this->redisConfig[0];
11289
$writeOnlyConfig['write_only'] = true;
113-
$this->cluster = new Credis_Cluster(array($writeOnlyConfig,$this->config[6]),2,$this->useStandalone);
90+
$this->cluster = new Credis_Cluster(array($writeOnlyConfig,$this->redisConfig[6]), 2, $this->useStandalone);
11491
$this->assertTrue($this->cluster->client('master')->set('key','value'));
92+
$this->waitForSlaveReplication();
11593
$this->assertEquals('value',$this->cluster->client('slave')->get('key'));
116-
$this->assertFalse($this->cluster->client('slave')->set('key2','value'));
11794
$this->assertEquals('value',$this->cluster->get('key'));
95+
$this->expectException('CredisException','read-only slaves should not be writeable');
96+
$this->assertFalse($this->cluster->client('slave')->set('key2','value'));
11897
}
11998
public function testMasterWithoutSlavesAndWriteOnlyFlag()
12099
{
121100
$this->tearDown();
122-
$writeOnlyConfig = $this->config[0];
101+
$writeOnlyConfig = $this->redisConfig[0];
123102
$writeOnlyConfig['write_only'] = true;
124103
$this->cluster = new Credis_Cluster(array($writeOnlyConfig),2,$this->useStandalone);
125104
$this->assertTrue($this->cluster->set('key','value'));
@@ -200,9 +179,9 @@ public function testRwsplit()
200179
public function testCredisClientInstancesInConstructor()
201180
{
202181
$this->tearDown();
203-
$two = new Credis_Client($this->config[1]['host'],$this->config[1]['port']);
204-
$three = new Credis_Client($this->config[2]['host'],$this->config[2]['port']);
205-
$four = new Credis_Client($this->config[3]['host'],$this->config[3]['port']);
182+
$two = new Credis_Client($this->redisConfig[1]['host'], $this->redisConfig[1]['port']);
183+
$three = new Credis_Client($this->redisConfig[2]['host'], $this->redisConfig[2]['port']);
184+
$four = new Credis_Client($this->redisConfig[3]['host'], $this->redisConfig[3]['port']);
206185
$this->cluster = new Credis_Cluster(array($two,$three,$four),2,$this->useStandalone);
207186
$this->assertTrue($this->cluster->set('key','value'));
208187
$this->assertEquals('value',$this->cluster->get('key'));
@@ -212,18 +191,18 @@ public function testCredisClientInstancesInConstructor()
212191
public function testSetMasterClient()
213192
{
214193
$this->tearDown();
215-
$master = new Credis_Client($this->config[0]['host'],$this->config[0]['port']);
216-
$slave = new Credis_Client($this->config[6]['host'],$this->config[6]['port']);
194+
$master = new Credis_Client($this->redisConfig[0]['host'], $this->redisConfig[0]['port']);
195+
$slave = new Credis_Client($this->redisConfig[6]['host'], $this->redisConfig[6]['port']);
217196

218197
$this->cluster = new Credis_Cluster(array($slave),2,$this->useStandalone);
219198
$this->assertInstanceOf('Credis_Cluster',$this->cluster->setMasterClient($master));
220199
$this->assertCount(2,$this->cluster->clients());
221-
$this->assertEquals($this->config[6]['port'],$this->cluster->client(0)->getPort());
222-
$this->assertEquals($this->config[0]['port'],$this->cluster->client('master')->getPort());
200+
$this->assertEquals($this->redisConfig[6]['port'], $this->cluster->client(0)->getPort());
201+
$this->assertEquals($this->redisConfig[0]['port'], $this->cluster->client('master')->getPort());
223202

224-
$this->cluster = new Credis_Cluster(array($this->config[0]),2,$this->useStandalone);
225-
$this->assertInstanceOf('Credis_Cluster',$this->cluster->setMasterClient(new Credis_Client($this->config[1]['host'],$this->config[1]['port'])));
226-
$this->assertEquals($this->config[0]['port'],$this->cluster->client('master')->getPort());
203+
$this->cluster = new Credis_Cluster(array($this->redisConfig[0]), 2, $this->useStandalone);
204+
$this->assertInstanceOf('Credis_Cluster',$this->cluster->setMasterClient(new Credis_Client($this->redisConfig[1]['host'], $this->redisConfig[1]['port'])));
205+
$this->assertEquals($this->redisConfig[0]['port'], $this->cluster->client('master')->getPort());
227206

228207
$this->cluster = new Credis_Cluster(array($slave),2,$this->useStandalone);
229208
$this->assertInstanceOf('Credis_Cluster',$this->cluster->setMasterClient($master,true));

tests/CredisSentinelTest.php

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,14 @@
77

88
class CredisSentinelTest extends CredisTestCommon
99
{
10-
1110
/** @var Credis_Sentinel */
1211
protected $sentinel;
1312

1413
protected $sentinelConfig;
15-
protected $redisConfig;
16-
17-
protected $useStandalone = FALSE;
1814

1915
protected function setUp()
2016
{
17+
parent::setUp();
2118
if($this->sentinelConfig === NULL) {
2219
$configFile = dirname(__FILE__).'/sentinel_config.json';
2320
if( ! file_exists($configFile) || ! ($config = file_get_contents($configFile))) {
@@ -27,26 +24,12 @@ protected function setUp()
2724
$this->sentinelConfig = json_decode($config);
2825
}
2926

30-
if($this->redisConfig === NULL) {
31-
$configFile = dirname(__FILE__).'/redis_config.json';
32-
if( ! file_exists($configFile) || ! ($config = file_get_contents($configFile))) {
33-
$this->markTestSkipped('Could not load '.$configFile);
34-
return;
35-
}
36-
$this->redisConfig = json_decode($config);
37-
$arrayConfig = array();
38-
foreach($this->redisConfig as $config) {
39-
$arrayConfig[] = (array)$config;
40-
}
41-
$this->redisConfig = $arrayConfig;
42-
}
4327
$sentinelClient = new Credis_Client($this->sentinelConfig->host, $this->sentinelConfig->port);
4428
$this->sentinel = new Credis_Sentinel($sentinelClient);
4529
if($this->useStandalone) {
4630
$this->sentinel->forceStandalone();
47-
} else if ( ! extension_loaded('redis')) {
48-
$this->fail('The Redis extension is not loaded.');
4931
}
32+
$this->waitForSlaveReplication();
5033
}
5134
protected function tearDown()
5235
{
@@ -172,7 +155,7 @@ public function testGetHostAndPort()
172155
$host = 'localhost';
173156
$port = '123456';
174157

175-
$client = $this->getMock('\Credis_Client');
158+
$client = $this->createMock('\Credis_Client');
176159
$sentinel = new Credis_Sentinel($client);
177160

178161
$client->expects($this->once())->method('getHost')->willReturn($host);

0 commit comments

Comments
 (0)