Skip to content

Commit

Permalink
Unit test suite improvements and cluster failover test
Browse files Browse the repository at this point in the history
* Added a test specifically for RedisCluster to test slave failover
  settings.
* Added an option to specifically disable colorization, as well as
  a mechanism to determine if the output is being piped, such that
  we can turn colorization off in that case as well.
  • Loading branch information
michael-grunder committed May 5, 2015
1 parent 97c9edc commit 08ecec9
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 15 deletions.
2 changes: 1 addition & 1 deletion tests/RedisArrayTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?php
<?php defined('PHPREDIS_TESTRUN') or die("Use TestRedis.php to run tests!\n");
require_once(dirname($_SERVER['PHP_SELF'])."/TestSuite.php");

define('REDIS_ARRAY_DATA_SIZE', 1000);
Expand Down
158 changes: 154 additions & 4 deletions tests/RedisClusterTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?php
<?php defined('PHPREDIS_TESTRUN') or die("Use TestRedis.php to run tests!\n");
require_once(dirname($_SERVER['PHP_SELF'])."/RedisTest.php");

/**
Expand All @@ -9,6 +9,20 @@
class Redis_Cluster_Test extends Redis_Test {
private $_arr_node_map = Array();

private $_arr_redis_types = Array(
Redis::REDIS_STRING,
Redis::REDIS_SET,
Redis::REDIS_LIST,
Redis::REDIS_ZSET,
Redis::REDIS_HASH
);

private $_arr_failover_types = Array(
RedisCluster::FAILOVER_NONE,
RedisCluster::FAILOVER_ERROR,
RedisCluster::FAILOVER_DISTRIBUTE
);

/* Tests we'll skip all together in the context of RedisCluster. The
* RedisCluster class doesn't implement specialized (non-redis) commands
* such as sortAsc, or sortDesc and other commands such as SELECT are
Expand Down Expand Up @@ -216,16 +230,17 @@ public function testFailedTransactions() {
$r = $this->newInstance(); // new instance, modifying `x'.
$r->incr('x');

// This transaction should fail because the other client changed 'x'
$ret = $this->redis->multi()->get('x')->exec();
$this->assertTrue($ret === Array(FALSE)); // failed because another client changed our watched key between WATCH and EXEC.

$this->assertTrue($ret === Array(FALSE));
// watch and unwatch
$this->redis->watch('x');
$r->incr('x'); // other instance
$this->redis->unwatch('x'); // cancel transaction watch

// This should succeed as the watch has been cancelled
$ret = $this->redis->multi()->get('x')->exec();
$this->assertTrue($ret === array('44')); // succeeded since we've cancel the WATCH command.
$this->assertTrue($ret === array('44'));
}

/* RedisCluster::script() is a 'raw' command, which requires a key such that
Expand Down Expand Up @@ -281,5 +296,140 @@ public function testEvalSHA() {
$this->assertTrue(1 === $this->redis->eval($scr,Array($str_key), 1));
$this->assertTrue(1 === $this->redis->evalsha($sha,Array($str_key), 1));
}

protected function genKeyName($i_key_idx, $i_type) {
switch ($i_type) {
case Redis::REDIS_STRING:
return "string-$i_key_idx";
case Redis::REDIS_SET:
return "set-$i_key_idx";
case Redis::REDIS_LIST:
return "list-$i_key_idx";
case Redis::REDIS_ZSET:
return "zset-$i_key_idx";
case Redis::REDIS_HASH:
return "hash-$i_key_idx";
default:
return "unknown-$i_key_idx";
}
}

protected function setKeyVals($i_key_idx, $i_type, &$arr_ref) {
$str_key = $this->genKeyName($i_key_idx, $i_type);

$this->redis->del($str_key);

switch ($i_type) {
case Redis::REDIS_STRING:
$value = "$str_key-value";
$this->redis->set($str_key, $value);
break;
case Redis::REDIS_SET:
$value = Array(
$str_key . '-mem1', $str_key . '-mem2', $str_key . '-mem3',
$str_key . '-mem4', $str_key . '-mem5', $str_key . '-mem6'
);
$arr_args = $value;
array_unshift($arr_args, $str_key);
call_user_func_array(Array($this->redis, 'sadd'), $arr_args);
break;
case Redis::REDIS_HASH:
$value = Array(
$str_key . '-mem1' => $str_key . '-val1',
$str_key . '-mem2' => $str_key . '-val2',
$str_key . '-mem3' => $str_key . '-val3'
);
$this->redis->hmset($str_key, $value);
break;
case Redis::REDIS_LIST:
$value = Array(
$str_key . '-ele1', $str_key . '-ele2', $str_key . '-ele3',
$str_key . '-ele4', $str_key . '-ele5', $str_key . '-ele6'
);
$arr_args = $value;
array_unshift($arr_args, $str_key);
call_user_func_array(Array($this->redis, 'rpush'), $arr_args);
break;
case Redis::REDIS_ZSET:
$i_score = 1;
$value = Array(
$str_key . '-mem1' => 1, $str_key . '-mem2' => 2,
$str_key . '-mem3' => 3, $str_key . '-mem3' => 3
);
foreach ($value as $str_mem => $i_score) {
$this->redis->zadd($str_key, $i_score, $str_mem);
}
break;
}

/* Update our reference array so we can verify values */
$arr_ref[$str_key] = $value;
return $str_key;
}

