Skip to content

Instantly share code, notes, and snippets.

@heavenshell
Created October 21, 2011 14:33
Show Gist options
  • Select an option

  • Save heavenshell/1303990 to your computer and use it in GitHub Desktop.

Select an option

Save heavenshell/1303990 to your computer and use it in GitHub Desktop.
Net_Okuyama for PHP5.2
<?php
/**
* Socket-based adapter for Net_Okuyama for PHP5.2
*
* This module is deprecated.
* Use \Net\Okuyama instead if you are using PHP5.3
*
* PHP version 5.2
*
* Copyright (c) 2011 Shinya Ohyanagi, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Shinya Ohyanagi nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @category Net
* @package Net_Okuyama
* @version $id$
* @copyright (c) 2011 Shinya Ohyanagi
* @author Shinya Ohyanagi <sohyanagi@gmail.com>
* @license New BSD License
*/
interface Net_Okuyama_Adapter
{
/**
* Get data.
*
* @param mixed $key Key string
* @param mixed $tag Tag string
* @access public
* @return mixed Value.
*/
public function get($key);
/**
* Get data.
*
* @param mixed $key Key string
* @param mixed $tag Tag string
* @access public
* @return mixed Value.
*/
public function set($key, $value, array $tags = array());
/**
* Remove data.
*
* @param mixed $key
* @access public
* @return mixed Result of remove command.
*/
public function remove($key);
}
/**
* Net_Okuyama_Exception
*
* This module is deprecated.
* Use \Net\Okuyama instead if you are using PHP5.3
*
* @category Net
* @package Net_Okuyama
* @version $id$
* @copyright (c) 2011 Shinya Ohyanagi
* @author Shinya Ohyanagi <sohyanagi@gmail.com>
* @license New BSD License
*/
class Net_Okuyama_Exception extends Exception
{
}
/**
* Socket.
*
* This module is deprecated.
* Use \Net\Okuyama instead if you are using PHP5.3
*
* @category Net
* @package Net_Okuyama
* @version $id$
* @copyright (c) 2011 Shinya Ohyanagi
* @author Shinya Ohyanagi <sohyanagi@gmail.com>
* @license New BSD License
*/
class Net_Okuyama_Adapter_Socket implements Net_Okuyama_Adapter
{
/**
* Version.
*/
const VERSION = '0.0.1';
/**
* Data delimiter.
*/
const DATA_DELIMITER = ',';
/**
* Tag delimiter.
*/
const TAG_DELIMITER = ':';
/**
* Byte data delimiter.
*/
const BYTE_DATA_DELIMITER = ':#:';
/**
* Alternative blank string.
*/
const BLANK_STRING = '(B)';
/**
* Transaction code.
*/
const TRANSACTION_CODE = '0';
/**
* Initialize Okuyama.
*/
const ID_INIT = '0';
/**
* Set data.
*/
const ID_SET = '1';
/**
* Get data.
*/
const ID_GET = '2';
/**
* Set tag data.
*/
const ID_TAG_SET = '3';
/**
* Get tag data.
*/
const ID_TAG_GET = '4';
/**
* Remove data.
*/
const ID_REMOVE = '5';
/**
* Add data(not override).
*/
const ID_ADD = '6';
/**
* Play script.
*/
const ID_PLAY_SCRIPT = '8';
/**
* Play script for update.
*/
const ID_UPDATE_SCRIPT = '9';
/**
* Gets.
*/
const ID_GETS = '15';
/**
* Cas.
*/
const ID_CAS = '16';
/**
* Socket resouce.
*
* @var mixed
* @access private
*/
private $_socket = null;
/**
* Error no when fsockopen failed.
*
* @var mixed
* @access private
*/
private $_errorno = null;
/**
* Error message when fsockopen failed.
*
* @var mixed
* @access private
*/
private $_errormsg = null;
/**
* Connection timeout.
*
* @var mixed
* @access private
*/
private $_timeout = 10;
/**
* Connected host and port.
*
* @var mixed
* @access private
*/
private $_connectedHost = null;
/**
* Binary data per size.
*
* @var int
* @access private
*/
private $_size = 2560;
/**
* Max data size to save.
*
* @var int
* @access private
*/
private $_maxSize = 2560;
/**
* Raw data.
*
* @var mixed
* @access private
*/
private $_rawData = null;
/**
* Constructor.
*
* @access public
* @return void
*/
public function __construct()
{
}
/**
* Get raw data.
*
* <pre>
* Raw means Okuyama original format.
* </pre>
*
* @access public
* @return mixed Raw data
*/
public function getRawData()
{
return $this->_rawData;
}
/**
* Get error message.
*
* @access public
* @return mixed Error message
*/
public function getErrorMessage()
{
return $this->_errormsg;
}
/**
* Set config options.
*
* @param array $args Config options
* @access public
* @return Net_Okuyama_Adapter_Socket Fluent interface
*/
public function setConfig(array $args)
{
$this->_timeout = isset($args['timeout']) ? $args['timeout'] : 10;
return $this;
}
/**
* Connect to socket.
*
* @param mixed $host Host name
* @param mixed $port Port number
* @access public
* @return mixed Resouce handler or false
*/
public function connect($host, $port)
{
if (false === ($socket = @fsockopen(
$host, $port, $this->_errorno,
$this->_errormsg, $this->_timeout))) {
return false;
}
$this->_socket = $socket;
// Initialize connection.
// Attempt to send initialize save size to Okuyama.
$command = '0' . self::DATA_DELIMITER . "\n";
$response = $this->_parse($this->send($command)->response(), self::ID_INIT);
$result = array($response[1], $response[2]);
$this->_rawData = $result;
if ($response[1] === 'true') {
$this->_size = $response[2];
$this->_maxSize = $response[2];
} else {
return false;
}
$this->_connectedHost = $host . ':' . $port;
return $socket;
}
/**
* Connect to host by randam.
*
* @param array $hosts
* @access public
* @throws Net_Okuyama_Exception Connection refused
* @return bool true: Connection sucess
*/
public function autoConnect(array $hosts)
{
$list = $hosts;
if (count($hosts) > 1) {
shuffle($list);
}
$socket = null;
while (count($list) > 0) {
$data = array_shift($list);
if ($this->_validateHostFormat($data) === false) {
continue;
}
list($host, $port) = explode(':', $data);
$socket = $this->connect($host, $port);
if ($socket !== false) {
break;
}
}
if ($socket === null) {
throw new Net_Okuyama_Exception('All hosts connection refused.');
}
return true;
}
/**
* Close connection.
*
* @access public
* @throws Net_Okuyama_Exception Connection already closed
* @return bool true: Connection close sucess
*/
public function close()
{
if ($this->_socket === null || fclose($this->_socket) === false) {
throw new Net_Okuyama_Exception('Connection already closed.');
}
$this->_socket = null;
return true;
}
/**
* Is socket connected?
*
* @access public
* @return bool true: Connected, false: Not connected
*/
public function isConnected()
{
if ($this->_socket === null) {
return false;
}
return true;
}
/**
* Retrieve the value of a record.
*
* @param mixed $key The key of the record
* @access public
* @throws Net_Okuyama_Exception Server returns error
* @return mixed null or the value of the record
*/
public function get($key)
{
$result = $this->_get($key, self::ID_GET);
return $result[1];
}
/**
* Set the value of a record.
*
* @param mixed $key The key of the record
* @param mixed $value The value of the record
* @param array $tags Tags
* @access public
* @return Net_Okuyama_Adapter_Socket Fluent interface.
*/
public function set($key, $value, array $tags = array())
{
return $this->_set($key, $value, self::ID_SET, $tags);
}
/**
* Add a record.
*
* <pre>
* Can not override data.
* </pre>
*
* @param mixed $key The key of the record
* @param mixed $value The value of the record
* @param array $tags Tags
* @access public
* @return Net_Okuyama_Adapter_Socket Fluent interface.
*/
public function add($key, $value, array $tags = array())
{
return $this->_set($key, $value, self::ID_ADD, $tags);
}
/**
* Get version no and value at once.
*
* <pre>
* Equivalent to Memcached gets.
* </pre>
*
* @param mixed $key The key of the record
* @access public
* @return array The value of the record and version no
*/
public function gets($key)
{
list($message, $value, $version) = $this->_get($key, self::ID_GETS);
return array('value' => $value, 'version' => intval($version));
}
/**
* Check and set record.
*
* <pre>
* Equivalent to Memcached cas.
* </pre>
*
* @param mixed $key The key of the record
* @param mixed $value The value of the record
* @param array $tags Tags
* @param mixed $version Version no
* @access public
* @return mixed Fluent interface or false
*/
public function cas($key, $value, $version, array $tags = array())
{
return $this->_set($key, $value, self::ID_CAS, $tags, $version);
}
/**
* Remove a record.
*
* @param mixed $key The key of the record
* @access public
* @return bool true: Sucess to remove data, false: Fail to remove data
*/
public function remove($key)
{
if ($key === null || $key === '') {
$this->_rawData = null;
return false;
}
$command = self::ID_REMOVE . self::DATA_DELIMITER
. base64_encode($key) . self::DATA_DELIMITER
. self::TRANSACTION_CODE . "\n";
$response = $this->_parse($this->send($command)->response(), self::ID_REMOVE);
$result = array($response[1]);
if ($response[1] === 'true') {
if ($response[2] === self::BLANK_STRING) {
$result[] = '';
} else {
$result[] = base64_decode($response[2]);
}
$this->_rawData = $result;
return true;
} else if ($response[1] === 'false') {
$result[] = null;
} else {
$result[] = $response[2];
}
$this->_rawData = $result;
return false;
}
/**
* Get keys by tag.
*
* @param mixed $tag
* @param mixed $returns
* @access public
* @return mixed Tags or null
*/
public function getKeysByTag($tag, $returns = false)
{
if ($tag === null || $tag === false) {
$this->_rawData = null;
return null;
}
$command = self::ID_TAG_SET . self::DATA_DELIMITER
. base64_encode($tag) . self::DATA_DELIMITER;
$command = ($returns === true) ? $command . 'true' : $command . 'false';
$response = $this->_parse(
$this->send($command . "\n")->response(), self::ID_TAG_GET
);
$result = array($response[1], array());
if ($response[1] === 'true') {
$data = $response[2];
if ($data === self::BLANK_STRING) {
$this->_rawData = $result;
return null;
}
$tags = explode(self::TAG_DELIMITER, trim($data));
foreach ($tags as $v) {
$result[1][] = base64_decode($v);
}
$this->_rawData = $result;
return $result[1];
} else if ($response['1'] === 'false') {
$this->_rawData = $result;
return null;
}
throw new Net_Okuyama_Exception(sprintf('Unknown response(%s) return.', $response[2]));
}
/**
* Run JavaScript code.
*
* <pre>
* If you want to update value by script, use self::ID_UPDATE_SCRIPT.
* </pre>
*
* @param mixed $key The key of the record
* @param mixed $script JavaScript code to run
* @param mixed $update If true set, update the value of the record
* @access public
* @return string Result of JavaScript code evaluation
*/
public function playScript($key, $script, $update = false)
{
if ($key === null || $key === '') {
$this->_rawData = null;
return false;
}
$type = ($update === false) ? self::ID_PLAY_SCRIPT : self::ID_UPDATE_SCRIPT;
$command = $type . self::DATA_DELIMITER . base64_encode($key)
. self::DATA_DELIMITER . base64_encode($script) . "\n";
$response = $this->_parse($this->send($command)->response(), $type);
$result = array($response[1]);
if ($response[1] === 'true') {
$data = $response[2];
if ($data === self::BLANK_STRING) {
$result[] = '';
} else {
$result[] = base64_decode($data);
}
} else if ($response[1] === 'false' || $response[1] === 'error') {
$result[] = null;
$result[] = $response[2];
} else {
throw new Exception(
sprintf('Unknown response(%s) return.'), $response[2]
);
}
$this->_rawData = $result;
return $result[1];
}
/**
* Send data to server.
*
* @param mixed $value
* @access public
* @throws Net_Okuyama_Exception Fail to write data
* @return Net_Okuyama_Adapter_Socket Fluent interface
*/
public function send($value)
{
if (false === @fwrite($this->_socket, $value, strlen($value))) {
throw new Net_Okuyama_Exception('Error writing request.');
}
return $this;
}
/**
* Get data from socket.
*
* @access public
* @throws Net_Okuyama_Exception Fail to get data
* @return string Received socket data
*/
public function response()
{
if (false === ($result = @fgets($this->_socket))) {
throw new Net_Okuyama_Exception('Error getting response.');
}
return $result;
}
/**
* Get value by key string.
*
* @param mixed $key The key of the record
* @param mixed $type Get or gets
* @access private
* @return array Result of get command
*/
private function _get($key, $type = self::ID_GET)
{
$command = $type . self::DATA_DELIMITER . base64_encode($key) . "\n";
$response = $this->_parse($this->send($command)->response(), $type);
$result = array($response[1]);
if ($response[1] === 'true') {
if ($response[2] === self::BLANK_STRING) {
$result[] = '';
} else {
$result[] = base64_decode($response[2]);
}
if ($type === self::ID_GETS) {
$result[] = $response[3];
}
} else if ($response[1] === 'false') {
$result[] = null;
$result[] = $response[2];
} else if ($response[1] === 'error') {
$result[] = null;
$result[] = $response[2];
} else {
throw new Exception(
sprintf('Unknown response(%s) return.'), $response[2]
);
}
$this->_rawData = $result;
return $result;
}
/**
* Set|add value.
*
* @param mixed $key The key of the record
* @param mixed $value The value of the record
* @param array $tags Tags
* @access public
* @throws Net_Okuyama_Exception Overflow data size.
* @return Net_Okuyama_Adapter_Socket Fluent interface.
*/
private function _set($key, $value, $type = self::ID_SET, array $tags = array(), $version = null)
{
$tpl = '%s(%s) size is overflow, allow max size is %s.';
if (strlen($key) > $this->_maxSize) {
throw new Net_Okuyama_Exception(sprintf($tpl, 'Key string', $key, $this->_maxSize));
}
// Is null allowed??
if ($value === '' || $value === null) {
$value = self::BLANK_STRING;
} else {
if (strlen($value) > $this->_maxSize) {
throw new Net_Okuyama_Exception(sprintf('Values', $value, $this->_maxSize));
}
$value = base64_encode($value);
}
$command = $type . self::DATA_DELIMITER
. base64_encode($key) . self::DATA_DELIMITER;
if ($tags === array()) {
$command = $command . self::BLANK_STRING;
} else {
$buffer = '';
foreach ($tags as $tag) {
if (strlen($tag) > $this->_maxSize) {
throw new Net_Okuyamag_Exception(sprintf($tpl, 'Tag string', $tag, $this->axSize));
}
$buffer .= self::TAG_DELIMITER . base64_encode($tag);
}
$command = $command . ltrim($buffer, self::TAG_DELIMITER);
}
$command = $command . self::DATA_DELIMITER
. self::TRANSACTION_CODE . self::DATA_DELIMITER
. $value;
if ($type === self::ID_CAS && $version !== null && is_int($version)) {
$command = $command . self::DATA_DELIMITER . $version;
}
$command .= "\n";
$response = $this->_parse($this->send($command)->response(), $type);
if ($response[1] === 'true') {
$this->_rawData = array($response[1], $response[2]);
return $this;
} else if ($response[1] === 'false') {
$this->_rawData = array($response[1], $response[2]);
return false;
}
throw new Net_Okuyama_Exception($response[2]);
}
/**
* Parse response string.
*
* @param mixed $response Response string
* @param mixed $id Proccess id
* @access private
* @throws Net_Okuyama_Exception Proccess id is not excpted
* @return array Split delimiter response string
*/
private function _parse($response, $id)
{
$result = explode(self::DATA_DELIMITER, trim($response));
if ($result[0] === $id) {
return $result;
}
throw new Net_Okuyama_Exception('Execute violation of validity.');
}
/**
* Validate host format.
*
* @param mixed $host
* @access private
* @return bool true: Valid host|IP, false: Not valid host|IP
*/
private function _validateHostFormat($host)
{
$pattern = '/^[a-zA-Z0-9\.]+[:][0-9]+$/';
if (preg_match($pattern, $host, $match)) {
return true;
}
return false;
}
}
<?php
/**
* Spec of Net_Okuyama_Adapter_Socket.
*
* PHP version 5.2
*
* Copyright (c) 2011 Shinya Ohyanagi, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Shinya Ohyanagi nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @category Net
* @package Net_Okuyama
* @version $id$
* @copyright (c) 2011 Shinya Ohyanagi
* @author Shinya Ohyanagi <sohyanagi@gmail.com>
* @license New BSD License
*/
/**
* @see Net_Okuyama_Adapter_Socket
*/
require_once 'Socket.php';
/**
* Socket test.
*
* <pre>
* Before you run this test, make sure okuyama running.
* </pre>
*
* @category Net
* @package Net_Okuyama
* @version $id$
* @copyright (c) 2011 Shinya Ohyanagi
* @author Shinya Ohyanagi <sohyanagi@gmail.com>
* @license New BSD License
*/
class Net_Okuyama_SocketTest extends PHPUnit_Framework_TestCase
{
const KEY_PREFIX = 'Net_Okuyama_Test_';
const HOST = '127.0.0.1';
const PORT = 8888;
private $_client = null;
public function setUp()
{
$this->_client = new Net_Okuyama_Adapter_Socket();
}
public function testShouldCreateInstance()
{
$this->assertTrue($this->_client instanceof Net_Okuyama_Adapter_Socket);
}
public function testShouldConnectToHost()
{
$result = $this->_client->connect(self::HOST, self::PORT);
$this->assertInternalType('resource', $result);
$this->assertTrue($this->_client->close());
}
public function testShouldCloseConnection()
{
$result = $this->_client->connect(self::HOST, self::PORT);
$this->assertTrue($this->_client->close());
}
/**
* @expectedException Net_Okuyama_Exception
*/
public function testShouldThrowsExceptionWhenConnctionCloseFailed()
{
$this->_client->close();
}
public function testShouldConnectToHostAuto()
{
$hosts = array(
self::HOST . ':' . (self::PORT + 1),
self::HOST . ':' . self::PORT
);
$result = $this->_client->autoConnect($hosts);
$this->assertTrue($result);
$this->_client->close();
}
public function testShouldSetDataToServer()
{
$this->_client->connect(self::HOST, self::PORT);
$ret = $this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$this->assertTrue($ret instanceof Net_Okuyama_Adapter_Socket);
$value = $this->_client->get(self::KEY_PREFIX . 'foo');
$this->assertSame($value, 'bar');
$this->_client->close();
}
public function testShouldSetDataWithTag()
{
$this->_client->connect(self::HOST, self::PORT);
$tags = array('fiz', 'baz');
$this->_client->set(self::KEY_PREFIX . 'bar', 'foo', $tags)
->set(self::KEY_PREFIX . 'hoge', 'fuga', $tags)
->set(self::KEY_PREFIX . 'foo', 'bar', $tags);
$result = $this->_client->getKeysByTag('fiz');
$keys = array(
self::KEY_PREFIX . 'foo',
self::KEY_PREFIX . 'bar',
self::KEY_PREFIX . 'hoge',
);
foreach ($keys as $key) {
$this->assertTrue(in_array($key, $result));
}
$this->_client->close();
}
public function testShouldGetDataWithTag()
{
$this->_client->connect(self::HOST, self::PORT);
$tags = array('fiz', 'baz');
$this->_client->set(self::KEY_PREFIX . 'bar', 'foo', $tags)
->set(self::KEY_PREFIX . 'hoge', 'fuga', $tags)
->set(self::KEY_PREFIX . 'foo', 'bar', $tags);
$result = $this->_client->getKeysByTag('baz');
$keys = array(
self::KEY_PREFIX . 'foo',
self::KEY_PREFIX . 'bar',
self::KEY_PREFIX . 'hoge',
);
foreach ($keys as $key) {
$this->assertTrue(in_array($key, $result));
}
$this->_client->close();
}
public function testShouldReturnNullWhenTagNotExitsts()
{
$this->_client->connect(self::HOST, self::PORT);
$tags = array('fiz', 'baz');
$this->_client->set(self::KEY_PREFIX . 'bar', 'foo', $tags)
->set(self::KEY_PREFIX . 'hoge', 'fuga', $tags)
->set(self::KEY_PREFIX . 'foo', 'bar', $tags);
$result = $this->_client->getKeysByTag(self::KEY_PREFIX . 'baz' . rand(0, 1000));
$this->assertSame($result, null);
$this->_client->close();
}
public function testShouldReturnNullWhenArgReturnsSetFalse()
{
$this->_client->connect(self::HOST, self::PORT);
$tags = array('fiz', 'baz');
$this->_client->set(self::KEY_PREFIX . 'bar', 'foo', $tags)
->set(self::KEY_PREFIX . 'hoge', 'fuga', $tags)
->set(self::KEY_PREFIX . 'foo', 'bar', $tags);
$this->_client->remove(self::KEY_PREFIX . 'bar');
$this->_client->remove(self::KEY_PREFIX . 'hoge');
$this->_client->remove(self::KEY_PREFIX . 'foo');
$ret = $this->_client->get('bar');
$result = $this->_client->getKeysByTag('baz', false);
$this->assertSame($result, null);
$this->_client->close();
}
public function testShouldReturnKeyWhenArgReturnsSetTrue()
{
$this->_client->connect(self::HOST, self::PORT);
$tags = array('fiz', 'baz');
$this->_client->set(self::KEY_PREFIX . 'bar', 'foo', $tags)
->set(self::KEY_PREFIX . 'hoge', 'fuga', $tags)
->set(self::KEY_PREFIX . 'foo', 'bar', $tags);
$this->_client->remove(self::KEY_PREFIX . 'bar');
$this->_client->remove(self::KEY_PREFIX . 'hoge');
$this->_client->remove(self::KEY_PREFIX . 'foo');
$result = $this->_client->getKeysByTag('fiz', true);
$keys = array(
self::KEY_PREFIX . 'foo',
self::KEY_PREFIX . 'bar',
self::KEY_PREFIX . 'hoge',
);
foreach ($keys as $key) {
$this->assertTrue(in_array($key, $result));
}
$this->_client->close();
}
public function testShouldReturnTrueWhenDeleteSuccess()
{
$this->_client->connect(self::HOST, self::PORT);
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$ret = $this->_client->remove(self::KEY_PREFIX . 'foo');
$this->assertTrue($ret);
$value = $this->_client->get(self::KEY_PREFIX . 'foo');
$this->assertSame($value, null);
$this->_client->close();
}
public function testShouldReturnFalseWhenRemoveFalse()
{
$this->_client->connect(self::HOST, self::PORT);
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$ret = $this->_client->remove(self::KEY_PREFIX . 'foo');
$this->assertTrue($ret);
$ret = $this->_client->remove(self::KEY_PREFIX . 'foo');
$this->assertFalse($ret);
$this->_client->close();
}
public function testShouldAddData()
{
$this->_client->connect(self::HOST, self::PORT);
$ret = $this->_client->remove(self::KEY_PREFIX . 'baz');
$ret = $this->_client->add(self::KEY_PREFIX . 'baz', 'fiz');
$this->assertTrue($ret instanceof Net_Okuyama_Adapter_Socket);
$this->_client->close();
}
public function testShouldReturnFalseWhenDataAlreadyAdded()
{
$this->_client->connect(self::HOST, self::PORT);
$ret = $this->_client->remove(self::KEY_PREFIX . 'baz');
$this->_client->add(self::KEY_PREFIX . 'baz', 'fiz');
$ret = $this->_client->add(self::KEY_PREFIX . 'baz', 'fiz');
$this->assertFalse($ret);
$this->_client->close();
}
public function testShouldGetVersionNo()
{
$this->_client->connect(self::HOST, self::PORT);
$this->_client->remove(self::KEY_PREFIX . 'foo');
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$ret = $this->_client->gets(self::KEY_PREFIX . 'foo');
$this->assertRegExp('/^[0-9]+/', strval($ret['version']));
$this->_client->close();
}
public function testShouldCheackAndVersion()
{
$this->_client->connect(self::HOST, self::PORT);
$this->_client->remove(self::KEY_PREFIX . 'foo');
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$ret = $this->_client->gets(self::KEY_PREFIX . 'foo');
$ver = $ret['version'];
$this->_client->cas(self::KEY_PREFIX . 'foo', 'foo', $ret['version']);
$ret = $this->_client->gets(self::KEY_PREFIX . 'foo');
$this->assertSame($ret['value'], 'foo');
$this->assertNotSame($ret['version'], $ver);
$this->_client->close();
}
public function testShouldSetFailedWhenSetOldVersionNo()
{
$this->_client->connect(self::HOST, self::PORT);
$this->_client->remove(self::KEY_PREFIX . 'foo');
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$ret = $this->_client->gets(self::KEY_PREFIX . 'foo');
$this->_client->cas(self::KEY_PREFIX . 'foo', 'foo', $ret['version']);
$ver = $ret['version'];
$ret = $this->_client->gets(self::KEY_PREFIX . 'foo');
$this->assertNotSame($ret['version'], $ver);
$ver2 = $ret['version'];
$ret = $this->_client->cas(self::KEY_PREFIX . 'foo', 'baz', 0);
$this->assertFalse($ret);
$ret = $this->_client->gets(self::KEY_PREFIX . 'foo');
$this->assertSame($ret['version'], $ver2);
$this->_client->close();
}
public function testShouldRunJavaScriptCode()
{
$this->_client->connect(self::HOST, self::PORT);
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$script = <<<EOT
var dataValue;
var retValue = 'foo' + dataValue;
var execRet = '1';
EOT;
$ret = $this->_client->playScript(self::KEY_PREFIX . 'foo', $script);
$this->assertSame($ret, 'foobar');
$ret = $this->_client->get(self::KEY_PREFIX . 'foo');
$this->assertSame($ret, 'bar');
$this->_client->remove(self::KEY_PREFIX . 'foo');
$this->_client->close();
}
public function testShouldRunJavaScriptCodeAndUpdateValue()
{
$this->_client->connect(self::HOST, self::PORT);
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$script = <<<EOT
var dataValue;
var retValue = 'foo' + dataValue;
var execRet = '2';
EOT;
$ret = $this->_client->playScript(self::KEY_PREFIX . 'foo', $script, true);
$this->assertSame($ret, 'foobar');
$ret = $this->_client->get(self::KEY_PREFIX . 'foo');
$this->assertSame($ret, 'foobar');
$this->_client->remove(self::KEY_PREFIX . 'foo');
$this->_client->close();
}
public function testShouldGetRawData()
{
$this->_client->connect(self::HOST, self::PORT);
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertRegExp('/\d+/', $result[1]);
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertSame($result[1], 'OK');
$this->_client->get(self::KEY_PREFIX . 'foo');
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertSame($result[1], 'bar');
$tags = array('fiz', 'baz');
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar', $tags);
$this->_client->getKeysByTag('fiz');
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertSame($result[1], array(self::KEY_PREFIX . 'foo'));
$this->_client->remove(self::KEY_PREFIX . 'foo');
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$this->_client->gets(self::KEY_PREFIX . 'foo');
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertSame($result[1], 'bar');
$this->assertRegExp('/^[0-9]+/', $result[2]);
$ver = intval($result[2]);
$this->_client->cas(self::KEY_PREFIX . 'foo', 'foobar', $ver);
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertSame($result[1], 'OK');
$this->_client->gets(self::KEY_PREFIX . 'foo');
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertSame($result[1], 'foobar');
$this->assertNotSame(intval($result[2]), $ver);
$this->_client->remove(self::KEY_PREFIX . 'foo');
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertSame($result[1], 'foobar');
$this->_client->set(self::KEY_PREFIX . 'foo', 'bar');
$script = <<<EOT
var dataValue;
var retValue = 'foo' + dataValue;
var execRet = '1';
EOT;
$this->_client->playScript(self::KEY_PREFIX . 'foo', $script);
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertSame($result[1], 'foobar');
$script = <<<EOT
var retValue = 'foo';
var execRet = '2';
EOT;
$this->_client->playScript(self::KEY_PREFIX . 'foo', $script, true);
$result = $this->_client->getRawData();
$this->assertSame($result[0], 'true');
$this->assertSame($result[1], 'foo');
$this->_client->close();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment