Compare commits

...

135 Commits

Author SHA1 Message Date
Daniele Alessandri f97312d683 Bump VERSION, update CHANGELOG and release. 2011-04-01 20:34:50 +02:00
Daniele Alessandri 17f83a5605 Fix random stuff. 2011-04-01 20:20:44 +02:00
Daniele Alessandri b1254a1375 Update README. 2011-04-01 00:17:49 +02:00
Daniele Alessandri 572fb292f1 Remove default support for long command names. 2011-03-31 22:00:45 +02:00
Daniele Alessandri 6301ae1402 Minor changes in Predis\ConnectionParameters. 2011-03-31 21:45:22 +02:00
Daniele Alessandri 7644d7fbeb Simple naming change. 2011-03-31 13:48:39 +02:00
Daniele Alessandri 72e117673e Slight change for more readable code. 2011-03-31 13:00:00 +02:00
Daniele Alessandri 6b7f47e087 Use a faster alternative to initialize the underlying connection resource. 2011-03-31 12:46:21 +02:00
Daniele Alessandri 434b9dd0f7 Switch to the new lightweight response reader. 2011-03-31 11:15:12 +02:00
Daniele Alessandri e5f010deb8 Fix ISSUE #27. 2011-03-30 23:45:18 +02:00
Daniele Alessandri 785d0f429f Some more random code improvements. 2011-03-30 22:33:54 +02:00
Daniele Alessandri 736a102aba Replace awful code with a nicer, compact and faster solution. 2011-03-30 21:44:41 +02:00
Daniele Alessandri 6b2697a133 Fix wrong class check (copy and paste is evil). 2011-03-30 18:31:34 +02:00
Daniele Alessandri b6b732ec51 Implement an optional lightweight protocol reader. 2011-03-30 13:22:30 +02:00
Daniele Alessandri 1bc891bed1 Update CHANGELOG. 2011-03-27 12:23:40 +02:00
Daniele Alessandri 1e47fb88f3 Fix SINTERSTORE and SUNIONSTORE to accept an array for the list of source keys. 2011-03-27 10:27:19 +02:00
Daniele Alessandri b882344840 Upgrade to PHPUnit 3.5. 2011-03-27 09:29:46 +02:00
Daniele Alessandri e5e8a19c7a Fix MGET, SINTER and SUNION to accept also an array to specify the list of keys. 2011-03-26 23:16:55 +01:00
Daniele Alessandri ffcbc4fdb1 Fix SUBSCRIBE and PSUBSCRIBE so that they can accept a list of channels for subscription. 2011-03-26 22:57:03 +01:00
Daniele Alessandri e398ff977e Switch to Redis 2.2 as the default server profile. 2011-03-20 16:12:14 +01:00
Daniele Alessandri 18b44fae53 Fix a couple of corner cases for Predis\MultiExecBlock. 2011-03-20 15:26:02 +01:00
Daniele Alessandri e800f1904b Remove trailing spaces. 2011-03-08 12:27:59 +01:00
Daniele Alessandri c73d0b375b Update CHANGELOG. 2011-03-08 12:18:44 +01:00
Daniele Alessandri 9f1f07083a Add a VERSION constant to Predis\Client. 2011-03-08 12:16:40 +01:00
Daniele Alessandri e1f8942569 Update CHANGELOG. 2011-03-06 15:15:10 +01:00
Daniele Alessandri 235d311cb1 Change network resource handling in the internals of Predis\Connection. 2011-03-06 15:03:07 +01:00
Daniele Alessandri c03ab9480e Adjust the tests for SUBSTR/GETRANGE since the return value for empty string slices has been fixed in Redis 2.2.2. 2011-03-06 12:47:39 +01:00
Daniele Alessandri 6f46fa1f2d Improve the parsing of replies to INFO. 2011-03-06 12:30:42 +01:00
Daniele Alessandri 798e2b18dc Implement Predis\Command::__toString(). 2011-03-06 11:21:32 +01:00
Daniele Alessandri aaa16c8276 Remove ConnectionParameters::__toString() (reverts ca6ff4f and e67cfe2). 2011-03-06 11:13:53 +01:00
Daniele Alessandri e700061cc0 Change Predis\Connection in order to disable read/write timeouts when the value of 'read_write_timeout' is also equal to 0. 2011-03-06 11:11:42 +01:00
Daniele Alessandri e67cfe27b3 Use a slightly different approach for ConnectionParameters::__toString(). 2011-03-05 16:42:22 +01:00
Daniele Alessandri e6e638b79e Update README. 2011-03-05 15:26:21 +01:00
Daniele Alessandri 96132ee50c Force the test suite to run on a client initialized with the Redis 2.2 profile for now. 2011-03-05 15:18:37 +01:00
Daniele Alessandri f36d7a1d56 Implement a new command class for INFO to parse the new reply format for this command in Redis > 2.2. 2011-03-05 15:15:10 +01:00
Daniele Alessandri ca6ff4f734 Implement ConnectionParameters::__toString(). 2011-03-05 13:49:58 +01:00
Daniele Alessandri bc0e29c1d2 Fix comment. 2011-03-05 12:41:34 +01:00
Daniele Alessandri 627c3a1724 Test suite: move the test suite safeguard flag to PredisShared.php. 2011-03-05 12:37:57 +01:00
Daniele Alessandri 06d974c0bc Allow passing an array for the list of source keys to be used in ZUNIONSTORE/ZINTERSTORE. 2011-03-05 12:33:04 +01:00
Daniele Alessandri 6b6edbe6c2 Add support for connecting to Redis with UNIX domain sockets. 2011-03-01 21:46:41 +01:00
Daniele Alessandri f76d616d57 Bump VERSION. 2011-02-12 21:49:30 +01:00
Daniele Alessandri c41bb2c314 Fix bug reading zero-length values from a bulk response. 2011-02-12 21:48:18 +01:00
Daniele Alessandri d4fb7d9143 Update VERSION. 2011-02-12 21:30:52 +01:00
Daniele Alessandri ca422b0300 Bump VERSION, update CHANGELOG and release. 2011-02-12 11:46:08 +01:00
Daniele Alessandri 79372cb99b Add inline (p)subscribe via options on Predis\PubSubContext initialization. 2011-02-12 11:43:37 +01:00
Daniele Alessandri 6a2e4d0396 Bump year in LICENSE file. 2011-01-26 16:25:05 +01:00
Daniele Alessandri 78814a473c Update CHANGELOG. 2011-01-26 16:24:50 +01:00
Daniele Alessandri 0d7fe31110 Minor indentation fix. 2011-01-26 16:24:34 +01:00
Daniele Alessandri 118af2809c Use only one check for replies that should not be passed to a reply parser. 2011-01-14 17:07:00 +01:00
Daniele Alessandri 8dcd10dbbc Fix missing registration for the Redis 2.2 profile. 2011-01-13 12:32:31 +01:00
Daniele Alessandri 3a6907241b Promote the profile for Redis 2.2 as stable (the default for the client is still 2.0). 2011-01-13 12:26:19 +01:00
Daniele Alessandri eae29bc3da Do not use is_numeric() when it is not really needed (it is relatively slow). 2011-01-13 12:18:24 +01:00
Daniele Alessandri 727feb3f27 Remove usage of constants in the protocol handlers. 2011-01-13 12:13:46 +01:00
Daniele Alessandri 3924235501 Apply minor changes. 2011-01-13 12:09:46 +01:00
Daniele Alessandri dc704c8cc4 Remove unused variables. 2011-01-13 12:07:54 +01:00
Daniele Alessandri 8d6f65d3dd Add the 'on_retry' callback as an option for Predis\MultiExecBlock. 2011-01-13 12:06:11 +01:00
Daniele Alessandri 40dfabb139 Do not perform useless read operations in the bulk reply handler. 2011-01-13 00:17:03 +01:00
Daniele Alessandri a605190354 Update README. 2011-01-06 11:49:15 +01:00
Daniele Alessandri b5ce81a030 Update CHANGELOG. 2011-01-06 11:40:39 +01:00
Daniele Alessandri a9e1d6b86b Reflect the status of the current branch. 2011-01-06 11:37:12 +01:00
Daniele Alessandri 923d998f35 Fix namespacing issue. 2011-01-06 00:59:12 +01:00
Daniele Alessandri eae8fb8971 Minor code style change. 2011-01-06 00:55:38 +01:00
Daniele Alessandri 4fc5ee65fd Look for a closing curly brace in a string only after the index of the opening one when using key tags. 2011-01-06 00:55:38 +01:00
Daniele Alessandri 007ddaecfa Optimize when a pair of curly brackets for key tagging is missing. 2011-01-06 00:55:38 +01:00
Daniele Alessandri 455e56927a Create a new class to handle the old response type of KEYS (Redis v1.2). 2011-01-06 00:55:38 +01:00
Daniele Alessandri 4b1302a93a Use a faster method to detect errors when reading a line from the server. 2011-01-06 00:55:00 +01:00
Daniele Alessandri d46b0e0785 Reuse code a bit. 2011-01-06 00:55:00 +01:00
Daniele Alessandri cf522ff2b4 Use a local cache for handlers while iterating chunks of a multi-bulk reply. 2011-01-06 00:54:10 +01:00
Daniele Alessandri db92c7a9b8 Reduce overhead by directly managing reply handlers for multibulk replies. 2011-01-06 00:54:10 +01:00
Daniele Alessandri 30926def60 Rewrite the bulk reply handler (more compact and faster code). 2011-01-06 00:54:10 +01:00
Daniele Alessandri 7465daa0eb More strict check of the length argument for a network read. 2011-01-06 00:52:56 +01:00
Daniele Alessandri 2c761d6c95 Remove a useless check for the payload length. 2011-01-06 00:52:56 +01:00
Daniele Alessandri 1e32f8aaa8 Use an explicit index to add values to the multi-bulk reply array. 2011-01-06 00:52:55 +01:00
Daniele Alessandri 2a25b0e3f3 Nothing fancy, and hardly an optimization. 2011-01-06 00:52:55 +01:00
Daniele Alessandri 5a6a48fa17 Avoid allocating an iterator to traverse the arguments list of a command. 2011-01-06 00:52:55 +01:00
Daniele Alessandri 64951b1799 Preallocate an empty array for empty command arguments. 2011-01-06 00:52:04 +01:00
Daniele Alessandri ec42796cb2 Bump version, update CHANGELOG, fasten seat belts and get ready for this new year release. 2011-01-01 18:49:46 +01:00
Daniele Alessandri c75bdd9509 Update README. 2011-01-01 17:14:08 +01:00
Daniele Alessandri 12c3e611a0 Update CHANGELOG. 2011-01-01 14:40:28 +01:00
Daniele Alessandri 0c9b822095 Code style changes only. 2011-01-01 13:49:55 +01:00
Daniele Alessandri 030d9740bd Cannot execute with a transaction block after using fluent interface style with Predis\MultiExecBlock. 2011-01-01 13:49:39 +01:00
Daniele Alessandri 0bbbe064b5 Improve fluent-interface style for transactions with CAS. 2011-01-01 13:49:39 +01:00
Daniele Alessandri 87439ae631 Cannot use the 'retry' option for transactions without providing a function block. 2011-01-01 13:49:39 +01:00
Daniele Alessandri d8c227e074 Add an example for MULTI/EXEC transactions using CAS. 2011-01-01 13:49:38 +01:00
Daniele Alessandri 7997eab57c Do not fail with empty transactions when using CAS. 2011-01-01 13:49:38 +01:00
Daniele Alessandri 2bc61ea0bc Update README. 2011-01-01 13:49:38 +01:00
Daniele Alessandri d667bcb6bb Fix and optimize WATCH with CAS. 2011-01-01 13:49:38 +01:00
Daniele Alessandri e3dd311dd3 Add support for optional automatic retries upon aborted transactions. 2011-01-01 13:49:08 +01:00
Daniele Alessandri 34f4d5584b Support DISCARD with CAS. 2011-01-01 13:49:08 +01:00
Daniele Alessandri 39619d0c54 Add support for check-and-set (CAS) for transactions with Predis\MultiExecBlock. 2011-01-01 13:49:08 +01:00
Daniele Alessandri 07a998ebdf Test suite: tiny fix in a test for LINSERT (again, this time for real). 2011-01-01 13:47:23 +01:00
Daniele Alessandri b73b9682c0 Test suite: tiny fix in a test for LINSERT. 2010-12-21 18:37:02 +01:00
Daniele Alessandri 355d6b6cf4 Update CHANGELOG. 2010-12-18 17:16:06 +01:00
Daniele Alessandri fe2316a655 Test suite: temporary fix for testSetExpire(). 2010-12-18 17:14:17 +01:00
Daniele Alessandri 7b2cd4abd0 Remove unused class. 2010-12-18 17:11:13 +01:00
Daniele Alessandri 35fd6ca509 New command: BRPOPLPUSH (Redis v2.2-dev). 2010-12-18 17:09:28 +01:00
Daniele Alessandri dea03a6aa9 Test suite: move up testStrlen(). 2010-12-18 16:53:31 +01:00
Daniele Alessandri fb5f878e21 New command: GETBIT (Redis v2.2-dev). 2010-12-18 16:53:26 +01:00
Daniele Alessandri e3ee595768 New command: SETBIT (Redis v2.2-dev). 2010-12-18 15:53:01 +01:00
Daniele Alessandri cc16311950 New command: SETRANGE (Redis v2.2-dev). 2010-12-18 13:11:59 +01:00
Daniele Alessandri f32cd19800 New command: GETRANGE (Redis v2.2-dev - replaces SUBSTR). 2010-12-18 12:36:04 +01:00
Daniele Alessandri 7db5e650ef Bump version and... release! 2010-11-28 20:23:39 +01:00
Daniele Alessandri 975bd98933 Update CHANGELOG. 2010-11-28 19:22:26 +01:00
Daniele Alessandri 7d5cccaf7c Overridden methods for UNWATCH and DISCARD in Predis\MultiExecBlock must return $this to not break method chaining. 2010-11-28 19:19:48 +01:00
Daniele Alessandri 08b1761e10 Fix a bunch of broken tests. 2010-11-28 17:21:46 +01:00
Daniele Alessandri 24f49abc14 Update CHANGELOG. 2010-11-28 16:54:02 +01:00
Daniele Alessandri b530f9f613 New command: PERSIST (Redis v2.2-dev). 2010-11-28 16:49:20 +01:00
Daniele Alessandri d677c72ae3 New command: ZREVRANGEBYSCORE (Redis v2.2-dev). 2010-11-28 16:39:07 +01:00
Daniele Alessandri c3cf2acb51 Update CHANGELOG. 2010-09-25 17:54:52 +02:00
Daniele Alessandri 8bfae69bf0 Make WATCH accept an array of keys that must be watched. 2010-09-25 17:52:23 +02:00
Daniele Alessandri 92d6ad62ce Test suite: add test for WATCH in Predis\MultiExecBlock. 2010-09-25 17:08:30 +02:00
Daniele Alessandri fa4d654d38 Update CHANGELOG. 2010-09-25 17:04:29 +02:00
Daniele Alessandri 9ac4571f91 Fix improper handling of a few corner cases for Predis\MultiExecBlock and send DISCARD to the server on uncaught exceptions inside a callable block. 2010-09-25 16:55:31 +02:00
Daniele Alessandri fea5e1c602 Test suite: add missing tests for Predis\MultiExecBlock. 2010-09-25 16:53:21 +02:00
Daniele Alessandri ec51b14fbb Fix an infinite recursion loop when calling Predis\Client::multiExec() (ISSUE #14). 2010-09-25 16:52:59 +02:00
Daniele Alessandri dc56526256 New commands: RPUSHX, LPUSHX (Redis v2.2-dev). 2010-09-25 16:38:16 +02:00
Daniele Alessandri 195c6eae99 New command: LINSERT (Redis v2.2-dev). 2010-09-25 16:34:18 +02:00
Daniele Alessandri 9ae47c865e New command: STRLEN (Redis v2.2-dev). 2010-09-25 16:31:35 +02:00
Daniele Alessandri d3ba25436c Slight micro-optimization. 2010-09-25 16:26:55 +02:00
Daniele Alessandri 580cf80436 Get the connection out of a cluster only once inside Predis\Client::getClientFor(). 2010-09-18 18:56:39 +02:00
Daniele Alessandri d6bea4390e Perform (p)unsubscribtion only if (p)subscribed to a channel when the destructor for Predis\PubSubContext is invoked. 2010-09-17 22:24:59 +02:00
Daniele Alessandri fd7f4a7b48 Make arguments handling more solid for the SORT command. 2010-09-17 22:11:37 +02:00
Daniele Alessandri 92f7e8bf9b Remove useless code duplication. 2010-09-17 21:56:31 +02:00
Daniele Alessandri 006b44e4bf Fix checks on the value for the STORE argument (ISSUE #13). 2010-09-17 11:36:47 +02:00
Daniele Alessandri bd961a767b Update CHANGELOG. It's release time! 2010-07-11 17:12:28 +02:00
Daniele Alessandri b3599a8e6b Update CHANGELOG. 2010-07-11 17:11:58 +02:00
Daniele Alessandri 0b46de424e Test suite: add a test for the LIMIT modifier of ZRANGEBYSCORE configured via associative array. 2010-07-11 17:02:33 +02:00
Daniele Alessandri 73bdfc2d72 Fix handling of the WEIGHT modifier for ZUNIONSTORE and ZINTERSTORE with more than two weights specified. 2010-07-11 16:35:03 +02:00
Daniele Alessandri 3077e76708 Update CHANGELOG. 2010-07-11 16:24:06 +02:00
Daniele Alessandri 208fdf6daf Update CHANGELOG. 2010-07-11 15:32:14 +02:00
Daniele Alessandri 7d7995ff8f Update CHANGELOG. 2010-07-07 20:07:15 +02:00
Daniele Alessandri 418197af75 Add tests for the new options handling for the ZRANGE commands family. 2010-07-07 19:59:16 +02:00
Daniele Alessandri 90cb9d437d Add support for the LIMIT modifier in ZRANGEBYSCORE. 2010-07-07 19:58:52 +02:00
Daniele Alessandri 4668bdca83 ZRANGE, ZREVRANGE and ZRANGEBYSCORE accepts an array instance for optional modifiers. 2010-07-07 19:58:41 +02:00
Daniele Alessandri 93a3c184ed Bump version number. 2010-07-02 22:31:39 +02:00
14 changed files with 2707 additions and 1136 deletions
+108 -12
View File
@@ -1,13 +1,106 @@
v0.6.1 (2010-xx-xx)
v0.6.6 (2011-04-01)
* Switched to Redis 2.2 as the default server profile (there are no changes
that would break compatibility with previous releases). Long command names
are no more supported by default but if you need them you can still require
Predis_Compatibility.php to avoid breaking compatibility.
* Added a VERSION constant to Predis\Client.
* Some performance improvements for multibulk replies (parsing them is about
16% faster than the previous version). A few core classes have been heavily
optimized to reduce overhead when creating new instances.
* Predis now uses by default a new protocol reader, more lightweight and
faster than the default handler-based one. Users can revert to the old
protocol reader with the 'reader' client option set to 'composable'.
This client option can also accept custom reader classes implementing the
new Predis\IResponseReader interface.
* Added support for connecting to Redis using UNIX domain sockets (ISSUE #25).
* The "read_write_timeout" connection parameter can now be set to 0 or false
to disable read and write timeouts on connections. The old behaviour of -1
is still intact.
* ZUNIONSTORE and ZINTERSTORE can accept an array to specify a list of the
source keys to be used to populate the destination key.
* MGET, SINTER, SUNION and SDIFF can accept an array to specify the list of
keys. SINTERSTORE, SUNIONSTORE and SDIFFSTORE can also accept an array to
specify the list of source keys.
* SUBSCRIBE and PSUBSCRIBE can accept a list of channels for subscription.
* FIX: some client-side clean-ups for MULTI/EXEC were handled incorrectly in
a couple of corner cases. See also ISSUE #27.
v0.6.5 (2011-02-12)
* FIX: due to an untested internal change introduced in v0.6.4, a wrong
handling of bulk reads of zero-length values was producing protocol
desynchronization errors (ISSUE #20).
v0.6.4 (2011-02-12)
* Various performance improvements (15% ~ 25%) especially when dealing with
long multibulk replies or when using clustered connections.
* Added the "on_retry" option to Predis\MultiExecBlock that can be used to
specify an external callback (or any callable object) that gets invoked
whenever a transaction is aborted by the server.
* Added inline (p)subscribtion via options when initializing an instance of
Predis\PubSubContext.
v0.6.3 (2011-01-01)
* New commands available in the Redis v2.2 profile (dev):
- Strings: SETRANGE, GETRANGE, SETBIT, GETBIT
- Lists : BRPOPLPUSH
* The abstraction for MULTI/EXEC transactions has been dramatically improved
by providing support for check-and-set (CAS) operations when using Redis >=
2.2. Aborted transactions can also be optionally replayed in automatic up
to a user-defined number of times, after which a Predis\AbortedMultiExec
exception is thrown.
v0.6.2 (2010-11-28)
* Minor internal improvements and clean ups.
* New commands available in the Redis v2.2 profile (dev):
- Strings: STRLEN
- Lists : LINSERT, RPUSHX, LPUSHX
- ZSets : ZREVRANGEBYSCORE
- Misc. : PERSIST
* WATCH also accepts a single array parameter with the keys that should be
monitored during a transaction.
* Improved the behaviour of Predis\MultiExecBlock in certain corner cases.
* Improved parameters checking for the SORT command.
* FIX: the STORE parameter for the SORT command didn't work correctly when
using '0' as the target key (ISSUE #13).
* FIX: the methods for UNWATCH and DISCARD do not break anymore method
chaining with Predis\MultiExecBlock.
v0.6.1 (2010-07-11)
* Minor internal improvements and clean ups.
* New commands available in the Redis v2.2 profile (dev):
- Misc. : WATCH, UNWATCH
* Minor internal improvements and clean ups.
* Optional modifiers for ZRANGE, ZREVRANGE and ZRANGEBYSCORE queries are
supported using an associative array passed as the last argument of their
respective methods.
* The constructor of Predis\Client::__construct now accepts also instances
of Predis\ConnectionParameters.
* The LIMIT modifier for ZRANGEBYSCORE can be specified using either:
- an indexed array: array($offset, $count)
- an associative array: array('offset' => $offset, 'count' => $count)
* Predis\MultiExecBlock and Predis\PubSubContext will throw an exception
* The method Predis\Client::__construct() now accepts also instances of
Predis\ConnectionParameters.
* Predis\MultiExecBlock and Predis\PubSubContext now throw an exception
when trying to create their instances using a profile that does not
support the required Redis commands or when the client is connected to
a cluster of connections.
@@ -17,14 +110,17 @@ v0.6.1 (2010-xx-xx)
- support for WATCH and UNWATCH when using the current development
profile (Redis v2.2) and aborted transactions.
* New method signature for Predis\Client::multiExec(). Now it is able to
accept an array of options for the underlying Predis\MultiExecBlock, but
it is still backwards compatible with previous releases of Predis.
* New signature for Predis\Client::multiExec() which is now able to accept
an array of options for the underlying instance of Predis\MultiExecBlock.
Backwards compatibility with previous releases of Predis is ensured.
* New method signature for Predis\Client::pipeline(). Now it is able to
accept an array of options for the underlying Predis\CommandPipeline,
but it is still backwards compatible with previous releases of Predis.
Predis\Client::pipelineSafe() is to be considered obsolete.
* New signature for Predis\Client::pipeline() which is now able to accept
an array of options for the underlying instance of Predis\CommandPipeline.
Backwards compatibility with previous releases of Predis is ensured.
The method Predis\Client::pipelineSafe() is to be considered deprecated.
* FIX: The WEIGHT modifier for ZUNIONSTORE and ZINTERSTORE was handled
incorrectly with more than two weights specified.
v0.6.0 (2010-05-24)
* Switched to the new multi-bulk request protocol for all of the commands
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2009-2010 Daniele Alessandri
Copyright (c) 2009-2011 Daniele Alessandri
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
+5 -3
View File
@@ -17,10 +17,12 @@ to be implemented soon in Predis.
## Main features ##
- Full support for Redis 2.0. Different versions of Redis are supported via server profiles.
- Full support for Redis 2.0 and 2.2. Different versions of Redis are supported via server profiles.
- Client-side sharding (support for consistent hashing and custom distribution strategies).
- Command pipelining on single and multiple connections (transparent).
- Abstraction for Redis transactions (>= 2.0) with support for CAS operations (>= 2.2).
- Lazy connections (connections to Redis instances are only established just in time).
- Ability to connect to Redis using TCP/IP or UNIX domain sockets.
- Flexible system to define and register your own set of commands to a client instance.
@@ -60,10 +62,10 @@ Furthermore, a pipeline can be initialized on a cluster of redis instances in th
same exact way they are created on single connection. Sharding is still transparent
to the user:
$redis = Predis\Client::create(
$redis = new Predis\Client(array(
array('host' => '10.0.0.1', 'port' => 6379),
array('host' => '10.0.0.2', 'port' => 6379)
);
));
$replies = $redis->pipeline(function($pipe) {
for ($i = 0; $i < 1000; $i++) {
+1 -1
View File
@@ -1 +1 @@
0.6.0
0.6.6
+1 -1
View File
@@ -3,7 +3,7 @@ require_once 'SharedConfigurations.php';
// Developers can customize the distribution strategy used by the client
// to distribute keys among a cluster of servers simply by creating a class
// that implements the Predis\Distribution\IDistributionAlgorithm interface.
// that implements the Predis\Distribution\IDistributionStrategy interface.
class NaiveDistributionStrategy
implements Predis\Distribution\IDistributionStrategy {
+41
View File
@@ -0,0 +1,41 @@
<?php
require_once 'SharedConfigurations.php';
/*
This is an implementation of an atomic client-side ZPOP using the support for
check-and-set (CAS) operations with MULTI/EXEC transactions, as described in
"WATCH explained" from http://redis.io/topics/transactions
First, populate your database with a tiny sample data set:
./redis-cli
SELECT 15
ZADD zset 1 a
ZADD zset 2 b
ZADD zset 3 c
*/
function zpop($client, $zsetKey) {
$element = null;
$options = array(
'cas' => true, // Initialize with support for CAS operations
'watch' => $zsetKey, // Key that needs to be WATCHed to detect changes
'retry' => 3, // Number of retries on aborted transactions, after
// which the client bails out with an exception.
);
$txReply = $client->multiExec($options, function($tx)
use ($zsetKey, &$element) {
@list($element) = $tx->zrange($zsetKey, 0, 0);
if (isset($element)) {
$tx->multi(); // With CAS, MULTI *must* be explicitly invoked.
$tx->zrem($zsetKey, $element);
}
});
return $element;
}
$redis = new Predis\Client($single_server, 'dev');
$zpopped = zpop($redis, 'zset');
echo isset($zpopped) ? "ZPOPed $zpopped" : "Nothing to ZPOP!", "\n";
?>
+1 -1
View File
@@ -5,7 +5,7 @@ require_once 'SharedConfigurations.php';
// events published on certain channels (PUBSUB).
// Create a client and disable r/w timeout on the socket
$redis = new Predis\Client($single_server + array('read_write_timeout' => -1));
$redis = new Predis\Client($single_server + array('read_write_timeout' => 0));
// Initialize a new pubsub context
$pubsub = $redis->pubSubContext();
+1099 -528
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+15
View File
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="test/bootstrap.php">
<testsuites>
<testsuite name="Predis Test Suite">
<directory>test/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">lib/Predis/</directory>
</whitelist>
</filter>
</phpunit>
@@ -1,19 +1,14 @@
<?php
define('I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE', false);
require_once 'PHPUnit/Framework.php';
require_once 'PredisShared.php';
require_once '../lib/Predis_Compatibility.php';
class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
class ClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
public $redis;
protected function setUp() {
protected function setUp() {
$this->redis = RC::getConnection();
$this->redis->flushDatabase();
$this->redis->flushdb();
}
protected function tearDown() {
protected function tearDown() {
}
protected function onNotSuccessfulTest(Exception $exception) {
@@ -89,7 +84,7 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
function testCommand_InlineWithNoArguments() {
$cmd = new \Predis\Compatibility\v1_0\Commands\Ping();
$this->assertType('\Predis\InlineCommand', $cmd);
$this->assertInstanceOf('\Predis\InlineCommand', $cmd);
$this->assertEquals('PING', $cmd->getCommandId());
$this->assertFalse($cmd->closesConnection());
$this->assertFalse($cmd->canBeHashed());
@@ -101,7 +96,7 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$cmd = new \Predis\Compatibility\v1_0\Commands\Get();
$cmd->setArgumentsArray(array('key'));
$this->assertType('\Predis\InlineCommand', $cmd);
$this->assertInstanceOf('\Predis\InlineCommand', $cmd);
$this->assertEquals('GET', $cmd->getCommandId());
$this->assertFalse($cmd->closesConnection());
$this->assertTrue($cmd->canBeHashed());
@@ -113,7 +108,7 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$cmd = new \Predis\Compatibility\v1_0\Commands\Set();
$cmd->setArgumentsArray(array('key', 'value'));
$this->assertType('\Predis\BulkCommand', $cmd);
$this->assertInstanceOf('\Predis\BulkCommand', $cmd);
$this->assertEquals('SET', $cmd->getCommandId());
$this->assertFalse($cmd->closesConnection());
$this->assertTrue($cmd->canBeHashed());
@@ -125,7 +120,7 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$cmd = new \Predis\Commands\SetMultiple();
$cmd->setArgumentsArray(array('key1', 'value1', 'key2', 'value2'));
$this->assertType('\Predis\MultiBulkCommand', $cmd);
$this->assertInstanceOf('\Predis\MultiBulkCommand', $cmd);
$this->assertEquals('MSET', $cmd->getCommandId());
$this->assertFalse($cmd->closesConnection());
$this->assertFalse($cmd->canBeHashed());
@@ -155,11 +150,11 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
/* RedisServerProfile and derivates */
function testRedisServerProfile_GetSpecificVersions() {
$this->assertType('\Predis\RedisServer_v1_0', \Predis\RedisServerProfile::get('1.0'));
$this->assertType('\Predis\RedisServer_v1_2', \Predis\RedisServerProfile::get('1.2'));
$this->assertType('\Predis\RedisServer_v2_0', \Predis\RedisServerProfile::get('2.0'));
$this->assertType('\Predis\RedisServer_vNext', \Predis\RedisServerProfile::get('dev'));
$this->assertType('\Predis\RedisServerProfile', \Predis\RedisServerProfile::get('default'));
$this->assertInstanceOf('\Predis\RedisServer_v1_0', \Predis\RedisServerProfile::get('1.0'));
$this->assertInstanceOf('\Predis\RedisServer_v1_2', \Predis\RedisServerProfile::get('1.2'));
$this->assertInstanceOf('\Predis\RedisServer_v2_0', \Predis\RedisServerProfile::get('2.0'));
$this->assertInstanceOf('\Predis\RedisServer_vNext', \Predis\RedisServerProfile::get('dev'));
$this->assertInstanceOf('\Predis\RedisServerProfile', \Predis\RedisServerProfile::get('default'));
$this->assertEquals(\Predis\RedisServerProfile::get('default'), \Predis\RedisServerProfile::getDefault());
}
@@ -181,12 +176,12 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$profile = \Predis\RedisServerProfile::get('1.0');
$cmdNoArgs = $profile->createCommand('info');
$this->assertType('\Predis\Compatibility\v1_0\Commands\Info', $cmdNoArgs);
$this->assertInstanceOf('\Predis\Compatibility\v1_0\Commands\Info', $cmdNoArgs);
$this->assertNull($cmdNoArgs->getArgument());
$args = array('key1', 'key2');
$cmdWithArgs = $profile->createCommand('mget', $args);
$this->assertType('\Predis\Compatibility\v1_0\Commands\GetMultiple', $cmdWithArgs);
$this->assertInstanceOf('\Predis\Compatibility\v1_0\Commands\GetMultiple', $cmdWithArgs);
$this->assertEquals($args[0], $cmdWithArgs->getArgument()); // TODO: why?
$this->assertEquals($args[0], $cmdWithArgs->getArgument(0));
$this->assertEquals($args[1], $cmdWithArgs->getArgument(1));
@@ -208,7 +203,7 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$this->assertFalse($profile->supportsCommand($cmdId));
$profile->registerCommand(new $cmdClass(), $cmdId);
$this->assertTrue($profile->supportsCommand($cmdId));
$this->assertType($cmdClass, $profile->createCommand($cmdId));
$this->assertInstanceOf($cmdClass, $profile->createCommand($cmdId));
}
@@ -216,6 +211,7 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
function testResponseQueued() {
$response = new \Predis\ResponseQueued();
$this->assertTrue($response->skipParse);
$this->assertTrue($response->queued);
$this->assertEquals(\Predis\Protocol::QUEUED, (string)$response);
}
@@ -227,6 +223,7 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$errorMessage = 'ERROR MESSAGE';
$response = new \Predis\ResponseError($errorMessage);
$this->assertTrue($response->skipParse);
$this->assertTrue($response->error);
$this->assertEquals($errorMessage, $response->message);
$this->assertEquals($errorMessage, (string)$response);
@@ -261,23 +258,26 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
function testConnection_WriteCommandAndCloseConnection() {
$cmd = \Predis\RedisServerProfile::getDefault()->createCommand('quit');
$connection = new \Predis\Connection(RC::getConnectionParameters());
$connection->connect();
$connection = new \Predis\Connection(new \Predis\ConnectionParameters(
RC::getConnectionArguments() + array('read_write_timeout' => 0.5)
));
$connection->connect();
$this->assertTrue($connection->isConnected());
$connection->writeCommand($cmd);
$connection->disconnect();
$exceptionMessage = 'Error while reading line from the server';
RC::testForCommunicationException($this, $exceptionMessage, function() use($connection, $cmd) {
$connection->readResponse($cmd);
});
//$this->assertFalse($connection->isConnected());
}
function testConnection_GetSocketOpensConnection() {
$connection = new \Predis\Connection(RC::getConnectionParameters());
$this->assertFalse($connection->isConnected());
$this->assertType('resource', $connection->getSocket());
$this->assertInternalType('resource', $connection->getSocket());
$this->assertTrue($connection->isConnected());
}
@@ -336,39 +336,26 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
function testResponseReader_OptionIterableMultiBulkReplies() {
$connection = new \Predis\Connection(RC::getConnectionParameters());
$responseReader = $connection->getResponseReader();
$responseReader->setHandler(
\Predis\Protocol::PREFIX_MULTI_BULK,
new \Predis\ResponseMultiBulkHandler()
);
$this->assertType('array', $connection->rawCommand("KEYS *\r\n"));
$connection->getResponseReader()->setOption('iterable_multibulk', false);
$this->assertInternalType('array', $connection->rawCommand("KEYS *\r\n"));
$responseReader->setHandler(
\Predis\Protocol::PREFIX_MULTI_BULK,
new \Predis\ResponseMultiBulkStreamHandler()
);
$this->assertType('\Iterator', $connection->rawCommand("KEYS *\r\n"));
$connection->getResponseReader()->setOption('iterable_multibulk', true);
$this->assertInstanceOf('\Iterator', $connection->rawCommand("KEYS *\r\n"));
}
function testResponseReader_OptionExceptionOnError() {
$connection = new \Predis\Connection(RC::getConnectionParameters());
$responseReader = $connection->getResponseReader();
$connection->rawCommand("SET key 5\r\nvalue\r\n");
$rawCmdUnexpected = "LPUSH key 5\r\nvalue\r\n";
$connection->rawCommand("*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n");
$rawCmdUnexpected = "*3\r\n$5\r\nLPUSH\r\n$3\r\nkey\r\n$5\r\nvalue\r\n";
$responseReader->setHandler(
\Predis\Protocol::PREFIX_ERROR,
new \Predis\ResponseErrorSilentHandler()
);
$responseReader->setOption('throw_on_error', false);
$errorReply = $connection->rawCommand($rawCmdUnexpected);
$this->assertType('\Predis\ResponseError', $errorReply);
$this->assertInstanceOf('\Predis\ResponseError', $errorReply);
$this->assertEquals(RC::EXCEPTION_WRONG_TYPE, $errorReply->message);
$responseReader->setHandler(
\Predis\Protocol::PREFIX_ERROR,
new \Predis\ResponseErrorHandler()
);
$responseReader->setOption('throw_on_error', true);
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function()
use ($connection, $rawCmdUnexpected) {
@@ -376,6 +363,12 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
});
}
function testResponseReader_EmptyBulkResponse() {
$this->assertTrue($this->redis->set('foo', ''));
$this->assertEquals('', $this->redis->get('foo'));
$this->assertEquals('', $this->redis->get('foo'));
}
/* Client + CommandPipeline */
@@ -385,18 +378,18 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$pipe = $client->pipeline();
$this->assertType('\Predis\CommandPipeline', $pipe);
$this->assertType('\Predis\CommandPipeline', $pipe->set('foo', 'bar'));
$this->assertType('\Predis\CommandPipeline', $pipe->set('hoge', 'piyo'));
$this->assertType('\Predis\CommandPipeline', $pipe->mset(array(
$this->assertInstanceOf('\Predis\CommandPipeline', $pipe);
$this->assertInstanceOf('\Predis\CommandPipeline', $pipe->set('foo', 'bar'));
$this->assertInstanceOf('\Predis\CommandPipeline', $pipe->set('hoge', 'piyo'));
$this->assertInstanceOf('\Predis\CommandPipeline', $pipe->mset(array(
'foofoo' => 'barbar', 'hogehoge' => 'piyopiyo'
)));
$this->assertType('\Predis\CommandPipeline', $pipe->mget(array(
$this->assertInstanceOf('\Predis\CommandPipeline', $pipe->mget(array(
'foo', 'hoge', 'foofoo', 'hogehoge'
)));
$replies = $pipe->execute();
$this->assertType('array', $replies);
$this->assertInternalType('array', $replies);
$this->assertEquals(4, count($replies));
$this->assertEquals(4, count($replies[3]));
$this->assertEquals('barbar', $replies[3][2]);
@@ -407,7 +400,7 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$client->flushdb();
$replies = $client->pipeline()->ping()->set('foo', 'bar')->get('foo')->execute();
$this->assertType('array', $replies);
$this->assertInternalType('array', $replies);
$this->assertEquals('bar', $replies[2]);
}
@@ -415,13 +408,13 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$client = RC::getConnection();
$client->flushdb();
$replies = $client->pipeline(function($pipe) {
$replies = $client->pipeline(function($pipe) {
$pipe->ping();
$pipe->set('foo', 'bar');
$pipe->get('foo');
});
$this->assertType('array', $replies);
$this->assertInternalType('array', $replies);
$this->assertEquals('bar', $replies[2]);
}
@@ -430,7 +423,7 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$client->flushdb();
RC::testForClientException($this, 'TEST', function() use($client) {
$client->pipeline(function($pipe) {
$client->pipeline(function($pipe) {
$pipe->ping();
$pipe->set('foo', 'bar');
throw new \Predis\ClientException("TEST");
@@ -442,16 +435,16 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
function testCommandPipeline_ServerExceptionInCallableBlock() {
$client = RC::getConnection();
$client->flushdb();
$client->getResponseReader()->setHandler('-', new \Predis\ResponseErrorSilentHandler());
$client->getResponseReader()->setOption('throw_on_error', false);
$replies = $client->pipeline(function($pipe) {
$replies = $client->pipeline(function($pipe) {
$pipe->set('foo', 'bar');
$pipe->lpush('foo', 'piyo'); // LIST operation on STRING type returns an ERROR
$pipe->set('hoge', 'piyo');
});
$this->assertType('array', $replies);
$this->assertType('\Predis\ResponseError', $replies[1]);
$this->assertInternalType('array', $replies);
$this->assertInstanceOf('\Predis\ResponseError', $replies[1]);
$this->assertTrue($client->exists('foo'));
$this->assertTrue($client->exists('hoge'));
}
@@ -466,10 +459,285 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
$pipe->ping()->mget(array('foo', 'hoge'));
$replies = $pipe->execute();
$this->assertType('array', $replies);
$this->assertInternalType('array', $replies);
$this->assertEquals(4, count($replies));
$this->assertEquals('bar', $replies[3][0]);
$this->assertEquals('piyo', $replies[3][1]);
}
/* Client + MultiExecBlock */
function testMultiExecBlock_Simple() {
$client = RC::getConnection();
$client->flushdb();
$multi = $client->multiExec();
$this->assertInstanceOf('\Predis\MultiExecBlock', $multi);
$this->assertInstanceOf('\Predis\MultiExecBlock', $multi->set('foo', 'bar'));
$this->assertInstanceOf('\Predis\MultiExecBlock', $multi->set('hoge', 'piyo'));
$this->assertInstanceOf('\Predis\MultiExecBlock', $multi->mset(array(
'foofoo' => 'barbar', 'hogehoge' => 'piyopiyo'
)));
$this->assertInstanceOf('\Predis\MultiExecBlock', $multi->mget(array(
'foo', 'hoge', 'foofoo', 'hogehoge'
)));
$replies = $multi->execute();
$this->assertInternalType('array', $replies);
$this->assertEquals(4, count($replies));
$this->assertEquals(4, count($replies[3]));
$this->assertEquals('barbar', $replies[3][2]);
}
function testMultiExecBlock_FluentInterface() {
$client = RC::getConnection();
$client->flushdb();
$replies = $client->multiExec()->ping()->set('foo', 'bar')->get('foo')->execute();
$this->assertInternalType('array', $replies);
$this->assertEquals('bar', $replies[2]);
}
function testMultiExecBlock_CallableAnonymousBlock() {
$client = RC::getConnection();
$client->flushdb();
$replies = $client->multiExec(function($multi) {
$multi->ping();
$multi->set('foo', 'bar');
$multi->get('foo');
});
$this->assertInternalType('array', $replies);
$this->assertEquals('bar', $replies[2]);
}
/**
* @expectedException Predis\ClientException
*/
function testMultiExecBlock_CannotMixFluentInterfaceAndAnonymousBlock() {
$emptyBlock = function($tx) { };
$tx = RC::getConnection()->multiExec()->get('foo')->execute($emptyBlock);
}
function testMultiExecBlock_EmptyCallableBlock() {
$client = RC::getConnection();
$client->flushdb();
$replies = $client->multiExec(function($multi) { });
$this->assertEquals(0, count($replies));
$options = array('cas' => true);
$replies = $client->multiExec($options, function($multi) { });
$this->assertEquals(0, count($replies));
$options = array('cas' => true);
$replies = $client->multiExec($options, function($multi) {
$multi->multi();
});
$this->assertEquals(0, count($replies));
}
function testMultiExecBlock_ClientExceptionInCallableBlock() {
$client = RC::getConnection();
$client->flushdb();
RC::testForClientException($this, 'TEST', function() use($client) {
$client->multiExec(function($multi) {
$multi->ping();
$multi->set('foo', 'bar');
throw new \Predis\ClientException("TEST");
});
});
$this->assertFalse($client->exists('foo'));
}
function testMultiExecBlock_ServerExceptionInCallableBlock() {
$client = RC::getConnection();
$client->flushdb();
$client->getResponseReader()->setOption('throw_on_error', false);
$replies = $client->multiExec(function($multi) {
$multi->set('foo', 'bar');
$multi->lpush('foo', 'piyo'); // LIST operation on STRING type returns an ERROR
$multi->set('hoge', 'piyo');
});
$this->assertInternalType('array', $replies);
$this->assertInstanceOf('\Predis\ResponseError', $replies[1]);
$this->assertTrue($client->exists('foo'));
$this->assertTrue($client->exists('hoge'));
}
function testMultiExecBlock_Discard() {
$client = RC::getConnection();
$client->flushdb();
$replies = $client->multiExec(function($multi) {
$multi->set('foo', 'bar');
$multi->discard();
$multi->set('hoge', 'piyo');
});
$this->assertEquals(1, count($replies));
$this->assertFalse($client->exists('foo'));
$this->assertTrue($client->exists('hoge'));
}
function testMultiExecBlock_DiscardEmpty() {
$client = RC::getConnection();
$client->flushdb();
$replies = $client->multiExec(function($multi) {
$multi->discard();
});
$this->assertEquals(0, count($replies));
}
function testMultiExecBlock_Watch() {
$client1 = RC::getConnection();
$client2 = RC::getConnection(true);
$client1->flushdb();
RC::testForAbortedMultiExecException($this, function()
use($client1, $client2) {
$client1->multiExec(array('watch' => 'sentinel'), function($multi)
use ($client2) {
$multi->set('sentinel', 'client1');
$multi->get('sentinel');
$client2->set('sentinel', 'client2');
});
});
$this->assertEquals('client2', $client1->get('sentinel'));
}
function testMultiExecBlock_CheckAndSet() {
$client = RC::getConnection();
$client->flushdb();
$client->set('foo', 'bar');
$options = array('watch' => 'foo', 'cas' => true);
$replies = $client->multiExec($options, function($tx) {
$tx->watch('foobar');
$foo = $tx->get('foo');
$tx->multi();
$tx->set('foobar', $foo);
$tx->mget('foo', 'foobar');
});
$this->assertInternalType('array', $replies);
$this->assertEquals(array(true, array('bar', 'bar')), $replies);
$tx = $client->multiExec($options);
$tx->watch('foobar');
$foo = $tx->get('foo');
$replies = $tx->multi()
->set('foobar', $foo)
->mget('foo', 'foobar')
->execute();
$this->assertInternalType('array', $replies);
$this->assertEquals(array(true, array('bar', 'bar')), $replies);
}
function testMultiExecBlock_RetryOnServerAbort() {
$client1 = RC::getConnection();
$client2 = RC::getConnection(true);
$client1->flushdb();
$retry = 3;
$attempts = 0;
RC::testForAbortedMultiExecException($this, function()
use($client1, $client2, $retry, &$attempts) {
$options = array('watch' => 'sentinel', 'retry' => $retry);
$client1->multiExec($options, function($tx)
use ($client2, &$attempts) {
$attempts++;
$tx->set('sentinel', 'client1');
$tx->get('sentinel');
$client2->set('sentinel', 'client2');
});
});
$this->assertEquals('client2', $client1->get('sentinel'));
$this->assertEquals($retry + 1, $attempts);
$retry = 3;
$attempts = 0;
RC::testForAbortedMultiExecException($this, function()
use($client1, $client2, $retry, &$attempts) {
$options = array(
'watch' => 'sentinel',
'cas' => true,
'retry' => $retry
);
$client1->multiExec($options, function($tx)
use ($client2, &$attempts) {
$attempts++;
$tx->incr('attempts');
$tx->multi();
$tx->set('sentinel', 'client1');
$tx->get('sentinel');
$client2->set('sentinel', 'client2');
});
});
$this->assertEquals('client2', $client1->get('sentinel'));
$this->assertEquals($retry + 1, $attempts);
$this->assertEquals($attempts, $client1->get('attempts'));
}
/**
* @expectedException InvalidArgumentException
*/
function testMultiExecBlock_RetryNotAvailableWithoutBlock() {
$options = array('watch' => 'foo', 'retry' => 1);
$tx = RC::getConnection()->multiExec($options);
$tx->multi()->get('foo')->exec();
}
function testMultiExecBlock_CheckAndSet_Discard() {
$client = RC::getConnection();
$client->flushdb();
$client->set('foo', 'bar');
$options = array('watch' => 'foo', 'cas' => true);
$replies = $client->multiExec($options, function($tx) {
$tx->watch('foobar');
$foo = $tx->get('foo');
$tx->multi();
$tx->set('foobar', $foo);
$tx->discard();
$tx->mget('foo', 'foobar');
});
$this->assertInternalType('array', $replies);
$this->assertEquals(array(array('bar', null)), $replies);
$hijack = true;
$client->set('foo', 'bar');
$client2 = RC::getConnection(true);
$options = array('watch' => 'foo', 'cas' => true, 'retry' => 1);
$replies = $client->multiExec($options, function($tx)
use ($client2, &$hijack) {
$foo = $tx->get('foo');
$tx->multi();
$tx->set('foobar', $foo);
$tx->discard();
if ($hijack) {
$hijack = false;
$client2->set('foo', 'hijacked!');
}
$tx->mget('foo', 'foobar');
});
$this->assertInternalType('array', $replies);
$this->assertEquals(array(array('hijacked!', null)), $replies);
}
}
?>
+40 -11
View File
@@ -1,12 +1,23 @@
<?php
require_once '../lib/Predis.php';
// -------------------------------------------------------------------------- //
define('I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE', false);
// -------------------------------------------------------------------------- //
if (I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE !== true) {
exit('Please set the I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE constant to TRUE if you want to proceed.');
exit(
"Please set the I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE " .
"constant to TRUE in PredisShared.php if you want to proceed.\n"
);
}
Predis\RedisServerProfile::registerProfile('\Predis\RedisServer_v1_2', '1.2');
Predis\RedisServerProfile::registerProfile('\Predis\RedisServer_v2_0', '2.0');
Predis\RedisServerProfile::registerProfile('\Predis\RedisServer_v2_2', '2.2');
if (!function_exists('array_union')) {
function array_union(Array $a, Array $b) {
function array_union(Array $a, Array $b) {
return array_merge($a, array_diff($b, $a));
}
}
@@ -20,31 +31,37 @@ class RC {
const EXCEPTION_WRONG_TYPE = 'Operation against a key holding the wrong kind of value';
const EXCEPTION_NO_SUCH_KEY = 'no such key';
const EXCEPTION_OUT_OF_RANGE = 'index out of range';
const EXCEPTION_OFFSET_RANGE = 'offset is out of range';
const EXCEPTION_INVALID_DB_IDX = 'invalid DB index';
const EXCEPTION_VALUE_NOT_INT = 'value is not an integer';
const EXCEPTION_EXEC_NO_MULTI = 'EXEC without MULTI';
const EXCEPTION_SETEX_TTL = 'invalid expire time in SETEX';
const EXCEPTION_HASH_VALNOTINT = 'hash value is not an integer';
const EXCEPTION_BIT_VALUE = 'bit is not an integer or out of range';
const EXCEPTION_BIT_OFFSET = 'bit offset is not an integer or out of range';
private static $_connection;
public static function getConnectionArguments() {
public static function getConnectionArguments() {
return array('host' => RC::SERVER_HOST, 'port' => RC::SERVER_PORT);
}
public static function getConnectionParameters() {
public static function getConnectionParameters() {
return new Predis\ConnectionParameters(array('host' => RC::SERVER_HOST, 'port' => RC::SERVER_PORT));
}
private static function createConnection() {
$serverProfile = Predis\RedisServerProfile::get('dev');
$serverProfile = Predis\RedisServerProfile::get('2.2');
$connection = new Predis\Client(RC::getConnectionArguments(), $serverProfile);
$connection->connect();
$connection->select(RC::DEFAULT_DATABASE);
return $connection;
}
public static function getConnection() {
public static function getConnection($new = false) {
if ($new == true) {
return self::createConnection();
}
if (self::$_connection === null || !self::$_connection->isConnected()) {
self::$_connection = self::createConnection();
}
@@ -63,8 +80,9 @@ class RC {
// in a separate process to properly test BLPOP/BRPOP
$redisUri = sprintf('redis://%s:%d/?database=%d', RC::SERVER_HOST, RC::SERVER_PORT, RC::DEFAULT_DATABASE);
$handle = popen('php', 'w');
$dir = __DIR__;
fwrite($handle, "<?php
require '../lib/Predis.php';
require '{$dir}/../lib/Predis.php';
\$redis = Predis\Client::create('$redisUri');
\$redis->rpush('{$op}1', 'a');
\$redis->rpush('{$op}2', 'b');
@@ -115,7 +133,7 @@ class RC {
catch (Predis\ServerException $exception) {
$thrownException = $exception;
}
$testcaseInstance->assertType('Predis\ServerException', $thrownException);
$testcaseInstance->assertInstanceOf('Predis\ServerException', $thrownException);
if (isset($expectedMessage)) {
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
}
@@ -129,7 +147,7 @@ class RC {
catch (Predis\ClientException $exception) {
$thrownException = $exception;
}
$testcaseInstance->assertType('Predis\ClientException', $thrownException);
$testcaseInstance->assertInstanceOf('Predis\ClientException', $thrownException);
if (isset($expectedMessage)) {
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
}
@@ -143,12 +161,23 @@ class RC {
catch (Predis\CommunicationException $exception) {
$thrownException = $exception;
}
$testcaseInstance->assertType('Predis\CommunicationException', $thrownException);
$testcaseInstance->assertInstanceOf('Predis\CommunicationException', $thrownException);
if (isset($expectedMessage)) {
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
}
}
public static function testForAbortedMultiExecException($testcaseInstance, $wrapFunction) {
$thrownException = null;
try {
$wrapFunction($testcaseInstance);
}
catch (Predis\AbortedMultiExec $exception) {
$thrownException = $exception;
}
$testcaseInstance->assertInstanceOf('Predis\AbortedMultiExec', $thrownException);
}
public static function pushTailAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
if ($wipeOut == true) {
$client->del($keyName);
+321 -16
View File
@@ -1,10 +1,6 @@
<?php
define('I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE', false);
require_once 'PHPUnit/Framework.php';
require_once 'PredisShared.php';
class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
class RedisCommandsTestSuite extends PHPUnit_Framework_TestCase {
public $redis;
// TODO: instead of an boolean assertion against the return value
@@ -14,12 +10,12 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
// should be provided.
// TODO: missing test with float values for a few commands
protected function setUp() {
protected function setUp() {
$this->redis = RC::getConnection();
$this->redis->flushdb();
}
protected function tearDown() {
protected function tearDown() {
}
protected function onNotSuccessfulTest(Exception $exception) {
@@ -51,9 +47,9 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
// respective Predis\Command::parseResponse methods. If you need that
// kind of behaviour, you should use an instance of Predis\MultiExecBlock.
$this->assertTrue($this->redis->multi());
$this->assertType('Predis\ResponseQueued', $this->redis->ping());
$this->assertType('Predis\ResponseQueued', $this->redis->echo('hello'));
$this->assertType('Predis\ResponseQueued', $this->redis->echo('redis'));
$this->assertInstanceOf('Predis\ResponseQueued', $this->redis->ping());
$this->assertInstanceOf('Predis\ResponseQueued', $this->redis->echo('hello'));
$this->assertInstanceOf('Predis\ResponseQueued', $this->redis->echo('redis'));
$this->assertEquals(array('PONG', 'hello', 'redis'), $this->redis->exec());
$this->assertTrue($this->redis->multi());
@@ -67,8 +63,8 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
function testDiscard() {
$this->assertTrue($this->redis->multi());
$this->assertType('Predis\ResponseQueued', $this->redis->set('foo', 'bar'));
$this->assertType('Predis\ResponseQueued', $this->redis->set('hoge', 'piyo'));
$this->assertInstanceOf('Predis\ResponseQueued', $this->redis->set('foo', 'bar'));
$this->assertInstanceOf('Predis\ResponseQueued', $this->redis->set('hoge', 'piyo'));
$this->assertEquals(true, $this->redis->discard());
// should throw an exception when trying to EXEC after a DISCARD
@@ -89,8 +85,11 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
function testGet() {
$this->redis->set('foo', 'bar');
$this->assertEquals('bar', $this->redis->get('foo'));
$this->assertTrue($this->redis->set('foo', ''));
$this->assertEquals('', $this->redis->get('foo'));
$this->assertNull($this->redis->get('fooDoesNotExist'));
// should throw an exception when trying to do a GET on non-string types
@@ -223,13 +222,35 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
});
}
function testSetRange() {
$this->assertEquals(6, $this->redis->setrange('var', 0, 'foobar'));
$this->assertEquals('foobar', $this->redis->get('var'));
$this->assertEquals(6, $this->redis->setrange('var', 3, 'foo'));
$this->assertEquals('foofoo', $this->redis->get('var'));
$this->assertEquals(16, $this->redis->setrange('var', 10, 'barbar'));
$this->assertEquals("foofoo\x00\x00\x00\x00barbar", $this->redis->get('var'));
$this->assertEquals(4, $this->redis->setrange('binary', 0, pack('l', -2147483648)));
list($unpacked) = array_values(unpack('l', $this->redis->get('binary')));
$this->assertEquals(-2147483648, $unpacked);
RC::testForServerException($this, RC::EXCEPTION_OFFSET_RANGE, function($test) {
$test->redis->setrange('var', -1, 'bogus');
});
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->rpush('metavars', 'foo');
$test->redis->setrange('metavars', 0, 'hoge');
});
}
function testSubstr() {
$this->redis->set('var', 'foobar');
$this->assertEquals('foo', $this->redis->substr('var', 0, 2));
$this->assertEquals('bar', $this->redis->substr('var', 3, 5));
$this->assertEquals('bar', $this->redis->substr('var', -3, -1));
$this->assertNull($this->redis->substr('var', 5, 0));
$this->assertEquals($this->redis->substr('var', 5, 0), '');
$this->redis->set('numeric', 123456789);
$this->assertEquals(12345, $this->redis->substr('numeric', 0, 4));
@@ -240,6 +261,74 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
});
}
function testStrlen() {
$this->redis->set('var', 'foobar');
$this->assertEquals(6, $this->redis->strlen('var'));
$this->assertEquals(9, $this->redis->append('var', '___'));
$this->assertEquals(9, $this->redis->strlen('var'));
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->rpush('metavars', 'foo');
$test->redis->strlen('metavars');
});
}
function testSetBit() {
$this->assertEquals(0, $this->redis->setbit('binary', 31, 1));
$this->assertEquals(0, $this->redis->setbit('binary', 0, 1));
$this->assertEquals(4, $this->redis->strlen('binary'));
$this->assertEquals("\x80\x00\00\x01", $this->redis->get('binary'));
$this->assertEquals(1, $this->redis->setbit('binary', 0, 0));
$this->assertEquals(0, $this->redis->setbit('binary', 0, 0));
$this->assertEquals("\x00\x00\00\x01", $this->redis->get('binary'));
RC::testForServerException($this, RC::EXCEPTION_BIT_OFFSET, function($test) {
$test->redis->setbit('binary', -1, 1);
});
RC::testForServerException($this, RC::EXCEPTION_BIT_OFFSET, function($test) {
$test->redis->setbit('binary', 'invalid', 1);
});
RC::testForServerException($this, RC::EXCEPTION_BIT_VALUE, function($test) {
$test->redis->setbit('binary', 15, 255);
});
RC::testForServerException($this, RC::EXCEPTION_BIT_VALUE, function($test) {
$test->redis->setbit('binary', 15, 'invalid');
});
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->rpush('metavars', 'foo');
$test->redis->setbit('metavars', 0, 1);
});
}
function testGetBit() {
$this->redis->set('binary', "\x80\x00\00\x01");
$this->assertEquals(1, $this->redis->getbit('binary', 0));
$this->assertEquals(0, $this->redis->getbit('binary', 15));
$this->assertEquals(1, $this->redis->getbit('binary', 31));
$this->assertEquals(0, $this->redis->getbit('binary', 63));
RC::testForServerException($this, RC::EXCEPTION_BIT_OFFSET, function($test) {
$test->redis->getbit('binary', -1);
});
RC::testForServerException($this, RC::EXCEPTION_BIT_OFFSET, function($test) {
$test->redis->getbit('binary', 'invalid');
});
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->rpush('metavars', 'foo');
$test->redis->getbit('metavars', 0);
});
}
/* commands operating on the key space */
function testKeys() {
@@ -324,6 +413,18 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
$this->assertEquals(-1, $this->redis->ttl('foo'));
}
function testPersist() {
$this->redis->set('foo', 'bar');
$this->assertTrue($this->redis->expire('foo', 1));
$this->assertEquals(1, $this->redis->ttl('foo'));
$this->assertTrue($this->redis->persist('foo'));
$this->assertEquals(-1, $this->redis->ttl('foo'));
$this->assertFalse($this->redis->persist('foo'));
$this->assertFalse($this->redis->persist('foobar'));
}
function testSetExpire() {
$this->assertTrue($this->redis->setex('foo', 10, 'bar'));
$this->assertTrue($this->redis->exists('foo'));
@@ -333,7 +434,8 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
sleep(2);
$this->assertFalse($this->redis->exists('hoge'));
RC::testForServerException($this, RC::EXCEPTION_VALUE_NOT_INT, function($test) {
// TODO: do not check the error message RC::EXCEPTION_VALUE_NOT_INT for now
RC::testForServerException($this, null, function($test) {
$test->redis->setex('hoge', 2.5, 'piyo');
});
RC::testForServerException($this, RC::EXCEPTION_SETEX_TTL, function($test) {
@@ -367,6 +469,20 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
});
}
function testPushTailX() {
$this->assertEquals(0, $this->redis->rpushx('numbers', 1));
$this->assertEquals(1, $this->redis->rpush('numbers', 2));
$this->assertEquals(2, $this->redis->rpushx('numbers', 3));
$this->assertEquals(2, $this->redis->llen('numbers'));
$this->assertEquals(array(2, 3), $this->redis->lrange('numbers', 0, -1));
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->set('foo', 'bar');
$test->redis->rpushx('foo', 'bar');
});
}
function testPushHead() {
// NOTE: List push operations return the list length since Redis commit 520b5a3
$this->assertEquals(1, $this->redis->lpush('metavars', 'foo'));
@@ -380,6 +496,20 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
});
}
function testPushHeadX() {
$this->assertEquals(0, $this->redis->lpushx('numbers', 1));
$this->assertEquals(1, $this->redis->lpush('numbers', 2));
$this->assertEquals(2, $this->redis->lpushx('numbers', 3));
$this->assertEquals(2, $this->redis->llen('numbers'));
$this->assertEquals(array(3, 2), $this->redis->lrange('numbers', 0, -1));
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->set('foo', 'bar');
$test->redis->lpushx('foo', 'bar');
});
}
function testListLength() {
$this->assertEquals(1, $this->redis->rpush('metavars', 'foo'));
$this->assertEquals(2, $this->redis->rpush('metavars', 'hoge'));
@@ -680,6 +810,47 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
$this->assertEquals((float)(time() - $start), 2, '', 1);
}
function testListBlockingPopLastPushHead() {
// TODO: this test does not cover all the aspects of BLPOP/BRPOP as it
// does not run with a concurrent client pushing items on lists.
$numbers = RC::pushTailAndReturn($this->redis, 'numbers', array(1, 2, 3));
$src_count = count($numbers);
$dst_count = 0;
while ($item = $this->redis->brpoplpush('numbers', 'temporary', 1)) {
$this->assertEquals(--$src_count, $this->redis->llen('numbers'));
$this->assertEquals(++$dst_count, $this->redis->llen('temporary'));
$this->assertEquals(array_pop($numbers), $this->redis->lindex('temporary', 0));
}
$start = time();
$this->assertNull($this->redis->brpoplpush('numbers', 'temporary', 2));
$this->assertEquals(2, (float)(time() - $start), '', 1);
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->del('numbers');
$test->redis->del('temporary');
$test->redis->set('numbers', 'foobar');
$test->redis->brpoplpush('numbers', 'temporary', 1);
});
}
function testListInsert() {
$numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers());
$this->assertEquals(11, $this->redis->linsert('numbers', 'before', 0, -2));
$this->assertEquals(12, $this->redis->linsert('numbers', 'after', -2, -1));
$this->assertEquals(array(-2, -1, 0, 1), $this->redis->lrange('numbers', 0, 3));
$this->assertEquals(-1, $this->redis->linsert('numbers', 'after', 100, 200));
$this->assertEquals(-1, $this->redis->linsert('numbers', 'before', 100, 50));
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->set('foo', 'bar');
$test->redis->linsert('foo', 'before', 0, 0);
});
}
/* commands operating on sets */
@@ -841,6 +1012,9 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
$this->redis->set('foo', 'bar');
$this->assertEquals(count($setA), $this->redis->sinterstore('foo', 'setA'));
// accepts an array for the list of source keys
$this->assertEquals(4, $this->redis->sinterstore('setC', array('setA', 'setB')));
// wrong type
$this->redis->set('foo', 'bar');
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
@@ -904,6 +1078,9 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
$this->redis->set('foo', 'bar');
$this->assertEquals(count($setA), $this->redis->sunionstore('foo', 'setA'));
// accepts an array for the list of source keys
$this->assertEquals(9, $this->redis->sunionstore('setC', array('setA', 'setB')));
// wrong type
$this->redis->set('foo', 'bar');
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
@@ -1095,6 +1272,11 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
$this->redis->zrange('zset', 0, 2, 'withscores')
);
$this->assertEquals(
array(array('a', -10), array('b', 0), array('c', 10)),
$this->redis->zrange('zset', 0, 2, array('withscores' => true))
);
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->set('foo', 'bar');
$test->redis->zrange('foo', 0, -1);
@@ -1149,6 +1331,11 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
$this->redis->zrevrange('zset', 0, 2, 'withscores')
);
$this->assertEquals(
array(array('f', 30), array('e', 20), array('d', 20)),
$this->redis->zrevrange('zset', 0, 2, array('withscores' => true))
);
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->set('foo', 'bar');
$test->redis->zrevrange('foo', 0, -1);
@@ -1183,12 +1370,96 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
$this->redis->zrangebyscore('zset', 10, 20, 'withscores')
);
$this->assertEquals(
array(array('c', 10), array('d', 20), array('e', 20)),
$this->redis->zrangebyscore('zset', 10, 20, array('withscores' => true))
);
$this->assertEquals(
array('d', 'e'),
$this->redis->zrangebyscore('zset', 10, 20, array('limit' => array(1, 2)))
);
$this->assertEquals(
array('d', 'e'),
$this->redis->zrangebyscore('zset', 10, 20, array(
'limit' => array('offset' => 1, 'count' => 2)
))
);
$this->assertEquals(
array(array('d', 20), array('e', 20)),
$this->redis->zrangebyscore('zset', 10, 20, array(
'limit' => array(1, 2),
'withscores' => true,
))
);
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->set('foo', 'bar');
$test->redis->zrangebyscore('foo', 0, 0);
});
}
function testZsetReverseRangeByScore() {
$zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray());
$this->assertEquals(
array('a'),
$this->redis->zrevrangebyscore('zset', -10, -10)
);
$this->assertEquals(
array('b', 'a'),
$this->redis->zrevrangebyscore('zset', 0, -10)
);
$this->assertEquals(
array('e', 'd'),
$this->redis->zrevrangebyscore('zset', 20, 20)
);
$this->assertEquals(
array('f', 'e', 'd', 'c', 'b'),
$this->redis->zrevrangebyscore('zset', 30, 0)
);
$this->assertEquals(
array(array('e', 20), array('d', 20), array('c', 10)),
$this->redis->zrevrangebyscore('zset', 20, 10, 'withscores')
);
$this->assertEquals(
array(array('e', 20), array('d', 20), array('c', 10)),
$this->redis->zrevrangebyscore('zset', 20, 10, array('withscores' => true))
);
$this->assertEquals(
array('d', 'c'),
$this->redis->zrevrangebyscore('zset', 20, 10, array('limit' => array(1, 2)))
);
$this->assertEquals(
array('d', 'c'),
$this->redis->zrevrangebyscore('zset', 20, 10, array(
'limit' => array('offset' => 1, 'count' => 2)
))
);
$this->assertEquals(
array(array('d', 20), array('c', 10)),
$this->redis->zrevrangebyscore('zset', 20, 10, array(
'limit' => array(1, 2),
'withscores' => true,
))
);
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->set('foo', 'bar');
$test->redis->zrevrangebyscore('foo', 0, 0);
});
}
function testZsetUnionStore() {
$zsetA = RC::zsetAddAndReturn($this->redis, 'zseta', array('a' => 1, 'b' => 2, 'c' => 3));
$zsetB = RC::zsetAddAndReturn($this->redis, 'zsetb', array('b' => 1, 'c' => 2, 'd' => 3));
@@ -1238,6 +1509,23 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
$this->redis->zrange('zsetc', 0, -1, 'withscores')
);
// using an array to pass the list of source keys
$sourceKeys = array('zseta', 'zsetb');
$this->assertEquals(4, $this->redis->zunionstore('zsetc', $sourceKeys));
$this->assertEquals(
array(array('a', 1), array('b', 3), array('d', 3), array('c', 5)),
$this->redis->zrange('zsetc', 0, -1, 'withscores')
);
// using an array to pass the list of source keys + options array
$options = array('weights' => array(2, 3));
$this->assertEquals(4, $this->redis->zunionstore('zsetc', $sourceKeys, $options));
$this->assertEquals(
array(array('a', 2), array('b', 7), array('d', 9), array('c', 12)),
$this->redis->zrange('zsetc', 0, -1, 'withscores')
);
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->set('zsetFake', 'fake');
$test->redis->zunionstore('zsetc', 2, 'zseta', 'zsetFake');
@@ -1283,6 +1571,23 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
$this->redis->zrange('zsetc', 0, -1, 'withscores')
);
// using an array to pass the list of source keys
$sourceKeys = array('zseta', 'zsetb');
$this->assertEquals(2, $this->redis->zinterstore('zsetc', $sourceKeys));
$this->assertEquals(
array(array('b', 3), array('c', 5)),
$this->redis->zrange('zsetc', 0, -1, 'withscores')
);
// using an array to pass the list of source keys + options array
$options = array('weights' => array(2, 3));
$this->assertEquals(2, $this->redis->zinterstore('zsetc', $sourceKeys, $options));
$this->assertEquals(
array(array('b', 7), array('c', 12)),
$this->redis->zrange('zsetc', 0, -1, 'withscores')
);
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) {
$test->redis->set('zsetFake', 'fake');
$test->redis->zinterstore('zsetc', 2, 'zseta', 'zsetFake');
@@ -1732,7 +2037,7 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
function testInfo() {
$serverInfo = $this->redis->info();
$this->assertType('array', $serverInfo);
$this->assertInternalType('array', $serverInfo);
$this->assertNotNull($serverInfo['redis_version']);
$this->assertGreaterThan(0, $serverInfo['uptime_in_seconds']);
$this->assertGreaterThan(0, $serverInfo['total_connections_received']);
+6
View File
@@ -0,0 +1,6 @@
<?php
require_once(__DIR__ . '/../lib/Predis.php');
require_once(__DIR__ . '/../lib/Predis_Compatibility.php');
require_once(__DIR__ . '/../test/PredisShared.php');