/* Verify that our ZSET values are identical */
protected function checkZSetEquality($a, $b) {
/* If the count is off, the array keys are different or the sums are
* different, we know there is something off */
$boo_diff = count($a) != count($b) ||
count(array_diff(array_keys($a), array_keys($b))) != 0 ||
array_sum($a) != array_sum($b);

if ($boo_diff) {
$this->assertEquals($a,$b);
return;
}
}

protected function checkKeyValue($str_key, $i_type, $value) {
switch ($i_type) {
case Redis::REDIS_STRING:
$this->assertEquals($value, $this->redis->get($str_key));
break;
case Redis::REDIS_SET:
$arr_r_values = $this->redis->sMembers($str_key);
$arr_l_values = $value;
sort($arr_r_values);
sort($arr_l_values);
$this->assertEquals($arr_r_values, $arr_l_values);
break;
case Redis::REDIS_LIST:
$this->assertEquals($value, $this->redis->lrange($str_key,0,-1));
break;
case Redis::REDIS_HASH:
$this->assertEquals($value, $this->redis->hgetall($str_key));
break;
case Redis::REDIS_ZSET:
$this->checkZSetEquality($value, $this->redis->zrange($str_key,0,-1,true));
break;
default:
throw new Exception("Unknown type " . $i_type);
}
}

/* Test automatic load distributor */
public function testFailOver() {
$arr_value_ref = Array();
$arr_type_ref = Array();

/* Set a bunch of keys of various redis types*/
for ($i = 0; $i < 200; $i++) {
foreach ($this->_arr_redis_types as $i_type) {
$str_key = $this->setKeyVals($i, $i_type, $arr_value_ref);
$arr_type_ref[$str_key] = $i_type;
}
}

/* Iterate over failover options */
foreach ($this->_arr_failover_types as $i_opt) {
$this->redis->setOption(RedisCluster::OPT_SLAVE_FAILOVER, $i_opt);

foreach ($arr_value_ref as $str_key => $value) {
$this->checkKeyValue($str_key, $arr_type_ref[$str_key], $value);
}

break;
}
}
}
?>
2 changes: 1 addition & 1 deletion tests/RedisTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?php
<?php defined('PHPREDIS_TESTRUN') or die("Use TestRedis.php to run tests!\n");

require_once(dirname($_SERVER['PHP_SELF'])."/TestSuite.php");

Expand Down
13 changes: 11 additions & 2 deletions tests/TestRedis.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
<?php
<?php define('PHPREDIS_TESTRUN', true);

