Created
October 21, 2011 14:33
-
-
Save heavenshell/1303990 to your computer and use it in GitHub Desktop.
Net_Okuyama for PHP5.2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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