require_once(dirname($_SERVER['PHP_SELF'])."/TestSuite.php");
require_once(dirname($_SERVER['PHP_SELF'])."/RedisTest.php");
require_once(dirname($_SERVER['PHP_SELF'])."/RedisArrayTest.php");
require_once(dirname($_SERVER['PHP_SELF'])."/RedisClusterTest.php");

/* Make sure errors go to stdout and are shown */
error_reporting(E_ALL);
ini_set( 'display_errors','1');

/* Grab options */
$arr_args = getopt('', Array('class:', 'test:'));
$arr_args = getopt('', Array('class:', 'test:', 'nocolors'));

/* Grab the test the user is trying to run */
$arr_valid_classes = Array('redis', 'redisarray', 'rediscluster');
$str_class = isset($arr_args['class']) ? strtolower($arr_args['class']) : 'redis';
$boo_colorize = !isset($arr_args['nocolors']);

/* Get our test filter if provided one */
$str_filter = isset($arr_args['test']) ? $arr_args['test'] : NULL;
Expand All @@ -20,6 +26,9 @@
exit(1);
}

/* Toggle colorization in our TestSuite class */
TestSuite::flagColorization($boo_colorize);

/* Let the user know this can take a bit of time */
echo "Note: these tests might take up to a minute. Don't worry :-)\n";

Expand Down
29 changes: 22 additions & 7 deletions tests/TestSuite.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?php
<?php defined('PHPREDIS_TESTRUN') or die("Use TestRedis.php to run tests!\n");

// phpunit is such a pain to install, we're going with pure-PHP here.
class TestSuite {
private static $_boo_colorize = false;

private static $BOLD_ON = "\033[1m";
private static $BOLD_OFF = "\033[0m";
Expand All @@ -18,19 +19,27 @@ class TestSuite {
public static $warnings = array();

public static function make_bold($str_msg) {
return self::$BOLD_ON . $str_msg . self::$BOLD_OFF;
return self::$_boo_colorize
? self::$BOLD_ON . $str_msg . self::$BOLD_OFF
: $str_msg;
}

public static function make_success($str_msg) {
return self::$GREEN . $str_msg . self::$BOLD_OFF;
return self::$_boo_colorize
? self::$GREEN . $str_msg . self::$BOLD_OFF
: $str_msg;
}

public static function make_fail($str_msg) {
return self::$RED . $str_msg . self::$BOLD_OFF;
return self::$_boo_colorize
? self::$RED . $str_msg . self::$BOLD_OFF
: $str_msg;
}

public static function make_warning($str_msg) {
return self::$YELLOW . $str_msg . self::$BOLD_OFF;
return self::$_boo_colorize
? self::$YELLOW . $str_msg . self::$BOLD_OFF
: $str_msg;
}

protected function assertFalse($bool) {
Expand Down Expand Up @@ -74,7 +83,7 @@ protected function markTestSkipped($msg='') {
throw new Exception($msg);
}

private function getMaxTestLen($arr_methods, $str_limit) {
private static function getMaxTestLen($arr_methods, $str_limit) {
$i_result = 0;

$str_limit = strtolower($str_limit);
Expand All @@ -92,6 +101,12 @@ private function getMaxTestLen($arr_methods, $str_limit) {
}
return $i_result;
}

/* Flag colorization */
public static function flagColorization($boo_override) {
self::$_boo_colorize = $boo_override && function_exists('posix_isatty') &&
posix_isatty(STDOUT);
}

public static function run($className, $str_limit = NULL) {
/* Lowercase our limit arg if we're passed one */
Expand Down Expand Up @@ -142,7 +157,7 @@ public static function run($className, $str_limit = NULL) {
echo "[" . $str_msg . "]\n";
}
echo "\n";
echo implode('', $className::$warnings);
echo implode('', $className::$warnings) . "\n";

if(empty($className::$errors)) {
echo "All tests passed. \o/\n";
Expand Down

0 comments on commit 08ecec9

Please sign in to comment.