From 9acd00e25a746b12495b60225ba360f61178864a Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 20 Oct 2015 20:39:17 +0200 Subject: [PATCH 001/121] POCO Redis experiment ... --- Redis/include/Poco/Redis/Array.h | 127 +++++++++++++++ Redis/include/Poco/Redis/Client.h | 186 ++++++++++++++++++++++ Redis/include/Poco/Redis/Exception.h | 32 ++++ Redis/include/Poco/Redis/Redis.h | 66 ++++++++ Redis/include/Poco/Redis/RedisSocket.h | 68 ++++++++ Redis/include/Poco/Redis/Type.h | 207 +++++++++++++++++++++++++ Redis/src/Array.cpp | 72 +++++++++ Redis/src/Client.cpp | 92 +++++++++++ Redis/src/Exception.cpp | 25 +++ Redis/src/RedisSocket.cpp | 119 ++++++++++++++ Redis/src/Type.cpp | 32 ++++ Redis/testsuite/src/Driver.cpp | 19 +++ Redis/testsuite/src/RedisTest.cpp | 113 ++++++++++++++ Redis/testsuite/src/RedisTest.h | 51 ++++++ Redis/testsuite/src/RedisTestSuite.cpp | 24 +++ Redis/testsuite/src/RedisTestSuite.h | 29 ++++ Redis/testsuite/src/WinCEDriver.cpp | 32 ++++ Redis/testsuite/src/WinDriver.cpp | 30 ++++ 18 files changed, 1324 insertions(+) create mode 100644 Redis/include/Poco/Redis/Array.h create mode 100644 Redis/include/Poco/Redis/Client.h create mode 100644 Redis/include/Poco/Redis/Exception.h create mode 100644 Redis/include/Poco/Redis/Redis.h create mode 100644 Redis/include/Poco/Redis/RedisSocket.h create mode 100644 Redis/include/Poco/Redis/Type.h create mode 100644 Redis/src/Array.cpp create mode 100644 Redis/src/Client.cpp create mode 100644 Redis/src/Exception.cpp create mode 100644 Redis/src/RedisSocket.cpp create mode 100644 Redis/src/Type.cpp create mode 100644 Redis/testsuite/src/Driver.cpp create mode 100644 Redis/testsuite/src/RedisTest.cpp create mode 100644 Redis/testsuite/src/RedisTest.h create mode 100644 Redis/testsuite/src/RedisTestSuite.cpp create mode 100644 Redis/testsuite/src/RedisTestSuite.h create mode 100644 Redis/testsuite/src/WinCEDriver.cpp create mode 100644 Redis/testsuite/src/WinDriver.cpp diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h new file mode 100644 index 000000000..17dbaeaef --- /dev/null +++ b/Redis/include/Poco/Redis/Array.h @@ -0,0 +1,127 @@ +// +// Array.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Array +// +// Definition of the Array class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#ifndef Redis_Array_INCLUDED +#define Redis_Array_INCLUDED + +#include +#include "Poco/Redis/Redis.h" +#include "Poco/Redis/Type.h" +#include "Poco/Redis/Exception.h" + +namespace Poco { +namespace Redis { + +class Redis_API Array +{ +public: + Array(); + + Array(const Array& copy); + + virtual ~Array(); + + void add(Poco::Int64 value); + + void add(const std::string& value); + + void add(const BulkString& value); + + void add(); + + void add(AbstractType::Ptr value); + + void clear(); + + std::string toString() const; + + size_t size() const; + +private: + + std::vector _elements; + + friend class Connection; +}; + +inline void Array::clear() +{ + _elements.clear(); +} + +inline size_t Array::size() const +{ + return _elements.size(); +} + +inline void Array::add(AbstractType::Ptr value) +{ + _elements.push_back(value); +} + +template<> +struct ElementTraits +{ + enum { TypeId = AbstractType::REDIS_ARRAY }; + + static std::string typeName() + { + return "Array"; + } + + static std::string toString(const Array& value) + { + return value.toString(); + } +}; + + +template<> inline +void Type::read(RedisSocket& socket) +{ + std::string line; + socket.readLine(line); + Int64 length = NumberParser::parse64(line); + for(int i = 0; i < length; ++i) + { + char elementType = socket.get(); + AbstractType::Ptr t; + + switch(elementType) + { + case ':': // Integer + t = new Type(); + break; + case '+' : // Simple String + t = new Type(); + break; + case '$' : // Bulk String + t = new Type(); + break; + } + + if ( t.isNull() ) throw RedisException("Wrong answer received from Redis server"); + + t->read(socket); + _value.add(t); + } +} + + +}} + +#endif // Redis_Array_INCLUDED diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h new file mode 100644 index 000000000..47109d39d --- /dev/null +++ b/Redis/include/Poco/Redis/Client.h @@ -0,0 +1,186 @@ +// +// Connection.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Connection +// +// Definition of the Connection class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Redis_Connection_INCLUDED +#define Redis_Connection_INCLUDED + + +#include "Poco/Net/SocketAddress.h" +#include "Poco/Optional.h" + +#include "Poco/Redis/Redis.h" +#include "Poco/Redis/Array.h" +#include "Poco/Redis/RedisSocket.h" + +namespace Poco { +namespace Redis { + + +class Redis_API Connection + /// Represents a connection to a Redis server +{ +public: + typedef Poco::SharedPtr Ptr; + + Connection(); + /// Default constructor. Use this when you want to + /// connect later on. + + Connection(const std::string& hostAndPort); + /// Constructor which connects to the given Redis host/port. + /// The host and port must be separated with a colon. + + Connection(const std::string& host, int port); + /// Constructor which connects to the given Redis host/port. + + Connection(const Net::SocketAddress& addrs); + /// Constructor which connects to the given Redis host/port. + + virtual ~Connection(); + /// Destructor + + Net::SocketAddress address() const; + /// Returns the address of the Redis connection + + void connect(const std::string& hostAndPort); + /// Connects to the given Redis server. The host and port must be separated + /// with a colon. + + void connect(const std::string& host, int port); + /// Connects to the given Redis server. + + void connect(const Net::SocketAddress& addrs); + /// Connects to the given Redis server. + + void disconnect(); + /// Disconnects from the Redis server + + void sendCommand(const Array& command); + /// Sends a request to the Redis server + + template + void sendCommand(const Array& command, T& result) + { + Type resultType; + + sendCommand(command); + + char type = _socket.get(); + + switch(type) + { + case ':': + { + if ( resultType.getType() == AbstractType::REDIS_INTEGER ) + { + resultType.read(_socket); + } + else + { + std::string message; + message.append("Expected "); + message.append(ElementTraits::typeName()); + message.append(", got an Integer"); + throw InvalidArgumentException(message); + } + break; + } + case '+': // Simple String + { + if ( resultType.getType() == AbstractType::REDIS_SIMPLE_STRING ) + { + resultType.read(_socket); + } + else + { + std::string message; + message.append("Expected "); + message.append(ElementTraits::typeName()); + message.append(", got a Simple String"); + throw InvalidArgumentException(message); + } + break; + } + case '-' : // Error + { + std::string error; + _socket.readLine(error); + throw RedisException(error); + } + case '$' : // Bulk String + { + if ( resultType.getType() == AbstractType::REDIS_BULK_STRING ) + { + resultType.read(_socket); + } + else + { + std::string message; + message.append("Expected "); + message.append(ElementTraits::typeName()); + message.append(", got a Bulk String"); + throw InvalidArgumentException(message); + } + break; + } + case '*' : //Array + { + if ( resultType.getType() == AbstractType::REDIS_ARRAY ) + { + resultType.read(_socket); + } + else + { + std::string message; + message.append("Expected "); + message.append(ElementTraits::typeName()); + message.append(", got an Array"); + throw InvalidArgumentException(message); + } + throw InvalidArgumentException("Expected integer, got an array"); + } + default: + throw IOException("Invalid Redis type returned"); + } + + result = resultType.value(); + } + +private: + + Connection(const Connection&); + Connection& operator = (const Connection&); + + Net::SocketAddress _address; + RedisSocket _socket; + + void connect(); + /// Connects to the Redis server +}; + + +inline Net::SocketAddress Connection::address() const +{ + return _address; +} + + +} } // namespace Poco::Redis + + +#endif //Redis_Connection_INCLUDED diff --git a/Redis/include/Poco/Redis/Exception.h b/Redis/include/Poco/Redis/Exception.h new file mode 100644 index 000000000..d45d85348 --- /dev/null +++ b/Redis/include/Poco/Redis/Exception.h @@ -0,0 +1,32 @@ +// +// Exception.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Exception +// +// Definition of the Exception class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#ifndef Redis_Exception_INCLUDED +#define Redis_Exception_INCLUDED + +#include "Poco/Redis/Redis.h" +#include +#include "Poco/Exception.h" + +namespace Poco { +namespace Redis { + +POCO_DECLARE_EXCEPTION(Redis_API, RedisException, Exception) + +}} + +#endif // Redis_Exception_INCLUDED diff --git a/Redis/include/Poco/Redis/Redis.h b/Redis/include/Poco/Redis/Redis.h new file mode 100644 index 000000000..a25cd1598 --- /dev/null +++ b/Redis/include/Poco/Redis/Redis.h @@ -0,0 +1,66 @@ +// +// Redis.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Redis +// +// Basic definitions for the Poco Redis library. +// This file must be the first file included by every other Redis +// header file. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef RedisRedis_INCLUDED +#define RedisRedis_INCLUDED + + +#include "Poco/Foundation.h" + + +// +// The following block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the Redis_EXPORTS +// symbol defined on the command line. this symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// Redis_API functions as being imported from a DLL, wheras this DLL sees symbols +// defined with this macro as being exported. +// + + +#if defined(_WIN32) && defined(POCO_DLL) + #if defined(Redis_EXPORTS) + #define Redis_API __declspec(dllexport) + #else + #define Redis_API __declspec(dllimport) + #endif +#endif + + +#if !defined(Redis_API) + #if !defined(POCO_NO_GCC_API_ATTRIBUTE) && defined (__GNUC__) && (__GNUC__ >= 4) + #define Redis_API __attribute__ ((visibility ("default"))) + #else + #define Redis_API + #endif +#endif + + +// +// Automatically link Redis library. +// +#if defined(_MSC_VER) + #if !defined(POCO_NO_AUTOMATIC_LIBS) && !defined(Redis_EXPORTS) + #pragma comment(lib, "PocoRedis" POCO_LIB_SUFFIX) + #endif +#endif + + +#endif // RedisRedis_INCLUDED diff --git a/Redis/include/Poco/Redis/RedisSocket.h b/Redis/include/Poco/Redis/RedisSocket.h new file mode 100644 index 000000000..f0f6aefd2 --- /dev/null +++ b/Redis/include/Poco/Redis/RedisSocket.h @@ -0,0 +1,68 @@ +// +// RedistSocket.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: RedistSocket +// +// Definition of the RedistSocket class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#ifndef Redis_RedisSocket_INCLUDED +#define Redis_RedisSocket_INCLUDED + +#include "Poco/Net/SocketAddress.h" +#include "Poco/Net/StreamSocket.h" + +#include "Poco/Redis/Redis.h" + +namespace Poco { +namespace Redis { + +class Redis_API RedisSocket +{ +public: + + RedisSocket(); + virtual ~RedisSocket(); + + void close(); + + void connect(const Net::SocketAddress& addrs); + + int get(); + + int peek(); + + void read(UInt64 length, std::string& data); + + int write(const char* buffer, std::streamsize length); + + int buffered(); + + void refill(); + + void readLine(std::string& line); + +private: + + RedisSocket(RedisSocket& copy); + RedisSocket& operator = (const RedisSocket&); + + Net::StreamSocket _socket; + + char* _buffer; + char* _current; + char* _end; +}; + +} } + +#endif // Redis_RedisSocket_INCLUDED diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h new file mode 100644 index 000000000..dccc48ab2 --- /dev/null +++ b/Redis/include/Poco/Redis/Type.h @@ -0,0 +1,207 @@ +// +// Type.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Type +// +// Definition of the Type class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#ifndef Redis_Type_INCLUDED +#define Redis_Type_INCLUDED + +#include "Poco/NumberFormatter.h" +#include "Poco/NumberParser.h" +#include "Poco/SharedPtr.h" +#include "Poco/Optional.h" + +#include "Poco/Redis/Redis.h" +#include "Poco/Redis/RedisSocket.h" + +namespace Poco { +namespace Redis { + + +class Redis_API AbstractType +{ +public: + + typedef SharedPtr Ptr; + + AbstractType(); + virtual ~AbstractType(); + + virtual int getType() const = 0; + + virtual void read(RedisSocket& socket) = 0; + + virtual std::string toString() const = 0; + + enum Types { + REDIS_INTEGER, + REDIS_SIMPLE_STRING, + REDIS_BULK_STRING, + REDIS_ARRAY + }; + +private: + +}; + +template +struct ElementTraits +{ +}; + + +template<> +struct ElementTraits +{ + enum { TypeId = AbstractType::REDIS_INTEGER }; + + static std::string typeName() + { + return "Integer"; + } + + static std::string toString(const Poco::Int64& value) + { + return ":" + NumberFormatter::format(value) + "\r\n"; + } +}; + + +template<> +struct ElementTraits +{ + enum { TypeId = AbstractType::REDIS_SIMPLE_STRING }; + + static std::string typeName() + { + return "Simple String"; + } + + static std::string toString(const std::string& value) + { + return "+" + value + "\r\n"; + } +}; + + +typedef Optional BulkString; + + +template<> +struct ElementTraits +{ + enum { TypeId = AbstractType::REDIS_BULK_STRING }; + + static std::string typeName() + { + return "Bulk String"; + } + + static std::string toString(const BulkString& value) + { + if ( value.isSpecified() ) { + std::string s = value.value(); + return "$" + NumberFormatter::format(s.length()) + "\r\n" + s + "\r\n"; + } + return "$-1\r\n"; + } +}; + + +template +class Redis_API Type : public AbstractType +{ + public: + + Type() + { + } + + Type(const T& t) : _value(t) + { + } + + Type(const Type& copy) : _value(copy._value) + { + } + + virtual ~Type() + { + } + + int getType() const + { + return ElementTraits::TypeId; + } + + void read(RedisSocket& socket) + { + } + + virtual std::string toString() const { + return ElementTraits::toString(_value); + } + + T value() const + { + return _value; + } + +private: + + T _value; +}; + +template<> inline +void Type::read(RedisSocket& socket) +{ + std::string number; + socket.readLine(number); + _value = NumberParser::parse64(number); +} + +template<> inline +void Type::read(RedisSocket& socket) +{ + std::string s; + socket.readLine(s); + _value = s; +} + +template<> inline +void Type::read(RedisSocket& socket) +{ + _value.clear(); + + std::string line; + socket.readLine(line); + int length = NumberParser::parse64(line); + if ( length >= 0 ) + { + std::string s; + socket.read(length, s); + _value.assign(s); + socket.readLine(line); + } + else // -1 + { + socket.readLine(line); + } +} + + +}} + +#endif // Redis_Type_INCLUDED diff --git a/Redis/src/Array.cpp b/Redis/src/Array.cpp new file mode 100644 index 000000000..92da09c6d --- /dev/null +++ b/Redis/src/Array.cpp @@ -0,0 +1,72 @@ +// +// Array.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Array +// +// Implementation of the Array class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include + +#include "Poco/Redis/Array.h" + +namespace Poco { +namespace Redis { + +Array::Array() +{ +} + + +Array::Array(const Array& copy) : _elements(copy._elements) +{ +} + + +Array::~Array() +{ +} + +void Array::add(Int64 value) +{ + _elements.push_back(new Type(value)); +} + +void Array::add(const std::string& value) +{ + BulkString rs(value); + _elements.push_back(new Type(rs)); +} + +void Array::add(const BulkString& value) +{ + _elements.push_back(new Type(value)); +} + +void Array::add() +{ + BulkString value; + _elements.push_back(new Type(value)); +} + +std::string Array::toString() const +{ + std::stringstream result; + result << "*" << _elements.size() << "\r\n"; + for(std::vector::const_iterator it = _elements.begin(); it != _elements.end(); ++it) + { + result << (*it)->toString(); + } + return result.str(); +} + +} } \ No newline at end of file diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp new file mode 100644 index 000000000..d0e5e23fc --- /dev/null +++ b/Redis/src/Client.cpp @@ -0,0 +1,92 @@ +// +// Connection.cpp +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Connection +// +// Implementation of the Connection class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include "Poco/Redis/Client.h" + + +namespace Poco { +namespace Redis { + + +Connection::Connection() : _address(), _socket() +{ +} + + +Connection::Connection(const std::string& hostAndPort) : _address(hostAndPort), _socket() +{ + connect(); +} + + +Connection::Connection(const std::string& host, int port) : _address(host, port), _socket() +{ + connect(); +} + + +Connection::Connection(const Net::SocketAddress& addrs) : _address(addrs), _socket() +{ + connect(); +} + + +Connection::~Connection() +{ +} + + +void Connection::connect() +{ + _socket.connect(_address); +} + + +void Connection::connect(const std::string& hostAndPort) +{ + _address = Net::SocketAddress(hostAndPort); + connect(); +} + + +void Connection::connect(const std::string& host, int port) +{ + _address = Net::SocketAddress(host, port); + connect(); +} + + +void Connection::connect(const Net::SocketAddress& addrs) +{ + _address = addrs; + connect(); +} + + +void Connection::disconnect() +{ + _socket.close(); +} + +void Connection::sendCommand(const Array& command) +{ + std::string commandStr = command.toString(); + _socket.write(commandStr.c_str(), commandStr.length()); +} + + +} } // Poco::Redis diff --git a/Redis/src/Exception.cpp b/Redis/src/Exception.cpp new file mode 100644 index 000000000..c27e5743c --- /dev/null +++ b/Redis/src/Exception.cpp @@ -0,0 +1,25 @@ +// +// Exception.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Exception +// +// Implementation of the Exception class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include "Poco/Redis/Exception.h" + +namespace Poco { +namespace Redis { + +POCO_IMPLEMENT_EXCEPTION(RedisException, Exception, "Redis Exception") + +}} diff --git a/Redis/src/RedisSocket.cpp b/Redis/src/RedisSocket.cpp new file mode 100644 index 000000000..d7c3c3c60 --- /dev/null +++ b/Redis/src/RedisSocket.cpp @@ -0,0 +1,119 @@ +// +// RedistSocket.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: RedistSocket +// +// Implementation of the RedistSocket class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include "Poco/Redis/RedisSocket.h" + +namespace Poco { +namespace Redis { + +RedisSocket::RedisSocket() : _socket(), _buffer(0), _current(0), _end(0) +{ +} + +RedisSocket::~RedisSocket() +{ + if ( _buffer ) delete[] _buffer; + + try + { + _socket.close(); + } + catch (...) + { + } +} + +void RedisSocket::close() +{ + _socket.close(); +} + +void RedisSocket::connect(const Net::SocketAddress& addrs) +{ + _socket.connect(addrs); +} + +int RedisSocket::get() +{ + if ( _current == _end ) refill(); + + if ( _current < _end ) return *_current++; + + return std::char_traits::eof(); +} + +int RedisSocket::peek() +{ + if ( _current == _end ) refill(); + + if ( _current < _end ) return *_current; + + return std::char_traits::eof(); +} + +void RedisSocket::read(UInt64 length, std::string& data) +{ + UInt64 count = 0; + data.clear(); + + while(count < length) + { + int c = get(); + if ( c == -1 ) throw IOException("Invalid EOF"); + + data += c; + ++count; + } +} + +int RedisSocket::write(const char* buffer, std::streamsize length) +{ + _socket.sendBytes(buffer, (int) length); +} + +void RedisSocket::refill() +{ + if ( ! _buffer ) _buffer = new char[1024]; + + _current = _end = _buffer; + int n = _socket.receiveBytes(_buffer, 1024); + _end += n; +} + + +void RedisSocket::readLine(std::string& line) +{ + line.clear(); + + int c = get(); + + while(1) + { + if ( c == -1 ) throw IOException("Invalid EOF"); + + if ( c == '\r' && peek() == '\n' ) + { + get(); + break; + } + + line += c; + c = get(); + } +} + +} } diff --git a/Redis/src/Type.cpp b/Redis/src/Type.cpp new file mode 100644 index 000000000..57f35fa1e --- /dev/null +++ b/Redis/src/Type.cpp @@ -0,0 +1,32 @@ +// +// Type.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Type +// +// Implementation of the Type class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include "Poco/Redis/Type.h" + +namespace Poco { +namespace Redis { + + +AbstractType::AbstractType() +{ +} + +AbstractType::~AbstractType() +{ +} + +}} \ No newline at end of file diff --git a/Redis/testsuite/src/Driver.cpp b/Redis/testsuite/src/Driver.cpp new file mode 100644 index 000000000..a3190c5cb --- /dev/null +++ b/Redis/testsuite/src/Driver.cpp @@ -0,0 +1,19 @@ +// +// Driver.cpp +// +// $Id$ +// +// Console-based test driver for Poco MongoDB. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "CppUnit/TestRunner.h" +#include "RedisTestSuite.h" + + +CppUnitMain(RedisTestSuite) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp new file mode 100644 index 000000000..9ec5dd356 --- /dev/null +++ b/Redis/testsuite/src/RedisTest.cpp @@ -0,0 +1,113 @@ +// +// RedisTest.cpp +// +// $Id$ +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// +#include + +#include "Poco/DateTime.h" +#include "Poco/ObjectPool.h" + +#include "Poco/Net/NetException.h" + +#include "RedisTest.h" +#include "Poco/Redis/Client.h" + +#include "CppUnit/TestCaller.h" +#include "CppUnit/TestSuite.h" + +using namespace Poco::Redis; + + +bool RedisTest::_connected = false; +Poco::Redis::Connection RedisTest::_redis; + + +RedisTest::RedisTest(const std::string& name): + CppUnit::TestCase("Redis"), + _host("localhost"), + _port(6379) +{ + if (!_connected) + { + try + { + _redis.connect(_host, _port); + _connected = true; + std::cout << "Connected to [" << _host << ':' << _port << ']' << std::endl; + } + catch (Poco::Net::ConnectionRefusedException& e) + { + std::cout << "Couldn't connect to " << e.message() << ". " << std::endl; + } + } +} + + +RedisTest::~RedisTest() +{ + if (_connected) + { + _redis.disconnect(); + _connected = false; + std::cout << "Disconnected from [" << _host << ':' << _port << ']' << std::endl; + } +} + + +void RedisTest::setUp() +{ + +} + + +void RedisTest::tearDown() +{ +} + + +void RedisTest::testEcho() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("ECHO"); + command.add("Hello World"); + + BulkString result; + _redis.sendCommand(command, result); +} + +void RedisTest::testPing() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("PING"); + + std::string result; + _redis.sendCommand(command, result); +} + +CppUnit::Test* RedisTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTest"); + + CppUnit_addTest(pSuite, RedisTest, testEcho); + CppUnit_addTest(pSuite, RedisTest, testPing); + + return pSuite; +} diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h new file mode 100644 index 000000000..6c5217ea1 --- /dev/null +++ b/Redis/testsuite/src/RedisTest.h @@ -0,0 +1,51 @@ +// +// RedisTest.h +// +// $Id$ +// +// Definition of the RedisTest class. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef RedisTest_INCLUDED +#define RedisTest_INCLUDED + + +#include "Poco/Redis/Redis.h" +#include "Poco/Redis/Client.h" + +#include "CppUnit/TestCase.h" + + +class RedisTest: public CppUnit::TestCase +{ +public: + RedisTest(const std::string& name); + + + virtual ~RedisTest(); + + void testEcho(); + void testPing(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +private: + + std::string _host; + unsigned _port; + static bool _connected; + static Poco::Redis::Connection _redis; + +}; + + +#endif // RedisTest_INCLUDED diff --git a/Redis/testsuite/src/RedisTestSuite.cpp b/Redis/testsuite/src/RedisTestSuite.cpp new file mode 100644 index 000000000..f2e806a73 --- /dev/null +++ b/Redis/testsuite/src/RedisTestSuite.cpp @@ -0,0 +1,24 @@ +// +// RedisTestSuite.cpp +// +// $Id$ +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "RedisTestSuite.h" +#include "RedisTest.h" + + +CppUnit::Test* RedisTestSuite::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTestSuite"); + + pSuite->addTest(RedisTest::suite()); + + return pSuite; +} diff --git a/Redis/testsuite/src/RedisTestSuite.h b/Redis/testsuite/src/RedisTestSuite.h new file mode 100644 index 000000000..4f7664e0b --- /dev/null +++ b/Redis/testsuite/src/RedisTestSuite.h @@ -0,0 +1,29 @@ +// +// RedisTestSuite.h +// +// $Id$ +// +// Definition of the RedisTestSuite class. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef RedisTestSuite_INCLUDED +#define RedisTestSuite_INCLUDED + + +#include "CppUnit/TestSuite.h" + + +class RedisTestSuite +{ +public: + static CppUnit::Test* suite(); +}; + + +#endif // RedisTestSuite_INCLUDED diff --git a/Redis/testsuite/src/WinCEDriver.cpp b/Redis/testsuite/src/WinCEDriver.cpp new file mode 100644 index 000000000..58f7abd62 --- /dev/null +++ b/Redis/testsuite/src/WinCEDriver.cpp @@ -0,0 +1,32 @@ +// +// WinCEDriver.cpp +// +// $Id$ +// +// Console-based test driver for Windows CE. +// +// Copyright (c) 2004-2010, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "CppUnit/TestRunner.h" +#include "RedisTestSuite.h" +#include + + +int _tmain(int argc, wchar_t* argv[]) +{ + std::vector args; + for (int i = 0; i < argc; ++i) + { + char buffer[1024]; + std::wcstombs(buffer, argv[i], sizeof(buffer)); + args.push_back(std::string(buffer)); + } + CppUnit::TestRunner runner; + runner.addTest("RedisTestSuite", RedisTestSuite::suite()); + return runner.run(args) ? 0 : 1; +} diff --git a/Redis/testsuite/src/WinDriver.cpp b/Redis/testsuite/src/WinDriver.cpp new file mode 100644 index 000000000..f1d37cd3a --- /dev/null +++ b/Redis/testsuite/src/WinDriver.cpp @@ -0,0 +1,30 @@ +// +// WinDriver.cpp +// +// $Id$ +// +// Windows test driver for Poco MongoDB. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "WinTestRunner/WinTestRunner.h" +#include "RedisTestSuite.h" + + +class TestDriver: public CppUnit::WinTestRunnerApp +{ + void TestMain() + { + CppUnit::WinTestRunner runner; + runner.addTest(RedisTestSuite::suite()); + runner.run(); + } +}; + + +TestDriver theDriver; From 8f950a903a1d5717344d58746cca23511ea6ac3c Mon Sep 17 00:00:00 2001 From: fbraem Date: Thu, 22 Oct 2015 18:54:44 +0200 Subject: [PATCH 002/121] Committing more work ... --- Makefile | 23 +++++- Redis/CMakeLists.txt | 37 +++++++++ Redis/Makefile | 19 +++++ Redis/Redis.progen | 16 ++++ Redis/dependencies | 2 + Redis/include/Poco/Redis/Array.h | 56 +++++++++---- Redis/include/Poco/Redis/Client.h | 133 ++++++++---------------------- Redis/include/Poco/Redis/Error.h | 83 +++++++++++++++++++ Redis/include/Poco/Redis/Type.h | 62 +++++++------- Redis/src/Array.cpp | 10 +-- Redis/src/Client.cpp | 87 +++++++++++++++---- Redis/src/Error.cpp | 35 ++++++++ Redis/src/RedisSocket.cpp | 4 +- Redis/src/Type.cpp | 4 +- Redis/testsuite/CMakeLists.txt | 23 ++++++ Redis/testsuite/Makefile | 17 ++++ Redis/testsuite/TestSuite.progen | 9 ++ Redis/testsuite/src/RedisTest.cpp | 45 +++++++++- Redis/testsuite/src/RedisTest.h | 4 +- components | 1 + 20 files changed, 492 insertions(+), 178 deletions(-) create mode 100644 Redis/CMakeLists.txt create mode 100644 Redis/Makefile create mode 100644 Redis/Redis.progen create mode 100644 Redis/dependencies create mode 100644 Redis/include/Poco/Redis/Error.h create mode 100644 Redis/src/Error.cpp create mode 100644 Redis/testsuite/CMakeLists.txt create mode 100644 Redis/testsuite/Makefile create mode 100644 Redis/testsuite/TestSuite.progen diff --git a/Makefile b/Makefile index 23f1e36df..4503d8f65 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ poco: libexecs $(if $(TESTS),tests) $(if $(SAMPLES),samples) all: libexecs tests samples INSTALLDIR = $(DESTDIR)$(POCO_PREFIX) -COMPONENTS = Foundation XML JSON Util Net Crypto NetSSL_OpenSSL Data Data/SQLite Data/ODBC Data/MySQL MongoDB Zip PageCompiler PageCompiler/File2Page CppParser PDF +COMPONENTS = Foundation XML JSON Util Net Crypto NetSSL_OpenSSL Data Data/SQLite Data/ODBC Data/MySQL MongoDB Redis Zip PageCompiler PageCompiler/File2Page CppParser PDF cppunit: $(MAKE) -C $(POCO_BASE)/CppUnit @@ -52,10 +52,10 @@ install: libexecs find $(POCO_BUILD)/lib/$(POCO_TARGET_OSNAME)/$(POCO_TARGET_OSARCH) -name "$(LIBPREFIX)Poco*" -type f -exec cp -f {} $(INSTALLDIR)/lib \; find $(POCO_BUILD)/lib/$(POCO_TARGET_OSNAME)/$(POCO_TARGET_OSARCH) -name "$(LIBPREFIX)Poco*" -type l -exec cp -Rf {} $(INSTALLDIR)/lib \; -libexecs = Foundation-libexec XML-libexec JSON-libexec Util-libexec Net-libexec Crypto-libexec NetSSL_OpenSSL-libexec Data-libexec Data/SQLite-libexec Data/ODBC-libexec Data/MySQL-libexec MongoDB-libexec Zip-libexec PageCompiler-libexec PageCompiler/File2Page-libexec CppParser-libexec PDF-libexec -tests = Foundation-tests XML-tests JSON-tests Util-tests Net-tests Crypto-tests NetSSL_OpenSSL-tests Data-tests Data/SQLite-tests Data/ODBC-tests Data/MySQL-tests MongoDB-tests Zip-tests CppParser-tests PDF-tests +libexecs = Foundation-libexec XML-libexec JSON-libexec Util-libexec Net-libexec Crypto-libexec NetSSL_OpenSSL-libexec Data-libexec Data/SQLite-libexec Data/ODBC-libexec Data/MySQL-libexec MongoDB-libexec Redis-libexec Zip-libexec PageCompiler-libexec PageCompiler/File2Page-libexec CppParser-libexec PDF-libexec +tests = Foundation-tests XML-tests JSON-tests Util-tests Net-tests Crypto-tests NetSSL_OpenSSL-tests Data-tests Data/SQLite-tests Data/ODBC-tests Data/MySQL-tests MongoDB-tests Redis-tests Zip-tests CppParser-tests PDF-tests samples = Foundation-samples XML-samples JSON-samples Util-samples Net-samples Crypto-samples NetSSL_OpenSSL-samples Data-samples MongoDB-samples Zip-samples PageCompiler-samples PDF-samples -cleans = Foundation-clean XML-clean JSON-clean Util-clean Net-clean Crypto-clean NetSSL_OpenSSL-clean Data-clean Data/SQLite-clean Data/ODBC-clean Data/MySQL-clean MongoDB-clean Zip-clean PageCompiler-clean PageCompiler/File2Page-clean CppParser-clean PDF-clean +cleans = Foundation-clean XML-clean JSON-clean Util-clean Net-clean Crypto-clean NetSSL_OpenSSL-clean Data-clean Data/SQLite-clean Data/ODBC-clean Data/MySQL-clean MongoDB-clean Redis-clean Zip-clean PageCompiler-clean PageCompiler/File2Page-clean CppParser-clean PDF-clean .PHONY: $(libexecs) .PHONY: $(tests) @@ -223,6 +223,21 @@ MongoDB-clean: $(MAKE) -C $(POCO_BASE)/MongoDB/testsuite clean $(MAKE) -C $(POCO_BASE)/MongoDB/samples clean +Redis-libexec: Foundation-libexec Net-libexec + $(MAKE) -C $(POCO_BASE)/Redis + +Redis-tests: Redis-libexec cppunit + $(MAKE) -C $(POCO_BASE)/Redis/testsuite + +#No samples yet ... uncomment this when added, and add Redis-samples to samples above +#Redis-samples: Redis-libexec +# $(MAKE) -C $(POCO_BASE)/Redis/samples + +Redis-clean: + $(MAKE) -C $(POCO_BASE)/Redis clean + $(MAKE) -C $(POCO_BASE)/Redis/testsuite clean +# $(MAKE) -C $(POCO_BASE)/Redis/samples clean + Zip-libexec: Foundation-libexec Net-libexec Util-libexec XML-libexec $(MAKE) -C $(POCO_BASE)/Zip diff --git a/Redis/CMakeLists.txt b/Redis/CMakeLists.txt new file mode 100644 index 000000000..c630784d8 --- /dev/null +++ b/Redis/CMakeLists.txt @@ -0,0 +1,37 @@ +set(LIBNAME "Redis") +set(POCO_LIBNAME "Poco${LIBNAME}") + +# Sources +file(GLOB SRCS_G "src/*.cpp") +POCO_SOURCES_AUTO( SRCS ${SRCS_G}) + +# Headers +file(GLOB_RECURSE HDRS_G "include/*.h" ) +POCO_HEADERS_AUTO( SRCS ${HDRS_G}) + +add_library( "${LIBNAME}" ${LIB_MODE} ${SRCS} ) +add_library( "${POCO_LIBNAME}" ALIAS "${LIBNAME}") +set_target_properties( "${LIBNAME}" + PROPERTIES + VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION} + OUTPUT_NAME ${POCO_LIBNAME} + DEFINE_SYMBOL Redis_EXPORTS + ) + +target_link_libraries( "${LIBNAME}" Net Foundation) +target_include_directories( "${LIBNAME}" + PUBLIC + $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ) +target_compile_definitions("${LIBNAME}" PUBLIC ${LIB_MODE_DEFINITIONS}) + +POCO_INSTALL("${LIBNAME}") +POCO_GENERATE_PACKAGE("${LIBNAME}") + +if (ENABLE_TESTS) + add_subdirectory(samples) + add_subdirectory(testsuite) +endif () + diff --git a/Redis/Makefile b/Redis/Makefile new file mode 100644 index 000000000..63dcb39e7 --- /dev/null +++ b/Redis/Makefile @@ -0,0 +1,19 @@ +# +# Makefile +# +# $Id$ +# +# Makefile for Poco Redis +# + +include $(POCO_BASE)/build/rules/global + +INCLUDE += -I $(POCO_BASE)/Redis/include/Poco/Redis + +objects = Array Client Error Exception RedisSocket Type + +target = PocoRedis +target_version = $(LIBVERSION) +target_libs = PocoFoundation PocoNet + +include $(POCO_BASE)/build/rules/lib diff --git a/Redis/Redis.progen b/Redis/Redis.progen new file mode 100644 index 000000000..72970aa94 --- /dev/null +++ b/Redis/Redis.progen @@ -0,0 +1,16 @@ +vc.project.guid = ${vc.project.guidFromName} +vc.project.name = Redis +vc.project.target = Poco${vc.project.name} +vc.project.type = library +vc.project.pocobase = .. +vc.project.outdir = ${vc.project.pocobase} +vc.project.platforms = Win32, x64 +vc.project.configurations = debug_shared, release_shared, debug_static_mt, release_static_mt, debug_static_md, release_static_md +vc.project.prototype = ${vc.project.name}_vs90.vcproj +vc.project.compiler.include = ..\\Foundation\\include;..\\Net\\include +vc.project.compiler.defines = +vc.project.compiler.defines.shared = ${vc.project.name}_EXPORTS +vc.project.compiler.defines.debug_shared = ${vc.project.compiler.defines.shared} +vc.project.compiler.defines.release_shared = ${vc.project.compiler.defines.shared} +vc.solution.create = true +vc.solution.include = testsuite\\TestSuite diff --git a/Redis/dependencies b/Redis/dependencies new file mode 100644 index 000000000..f6d54af82 --- /dev/null +++ b/Redis/dependencies @@ -0,0 +1,2 @@ +Foundation +Net diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 17dbaeaef..949d7c9af 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -19,6 +19,8 @@ #define Redis_Array_INCLUDED #include +#include + #include "Poco/Redis/Redis.h" #include "Poco/Redis/Type.h" #include "Poco/Redis/Exception.h" @@ -43,9 +45,13 @@ public: void add(); - void add(AbstractType::Ptr value); + void add(RedisType::Ptr value); + + std::vector::const_iterator begin() const; void clear(); + + std::vector::const_iterator end() const; std::string toString() const; @@ -53,22 +59,32 @@ public: private: - std::vector _elements; + std::vector _elements; friend class Connection; }; +inline std::vector::const_iterator Array::begin() const +{ + return _elements.begin(); +} + inline void Array::clear() { _elements.clear(); } +inline std::vector::const_iterator Array::end() const +{ + return _elements.end(); +} + inline size_t Array::size() const { return _elements.size(); } -inline void Array::add(AbstractType::Ptr value) +inline void Array::add(RedisType::Ptr value) { _elements.push_back(value); } @@ -76,7 +92,9 @@ inline void Array::add(AbstractType::Ptr value) template<> struct ElementTraits { - enum { TypeId = AbstractType::REDIS_ARRAY }; + enum { TypeId = RedisType::REDIS_ARRAY }; + + static const char marker = '*'; static std::string typeName() { @@ -85,39 +103,45 @@ struct ElementTraits static std::string toString(const Array& value) { - return value.toString(); + std::stringstream result; + result << marker << value.size() << LineEnding::NEWLINE_CRLF; + for(std::vector::const_iterator it = value.begin(); it != value.end(); ++it) + { + result << (*it)->toString(); + } + return result.str(); } }; - template<> inline void Type::read(RedisSocket& socket) { std::string line; socket.readLine(line); Int64 length = NumberParser::parse64(line); + for(int i = 0; i < length; ++i) { char elementType = socket.get(); - AbstractType::Ptr t; + RedisType::Ptr element; switch(elementType) { - case ':': // Integer - t = new Type(); + case ElementTraits::marker : + element = new Type(); break; - case '+' : // Simple String - t = new Type(); + case ElementTraits::marker : + element = new Type(); break; - case '$' : // Bulk String - t = new Type(); + case ElementTraits::marker : + element = new Type(); break; } - if ( t.isNull() ) throw RedisException("Wrong answer received from Redis server"); + if ( element.isNull() ) throw RedisException("Wrong answer received from Redis server"); - t->read(socket); - _value.add(t); + element->read(socket); + _value.add(element); } } diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 47109d39d..0ba692c9c 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -1,13 +1,13 @@ // -// Connection.h +// Client.h // // $Id$ // // Library: Redis // Package: Redis -// Module: Connection +// Module: Client // -// Definition of the Connection class. +// Definition of the Client class. // // Copyright (c) 2012, Applied Informatics Software Engineering GmbH. // and Contributors. @@ -25,33 +25,34 @@ #include "Poco/Redis/Redis.h" #include "Poco/Redis/Array.h" +#include "Poco/Redis/Error.h" #include "Poco/Redis/RedisSocket.h" namespace Poco { namespace Redis { -class Redis_API Connection +class Redis_API Client /// Represents a connection to a Redis server { public: - typedef Poco::SharedPtr Ptr; + typedef Poco::SharedPtr Ptr; - Connection(); + Client(); /// Default constructor. Use this when you want to /// connect later on. - Connection(const std::string& hostAndPort); + Client(const std::string& hostAndPort); /// Constructor which connects to the given Redis host/port. /// The host and port must be separated with a colon. - Connection(const std::string& host, int port); + Client(const std::string& host, int port); /// Constructor which connects to the given Redis host/port. - Connection(const Net::SocketAddress& addrs); + Client(const Net::SocketAddress& addrs); /// Constructor which connects to the given Redis host/port. - virtual ~Connection(); + virtual ~Client(); /// Destructor Net::SocketAddress address() const; @@ -70,111 +71,47 @@ public: void disconnect(); /// Disconnects from the Redis server - void sendCommand(const Array& command); - /// Sends a request to the Redis server + RedisType::Ptr sendCommand(const Array& command); template - void sendCommand(const Array& command, T& result) + void sendCommand(const Array& command, T& result) { - Type resultType; - sendCommand(command); - - char type = _socket.get(); - - switch(type) - { - case ':': - { - if ( resultType.getType() == AbstractType::REDIS_INTEGER ) - { - resultType.read(_socket); - } - else - { - std::string message; - message.append("Expected "); - message.append(ElementTraits::typeName()); - message.append(", got an Integer"); - throw InvalidArgumentException(message); - } - break; - } - case '+': // Simple String - { - if ( resultType.getType() == AbstractType::REDIS_SIMPLE_STRING ) - { - resultType.read(_socket); - } - else - { - std::string message; - message.append("Expected "); - message.append(ElementTraits::typeName()); - message.append(", got a Simple String"); - throw InvalidArgumentException(message); - } - break; - } - case '-' : // Error - { - std::string error; - _socket.readLine(error); - throw RedisException(error); - } - case '$' : // Bulk String - { - if ( resultType.getType() == AbstractType::REDIS_BULK_STRING ) - { - resultType.read(_socket); - } - else - { - std::string message; - message.append("Expected "); - message.append(ElementTraits::typeName()); - message.append(", got a Bulk String"); - throw InvalidArgumentException(message); - } - break; - } - case '*' : //Array - { - if ( resultType.getType() == AbstractType::REDIS_ARRAY ) - { - resultType.read(_socket); - } - else - { - std::string message; - message.append("Expected "); - message.append(ElementTraits::typeName()); - message.append(", got an Array"); - throw InvalidArgumentException(message); - } - throw InvalidArgumentException("Expected integer, got an array"); - } - default: - throw IOException("Invalid Redis type returned"); - } - - result = resultType.value(); + readReply(result); } + RedisType::Ptr readReply(); + + template + void readReply(T& result) + { + RedisType::Ptr redisResult = readReply(); + if ( redisResult->type() == ElementTraits::TypeId ) + result = ((Type*) redisResult.get())->value(); + else throw BadCastException(); + } + + void sendCommands(const std::vector& commands, std::vector& results); + + void writeCommand(const Array& command); + /// Sends a request to the Redis server + private: - Connection(const Connection&); - Connection& operator = (const Connection&); + Client(const Client&); + Client& operator = (const Client&); Net::SocketAddress _address; RedisSocket _socket; void connect(); /// Connects to the Redis server + + static RedisType::Ptr createRedisType(char marker); }; -inline Net::SocketAddress Connection::address() const +inline Net::SocketAddress Client::address() const { return _address; } diff --git a/Redis/include/Poco/Redis/Error.h b/Redis/include/Poco/Redis/Error.h new file mode 100644 index 000000000..2c71edf1b --- /dev/null +++ b/Redis/include/Poco/Redis/Error.h @@ -0,0 +1,83 @@ +// +// Error.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Error +// +// Definition of the Error class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#ifndef Redis_Error_INCLUDED +#define Redis_Error_INCLUDED + +#include "Poco/Redis/Type.h" +#include "Poco/Redis/RedisSocket.h" + +namespace Poco { +namespace Redis { + +class Redis_API Error +{ +public: + + Error(); + Error(const std::string& message); + virtual ~Error(); + + std::string getMessage() const; + + void setMessage(const std::string& message); + +private: + + std::string _message; +}; + +inline std::string Error::getMessage() const +{ + return _message; +} + +inline void Error::setMessage(const std::string& message) +{ + _message = message; +} + +template<> +struct ElementTraits +{ + enum { TypeId = RedisType::REDIS_ERROR }; + + static const char marker = '-'; + + static std::string typeName() + { + return "Error"; + } + + static std::string toString(const Error& value) + { + return marker + value.getMessage() + "\r\n"; + } +}; + + +template<> inline +void Type::read(RedisSocket& socket) +{ + std::string s; + socket.readLine(s); + _value = s; +} + +}} // Namespace Poco::Redis + +#endif // Redis_Error_INCLUDED \ No newline at end of file diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index dccc48ab2..3d81ee64b 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -18,6 +18,7 @@ #ifndef Redis_Type_INCLUDED #define Redis_Type_INCLUDED +#include "Poco/LineEndingConverter.h" #include "Poco/NumberFormatter.h" #include "Poco/NumberParser.h" #include "Poco/SharedPtr.h" @@ -30,16 +31,16 @@ namespace Poco { namespace Redis { -class Redis_API AbstractType +class Redis_API RedisType { public: - typedef SharedPtr Ptr; + typedef SharedPtr Ptr; - AbstractType(); - virtual ~AbstractType(); + RedisType(); + virtual ~RedisType(); - virtual int getType() const = 0; + virtual int type() const = 0; virtual void read(RedisSocket& socket) = 0; @@ -49,7 +50,8 @@ public: REDIS_INTEGER, REDIS_SIMPLE_STRING, REDIS_BULK_STRING, - REDIS_ARRAY + REDIS_ARRAY, + REDIS_ERROR }; private: @@ -65,7 +67,9 @@ struct ElementTraits template<> struct ElementTraits { - enum { TypeId = AbstractType::REDIS_INTEGER }; + enum { TypeId = RedisType::REDIS_INTEGER }; + + static const char marker = ':'; static std::string typeName() { @@ -74,7 +78,7 @@ struct ElementTraits static std::string toString(const Poco::Int64& value) { - return ":" + NumberFormatter::format(value) + "\r\n"; + return marker + NumberFormatter::format(value) + "\r\n"; } }; @@ -82,16 +86,18 @@ struct ElementTraits template<> struct ElementTraits { - enum { TypeId = AbstractType::REDIS_SIMPLE_STRING }; + enum { TypeId = RedisType::REDIS_SIMPLE_STRING }; static std::string typeName() { return "Simple String"; } + static const char marker = '+'; + static std::string toString(const std::string& value) { - return "+" + value + "\r\n"; + return marker + value + LineEnding::NEWLINE_CRLF; } }; @@ -102,28 +108,31 @@ typedef Optional BulkString; template<> struct ElementTraits { - enum { TypeId = AbstractType::REDIS_BULK_STRING }; + enum { TypeId = RedisType::REDIS_BULK_STRING }; static std::string typeName() { return "Bulk String"; } + static const char marker = '$'; + static std::string toString(const BulkString& value) { - if ( value.isSpecified() ) { + if ( value.isSpecified() ) + { std::string s = value.value(); - return "$" + NumberFormatter::format(s.length()) + "\r\n" + s + "\r\n"; + return marker + NumberFormatter::format(s.length()) + LineEnding::NEWLINE_CRLF + s + LineEnding::NEWLINE_CRLF; } - return "$-1\r\n"; + return marker + std::string("-1") + LineEnding::NEWLINE_CRLF; } }; template -class Redis_API Type : public AbstractType +class Redis_API Type : public RedisType { - public: +public: Type() { @@ -141,16 +150,15 @@ class Redis_API Type : public AbstractType { } - int getType() const + int type() const { return ElementTraits::TypeId; } - void read(RedisSocket& socket) - { - } + virtual void read(RedisSocket& socket); - virtual std::string toString() const { + virtual std::string toString() const + { return ElementTraits::toString(_value); } @@ -175,9 +183,8 @@ void Type::read(RedisSocket& socket) template<> inline void Type::read(RedisSocket& socket) { - std::string s; - socket.readLine(s); - _value = s; + _value.clear(); + socket.readLine(_value); } template<> inline @@ -187,16 +194,15 @@ void Type::read(RedisSocket& socket) std::string line; socket.readLine(line); + int length = NumberParser::parse64(line); + if ( length >= 0 ) { std::string s; socket.read(length, s); _value.assign(s); - socket.readLine(line); - } - else // -1 - { + socket.readLine(line); } } diff --git a/Redis/src/Array.cpp b/Redis/src/Array.cpp index 92da09c6d..d97693af1 100644 --- a/Redis/src/Array.cpp +++ b/Redis/src/Array.cpp @@ -15,8 +15,6 @@ // SPDX-License-Identifier: BSL-1.0 // -#include - #include "Poco/Redis/Array.h" namespace Poco { @@ -60,13 +58,7 @@ void Array::add() std::string Array::toString() const { - std::stringstream result; - result << "*" << _elements.size() << "\r\n"; - for(std::vector::const_iterator it = _elements.begin(); it != _elements.end(); ++it) - { - result << (*it)->toString(); - } - return result.str(); + return ElementTraits::toString(*this); } } } \ No newline at end of file diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index d0e5e23fc..d337b7ed5 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -1,20 +1,20 @@ // -// Connection.cpp +// Client.cpp // // $Id$ // // Library: Redis // Package: Redis -// Module: Connection +// Module: Client // -// Implementation of the Connection class. +// Implementation of the Client class. // // Copyright (c) 2012, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // - +#include #include "Poco/Redis/Client.h" @@ -22,71 +22,128 @@ namespace Poco { namespace Redis { -Connection::Connection() : _address(), _socket() +Client::Client() : _address(), _socket() { } -Connection::Connection(const std::string& hostAndPort) : _address(hostAndPort), _socket() +Client::Client(const std::string& hostAndPort) : _address(hostAndPort), _socket() { connect(); } -Connection::Connection(const std::string& host, int port) : _address(host, port), _socket() +Client::Client(const std::string& host, int port) : _address(host, port), _socket() { connect(); } -Connection::Connection(const Net::SocketAddress& addrs) : _address(addrs), _socket() +Client::Client(const Net::SocketAddress& addrs) : _address(addrs), _socket() { connect(); } -Connection::~Connection() +Client::~Client() { } -void Connection::connect() +void Client::connect() { _socket.connect(_address); } -void Connection::connect(const std::string& hostAndPort) +void Client::connect(const std::string& hostAndPort) { _address = Net::SocketAddress(hostAndPort); connect(); } -void Connection::connect(const std::string& host, int port) +void Client::connect(const std::string& host, int port) { _address = Net::SocketAddress(host, port); connect(); } -void Connection::connect(const Net::SocketAddress& addrs) +void Client::connect(const Net::SocketAddress& addrs) { _address = addrs; connect(); } -void Connection::disconnect() +void Client::disconnect() { _socket.close(); } -void Connection::sendCommand(const Array& command) +void Client::writeCommand(const Array& command) { std::string commandStr = command.toString(); _socket.write(commandStr.c_str(), commandStr.length()); } +RedisType::Ptr Client::readReply() +{ + RedisType::Ptr result = createRedisType( _socket.get()); + if ( result.isNull() ) + { + throw IOException("Invalid Redis type returned"); + } + + result->read(_socket); + + return result; +} + +RedisType::Ptr Client::sendCommand(const Array& command) +{ + writeCommand(command); + return readReply(); +} + +void Client::sendCommands(const std::vector& commands, std::vector& results) +{ + for(std::vector::const_iterator it = commands.begin(); it != commands.end(); ++it) + { + writeCommand(*it); + } + + for(int i = 0; i < commands.size(); ++i) + { + RedisType::Ptr result = readReply(); + results.push_back(result); + } +} + +RedisType::Ptr Client::createRedisType(char marker) +{ + RedisType::Ptr result; + + switch(marker) + { + case ElementTraits::marker : + result = new Type(); + break; + case ElementTraits::marker : + result = new Type(); + break; + case ElementTraits::marker : + result = new Type(); + break; + case ElementTraits::marker : + result = new Type(); + break; + case ElementTraits::marker : + result = new Type(); + break; + } + return result; +} } } // Poco::Redis diff --git a/Redis/src/Error.cpp b/Redis/src/Error.cpp new file mode 100644 index 000000000..51c9f7a40 --- /dev/null +++ b/Redis/src/Error.cpp @@ -0,0 +1,35 @@ +// +// Error.cpp +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Error +// +// Implementation of the Error class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include "Poco/Redis/Error.h" + +namespace Poco { +namespace Redis { + +Error::Error() +{ +} + +Error::Error(const std::string& message) : _message(message) +{ +} + +Error::~Error() +{ +} + +} } \ No newline at end of file diff --git a/Redis/src/RedisSocket.cpp b/Redis/src/RedisSocket.cpp index d7c3c3c60..ced4f17b3 100644 --- a/Redis/src/RedisSocket.cpp +++ b/Redis/src/RedisSocket.cpp @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: BSL-1.0 // - +#include #include "Poco/Redis/RedisSocket.h" namespace Poco { @@ -82,7 +82,7 @@ void RedisSocket::read(UInt64 length, std::string& data) int RedisSocket::write(const char* buffer, std::streamsize length) { - _socket.sendBytes(buffer, (int) length); + return _socket.sendBytes(buffer, (int) length); } void RedisSocket::refill() diff --git a/Redis/src/Type.cpp b/Redis/src/Type.cpp index 57f35fa1e..84f1b51fd 100644 --- a/Redis/src/Type.cpp +++ b/Redis/src/Type.cpp @@ -21,11 +21,11 @@ namespace Poco { namespace Redis { -AbstractType::AbstractType() +RedisType::RedisType() { } -AbstractType::~AbstractType() +RedisType::~RedisType() { } diff --git a/Redis/testsuite/CMakeLists.txt b/Redis/testsuite/CMakeLists.txt new file mode 100644 index 000000000..2cd26aefe --- /dev/null +++ b/Redis/testsuite/CMakeLists.txt @@ -0,0 +1,23 @@ +set(TESTUNIT "${LIBNAME}-testrunner") + +# Sources +file(GLOB SRCS_G "src/*.cpp") +POCO_SOURCES_AUTO( TEST_SRCS ${SRCS_G}) + +# Headers +file(GLOB_RECURSE HDRS_G "src/*.h" ) +POCO_HEADERS_AUTO( TEST_SRCS ${HDRS_G}) + +POCO_SOURCES_AUTO_PLAT( TEST_SRCS OFF + src/WinDriver.cpp +) + +POCO_SOURCES_AUTO_PLAT( TEST_SRCS WINCE + src/WinCEDriver.cpp +) + +set(TESTUNIT "${LIBNAME}-testrunner") + +add_executable( ${TESTUNIT} ${TEST_SRCS} ) +add_test(NAME ${LIBNAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${TESTUNIT} -all) +target_link_libraries( ${TESTUNIT} PocoRedis PocoFoundation CppUnit ) diff --git a/Redis/testsuite/Makefile b/Redis/testsuite/Makefile new file mode 100644 index 000000000..e3760770d --- /dev/null +++ b/Redis/testsuite/Makefile @@ -0,0 +1,17 @@ +# +# Makefile +# +# $Id$ +# +# Makefile for Poco Redis testsuite +# + +include $(POCO_BASE)/build/rules/global + +objects = Driver RedisTest RedisTestSuite + +target = testrunner +target_version = 1 +target_libs = PocoRedis PocoFoundation PocoNet CppUnit + +include $(POCO_BASE)/build/rules/exec diff --git a/Redis/testsuite/TestSuite.progen b/Redis/testsuite/TestSuite.progen new file mode 100644 index 000000000..d55b05017 --- /dev/null +++ b/Redis/testsuite/TestSuite.progen @@ -0,0 +1,9 @@ +vc.project.guid = ${vc.project.guidFromName} +vc.project.name = TestSuite +vc.project.target = TestSuite +vc.project.type = testsuite +vc.project.pocobase = ..\\.. +vc.project.platforms = Win32, x64 +vc.project.configurations = debug_shared, release_shared, debug_static_mt, release_static_mt, debug_static_md, release_static_md +vc.project.prototype = TestSuite_vs90.vcproj +vc.project.compiler.include = ..\\..\\Foundation\\include;..\\..\\Net\\include diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 9ec5dd356..1c93e9679 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -25,7 +25,7 @@ using namespace Poco::Redis; bool RedisTest::_connected = false; -Poco::Redis::Connection RedisTest::_redis; +Poco::Redis::Client RedisTest::_redis; RedisTest::RedisTest(const std::string& name): @@ -98,16 +98,55 @@ void RedisTest::testPing() Array command; command.add("PING"); - std::string result; - _redis.sendCommand(command, result); + RedisType::Ptr result = _redis.sendCommand(command); } +void RedisTest::testSet() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("SET"); + command.add("mykey"); + command.add("Hello"); + command.add("NX"); + + RedisType::Ptr result = _redis.sendCommand(command); +} + +void RedisTest::testPipelining() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + std::vector commands; + + Array ping; + ping.add("PING"); + commands.push_back(ping); + commands.push_back(ping); + + std::vector result; + _redis.sendCommands(commands, result); +} + + CppUnit::Test* RedisTest::suite() { CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTest"); CppUnit_addTest(pSuite, RedisTest, testEcho); CppUnit_addTest(pSuite, RedisTest, testPing); + CppUnit_addTest(pSuite, RedisTest, testSet); + + CppUnit_addTest(pSuite, RedisTest, testPipelining); return pSuite; } diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 6c5217ea1..35bfd7a6f 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -32,6 +32,8 @@ public: void testEcho(); void testPing(); + void testSet(); + void testPipelining(); void setUp(); void tearDown(); @@ -43,7 +45,7 @@ private: std::string _host; unsigned _port; static bool _connected; - static Poco::Redis::Connection _redis; + static Poco::Redis::Client _redis; }; diff --git a/components b/components index 1ad691031..a415f7da3 100644 --- a/components +++ b/components @@ -18,5 +18,6 @@ PageCompiler/File2Page PDF CppParser MongoDB +Redis PocoDoc ProGen From 5c077ea4f98aa0e3a6946408031ad58f7b120cb0 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 23 Oct 2015 20:02:47 +0200 Subject: [PATCH 003/121] Remove unnecessary includes --- Redis/include/Poco/Redis/Client.h | 1 - Redis/include/Poco/Redis/Error.h | 1 - Redis/src/Client.cpp | 1 - Redis/src/RedisSocket.cpp | 1 - 4 files changed, 4 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 0ba692c9c..5d1ea5219 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -21,7 +21,6 @@ #include "Poco/Net/SocketAddress.h" -#include "Poco/Optional.h" #include "Poco/Redis/Redis.h" #include "Poco/Redis/Array.h" diff --git a/Redis/include/Poco/Redis/Error.h b/Redis/include/Poco/Redis/Error.h index 2c71edf1b..84cda31b7 100644 --- a/Redis/include/Poco/Redis/Error.h +++ b/Redis/include/Poco/Redis/Error.h @@ -19,7 +19,6 @@ #define Redis_Error_INCLUDED #include "Poco/Redis/Type.h" -#include "Poco/Redis/RedisSocket.h" namespace Poco { namespace Redis { diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index d337b7ed5..66f55933b 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -14,7 +14,6 @@ // // SPDX-License-Identifier: BSL-1.0 // -#include #include "Poco/Redis/Client.h" diff --git a/Redis/src/RedisSocket.cpp b/Redis/src/RedisSocket.cpp index ced4f17b3..cd12a08b5 100644 --- a/Redis/src/RedisSocket.cpp +++ b/Redis/src/RedisSocket.cpp @@ -14,7 +14,6 @@ // // SPDX-License-Identifier: BSL-1.0 // -#include #include "Poco/Redis/RedisSocket.h" namespace Poco { From 0f73e68b023bfaf5ecaa3dfe9b751f1177c1cf95 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 23 Oct 2015 20:06:29 +0200 Subject: [PATCH 004/121] Throw RedisException when redis type can't be determined --- Redis/src/Client.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index 66f55933b..1b289864b 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -14,8 +14,9 @@ // // SPDX-License-Identifier: BSL-1.0 // -#include "Poco/Redis/Client.h" +#include "Poco/Redis/Client.h" +#include "Poco/Redis/Exception.h" namespace Poco { namespace Redis { @@ -92,7 +93,7 @@ RedisType::Ptr Client::readReply() RedisType::Ptr result = createRedisType( _socket.get()); if ( result.isNull() ) { - throw IOException("Invalid Redis type returned"); + throw RedisException("Invalid Redis type returned"); } result->read(_socket); From e66cd6d4f8f4a50272e356a9d03d7fe4c45757a9 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 23 Oct 2015 20:43:13 +0200 Subject: [PATCH 005/121] Remove typeName --- Redis/include/Poco/Redis/Array.h | 5 ----- Redis/include/Poco/Redis/Client.h | 1 + Redis/include/Poco/Redis/Error.h | 5 ----- Redis/include/Poco/Redis/Type.h | 15 --------------- 4 files changed, 1 insertion(+), 25 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 949d7c9af..188a21459 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -96,11 +96,6 @@ struct ElementTraits static const char marker = '*'; - static std::string typeName() - { - return "Array"; - } - static std::string toString(const Array& value) { std::stringstream result; diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 5d1ea5219..74938dbef 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -71,6 +71,7 @@ public: /// Disconnects from the Redis server RedisType::Ptr sendCommand(const Array& command); + /// Sends a Redis command to the server and returns the reply template void sendCommand(const Array& command, T& result) diff --git a/Redis/include/Poco/Redis/Error.h b/Redis/include/Poco/Redis/Error.h index 84cda31b7..82ee1885e 100644 --- a/Redis/include/Poco/Redis/Error.h +++ b/Redis/include/Poco/Redis/Error.h @@ -57,11 +57,6 @@ struct ElementTraits static const char marker = '-'; - static std::string typeName() - { - return "Error"; - } - static std::string toString(const Error& value) { return marker + value.getMessage() + "\r\n"; diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index 3d81ee64b..0a0a3cb2d 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -71,11 +71,6 @@ struct ElementTraits static const char marker = ':'; - static std::string typeName() - { - return "Integer"; - } - static std::string toString(const Poco::Int64& value) { return marker + NumberFormatter::format(value) + "\r\n"; @@ -88,11 +83,6 @@ struct ElementTraits { enum { TypeId = RedisType::REDIS_SIMPLE_STRING }; - static std::string typeName() - { - return "Simple String"; - } - static const char marker = '+'; static std::string toString(const std::string& value) @@ -110,11 +100,6 @@ struct ElementTraits { enum { TypeId = RedisType::REDIS_BULK_STRING }; - static std::string typeName() - { - return "Bulk String"; - } - static const char marker = '$'; static std::string toString(const BulkString& value) From 4c4e41a5ed237340c701d6e01066b4121a07edba Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 23 Oct 2015 21:50:21 +0200 Subject: [PATCH 006/121] Add documentation comments --- Redis/include/Poco/Redis/Client.h | 60 ++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 74938dbef..f59a259ef 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -32,7 +32,27 @@ namespace Redis { class Redis_API Client - /// Represents a connection to a Redis server + /// Represents a connection to a Redis server. + /// + /// A command is always made from an Array and a reply can be a signed 64 + /// bit integer, a simple string, a bulk string, an array or an error. The + /// first element of the command array is the Redis command. A simple string + /// is a string that cannot contain a CR or LF character. A bulk string is + /// implemented as a typedef for Poco::Optional. This is + /// because a bulk string can represent a Null value. When the optional + /// object isn't assigned, you know that a Null value is returned: + /// + /// BulkString bs = client.sendCommand(...); + /// if ( bs.isSpecified() ) + /// { + /// // We have a std::string + /// } + /// else + /// { + /// // We have a Null value + /// } + /// + /// An Array can't contain another Array. { public: typedef Poco::SharedPtr Ptr; @@ -52,14 +72,14 @@ public: /// Constructor which connects to the given Redis host/port. virtual ~Client(); - /// Destructor + /// Destructor. Net::SocketAddress address() const; - /// Returns the address of the Redis connection + /// Returns the address of the Redis connection. void connect(const std::string& hostAndPort); - /// Connects to the given Redis server. The host and port must be separated - /// with a colon. + /// Connects to the given Redis server. The host and port must be + /// separated with a colon. void connect(const std::string& host, int port); /// Connects to the given Redis server. @@ -68,33 +88,51 @@ public: /// Connects to the given Redis server. void disconnect(); - /// Disconnects from the Redis server + /// Disconnects from the Redis server. RedisType::Ptr sendCommand(const Array& command); /// Sends a Redis command to the server and returns the reply template void sendCommand(const Array& command, T& result) + /// Sends a Redis command to the server, gets the reply and tries + /// to convert that reply to the template type. When + /// the reply is a Redis error, it wil throw a RedisException. + /// A BadCastException will be thrown, when the reply is not of the + /// given type. { sendCommand(command); readReply(result); } RedisType::Ptr readReply(); + /// Read a reply from the Redis server. template void readReply(T& result) + /// Read a reply from the Redis server and tries to convert that reply + /// to the template type. When the reply is a Redis error, it will + /// throw a RedisException. A BadCastException will be thrown, when + /// the reply is not of the given type. { RedisType::Ptr redisResult = readReply(); + if ( redisResult->type() == ElementTraits::TypeId ) + { + throw RedisException(((Error*) redisResult.get())->getMessage()); + } if ( redisResult->type() == ElementTraits::TypeId ) result = ((Type*) redisResult.get())->value(); else throw BadCastException(); } - void sendCommands(const std::vector& commands, std::vector& results); + void sendCommands(const std::vector& commands, + std::vector& results); + /// Sends all commands (pipelining) to the Redis server before + /// getting all replies. void writeCommand(const Array& command); - /// Sends a request to the Redis server + /// Sends a request to the Redis server. Use readReply to get the + /// answer. private: @@ -108,6 +146,12 @@ private: /// Connects to the Redis server static RedisType::Ptr createRedisType(char marker); + /// Create a Redis type based on the marker : + /// + : a simple string (std::string) + /// - : an error (Error) + /// $ : a bulk string (BulkString) + /// * : an array (Array) + /// : : a signed 64 bit integer (Int64) }; From 901751f800f7e1bef25a49be9a6b5c1b48efb4d4 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 23 Oct 2015 21:59:00 +0200 Subject: [PATCH 007/121] Whitespace correction --- Redis/include/Poco/Redis/Type.h | 2 +- Redis/src/Client.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index 0a0a3cb2d..6c314ff88 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -31,7 +31,7 @@ namespace Poco { namespace Redis { -class Redis_API RedisType +class Redis_API RedisType { public: diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index 1b289864b..3db3b3559 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -90,7 +90,7 @@ void Client::writeCommand(const Array& command) RedisType::Ptr Client::readReply() { - RedisType::Ptr result = createRedisType( _socket.get()); + RedisType::Ptr result = createRedisType(_socket.get()); if ( result.isNull() ) { throw RedisException("Invalid Redis type returned"); From f77642a77ad58e4b4cf7a3ccde2577a1c4cb3700 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 23 Oct 2015 22:00:50 +0200 Subject: [PATCH 008/121] An array can contain other arrays ... it can even contain an error ... --- Redis/include/Poco/Redis/Array.h | 12 ++++++++++-- Redis/include/Poco/Redis/Client.h | 3 +-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 188a21459..15baf5fcc 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -23,12 +23,14 @@ #include "Poco/Redis/Redis.h" #include "Poco/Redis/Type.h" +#include "Poco/Redis/Error.h" #include "Poco/Redis/Exception.h" namespace Poco { namespace Redis { class Redis_API Array + /// Represents a Redis Array. { public: Array(); @@ -123,13 +125,19 @@ void Type::read(RedisSocket& socket) switch(elementType) { case ElementTraits::marker : - element = new Type(); + element = new Type(); break; case ElementTraits::marker : element = new Type(); break; case ElementTraits::marker : - element = new Type(); + element = new Type(); + break; + case ElementTraits::marker : + element = new Type(); + break; + case ElementTraits::marker : + element = new Type(); break; } diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index f59a259ef..87f5339c4 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -51,8 +51,6 @@ class Redis_API Client /// { /// // We have a Null value /// } - /// - /// An Array can't contain another Array. { public: typedef Poco::SharedPtr Ptr; @@ -152,6 +150,7 @@ private: /// $ : a bulk string (BulkString) /// * : an array (Array) /// : : a signed 64 bit integer (Int64) + friend class Array; }; From f9af763cf6e9a4db7963bcc7e9060baa31c0745e Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 07:42:37 +0100 Subject: [PATCH 009/121] No need to be friends with Connection --- Redis/include/Poco/Redis/Array.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 15baf5fcc..e32df8bc8 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -62,8 +62,6 @@ public: private: std::vector _elements; - - friend class Connection; }; inline std::vector::const_iterator Array::begin() const From 40f20421a83cd8a5d2985bf751669f1255bb9644 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 09:32:00 +0100 Subject: [PATCH 010/121] Use Poco::Nullable instead of Poco::Optional for BulkString --- Redis/include/Poco/Redis/Client.h | 15 +++++++-------- Redis/include/Poco/Redis/Type.h | 19 ++++++++++++++----- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 87f5339c4..c23d42eaa 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -38,18 +38,17 @@ class Redis_API Client /// bit integer, a simple string, a bulk string, an array or an error. The /// first element of the command array is the Redis command. A simple string /// is a string that cannot contain a CR or LF character. A bulk string is - /// implemented as a typedef for Poco::Optional. This is - /// because a bulk string can represent a Null value. When the optional - /// object isn't assigned, you know that a Null value is returned: + /// implemented as a typedef for Poco::Nullable. This is + /// because a bulk string can represent a Null value. /// /// BulkString bs = client.sendCommand(...); - /// if ( bs.isSpecified() ) + /// if ( bs.isNull() ) /// { - /// // We have a std::string + /// // We have a Null value /// } /// else /// { - /// // We have a Null value + /// // We have a string value /// } { public: @@ -92,9 +91,9 @@ public: /// Sends a Redis command to the server and returns the reply template - void sendCommand(const Array& command, T& result) + void sendCommand(const Array& command, T& result) /// Sends a Redis command to the server, gets the reply and tries - /// to convert that reply to the template type. When + /// to convert that reply to the template type. When /// the reply is a Redis error, it wil throw a RedisException. /// A BadCastException will be thrown, when the reply is not of the /// given type. diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index 6c314ff88..aa0a4b458 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -22,7 +22,7 @@ #include "Poco/NumberFormatter.h" #include "Poco/NumberParser.h" #include "Poco/SharedPtr.h" -#include "Poco/Optional.h" +#include "Poco/Nullable.h" #include "Poco/Redis/Redis.h" #include "Poco/Redis/RedisSocket.h" @@ -92,7 +92,9 @@ struct ElementTraits }; -typedef Optional BulkString; +typedef Nullable BulkString; + /// A bulk string is a string that can contain a NULL value. + /// So, BulkString is a typedef for Nullable. template<> @@ -104,12 +106,19 @@ struct ElementTraits static std::string toString(const BulkString& value) { - if ( value.isSpecified() ) + if ( value.isNull() ) + { + return marker + std::string("-1") + LineEnding::NEWLINE_CRLF; + } + else { std::string s = value.value(); - return marker + NumberFormatter::format(s.length()) + LineEnding::NEWLINE_CRLF + s + LineEnding::NEWLINE_CRLF; + return marker + + NumberFormatter::format(s.length()) + + LineEnding::NEWLINE_CRLF + + s + + LineEnding::NEWLINE_CRLF; } - return marker + std::string("-1") + LineEnding::NEWLINE_CRLF; } }; From 74b1ef2bb23cbc69b84803cc3d7dc234fed5cd17 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 12:04:18 +0100 Subject: [PATCH 011/121] Output result of testEcho --- Redis/testsuite/src/RedisTest.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 1c93e9679..795e4fca0 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -83,8 +83,18 @@ void RedisTest::testEcho() command.add("ECHO"); command.add("Hello World"); - BulkString result; - _redis.sendCommand(command, result); + try + { + BulkString result; + _redis.sendCommand(command, result); + + if ( ! result.isNull() ) + std::cout << "Result: " << result.value() << std::endl; + } + catch(RedisException &e) + { + std::cout << e.message() << std::endl; + } } void RedisTest::testPing() From 723704ad161869621e245437d504828109ed140b Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 12:05:00 +0100 Subject: [PATCH 012/121] Move createRedisType to Type --- Redis/include/Poco/Redis/Type.h | 9 +++++++++ Redis/src/Client.cpp | 26 +------------------------- Redis/src/Type.cpp | 29 +++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index aa0a4b458..b3e83a6dc 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -54,6 +54,14 @@ public: REDIS_ERROR }; + static RedisType::Ptr createRedisType(char marker); + /// Create a Redis type based on the marker : + /// + : a simple string (std::string) + /// - : an error (Error) + /// $ : a bulk string (BulkString) + /// * : an array (Array) + /// : : a signed 64 bit integer (Int64) + private: }; @@ -199,6 +207,7 @@ void Type::read(RedisSocket& socket) socket.readLine(line); } + } diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index 3db3b3559..9bc5576eb 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -90,7 +90,7 @@ void Client::writeCommand(const Array& command) RedisType::Ptr Client::readReply() { - RedisType::Ptr result = createRedisType(_socket.get()); + RedisType::Ptr result = RedisType::createRedisType(_socket.get()); if ( result.isNull() ) { throw RedisException("Invalid Redis type returned"); @@ -121,29 +121,5 @@ void Client::sendCommands(const std::vector& commands, std::vector::marker : - result = new Type(); - break; - case ElementTraits::marker : - result = new Type(); - break; - case ElementTraits::marker : - result = new Type(); - break; - case ElementTraits::marker : - result = new Type(); - break; - case ElementTraits::marker : - result = new Type(); - break; - } - return result; -} } } // Poco::Redis diff --git a/Redis/src/Type.cpp b/Redis/src/Type.cpp index 84f1b51fd..e0962f62b 100644 --- a/Redis/src/Type.cpp +++ b/Redis/src/Type.cpp @@ -16,6 +16,8 @@ // #include "Poco/Redis/Type.h" +#include "Poco/Redis/Error.h" +#include "Poco/Redis/Array.h" namespace Poco { namespace Redis { @@ -29,4 +31,31 @@ RedisType::~RedisType() { } + +RedisType::Ptr RedisType::createRedisType(char marker) +{ + RedisType::Ptr result; + + switch(marker) + { + case ElementTraits::marker : + result = new Type(); + break; + case ElementTraits::marker : + result = new Type(); + break; + case ElementTraits::marker : + result = new Type(); + break; + case ElementTraits::marker : + result = new Type(); + break; + case ElementTraits::marker : + result = new Type(); + break; + } + return result; +} + + }} \ No newline at end of file From 605866f1ecb09a2fbc7f19f3283b5010a3d4b2a3 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 12:05:37 +0100 Subject: [PATCH 013/121] Use NEWLINE_CRLF --- Redis/include/Poco/Redis/Error.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Error.h b/Redis/include/Poco/Redis/Error.h index 82ee1885e..59d45b2ac 100644 --- a/Redis/include/Poco/Redis/Error.h +++ b/Redis/include/Poco/Redis/Error.h @@ -59,7 +59,7 @@ struct ElementTraits static std::string toString(const Error& value) { - return marker + value.getMessage() + "\r\n"; + return marker + value.getMessage() + LineEnding::NEWLINE_CRLF; } }; @@ -69,6 +69,9 @@ void Type::read(RedisSocket& socket) { std::string s; socket.readLine(s); + + std::cout << s << std::endl; + _value = s; } From 4012bea1f8a0127057a48f47786e72b89250764e Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 12:05:59 +0100 Subject: [PATCH 014/121] Move createRedisType to Type --- Redis/include/Poco/Redis/Client.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index c23d42eaa..3d4860644 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -141,15 +141,6 @@ private: void connect(); /// Connects to the Redis server - - static RedisType::Ptr createRedisType(char marker); - /// Create a Redis type based on the marker : - /// + : a simple string (std::string) - /// - : an error (Error) - /// $ : a bulk string (BulkString) - /// * : an array (Array) - /// : : a signed 64 bit integer (Int64) - friend class Array; }; From 1a6dbd0b2ddd2784841e13bcb41c8e27ba19dbac Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 12:06:09 +0100 Subject: [PATCH 015/121] Use Nullable --- Redis/include/Poco/Redis/Array.h | 75 +++++++++++++++++--------------- Redis/src/Array.cpp | 21 ++++++--- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index e32df8bc8..bc4bcf67e 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -23,7 +23,6 @@ #include "Poco/Redis/Redis.h" #include "Poco/Redis/Type.h" -#include "Poco/Redis/Error.h" #include "Poco/Redis/Exception.h" namespace Poco { @@ -54,6 +53,8 @@ public: void clear(); std::vector::const_iterator end() const; + + bool isNull() const; std::string toString() const; @@ -61,32 +62,42 @@ public: private: - std::vector _elements; + Nullable > _elements; + + static std::vector _empty; }; inline std::vector::const_iterator Array::begin() const { - return _elements.begin(); + return _elements.value().begin(); } inline void Array::clear() { - _elements.clear(); + if ( !_elements.isNull() ) + { + _elements.value().clear(); + } } inline std::vector::const_iterator Array::end() const { - return _elements.end(); + return _elements.value().end(); +} + +inline bool Array::isNull() const +{ + return _elements.isNull(); } inline size_t Array::size() const { - return _elements.size(); + return _elements.value().size(); } inline void Array::add(RedisType::Ptr value) { - _elements.push_back(value); + _elements.value().push_back(value); } template<> @@ -99,10 +110,19 @@ struct ElementTraits static std::string toString(const Array& value) { std::stringstream result; - result << marker << value.size() << LineEnding::NEWLINE_CRLF; - for(std::vector::const_iterator it = value.begin(); it != value.end(); ++it) + result << marker; + if ( value.isNull() ) { - result << (*it)->toString(); + result << "-1" << LineEnding::NEWLINE_CRLF; + } + else + { + result << value.size() << LineEnding::NEWLINE_CRLF; + for(std::vector::const_iterator it = value.begin(); + it != value.end(); ++it) + { + result << (*it)->toString(); + } } return result.str(); } @@ -115,34 +135,19 @@ void Type::read(RedisSocket& socket) socket.readLine(line); Int64 length = NumberParser::parse64(line); - for(int i = 0; i < length; ++i) + if ( length != -1 ) { - char elementType = socket.get(); - RedisType::Ptr element; - - switch(elementType) + for(int i = 0; i < length; ++i) { - case ElementTraits::marker : - element = new Type(); - break; - case ElementTraits::marker : - element = new Type(); - break; - case ElementTraits::marker : - element = new Type(); - break; - case ElementTraits::marker : - element = new Type(); - break; - case ElementTraits::marker : - element = new Type(); - break; + char marker = socket.get(); + RedisType::Ptr element = Type::createRedisType(marker); + + if ( element.isNull() ) + throw RedisException("Wrong answer received from Redis server"); + + element->read(socket); + _value.add(element); } - - if ( element.isNull() ) throw RedisException("Wrong answer received from Redis server"); - - element->read(socket); - _value.add(element); } } diff --git a/Redis/src/Array.cpp b/Redis/src/Array.cpp index d97693af1..1debc151a 100644 --- a/Redis/src/Array.cpp +++ b/Redis/src/Array.cpp @@ -20,6 +20,9 @@ namespace Poco { namespace Redis { +std::vector Array::_empty; + + Array::Array() { } @@ -36,24 +39,32 @@ Array::~Array() void Array::add(Int64 value) { - _elements.push_back(new Type(value)); + if ( _elements.isNull() ) _elements.assign(_empty); + + _elements.value().push_back(new Type(value)); } void Array::add(const std::string& value) { + if ( _elements.isNull() ) _elements.assign(_empty); + BulkString rs(value); - _elements.push_back(new Type(rs)); + _elements.value().push_back(new Type(rs)); } void Array::add(const BulkString& value) { - _elements.push_back(new Type(value)); + if ( _elements.isNull() ) _elements.assign(_empty); + + _elements.value().push_back(new Type(value)); } void Array::add() { + if ( _elements.isNull() ) _elements.assign(_empty); + BulkString value; - _elements.push_back(new Type(value)); + _elements.value().push_back(new Type(value)); } std::string Array::toString() const @@ -61,4 +72,4 @@ std::string Array::toString() const return ElementTraits::toString(*this); } -} } \ No newline at end of file +} } From 4dc1d2f62df028dfc584f67cd953efc0f55c3027 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 14:34:46 +0100 Subject: [PATCH 016/121] writeCommand must be called in sendCommand --- Redis/include/Poco/Redis/Client.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 3d4860644..b396a2ae9 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -98,7 +98,7 @@ public: /// A BadCastException will be thrown, when the reply is not of the /// given type. { - sendCommand(command); + writeCommand(command); readReply(result); } @@ -119,7 +119,7 @@ public: } if ( redisResult->type() == ElementTraits::TypeId ) result = ((Type*) redisResult.get())->value(); - else throw BadCastException(); + else throw BadCastException(); } void sendCommands(const std::vector& commands, From a46ef4144e4dd1839eca99a00f8dc3c1ebb8b9a3 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 15:20:49 +0100 Subject: [PATCH 017/121] Add checkNull and documentation --- Redis/include/Poco/Redis/Array.h | 30 ++++++++++++++++++++++++++++-- Redis/src/Array.cpp | 10 ++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index bc4bcf67e..4ee3ec175 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -29,42 +29,62 @@ namespace Poco { namespace Redis { class Redis_API Array - /// Represents a Redis Array. + /// Represents a Redis Array. An Array can contain Integers, Strings, + /// Bulk Strings, Errors and other arrays. It can also contain a Null + /// value. { public: Array(); + /// Default constructor. As long as there are no elements added, + /// the array will contain a Null value. Array(const Array& copy); + /// Copy constructor. virtual ~Array(); + /// Destructor. void add(Poco::Int64 value); + /// Adds an integer element. void add(const std::string& value); + /// Adds a simple string element (can't contain a newline!). void add(const BulkString& value); + /// Adds a bulk string element. void add(); + /// Adds a Null bulk string element. void add(RedisType::Ptr value); + /// Adds a Redis element. std::vector::const_iterator begin() const; + /// Returns an iterator to the start of the array. Note: + /// this can throw a NullValueException when this is a Null array. void clear(); std::vector::const_iterator end() const; + /// Returns an iterator to the end of the array. Note: + /// this can throw a NullValueException when this is a Null array. bool isNull() const; + /// Returns true when this is a Null array. std::string toString() const; + /// Returns the String representation as specified in the + /// Redis Protocol specification. size_t size() const; + /// Returns the size of the array. Note: + /// this can throw a NullValueException when this is a Null array. private: Nullable > _elements; - static std::vector _empty; + void checkNull(); }; inline std::vector::const_iterator Array::begin() const @@ -72,6 +92,12 @@ inline std::vector::const_iterator Array::begin() const return _elements.value().begin(); } +inline void Array::checkNull() +{ + std::vector v; + if ( _elements.isNull() ) _elements.assign(v); +} + inline void Array::clear() { if ( !_elements.isNull() ) diff --git a/Redis/src/Array.cpp b/Redis/src/Array.cpp index 1debc151a..0a0d33597 100644 --- a/Redis/src/Array.cpp +++ b/Redis/src/Array.cpp @@ -20,8 +20,6 @@ namespace Poco { namespace Redis { -std::vector Array::_empty; - Array::Array() { @@ -39,14 +37,14 @@ Array::~Array() void Array::add(Int64 value) { - if ( _elements.isNull() ) _elements.assign(_empty); + checkNull(); _elements.value().push_back(new Type(value)); } void Array::add(const std::string& value) { - if ( _elements.isNull() ) _elements.assign(_empty); + checkNull(); BulkString rs(value); _elements.value().push_back(new Type(rs)); @@ -54,14 +52,14 @@ void Array::add(const std::string& value) void Array::add(const BulkString& value) { - if ( _elements.isNull() ) _elements.assign(_empty); + checkNull(); _elements.value().push_back(new Type(value)); } void Array::add() { - if ( _elements.isNull() ) _elements.assign(_empty); + checkNull(); BulkString value; _elements.value().push_back(new Type(value)); From 611f38002fe941d71739268bf2ecb0be0ef0a55a Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 15:56:52 +0100 Subject: [PATCH 018/121] Add some type helper functions --- Redis/include/Poco/Redis/Type.h | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index b3e83a6dc..5fc619a83 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -40,6 +40,16 @@ public: RedisType(); virtual ~RedisType(); + bool isArray() const; + + bool isBulkString() const; + + bool isError() const; + + bool isInteger() const; + + bool isSimpleString() const; + virtual int type() const = 0; virtual void read(RedisSocket& socket) = 0; @@ -66,6 +76,31 @@ private: }; +inline bool RedisType::isArray() const +{ + return type() == REDIS_ARRAY; +} + +inline bool RedisType::isBulkString() const +{ + return type() == REDIS_BULK_STRING; +} + +inline bool RedisType::isError() const +{ + return type() == REDIS_ERROR; +} + +inline bool RedisType::isInteger() const +{ + return type() == REDIS_INTEGER; +} + +inline bool RedisType::isSimpleString() const +{ + return type() == REDIS_SIMPLE_STRING; +} + template struct ElementTraits { From 76905b426a946efb099e98f24e12a426cd9b4518 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 15:57:07 +0100 Subject: [PATCH 019/121] Add more asserts --- Redis/testsuite/src/RedisTest.cpp | 76 ++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 795e4fca0..cd8465aa1 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -88,12 +88,12 @@ void RedisTest::testEcho() BulkString result; _redis.sendCommand(command, result); - if ( ! result.isNull() ) - std::cout << "Result: " << result.value() << std::endl; + assert(!result.isNull()); + assert(result.value().compare("Hello World") == 0); } catch(RedisException &e) { - std::cout << e.message() << std::endl; + fail(e.message()); } } @@ -108,7 +108,34 @@ void RedisTest::testPing() Array command; command.add("PING"); - RedisType::Ptr result = _redis.sendCommand(command); + // A PING without a custom strings, responds with a simple "PONG" string + try + { + std::string result; + _redis.sendCommand(command, result); + + assert(result.compare("PONG") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + // A PING with a custom string responds with a bulk string + command.add("Hello"); + try + { + BulkString result; + _redis.sendCommand(command, result); + + assert(!result.isNull()); + assert(result.value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + } void RedisTest::testSet() @@ -123,9 +150,34 @@ void RedisTest::testSet() command.add("SET"); command.add("mykey"); command.add("Hello"); - command.add("NX"); - RedisType::Ptr result = _redis.sendCommand(command); + // A set responds with a simple OK string + try + { + std::string result; + _redis.sendCommand(command, result); + + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.add("NX"); + // A set NX responds with a Null bulk string + // when the key is already set + try + { + BulkString result; + _redis.sendCommand(command, result); + + assert(result.isNull()); + } + catch(RedisException &e) + { + fail(e.message()); + } } void RedisTest::testPipelining() @@ -145,6 +197,18 @@ void RedisTest::testPipelining() std::vector result; _redis.sendCommands(commands, result); + + // We expect 2 results + assert(result.size() == 2); + + // The 2 results must be simple PONG strings + for(std::vector::iterator it = result.begin(); it != result.end(); ++it) + { + assert((*it)->isSimpleString()); + + std::string pong = ((Type*) it->get())->value(); + assert(pong.compare("PONG") == 0); + } } From 2017e937a699bfeaf703de320fc5494862bf8d5e Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 20:27:53 +0100 Subject: [PATCH 020/121] Use Array to return all replies --- Redis/include/Poco/Redis/Client.h | 7 ++++--- Redis/src/Client.cpp | 5 ++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index b396a2ae9..5d1316b30 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -122,14 +122,15 @@ public: else throw BadCastException(); } - void sendCommands(const std::vector& commands, - std::vector& results); + void sendCommands(const std::vector& commands, Array& results); /// Sends all commands (pipelining) to the Redis server before /// getting all replies. void writeCommand(const Array& command); /// Sends a request to the Redis server. Use readReply to get the - /// answer. + /// answer. Can also be used for pipelining commands. Make sure you + /// call readReply as many times as you called writeCommand, even when + /// an error occurred on a command. private: diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index 9bc5576eb..231302867 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -107,7 +107,7 @@ RedisType::Ptr Client::sendCommand(const Array& command) return readReply(); } -void Client::sendCommands(const std::vector& commands, std::vector& results) +void Client::sendCommands(const std::vector& commands, Array& results) { for(std::vector::const_iterator it = commands.begin(); it != commands.end(); ++it) { @@ -116,8 +116,7 @@ void Client::sendCommands(const std::vector& commands, std::vector Date: Mon, 26 Oct 2015 20:28:49 +0100 Subject: [PATCH 021/121] add (const) T& value() method --- Redis/include/Poco/Redis/Type.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index 5fc619a83..cf76259ac 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -199,7 +199,12 @@ public: return ElementTraits::toString(_value); } - T value() const + T& value() + { + return _value; + } + + const T& value() const { return _value; } From 7b3a796460b3123d4421a9f62e118ca16d52a341 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 20:29:32 +0100 Subject: [PATCH 022/121] Update add methods, make it possible to chain them, ... --- Redis/include/Poco/Redis/Array.h | 100 ++++++++++++++++++++++++++----- Redis/src/Array.cpp | 29 ++------- 2 files changed, 90 insertions(+), 39 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 4ee3ec175..ba4615fa9 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -34,6 +34,9 @@ class Redis_API Array /// value. { public: + + typedef std::vector::const_iterator const_iterator; + Array(); /// Default constructor. As long as there are no elements added, /// the array will contain a Null value. @@ -44,34 +47,67 @@ public: virtual ~Array(); /// Destructor. - void add(Poco::Int64 value); + Array& add(Poco::Int64 value); /// Adds an integer element. - void add(const std::string& value); - /// Adds a simple string element (can't contain a newline!). + Array& add(const std::string& value); + /// Adds a bulk string element. A bulk string is a string that + /// is binary safe (it can contain newlines). If you want a simple + /// string use addSimpleString (can't contain a newline!). - void add(const BulkString& value); + Array& add(const BulkString& value); /// Adds a bulk string element. - void add(); + Array& add(); /// Adds a Null bulk string element. - void add(RedisType::Ptr value); + Array& add(RedisType::Ptr value); /// Adds a Redis element. - std::vector::const_iterator begin() const; + Array& add(const Array& array); + /// Adds an array. + + Array& addSimpleString(const std::string& value); + + const_iterator begin() const; /// Returns an iterator to the start of the array. Note: /// this can throw a NullValueException when this is a Null array. void clear(); + /// Removes all elements from the array. - std::vector::const_iterator end() const; + const_iterator end() const; /// Returns an iterator to the end of the array. Note: /// this can throw a NullValueException when this is a Null array. + template + T get(size_t pos) const + /// Returns the element on the given position and tries to convert + /// to the template type. A BadCastException will be thrown when the + /// the conversion fails. An InvalidArgumentException will be thrown + /// when the index is out of range. When the array is a Null array + /// a NullValueException is thrown. + { + if ( _elements.isNull() ) throw NullValueException(); + + if ( pos >= _elements.value().size() ) throw InvalidArgumentException(); + + RedisType::Ptr element = _elements.value().at(pos); + if ( ElementTraits::TypeId == element->type() ) + { + Type* concrete = dynamic_cast* >(element.get()); + if ( concrete != NULL ) return concrete->value(); + } + throw BadCastException(); + } + bool isNull() const; /// Returns true when this is a Null array. - + + void makeNull(); + /// Turns the array into a Null array. When the array already has some + /// elements, the array will be cleared. + std::string toString() const; /// Returns the String representation as specified in the /// Redis Protocol specification. @@ -87,7 +123,38 @@ private: void checkNull(); }; -inline std::vector::const_iterator Array::begin() const +inline Array& Array::add() +{ + BulkString value; + return add(new Type(value)); +} + +inline Array& Array::add(Int64 value) +{ + return add(new Type(value)); +} + +inline Array& Array::add(const std::string& value) +{ + return add(new Type(value)); +} + +inline Array& Array::add(const BulkString& value) +{ + return add(new Type(value)); +} + +inline Array& Array::add(const Array& value) +{ + return add(new Type(value)); +} + +inline Array& Array::addSimpleString(const std::string& value) +{ + return add(new Type(value)); +} + +inline Array::const_iterator Array::begin() const { return _elements.value().begin(); } @@ -106,7 +173,7 @@ inline void Array::clear() } } -inline std::vector::const_iterator Array::end() const +inline Array::const_iterator Array::end() const { return _elements.value().end(); } @@ -116,15 +183,18 @@ inline bool Array::isNull() const return _elements.isNull(); } +inline void Array::makeNull() +{ + if ( !_elements.isNull() ) _elements.value().clear(); + + _elements.clear(); +} + inline size_t Array::size() const { return _elements.value().size(); } -inline void Array::add(RedisType::Ptr value) -{ - _elements.value().push_back(value); -} template<> struct ElementTraits diff --git a/Redis/src/Array.cpp b/Redis/src/Array.cpp index 0a0d33597..bcf8ef507 100644 --- a/Redis/src/Array.cpp +++ b/Redis/src/Array.cpp @@ -35,35 +35,16 @@ Array::~Array() { } -void Array::add(Int64 value) + +Array& Array::add(RedisType::Ptr value) { checkNull(); - _elements.value().push_back(new Type(value)); + _elements.value().push_back(value); + + return *this; } -void Array::add(const std::string& value) -{ - checkNull(); - - BulkString rs(value); - _elements.value().push_back(new Type(rs)); -} - -void Array::add(const BulkString& value) -{ - checkNull(); - - _elements.value().push_back(new Type(value)); -} - -void Array::add() -{ - checkNull(); - - BulkString value; - _elements.value().push_back(new Type(value)); -} std::string Array::toString() const { From 9d22184a9f82ec83b2a2fcc35897470efca83311 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 20:33:03 +0100 Subject: [PATCH 023/121] Update some tests / Add testPipeliningWithWriteCommand --- Redis/testsuite/src/RedisTest.cpp | 61 ++++++++++++++++++++++++------- Redis/testsuite/src/RedisTest.h | 3 +- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index cd8465aa1..d4744e1cf 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -80,8 +80,8 @@ void RedisTest::testEcho() } Array command; - command.add("ECHO"); - command.add("Hello World"); + command.add("ECHO") + .add("Hello World"); try { @@ -147,9 +147,9 @@ void RedisTest::testSet() } Array command; - command.add("SET"); - command.add("mykey"); - command.add("Hello"); + command.add("SET") + .add("mykey") + .add("Hello"); // A set responds with a simple OK string try @@ -180,7 +180,7 @@ void RedisTest::testSet() } } -void RedisTest::testPipelining() +void RedisTest::testPipeliningWithSendCommands() { if (!_connected) { @@ -195,22 +195,56 @@ void RedisTest::testPipelining() commands.push_back(ping); commands.push_back(ping); - std::vector result; + Array result; _redis.sendCommands(commands, result); // We expect 2 results assert(result.size() == 2); // The 2 results must be simple PONG strings - for(std::vector::iterator it = result.begin(); it != result.end(); ++it) + for(size_t i = 0; i < 2; ++i) { - assert((*it)->isSimpleString()); - - std::string pong = ((Type*) it->get())->value(); - assert(pong.compare("PONG") == 0); + try + { + std::string pong = result.get(i); + assert(pong.compare("PONG") == 0); + } + catch(...) + { + fail("An exception occurred"); + } } } +void RedisTest::testPipeliningWithWriteCommand() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array ping; + ping.add("PING"); + + _redis.writeCommand(ping); + _redis.writeCommand(ping); + + // We expect 2 results with simple "PONG" strings + for(int i = 0; i < 2; ++i) + { + std::string pong; + try + { + _redis.readReply(pong); + assert(pong.compare("PONG") == 0); + } + catch(RedisException& e) + { + fail(e.message()); + } + } +} CppUnit::Test* RedisTest::suite() { @@ -220,7 +254,8 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testPing); CppUnit_addTest(pSuite, RedisTest, testSet); - CppUnit_addTest(pSuite, RedisTest, testPipelining); + CppUnit_addTest(pSuite, RedisTest, testPipeliningWithSendCommands); + CppUnit_addTest(pSuite, RedisTest, testPipeliningWithWriteCommand); return pSuite; } diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 35bfd7a6f..f5ed187f8 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -33,7 +33,8 @@ public: void testEcho(); void testPing(); void testSet(); - void testPipelining(); + void testPipeliningWithSendCommands(); + void testPipeliningWithWriteCommand(); void setUp(); void tearDown(); From cf2450d1c55ffb226c77ba154b1bdde263ba0bbf Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 26 Oct 2015 21:41:27 +0100 Subject: [PATCH 024/121] add testAppend --- Redis/testsuite/src/RedisTest.cpp | 85 +++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 2 files changed, 86 insertions(+) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index d4744e1cf..def85e770 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -71,6 +71,90 @@ void RedisTest::tearDown() } +void RedisTest::testAppend() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array delCommand; + delCommand.add("DEL") + .add("mykey"); + try + { + Poco::Int64 result; + _redis.sendCommand(delCommand, result); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + Array setCommand; + setCommand.add("SET") + .add("mykey") + .add("Hello"); + try + { + std::string result; + _redis.sendCommand(setCommand, result); + assert(result.compare("OK") == 0); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + Array appendCommand; + appendCommand.add("APPEND") + .add("mykey") + .add(" World"); + try + { + Poco::Int64 result; + _redis.sendCommand(appendCommand, result); + + assert(result == 11); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + Array getCommand; + getCommand.add("GET") + .add("mykey"); + try + { + BulkString result; + _redis.sendCommand(getCommand, result); + + assert(result.value().compare("Hello World") == 0); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } +} + void RedisTest::testEcho() { if (!_connected) @@ -250,6 +334,7 @@ CppUnit::Test* RedisTest::suite() { CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTest"); + CppUnit_addTest(pSuite, RedisTest, testAppend); CppUnit_addTest(pSuite, RedisTest, testEcho); CppUnit_addTest(pSuite, RedisTest, testPing); CppUnit_addTest(pSuite, RedisTest, testSet); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index f5ed187f8..66b8c4375 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -30,6 +30,7 @@ public: virtual ~RedisTest(); + void testAppend(); void testEcho(); void testPing(); void testSet(); From 2d0c312be372f7e985ba5755d260c6e1be0acbc4 Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 27 Oct 2015 22:04:38 +0100 Subject: [PATCH 025/121] More tests ... --- Redis/testsuite/src/RedisTest.cpp | 438 ++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 7 + 2 files changed, 445 insertions(+) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index def85e770..348beb53e 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -181,6 +181,93 @@ void RedisTest::testEcho() } } +void RedisTest::testIncr() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("SET") + .add("mykey") + .add("10"); + + // A set responds with a simple OK string + try + { + std::string result; + _redis.sendCommand(command, result); + + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.clear(); + command.add("INCR") + .add("mykey"); + + try + { + Poco::Int64 value; + _redis.sendCommand(command, value); + + assert(value == 11); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testIncrBy() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("SET") + .add("mykey") + .add("10"); + + // A set responds with a simple OK string + try + { + std::string result; + _redis.sendCommand(command, result); + + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.clear(); + command.add("INCRBY") + .add("mykey") + .add("5"); + + try + { + Poco::Int64 value; + _redis.sendCommand(command, value); + + assert(value == 15); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testPing() { if (!_connected) @@ -264,6 +351,350 @@ void RedisTest::testSet() } } +void RedisTest::testMSet() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("MSET") + .add("key1") + .add("Hello") + .add("key2") + .add("World"); + + // A MSET responds with a simple OK string + try + { + std::string result; + _redis.sendCommand(command, result); + + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.clear(); + command.add("MGET") + .add("key1") + .add("key2") + .add("nonexisting"); + try + { + Array result; + _redis.sendCommand(command, result); + + assert(result.size() == 3); + BulkString value = result.get(0); + assert(value.value().compare("Hello") == 0); + + value = result.get(1); + assert(value.value().compare("World") == 0); + + value = result.get(2); + assert(value.isNull()); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } +} + +void RedisTest::testStrlen() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("SET") + .add("mykey") + .add("Hello World"); + + // A set responds with a simple OK string + try + { + std::string result; + _redis.sendCommand(command, result); + + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.clear(); + command.add("STRLEN") + .add("mykey"); + + try + { + Poco::Int64 result; + _redis.sendCommand(command, result); + + assert(result == 11); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testRPush() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + Array delCommand; + delCommand.add("DEL") + .add("mylist"); + try + { + Poco::Int64 result; + _redis.sendCommand(delCommand, result); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + for(int i = 0; i < 2; ++i) + { + Array command; + command.add("RPUSH") + .add("mylist"); + + if ( i == 0 ) command.add("Hello"); + else command.add("World"); + + // A RPUSH responds with an integer + try + { + Poco::Int64 result; + _redis.sendCommand(command, result); + + assert(result == (i + 1)); + } + catch(RedisException &e) + { + fail(e.message()); + } + } + + Array command; + command.add("LRANGE") + .add("mylist") + .add("0") + .add("-1"); + + try + { + Array result; + _redis.sendCommand(command, result); + + assert(result.size() == 2); + BulkString value = result.get(0); + assert(value.value().compare("Hello") == 0); + + value = result.get(1); + assert(value.value().compare("World") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testLIndex() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + Array delCommand; + delCommand.add("DEL") + .add("mylist"); + try + { + Poco::Int64 result; + _redis.sendCommand(delCommand, result); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + for(int i = 0; i < 2; ++i) + { + Array command; + command.add("LPUSH") + .add("mylist"); + + if ( i == 0 ) command.add("World"); + else command.add("Hello"); + + // A RPUSH responds with an integer + try + { + Poco::Int64 result; + _redis.sendCommand(command, result); + + assert(result == (i + 1)); + } + catch(RedisException &e) + { + fail(e.message()); + } + } + + Array command; + command.add("LINDEX") + .add("mylist") + .add("0"); + + try + { + BulkString result; + _redis.sendCommand(command, result); + + assert(result.value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testMulti() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure keys are gone from a previous testrun ... + Array delCommand; + delCommand.add("DEL") + .add("foo") + .add("bar"); + try + { + Poco::Int64 result; + _redis.sendCommand(delCommand, result); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + Array command; + command.add("MULTI"); + try + { + std::string result; + _redis.sendCommand(command, result); + assert(result.compare("OK") == 0); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + command.clear(); + command.add("INCR") + .add("foo"); + try + { + std::string result; + _redis.sendCommand(command, result); + assert(result.compare("QUEUED") == 0); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + command.clear(); + command.add("INCR") + .add("bar"); + try + { + std::string result; + _redis.sendCommand(command, result); + assert(result.compare("QUEUED") == 0); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + command.clear(); + command.add("EXEC"); + try + { + Array result; + _redis.sendCommand(command, result); + assert(result.size() == 2); + + Poco::Int64 v = result.get(0); + assert(v == 1); + v = result.get(1); + assert(v == 1); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } +} + void RedisTest::testPipeliningWithSendCommands() { if (!_connected) @@ -335,9 +766,16 @@ CppUnit::Test* RedisTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTest"); CppUnit_addTest(pSuite, RedisTest, testAppend); + CppUnit_addTest(pSuite, RedisTest, testIncr); + CppUnit_addTest(pSuite, RedisTest, testIncrBy); CppUnit_addTest(pSuite, RedisTest, testEcho); CppUnit_addTest(pSuite, RedisTest, testPing); CppUnit_addTest(pSuite, RedisTest, testSet); + CppUnit_addTest(pSuite, RedisTest, testMSet); + CppUnit_addTest(pSuite, RedisTest, testStrlen); + CppUnit_addTest(pSuite, RedisTest, testRPush); + CppUnit_addTest(pSuite, RedisTest, testLIndex); + CppUnit_addTest(pSuite, RedisTest, testMulti); CppUnit_addTest(pSuite, RedisTest, testPipeliningWithSendCommands); CppUnit_addTest(pSuite, RedisTest, testPipeliningWithWriteCommand); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 66b8c4375..67590d717 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -32,8 +32,15 @@ public: void testAppend(); void testEcho(); + void testIncr(); + void testIncrBy(); void testPing(); void testSet(); + void testMSet(); + void testStrlen(); + void testRPush(); + void testLIndex(); + void testMulti(); void testPipeliningWithSendCommands(); void testPipeliningWithWriteCommand(); From 064f8ef2de1982eafe8fdc6c9fd5e4ba3a5d5109 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 2 Nov 2015 08:06:32 +0100 Subject: [PATCH 026/121] Work on AsyncClient and add execute method --- Redis/Makefile | 2 +- Redis/include/Poco/Redis/AsyncClient.h | 98 +++++++++++++++ Redis/include/Poco/Redis/Client.h | 68 +++++++---- Redis/include/Poco/Redis/RedisSocket.h | 6 +- Redis/src/AsyncClient.cpp | 75 ++++++++++++ Redis/src/Client.cpp | 32 ++++- Redis/src/RedisSocket.cpp | 6 + Redis/testsuite/src/RedisTest.cpp | 159 ++++++++++++------------- Redis/testsuite/src/RedisTest.h | 7 +- 9 files changed, 340 insertions(+), 113 deletions(-) create mode 100644 Redis/include/Poco/Redis/AsyncClient.h create mode 100644 Redis/src/AsyncClient.cpp diff --git a/Redis/Makefile b/Redis/Makefile index 63dcb39e7..4443b01c6 100644 --- a/Redis/Makefile +++ b/Redis/Makefile @@ -10,7 +10,7 @@ include $(POCO_BASE)/build/rules/global INCLUDE += -I $(POCO_BASE)/Redis/include/Poco/Redis -objects = Array Client Error Exception RedisSocket Type +objects = AsyncClient Array Client Error Exception RedisSocket Type target = PocoRedis target_version = $(LIBVERSION) diff --git a/Redis/include/Poco/Redis/AsyncClient.h b/Redis/include/Poco/Redis/AsyncClient.h new file mode 100644 index 000000000..6541bab23 --- /dev/null +++ b/Redis/include/Poco/Redis/AsyncClient.h @@ -0,0 +1,98 @@ +// +// AsyncClient.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: AsyncClient +// +// Definition of the AsyncClient class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Redis_AsyncClient_INCLUDED +#define Redis_AsyncClient_INCLUDED + + +#include "Poco/Redis/Redis.h" +#include "Poco/Redis/Client.h" +#include "Poco/Activity.h" + +namespace Poco { +namespace Redis { + + +class Redis_API AsyncClient : public Client +{ +public: + + + BasicEvent redisResponse; + + + AsyncClient(); + /// Default constructor. Use this when you want to + /// connect later on. + + AsyncClient(const std::string& hostAndPort); + /// Constructor which connects to the given Redis host/port. + /// The host and port must be separated with a colon. + + AsyncClient(const std::string& host, int port); + /// Constructor which connects to the given Redis host/port. + + AsyncClient(const Net::SocketAddress& addrs); + /// Constructor which connects to the given Redis host/port. + + virtual ~AsyncClient(); + /// Destructor + + bool isStopped(); + /// Returns true if the activity is not running, false when it is. + + void start(); + /// Starts the activity to read replies from the Redis server. + + void stop(); + /// Stops the read activity. + +protected: + + void runActivity(); + +private: + + AsyncClient(const AsyncClient&); + AsyncClient& operator = (const AsyncClient&); + + + Activity _activity; + +}; + + +inline bool AsyncClient::isStopped() +{ + return _activity.isStopped(); +} + +inline void AsyncClient::start() +{ + _activity.start(); +} + +inline void AsyncClient::stop() +{ + _activity.stop(); +} + + +} } // namespace Poco::Redis + +#endif //Redis_Client_INCLUDED diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 5d1316b30..3f7ebab34 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -16,11 +16,11 @@ // -#ifndef Redis_Connection_INCLUDED -#define Redis_Connection_INCLUDED - +#ifndef Redis_Client_INCLUDED +#define Redis_Client_INCLUDED #include "Poco/Net/SocketAddress.h" +#include "Poco/Timespan.h" #include "Poco/Redis/Redis.h" #include "Poco/Redis/Array.h" @@ -41,7 +41,7 @@ class Redis_API Client /// implemented as a typedef for Poco::Nullable. This is /// because a bulk string can represent a Null value. /// - /// BulkString bs = client.sendCommand(...); + /// BulkString bs = client.execute(...); /// if ( bs.isNull() ) /// { /// // We have a Null value @@ -84,24 +84,41 @@ public: void connect(const Net::SocketAddress& addrs); /// Connects to the given Redis server. + void connect(const std::string& hostAndPort, const Timespan& timeout); + /// Connects to the given Redis server. The host and port must be + /// separated with a colon. + + void connect(const std::string& host, int port, const Timespan& timeout); + /// Connects to the given Redis server. + + void connect(const Net::SocketAddress& addrs, const Timespan& timeout); + /// Connects to the given Redis server. + void disconnect(); /// Disconnects from the Redis server. - RedisType::Ptr sendCommand(const Array& command); - /// Sends a Redis command to the server and returns the reply - template - void sendCommand(const Array& command, T& result) - /// Sends a Redis command to the server, gets the reply and tries - /// to convert that reply to the template type. When - /// the reply is a Redis error, it wil throw a RedisException. - /// A BadCastException will be thrown, when the reply is not of the - /// given type. + T execute(const Array& command) + /// Sends the Redis Command to the server. It gets the reply + /// and tries to convert it to the given template type. + /// A specialization exists for type void, which doesn't read + /// the reply. If the server sends a reply, it is your + /// responsibility to read it ... (Use this for pipelining) + /// A BadCastException will be thrown when the reply couldn't be + /// converted. Supported types are Int64, std::string, BulkString, + /// Array and void. When the reply is an Error, it will throw + /// a RedisException. { + T result; writeCommand(command); readReply(result); + return result; } + RedisType::Ptr sendCommand(const Array& command); + /// Sends a Redis command to the server and returns the reply. + /// Use this when the type of the reply isn't known. + RedisType::Ptr readReply(); /// Read a reply from the Redis server. @@ -122,16 +139,10 @@ public: else throw BadCastException(); } - void sendCommands(const std::vector& commands, Array& results); + Array sendCommands(const std::vector& commands); /// Sends all commands (pipelining) to the Redis server before /// getting all replies. - void writeCommand(const Array& command); - /// Sends a request to the Redis server. Use readReply to get the - /// answer. Can also be used for pipelining commands. Make sure you - /// call readReply as many times as you called writeCommand, even when - /// an error occurred on a command. - private: Client(const Client&); @@ -142,6 +153,15 @@ private: void connect(); /// Connects to the Redis server + void connect(const Timespan& timeout); + /// Connects to the Redis server and sets a timeout. + + void writeCommand(const Array& command); + /// Sends a request to the Redis server. Use readReply to get the + /// answer. Can also be used for pipelining commands. Make sure you + /// call readReply as many times as you called writeCommand, even when + /// an error occurred on a command. + }; @@ -150,8 +170,14 @@ inline Net::SocketAddress Client::address() const return _address; } +template<> inline +void Client::execute(const Array& command) +{ + writeCommand(command); +} + } } // namespace Poco::Redis -#endif //Redis_Connection_INCLUDED +#endif //Redis_Client_INCLUDED diff --git a/Redis/include/Poco/Redis/RedisSocket.h b/Redis/include/Poco/Redis/RedisSocket.h index f0f6aefd2..7eb0cf8f5 100644 --- a/Redis/include/Poco/Redis/RedisSocket.h +++ b/Redis/include/Poco/Redis/RedisSocket.h @@ -18,6 +18,7 @@ #ifndef Redis_RedisSocket_INCLUDED #define Redis_RedisSocket_INCLUDED +#include "Poco/Timespan.h" #include "Poco/Net/SocketAddress.h" #include "Poco/Net/StreamSocket.h" @@ -37,6 +38,8 @@ public: void connect(const Net::SocketAddress& addrs); + void connect(const Net::SocketAddress& addrs, const Timespan& timeout); + int get(); int peek(); @@ -45,8 +48,6 @@ public: int write(const char* buffer, std::streamsize length); - int buffered(); - void refill(); void readLine(std::string& line); @@ -63,6 +64,7 @@ private: char* _end; }; + } } #endif // Redis_RedisSocket_INCLUDED diff --git a/Redis/src/AsyncClient.cpp b/Redis/src/AsyncClient.cpp new file mode 100644 index 000000000..691bf4a99 --- /dev/null +++ b/Redis/src/AsyncClient.cpp @@ -0,0 +1,75 @@ +// +// AsyncClient.cpp +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: AsyncClient +// +// Implementation of the AsyncClient class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include "Poco/Redis/AsyncClient.h" + +namespace Poco { +namespace Redis { + + +AsyncClient::AsyncClient() : Client(), + _activity(this, &AsyncClient::runActivity) +{ +} + + +AsyncClient::AsyncClient(const std::string& hostAndPort) : Client(hostAndPort), + _activity(this, &AsyncClient::runActivity) +{ +} + + +AsyncClient::AsyncClient(const std::string& host, int port) : Client(host, port), + _activity(this, &AsyncClient::runActivity) +{ +} + + +AsyncClient::AsyncClient(const Net::SocketAddress& addrs) : Client(addrs), + _activity(this, &AsyncClient::runActivity) +{ +} + + +AsyncClient::~AsyncClient() +{ + stop(); +} + + +void AsyncClient::runActivity() +{ + while(!_activity.isStopped()) + { + try + { + RedisType::Ptr reply = readReply(); + redisResponse.notify(this, reply); + } + catch(TimeoutException&) + { + continue; + } + catch(Exception &) + { + stop(); + } + } +} + + +} } // Poco::Redis diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index 231302867..b8220253c 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -55,7 +55,6 @@ void Client::connect() _socket.connect(_address); } - void Client::connect(const std::string& hostAndPort) { _address = Net::SocketAddress(hostAndPort); @@ -76,6 +75,30 @@ void Client::connect(const Net::SocketAddress& addrs) connect(); } +void Client::connect(const Timespan& timeout) +{ + _socket.connect(_address, timeout); +} + +void Client::connect(const std::string& hostAndPort, const Timespan& timeout) +{ + _address = Net::SocketAddress(hostAndPort); + connect(timeout); +} + + +void Client::connect(const std::string& host, int port, const Timespan& timeout) +{ + _address = Net::SocketAddress(host, port); + connect(timeout); +} + + +void Client::connect(const Net::SocketAddress& addrs, const Timespan& timeout) +{ + _address = addrs; + connect(timeout); +} void Client::disconnect() { @@ -107,8 +130,10 @@ RedisType::Ptr Client::sendCommand(const Array& command) return readReply(); } -void Client::sendCommands(const std::vector& commands, Array& results) +Array Client::sendCommands(const std::vector& commands) { + Array results; + for(std::vector::const_iterator it = commands.begin(); it != commands.end(); ++it) { writeCommand(*it); @@ -118,7 +143,8 @@ void Client::sendCommands(const std::vector& commands, Array& results) { results.add(readReply()); } + + return results; } - } } // Poco::Redis diff --git a/Redis/src/RedisSocket.cpp b/Redis/src/RedisSocket.cpp index cd12a08b5..64494b425 100644 --- a/Redis/src/RedisSocket.cpp +++ b/Redis/src/RedisSocket.cpp @@ -46,6 +46,12 @@ void RedisSocket::connect(const Net::SocketAddress& addrs) _socket.connect(addrs); } +void RedisSocket::connect(const Net::SocketAddress& addrs, const Timespan& timeout) +{ + _socket.connect(addrs, timeout); +} + + int RedisSocket::get() { if ( _current == _end ) refill(); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 348beb53e..f9798a6b6 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -10,13 +10,11 @@ // #include -#include "Poco/DateTime.h" -#include "Poco/ObjectPool.h" - #include "Poco/Net/NetException.h" +#include "Poco/Delegate.h" +#include "Poco/Thread.h" #include "RedisTest.h" -#include "Poco/Redis/Client.h" #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" @@ -25,7 +23,7 @@ using namespace Poco::Redis; bool RedisTest::_connected = false; -Poco::Redis::Client RedisTest::_redis; +Poco::Redis::AsyncClient RedisTest::_redis; RedisTest::RedisTest(const std::string& name): @@ -37,7 +35,8 @@ RedisTest::RedisTest(const std::string& name): { try { - _redis.connect(_host, _port); + Poco::Timespan t(30, 0); // 30 seconds + _redis.connect(_host, _port, t); _connected = true; std::cout << "Connected to [" << _host << ':' << _port << ']' << std::endl; } @@ -84,8 +83,7 @@ void RedisTest::testAppend() .add("mykey"); try { - Poco::Int64 result; - _redis.sendCommand(delCommand, result); + _redis.execute(delCommand); } catch(RedisException& e) { @@ -102,8 +100,7 @@ void RedisTest::testAppend() .add("Hello"); try { - std::string result; - _redis.sendCommand(setCommand, result); + std::string result = _redis.execute(setCommand); assert(result.compare("OK") == 0); } catch(RedisException& e) @@ -121,9 +118,7 @@ void RedisTest::testAppend() .add(" World"); try { - Poco::Int64 result; - _redis.sendCommand(appendCommand, result); - + Poco::Int64 result = _redis.execute(appendCommand); assert(result == 11); } catch(RedisException& e) @@ -140,9 +135,7 @@ void RedisTest::testAppend() .add("mykey"); try { - BulkString result; - _redis.sendCommand(getCommand, result); - + BulkString result = _redis.execute(getCommand); assert(result.value().compare("Hello World") == 0); } catch(RedisException& e) @@ -169,9 +162,7 @@ void RedisTest::testEcho() try { - BulkString result; - _redis.sendCommand(command, result); - + BulkString result = _redis.execute(command); assert(!result.isNull()); assert(result.value().compare("Hello World") == 0); } @@ -197,9 +188,7 @@ void RedisTest::testIncr() // A set responds with a simple OK string try { - std::string result; - _redis.sendCommand(command, result); - + std::string result = _redis.execute(command); assert(result.compare("OK") == 0); } catch(RedisException &e) @@ -213,9 +202,7 @@ void RedisTest::testIncr() try { - Poco::Int64 value; - _redis.sendCommand(command, value); - + Poco::Int64 value = _redis.execute(command); assert(value == 11); } catch(RedisException &e) @@ -240,9 +227,7 @@ void RedisTest::testIncrBy() // A set responds with a simple OK string try { - std::string result; - _redis.sendCommand(command, result); - + std::string result = _redis.execute(command); assert(result.compare("OK") == 0); } catch(RedisException &e) @@ -257,9 +242,7 @@ void RedisTest::testIncrBy() try { - Poco::Int64 value; - _redis.sendCommand(command, value); - + Poco::Int64 value = _redis.execute(command); assert(value == 15); } catch(RedisException &e) @@ -282,9 +265,7 @@ void RedisTest::testPing() // A PING without a custom strings, responds with a simple "PONG" string try { - std::string result; - _redis.sendCommand(command, result); - + std::string result = _redis.execute(command); assert(result.compare("PONG") == 0); } catch(RedisException &e) @@ -296,9 +277,7 @@ void RedisTest::testPing() command.add("Hello"); try { - BulkString result; - _redis.sendCommand(command, result); - + BulkString result = _redis.execute(command); assert(!result.isNull()); assert(result.value().compare("Hello") == 0); } @@ -325,9 +304,7 @@ void RedisTest::testSet() // A set responds with a simple OK string try { - std::string result; - _redis.sendCommand(command, result); - + std::string result = _redis.execute(command); assert(result.compare("OK") == 0); } catch(RedisException &e) @@ -340,9 +317,7 @@ void RedisTest::testSet() // when the key is already set try { - BulkString result; - _redis.sendCommand(command, result); - + BulkString result = _redis.execute(command); assert(result.isNull()); } catch(RedisException &e) @@ -369,9 +344,7 @@ void RedisTest::testMSet() // A MSET responds with a simple OK string try { - std::string result; - _redis.sendCommand(command, result); - + std::string result = _redis.execute(command); assert(result.compare("OK") == 0); } catch(RedisException &e) @@ -386,8 +359,7 @@ void RedisTest::testMSet() .add("nonexisting"); try { - Array result; - _redis.sendCommand(command, result); + Array result = _redis.execute(command); assert(result.size() == 3); BulkString value = result.get(0); @@ -425,9 +397,7 @@ void RedisTest::testStrlen() // A set responds with a simple OK string try { - std::string result; - _redis.sendCommand(command, result); - + std::string result = _redis.execute(command); assert(result.compare("OK") == 0); } catch(RedisException &e) @@ -441,8 +411,7 @@ void RedisTest::testStrlen() try { - Poco::Int64 result; - _redis.sendCommand(command, result); + Poco::Int64 result = _redis.execute(command); assert(result == 11); } @@ -466,8 +435,7 @@ void RedisTest::testRPush() .add("mylist"); try { - Poco::Int64 result; - _redis.sendCommand(delCommand, result); + _redis.execute(delCommand); } catch(RedisException& e) { @@ -490,9 +458,7 @@ void RedisTest::testRPush() // A RPUSH responds with an integer try { - Poco::Int64 result; - _redis.sendCommand(command, result); - + Poco::Int64 result = _redis.execute(command); assert(result == (i + 1)); } catch(RedisException &e) @@ -509,8 +475,7 @@ void RedisTest::testRPush() try { - Array result; - _redis.sendCommand(command, result); + Array result = _redis.execute(command); assert(result.size() == 2); BulkString value = result.get(0); @@ -539,8 +504,7 @@ void RedisTest::testLIndex() .add("mylist"); try { - Poco::Int64 result; - _redis.sendCommand(delCommand, result); + _redis.execute(delCommand); } catch(RedisException& e) { @@ -563,9 +527,7 @@ void RedisTest::testLIndex() // A RPUSH responds with an integer try { - Poco::Int64 result; - _redis.sendCommand(command, result); - + Poco::Int64 result = _redis.execute(command); assert(result == (i + 1)); } catch(RedisException &e) @@ -581,9 +543,7 @@ void RedisTest::testLIndex() try { - BulkString result; - _redis.sendCommand(command, result); - + BulkString result = _redis.execute(command); assert(result.value().compare("Hello") == 0); } catch(RedisException &e) @@ -607,8 +567,7 @@ void RedisTest::testMulti() .add("bar"); try { - Poco::Int64 result; - _redis.sendCommand(delCommand, result); + _redis.execute(delCommand); } catch(RedisException& e) { @@ -623,8 +582,7 @@ void RedisTest::testMulti() command.add("MULTI"); try { - std::string result; - _redis.sendCommand(command, result); + std::string result = _redis.execute(command); assert(result.compare("OK") == 0); } catch(RedisException& e) @@ -641,8 +599,7 @@ void RedisTest::testMulti() .add("foo"); try { - std::string result; - _redis.sendCommand(command, result); + std::string result = _redis.execute(command); assert(result.compare("QUEUED") == 0); } catch(RedisException& e) @@ -659,8 +616,7 @@ void RedisTest::testMulti() .add("bar"); try { - std::string result; - _redis.sendCommand(command, result); + std::string result = _redis.execute(command); assert(result.compare("QUEUED") == 0); } catch(RedisException& e) @@ -676,8 +632,7 @@ void RedisTest::testMulti() command.add("EXEC"); try { - Array result; - _redis.sendCommand(command, result); + Array result = _redis.execute(command); assert(result.size() == 2); Poco::Int64 v = result.get(0); @@ -710,8 +665,7 @@ void RedisTest::testPipeliningWithSendCommands() commands.push_back(ping); commands.push_back(ping); - Array result; - _redis.sendCommands(commands, result); + Array result = _redis.sendCommands(commands); // We expect 2 results assert(result.size() == 2); @@ -719,7 +673,7 @@ void RedisTest::testPipeliningWithSendCommands() // The 2 results must be simple PONG strings for(size_t i = 0; i < 2; ++i) { - try + try { std::string pong = result.get(i); assert(pong.compare("PONG") == 0); @@ -742,14 +696,14 @@ void RedisTest::testPipeliningWithWriteCommand() Array ping; ping.add("PING"); - _redis.writeCommand(ping); - _redis.writeCommand(ping); + _redis.execute(ping); + _redis.execute(ping); // We expect 2 results with simple "PONG" strings for(int i = 0; i < 2; ++i) { std::string pong; - try + try { _redis.readReply(pong); assert(pong.compare("PONG") == 0); @@ -761,6 +715,41 @@ void RedisTest::testPipeliningWithWriteCommand() } } +class RedisSubscriber +{ +public: + + void onMessage(const void* pSender, RedisType::Ptr& message) + { + std::cout << message->toString() << std::endl; + } + +}; + +void RedisTest::testPubSub() +{ + RedisSubscriber subscriber; + + Array subscribe; + subscribe.add("SUBSCRIBE") + .add("test"); + + Array subscribeReply = _redis.execute(subscribe); + + _redis.redisResponse += Poco::delegate(&subscriber, &RedisSubscriber::onMessage); + _redis.start(); + + Poco::Thread::sleep(30000); + + Array unsubscribe; + unsubscribe.add("UNSUBSCRIBE"); + + Array unsubscribeReply = _redis.execute(unsubscribe); + std::cout << "SUBS: " << unsubscribeReply.toString() << std::endl; + + _redis.stop(); +} + CppUnit::Test* RedisTest::suite() { CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTest"); @@ -777,6 +766,8 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testLIndex); CppUnit_addTest(pSuite, RedisTest, testMulti); + CppUnit_addTest(pSuite, RedisTest, testPubSub); + CppUnit_addTest(pSuite, RedisTest, testPipeliningWithSendCommands); CppUnit_addTest(pSuite, RedisTest, testPipeliningWithWriteCommand); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 67590d717..e2f46f672 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -17,7 +17,7 @@ #include "Poco/Redis/Redis.h" -#include "Poco/Redis/Client.h" +#include "Poco/Redis/AsyncClient.h" #include "CppUnit/TestCase.h" @@ -41,6 +41,9 @@ public: void testRPush(); void testLIndex(); void testMulti(); + + void testPubSub(); + void testPipeliningWithSendCommands(); void testPipeliningWithWriteCommand(); @@ -54,7 +57,7 @@ private: std::string _host; unsigned _port; static bool _connected; - static Poco::Redis::Client _redis; + static Poco::Redis::AsyncClient _redis; }; From ae7c0c095ac7484c99d08e55d645f7c8a0c0b526 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 2 Nov 2015 22:07:31 +0100 Subject: [PATCH 027/121] Add ENABLE_REDIS --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index abf9507cc..bbc5d76fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ option(ENABLE_CPPPARSER "Enable C++ parser" OFF) option(ENABLE_POCODOC "Enable Poco Documentation Generator" OFF) option(ENABLE_PAGECOMPILER "Enable PageCompiler" ON) option(ENABLE_PAGECOMPILER_FILE2PAGE "Enable File2Page" ON) +option(ENABLE_REDIS "Enable Redis" ON) option(FORCE_OPENSSL "Force usage of OpenSSL even under windows" OFF) @@ -192,6 +193,10 @@ if(ENABLE_ZIP) add_subdirectory(Zip) list(APPEND Poco_COMPONENTS "Zip") endif() +if(ENABLE_REDIS) +add_subdirectory(Redis) +list(APPEND Poco_COMPONENTS "Redis") +endif() find_package(APR) find_package(Apache2) From 93a2cced8d0fd8afd337b03f8a241c23fd0a5771 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 2 Nov 2015 22:07:49 +0100 Subject: [PATCH 028/121] No samples yet ... --- Redis/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Redis/CMakeLists.txt b/Redis/CMakeLists.txt index c630784d8..191014eee 100644 --- a/Redis/CMakeLists.txt +++ b/Redis/CMakeLists.txt @@ -31,7 +31,7 @@ POCO_INSTALL("${LIBNAME}") POCO_GENERATE_PACKAGE("${LIBNAME}") if (ENABLE_TESTS) - add_subdirectory(samples) +# add_subdirectory(samples) add_subdirectory(testsuite) endif () From cb8b6cfe8d448176a53ed42a2a36bee6d3853319 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 2 Nov 2015 22:08:27 +0100 Subject: [PATCH 029/121] Renamed AsyncClient into AsyncReader --- Redis/Makefile | 2 +- Redis/include/Poco/Redis/AsyncClient.h | 98 -------------------------- Redis/include/Poco/Redis/AsyncReader.h | 92 ++++++++++++++++++++++++ Redis/src/AsyncClient.cpp | 75 -------------------- Redis/src/AsyncReader.cpp | 57 +++++++++++++++ 5 files changed, 150 insertions(+), 174 deletions(-) delete mode 100644 Redis/include/Poco/Redis/AsyncClient.h create mode 100644 Redis/include/Poco/Redis/AsyncReader.h delete mode 100644 Redis/src/AsyncClient.cpp create mode 100644 Redis/src/AsyncReader.cpp diff --git a/Redis/Makefile b/Redis/Makefile index 4443b01c6..b110ce63e 100644 --- a/Redis/Makefile +++ b/Redis/Makefile @@ -10,7 +10,7 @@ include $(POCO_BASE)/build/rules/global INCLUDE += -I $(POCO_BASE)/Redis/include/Poco/Redis -objects = AsyncClient Array Client Error Exception RedisSocket Type +objects = AsyncReader Array Client Error Exception RedisSocket Type target = PocoRedis target_version = $(LIBVERSION) diff --git a/Redis/include/Poco/Redis/AsyncClient.h b/Redis/include/Poco/Redis/AsyncClient.h deleted file mode 100644 index 6541bab23..000000000 --- a/Redis/include/Poco/Redis/AsyncClient.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// AsyncClient.h -// -// $Id$ -// -// Library: Redis -// Package: Redis -// Module: AsyncClient -// -// Definition of the AsyncClient class. -// -// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// - - -#ifndef Redis_AsyncClient_INCLUDED -#define Redis_AsyncClient_INCLUDED - - -#include "Poco/Redis/Redis.h" -#include "Poco/Redis/Client.h" -#include "Poco/Activity.h" - -namespace Poco { -namespace Redis { - - -class Redis_API AsyncClient : public Client -{ -public: - - - BasicEvent redisResponse; - - - AsyncClient(); - /// Default constructor. Use this when you want to - /// connect later on. - - AsyncClient(const std::string& hostAndPort); - /// Constructor which connects to the given Redis host/port. - /// The host and port must be separated with a colon. - - AsyncClient(const std::string& host, int port); - /// Constructor which connects to the given Redis host/port. - - AsyncClient(const Net::SocketAddress& addrs); - /// Constructor which connects to the given Redis host/port. - - virtual ~AsyncClient(); - /// Destructor - - bool isStopped(); - /// Returns true if the activity is not running, false when it is. - - void start(); - /// Starts the activity to read replies from the Redis server. - - void stop(); - /// Stops the read activity. - -protected: - - void runActivity(); - -private: - - AsyncClient(const AsyncClient&); - AsyncClient& operator = (const AsyncClient&); - - - Activity _activity; - -}; - - -inline bool AsyncClient::isStopped() -{ - return _activity.isStopped(); -} - -inline void AsyncClient::start() -{ - _activity.start(); -} - -inline void AsyncClient::stop() -{ - _activity.stop(); -} - - -} } // namespace Poco::Redis - -#endif //Redis_Client_INCLUDED diff --git a/Redis/include/Poco/Redis/AsyncReader.h b/Redis/include/Poco/Redis/AsyncReader.h new file mode 100644 index 000000000..79ce85b37 --- /dev/null +++ b/Redis/include/Poco/Redis/AsyncReader.h @@ -0,0 +1,92 @@ +// +// AsyncReader.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: AsyncReader +// +// Definition of the AsyncReader class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Redis_AsyncReader_INCLUDED +#define Redis_AsyncReader_INCLUDED + + +#include "Poco/Redis/Redis.h" +#include "Poco/Redis/Client.h" +#include "Poco/Activity.h" + +namespace Poco { +namespace Redis { + + +class Redis_API AsyncReader + /// Wrapper around a Redis client to read messages asynchronously. Use this + /// for publish/subscribe. The redisResponse event is used to notify that + /// a message is received. When a reader is started for a Redis server, + /// you should use execute, because this class is responsible for + /// reading all replies. +{ +public: + + BasicEvent redisResponse; + /// Event that is called when a message is received + + AsyncReader(Client& client); + /// Constructor. + + virtual ~AsyncReader(); + /// Destructor + + bool isStopped(); + /// Returns true if the activity is not running, false when it is. + + void start(); + /// Starts the activity to read replies from the Redis server. + + void stop(); + /// Stops the read activity. + +protected: + + void runActivity(); + +private: + + AsyncReader(const AsyncReader&); + AsyncReader& operator = (const AsyncReader&); + + + Activity _activity; + + Client& _client; +}; + + +inline bool AsyncReader::isStopped() +{ + return _activity.isStopped(); +} + +inline void AsyncReader::start() +{ + _activity.start(); +} + +inline void AsyncReader::stop() +{ + _activity.stop(); +} + + +} } // namespace Poco::Redis + +#endif //Redis_AsyncReader_INCLUDED diff --git a/Redis/src/AsyncClient.cpp b/Redis/src/AsyncClient.cpp deleted file mode 100644 index 691bf4a99..000000000 --- a/Redis/src/AsyncClient.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// -// AsyncClient.cpp -// -// $Id$ -// -// Library: Redis -// Package: Redis -// Module: AsyncClient -// -// Implementation of the AsyncClient class. -// -// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// - -#include "Poco/Redis/AsyncClient.h" - -namespace Poco { -namespace Redis { - - -AsyncClient::AsyncClient() : Client(), - _activity(this, &AsyncClient::runActivity) -{ -} - - -AsyncClient::AsyncClient(const std::string& hostAndPort) : Client(hostAndPort), - _activity(this, &AsyncClient::runActivity) -{ -} - - -AsyncClient::AsyncClient(const std::string& host, int port) : Client(host, port), - _activity(this, &AsyncClient::runActivity) -{ -} - - -AsyncClient::AsyncClient(const Net::SocketAddress& addrs) : Client(addrs), - _activity(this, &AsyncClient::runActivity) -{ -} - - -AsyncClient::~AsyncClient() -{ - stop(); -} - - -void AsyncClient::runActivity() -{ - while(!_activity.isStopped()) - { - try - { - RedisType::Ptr reply = readReply(); - redisResponse.notify(this, reply); - } - catch(TimeoutException&) - { - continue; - } - catch(Exception &) - { - stop(); - } - } -} - - -} } // Poco::Redis diff --git a/Redis/src/AsyncReader.cpp b/Redis/src/AsyncReader.cpp new file mode 100644 index 000000000..2a9663629 --- /dev/null +++ b/Redis/src/AsyncReader.cpp @@ -0,0 +1,57 @@ +// +// AsyncReader.cpp +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: AsyncReader +// +// Implementation of the AsyncReader class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include "Poco/Redis/AsyncReader.h" + +namespace Poco { +namespace Redis { + + +AsyncReader::AsyncReader(Client& client) : _client(client), + _activity(this, &AsyncReader::runActivity) +{ +} + + +AsyncReader::~AsyncReader() +{ + stop(); +} + + +void AsyncReader::runActivity() +{ + while(!_activity.isStopped()) + { + try + { + RedisType::Ptr reply = _client.readReply(); + redisResponse.notify(this, reply); + } + catch(TimeoutException&) + { + continue; + } + catch(Exception &) + { + stop(); + } + } +} + + +} } // Poco::Redis From c135c87b1d7eac4edb2e7210cb5379b34b17918c Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 2 Nov 2015 22:08:58 +0100 Subject: [PATCH 030/121] Add setReceiveTimeout --- Redis/include/Poco/Redis/RedisSocket.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Redis/include/Poco/Redis/RedisSocket.h b/Redis/include/Poco/Redis/RedisSocket.h index 7eb0cf8f5..cfd034b98 100644 --- a/Redis/include/Poco/Redis/RedisSocket.h +++ b/Redis/include/Poco/Redis/RedisSocket.h @@ -52,6 +52,8 @@ public: void readLine(std::string& line); + void setReceiveTimeout(const Timespan& timeout); + private: RedisSocket(RedisSocket& copy); @@ -65,6 +67,11 @@ private: }; +inline void RedisSocket::setReceiveTimeout(const Timespan& timeout) +{ + _socket.setReceiveTimeout(timeout); +} + } } #endif // Redis_RedisSocket_INCLUDED From cbb45f5b25fe31df03e8e1136aa86abe775fa227 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 2 Nov 2015 22:09:21 +0100 Subject: [PATCH 031/121] Add setReceiveTimeout --- Redis/include/Poco/Redis/Client.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 3f7ebab34..3c5cc6f01 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -104,9 +104,9 @@ public: /// A specialization exists for type void, which doesn't read /// the reply. If the server sends a reply, it is your /// responsibility to read it ... (Use this for pipelining) - /// A BadCastException will be thrown when the reply couldn't be - /// converted. Supported types are Int64, std::string, BulkString, - /// Array and void. When the reply is an Error, it will throw + /// A BadCastException will be thrown when the reply couldn't be + /// converted. Supported types are Int64, std::string, BulkString, + /// Array and void. When the reply is an Error, it will throw /// a RedisException. { T result; @@ -143,6 +143,8 @@ public: /// Sends all commands (pipelining) to the Redis server before /// getting all replies. + void setReceiveTimeout(const Timespan& timeout); + private: Client(const Client&); @@ -161,7 +163,7 @@ private: /// answer. Can also be used for pipelining commands. Make sure you /// call readReply as many times as you called writeCommand, even when /// an error occurred on a command. - + }; @@ -176,6 +178,11 @@ void Client::execute(const Array& command) writeCommand(command); } +inline void Client::setReceiveTimeout(const Timespan& timeout) +{ + _socket.setReceiveTimeout(timeout); +} + } } // namespace Poco::Redis From dfc89d09deb4008e230054c6faca57e9891a5d24 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 2 Nov 2015 22:09:35 +0100 Subject: [PATCH 032/121] Work on pubsub sample --- Redis/testsuite/src/RedisTest.cpp | 36 ++++++++++++++++++------------- Redis/testsuite/src/RedisTest.h | 4 ++-- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index f9798a6b6..b7dec0184 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -10,11 +10,12 @@ // #include -#include "Poco/Net/NetException.h" +#include "Poco/Exception.h" #include "Poco/Delegate.h" #include "Poco/Thread.h" #include "RedisTest.h" +#include "Poco/Redis/AsyncReader.h" #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" @@ -23,7 +24,7 @@ using namespace Poco::Redis; bool RedisTest::_connected = false; -Poco::Redis::AsyncClient RedisTest::_redis; +Poco::Redis::Client RedisTest::_redis; RedisTest::RedisTest(const std::string& name): @@ -35,14 +36,15 @@ RedisTest::RedisTest(const std::string& name): { try { - Poco::Timespan t(30, 0); // 30 seconds + Poco::Timespan t(10, 0); // Connect within 10 seconds _redis.connect(_host, _port, t); + _redis.setReceiveTimeout(t); // Receive answers within 10 seconds _connected = true; std::cout << "Connected to [" << _host << ':' << _port << ']' << std::endl; } - catch (Poco::Net::ConnectionRefusedException& e) + catch (Poco::Exception& e) { - std::cout << "Couldn't connect to " << e.message() << ". " << std::endl; + std::cout << "Couldn't connect to [" << _host << ':' << _port << ']' << e.message() << ". " << std::endl; } } } @@ -665,7 +667,7 @@ void RedisTest::testPipeliningWithSendCommands() commands.push_back(ping); commands.push_back(ping); - Array result = _redis.sendCommands(commands); + Array result = _redis.sendCommands(commands); // We expect 2 results assert(result.size() == 2); @@ -673,7 +675,7 @@ void RedisTest::testPipeliningWithSendCommands() // The 2 results must be simple PONG strings for(size_t i = 0; i < 2; ++i) { - try + try { std::string pong = result.get(i); assert(pong.compare("PONG") == 0); @@ -703,7 +705,7 @@ void RedisTest::testPipeliningWithWriteCommand() for(int i = 0; i < 2; ++i) { std::string pong; - try + try { _redis.readReply(pong); assert(pong.compare("PONG") == 0); @@ -728,26 +730,30 @@ public: void RedisTest::testPubSub() { + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + RedisSubscriber subscriber; Array subscribe; subscribe.add("SUBSCRIBE") .add("test"); - Array subscribeReply = _redis.execute(subscribe); + _redis.execute(subscribe); - _redis.redisResponse += Poco::delegate(&subscriber, &RedisSubscriber::onMessage); - _redis.start(); + AsyncReader reader(_redis); + reader.redisResponse += Poco::delegate(&subscriber, &RedisSubscriber::onMessage); + reader.start(); Poco::Thread::sleep(30000); Array unsubscribe; unsubscribe.add("UNSUBSCRIBE"); - Array unsubscribeReply = _redis.execute(unsubscribe); - std::cout << "SUBS: " << unsubscribeReply.toString() << std::endl; - - _redis.stop(); + _redis.execute(unsubscribe); } CppUnit::Test* RedisTest::suite() diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index e2f46f672..369f6fb9f 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -17,7 +17,7 @@ #include "Poco/Redis/Redis.h" -#include "Poco/Redis/AsyncClient.h" +#include "Poco/Redis/Client.h" #include "CppUnit/TestCase.h" @@ -57,7 +57,7 @@ private: std::string _host; unsigned _port; static bool _connected; - static Poco::Redis::AsyncClient _redis; + static Poco::Redis::Client _redis; }; From 8e586b1012be7ac45bd8e7f58054118f9e5f06c5 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 2 Nov 2015 22:10:23 +0100 Subject: [PATCH 033/121] Add cmake dependency file --- Redis/cmake/PocoRedisConfig.cmake | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Redis/cmake/PocoRedisConfig.cmake diff --git a/Redis/cmake/PocoRedisConfig.cmake b/Redis/cmake/PocoRedisConfig.cmake new file mode 100644 index 000000000..300a9f65f --- /dev/null +++ b/Redis/cmake/PocoRedisConfig.cmake @@ -0,0 +1,4 @@ +include(CMakeFindDependencyMacro) +find_dependency(PocoFoundation) +find_dependency(PocoNet) +include("${CMAKE_CURRENT_LIST_DIR}/PocoRedisTargets.cmake") From 004bcfe48a5bd28a476aa1bd81c09b0bc3328a3c Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 3 Nov 2015 22:36:46 +0100 Subject: [PATCH 034/121] Use RedisStream instead of RedisSocket --- Redis/include/Poco/Redis/Array.h | 10 +- Redis/include/Poco/Redis/Client.h | 33 +++++-- Redis/include/Poco/Redis/Error.h | 9 +- Redis/include/Poco/Redis/RedisSocket.h | 77 --------------- Redis/include/Poco/Redis/RedisStream.h | 106 +++++++++++++++++++++ Redis/include/Poco/Redis/Type.h | 26 +++--- Redis/src/Client.cpp | 40 ++++++-- Redis/src/RedisSocket.cpp | 124 ------------------------- Redis/src/RedisStream.cpp | 108 +++++++++++++++++++++ 9 files changed, 286 insertions(+), 247 deletions(-) delete mode 100644 Redis/include/Poco/Redis/RedisSocket.h create mode 100644 Redis/include/Poco/Redis/RedisStream.h delete mode 100644 Redis/src/RedisSocket.cpp create mode 100644 Redis/src/RedisStream.cpp diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index ba4615fa9..ff4456d88 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -225,23 +225,21 @@ struct ElementTraits }; template<> inline -void Type::read(RedisSocket& socket) +void Type::read(RedisInputStream& input) { - std::string line; - socket.readLine(line); - Int64 length = NumberParser::parse64(line); + Int64 length = NumberParser::parse64(input.getline()); if ( length != -1 ) { for(int i = 0; i < length; ++i) { - char marker = socket.get(); + char marker = input.get(); RedisType::Ptr element = Type::createRedisType(marker); if ( element.isNull() ) throw RedisException("Wrong answer received from Redis server"); - element->read(socket); + element->read(input); _value.add(element); } } diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 3c5cc6f01..532ce2ba7 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -25,7 +25,7 @@ #include "Poco/Redis/Redis.h" #include "Poco/Redis/Array.h" #include "Poco/Redis/Error.h" -#include "Poco/Redis/RedisSocket.h" +#include "Poco/Redis/RedisStream.h" namespace Poco { namespace Redis { @@ -52,8 +52,6 @@ class Redis_API Client /// } { public: - typedef Poco::SharedPtr Ptr; - Client(); /// Default constructor. Use this when you want to /// connect later on. @@ -98,7 +96,7 @@ public: /// Disconnects from the Redis server. template - T execute(const Array& command) + T execute(const Array& command, bool flush = true) /// Sends the Redis Command to the server. It gets the reply /// and tries to convert it to the given template type. /// A specialization exists for type void, which doesn't read @@ -108,13 +106,22 @@ public: /// converted. Supported types are Int64, std::string, BulkString, /// Array and void. When the reply is an Error, it will throw /// a RedisException. + /// + /// The flush argument only makes sense when using for type void. + /// When flush is false, the commands are build in a buffer and stays + /// there until flush is called or when a command is executed with + /// flush set to true. { T result; - writeCommand(command); + writeCommand(command, true); readReply(result); return result; } + void flush(); + /// Flush the output buffer to Redis. Use this when commands + /// are stored in the buffer to send them all at once to Redis. + RedisType::Ptr sendCommand(const Array& command); /// Sends a Redis command to the server and returns the reply. /// Use this when the type of the reply isn't known. @@ -151,19 +158,21 @@ private: Client& operator = (const Client&); Net::SocketAddress _address; - RedisSocket _socket; + Net::StreamSocket _socket; void connect(); /// Connects to the Redis server void connect(const Timespan& timeout); /// Connects to the Redis server and sets a timeout. - void writeCommand(const Array& command); + void writeCommand(const Array& command, bool flush); /// Sends a request to the Redis server. Use readReply to get the /// answer. Can also be used for pipelining commands. Make sure you /// call readReply as many times as you called writeCommand, even when /// an error occurred on a command. + RedisInputStream* _input; + RedisOutputStream* _output; }; @@ -173,9 +182,15 @@ inline Net::SocketAddress Client::address() const } template<> inline -void Client::execute(const Array& command) +void Client::execute(const Array& command, bool flush) { - writeCommand(command); + writeCommand(command, flush); +} + +inline void Client::flush() +{ + poco_assert(!_output); + _output->flush(); } inline void Client::setReceiveTimeout(const Timespan& timeout) diff --git a/Redis/include/Poco/Redis/Error.h b/Redis/include/Poco/Redis/Error.h index 59d45b2ac..1fccad94e 100644 --- a/Redis/include/Poco/Redis/Error.h +++ b/Redis/include/Poco/Redis/Error.h @@ -65,14 +65,9 @@ struct ElementTraits template<> inline -void Type::read(RedisSocket& socket) +void Type::read(RedisInputStream& input) { - std::string s; - socket.readLine(s); - - std::cout << s << std::endl; - - _value = s; + _value = input.getline(); } }} // Namespace Poco::Redis diff --git a/Redis/include/Poco/Redis/RedisSocket.h b/Redis/include/Poco/Redis/RedisSocket.h deleted file mode 100644 index cfd034b98..000000000 --- a/Redis/include/Poco/Redis/RedisSocket.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// RedistSocket.h -// -// $Id$ -// -// Library: Redis -// Package: Redis -// Module: RedistSocket -// -// Definition of the RedistSocket class. -// -// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// - -#ifndef Redis_RedisSocket_INCLUDED -#define Redis_RedisSocket_INCLUDED - -#include "Poco/Timespan.h" -#include "Poco/Net/SocketAddress.h" -#include "Poco/Net/StreamSocket.h" - -#include "Poco/Redis/Redis.h" - -namespace Poco { -namespace Redis { - -class Redis_API RedisSocket -{ -public: - - RedisSocket(); - virtual ~RedisSocket(); - - void close(); - - void connect(const Net::SocketAddress& addrs); - - void connect(const Net::SocketAddress& addrs, const Timespan& timeout); - - int get(); - - int peek(); - - void read(UInt64 length, std::string& data); - - int write(const char* buffer, std::streamsize length); - - void refill(); - - void readLine(std::string& line); - - void setReceiveTimeout(const Timespan& timeout); - -private: - - RedisSocket(RedisSocket& copy); - RedisSocket& operator = (const RedisSocket&); - - Net::StreamSocket _socket; - - char* _buffer; - char* _current; - char* _end; -}; - - -inline void RedisSocket::setReceiveTimeout(const Timespan& timeout) -{ - _socket.setReceiveTimeout(timeout); -} - -} } - -#endif // Redis_RedisSocket_INCLUDED diff --git a/Redis/include/Poco/Redis/RedisStream.h b/Redis/include/Poco/Redis/RedisStream.h new file mode 100644 index 000000000..5c7a807aa --- /dev/null +++ b/Redis/include/Poco/Redis/RedisStream.h @@ -0,0 +1,106 @@ +// +// RedisStream.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: RedisStream +// +// Definition of the RedisStream class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#ifndef Redis_RedisStream_INCLUDED +#define Redis_RedisStream_INCLUDED + +#include "Poco/BufferedStreamBuf.h" +#include "Poco/Net/StreamSocket.h" + +#include +#include + +namespace Poco { +namespace Redis { + +class RedisStreamBuf : public BufferedStreamBuf +{ +public: + RedisStreamBuf(Net::StreamSocket& redis); + ~RedisStreamBuf(); + + std::string readLine(); + +protected: + int readFromDevice(char* buffer, std::streamsize length); + int writeToDevice(const char* buffer, std::streamsize length); + +private: + + enum + { + STREAM_BUFFER_SIZE = 1024 + }; + + Net::StreamSocket& _redis; +}; + +class RedisIOS: public virtual std::ios +{ +public: + RedisIOS(Net::StreamSocket& redis); + /// Creates the RedisIOS with the given socket. + + ~RedisIOS(); + /// Destroys the RedisIOS. + /// + /// Flushes the buffer, but does not close the socket. + + RedisStreamBuf* rdbuf(); + /// Returns a pointer to the internal RedisStreamBuf. + + void close(); + /// Flushes the stream. + +protected: + RedisStreamBuf _buf; +}; + + +class RedisOutputStream: public RedisIOS, public std::ostream + /// An output stream for writing to a Redis server. +{ +public: + RedisOutputStream(Net::StreamSocket& redis); + /// Creates the RedisOutputStream with the given socket. + + ~RedisOutputStream(); + /// Destroys the RedisOutputStream. + /// + /// Flushes the buffer. +}; + + +class RedisInputStream: public RedisIOS, public std::istream + /// An input stream for reading from a Redis server. +{ +public: + RedisInputStream(Net::StreamSocket& redis); + /// Creates the RedisInputStream with the given socket. + + ~RedisInputStream(); + /// Destroys the RedisInputStream. + + std::string getline(); + /// Redis uses /r/n as delimiter. This getline version removes + /// the /r from the result. +}; + + +}} // Poco::Redis + +#endif // Redis_RedisStream_INCLUDED \ No newline at end of file diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index cf76259ac..2e1ee4563 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -25,7 +25,7 @@ #include "Poco/Nullable.h" #include "Poco/Redis/Redis.h" -#include "Poco/Redis/RedisSocket.h" +#include "Poco/Redis/RedisStream.h" namespace Poco { namespace Redis { @@ -52,7 +52,7 @@ public: virtual int type() const = 0; - virtual void read(RedisSocket& socket) = 0; + virtual void read(RedisInputStream& input) = 0; virtual std::string toString() const = 0; @@ -192,7 +192,7 @@ public: return ElementTraits::TypeId; } - virtual void read(RedisSocket& socket); + virtual void read(RedisInputStream& socket); virtual std::string toString() const { @@ -215,37 +215,35 @@ private: }; template<> inline -void Type::read(RedisSocket& socket) +void Type::read(RedisInputStream& input) { - std::string number; - socket.readLine(number); + std::string number = input.getline(); _value = NumberParser::parse64(number); } template<> inline -void Type::read(RedisSocket& socket) +void Type::read(RedisInputStream& input) { _value.clear(); - socket.readLine(_value); + _value = input.getline(); } template<> inline -void Type::read(RedisSocket& socket) +void Type::read(RedisInputStream& input) { _value.clear(); - std::string line; - socket.readLine(line); - + std::string line = input.getline(); int length = NumberParser::parse64(line); if ( length >= 0 ) { std::string s; - socket.read(length, s); + s.resize(length, ' '); + input.read(&*s.begin(), length); _value.assign(s); - socket.readLine(line); + line = input.getline(); } } diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index b8220253c..e24eb71af 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -22,24 +22,24 @@ namespace Poco { namespace Redis { -Client::Client() : _address(), _socket() +Client::Client() : _address(), _socket(), _input(0), _output(0) { } -Client::Client(const std::string& hostAndPort) : _address(hostAndPort), _socket() +Client::Client(const std::string& hostAndPort) : _address(hostAndPort), _socket(), _input(0), _output(0) { connect(); } -Client::Client(const std::string& host, int port) : _address(host, port), _socket() +Client::Client(const std::string& host, int port) : _address(host, port), _socket(), _input(0), _output(0) { connect(); } -Client::Client(const Net::SocketAddress& addrs) : _address(addrs), _socket() +Client::Client(const Net::SocketAddress& addrs) : _address(addrs), _socket(), _input(0), _output(0) { connect(); } @@ -47,12 +47,19 @@ Client::Client(const Net::SocketAddress& addrs) : _address(addrs), _socket() Client::~Client() { + delete _input; + delete _output; } void Client::connect() { + poco_assert(! _input); + poco_assert(! _output); + _socket.connect(_address); + _input = new RedisInputStream(_socket); + _output = new RedisOutputStream(_socket); } void Client::connect(const std::string& hostAndPort) @@ -77,7 +84,12 @@ void Client::connect(const Net::SocketAddress& addrs) void Client::connect(const Timespan& timeout) { + poco_assert(! _input); + poco_assert(! _output); + _socket.connect(_address, timeout); + _input = new RedisInputStream(_socket); + _output = new RedisOutputStream(_socket); } void Client::connect(const std::string& hostAndPort, const Timespan& timeout) @@ -102,31 +114,38 @@ void Client::connect(const Net::SocketAddress& addrs, const Timespan& timeout) void Client::disconnect() { + delete _input; + _input = 0; + + delete _output; + _output = 0; + _socket.close(); } -void Client::writeCommand(const Array& command) +void Client::writeCommand(const Array& command, bool flush) { std::string commandStr = command.toString(); - _socket.write(commandStr.c_str(), commandStr.length()); + _output->write(commandStr.c_str(), commandStr.length()); + if ( flush ) _output->flush(); } RedisType::Ptr Client::readReply() { - RedisType::Ptr result = RedisType::createRedisType(_socket.get()); + RedisType::Ptr result = RedisType::createRedisType(_input->get()); if ( result.isNull() ) { throw RedisException("Invalid Redis type returned"); } - result->read(_socket); + result->read(*_input); return result; } RedisType::Ptr Client::sendCommand(const Array& command) { - writeCommand(command); + writeCommand(command, true); return readReply(); } @@ -136,8 +155,9 @@ Array Client::sendCommands(const std::vector& commands) for(std::vector::const_iterator it = commands.begin(); it != commands.end(); ++it) { - writeCommand(*it); + writeCommand(*it, false); } + _output->flush(); for(int i = 0; i < commands.size(); ++i) { diff --git a/Redis/src/RedisSocket.cpp b/Redis/src/RedisSocket.cpp deleted file mode 100644 index 64494b425..000000000 --- a/Redis/src/RedisSocket.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// -// RedistSocket.h -// -// $Id$ -// -// Library: Redis -// Package: Redis -// Module: RedistSocket -// -// Implementation of the RedistSocket class. -// -// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// -#include "Poco/Redis/RedisSocket.h" - -namespace Poco { -namespace Redis { - -RedisSocket::RedisSocket() : _socket(), _buffer(0), _current(0), _end(0) -{ -} - -RedisSocket::~RedisSocket() -{ - if ( _buffer ) delete[] _buffer; - - try - { - _socket.close(); - } - catch (...) - { - } -} - -void RedisSocket::close() -{ - _socket.close(); -} - -void RedisSocket::connect(const Net::SocketAddress& addrs) -{ - _socket.connect(addrs); -} - -void RedisSocket::connect(const Net::SocketAddress& addrs, const Timespan& timeout) -{ - _socket.connect(addrs, timeout); -} - - -int RedisSocket::get() -{ - if ( _current == _end ) refill(); - - if ( _current < _end ) return *_current++; - - return std::char_traits::eof(); -} - -int RedisSocket::peek() -{ - if ( _current == _end ) refill(); - - if ( _current < _end ) return *_current; - - return std::char_traits::eof(); -} - -void RedisSocket::read(UInt64 length, std::string& data) -{ - UInt64 count = 0; - data.clear(); - - while(count < length) - { - int c = get(); - if ( c == -1 ) throw IOException("Invalid EOF"); - - data += c; - ++count; - } -} - -int RedisSocket::write(const char* buffer, std::streamsize length) -{ - return _socket.sendBytes(buffer, (int) length); -} - -void RedisSocket::refill() -{ - if ( ! _buffer ) _buffer = new char[1024]; - - _current = _end = _buffer; - int n = _socket.receiveBytes(_buffer, 1024); - _end += n; -} - - -void RedisSocket::readLine(std::string& line) -{ - line.clear(); - - int c = get(); - - while(1) - { - if ( c == -1 ) throw IOException("Invalid EOF"); - - if ( c == '\r' && peek() == '\n' ) - { - get(); - break; - } - - line += c; - c = get(); - } -} - -} } diff --git a/Redis/src/RedisStream.cpp b/Redis/src/RedisStream.cpp new file mode 100644 index 000000000..b794bb210 --- /dev/null +++ b/Redis/src/RedisStream.cpp @@ -0,0 +1,108 @@ +// +// RedisStream.cpp +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: RedisStream +// +// Implementation of the RedisStream class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// +#include +#include "Poco/Redis/RedisStream.h" + +namespace Poco { +namespace Redis { + + +RedisStreamBuf::RedisStreamBuf(Net::StreamSocket& redis): + BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in | std::ios::out), + _redis(redis) +{ +} + + +RedisStreamBuf::~RedisStreamBuf() +{ +} + + +int RedisStreamBuf::readFromDevice(char* buffer, std::streamsize len) +{ + return _redis.receiveBytes(buffer, len); +} + + +int RedisStreamBuf::writeToDevice(const char* buffer, std::streamsize length) +{ + return _redis.sendBytes(buffer, length); +} + +RedisIOS::RedisIOS(Net::StreamSocket& redis): + _buf(redis) +{ + poco_ios_init(&_buf); +} + + +RedisIOS::~RedisIOS() +{ + try + { + _buf.sync(); + } + catch (...) + { + } +} + + +RedisStreamBuf* RedisIOS::rdbuf() +{ + return &_buf; +} + + +void RedisIOS::close() +{ + _buf.sync(); +} + +RedisOutputStream::RedisOutputStream(Net::StreamSocket& redis): + RedisIOS(redis), + std::ostream(&_buf) +{ +} + + +RedisOutputStream::~RedisOutputStream() +{ +} + +RedisInputStream::RedisInputStream(Net::StreamSocket& redis): + RedisIOS(redis), + std::istream(&_buf) +{ +} + + +RedisInputStream::~RedisInputStream() +{ +} + +std::string RedisInputStream::getline() +{ + std::string line; + std::getline(*this, line); + if ( line.size() > 0 ) line.erase(line.end() - 1); + return line; +} + + +}} \ No newline at end of file From 38973aa12838022329cc90f922dc71cee230966a Mon Sep 17 00:00:00 2001 From: Franky Braem Date: Wed, 4 Nov 2015 13:59:27 +0100 Subject: [PATCH 035/121] Remove Redis_API from Type to avoid unresolved externals on Windows --- Redis/include/Poco/Redis/Type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index 2e1ee4563..dd82960bb 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -167,7 +167,7 @@ struct ElementTraits template -class Redis_API Type : public RedisType +class Type : public RedisType { public: From 317117b5105720268ad611c1d3d556163afb9a75 Mon Sep 17 00:00:00 2001 From: kblaschke Date: Fri, 6 Nov 2015 11:30:41 +0100 Subject: [PATCH 036/121] Linux build configuration: Add -m32/-m64 flags to compiler and dynamic linker to fully support OSARCH_64BITS in cross-compiling scenarios --- build/config/Linux | 12 ++++++------ build/rules/lib | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/config/Linux b/build/config/Linux index 9d1c09731..1daceb7ca 100644 --- a/build/config/Linux +++ b/build/config/Linux @@ -39,14 +39,14 @@ SHAREDLIBLINKEXT = .so # Compiler and Linker Flags # CFLAGS = -CFLAGS32 = -CFLAGS64 = +CFLAGS32 = -m32 +CFLAGS64 = -m64 CXXFLAGS = -Wall -Wno-sign-compare -CXXFLAGS32 = -CXXFLAGS64 = +CXXFLAGS32 = -m32 +CXXFLAGS64 = -m64 LINKFLAGS = -LINKFLAGS32 = -LINKFLAGS64 = +LINKFLAGS32 = -m32 +LINKFLAGS64 = -m64 STATICOPT_CC = STATICOPT_CXX = STATICOPT_LINK = -static diff --git a/build/rules/lib b/build/rules/lib index 8126f4af3..a814d8fb4 100644 --- a/build/rules/lib +++ b/build/rules/lib @@ -61,13 +61,13 @@ $(LIB_RELEASE_STATIC): $(foreach o,$(objects),$(OBJPATH_RELEASE_STATIC)/$(o).o) $(LIB_DEBUG_SHARED): $(foreach o,$(objects),$(OBJPATH_DEBUG_SHARED)/$(o).o) @echo "** Building shared library (debug)" $@ - $(SHLIB) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_DEBUG) $(SYSLIBS) + $(SHLIB) $(LINKFLAGS) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_DEBUG) $(SYSLIBS) $(SHLIBLN) $(LIB_DEBUG_SHARED) $(LIB_DEBUG_SHARED_LINK) $(postbuild) $(LIB_RELEASE_SHARED): $(foreach o,$(objects),$(OBJPATH_RELEASE_SHARED)/$(o).o) @echo "** Building shared library (release)" $@ - $(SHLIB) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_RELEASE) $(SYSLIBS) + $(SHLIB) $(LINKFLAGS) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_RELEASE) $(SYSLIBS) $(SHLIBLN) $(LIB_RELEASE_SHARED) $(LIB_RELEASE_SHARED_LINK) $(STRIPCMD) $(postbuild) From 795b4fc9bbc1f0df9d020042977123e77cc9715e Mon Sep 17 00:00:00 2001 From: kblaschke Date: Fri, 6 Nov 2015 11:55:21 +0100 Subject: [PATCH 037/121] Auto-detect OSARCH_64BITS. Otherwise, if OSARCH_64BITS is not specified, the build system would always produce 32-bit libraries, even on 64-bit hosts. --- build/config/Linux | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/build/config/Linux b/build/config/Linux index 1daceb7ca..dc336e497 100644 --- a/build/config/Linux +++ b/build/config/Linux @@ -69,3 +69,15 @@ SYSFLAGS = -D_XOPEN_SOURCE=500 -D_REENTRANT -D_THREAD_SAFE -D_FILE_OFFSET_BITS=6 # System Specific Libraries # SYSLIBS = -lpthread -ldl -lrt + +# +# Auto-detect architecture if not specified +# +ifndef OSARCH_64BITS + LBITS := $(shell getconf LONG_BIT) + ifeq ($(LBITS),64) + OSARCH_64BITS = 1 + else + OSARCH_64BITS = 0 + endif +endif From 180cd8963bf74dadd38004dfce881c45f30aca79 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 6 Nov 2015 16:25:32 +0100 Subject: [PATCH 038/121] Add comment --- Redis/include/Poco/Redis/Array.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index ff4456d88..850550af9 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -68,6 +68,7 @@ public: /// Adds an array. Array& addSimpleString(const std::string& value); + /// Adds a simple string (can't contain newline characters!) const_iterator begin() const; /// Returns an iterator to the start of the array. Note: From f54a25f0416995fcb37dfedc189c72559d6d48c6 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 6 Nov 2015 16:26:36 +0100 Subject: [PATCH 039/121] Add flush method --- Redis/include/Poco/Redis/Client.h | 13 ++++--------- Redis/testsuite/src/RedisTest.cpp | 3 +++ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 532ce2ba7..e38f166e5 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -96,7 +96,7 @@ public: /// Disconnects from the Redis server. template - T execute(const Array& command, bool flush = true) + T execute(const Array& command) /// Sends the Redis Command to the server. It gets the reply /// and tries to convert it to the given template type. /// A specialization exists for type void, which doesn't read @@ -106,11 +106,6 @@ public: /// converted. Supported types are Int64, std::string, BulkString, /// Array and void. When the reply is an Error, it will throw /// a RedisException. - /// - /// The flush argument only makes sense when using for type void. - /// When flush is false, the commands are build in a buffer and stays - /// there until flush is called or when a command is executed with - /// flush set to true. { T result; writeCommand(command, true); @@ -182,14 +177,14 @@ inline Net::SocketAddress Client::address() const } template<> inline -void Client::execute(const Array& command, bool flush) +void Client::execute(const Array& command) { - writeCommand(command, flush); + writeCommand(command, false); } inline void Client::flush() { - poco_assert(!_output); + poco_assert(_output); _output->flush(); } diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index b7dec0184..0c9ea3f64 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -700,6 +700,7 @@ void RedisTest::testPipeliningWithWriteCommand() _redis.execute(ping); _redis.execute(ping); + _redis.flush(); // We expect 2 results with simple "PONG" strings for(int i = 0; i < 2; ++i) @@ -743,6 +744,7 @@ void RedisTest::testPubSub() .add("test"); _redis.execute(subscribe); + _redis.flush(); AsyncReader reader(_redis); reader.redisResponse += Poco::delegate(&subscriber, &RedisSubscriber::onMessage); @@ -754,6 +756,7 @@ void RedisTest::testPubSub() unsubscribe.add("UNSUBSCRIBE"); _redis.execute(unsubscribe); + _redis.flush(); } CppUnit::Test* RedisTest::suite() From 1f1758f37caf44cfea1b0c540af28e4763f0e0e6 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 7 Nov 2015 21:44:53 +0100 Subject: [PATCH 040/121] Solve wrong casts --- Redis/include/Poco/Redis/Client.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index e38f166e5..82f272135 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -132,12 +132,17 @@ public: /// the reply is not of the given type. { RedisType::Ptr redisResult = readReply(); - if ( redisResult->type() == ElementTraits::TypeId ) + if (redisResult->type() == ElementTraits::TypeId) { - throw RedisException(((Error*) redisResult.get())->getMessage()); + Type* error = dynamic_cast*>(redisResult.get()); + throw RedisException(error->value().getMessage()); + } + + if (redisResult->type() == ElementTraits::TypeId) + { + Type* type = dynamic_cast*>(redisResult.get()); + if (type != NULL) result = type->value(); } - if ( redisResult->type() == ElementTraits::TypeId ) - result = ((Type*) redisResult.get())->value(); else throw BadCastException(); } From 0efa6333ca7b1e956629d3a3824a758f1335f1ad Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 7 Nov 2015 21:45:23 +0100 Subject: [PATCH 041/121] Introduce command class --- Redis/include/Poco/Redis/Command.h | 47 ++++++++++++++++++++++++++ Redis/src/Command.cpp | 54 ++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 Redis/include/Poco/Redis/Command.h create mode 100644 Redis/src/Command.cpp diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h new file mode 100644 index 000000000..ae0dd52b5 --- /dev/null +++ b/Redis/include/Poco/Redis/Command.h @@ -0,0 +1,47 @@ +// +// Command.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Command +// +// Definition of the Command class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#ifndef Redis_Command_INCLUDED +#define Redis_Command_INCLUDED + +#include "Poco/Redis/Redis.h" +#include "Poco/Redis/Array.h" + +namespace Poco { +namespace Redis { + +class Redis_API Command : public Array + /// Helper class for creating commands. This class contains + /// factory methods for common used Redis commands. +{ +public: + Command(const std::string& command); + /// Constructor + + Command(const Command& copy); + /// Copy constructor + + virtual ~Command(); + /// Destructor + + static Command set(const std::string& key, const std::string& value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); + /// Returns a SET command to set the key with a value +}; + +}} // namespace Poco::Redis + +#endif // Redis_Command_INCLUDED diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp new file mode 100644 index 000000000..648e06f49 --- /dev/null +++ b/Redis/src/Command.cpp @@ -0,0 +1,54 @@ +// +// Command.cpp +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: Command +// +// Implementation of the Command class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include "Poco/Redis/Command.h" + +namespace Poco { +namespace Redis { + +Command::Command(const std::string& command) : Array() +{ + add(command); +} + +Command::Command(const Command& copy) : Array(copy) +{ +} + +Command::~Command() +{ +} + +Command Command::set(const std::string& key, const std::string& value, bool overwrite, const Poco::Timespan& expireTime, bool create) +{ + Command cmd("SET"); + cmd.add(key); + cmd.add(value); + if ( ! overwrite ) cmd.add("NX"); + if ( ! create ) cmd.add("XX"); + + if ( expireTime.totalMicroseconds() > 0 ) + { + cmd.add("PX"); + cmd.add(expireTime.totalMilliseconds()); + } + + return cmd; +} + + +}} // Poco::Redis \ No newline at end of file From 2f26d6adf5df3c60413139ae85f37f73b6cfd215 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 7 Nov 2015 21:45:46 +0100 Subject: [PATCH 042/121] Add Command / RedisEventArgs / RedisStream --- Redis/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Redis/Makefile b/Redis/Makefile index b110ce63e..48d04ee4a 100644 --- a/Redis/Makefile +++ b/Redis/Makefile @@ -10,7 +10,7 @@ include $(POCO_BASE)/build/rules/global INCLUDE += -I $(POCO_BASE)/Redis/include/Poco/Redis -objects = AsyncReader Array Client Error Exception RedisSocket Type +objects = AsyncReader Array Client Command Error Exception RedisStream RedisEventArgs Type target = PocoRedis target_version = $(LIBVERSION) From fce0afab8eaf23f79d70e2d08d2226c51c45e2d9 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 7 Nov 2015 21:46:11 +0100 Subject: [PATCH 043/121] Use RedisEventArgs --- Redis/include/Poco/Redis/AsyncReader.h | 5 +- Redis/include/Poco/Redis/RedisEventArgs.h | 85 +++++++++++++++++++++++ Redis/src/AsyncReader.cpp | 15 ++-- Redis/src/RedisEventArgs.cpp | 43 ++++++++++++ 4 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 Redis/include/Poco/Redis/RedisEventArgs.h create mode 100644 Redis/src/RedisEventArgs.cpp diff --git a/Redis/include/Poco/Redis/AsyncReader.h b/Redis/include/Poco/Redis/AsyncReader.h index 79ce85b37..ad99a3975 100644 --- a/Redis/include/Poco/Redis/AsyncReader.h +++ b/Redis/include/Poco/Redis/AsyncReader.h @@ -22,6 +22,7 @@ #include "Poco/Redis/Redis.h" #include "Poco/Redis/Client.h" +#include "Poco/Redis/RedisEventArgs.h" #include "Poco/Activity.h" namespace Poco { @@ -37,8 +38,10 @@ class Redis_API AsyncReader { public: - BasicEvent redisResponse; + BasicEvent redisResponse; /// Event that is called when a message is received + BasicEvent redisException; + /// Event that is called when an error occurred. AsyncReader(Client& client); /// Constructor. diff --git a/Redis/include/Poco/Redis/RedisEventArgs.h b/Redis/include/Poco/Redis/RedisEventArgs.h new file mode 100644 index 000000000..eca6c9877 --- /dev/null +++ b/Redis/include/Poco/Redis/RedisEventArgs.h @@ -0,0 +1,85 @@ +// +// RedisEventArgs.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: RedisEventArgs +// +// Definition of the RedisEventArgs class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#ifndef Redis_RedisEventArgs_INCLUDED +#define Redis_RedisEventArgs_INCLUDED + +#include "Poco/Redis/Type.h" + +namespace Poco { +namespace Redis { + +class Redis_API RedisEventArgs +{ +public: + RedisEventArgs(RedisType::Ptr message); + /// Constructor + + RedisEventArgs(Exception* e); + /// Constructor + + ~RedisEventArgs(); + /// Destructor + + RedisType::Ptr message() const; + /// Returns the message retrieved from the Redis server. + /// This can be a NULL pointer when this event is about an exception. + + const Exception* exception() const; + /// Returns the exception if any, otherwise it returns null pointer + + void stop(); + /// When called, the AsyncReader will stop. + /// Note: The AsyncReader will always stop when this is an exception + /// event. Use this for example for pub/sub when there are no + /// subcribers anymore ... + + bool isStopped() const; + /// Returns true when the AsyncReader will stop + +private: + RedisType::Ptr _message; + + Exception* _exception; + + bool _stop; +}; + +inline RedisType::Ptr RedisEventArgs::message() const +{ + return _message; +} + +inline const Exception* RedisEventArgs::exception() const +{ + return _exception; +} + +inline bool RedisEventArgs::isStopped() const +{ + return _stop; +} + +inline void RedisEventArgs::stop() +{ + _stop = true; +} + + +}} // namespace Poco::Redis + +#endif // Redis_RedisEventArgs_INCLUDED diff --git a/Redis/src/AsyncReader.cpp b/Redis/src/AsyncReader.cpp index 2a9663629..41a3ebcba 100644 --- a/Redis/src/AsyncReader.cpp +++ b/Redis/src/AsyncReader.cpp @@ -40,16 +40,19 @@ void AsyncReader::runActivity() try { RedisType::Ptr reply = _client.readReply(); - redisResponse.notify(this, reply); + + RedisEventArgs args(reply); + redisResponse.notify(this, args); + + if ( args.isStopped() ) stop(); } - catch(TimeoutException&) - { - continue; - } - catch(Exception &) + catch(Exception& e) { + RedisEventArgs args(&e); + redisException.notify(this, args); stop(); } + if (!_activity.isStopped()) Thread::trySleep(100); } } diff --git a/Redis/src/RedisEventArgs.cpp b/Redis/src/RedisEventArgs.cpp new file mode 100644 index 000000000..4a7cd7e18 --- /dev/null +++ b/Redis/src/RedisEventArgs.cpp @@ -0,0 +1,43 @@ +// +// RedisEventArgs.cpp +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: RedisEventArgs +// +// Implementation of the RedisEventArgs class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + +#include "Poco/Redis/RedisEventArgs.h" + +namespace Poco { +namespace Redis { + +RedisEventArgs::RedisEventArgs(RedisType::Ptr message) : + _message(message), + _exception(0), + _stop(false) +{ +} + +RedisEventArgs::RedisEventArgs(Exception* exception) : + _message(), + _exception(exception ? exception->clone() : 0), + _stop(false) +{ +} + +RedisEventArgs::~RedisEventArgs() +{ + delete _exception; +} + + +}} // namespace Poco::Redis \ No newline at end of file From fcd7b68695eeea2adc0f1af611af4c77f2636759 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 7 Nov 2015 21:46:59 +0100 Subject: [PATCH 044/121] Add asserts --- Redis/src/Client.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index e24eb71af..d63906561 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -125,14 +125,20 @@ void Client::disconnect() void Client::writeCommand(const Array& command, bool flush) { + poco_assert(_output); + std::string commandStr = command.toString(); + _output->write(commandStr.c_str(), commandStr.length()); if ( flush ) _output->flush(); } RedisType::Ptr Client::readReply() { - RedisType::Ptr result = RedisType::createRedisType(_input->get()); + poco_assert(_input); + + int c = _input->get(); + RedisType::Ptr result = RedisType::createRedisType(c); if ( result.isNull() ) { throw RedisException("Invalid Redis type returned"); From c864435f00ba708bb6c7913b926a3772d350c4f1 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 7 Nov 2015 21:47:18 +0100 Subject: [PATCH 045/121] Work on PubSub test --- Redis/testsuite/src/RedisTest.cpp | 49 ++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 0c9ea3f64..917d53e1e 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -16,6 +16,7 @@ #include "RedisTest.h" #include "Poco/Redis/AsyncReader.h" +#include "Poco/Redis/Command.h" #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" @@ -38,7 +39,6 @@ RedisTest::RedisTest(const std::string& name): { Poco::Timespan t(10, 0); // Connect within 10 seconds _redis.connect(_host, _port, t); - _redis.setReceiveTimeout(t); // Receive answers within 10 seconds _connected = true; std::cout << "Connected to [" << _host << ':' << _port << ']' << std::endl; } @@ -96,10 +96,7 @@ void RedisTest::testAppend() fail(e.message()); } - Array setCommand; - setCommand.add("SET") - .add("mykey") - .add("Hello"); + Command setCommand = Command::set("mykey", "Hello"); try { std::string result = _redis.execute(setCommand); @@ -722,9 +719,43 @@ class RedisSubscriber { public: - void onMessage(const void* pSender, RedisType::Ptr& message) + void onMessage(const void* pSender, RedisEventArgs& args) { - std::cout << message->toString() << std::endl; + if ( ! args.message().isNull() ) + { + Type* arrayType = dynamic_cast*>(args.message().get()); + if ( arrayType != NULL ) + { + Array& array = arrayType->value(); + if ( array.size() == 3 ) + { + BulkString type = array.get(0); + if ( type.value().compare("unsubscribe") == 0 ) + { + Poco::Int64 n = array.get(2); + // When 0, no subscribers anymore, so stop reading ... + if ( n == 0 ) args.stop(); + } + } + else + { + // Wrong array received. Stop the reader + args.stop(); + } + } + else + { + // Invalid type of message received. Stop the reader ... + args.stop(); + } + } + } + + void onError(const void* pSender, RedisEventArgs& args) + { + std::cout << args.exception()->className() << std::endl; + // No need to call stop, AsyncReader stops automatically when an + // exception is received. } }; @@ -748,9 +779,11 @@ void RedisTest::testPubSub() AsyncReader reader(_redis); reader.redisResponse += Poco::delegate(&subscriber, &RedisSubscriber::onMessage); + reader.redisException += Poco::delegate(&subscriber, &RedisSubscriber::onError); reader.start(); - Poco::Thread::sleep(30000); + std::cout << "Sleeping ..." << std::endl; + Poco::Thread::sleep(10000); Array unsubscribe; unsubscribe.add("UNSUBSCRIBE"); From 93afd2637c540dbd2c15e3e4264f8dfcc1ce0cc1 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 7 Nov 2015 21:48:23 +0100 Subject: [PATCH 046/121] Add VS project files --- Redis/Redis_x64_vs90.sln | 60 +++ Redis/Redis_x64_vs90.vcproj | 576 ++++++++++++++++++++++ Redis/testsuite/TestSuite_x64_vs90.vcproj | 464 +++++++++++++++++ 3 files changed, 1100 insertions(+) create mode 100644 Redis/Redis_x64_vs90.sln create mode 100644 Redis/Redis_x64_vs90.vcproj create mode 100644 Redis/testsuite/TestSuite_x64_vs90.vcproj diff --git a/Redis/Redis_x64_vs90.sln b/Redis/Redis_x64_vs90.sln new file mode 100644 index 000000000..d91f9aaf0 --- /dev/null +++ b/Redis/Redis_x64_vs90.sln @@ -0,0 +1,60 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Redis", "Redis_x64_vs90.vcproj", "{4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestSuite", "testsuite\TestSuite_x64_vs90.vcproj", "{96CF3103-E49E-3F5E-A11D-6DBCDA043053}" + ProjectSection(ProjectDependencies) = postProject + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199} = {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + debug_shared|x64 = debug_shared|x64 + release_shared|x64 = release_shared|x64 + debug_static_mt|x64 = debug_static_mt|x64 + release_static_mt|x64 = release_static_mt|x64 + debug_static_md|x64 = debug_static_md|x64 + release_static_md|x64 = release_static_md|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.debug_shared|x64.ActiveCfg = debug_shared|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.debug_shared|x64.Build.0 = debug_shared|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.debug_shared|x64.Deploy.0 = debug_shared|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.release_shared|x64.ActiveCfg = release_shared|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.release_shared|x64.Build.0 = release_shared|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.release_shared|x64.Deploy.0 = release_shared|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.release_static_mt|x64.Build.0 = release_static_mt|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.debug_static_md|x64.Build.0 = debug_static_md|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.release_static_md|x64.ActiveCfg = release_static_md|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.release_static_md|x64.Build.0 = release_static_md|x64 + {4FF2F34B-7F37-3ACD-AFBC-F21D6D426199}.release_static_md|x64.Deploy.0 = release_static_md|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.debug_shared|x64.ActiveCfg = debug_shared|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.debug_shared|x64.Build.0 = debug_shared|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.debug_shared|x64.Deploy.0 = debug_shared|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.release_shared|x64.ActiveCfg = release_shared|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.release_shared|x64.Build.0 = release_shared|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.release_shared|x64.Deploy.0 = release_shared|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.debug_static_mt|x64.ActiveCfg = debug_static_mt|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.debug_static_mt|x64.Build.0 = debug_static_mt|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.debug_static_mt|x64.Deploy.0 = debug_static_mt|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.release_static_mt|x64.ActiveCfg = release_static_mt|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.release_static_mt|x64.Build.0 = release_static_mt|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.release_static_mt|x64.Deploy.0 = release_static_mt|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.debug_static_md|x64.ActiveCfg = debug_static_md|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.debug_static_md|x64.Build.0 = debug_static_md|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.debug_static_md|x64.Deploy.0 = debug_static_md|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.release_static_md|x64.ActiveCfg = release_static_md|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.release_static_md|x64.Build.0 = release_static_md|x64 + {96CF3103-E49E-3F5E-A11D-6DBCDA043053}.release_static_md|x64.Deploy.0 = release_static_md|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Redis/Redis_x64_vs90.vcproj b/Redis/Redis_x64_vs90.vcproj new file mode 100644 index 000000000..4e6e4fd40 --- /dev/null +++ b/Redis/Redis_x64_vs90.vcproj @@ -0,0 +1,576 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Redis/testsuite/TestSuite_x64_vs90.vcproj b/Redis/testsuite/TestSuite_x64_vs90.vcproj new file mode 100644 index 000000000..8cc28cca7 --- /dev/null +++ b/Redis/testsuite/TestSuite_x64_vs90.vcproj @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From ee19720231bd4b6a35d1b0e123f027acb855e95c Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 9 Nov 2015 22:25:10 +0100 Subject: [PATCH 047/121] Add more commands --- Redis/include/Poco/Redis/Command.h | 44 ++++++ Redis/src/Command.cpp | 122 +++++++++++++++- Redis/testsuite/src/RedisTest.cpp | 223 ++++++++++++++++------------- Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 290 insertions(+), 100 deletions(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index ae0dd52b5..da28e93e0 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -21,6 +21,8 @@ #include "Poco/Redis/Redis.h" #include "Poco/Redis/Array.h" +#include + namespace Poco { namespace Redis { @@ -38,8 +40,50 @@ public: virtual ~Command(); /// Destructor + static Command append(const std::string& key, const std::string& value); + /// Returns an APPEND command + + static Command del(const std::string& key); + /// Returns an DEL command + + static Command del(const std::vector& keys); + /// Returns an DEL command + + static Command get(const std::string& key); + /// Returns an GET command + + static Command incr(const std::string& key, Int64 by = 0); + /// Returns an INCR or INCRBY command. Calls INCR when by is omitted or zero. + + static Command lindex(const std::string& list, Int64 index = 0); + /// Returns a LINDEX command + + static Command linsert(const std::string& list, bool before, const std::string& reference, const std::string& value); + /// Returns a LINSERT command + + static Command llen(const std::string& list); + /// Returns a LINDEX command + + static Command lpush(const std::string& list, const std::string& value, bool create = true); + /// Returns a LPUSH or LPUSHX (when create is false) command + + static Command lpush(const std::string& list, const std::vector& value, bool create = true); + /// Returns a LPUSH or LPUSHX (when create is false) command + + static Command lrange(const std::string& list, Int64 start = 0, Int64 stop = 0); + /// Returns a LRANGE command + static Command set(const std::string& key, const std::string& value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); /// Returns a SET command to set the key with a value + + static Command set(const std::string& key, Int64 value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); + /// Returns a SET command to set the key with a value + + static Command rpush(const std::string& list, const std::string& value, bool create = true); + /// Returns a RPUSH or RPUSHX (when create is false) command + + static Command rpush(const std::string& list, const std::vector& value, bool create = true); + /// Returns a RPUSH or RPUSHX (when create is false) command }; }} // namespace Poco::Redis diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 648e06f49..578500648 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -16,6 +16,7 @@ // #include "Poco/Redis/Command.h" +#include "Poco/NumberFormatter.h" namespace Poco { namespace Redis { @@ -33,18 +34,131 @@ Command::~Command() { } +Command Command::append(const std::string& key, const std::string& value) +{ + Command cmd("APPEND"); + cmd.add(key).add(value); + return cmd; +} + +Command Command::del(const std::string& key) +{ + Command cmd("DEL"); + cmd.add(key); + return cmd; +} + +Command Command::del(const std::vector& keys) +{ + Command cmd("DEL"); + for(std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it) + { + cmd.add(*it); + } + return cmd; +} + +Command Command::get(const std::string& key) +{ + Command cmd("GET"); + cmd.add(key); + return cmd; +} + +Command Command::incr(const std::string& key, Int64 by) +{ + Command cmd(by == 0 ? "INCR" : "INCRBY"); + cmd.add(key); + if ( by > 0 ) cmd.add(NumberFormatter::format(by)); + return cmd; +} + +Command Command::lindex(const std::string& list, Int64 index) +{ + Command cmd("LINDEX"); + cmd.add(list).add(NumberFormatter::format(index)); + return cmd; +} + +Command Command::linsert(const std::string& list, bool before, const std::string& reference, const std::string& value) +{ + Command cmd("LINSERT"); + cmd.add(list).add(before ? "BEFORE" : "AFTER").add(reference).add(value); + return cmd; +} + +Command Command::llen(const std::string& list) +{ + Command cmd("LLEN"); + cmd.add(list); + return cmd; +} + +Command Command::lpush(const std::string& list, const std::string& value, bool create) +{ + Command cmd(create ? "LPUSH" : "LPUSHX"); + cmd.add(list).add(value); + + return cmd; +} + +Command Command::lpush(const std::string& list, const std::vector& values, bool create) +{ + Command cmd(create ? "LPUSH" : "LPUSHX"); + cmd.add(list); + + for(std::vector::const_iterator it = values.begin(); it != values.end(); ++it) + { + cmd.add(*it); + } + + return cmd; +} + +Command Command::lrange(const std::string& list, Int64 start, Int64 stop) +{ + Command cmd("LRANGE"); + cmd.add(list).add(NumberFormatter::format(start)).add(NumberFormatter::format(stop)); + return cmd; +} + + Command Command::set(const std::string& key, const std::string& value, bool overwrite, const Poco::Timespan& expireTime, bool create) { Command cmd("SET"); - cmd.add(key); - cmd.add(value); + cmd.add(key).add(value); if ( ! overwrite ) cmd.add("NX"); if ( ! create ) cmd.add("XX"); if ( expireTime.totalMicroseconds() > 0 ) { - cmd.add("PX"); - cmd.add(expireTime.totalMilliseconds()); + cmd.add("PX").add(expireTime.totalMilliseconds()); + } + + return cmd; +} + +Command Command::set(const std::string& key, Int64 value, bool overwrite, const Poco::Timespan& expireTime, bool create) +{ + return set(key, NumberFormatter::format(value), overwrite, expireTime, create); +} + +Command Command::rpush(const std::string& list, const std::string& value, bool create) +{ + Command cmd(create ? "RPUSH" : "RPUSHX"); + cmd.add(list).add(value); + + return cmd; +} + +Command Command::rpush(const std::string& list, const std::vector& values, bool create) +{ + Command cmd(create ? "RPUSH" : "RPUSHX"); + cmd.add(list); + + for(std::vector::const_iterator it = values.begin(); it != values.end(); ++it) + { + cmd.add(*it); } return cmd; diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 917d53e1e..651e457ce 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -80,9 +80,7 @@ void RedisTest::testAppend() return; } - Array delCommand; - delCommand.add("DEL") - .add("mykey"); + Command delCommand = Command::del("mykey"); try { _redis.execute(delCommand); @@ -111,10 +109,7 @@ void RedisTest::testAppend() fail(e.message()); } - Array appendCommand; - appendCommand.add("APPEND") - .add("mykey") - .add(" World"); + Command appendCommand = Command::append("mykey", " World"); try { Poco::Int64 result = _redis.execute(appendCommand); @@ -129,9 +124,7 @@ void RedisTest::testAppend() fail(e.message()); } - Array getCommand; - getCommand.add("GET") - .add("mykey"); + Command getCommand = Command::get("mykey"); try { BulkString result = _redis.execute(getCommand); @@ -179,11 +172,7 @@ void RedisTest::testIncr() return; } - Array command; - command.add("SET") - .add("mykey") - .add("10"); - + Command command = Command::set("mykey", "10"); // A set responds with a simple OK string try { @@ -195,10 +184,7 @@ void RedisTest::testIncr() fail(e.message()); } - command.clear(); - command.add("INCR") - .add("mykey"); - + command = Command::incr("mykey"); try { Poco::Int64 value = _redis.execute(command); @@ -218,11 +204,7 @@ void RedisTest::testIncrBy() return; } - Array command; - command.add("SET") - .add("mykey") - .add("10"); - + Command command = Command::set("mykey", "10"); // A set responds with a simple OK string try { @@ -234,11 +216,7 @@ void RedisTest::testIncrBy() fail(e.message()); } - command.clear(); - command.add("INCRBY") - .add("mykey") - .add("5"); - + command = Command::incr("mykey", 5); try { Poco::Int64 value = _redis.execute(command); @@ -429,9 +407,7 @@ void RedisTest::testRPush() } // Make sure the list is not there yet ... - Array delCommand; - delCommand.add("DEL") - .add("mylist"); + Command delCommand = Command::del("mylist"); try { _redis.execute(delCommand); @@ -445,48 +421,53 @@ void RedisTest::testRPush() fail(e.message()); } - for(int i = 0; i < 2; ++i) - { - Array command; - command.add("RPUSH") - .add("mylist"); - - if ( i == 0 ) command.add("Hello"); - else command.add("World"); - - // A RPUSH responds with an integer - try - { - Poco::Int64 result = _redis.execute(command); - assert(result == (i + 1)); - } - catch(RedisException &e) - { - fail(e.message()); - } - } - - Array command; - command.add("LRANGE") - .add("mylist") - .add("0") - .add("-1"); - try { - Array result = _redis.execute(command); + Command rpush = Command::rpush("mylist", "World"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); - assert(result.size() == 2); - BulkString value = result.get(0); - assert(value.value().compare("Hello") == 0); - - value = result.get(1); - assert(value.value().compare("World") == 0); + rpush = Command::rpush("mylist", "Hello"); + result = _redis.execute(rpush); + assert(result == 2); } catch(RedisException &e) { fail(e.message()); } + + Command llen = Command::llen("mylist"); + try + { + Poco::Int64 n = _redis.execute(llen); + assert(n == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist", 0, -1); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("World") == 0); + assert(result.get(1).value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } } void RedisTest::testLIndex() @@ -498,9 +479,7 @@ void RedisTest::testLIndex() } // Make sure the list is not there yet ... - Array delCommand; - delCommand.add("DEL") - .add("mylist"); + Command delCommand = Command::del("mylist"); try { _redis.execute(delCommand); @@ -514,35 +493,25 @@ void RedisTest::testLIndex() fail(e.message()); } - for(int i = 0; i < 2; ++i) - { - Array command; - command.add("LPUSH") - .add("mylist"); - - if ( i == 0 ) command.add("World"); - else command.add("Hello"); - - // A RPUSH responds with an integer - try - { - Poco::Int64 result = _redis.execute(command); - assert(result == (i + 1)); - } - catch(RedisException &e) - { - fail(e.message()); - } - } - - Array command; - command.add("LINDEX") - .add("mylist") - .add("0"); - try { - BulkString result = _redis.execute(command); + Command lpush = Command::lpush("mylist", "World"); + Poco::Int64 result = _redis.execute(lpush); + assert(result == 1); + + lpush = Command::lpush("mylist", "Hello"); + result = _redis.execute(lpush); + assert(result == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lindex = Command::lindex("mylist", 0); + try + { + BulkString result = _redis.execute(lindex); assert(result.value().compare("Hello") == 0); } catch(RedisException &e) @@ -551,6 +520,67 @@ void RedisTest::testLIndex() } } +void RedisTest::testLInsert() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + Command delCommand = Command::del("mylist"); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + try + { + Command rpush = Command::rpush("mylist", "Hello"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "World"); + result = _redis.execute(rpush); + assert(result == 2); + + Command linsert = Command::linsert("mylist", true, "World", "There"); + result = _redis.execute(linsert); + assert(result == 3); + + Command lrange = Command::lrange("mylist", 0, -1); + Array range = _redis.execute(lrange); + assert(range.size() == 3); + + std::cout << range.toString() << std::endl; + + assert(range.get(0).value().compare("Hello") == 0); + assert(range.get(1).value().compare("There") == 0); + assert(range.get(2).value().compare("World") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::BadCastException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } +} + void RedisTest::testMulti() { if (!_connected) @@ -806,6 +836,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testStrlen); CppUnit_addTest(pSuite, RedisTest, testRPush); CppUnit_addTest(pSuite, RedisTest, testLIndex); + CppUnit_addTest(pSuite, RedisTest, testLInsert); CppUnit_addTest(pSuite, RedisTest, testMulti); CppUnit_addTest(pSuite, RedisTest, testPubSub); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 369f6fb9f..bf2d3d11b 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -40,6 +40,7 @@ public: void testStrlen(); void testRPush(); void testLIndex(); + void testLInsert(); void testMulti(); void testPubSub(); From 825e99578a83996e0e9a59fcb152042aefa0f7ba Mon Sep 17 00:00:00 2001 From: Guenter Obiltschnig Date: Tue, 10 Nov 2015 09:27:15 +0100 Subject: [PATCH 048/121] GH #1022: clean-up setThreadName --- Foundation/src/Thread_POSIX.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Foundation/src/Thread_POSIX.cpp b/Foundation/src/Thread_POSIX.cpp index ff4208f8f..b8295c4fa 100644 --- a/Foundation/src/Thread_POSIX.cpp +++ b/Foundation/src/Thread_POSIX.cpp @@ -76,14 +76,12 @@ void setThreadName(pthread_t thread, const std::string& threadName) #if (POCO_OS == POCO_OS_MAC_OS_X) pthread_setname_np(threadName.c_str()); // __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2) #else - if (pthread_setname_np(thread, threadName.c_str())) + if (pthread_setname_np(thread, threadName.c_str()) != 0 && errno == ERANGE && threadName.size() > 15) { - char truncName[16] = {0}; - std::size_t suffixIndex = threadName.length() - 7; - std::memcpy(truncName, &threadName[0], 7); - truncName[7] = '~'; - memcpy(&truncName[8], &threadName[suffixIndex], 7); - pthread_setname_np(thread, truncName); + std::string truncName(threadName, 0, 7); + truncName.append("~"); + truncName.append(threadName, threadName.size() - 7, 7); + pthread_setname_np(thread, truncName.c_str()); } #endif } From 98918b39c4ac32c4063d095881fb7f9575bc1395 Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 10 Nov 2015 22:48:28 +0100 Subject: [PATCH 049/121] Add more comments --- Redis/include/Poco/Redis/Client.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 82f272135..40f2ca45a 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -50,6 +50,17 @@ class Redis_API Client /// { /// // We have a string value /// } + /// + /// To create Redis commands, the factory methods of the Command class can + /// be used or the Array class can be used directly. + /// + /// Command llen = Command::llen("list"); + /// + /// is the same as + /// + /// Array command; + /// command.add("LLEN").add("list"); + /// { public: Client(); @@ -137,7 +148,7 @@ public: Type* error = dynamic_cast*>(redisResult.get()); throw RedisException(error->value().getMessage()); } - + if (redisResult->type() == ElementTraits::TypeId) { Type* type = dynamic_cast*>(redisResult.get()); From b66751a919d498bf5773ee1008694448136c4f03 Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 10 Nov 2015 22:48:54 +0100 Subject: [PATCH 050/121] Add more factory methods for commands --- Redis/include/Poco/Redis/Command.h | 23 ++- Redis/src/Command.cpp | 48 +++++ Redis/testsuite/src/RedisTest.cpp | 286 +++++++++++++++++++++++++---- Redis/testsuite/src/RedisTest.h | 4 + 4 files changed, 318 insertions(+), 43 deletions(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index da28e93e0..ea7ea5fe1 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -22,6 +22,7 @@ #include "Poco/Redis/Array.h" #include +#include namespace Poco { namespace Redis { @@ -43,6 +44,9 @@ public: static Command append(const std::string& key, const std::string& value); /// Returns an APPEND command + static Command decr(const std::string& key, Int64 by = 0); + /// Returns an DECR or DECRBY command. Calls DECR when by is omitted or zero. + static Command del(const std::string& key); /// Returns an DEL command @@ -62,7 +66,10 @@ public: /// Returns a LINSERT command static Command llen(const std::string& list); - /// Returns a LINDEX command + /// Returns a LLEN command + + static Command lpop(const std::string& list); + /// Returns a LPOP command static Command lpush(const std::string& list, const std::string& value, bool create = true); /// Returns a LPUSH or LPUSHX (when create is false) command @@ -70,8 +77,18 @@ public: static Command lpush(const std::string& list, const std::vector& value, bool create = true); /// Returns a LPUSH or LPUSHX (when create is false) command - static Command lrange(const std::string& list, Int64 start = 0, Int64 stop = 0); - /// Returns a LRANGE command + static Command lrange(const std::string& list, Int64 start = 0, Int64 stop = -1); + /// Returns a LRANGE command. When start and stop is omitted an LRANGE + /// command will returned that returns all items of the list. + + static Command lrem(const std::string& list, Int64 count, const std::string& value); + /// Returns a LREM command + + static Command mget(const std::vector& keys); + /// Returns a MGET command + + static Command mset(const std::map& keyvalues, bool create = true); + /// Returns a MSET or MSETNX (when create is false) command static Command set(const std::string& key, const std::string& value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); /// Returns a SET command to set the key with a value diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 578500648..0566cf0da 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -41,6 +41,14 @@ Command Command::append(const std::string& key, const std::string& value) return cmd; } +Command Command::decr(const std::string& key, Int64 by) +{ + Command cmd(by == 0 ? "DECR" : "DECRBY"); + cmd.add(key); + if ( by > 0 ) cmd.add(NumberFormatter::format(by)); + return cmd; +} + Command Command::del(const std::string& key) { Command cmd("DEL"); @@ -94,6 +102,13 @@ Command Command::llen(const std::string& list) return cmd; } +Command Command::lpop(const std::string& list) +{ + Command cmd("LPOP"); + cmd.add(list); + return cmd; +} + Command Command::lpush(const std::string& list, const std::string& value, bool create) { Command cmd(create ? "LPUSH" : "LPUSHX"); @@ -122,6 +137,39 @@ Command Command::lrange(const std::string& list, Int64 start, Int64 stop) return cmd; } +Command Command::lrem(const std::string& list, Int64 count, const std::string& value) +{ + Command cmd("LREM"); + + cmd.add(list).add(NumberFormatter::format(count)).add(value); + + return cmd; +} + +Command Command::mget(const std::vector& keys) +{ + Command cmd("MGET"); + + for(std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it) + { + cmd.add(*it); + } + + return cmd; +} + +Command Command::mset(const std::map& keyvalues, bool create) +{ + Command cmd(create ? "MSET" : "MSETNX"); + + for(std::map::const_iterator it = keyvalues.begin(); it != keyvalues.end(); ++it) + { + cmd.add(it->first); + cmd.add(it->second); + } + + return cmd; +} Command Command::set(const std::string& key, const std::string& value, bool overwrite, const Poco::Timespan& expireTime, bool create) { diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 651e457ce..6a90c29f1 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -140,6 +140,59 @@ void RedisTest::testAppend() } } +void RedisTest::testDecr() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Command set = Command::set("mykey", 10); + try + { + std::string result = _redis.execute(set); + assert(result.compare("OK") == 0); + } + catch(RedisException& e) + { + fail(e.message()); + } + + Command decr = Command::decr("mykey"); + try + { + Poco::Int64 result = _redis.execute(decr); + assert(result == 9); + } + catch(RedisException& e) + { + fail(e.message()); + } + + set = Command::set("mykey", "234293482390480948029348230948"); + try + { + std::string result = _redis.execute(set); + assert(result.compare("OK") == 0); + } + catch(RedisException& e) + { + fail(e.message()); + } + + try + { + Poco::Int64 result = _redis.execute(decr); + fail("This must fail"); + } + catch(RedisException& e) + { + // ERR value is not an integer or out of range + } + +} + void RedisTest::testEcho() { if (!_connected) @@ -164,6 +217,66 @@ void RedisTest::testEcho() } } +void RedisTest::testError() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("Wrong Command"); + + try + { + BulkString result = _redis.execute(command); + fail("Invalid command must throw RedisException"); + } + catch(RedisException &e) + { + // Must fail + } +} + +void RedisTest::testSet() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("SET") + .add("mykey") + .add("Hello"); + + // A set responds with a simple OK string + try + { + std::string result = _redis.execute(command); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.add("NX"); + // A set NX responds with a Null bulk string + // when the key is already set + try + { + BulkString result = _redis.execute(command); + assert(result.isNull()); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testIncr() { if (!_connected) @@ -265,44 +378,6 @@ void RedisTest::testPing() } -void RedisTest::testSet() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - Array command; - command.add("SET") - .add("mykey") - .add("Hello"); - - // A set responds with a simple OK string - try - { - std::string result = _redis.execute(command); - assert(result.compare("OK") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - - command.add("NX"); - // A set NX responds with a Null bulk string - // when the key is already set - try - { - BulkString result = _redis.execute(command); - assert(result.isNull()); - } - catch(RedisException &e) - { - fail(e.message()); - } -} - void RedisTest::testMSet() { if (!_connected) @@ -358,6 +433,62 @@ void RedisTest::testMSet() } } +void RedisTest::testMSetWithMap() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + std::map keyValuePairs; + keyValuePairs.insert(std::make_pair("key1", "Hello")); + keyValuePairs.insert(std::make_pair("key2", "World")); + + Command mset = Command::mset(keyValuePairs); + + // A MSET responds with a simple OK string + try + { + std::string result = _redis.execute(mset); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + std::vector keys; + keys.push_back("key1"); + keys.push_back("key2"); + keys.push_back("nonexisting"); + + Command mget = Command::mget(keys); + try + { + Array result = _redis.execute(mget); + + assert(result.size() == 3); + BulkString value = result.get(0); + assert(value.value().compare("Hello") == 0); + + value = result.get(1); + assert(value.value().compare("World") == 0); + + value = result.get(2); + assert(value.isNull()); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } +} + + void RedisTest::testStrlen() { if (!_connected) @@ -561,8 +692,6 @@ void RedisTest::testLInsert() Array range = _redis.execute(lrange); assert(range.size() == 3); - std::cout << range.toString() << std::endl; - assert(range.get(0).value().compare("Hello") == 0); assert(range.get(1).value().compare("There") == 0); assert(range.get(2).value().compare("World") == 0); @@ -581,6 +710,79 @@ void RedisTest::testLInsert() } } +void RedisTest::testLRem() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + Command delCommand = Command::del("mylist"); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + try + { + std::vector list; + list.push_back("hello"); + list.push_back("hello"); + list.push_back("foo"); + list.push_back("hello"); + Command rpush = Command::rpush("mylist", list); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 4); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lrem = Command::lrem("mylist", -2, "hello"); + try + { + Poco::Int64 n = _redis.execute(lrem); + assert(n == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("hello") == 0); + assert(result.get(1).value().compare("foo") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } +} + void RedisTest::testMulti() { if (!_connected) @@ -827,16 +1029,20 @@ CppUnit::Test* RedisTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTest"); CppUnit_addTest(pSuite, RedisTest, testAppend); + CppUnit_addTest(pSuite, RedisTest, testDecr); CppUnit_addTest(pSuite, RedisTest, testIncr); CppUnit_addTest(pSuite, RedisTest, testIncrBy); CppUnit_addTest(pSuite, RedisTest, testEcho); + CppUnit_addTest(pSuite, RedisTest, testError); CppUnit_addTest(pSuite, RedisTest, testPing); CppUnit_addTest(pSuite, RedisTest, testSet); CppUnit_addTest(pSuite, RedisTest, testMSet); + CppUnit_addTest(pSuite, RedisTest, testMSetWithMap); CppUnit_addTest(pSuite, RedisTest, testStrlen); CppUnit_addTest(pSuite, RedisTest, testRPush); CppUnit_addTest(pSuite, RedisTest, testLIndex); CppUnit_addTest(pSuite, RedisTest, testLInsert); + CppUnit_addTest(pSuite, RedisTest, testLRem); CppUnit_addTest(pSuite, RedisTest, testMulti); CppUnit_addTest(pSuite, RedisTest, testPubSub); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index bf2d3d11b..092c16b9c 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -31,16 +31,20 @@ public: virtual ~RedisTest(); void testAppend(); + void testDecr(); void testEcho(); + void testError(); void testIncr(); void testIncrBy(); void testPing(); void testSet(); void testMSet(); + void testMSetWithMap(); void testStrlen(); void testRPush(); void testLIndex(); void testLInsert(); + void testLRem(); void testMulti(); void testPubSub(); From 2a2b768afd27b1407434e92265c0ef0c2e5b4a4e Mon Sep 17 00:00:00 2001 From: Daniel Rosser Date: Thu, 12 Nov 2015 17:19:34 +1100 Subject: [PATCH 051/121] tvOS / WatchOS bitcode enabled --- build/config/AppleTV | 2 +- build/config/WatchOS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/config/AppleTV b/build/config/AppleTV index dff58750c..4f68d8bab 100644 --- a/build/config/AppleTV +++ b/build/config/AppleTV @@ -31,7 +31,7 @@ TVOS_SDK_VERSION_MIN ?= $(patsubst %.sdk,%,$(patsubst $(TVOS_SDK_ROOT_DIR)%,%,$( POCO_TARGET_OSNAME ?= $(TVOS_SDK) POCO_TARGET_OSARCH ?= arm64 TOOL_PREFIX ?= $(shell xcode-select -print-path)/Platforms/$(TVOS_SDK).platform/Developer/usr/bin -OSFLAGS ?= -arch $(POCO_TARGET_OSARCH) -isysroot $(TVOS_SDK_BASE) -mtvos-version-min=$(TVOS_SDK_VERSION_MIN) +OSFLAGS ?= -arch $(POCO_TARGET_OSARCH) -isysroot $(TVOS_SDK_BASE) -mtvos-version-min=$(TVOS_SDK_VERSION_MIN) -fembed-bitcode # # Tools diff --git a/build/config/WatchOS b/build/config/WatchOS index 15721fe22..d576e0235 100644 --- a/build/config/WatchOS +++ b/build/config/WatchOS @@ -31,7 +31,7 @@ WATCHOS_SDK_VERSION_MIN ?= $(patsubst %.sdk,%,$(patsubst $(WATCHOS_SDK_ROOT_DIR) POCO_TARGET_OSNAME ?= $(WATCHOS_SDK) POCO_TARGET_OSARCH ?= armv7k TOOL_PREFIX ?= $(shell xcode-select -print-path)/Platforms/$(WATCHOS_SDK).platform/Developer/usr/bin -OSFLAGS ?= -arch $(POCO_TARGET_OSARCH) -isysroot $(WATCHOS_SDK_BASE) -mwatchos-version-min=$(WATCHOS_SDK_VERSION_MIN) +OSFLAGS ?= -arch $(POCO_TARGET_OSARCH) -isysroot $(WATCHOS_SDK_BASE) -mwatchos-version-min=$(WATCHOS_SDK_VERSION_MIN) -fembed-bitcode # # Tools From 9e66e6e522619fe8da1cc986f528de351d9c493c Mon Sep 17 00:00:00 2001 From: Daniel Rosser Date: Thu, 12 Nov 2015 23:56:52 +1100 Subject: [PATCH 052/121] tvOS / WatchOS bitcode enabled for simulators --- build/config/AppleTVSimulator | 2 +- build/config/WatchSimulator | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/config/AppleTVSimulator b/build/config/AppleTVSimulator index 211b34c31..a8659a2ca 100644 --- a/build/config/AppleTVSimulator +++ b/build/config/AppleTVSimulator @@ -8,6 +8,6 @@ TVOS_SDK = AppleTVSimulator POCO_TARGET_OSARCH = x86_64 -OSFLAGS = -arch $(POCO_TARGET_OSARCH) -isysroot $(TVOS_SDK_BASE) -mtvos-simulator-version-min=$(TVOS_SDK_VERSION_MIN) +OSFLAGS = -arch $(POCO_TARGET_OSARCH) -isysroot $(TVOS_SDK_BASE) -mtvos-simulator-version-min=$(TVOS_SDK_VERSION_MIN) -fembed-bitcode include $(POCO_BASE)/build/config/AppleTV diff --git a/build/config/WatchSimulator b/build/config/WatchSimulator index 3e296ac20..b264e4c9a 100644 --- a/build/config/WatchSimulator +++ b/build/config/WatchSimulator @@ -8,6 +8,6 @@ WATCHOS_SDK = WatchSimulator POCO_TARGET_OSARCH = i386 -OSFLAGS = -arch $(POCO_TARGET_OSARCH) -isysroot $(WATCHOS_SDK_BASE) -mwatchos-simulator-version-min=$(WATCHOS_SDK_VERSION_MIN) +OSFLAGS = -arch $(POCO_TARGET_OSARCH) -isysroot $(WATCHOS_SDK_BASE) -mwatchos-simulator-version-min=$(WATCHOS_SDK_VERSION_MIN) -fembed-bitcode include $(POCO_BASE)/build/config/WatchOS From b7bdbf89f0b2a89c0aeb024eef2375d836aa2729 Mon Sep 17 00:00:00 2001 From: fbraem Date: Thu, 12 Nov 2015 18:29:46 +0100 Subject: [PATCH 053/121] add testLPop --- Redis/testsuite/src/RedisTest.cpp | 74 +++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 2 files changed, 75 insertions(+) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 6a90c29f1..08e8a5a82 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -378,6 +378,79 @@ void RedisTest::testPing() } +void RedisTest::testLPop() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + Command delCommand = Command::del("mylist"); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + try + { + Command rpush = Command::rpush("mylist", "one"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "two"); + result = _redis.execute(rpush); + assert(result == 2); + + rpush = Command::rpush("mylist", "three"); + result = _redis.execute(rpush); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lpop = Command::lpop("mylist"); + try + { + BulkString result = _redis.execute(lpop); + assert(result.value().compare("one") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("two") == 0); + assert(result.get(1).value().compare("three") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } + +} + void RedisTest::testMSet() { if (!_connected) @@ -1043,6 +1116,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testLIndex); CppUnit_addTest(pSuite, RedisTest, testLInsert); CppUnit_addTest(pSuite, RedisTest, testLRem); + CppUnit_addTest(pSuite, RedisTest, testLPop); CppUnit_addTest(pSuite, RedisTest, testMulti); CppUnit_addTest(pSuite, RedisTest, testPubSub); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 092c16b9c..19ab9decf 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -44,6 +44,7 @@ public: void testRPush(); void testLIndex(); void testLInsert(); + void testLPop(); void testLRem(); void testMulti(); From cd2060232099230084d03d345ca3f687084a7f73 Mon Sep 17 00:00:00 2001 From: fbraem Date: Thu, 12 Nov 2015 19:06:35 +0100 Subject: [PATCH 054/121] Rename ElementTraits to RedisTypeTraits / Move read to traits --- Redis/include/Poco/Redis/Array.h | 35 ++++++------ Redis/include/Poco/Redis/Client.h | 4 +- Redis/include/Poco/Redis/Error.h | 14 +++-- Redis/include/Poco/Redis/Type.h | 90 +++++++++++++++---------------- Redis/src/Array.cpp | 4 +- Redis/src/Type.cpp | 10 ++-- 6 files changed, 77 insertions(+), 80 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 850550af9..34bc1b6af 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -94,7 +94,7 @@ public: if ( pos >= _elements.value().size() ) throw InvalidArgumentException(); RedisType::Ptr element = _elements.value().at(pos); - if ( ElementTraits::TypeId == element->type() ) + if ( RedisTypeTraits::TypeId == element->type() ) { Type* concrete = dynamic_cast* >(element.get()); if ( concrete != NULL ) return concrete->value(); @@ -198,7 +198,7 @@ inline size_t Array::size() const template<> -struct ElementTraits +struct RedisTypeTraits { enum { TypeId = RedisType::REDIS_ARRAY }; @@ -223,28 +223,29 @@ struct ElementTraits } return result.str(); } -}; -template<> inline -void Type::read(RedisInputStream& input) -{ - Int64 length = NumberParser::parse64(input.getline()); - - if ( length != -1 ) + static void read(RedisInputStream& input, Array& value) { - for(int i = 0; i < length; ++i) + value.clear(); + + Int64 length = NumberParser::parse64(input.getline()); + + if ( length != -1 ) { - char marker = input.get(); - RedisType::Ptr element = Type::createRedisType(marker); + for(int i = 0; i < length; ++i) + { + char marker = input.get(); + RedisType::Ptr element = RedisType::createRedisType(marker); - if ( element.isNull() ) - throw RedisException("Wrong answer received from Redis server"); + if ( element.isNull() ) + throw RedisException("Wrong answer received from Redis server"); - element->read(input); - _value.add(element); + element->read(input); + value.add(element); + } } } -} +}; }} diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 40f2ca45a..8650ef466 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -143,13 +143,13 @@ public: /// the reply is not of the given type. { RedisType::Ptr redisResult = readReply(); - if (redisResult->type() == ElementTraits::TypeId) + if (redisResult->type() == RedisTypeTraits::TypeId) { Type* error = dynamic_cast*>(redisResult.get()); throw RedisException(error->value().getMessage()); } - if (redisResult->type() == ElementTraits::TypeId) + if (redisResult->type() == RedisTypeTraits::TypeId) { Type* type = dynamic_cast*>(redisResult.get()); if (type != NULL) result = type->value(); diff --git a/Redis/include/Poco/Redis/Error.h b/Redis/include/Poco/Redis/Error.h index 1fccad94e..f9464c40c 100644 --- a/Redis/include/Poco/Redis/Error.h +++ b/Redis/include/Poco/Redis/Error.h @@ -51,7 +51,7 @@ inline void Error::setMessage(const std::string& message) } template<> -struct ElementTraits +struct RedisTypeTraits { enum { TypeId = RedisType::REDIS_ERROR }; @@ -61,15 +61,13 @@ struct ElementTraits { return marker + value.getMessage() + LineEnding::NEWLINE_CRLF; } + + static void read(RedisInputStream& input, Error& value) + { + value.setMessage(input.getline()); + } }; - -template<> inline -void Type::read(RedisInputStream& input) -{ - _value = input.getline(); -} - }} // Namespace Poco::Redis #endif // Redis_Error_INCLUDED \ No newline at end of file diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index dd82960bb..9a930964f 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -102,27 +102,34 @@ inline bool RedisType::isSimpleString() const } template -struct ElementTraits +struct RedisTypeTraits { }; template<> -struct ElementTraits +struct RedisTypeTraits { enum { TypeId = RedisType::REDIS_INTEGER }; static const char marker = ':'; - static std::string toString(const Poco::Int64& value) + static std::string toString(const Int64& value) { return marker + NumberFormatter::format(value) + "\r\n"; } + + static void read(RedisInputStream& input, Int64& value) + { + std::string number = input.getline(); + value = NumberParser::parse64(number); + } + }; template<> -struct ElementTraits +struct RedisTypeTraits { enum { TypeId = RedisType::REDIS_SIMPLE_STRING }; @@ -132,6 +139,11 @@ struct ElementTraits { return marker + value + LineEnding::NEWLINE_CRLF; } + + static void read(RedisInputStream& input, std::string& value) + { + value = input.getline(); + } }; @@ -141,7 +153,7 @@ typedef Nullable BulkString; template<> -struct ElementTraits +struct RedisTypeTraits { enum { TypeId = RedisType::REDIS_BULK_STRING }; @@ -163,6 +175,24 @@ struct ElementTraits + LineEnding::NEWLINE_CRLF; } } + + static void read(RedisInputStream& input, BulkString& value) + { + value.clear(); + + std::string line = input.getline(); + int length = NumberParser::parse64(line); + + if ( length >= 0 ) + { + std::string s; + s.resize(length, ' '); + input.read(&*s.begin(), length); + value.assign(s); + + input.getline(); // Read and ignore /r/n + } + } }; @@ -189,14 +219,17 @@ public: int type() const { - return ElementTraits::TypeId; + return RedisTypeTraits::TypeId; } - virtual void read(RedisInputStream& socket); - - virtual std::string toString() const + void read(RedisInputStream& socket) { - return ElementTraits::toString(_value); + RedisTypeTraits::read(socket, _value); + } + + std::string toString() const + { + return RedisTypeTraits::toString(_value); } T& value() @@ -214,41 +247,6 @@ private: T _value; }; -template<> inline -void Type::read(RedisInputStream& input) -{ - std::string number = input.getline(); - _value = NumberParser::parse64(number); -} - -template<> inline -void Type::read(RedisInputStream& input) -{ - _value.clear(); - _value = input.getline(); -} - -template<> inline -void Type::read(RedisInputStream& input) -{ - _value.clear(); - - std::string line = input.getline(); - int length = NumberParser::parse64(line); - - if ( length >= 0 ) - { - std::string s; - s.resize(length, ' '); - input.read(&*s.begin(), length); - _value.assign(s); - - line = input.getline(); - } - -} - - -}} +}} // Namespace Poco/Redis #endif // Redis_Type_INCLUDED diff --git a/Redis/src/Array.cpp b/Redis/src/Array.cpp index bcf8ef507..dcceab844 100644 --- a/Redis/src/Array.cpp +++ b/Redis/src/Array.cpp @@ -46,9 +46,9 @@ Array& Array::add(RedisType::Ptr value) } -std::string Array::toString() const +std::string Array::toString() const { - return ElementTraits::toString(*this); + return RedisTypeTraits::toString(*this); } } } diff --git a/Redis/src/Type.cpp b/Redis/src/Type.cpp index e0962f62b..68ce05a90 100644 --- a/Redis/src/Type.cpp +++ b/Redis/src/Type.cpp @@ -38,19 +38,19 @@ RedisType::Ptr RedisType::createRedisType(char marker) switch(marker) { - case ElementTraits::marker : + case RedisTypeTraits::marker : result = new Type(); break; - case ElementTraits::marker : + case RedisTypeTraits::marker : result = new Type(); break; - case ElementTraits::marker : + case RedisTypeTraits::marker : result = new Type(); break; - case ElementTraits::marker : + case RedisTypeTraits::marker : result = new Type(); break; - case ElementTraits::marker : + case RedisTypeTraits::marker : result = new Type(); break; } From b8ea4e1d3bde4181812d72722735f62eda9f8356 Mon Sep 17 00:00:00 2001 From: fbraem Date: Thu, 12 Nov 2015 23:37:14 +0100 Subject: [PATCH 055/121] Add operator<< and make use of template function for add --- Redis/include/Poco/Redis/Array.h | 69 ++++++++++++++++++-------------- Redis/src/Array.cpp | 2 +- Redis/src/Client.cpp | 2 +- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 34bc1b6af..b1c1548af 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -47,26 +47,34 @@ public: virtual ~Array(); /// Destructor. - Array& add(Poco::Int64 value); - /// Adds an integer element. + template + Array& operator<<(const T& arg) + /// Adds the argument to the array + { + addRedisType(new Type(arg)); + return *this; + } - Array& add(const std::string& value); - /// Adds a bulk string element. A bulk string is a string that - /// is binary safe (it can contain newlines). If you want a simple - /// string use addSimpleString (can't contain a newline!). - - Array& add(const BulkString& value); - /// Adds a bulk string element. + Array& operator<<(const char* s); Array& add(); - /// Adds a Null bulk string element. + /// Adds an Null BulkString - Array& add(RedisType::Ptr value); + template + Array& add(const T& arg) + /// Adds an element to the array. + /// Note: the specialization for std::string will add a BulkString! + /// If you really need a simple string, call addSimpleString. + { + addRedisType(new Type(arg)); + return *this; + } + + Array& add(const char* s); + + Array& addRedisType(RedisType::Ptr value); /// Adds a Redis element. - Array& add(const Array& array); - /// Adds an array. - Array& addSimpleString(const std::string& value); /// Adds a simple string (can't contain newline characters!) @@ -124,35 +132,34 @@ private: void checkNull(); }; +inline Array& Array::operator<<(const char* s) +{ + BulkString value(s); + return add(value); +} + inline Array& Array::add() { BulkString value; - return add(new Type(value)); + return add(value); } -inline Array& Array::add(Int64 value) +template<> +inline Array& Array::add(const std::string& arg) { - return add(new Type(value)); + BulkString value(arg); + return add(value); } -inline Array& Array::add(const std::string& value) +inline Array& Array::add(const char* s) { - return add(new Type(value)); -} - -inline Array& Array::add(const BulkString& value) -{ - return add(new Type(value)); -} - -inline Array& Array::add(const Array& value) -{ - return add(new Type(value)); + BulkString value(s); + return add(value); } inline Array& Array::addSimpleString(const std::string& value) { - return add(new Type(value)); + return addRedisType(new Type(value)); } inline Array::const_iterator Array::begin() const @@ -241,7 +248,7 @@ struct RedisTypeTraits throw RedisException("Wrong answer received from Redis server"); element->read(input); - value.add(element); + value.addRedisType(element); } } } diff --git a/Redis/src/Array.cpp b/Redis/src/Array.cpp index dcceab844..f4f56754c 100644 --- a/Redis/src/Array.cpp +++ b/Redis/src/Array.cpp @@ -36,7 +36,7 @@ Array::~Array() } -Array& Array::add(RedisType::Ptr value) +Array& Array::addRedisType(RedisType::Ptr value) { checkNull(); diff --git a/Redis/src/Client.cpp b/Redis/src/Client.cpp index d63906561..80a6c6222 100644 --- a/Redis/src/Client.cpp +++ b/Redis/src/Client.cpp @@ -167,7 +167,7 @@ Array Client::sendCommands(const std::vector& commands) for(int i = 0; i < commands.size(); ++i) { - results.add(readReply()); + results.addRedisType(readReply()); } return results; From 43cdb369b4ecdc00b6a1c24fd852b3447564bf9d Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 13 Nov 2015 19:01:51 +0100 Subject: [PATCH 056/121] Call add so we are sure we call the specialization for std::string --- Redis/include/Poco/Redis/Array.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index b1c1548af..67de2bfa0 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -49,10 +49,12 @@ public: template Array& operator<<(const T& arg) - /// Adds the argument to the array + /// Adds the argument to the array. + /// Note: a std::string will be added as a BulkString because this + /// is commonly used for representing strings in Redis. If you + /// really need a simple string, use addSimpleString. { - addRedisType(new Type(arg)); - return *this; + return add(arg); } Array& operator<<(const char* s); @@ -65,6 +67,9 @@ public: /// Adds an element to the array. /// Note: the specialization for std::string will add a BulkString! /// If you really need a simple string, call addSimpleString. + /// Note: the specialization for std::string will add the string as + /// a BulkString because this is commonly used for representing strings + /// in Redis. If you really need a simple string, use addSimpleString. { addRedisType(new Type(arg)); return *this; From d1f9d36fb624684df642af55d0d7a53f9a9f0905 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 13 Nov 2015 22:51:32 +0100 Subject: [PATCH 057/121] Add lset, ltrim and rpop and use operator << --- Redis/include/Poco/Redis/Command.h | 9 +++ Redis/src/Command.cpp | 107 +++++++++++++++++++++-------- 2 files changed, 86 insertions(+), 30 deletions(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index ea7ea5fe1..68bcc0e6e 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -84,6 +84,12 @@ public: static Command lrem(const std::string& list, Int64 count, const std::string& value); /// Returns a LREM command + static Command lset(const std::string& list, Int64 index, const std::string& value); + /// Returns a LSET command + + static Command ltrim(const std::string& list, Int64 start = 0, Int64 stop = -1); + /// Returns a LTRIM command + static Command mget(const std::vector& keys); /// Returns a MGET command @@ -96,6 +102,9 @@ public: static Command set(const std::string& key, Int64 value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); /// Returns a SET command to set the key with a value + static Command rpop(const std::string& list); + /// Returns a RPOP command + static Command rpush(const std::string& list, const std::string& value, bool create = true); /// Returns a RPUSH or RPUSHX (when create is false) command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 0566cf0da..af2362fce 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -37,82 +37,102 @@ Command::~Command() Command Command::append(const std::string& key, const std::string& value) { Command cmd("APPEND"); - cmd.add(key).add(value); + + cmd << key << value; + return cmd; } Command Command::decr(const std::string& key, Int64 by) { Command cmd(by == 0 ? "DECR" : "DECRBY"); - cmd.add(key); - if ( by > 0 ) cmd.add(NumberFormatter::format(by)); + + cmd << key; + if ( by > 0 ) cmd << NumberFormatter::format(by); + return cmd; } Command Command::del(const std::string& key) { Command cmd("DEL"); - cmd.add(key); + + cmd << key; + return cmd; } Command Command::del(const std::vector& keys) { Command cmd("DEL"); + for(std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it) { - cmd.add(*it); + cmd << *it; } + return cmd; } Command Command::get(const std::string& key) { Command cmd("GET"); - cmd.add(key); + + cmd << key; + return cmd; } Command Command::incr(const std::string& key, Int64 by) { Command cmd(by == 0 ? "INCR" : "INCRBY"); - cmd.add(key); - if ( by > 0 ) cmd.add(NumberFormatter::format(by)); + + cmd << key; + if ( by > 0 ) cmd << NumberFormatter::format(by); + return cmd; } Command Command::lindex(const std::string& list, Int64 index) { Command cmd("LINDEX"); - cmd.add(list).add(NumberFormatter::format(index)); + + cmd << list << NumberFormatter::format(index); + return cmd; } Command Command::linsert(const std::string& list, bool before, const std::string& reference, const std::string& value) { Command cmd("LINSERT"); - cmd.add(list).add(before ? "BEFORE" : "AFTER").add(reference).add(value); + + cmd << list << (before ? "BEFORE" : "AFTER") << reference << value; return cmd; } Command Command::llen(const std::string& list) { Command cmd("LLEN"); - cmd.add(list); + + cmd << list; + return cmd; } Command Command::lpop(const std::string& list) { Command cmd("LPOP"); - cmd.add(list); + + cmd << list; + return cmd; } Command Command::lpush(const std::string& list, const std::string& value, bool create) { Command cmd(create ? "LPUSH" : "LPUSHX"); - cmd.add(list).add(value); + + cmd << list << value; return cmd; } @@ -120,11 +140,11 @@ Command Command::lpush(const std::string& list, const std::string& value, bool c Command Command::lpush(const std::string& list, const std::vector& values, bool create) { Command cmd(create ? "LPUSH" : "LPUSHX"); - cmd.add(list); + cmd << list; for(std::vector::const_iterator it = values.begin(); it != values.end(); ++it) { - cmd.add(*it); + cmd << *it; } return cmd; @@ -133,7 +153,9 @@ Command Command::lpush(const std::string& list, const std::vector& Command Command::lrange(const std::string& list, Int64 start, Int64 stop) { Command cmd("LRANGE"); - cmd.add(list).add(NumberFormatter::format(start)).add(NumberFormatter::format(stop)); + + cmd << list << NumberFormatter::format(start) << NumberFormatter::format(stop); + return cmd; } @@ -141,7 +163,25 @@ Command Command::lrem(const std::string& list, Int64 count, const std::string& v { Command cmd("LREM"); - cmd.add(list).add(NumberFormatter::format(count)).add(value); + cmd << list << NumberFormatter::format(count) << value; + + return cmd; +} + +Command Command::lset(const std::string& list, Int64 index, const std::string& value) +{ + Command cmd("LSET"); + + cmd << list << NumberFormatter::format(index) << value; + + return cmd; +} + +Command Command::ltrim(const std::__cxx11::string& list, Int64 start, Int64 stop) +{ + Command cmd("LTRIM"); + + cmd << list << NumberFormatter::format(start) << NumberFormatter::format(stop); return cmd; } @@ -152,7 +192,7 @@ Command Command::mget(const std::vector& keys) for(std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it) { - cmd.add(*it); + cmd << *it; } return cmd; @@ -164,8 +204,7 @@ Command Command::mset(const std::map& keyvalues, bool for(std::map::const_iterator it = keyvalues.begin(); it != keyvalues.end(); ++it) { - cmd.add(it->first); - cmd.add(it->second); + cmd << it->first << it->second; } return cmd; @@ -174,14 +213,11 @@ Command Command::mset(const std::map& keyvalues, bool Command Command::set(const std::string& key, const std::string& value, bool overwrite, const Poco::Timespan& expireTime, bool create) { Command cmd("SET"); - cmd.add(key).add(value); - if ( ! overwrite ) cmd.add("NX"); - if ( ! create ) cmd.add("XX"); - if ( expireTime.totalMicroseconds() > 0 ) - { - cmd.add("PX").add(expireTime.totalMilliseconds()); - } + cmd << key << value; + if (! overwrite) cmd << "NX"; + if (! create) cmd << "XX"; + if (expireTime.totalMicroseconds() > 0) cmd << "PX" << expireTime.totalMilliseconds(); return cmd; } @@ -191,10 +227,21 @@ Command Command::set(const std::string& key, Int64 value, bool overwrite, const return set(key, NumberFormatter::format(value), overwrite, expireTime, create); } +Command Command::rpop(const std::string& list) +{ + Command cmd("RPOP"); + + cmd << list; + + return cmd; +} + + Command Command::rpush(const std::string& list, const std::string& value, bool create) { Command cmd(create ? "RPUSH" : "RPUSHX"); - cmd.add(list).add(value); + + cmd << list << value; return cmd; } @@ -202,11 +249,11 @@ Command Command::rpush(const std::string& list, const std::string& value, bool c Command Command::rpush(const std::string& list, const std::vector& values, bool create) { Command cmd(create ? "RPUSH" : "RPUSHX"); - cmd.add(list); + cmd << list; for(std::vector::const_iterator it = values.begin(); it != values.end(); ++it) { - cmd.add(*it); + cmd << *it; } return cmd; From df452c610f3a1ce4630fbf7f3d744135985e584f Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 13 Nov 2015 22:52:15 +0100 Subject: [PATCH 058/121] Add lset, ltrim and rpop tests --- Redis/testsuite/src/RedisTest.cpp | 241 +++++++++++++++++++++++++++++- Redis/testsuite/src/RedisTest.h | 3 + 2 files changed, 238 insertions(+), 6 deletions(-) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 08e8a5a82..f73b55902 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -451,6 +451,162 @@ void RedisTest::testLPop() } +void RedisTest::testLSet() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + Command delCommand = Command::del("mylist"); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + try + { + Command rpush = Command::rpush("mylist", "one"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "two"); + result = _redis.execute(rpush); + assert(result == 2); + + rpush = Command::rpush("mylist", "three"); + result = _redis.execute(rpush); + assert(result == 3); + } + catch(RedisException& e) + { + fail(e.message()); + } + + Command lset = Command::lset("mylist", 0, "four"); + try + { + std::string result = _redis.execute(lset); + } + catch(RedisException& e) + { + fail(e.message()); + } + + lset = Command::lset("mylist", -2, "five"); + try + { + std::string result = _redis.execute(lset); + } + catch(RedisException& e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 3); + assert(result.get(0).value().compare("four") == 0); + assert(result.get(1).value().compare("five") == 0); + assert(result.get(2).value().compare("three") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } + +} + +void RedisTest::testLTrim() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + Command delCommand = Command::del("mylist"); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + try + { + Command rpush = Command::rpush("mylist", "one"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "two"); + result = _redis.execute(rpush); + assert(result == 2); + + rpush = Command::rpush("mylist", "three"); + result = _redis.execute(rpush); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command ltrim = Command::ltrim("mylist", 1); + try + { + std::string result = _redis.execute(ltrim); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("two") == 0); + assert(result.get(1).value().compare("three") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } + +} + void RedisTest::testMSet() { if (!_connected) @@ -459,12 +615,8 @@ void RedisTest::testMSet() return; } - Array command; - command.add("MSET") - .add("key1") - .add("Hello") - .add("key2") - .add("World"); + Command command("MSET"); + command << "key1" << "Hello" << "key2" << "World"; // A MSET responds with a simple OK string try @@ -602,6 +754,79 @@ void RedisTest::testStrlen() } } +void RedisTest::testRPop() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + Command delCommand = Command::del("mylist"); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + try + { + Command rpush = Command::rpush("mylist", "one"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "two"); + result = _redis.execute(rpush); + assert(result == 2); + + rpush = Command::rpush("mylist", "three"); + result = _redis.execute(rpush); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command rpop = Command::rpop("mylist"); + try + { + BulkString result = _redis.execute(rpop); + assert(result.value().compare("three") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("one") == 0); + assert(result.get(1).value().compare("two") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } + +} + void RedisTest::testRPush() { if (!_connected) @@ -1116,11 +1341,15 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testLIndex); CppUnit_addTest(pSuite, RedisTest, testLInsert); CppUnit_addTest(pSuite, RedisTest, testLRem); + CppUnit_addTest(pSuite, RedisTest, testLSet); + CppUnit_addTest(pSuite, RedisTest, testLTrim); CppUnit_addTest(pSuite, RedisTest, testLPop); CppUnit_addTest(pSuite, RedisTest, testMulti); CppUnit_addTest(pSuite, RedisTest, testPubSub); + CppUnit_addTest(pSuite, RedisTest, testRPop); + CppUnit_addTest(pSuite, RedisTest, testPipeliningWithSendCommands); CppUnit_addTest(pSuite, RedisTest, testPipeliningWithWriteCommand); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 19ab9decf..34bbdf52f 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -46,9 +46,12 @@ public: void testLInsert(); void testLPop(); void testLRem(); + void testLSet(); + void testLTrim(); void testMulti(); void testPubSub(); + void testRPop(); void testPipeliningWithSendCommands(); void testPipeliningWithWriteCommand(); From f3dd36ac70007dc2335f0673b8d379a8358c84f0 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 14 Nov 2015 18:36:48 +0100 Subject: [PATCH 059/121] Add rpoplpush --- Redis/include/Poco/Redis/Command.h | 3 + Redis/src/Command.cpp | 8 +++ Redis/testsuite/src/RedisTest.cpp | 93 ++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 105 insertions(+) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 68bcc0e6e..096499a04 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -105,6 +105,9 @@ public: static Command rpop(const std::string& list); /// Returns a RPOP command + static Command rpoplpush(const std::string& sourceList, const std::string& destinationList); + /// Returns a RPOPLPUSH command + static Command rpush(const std::string& list, const std::string& value, bool create = true); /// Returns a RPUSH or RPUSHX (when create is false) command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index af2362fce..6957d96f4 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -236,6 +236,14 @@ Command Command::rpop(const std::string& list) return cmd; } +Command Command::rpoplpush(const std::string& sourceList, const std::string& destinationList) +{ + Command cmd("RPOPLPUSH"); + + cmd << sourceList << destinationList; + + return cmd; +} Command Command::rpush(const std::string& list, const std::string& value, bool create) { diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index f73b55902..d9b567e50 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -827,6 +827,98 @@ void RedisTest::testRPop() } +void RedisTest::testRPoplPush() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the lists are not there yet ... + std::vector lists; + lists.push_back("mylist"); + lists.push_back("myotherlist"); + Command delCommand = Command::del(lists); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + try + { + Command rpush = Command::rpush("mylist", "one"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "two"); + result = _redis.execute(rpush); + assert(result == 2); + + rpush = Command::rpush("mylist", "three"); + result = _redis.execute(rpush); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command rpoplpush = Command::rpoplpush("mylist", "myotherlist"); + try + { + BulkString result = _redis.execute(rpoplpush); + assert(result.value().compare("three") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("one") == 0); + assert(result.get(1).value().compare("two") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } + + lrange = Command::lrange("myotherlist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 1); + assert(result.get(0).value().compare("three") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } +} + void RedisTest::testRPush() { if (!_connected) @@ -1338,6 +1430,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testMSetWithMap); CppUnit_addTest(pSuite, RedisTest, testStrlen); CppUnit_addTest(pSuite, RedisTest, testRPush); + CppUnit_addTest(pSuite, RedisTest, testRPoplPush); CppUnit_addTest(pSuite, RedisTest, testLIndex); CppUnit_addTest(pSuite, RedisTest, testLInsert); CppUnit_addTest(pSuite, RedisTest, testLRem); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 34bbdf52f..ffb07352e 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -52,6 +52,7 @@ public: void testPubSub(); void testRPop(); + void testRPoplPush(); void testPipeliningWithSendCommands(); void testPipeliningWithWriteCommand(); From ed0b61c6e1c718e06710bc3ff321f05ef2168c04 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 14 Nov 2015 18:53:19 +0100 Subject: [PATCH 060/121] Sort methods and add delKey method --- Redis/testsuite/src/RedisTest.cpp | 1049 +++++++++++++---------------- Redis/testsuite/src/RedisTest.h | 22 +- 2 files changed, 479 insertions(+), 592 deletions(-) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index d9b567e50..e008092d3 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -80,19 +80,7 @@ void RedisTest::testAppend() return; } - Command delCommand = Command::del("mykey"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } + delKey("mykey"); Command setCommand = Command::set("mykey", "Hello"); try @@ -239,44 +227,6 @@ void RedisTest::testError() } } -void RedisTest::testSet() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - Array command; - command.add("SET") - .add("mykey") - .add("Hello"); - - // A set responds with a simple OK string - try - { - std::string result = _redis.execute(command); - assert(result.compare("OK") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - - command.add("NX"); - // A set NX responds with a Null bulk string - // when the key is already set - try - { - BulkString result = _redis.execute(command); - assert(result.isNull()); - } - catch(RedisException &e) - { - fail(e.message()); - } -} - void RedisTest::testIncr() { if (!_connected) @@ -387,19 +337,7 @@ void RedisTest::testLPop() } // Make sure the list is not there yet ... - Command delCommand = Command::del("mylist"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } + delKey("mylist"); try { @@ -460,19 +398,7 @@ void RedisTest::testLSet() } // Make sure the list is not there yet ... - Command delCommand = Command::del("mylist"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } + delKey("mylist"); try { @@ -533,6 +459,151 @@ void RedisTest::testLSet() } } +void RedisTest::testLIndex() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + delKey("mylist"); + + try + { + Command lpush = Command::lpush("mylist", "World"); + Poco::Int64 result = _redis.execute(lpush); + assert(result == 1); + + lpush = Command::lpush("mylist", "Hello"); + result = _redis.execute(lpush); + assert(result == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lindex = Command::lindex("mylist", 0); + try + { + BulkString result = _redis.execute(lindex); + assert(result.value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testLInsert() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + delKey("mylist"); + + try + { + Command rpush = Command::rpush("mylist", "Hello"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "World"); + result = _redis.execute(rpush); + assert(result == 2); + + Command linsert = Command::linsert("mylist", true, "World", "There"); + result = _redis.execute(linsert); + assert(result == 3); + + Command lrange = Command::lrange("mylist", 0, -1); + Array range = _redis.execute(lrange); + assert(range.size() == 3); + + assert(range.get(0).value().compare("Hello") == 0); + assert(range.get(1).value().compare("There") == 0); + assert(range.get(2).value().compare("World") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::BadCastException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } +} + +void RedisTest::testLRem() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + delKey("mylist"); + + try + { + std::vector list; + list.push_back("hello"); + list.push_back("hello"); + list.push_back("foo"); + list.push_back("hello"); + Command rpush = Command::rpush("mylist", list); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 4); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lrem = Command::lrem("mylist", -2, "hello"); + try + { + Poco::Int64 n = _redis.execute(lrem); + assert(n == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("hello") == 0); + assert(result.get(1).value().compare("foo") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } +} void RedisTest::testLTrim() { @@ -543,19 +614,7 @@ void RedisTest::testLTrim() } // Make sure the list is not there yet ... - Command delCommand = Command::del("mylist"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } + delKey("mylist"); try { @@ -713,466 +772,6 @@ void RedisTest::testMSetWithMap() } } - -void RedisTest::testStrlen() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - Array command; - command.add("SET") - .add("mykey") - .add("Hello World"); - - // A set responds with a simple OK string - try - { - std::string result = _redis.execute(command); - assert(result.compare("OK") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - - command.clear(); - command.add("STRLEN") - .add("mykey"); - - try - { - Poco::Int64 result = _redis.execute(command); - - assert(result == 11); - } - catch(RedisException &e) - { - fail(e.message()); - } -} - -void RedisTest::testRPop() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - // Make sure the list is not there yet ... - Command delCommand = Command::del("mylist"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } - - try - { - Command rpush = Command::rpush("mylist", "one"); - Poco::Int64 result = _redis.execute(rpush); - assert(result == 1); - - rpush = Command::rpush("mylist", "two"); - result = _redis.execute(rpush); - assert(result == 2); - - rpush = Command::rpush("mylist", "three"); - result = _redis.execute(rpush); - assert(result == 3); - } - catch(RedisException &e) - { - fail(e.message()); - } - - Command rpop = Command::rpop("mylist"); - try - { - BulkString result = _redis.execute(rpop); - assert(result.value().compare("three") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - - Command lrange = Command::lrange("mylist"); - try - { - Array result = _redis.execute(lrange); - - assert(result.size() == 2); - assert(result.get(0).value().compare("one") == 0); - assert(result.get(1).value().compare("two") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - catch(Poco::NullValueException &e) - { - fail(e.message()); - } - -} - -void RedisTest::testRPoplPush() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - // Make sure the lists are not there yet ... - std::vector lists; - lists.push_back("mylist"); - lists.push_back("myotherlist"); - Command delCommand = Command::del(lists); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } - - try - { - Command rpush = Command::rpush("mylist", "one"); - Poco::Int64 result = _redis.execute(rpush); - assert(result == 1); - - rpush = Command::rpush("mylist", "two"); - result = _redis.execute(rpush); - assert(result == 2); - - rpush = Command::rpush("mylist", "three"); - result = _redis.execute(rpush); - assert(result == 3); - } - catch(RedisException &e) - { - fail(e.message()); - } - - Command rpoplpush = Command::rpoplpush("mylist", "myotherlist"); - try - { - BulkString result = _redis.execute(rpoplpush); - assert(result.value().compare("three") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - - Command lrange = Command::lrange("mylist"); - try - { - Array result = _redis.execute(lrange); - - assert(result.size() == 2); - assert(result.get(0).value().compare("one") == 0); - assert(result.get(1).value().compare("two") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - catch(Poco::NullValueException &e) - { - fail(e.message()); - } - - lrange = Command::lrange("myotherlist"); - try - { - Array result = _redis.execute(lrange); - - assert(result.size() == 1); - assert(result.get(0).value().compare("three") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - catch(Poco::NullValueException &e) - { - fail(e.message()); - } -} - -void RedisTest::testRPush() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - // Make sure the list is not there yet ... - Command delCommand = Command::del("mylist"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } - - try - { - Command rpush = Command::rpush("mylist", "World"); - Poco::Int64 result = _redis.execute(rpush); - assert(result == 1); - - rpush = Command::rpush("mylist", "Hello"); - result = _redis.execute(rpush); - assert(result == 2); - } - catch(RedisException &e) - { - fail(e.message()); - } - - Command llen = Command::llen("mylist"); - try - { - Poco::Int64 n = _redis.execute(llen); - assert(n == 2); - } - catch(RedisException &e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } - - Command lrange = Command::lrange("mylist", 0, -1); - try - { - Array result = _redis.execute(lrange); - - assert(result.size() == 2); - assert(result.get(0).value().compare("World") == 0); - assert(result.get(1).value().compare("Hello") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - catch(Poco::NullValueException &e) - { - fail(e.message()); - } -} - -void RedisTest::testLIndex() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - // Make sure the list is not there yet ... - Command delCommand = Command::del("mylist"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } - - try - { - Command lpush = Command::lpush("mylist", "World"); - Poco::Int64 result = _redis.execute(lpush); - assert(result == 1); - - lpush = Command::lpush("mylist", "Hello"); - result = _redis.execute(lpush); - assert(result == 2); - } - catch(RedisException &e) - { - fail(e.message()); - } - - Command lindex = Command::lindex("mylist", 0); - try - { - BulkString result = _redis.execute(lindex); - assert(result.value().compare("Hello") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } -} - -void RedisTest::testLInsert() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - // Make sure the list is not there yet ... - Command delCommand = Command::del("mylist"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } - - try - { - Command rpush = Command::rpush("mylist", "Hello"); - Poco::Int64 result = _redis.execute(rpush); - assert(result == 1); - - rpush = Command::rpush("mylist", "World"); - result = _redis.execute(rpush); - assert(result == 2); - - Command linsert = Command::linsert("mylist", true, "World", "There"); - result = _redis.execute(linsert); - assert(result == 3); - - Command lrange = Command::lrange("mylist", 0, -1); - Array range = _redis.execute(lrange); - assert(range.size() == 3); - - assert(range.get(0).value().compare("Hello") == 0); - assert(range.get(1).value().compare("There") == 0); - assert(range.get(2).value().compare("World") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - catch(Poco::BadCastException &e) - { - fail(e.message()); - } - catch(Poco::NullValueException &e) - { - fail(e.message()); - } -} - -void RedisTest::testLRem() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - // Make sure the list is not there yet ... - Command delCommand = Command::del("mylist"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } - - try - { - std::vector list; - list.push_back("hello"); - list.push_back("hello"); - list.push_back("foo"); - list.push_back("hello"); - Command rpush = Command::rpush("mylist", list); - Poco::Int64 result = _redis.execute(rpush); - assert(result == 4); - } - catch(RedisException &e) - { - fail(e.message()); - } - - Command lrem = Command::lrem("mylist", -2, "hello"); - try - { - Poco::Int64 n = _redis.execute(lrem); - assert(n == 2); - } - catch(RedisException &e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } - - Command lrange = Command::lrange("mylist"); - try - { - Array result = _redis.execute(lrange); - - assert(result.size() == 2); - assert(result.get(0).value().compare("hello") == 0); - assert(result.get(1).value().compare("foo") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - catch(Poco::NullValueException &e) - { - fail(e.message()); - } -} - void RedisTest::testMulti() { if (!_connected) @@ -1182,22 +781,8 @@ void RedisTest::testMulti() } // Make sure keys are gone from a previous testrun ... - Array delCommand; - delCommand.add("DEL") - .add("foo") - .add("bar"); - try - { - _redis.execute(delCommand); - } - catch(RedisException& e) - { - fail(e.message()); - } - catch(Poco::BadCastException& e) - { - fail(e.message()); - } + delKey("foo"); + delKey("bar"); Array command; command.add("MULTI"); @@ -1393,8 +978,7 @@ void RedisTest::testPubSub() RedisSubscriber subscriber; Array subscribe; - subscribe.add("SUBSCRIBE") - .add("test"); + subscribe.add("SUBSCRIBE").add("test"); _redis.execute(subscribe); _redis.flush(); @@ -1414,6 +998,312 @@ void RedisTest::testPubSub() _redis.flush(); } +void RedisTest::testSet() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("SET").add("mykey").add("Hello"); + + // A set responds with a simple OK string + try + { + std::string result = _redis.execute(command); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.add("NX"); + // A set NX responds with a Null bulk string + // when the key is already set + try + { + BulkString result = _redis.execute(command); + assert(result.isNull()); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testStrlen() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("SET").add("mykey").add("Hello World"); + + // A set responds with a simple OK string + try + { + std::string result = _redis.execute(command); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.clear(); + command.add("STRLEN") + .add("mykey"); + + try + { + Poco::Int64 result = _redis.execute(command); + + assert(result == 11); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testRPop() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + delKey("mylist"); + + try + { + Command rpush = Command::rpush("mylist", "one"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "two"); + result = _redis.execute(rpush); + assert(result == 2); + + rpush = Command::rpush("mylist", "three"); + result = _redis.execute(rpush); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command rpop = Command::rpop("mylist"); + try + { + BulkString result = _redis.execute(rpop); + assert(result.value().compare("three") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("one") == 0); + assert(result.get(1).value().compare("two") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } + +} + +void RedisTest::testRPoplPush() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the lists are not there yet ... + std::vector lists; + lists.push_back("mylist"); + lists.push_back("myotherlist"); + Command delCommand = Command::del(lists); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + try + { + Command rpush = Command::rpush("mylist", "one"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "two"); + result = _redis.execute(rpush); + assert(result == 2); + + rpush = Command::rpush("mylist", "three"); + result = _redis.execute(rpush); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command rpoplpush = Command::rpoplpush("mylist", "myotherlist"); + try + { + BulkString result = _redis.execute(rpoplpush); + assert(result.value().compare("three") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("one") == 0); + assert(result.get(1).value().compare("two") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } + + lrange = Command::lrange("myotherlist"); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 1); + assert(result.get(0).value().compare("three") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } +} + +void RedisTest::testRPush() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the list is not there yet ... + delKey("mylist"); + + try + { + Command rpush = Command::rpush("mylist", "World"); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 1); + + rpush = Command::rpush("mylist", "Hello"); + result = _redis.execute(rpush); + assert(result == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command llen = Command::llen("mylist"); + try + { + Poco::Int64 n = _redis.execute(llen); + assert(n == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + Command lrange = Command::lrange("mylist", 0, -1); + try + { + Array result = _redis.execute(lrange); + + assert(result.size() == 2); + assert(result.get(0).value().compare("World") == 0); + assert(result.get(1).value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + catch(Poco::NullValueException &e) + { + fail(e.message()); + } +} + + +void RedisTest::delKey(const std::string& key) +{ + Command delCommand = Command::del(key); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } +} + + CppUnit::Test* RedisTest::suite() { CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTest"); @@ -1424,27 +1314,24 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testIncrBy); CppUnit_addTest(pSuite, RedisTest, testEcho); CppUnit_addTest(pSuite, RedisTest, testError); - CppUnit_addTest(pSuite, RedisTest, testPing); - CppUnit_addTest(pSuite, RedisTest, testSet); - CppUnit_addTest(pSuite, RedisTest, testMSet); - CppUnit_addTest(pSuite, RedisTest, testMSetWithMap); - CppUnit_addTest(pSuite, RedisTest, testStrlen); - CppUnit_addTest(pSuite, RedisTest, testRPush); - CppUnit_addTest(pSuite, RedisTest, testRPoplPush); CppUnit_addTest(pSuite, RedisTest, testLIndex); CppUnit_addTest(pSuite, RedisTest, testLInsert); + CppUnit_addTest(pSuite, RedisTest, testLPop); CppUnit_addTest(pSuite, RedisTest, testLRem); CppUnit_addTest(pSuite, RedisTest, testLSet); CppUnit_addTest(pSuite, RedisTest, testLTrim); - CppUnit_addTest(pSuite, RedisTest, testLPop); + CppUnit_addTest(pSuite, RedisTest, testMSet); + CppUnit_addTest(pSuite, RedisTest, testMSetWithMap); CppUnit_addTest(pSuite, RedisTest, testMulti); - - CppUnit_addTest(pSuite, RedisTest, testPubSub); - - CppUnit_addTest(pSuite, RedisTest, testRPop); - + CppUnit_addTest(pSuite, RedisTest, testPing); CppUnit_addTest(pSuite, RedisTest, testPipeliningWithSendCommands); CppUnit_addTest(pSuite, RedisTest, testPipeliningWithWriteCommand); + CppUnit_addTest(pSuite, RedisTest, testPubSub); + CppUnit_addTest(pSuite, RedisTest, testSet); + CppUnit_addTest(pSuite, RedisTest, testStrlen); + CppUnit_addTest(pSuite, RedisTest, testRPop); + CppUnit_addTest(pSuite, RedisTest, testRPoplPush); + CppUnit_addTest(pSuite, RedisTest, testRPush); return pSuite; } diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index ffb07352e..aedc50b13 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -36,12 +36,6 @@ public: void testError(); void testIncr(); void testIncrBy(); - void testPing(); - void testSet(); - void testMSet(); - void testMSetWithMap(); - void testStrlen(); - void testRPush(); void testLIndex(); void testLInsert(); void testLPop(); @@ -49,13 +43,17 @@ public: void testLSet(); void testLTrim(); void testMulti(); - - void testPubSub(); - void testRPop(); - void testRPoplPush(); - + void testMSet(); + void testMSetWithMap(); + void testPing(); void testPipeliningWithSendCommands(); void testPipeliningWithWriteCommand(); + void testPubSub(); + void testSet(); + void testStrlen(); + void testRPop(); + void testRPoplPush(); + void testRPush(); void setUp(); void tearDown(); @@ -64,6 +62,8 @@ public: private: + void delKey(const std::string& key); + std::string _host; unsigned _port; static bool _connected; From 4e5fe3f8740b92f9f5e12e793008138b2c483a43 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 14 Nov 2015 19:39:16 +0100 Subject: [PATCH 061/121] Add blpop / brpop / brpoplpush --- Redis/include/Poco/Redis/Command.h | 9 +++ Redis/src/Command.cpp | 35 +++++++++ Redis/testsuite/src/RedisTest.cpp | 115 +++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 2 + 4 files changed, 161 insertions(+) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 096499a04..1cfa879e6 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -44,6 +44,15 @@ public: static Command append(const std::string& key, const std::string& value); /// Returns an APPEND command + static Command blpop(const std::vector& lists, Int64 timeout = 0); + /// Returns a BLPOP command + + static Command brpop(const std::vector& lists, Int64 timeout = 0); + /// Returns a BRPOP command + + static Command brpoplpush(const std::string& sourceList, const std::string& destinationList, Int64 timeout = 0); + /// Returns a BRPOPLPUSH command + static Command decr(const std::string& key, Int64 by = 0); /// Returns an DECR or DECRBY command. Calls DECR when by is omitted or zero. diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 6957d96f4..382e3b528 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -43,6 +43,41 @@ Command Command::append(const std::string& key, const std::string& value) return cmd; } +Command Command::blpop(const std::vector& lists, Int64 timeout) +{ + Command cmd("BLPOP"); + + for(std::vector::const_iterator it = lists.begin(); it != lists.end(); ++it) + { + cmd << *it; + } + cmd << NumberFormatter::format(timeout); + + return cmd; +} + +Command Command::brpop(const std::vector& lists, Int64 timeout) +{ + Command cmd("BRPOP"); + + for(std::vector::const_iterator it = lists.begin(); it != lists.end(); ++it) + { + cmd << *it; + } + cmd << NumberFormatter::format(timeout); + + return cmd; +} + +Command Command::brpoplpush(const std::string& sourceList, const std::string& destinationList, Int64 timeout) +{ + Command cmd("BRPOPLPUSH"); + + cmd << sourceList << destinationList << NumberFormatter::format(timeout); + + return cmd; +} + Command Command::decr(const std::string& key, Int64 by) { Command cmd(by == 0 ? "DECR" : "DECRBY"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index e008092d3..c27278950 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -128,6 +128,118 @@ void RedisTest::testAppend() } } +void RedisTest::testBLpop() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the lists are not there yet ... + std::vector lists; + lists.push_back("list1"); + lists.push_back("list2"); + Command delCommand = Command::del(lists); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + std::vector values; + values.push_back("a"); + values.push_back("b"); + values.push_back("c"); + + try + { + Command rpush = Command::rpush("list1", values); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command blpop = Command::blpop(lists); + try + { + Array result = _redis.execute(blpop); + assert(result.size() == 2); + assert(result.get(0).value().compare("list1") == 0); + assert(result.get(1).value().compare("a") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testBRpop() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + // Make sure the lists are not there yet ... + std::vector lists; + lists.push_back("list1"); + lists.push_back("list2"); + Command delCommand = Command::del(lists); + try + { + _redis.execute(delCommand); + } + catch(RedisException& e) + { + fail(e.message()); + } + catch(Poco::BadCastException& e) + { + fail(e.message()); + } + + std::vector values; + values.push_back("a"); + values.push_back("b"); + values.push_back("c"); + + try + { + Command rpush = Command::rpush("list1", values); + Poco::Int64 result = _redis.execute(rpush); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command brpop = Command::brpop(lists); + try + { + Array result = _redis.execute(brpop); + assert(result.size() == 2); + assert(result.get(0).value().compare("list1") == 0); + assert(result.get(1).value().compare("c") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testDecr() { if (!_connected) @@ -1309,6 +1421,9 @@ CppUnit::Test* RedisTest::suite() CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTest"); CppUnit_addTest(pSuite, RedisTest, testAppend); + CppUnit_addTest(pSuite, RedisTest, testBLpop); + CppUnit_addTest(pSuite, RedisTest, testBRpop); + CppUnit_addTest(pSuite, RedisTest, testDecr); CppUnit_addTest(pSuite, RedisTest, testDecr); CppUnit_addTest(pSuite, RedisTest, testIncr); CppUnit_addTest(pSuite, RedisTest, testIncrBy); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index aedc50b13..155031a20 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -31,6 +31,8 @@ public: virtual ~RedisTest(); void testAppend(); + void testBLpop(); + void testBRpop(); void testDecr(); void testEcho(); void testError(); From 36108e2378186327d49a458b0332c015e3490b88 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 14 Nov 2015 20:12:33 +0100 Subject: [PATCH 062/121] Add rename --- Redis/include/Poco/Redis/Command.h | 5 +- Redis/src/Command.cpp | 10 +++ Redis/testsuite/src/RedisTest.cpp | 97 ++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 2 + 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 1cfa879e6..c8b85e750 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -29,7 +29,7 @@ namespace Redis { class Redis_API Command : public Array /// Helper class for creating commands. This class contains - /// factory methods for common used Redis commands. + /// factory methods for commonly used Redis commands. { public: Command(const std::string& command); @@ -111,6 +111,9 @@ public: static Command set(const std::string& key, Int64 value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); /// Returns a SET command to set the key with a value + static Command rename(const std::string& key, const std::string& newName, bool overwrite = true); + /// Returns a RENAME or RENAMENX when overwrite is false + static Command rpop(const std::string& list); /// Returns a RPOP command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 382e3b528..8fdc6ce5f 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -262,6 +262,16 @@ Command Command::set(const std::string& key, Int64 value, bool overwrite, const return set(key, NumberFormatter::format(value), overwrite, expireTime, create); } +Command Command::rename(const std::string& key, const std::string& newName, bool overwrite) +{ + Command cmd(overwrite ? "RENAME" : "RENAMENX"); + + cmd << key << newName; + + return cmd; +} + + Command Command::rpop(const std::string& list) { Command cmd("RPOP"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index c27278950..21d53c984 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -1184,6 +1184,101 @@ void RedisTest::testStrlen() } } +void RedisTest::testRename() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Command set = Command::set("mykey", "Hello"); + try + { + std::string result = _redis.execute(set); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command rename = Command::rename("mykey", "myotherkey"); + try + { + std::string result = _redis.execute(rename); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command get = Command::get("myotherkey"); + try + { + BulkString result = _redis.execute(get); + assert(result.value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testRenameNx() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Command set = Command::set("mykey", "Hello"); + try + { + std::string result = _redis.execute(set); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + set = Command::set("myotherkey", "World"); + try + { + std::string result = _redis.execute(set); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command rename = Command::rename("mykey", "myotherkey", false); + try + { + Poco::Int64 result = _redis.execute(rename); + assert(result == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command get = Command::get("myotherkey"); + try + { + BulkString result = _redis.execute(get); + assert(result.value().compare("World") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testRPop() { if (!_connected) @@ -1444,6 +1539,8 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testPubSub); CppUnit_addTest(pSuite, RedisTest, testSet); CppUnit_addTest(pSuite, RedisTest, testStrlen); + CppUnit_addTest(pSuite, RedisTest, testRename); + CppUnit_addTest(pSuite, RedisTest, testRenameNx); CppUnit_addTest(pSuite, RedisTest, testRPop); CppUnit_addTest(pSuite, RedisTest, testRPoplPush); CppUnit_addTest(pSuite, RedisTest, testRPush); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 155031a20..ab387865b 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -53,6 +53,8 @@ public: void testPubSub(); void testSet(); void testStrlen(); + void testRename(); + void testRenameNx(); void testRPop(); void testRPoplPush(); void testRPush(); From d4a791d79cd8d771c1a9bc1d75670b00411b6835 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 14 Nov 2015 20:41:12 +0100 Subject: [PATCH 063/121] Add scard --- Redis/include/Poco/Redis/Command.h | 16 ++++ Redis/src/Command.cpp | 40 +++++++++ Redis/testsuite/src/RedisTest.cpp | 138 +++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 3 + 4 files changed, 197 insertions(+) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index c8b85e750..181a68b5d 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -30,6 +30,10 @@ namespace Redis { class Redis_API Command : public Array /// Helper class for creating commands. This class contains /// factory methods for commonly used Redis commands. + /// There are two ways of building commands: + /// 1. Use this class (which uses option 2 in the factory methods) + /// 2. Use the Array class and build the command using the add method + /// or << operator. { public: Command(const std::string& command); @@ -105,6 +109,18 @@ public: static Command mset(const std::map& keyvalues, bool create = true); /// Returns a MSET or MSETNX (when create is false) command + static Command sadd(const std::string& key, const std::string& value); + /// Returns a SADD command + + static Command sadd(const std::string& key, const std::vector& values); + /// Returns a SADD command + + static Command scard(const std::string& key); + /// Returns a SCARD command + + static Command smembers(const std::string& key); + /// Returns a SMEMBERS command + static Command set(const std::string& key, const std::string& value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); /// Returns a SET command to set the key with a value diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 8fdc6ce5f..aa0fe2058 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -245,6 +245,46 @@ Command Command::mset(const std::map& keyvalues, bool return cmd; } +Command Command::sadd(const std::string& key, const std::string& value) +{ + Command cmd("SADD"); + + cmd << key << value; + + return cmd; +} + +Command Command::sadd(const std::string& key, const std::vector& values) +{ + Command cmd("SADD"); + + cmd << key; + for(std::vector::const_iterator it = values.begin(); it != values.end(); ++it) + { + cmd << *it; + } + + return cmd; +} + +Command Command::scard(const std::string& key) +{ + Command cmd("SCARD"); + + cmd << key; + + return cmd; +} + +Command Command::smembers(const std::string& key) +{ + Command cmd("SMEMBERS"); + + cmd << key; + + return cmd; +} + Command Command::set(const std::string& key, const std::string& value, bool overwrite, const Poco::Timespan& expireTime, bool create) { Command cmd("SET"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 21d53c984..0fdcf9fc0 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -1110,6 +1110,94 @@ void RedisTest::testPubSub() _redis.flush(); } +void RedisTest::testSAdd() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myset"); + + Command sadd = Command::sadd("myset", "Hello"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myset", "World"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myset", "World"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testSCard() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myset"); + + Command sadd = Command::sadd("myset", "Hello"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myset", "World"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command scard = Command::scard("myset"); + try + { + Poco::Int64 result = _redis.execute(scard); + assert(result == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testSet() { if (!_connected) @@ -1184,6 +1272,53 @@ void RedisTest::testStrlen() } } +void RedisTest::testSMembers() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myset"); + + Command sadd = Command::sadd("myset", "Hello"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myset", "World"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command smembers = Command::smembers("myset"); + try + { + Array result = _redis.execute(smembers); + + assert(result.size() == 2); + assert(result.get(0).value().compare("World") == 0); + assert(result.get(1).value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testRename() { if (!_connected) @@ -1537,7 +1672,10 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testPipeliningWithSendCommands); CppUnit_addTest(pSuite, RedisTest, testPipeliningWithWriteCommand); CppUnit_addTest(pSuite, RedisTest, testPubSub); + CppUnit_addTest(pSuite, RedisTest, testSAdd); + CppUnit_addTest(pSuite, RedisTest, testSCard); CppUnit_addTest(pSuite, RedisTest, testSet); + CppUnit_addTest(pSuite, RedisTest, testSMembers); CppUnit_addTest(pSuite, RedisTest, testStrlen); CppUnit_addTest(pSuite, RedisTest, testRename); CppUnit_addTest(pSuite, RedisTest, testRenameNx); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index ab387865b..16889f967 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -51,7 +51,10 @@ public: void testPipeliningWithSendCommands(); void testPipeliningWithWriteCommand(); void testPubSub(); + void testSAdd(); + void testSCard(); void testSet(); + void testSMembers(); void testStrlen(); void testRename(); void testRenameNx(); From 7a72e3d695f99ce7480a15fb51aff6d2c609433b Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 14 Nov 2015 22:02:36 +0100 Subject: [PATCH 064/121] Add more set methods --- Redis/include/Poco/Redis/Command.h | 46 +++- Redis/src/Command.cpp | 150 +++++++++++- Redis/testsuite/src/RedisTest.cpp | 366 ++++++++++++++++++++++++++++- Redis/testsuite/src/RedisTest.h | 6 + 4 files changed, 551 insertions(+), 17 deletions(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 181a68b5d..9edad4a30 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -109,17 +109,26 @@ public: static Command mset(const std::map& keyvalues, bool create = true); /// Returns a MSET or MSETNX (when create is false) command - static Command sadd(const std::string& key, const std::string& value); + static Command sadd(const std::string& set, const std::string& value); /// Returns a SADD command - static Command sadd(const std::string& key, const std::vector& values); + static Command sadd(const std::string& set, const std::vector& values); /// Returns a SADD command - static Command scard(const std::string& key); + static Command scard(const std::string& set); /// Returns a SCARD command - static Command smembers(const std::string& key); - /// Returns a SMEMBERS command + static Command sdiff(const std::string& set1, const std::string& set2); + /// Returns a SDIFF command + + static Command sdiff(const std::string& set, const std::vector& sets); + /// Returns a SDIFF command + + static Command sdiffstore(const std::string& set, const std::string& set1, const std::string& set2); + /// Returns a SDIFFSTORE command + + static Command sdiffstore(const std::string& set, const std::vector& sets); + /// Returns a SDIFFSTORE command static Command set(const std::string& key, const std::string& value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); /// Returns a SET command to set the key with a value @@ -127,6 +136,33 @@ public: static Command set(const std::string& key, Int64 value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); /// Returns a SET command to set the key with a value + static Command sinter(const std::string& set1, const std::string& set2); + /// Returns a SINTER command + + static Command sinter(const std::string& set, const std::vector& sets); + /// Returns a SINTER command + + static Command sinterstore(const std::string& set, const std::string& set1, const std::string& set2); + /// Returns a SINTERSTORE command + + static Command sinterstore(const std::string& set, const std::vector& sets); + /// Returns a SINTERSTORE command + + static Command smembers(const std::string& set); + /// Returns a SMEMBERS command + + static Command sunion(const std::string& set1, const std::string& set2); + /// Returns a SUNION command + + static Command sunion(const std::string& set, const std::vector& sets); + /// Returns a SUNION command + + static Command sunionstore(const std::string& set, const std::string& set1, const std::string& set2); + /// Returns a SUNIONSTORE command + + static Command sunionstore(const std::string& set, const std::vector& sets); + /// Returns a SUNIONSTORE command + static Command rename(const std::string& key, const std::string& newName, bool overwrite = true); /// Returns a RENAME or RENAMENX when overwrite is false diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index aa0fe2058..f3bc602e8 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -245,20 +245,20 @@ Command Command::mset(const std::map& keyvalues, bool return cmd; } -Command Command::sadd(const std::string& key, const std::string& value) +Command Command::sadd(const std::string& set, const std::string& value) { Command cmd("SADD"); - cmd << key << value; + cmd << set << value; return cmd; } -Command Command::sadd(const std::string& key, const std::vector& values) +Command Command::sadd(const std::string& set, const std::vector& values) { Command cmd("SADD"); - cmd << key; + cmd << set; for(std::vector::const_iterator it = values.begin(); it != values.end(); ++it) { cmd << *it; @@ -267,20 +267,55 @@ Command Command::sadd(const std::string& key, const std::vector& va return cmd; } -Command Command::scard(const std::string& key) +Command Command::scard(const std::string& set) { Command cmd("SCARD"); - cmd << key; + cmd << set; return cmd; } -Command Command::smembers(const std::string& key) +Command Command::sdiff(const std::string& set1, const std::string& set2) { - Command cmd("SMEMBERS"); + Command cmd("SDIFF"); - cmd << key; + cmd << set1 << set2; + + return cmd; +} + +Command Command::sdiff(const std::string& set, const std::vector& sets) +{ + Command cmd("SDIFF"); + + cmd << set; + for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + { + cmd << *it; + } + + return cmd; +} + +Command Command::sdiffstore(const std::string& set, const std::string& set1, const std::string& set2) +{ + Command cmd("SDIFFSTORE"); + + cmd << set << set1 << set2; + + return cmd; +} + +Command Command::sdiffstore(const std::string& set, const std::vector& sets) +{ + Command cmd("SDIFFSTORE"); + + cmd << set; + for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + { + cmd << *it; + } return cmd; } @@ -302,6 +337,103 @@ Command Command::set(const std::string& key, Int64 value, bool overwrite, const return set(key, NumberFormatter::format(value), overwrite, expireTime, create); } +Command Command::sinter(const std::string& set1, const std::string& set2) +{ + Command cmd("SINTER"); + + cmd << set1 << set2; + + return cmd; +} + +Command Command::sinter(const std::string& set, const std::vector& sets) +{ + Command cmd("SINTER"); + + cmd << set; + for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + { + cmd << *it; + } + + return cmd; +} + +Command Command::sinterstore(const std::string& set, const std::string& set1, const std::string& set2) +{ + Command cmd("SINTERSTORE"); + + cmd << set << set1 << set2; + + return cmd; +} + +Command Command::sinterstore(const std::string& set, const std::vector& sets) +{ + Command cmd("SINTERSTORE"); + + cmd << set; + for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + { + cmd << *it; + } + + return cmd; +} + +Command Command::smembers(const std::string& set) +{ + Command cmd("SMEMBERS"); + + cmd << set; + + return cmd; +} + +Command Command::sunion(const std::string& set1, const std::string& set2) +{ + Command cmd("SUNION"); + + cmd << set1 << set2; + + return cmd; +} + +Command Command::sunion(const std::string& set, const std::vector& sets) +{ + Command cmd("SUNION"); + + cmd << set; + for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + { + cmd << *it; + } + + return cmd; +} + +Command Command::sunionstore(const std::string& set, const std::string& set1, const std::string& set2) +{ + Command cmd("SUNIONSTORE"); + + cmd << set << set1 << set2; + + return cmd; +} + +Command Command::sunionstore(const std::string& set, const std::vector& sets) +{ + Command cmd("SUNIONSTORE"); + + cmd << set; + for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + { + cmd << *it; + } + + return cmd; +} + Command Command::rename(const std::string& key, const std::string& newName, bool overwrite) { Command cmd(overwrite ? "RENAME" : "RENAMENX"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 0fdcf9fc0..a1502dbd9 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -1198,6 +1198,124 @@ void RedisTest::testSCard() } } +void RedisTest::testSDiff() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("key1"); + delKey("key2"); + + std::vector values1; + values1.push_back("a"); + values1.push_back("b"); + values1.push_back("c"); + Command sadd = Command::sadd("key1", values1); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + std::vector values2; + values2.push_back("c"); + values2.push_back("d"); + values2.push_back("e"); + sadd = Command::sadd("key2", values2); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command sdiff = Command::sdiff("key1", "key2"); + try + { + Array result = _redis.execute(sdiff); + assert(result.size() == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testSDiffStore() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("key"); + delKey("key1"); + delKey("key2"); + + std::vector values1; + values1.push_back("a"); + values1.push_back("b"); + values1.push_back("c"); + Command sadd = Command::sadd("key1", values1); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + std::vector values2; + values2.push_back("c"); + values2.push_back("d"); + values2.push_back("e"); + sadd = Command::sadd("key2", values2); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command sdiffstore = Command::sdiffstore("key", "key1", "key2"); + try + { + Poco::Int64 result = _redis.execute(sdiffstore); + assert(result == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command smembers = Command::smembers("key"); + try + { + Array result = _redis.execute(smembers); + assert(result.size() == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testSet() { if (!_connected) @@ -1234,6 +1352,127 @@ void RedisTest::testSet() } } + +void RedisTest::testSInter() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("key1"); + delKey("key2"); + + std::vector values1; + values1.push_back("a"); + values1.push_back("b"); + values1.push_back("c"); + Command sadd = Command::sadd("key1", values1); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + std::vector values2; + values2.push_back("c"); + values2.push_back("d"); + values2.push_back("e"); + sadd = Command::sadd("key2", values2); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command sinter = Command::sinter("key1", "key2"); + try + { + Array result = _redis.execute(sinter); + assert(result.size() == 1); + assert(result.get(0).value().compare("c") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testSInterStore() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("key"); + delKey("key1"); + delKey("key2"); + + std::vector values1; + values1.push_back("a"); + values1.push_back("b"); + values1.push_back("c"); + Command sadd = Command::sadd("key1", values1); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + std::vector values2; + values2.push_back("c"); + values2.push_back("d"); + values2.push_back("e"); + sadd = Command::sadd("key2", values2); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command sinterstore = Command::sinterstore("key", "key1", "key2"); + try + { + Poco::Int64 result = _redis.execute(sinterstore); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command smembers = Command::smembers("key"); + try + { + Array result = _redis.execute(smembers); + assert(result.size() == 1); + assert(result.get(0).value().compare("c") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testStrlen() { if (!_connected) @@ -1308,10 +1547,125 @@ void RedisTest::testSMembers() try { Array result = _redis.execute(smembers); - assert(result.size() == 2); - assert(result.get(0).value().compare("World") == 0); - assert(result.get(1).value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testSUnion() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("key1"); + delKey("key2"); + + std::vector values1; + values1.push_back("a"); + values1.push_back("b"); + values1.push_back("c"); + Command sadd = Command::sadd("key1", values1); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + std::vector values2; + values2.push_back("c"); + values2.push_back("d"); + values2.push_back("e"); + sadd = Command::sadd("key2", values2); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command sunion = Command::sunion("key1", "key2"); + try + { + Array result = _redis.execute(sunion); + assert(result.size() == 5); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testSUnionStore() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("key"); + delKey("key1"); + delKey("key2"); + + std::vector values1; + values1.push_back("a"); + values1.push_back("b"); + values1.push_back("c"); + Command sadd = Command::sadd("key1", values1); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + std::vector values2; + values2.push_back("c"); + values2.push_back("d"); + values2.push_back("e"); + sadd = Command::sadd("key2", values2); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command sunionstore = Command::sunionstore("key", "key1", "key2"); + try + { + Poco::Int64 result = _redis.execute(sunionstore); + assert(result == 5); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command smembers = Command::smembers("key"); + try + { + Array result = _redis.execute(smembers); + assert(result.size() == 5); } catch(RedisException &e) { @@ -1674,9 +2028,15 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testPubSub); CppUnit_addTest(pSuite, RedisTest, testSAdd); CppUnit_addTest(pSuite, RedisTest, testSCard); + CppUnit_addTest(pSuite, RedisTest, testSDiff); + CppUnit_addTest(pSuite, RedisTest, testSDiffStore); CppUnit_addTest(pSuite, RedisTest, testSet); + CppUnit_addTest(pSuite, RedisTest, testSInter); + CppUnit_addTest(pSuite, RedisTest, testSInterStore); CppUnit_addTest(pSuite, RedisTest, testSMembers); CppUnit_addTest(pSuite, RedisTest, testStrlen); + CppUnit_addTest(pSuite, RedisTest, testSUnion); + CppUnit_addTest(pSuite, RedisTest, testSUnionStore); CppUnit_addTest(pSuite, RedisTest, testRename); CppUnit_addTest(pSuite, RedisTest, testRenameNx); CppUnit_addTest(pSuite, RedisTest, testRPop); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 16889f967..7ee732456 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -53,8 +53,14 @@ public: void testPubSub(); void testSAdd(); void testSCard(); + void testSDiff(); + void testSDiffStore(); void testSet(); + void testSInter(); + void testSInterStore(); void testSMembers(); + void testSUnion(); + void testSUnionStore(); void testStrlen(); void testRename(); void testRenameNx(); From 6dc3ac79c19ee5af3364bd95c43cf591b4db9693 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sun, 15 Nov 2015 21:16:47 +0100 Subject: [PATCH 065/121] Add sismember --- Redis/include/Poco/Redis/Command.h | 3 ++ Redis/src/Command.cpp | 9 ++++ Redis/testsuite/src/RedisTest.cpp | 70 +++++++++++++++++++++++++----- Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 9edad4a30..54bab203a 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -148,6 +148,9 @@ public: static Command sinterstore(const std::string& set, const std::vector& sets); /// Returns a SINTERSTORE command + static Command sismember(const std::string& set, const std::string& member); + /// Returns a SISMEMBER command + static Command smembers(const std::string& set); /// Returns a SMEMBERS command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index f3bc602e8..e18d9213d 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -381,6 +381,15 @@ Command Command::sinterstore(const std::string& set, const std::vector(command); - assert(result.compare("OK") == 0); + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); } catch(RedisException &e) { fail(e.message()); } - command.clear(); - command.add("STRLEN") - .add("mykey"); - + Command sismember = Command::sismember("myset", "one"); try { - Poco::Int64 result = _redis.execute(command); + Poco::Int64 result = _redis.execute(sismember); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } - assert(result == 11); + sismember = Command::sismember("myset", "two"); + try + { + Poco::Int64 result = _redis.execute(sismember); + assert(result == 0); } catch(RedisException &e) { @@ -1608,6 +1615,44 @@ void RedisTest::testSUnion() } } +void RedisTest::testStrlen() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("SET").add("mykey").add("Hello World"); + + // A set responds with a simple OK string + try + { + std::string result = _redis.execute(command); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.clear(); + command.add("STRLEN") + .add("mykey"); + + try + { + Poco::Int64 result = _redis.execute(command); + + assert(result == 11); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testSUnionStore() { if (!_connected) @@ -2033,6 +2078,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testSet); CppUnit_addTest(pSuite, RedisTest, testSInter); CppUnit_addTest(pSuite, RedisTest, testSInterStore); + CppUnit_addTest(pSuite, RedisTest, testSIsmember); CppUnit_addTest(pSuite, RedisTest, testSMembers); CppUnit_addTest(pSuite, RedisTest, testStrlen); CppUnit_addTest(pSuite, RedisTest, testSUnion); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 7ee732456..80af1d7ab 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -58,6 +58,7 @@ public: void testSet(); void testSInter(); void testSInterStore(); + void testSIsmember(); void testSMembers(); void testSUnion(); void testSUnionStore(); From 7c45bf49933c88b1e009e8cf24daf05c320c89be Mon Sep 17 00:00:00 2001 From: fbraem Date: Sun, 15 Nov 2015 23:20:32 +0100 Subject: [PATCH 066/121] Add smove --- Redis/include/Poco/Redis/Command.h | 3 ++ Redis/src/Command.cpp | 9 ++++ Redis/testsuite/src/RedisTest.cpp | 80 +++++++++++++++++++++++++++++- Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 54bab203a..b68c0792e 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -154,6 +154,9 @@ public: static Command smembers(const std::string& set); /// Returns a SMEMBERS command + static Command smove(const std::string& source, const std::string& destination, const std::string& member); + /// Returns a SMOVE command + static Command sunion(const std::string& set1, const std::string& set2); /// Returns a SUNION command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index e18d9213d..4f83c767f 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -399,6 +399,15 @@ Command Command::smembers(const std::string& set) return cmd; } +Command Command::smove(const std::string& source, const std::string& destination, const std::string& member) +{ + Command cmd("SMOVE"); + + cmd << source << destination << member; + + return cmd; +} + Command Command::sunion(const std::string& set1, const std::string& set2) { Command cmd("SUNION"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index b36a3d1cb..38ca7fdbc 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -1473,7 +1473,6 @@ void RedisTest::testSInterStore() } } - void RedisTest::testSIsmember() { if (!_connected) @@ -1562,6 +1561,84 @@ void RedisTest::testSMembers() } } +void RedisTest::testSMove() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myset"); + + Command sadd = Command::sadd("myset", "one"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myset", "two"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myotherset", "three"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command smove = Command::smove("myset", "myotherset", "two"); + try + { + Poco::Int64 result = _redis.execute(smove); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command smembers = Command::smembers("myset"); + try + { + Array result = _redis.execute(smembers); + assert(result.size() == 1); + assert(result.get(0).value().compare("one") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + smembers = Command::smembers("myotherset"); + try + { + Array result = _redis.execute(smembers); + assert(result.size() == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testSUnion() { if (!_connected) @@ -2080,6 +2157,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testSInterStore); CppUnit_addTest(pSuite, RedisTest, testSIsmember); CppUnit_addTest(pSuite, RedisTest, testSMembers); + CppUnit_addTest(pSuite, RedisTest, testSMove); CppUnit_addTest(pSuite, RedisTest, testStrlen); CppUnit_addTest(pSuite, RedisTest, testSUnion); CppUnit_addTest(pSuite, RedisTest, testSUnionStore); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 80af1d7ab..801502161 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -60,6 +60,7 @@ public: void testSInterStore(); void testSIsmember(); void testSMembers(); + void testSMove(); void testSUnion(); void testSUnionStore(); void testStrlen(); From 7732d756ad2c828f46659e38e241b9ee70bd3563 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 16 Nov 2015 21:58:12 +0100 Subject: [PATCH 067/121] add srem --- Redis/include/Poco/Redis/Command.h | 6 ++ Redis/src/Command.cpp | 22 +++++ Redis/testsuite/src/RedisTest.cpp | 152 +++++++++++++++++++++-------- Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 143 insertions(+), 38 deletions(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index b68c0792e..96230cc0b 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -157,6 +157,12 @@ public: static Command smove(const std::string& source, const std::string& destination, const std::string& member); /// Returns a SMOVE command + static Command srem(const std::string& set, const std::string& member); + /// Returns a SREM command + + static Command srem(const std::string& set, const std::vector& member); + /// Returns a SREM command + static Command sunion(const std::string& set1, const std::string& set2); /// Returns a SUNION command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 4f83c767f..a9a2444de 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -408,6 +408,28 @@ Command Command::smove(const std::string& source, const std::string& destination return cmd; } +Command Command::srem(const std::string& set1, const std::string& member) +{ + Command cmd("SREM"); + + cmd << set1 << member; + + return cmd; +} + +Command Command::srem(const std::string& set, const std::vector& members) +{ + Command cmd("SREM"); + + cmd << set; + for(std::vector::const_iterator it = members.begin(); it != members.end(); ++it) + { + cmd << *it; + } + + return cmd; +} + Command Command::sunion(const std::string& set1, const std::string& set2) { Command cmd("SUNION"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 38ca7fdbc..e955dec1d 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -1639,6 +1639,119 @@ void RedisTest::testSMove() } } +void RedisTest::testStrlen() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Array command; + command.add("SET").add("mykey").add("Hello World"); + + // A set responds with a simple OK string + try + { + std::string result = _redis.execute(command); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + command.clear(); + command.add("STRLEN") + .add("mykey"); + + try + { + Poco::Int64 result = _redis.execute(command); + + assert(result == 11); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testSRem() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myset"); + + Command sadd = Command::sadd("myset", "one"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + sadd = Command::sadd("myset", "two"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + sadd = Command::sadd("myset", "three"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command srem = Command::srem("myset", "one"); + try + { + Poco::Int64 result = _redis.execute(srem); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + srem = Command::srem("myset", "four"); + try + { + Poco::Int64 result = _redis.execute(srem); + assert(result == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command smembers = Command::smembers("myset"); + try + { + Array result = _redis.execute(smembers); + assert(result.size() == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testSUnion() { if (!_connected) @@ -1692,44 +1805,6 @@ void RedisTest::testSUnion() } } -void RedisTest::testStrlen() -{ - if (!_connected) - { - std::cout << "Not connected, test skipped." << std::endl; - return; - } - - Array command; - command.add("SET").add("mykey").add("Hello World"); - - // A set responds with a simple OK string - try - { - std::string result = _redis.execute(command); - assert(result.compare("OK") == 0); - } - catch(RedisException &e) - { - fail(e.message()); - } - - command.clear(); - command.add("STRLEN") - .add("mykey"); - - try - { - Poco::Int64 result = _redis.execute(command); - - assert(result == 11); - } - catch(RedisException &e) - { - fail(e.message()); - } -} - void RedisTest::testSUnionStore() { if (!_connected) @@ -2158,6 +2233,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testSIsmember); CppUnit_addTest(pSuite, RedisTest, testSMembers); CppUnit_addTest(pSuite, RedisTest, testSMove); + CppUnit_addTest(pSuite, RedisTest, testSRem); CppUnit_addTest(pSuite, RedisTest, testStrlen); CppUnit_addTest(pSuite, RedisTest, testSUnion); CppUnit_addTest(pSuite, RedisTest, testSUnionStore); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 801502161..9703a216e 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -61,6 +61,7 @@ public: void testSIsmember(); void testSMembers(); void testSMove(); + void testSRem(); void testSUnion(); void testSUnionStore(); void testStrlen(); From 7857e156c1ea5ef85451907ff0bda7d8f5f7f328 Mon Sep 17 00:00:00 2001 From: fbraem Date: Mon, 16 Nov 2015 22:51:13 +0100 Subject: [PATCH 068/121] Add spop and srandmember --- Redis/include/Poco/Redis/Command.h | 6 ++ Redis/src/Command.cpp | 20 ++++ Redis/testsuite/src/RedisTest.cpp | 163 +++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 2 + 4 files changed, 191 insertions(+) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 96230cc0b..a8593adf1 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -157,6 +157,12 @@ public: static Command smove(const std::string& source, const std::string& destination, const std::string& member); /// Returns a SMOVE command + static Command spop(const std::string& set, Int64 count = 0); + /// Returns a SPOP command + + static Command srandmember(const std::string& set, Int64 count = 0); + /// Returns a SRANDMEMBER command + static Command srem(const std::string& set, const std::string& member); /// Returns a SREM command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index a9a2444de..109c2302d 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -408,6 +408,26 @@ Command Command::smove(const std::string& source, const std::string& destination return cmd; } +Command Command::spop(const std::string& set, Int64 count) +{ + Command cmd("SPOP"); + + cmd << set; + if( count != 0 ) cmd << NumberFormatter::format(count); + + return cmd; +} + +Command Command::srandmember(const std::string& set, Int64 count) +{ + Command cmd("SRANDMEMBER"); + + cmd << set; + if( count != 0 ) cmd << NumberFormatter::format(count); + + return cmd; +} + Command Command::srem(const std::string& set1, const std::string& member) { Command cmd("SREM"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index e955dec1d..e9e83d61f 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -1639,6 +1639,167 @@ void RedisTest::testSMove() } } +void RedisTest::testSPop() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myset"); + + Command sadd = Command::sadd("myset", "one"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myset", "two"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myset", "three"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command spop = Command::spop("myset"); + try + { + BulkString result = _redis.execute(spop); + assert(!result.isNull()); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command smembers = Command::smembers("myset"); + try + { + Array result = _redis.execute(smembers); + assert(result.size() == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myset", "four"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + sadd = Command::sadd("myset", "five"); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } +// Redis server 3.0.5 doesn't support this yet .. +/* + spop = Command::spop("myset", 3); + try + { + Array result = _redis.execute(spop); + assert(result.size() == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } +*/ +} + +void RedisTest::testSRandMember() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myset"); + + std::vector members; + members.push_back("one"); + members.push_back("two"); + members.push_back("three"); + + Command sadd = Command::sadd("myset", members); + try + { + Poco::Int64 result = _redis.execute(sadd); + assert(result == 3); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command srandmember = Command::srandmember("myset"); + try + { + BulkString result = _redis.execute(srandmember); + assert(!result.isNull()); + } + catch(RedisException &e) + { + fail(e.message()); + } + + srandmember = Command::srandmember("myset", 2); + try + { + Array result = _redis.execute(srandmember); + assert(result.size() == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + + srandmember = Command::srandmember("myset", -5); + try + { + Array result = _redis.execute(srandmember); + assert(result.size() == 5); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testStrlen() { if (!_connected) @@ -2233,6 +2394,8 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testSIsmember); CppUnit_addTest(pSuite, RedisTest, testSMembers); CppUnit_addTest(pSuite, RedisTest, testSMove); + CppUnit_addTest(pSuite, RedisTest, testSPop); + CppUnit_addTest(pSuite, RedisTest, testSRandMember); CppUnit_addTest(pSuite, RedisTest, testSRem); CppUnit_addTest(pSuite, RedisTest, testStrlen); CppUnit_addTest(pSuite, RedisTest, testSUnion); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 9703a216e..1b22b3c9c 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -61,6 +61,8 @@ public: void testSIsmember(); void testSMembers(); void testSMove(); + void testSPop(); + void testSRandMember(); void testSRem(); void testSUnion(); void testSUnionStore(); From 780ae40990c8f71729143de64c821f8718386892 Mon Sep 17 00:00:00 2001 From: zosrothko Date: Tue, 17 Nov 2015 18:06:59 +0100 Subject: [PATCH 069/121] Workaroud for travis old wget --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 906196bfe..4954e8a7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,11 @@ cache: before_install: # we need a recent version of CMake - - sudo add-apt-repository -y ppa:andykimpe/cmake3 + # - sudo add-apt-repository -y ppa:andykimpe/cmake3 + # linux prereqisite packages + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then wget --no-check-certificate https://www.cmake.org/files/v3.2/cmake-3.2.3-Linux-x86_64.tar.gz; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then tar -xzvf cmake-3.2.3-Linux-x86_64.tar.gz; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export PATH=$PWD/cmake-3.2.3-Linux-x86_64/bin:$PATH; fi - sudo apt-get update -qq - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev g++-arm-linux-gnueabi g++-arm-linux-gnueabihf clang-3.5 sloccount cppcheck @@ -42,14 +46,12 @@ matrix: - env: TEST_NAME="gcc (CMake)" compiler: gcc script: - - sudo apt-get install -qq -y cmake3 # disable tests, gcc-4.6 gets an internal compiler error - mkdir cmake-build && cd cmake-build && cmake -DENABLE_TESTS=OFF .. && make -j2 && cd .. - env: TEST_NAME="gcc-4.8 (CMake)" compiler: gcc script: - - sudo apt-get install -qq -y cmake3 - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - sudo apt-get update -qq - sudo apt-get install -qq -y g++-4.8 @@ -60,19 +62,16 @@ matrix: - env: TEST_NAME="clang (CMake)" compiler: clang script: - - sudo apt-get install -qq -y cmake3 - mkdir cmake-build && cd cmake-build && cmake -DENABLE_TESTS=ON .. && make -j2 && cd .. - env: TEST_NAME="arm-linux-gnueabi-g++ (CMake)" script: - - sudo apt-get install -qq -y cmake3 - export CC="arm-linux-gnueabi-gcc" - export CXX="arm-linux-gnueabi-g++" - mkdir cmake-build && cd cmake-build && cmake -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_TESTS=ON .. && make -j2 && cd .. - env: TEST_NAME="arm-linux-gnueabihf-g++ (CMake)" script: - - sudo apt-get install -qq -y cmake3 - export CC="arm-linux-gnueabihf-gcc" - export CXX="arm-linux-gnueabihf-g++" - mkdir cmake-build && cd cmake-build && cmake -DENABLE_NETSSL=OFF -DENABLE_CRYPTO=OFF -DENABLE_TESTS=ON .. && make -j2 && cd .. From 0598428563426c5de283bc6a7ad8dbb791656728 Mon Sep 17 00:00:00 2001 From: zosrothko Date: Tue, 17 Nov 2015 18:33:21 +0100 Subject: [PATCH 070/121] Add an Travis test for unbundled --- .travis.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4954e8a7a..42dca81db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,9 @@ before_install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then tar -xzvf cmake-3.2.3-Linux-x86_64.tar.gz; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export PATH=$PWD/cmake-3.2.3-Linux-x86_64/bin:$PATH; fi - sudo apt-get update -qq - - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev g++-arm-linux-gnueabi g++-arm-linux-gnueabihf clang-3.5 sloccount cppcheck + - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev pcre-dev openssl-dev libsqlite3-dev libpcre3-dev libexpat1-dev + - sudo apt-get install -qq -y g++-arm-linux-gnueabi g++-arm-linux-gnueabihf clang-3.5 + - sudo apt-get install -qq -y sloccount cppcheck services: - mongodb @@ -27,12 +29,18 @@ before_script: matrix: include: - - env: TEST_NAME="gcc (make)" + - env: TEST_NAME="gcc (make) bundled" compiler: gcc script: - ./configure --everything && make -s -j2 - ./travis/runtests.sh + - env: TEST_NAME="gcc (make) unbundled" + compiler: gcc + script: + - ./configure --everything --unbundled && make -s -j2 + - ./travis/runtests.sh + - env: TEST_NAME="clang (make)" compiler: clang script: From abcbb43abbde50aa19ed1605f87a4c6fef4ae3e3 Mon Sep 17 00:00:00 2001 From: zosrothko Date: Tue, 17 Nov 2015 18:39:17 +0100 Subject: [PATCH 071/121] use proper Ubuntu development libs --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 42dca81db..80e14ca00 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then tar -xzvf cmake-3.2.3-Linux-x86_64.tar.gz; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export PATH=$PWD/cmake-3.2.3-Linux-x86_64/bin:$PATH; fi - sudo apt-get update -qq - - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev pcre-dev openssl-dev libsqlite3-dev libpcre3-dev libexpat1-dev + - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev libpcre3-dev libssl-dev libsqlite3-dev libexpat1-dev - sudo apt-get install -qq -y g++-arm-linux-gnueabi g++-arm-linux-gnueabihf clang-3.5 - sudo apt-get install -qq -y sloccount cppcheck From 94bb16fdeea5cd804c586b282cdbdd1c45360718 Mon Sep 17 00:00:00 2001 From: zosrothko Date: Tue, 17 Nov 2015 18:45:44 +0100 Subject: [PATCH 072/121] Include for an unbundled build. --- Foundation/include/Poco/RegularExpression.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Foundation/include/Poco/RegularExpression.h b/Foundation/include/Poco/RegularExpression.h index 9181d29df..e2b3446ce 100644 --- a/Foundation/include/Poco/RegularExpression.h +++ b/Foundation/include/Poco/RegularExpression.h @@ -28,17 +28,19 @@ #include +#ifdef POCO_UNBUNDLED +#include +#else // // Copy these definitions from pcre.h // to avoid pulling in the entire header file // extern "C" { - struct real_pcre8_or_16; /* declaration; the definition is private */ typedef struct real_pcre8_or_16 pcre; struct pcre_extra; } - +#endif namespace Poco { From ca6748f430b9cef28f16df63948619409b32494d Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Tue, 17 Nov 2015 19:36:10 +0100 Subject: [PATCH 073/121] Remove $(OSARCH_POSTFIX). Signed-off-by: FrancisANDRE --- build/rules/dylib | 12 ++++++------ build/rules/exec | 12 ++++++------ build/rules/global | 8 ++++---- build/rules/lib | 16 ++++++++-------- build/rules/sample | 8 ++++---- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/build/rules/dylib b/build/rules/dylib index b4fa9b951..dd2025291 100644 --- a/build/rules/dylib +++ b/build/rules/dylib @@ -22,13 +22,13 @@ DYLIB = $(SHLIB) DYLIBFLAGS = $(SHLIBFLAGS) endif -DYLIB_DEBUG = $(BINPATH)/$(target)d$(OSARCH_POSTFIX)$(SHL_EXT) -DYLIB_RELEASE = $(BINPATH)/$(target)$(OSARCH_POSTFIX)$(SHL_EXT) -DYLIB_S_DEBUG = $(BINPATH)/static/$(target)d$(OSARCH_POSTFIX)$(SHL_EXT) -DYLIB_S_RELEASE = $(BINPATH)/static/$(target)$(OSARCH_POSTFIX)$(SHL_EXT) +DYLIB_DEBUG = $(BINPATH)/$(target)d$(SHL_EXT) +DYLIB_RELEASE = $(BINPATH)/$(target)$(SHL_EXT) +DYLIB_S_DEBUG = $(BINPATH)/static/$(target)d$(SHL_EXT) +DYLIB_S_RELEASE = $(BINPATH)/static/$(target)$(SHL_EXT) -TARGET_LIBS_DEBUG = $(foreach l,$(target_libs),-l$(l)d$(OSARCH_POSTFIX)) -TARGET_LIBS_RELEASE = $(foreach l,$(target_libs),-l$(l)$(OSARCH_POSTFIX)) +TARGET_LIBS_DEBUG = $(foreach l,$(target_libs),-l$(l)d) +TARGET_LIBS_RELEASE = $(foreach l,$(target_libs),-l$(l)) # # Include the compile rules diff --git a/build/rules/exec b/build/rules/exec index d65d09b6d..73753a29c 100644 --- a/build/rules/exec +++ b/build/rules/exec @@ -9,13 +9,13 @@ # # Target names # -EXEC_RELEASE_STATIC = $(BINPATH)/static/$(target)$(OSARCH_POSTFIX)$(BINEXT) -EXEC_DEBUG_STATIC = $(BINPATH)/static/$(target)d$(OSARCH_POSTFIX)$(BINEXT) -EXEC_RELEASE_SHARED = $(BINPATH)/$(target)$(OSARCH_POSTFIX)$(BINEXT) -EXEC_DEBUG_SHARED = $(BINPATH)/$(target)d$(OSARCH_POSTFIX)$(BINEXT) +EXEC_RELEASE_STATIC = $(BINPATH)/static/$(target)$(BINEXT) +EXEC_DEBUG_STATIC = $(BINPATH)/static/$(target)d$(BINEXT) +EXEC_RELEASE_SHARED = $(BINPATH)/$(target)$(BINEXT) +EXEC_DEBUG_SHARED = $(BINPATH)/$(target)d$(BINEXT) -TARGET_LIBS_DEBUG = $(foreach l,$(target_libs),-l$(l)d$(OSARCH_POSTFIX)) -TARGET_LIBS_RELEASE = $(foreach l,$(target_libs),-l$(l)$(OSARCH_POSTFIX)) +TARGET_LIBS_DEBUG = $(foreach l,$(target_libs),-l$(l)d) +TARGET_LIBS_RELEASE = $(foreach l,$(target_libs),-l$(l)) # # Include the compile rules diff --git a/build/rules/global b/build/rules/global index 0f4e08968..a92bdd865 100644 --- a/build/rules/global +++ b/build/rules/global @@ -263,10 +263,10 @@ endif # # Compose object file path # -OBJPATH_RELEASE_STATIC = $(OBJPATH)/release_static$(OSARCH_POSTFIX) -OBJPATH_DEBUG_STATIC = $(OBJPATH)/debug_static$(OSARCH_POSTFIX) -OBJPATH_RELEASE_SHARED = $(OBJPATH)/release_shared$(OSARCH_POSTFIX) -OBJPATH_DEBUG_SHARED = $(OBJPATH)/debug_shared$(OSARCH_POSTFIX) +OBJPATH_RELEASE_STATIC = $(OBJPATH)/release_static +OBJPATH_DEBUG_STATIC = $(OBJPATH)/debug_static +OBJPATH_RELEASE_SHARED = $(OBJPATH)/release_shared +OBJPATH_DEBUG_SHARED = $(OBJPATH)/debug_shared # # Build Include directory List diff --git a/build/rules/lib b/build/rules/lib index a814d8fb4..14849be8e 100644 --- a/build/rules/lib +++ b/build/rules/lib @@ -15,15 +15,15 @@ else SHL_EXT = $(SHAREDLIBLINKEXT) endif -LIB_RELEASE_STATIC = $(LIBPATH)/$(LIBPREFIX)$(target)$(OSARCH_POSTFIX).a -LIB_DEBUG_STATIC = $(LIBPATH)/$(LIBPREFIX)$(target)d$(OSARCH_POSTFIX).a -LIB_RELEASE_SHARED = $(LIBPATH)/$(LIBPREFIX)$(target)$(OSARCH_POSTFIX)$(SHL_EXT) -LIB_DEBUG_SHARED = $(LIBPATH)/$(LIBPREFIX)$(target)d$(OSARCH_POSTFIX)$(SHL_EXT) -LIB_RELEASE_SHARED_LINK = $(LIBPATH)/$(LIBPREFIX)$(target)$(OSARCH_POSTFIX)$(SHAREDLIBLINKEXT) -LIB_DEBUG_SHARED_LINK = $(LIBPATH)/$(LIBPREFIX)$(target)d$(OSARCH_POSTFIX)$(SHAREDLIBLINKEXT) +LIB_RELEASE_STATIC = $(LIBPATH)/$(LIBPREFIX)$(target).a +LIB_DEBUG_STATIC = $(LIBPATH)/$(LIBPREFIX)$(target)d.a +LIB_RELEASE_SHARED = $(LIBPATH)/$(LIBPREFIX)$(target)$(SHL_EXT) +LIB_DEBUG_SHARED = $(LIBPATH)/$(LIBPREFIX)$(target)d$(SHL_EXT) +LIB_RELEASE_SHARED_LINK = $(LIBPATH)/$(LIBPREFIX)$(target)$(SHAREDLIBLINKEXT) +LIB_DEBUG_SHARED_LINK = $(LIBPATH)/$(LIBPREFIX)$(target)d$(SHAREDLIBLINKEXT) -TARGET_LIBS_DEBUG = $(foreach l,$(target_libs),-l$(l)d$(OSARCH_POSTFIX)) -TARGET_LIBS_RELEASE = $(foreach l,$(target_libs),-l$(l)$(OSARCH_POSTFIX)) +TARGET_LIBS_DEBUG = $(foreach l,$(target_libs),-l$(l)d) +TARGET_LIBS_RELEASE = $(foreach l,$(target_libs),-l$(l)) # # Include the compile rules diff --git a/build/rules/sample b/build/rules/sample index b0724afb0..92ab738b1 100644 --- a/build/rules/sample +++ b/build/rules/sample @@ -78,10 +78,10 @@ LINKFLAGS += $(COMMONFLAGS) $(SYSFLAGS) # # Compose object file path # -OBJPATH_RELEASE_STATIC = $(OBJPATH)/release_static$(OSARCH_POSTFIX) -OBJPATH_DEBUG_STATIC = $(OBJPATH)/debug_static$(OSARCH_POSTFIX) -OBJPATH_RELEASE_SHARED = $(OBJPATH)/release_shared$(OSARCH_POSTFIX) -OBJPATH_DEBUG_SHARED = $(OBJPATH)/debug_shared$(OSARCH_POSTFIX) +OBJPATH_RELEASE_STATIC = $(OBJPATH)/release_static +OBJPATH_DEBUG_STATIC = $(OBJPATH)/debug_static +OBJPATH_RELEASE_SHARED = $(OBJPATH)/release_shared +OBJPATH_DEBUG_SHARED = $(OBJPATH)/debug_shared # # Build Include directory List From f7bb5d319fa7a27e45ab16fbfdfb040faecbcbe5 Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 17 Nov 2015 20:12:41 +0100 Subject: [PATCH 074/121] Add testEval --- Redis/testsuite/src/RedisTest.cpp | 36 +++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 2 files changed, 37 insertions(+) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index e9e83d61f..cebf5cdea 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -339,6 +339,41 @@ void RedisTest::testError() } } +void RedisTest::testEval() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + Command cmd("EVAL"); + cmd << "return {1, 2, {3, 'Hello World!'}}" << Poco::NumberFormatter::format(0); + + try + { + Array value = _redis.execute(cmd); + assert(value.size() == 3); + + Poco::Int64 i = value.get(0); + assert(i == 1); + i = value.get(1); + assert(i == 2); + + Array a = value.get(2); + assert(a.size() == 2); + i = a.get(0); + assert(i == 3); + BulkString s = a.get(1); + assert(s.value().compare("Hello World!") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + +} + void RedisTest::testIncr() { if (!_connected) @@ -2371,6 +2406,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testIncrBy); CppUnit_addTest(pSuite, RedisTest, testEcho); CppUnit_addTest(pSuite, RedisTest, testError); + CppUnit_addTest(pSuite, RedisTest, testEval); CppUnit_addTest(pSuite, RedisTest, testLIndex); CppUnit_addTest(pSuite, RedisTest, testLInsert); CppUnit_addTest(pSuite, RedisTest, testLPop); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 1b22b3c9c..b9413f74c 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -36,6 +36,7 @@ public: void testDecr(); void testEcho(); void testError(); + void testEval(); void testIncr(); void testIncrBy(); void testLIndex(); From 90eb6dcd18e90c824b5b50c884abb45cebe739a3 Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 17 Nov 2015 20:31:23 +0100 Subject: [PATCH 075/121] Add hset/hget --- Redis/include/Poco/Redis/Command.h | 6 +++++ Redis/src/Command.cpp | 18 ++++++++++++++ Redis/testsuite/src/RedisTest.cpp | 38 ++++++++++++++++++++++++++++-- Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index a8593adf1..3fdc78985 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -69,6 +69,12 @@ public: static Command get(const std::string& key); /// Returns an GET command + static Command hget(const std::string& hash, const std::string& field); + /// Returns an HGET command + + static Command hset(const std::string& hash, const std::string& field, const std::string& value, bool create = true); + /// Returns an HSET or HSETNX (when create is false) command + static Command incr(const std::string& key, Int64 by = 0); /// Returns an INCR or INCRBY command. Calls INCR when by is omitted or zero. diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 109c2302d..6806e83c1 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -118,6 +118,24 @@ Command Command::get(const std::string& key) return cmd; } +Command Command::hget(const std::string& hash, const std::string& field) +{ + Command cmd("HGET"); + + cmd << hash << field; + + return cmd; +} + +Command Command::hset(const std::string& hash, const std::string& field, const std::string& value, bool create) +{ + Command cmd(create ? "HSET" : "HSETNX"); + + cmd << hash << field << value; + + return cmd; +} + Command Command::incr(const std::string& key, Int64 by) { Command cmd(by == 0 ? "INCR" : "INCRBY"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index cebf5cdea..b1c72850c 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -374,6 +374,39 @@ void RedisTest::testEval() } +void RedisTest::testHSet() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + Command hset = Command::hset("myhash", "field1", "Hello"); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hget = Command::hget("myhash", "field1"); + try + { + BulkString s = _redis.execute(hget); + assert(s.value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testIncr() { if (!_connected) @@ -2402,11 +2435,12 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testBRpop); CppUnit_addTest(pSuite, RedisTest, testDecr); CppUnit_addTest(pSuite, RedisTest, testDecr); - CppUnit_addTest(pSuite, RedisTest, testIncr); - CppUnit_addTest(pSuite, RedisTest, testIncrBy); CppUnit_addTest(pSuite, RedisTest, testEcho); CppUnit_addTest(pSuite, RedisTest, testError); CppUnit_addTest(pSuite, RedisTest, testEval); + CppUnit_addTest(pSuite, RedisTest, testHSet); + CppUnit_addTest(pSuite, RedisTest, testIncr); + CppUnit_addTest(pSuite, RedisTest, testIncrBy); CppUnit_addTest(pSuite, RedisTest, testLIndex); CppUnit_addTest(pSuite, RedisTest, testLInsert); CppUnit_addTest(pSuite, RedisTest, testLPop); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index b9413f74c..bcf008cdb 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -37,6 +37,7 @@ public: void testEcho(); void testError(); void testEval(); + void testHSet(); void testIncr(); void testIncrBy(); void testLIndex(); From 4756fa353a224564a6454b824d4959d8b91d70e3 Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 17 Nov 2015 21:03:40 +0100 Subject: [PATCH 076/121] Add hdel --- Redis/include/Poco/Redis/Command.h | 6 ++++ Redis/src/Command.cpp | 22 +++++++++++++++ Redis/testsuite/src/RedisTest.cpp | 45 ++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 74 insertions(+) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 3fdc78985..94a6f1ebe 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -69,6 +69,12 @@ public: static Command get(const std::string& key); /// Returns an GET command + static Command hdel(const std::string& hash, const std::string& field); + /// Returns an HDEL command + + static Command hdel(const std::string& hash, const std::vector& fields); + /// Returns an HDEL command + static Command hget(const std::string& hash, const std::string& field); /// Returns an HGET command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 6806e83c1..78a08bb11 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -118,6 +118,28 @@ Command Command::get(const std::string& key) return cmd; } +Command Command::hdel(const std::string& hash, const std::string& field) +{ + Command cmd("HDEL"); + + cmd << hash << field; + + return cmd; +} + +Command Command::hdel(const std::string& hash, const std::vector& fields) +{ + Command cmd("HDEL"); + + cmd << hash; + for(std::vector::const_iterator it = fields.begin(); it != fields.end(); ++it) + { + cmd << *it; + } + + return cmd; +} + Command Command::hget(const std::string& hash, const std::string& field) { Command cmd("HGET"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index b1c72850c..47231f45f 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -374,6 +374,50 @@ void RedisTest::testEval() } +void RedisTest::testHDel() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + Command hset = Command::hset("myhash", "field1", "foo"); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hdel = Command::hdel("myhash", "field1"); + try + { + Poco::Int64 result = _redis.execute(hdel); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hdel = Command::hdel("myhash", "field2"); + try + { + Poco::Int64 result = _redis.execute(hdel); + assert(result == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testHSet() { if (!_connected) @@ -2438,6 +2482,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testEcho); CppUnit_addTest(pSuite, RedisTest, testError); CppUnit_addTest(pSuite, RedisTest, testEval); + CppUnit_addTest(pSuite, RedisTest, testHDel); CppUnit_addTest(pSuite, RedisTest, testHSet); CppUnit_addTest(pSuite, RedisTest, testIncr); CppUnit_addTest(pSuite, RedisTest, testIncrBy); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index bcf008cdb..0c95cc901 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -37,6 +37,7 @@ public: void testEcho(); void testError(); void testEval(); + void testHDel(); void testHSet(); void testIncr(); void testIncrBy(); From 1a8cd2ee7daed68eae4c0cc24b8d0379928afc1f Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Tue, 17 Nov 2015 21:05:21 +0100 Subject: [PATCH 077/121] Remove LINKFLAGS which is used for producing executables. Signed-off-by: FrancisANDRE --- build/rules/lib | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/rules/lib b/build/rules/lib index 14849be8e..74c084d19 100644 --- a/build/rules/lib +++ b/build/rules/lib @@ -61,13 +61,13 @@ $(LIB_RELEASE_STATIC): $(foreach o,$(objects),$(OBJPATH_RELEASE_STATIC)/$(o).o) $(LIB_DEBUG_SHARED): $(foreach o,$(objects),$(OBJPATH_DEBUG_SHARED)/$(o).o) @echo "** Building shared library (debug)" $@ - $(SHLIB) $(LINKFLAGS) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_DEBUG) $(SYSLIBS) + $(SHLIB) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_DEBUG) $(SYSLIBS) $(SHLIBLN) $(LIB_DEBUG_SHARED) $(LIB_DEBUG_SHARED_LINK) $(postbuild) $(LIB_RELEASE_SHARED): $(foreach o,$(objects),$(OBJPATH_RELEASE_SHARED)/$(o).o) @echo "** Building shared library (release)" $@ - $(SHLIB) $(LINKFLAGS) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_RELEASE) $(SYSLIBS) + $(SHLIB) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_RELEASE) $(SYSLIBS) $(SHLIBLN) $(LIB_RELEASE_SHARED) $(LIB_RELEASE_SHARED_LINK) $(STRIPCMD) $(postbuild) From 30bec39a50b6f3ef80cc7f8108a15e68c2afd69d Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Tue, 17 Nov 2015 21:07:36 +0100 Subject: [PATCH 078/121] Add SHLIBFLAGS for linking shared libraries. Signed-off-by: FrancisANDRE --- build/config/Linux | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/config/Linux b/build/config/Linux index dc336e497..5e61675b3 100644 --- a/build/config/Linux +++ b/build/config/Linux @@ -44,6 +44,9 @@ CFLAGS64 = -m64 CXXFLAGS = -Wall -Wno-sign-compare CXXFLAGS32 = -m32 CXXFLAGS64 = -m64 +SHLIBFLAGS = +SHLIBFLAGS32 = -m32 +SHLIBFLAGS64 = -m64 LINKFLAGS = LINKFLAGS32 = -m32 LINKFLAGS64 = -m64 From 383f2bbf064eb8d3edffbd4f4c775bf9d592321c Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Tue, 17 Nov 2015 21:10:02 +0100 Subject: [PATCH 079/121] Add LIBFLAGS when linking a static library. Signed-off-by: FrancisANDRE --- build/rules/lib | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/rules/lib b/build/rules/lib index 74c084d19..8e106b956 100644 --- a/build/rules/lib +++ b/build/rules/lib @@ -49,13 +49,13 @@ shared_release: libdirs $(LIB_RELEASE_SHARED) $(LIB_DEBUG_STATIC): $(foreach o,$(objects),$(OBJPATH_DEBUG_STATIC)/$(o).o) @echo "** Building library (debug)" $@ - $(LIB) $@ $^ + $(LIB) $(LIBFLAGS) $@ $^ $(RANLIB) $@ $(postbuild) $(LIB_RELEASE_STATIC): $(foreach o,$(objects),$(OBJPATH_RELEASE_STATIC)/$(o).o) @echo "** Building library (release)" $@ - $(LIB) $@ $^ + $(LIB) $(LIBFLAGS) $@ $^ $(RANLIB) $@ $(postbuild) From 3ea2bed26d1bd61f218166154e171335c165ad78 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Tue, 17 Nov 2015 21:11:51 +0100 Subject: [PATCH 080/121] Add LIBFLAGS. Signed-off-by: FrancisANDRE --- build/config/Linux | 3 +++ build/rules/global | 2 ++ 2 files changed, 5 insertions(+) diff --git a/build/config/Linux b/build/config/Linux index 5e61675b3..c1e56d699 100644 --- a/build/config/Linux +++ b/build/config/Linux @@ -47,6 +47,9 @@ CXXFLAGS64 = -m64 SHLIBFLAGS = SHLIBFLAGS32 = -m32 SHLIBFLAGS64 = -m64 +LIBFLAGS = +LIBFLAGS32 = -m32 +LIBFLAGS64 = -m64 LINKFLAGS = LINKFLAGS32 = -m32 LINKFLAGS64 = -m64 diff --git a/build/rules/global b/build/rules/global index a92bdd865..ea1ef2cec 100644 --- a/build/rules/global +++ b/build/rules/global @@ -249,12 +249,14 @@ LINKFLAGS += $(COMMONFLAGS) $(SYSFLAGS) ifeq ($(OSARCH_64BITS),1) CFLAGS += $(CFLAGS64) CXXFLAGS += $(CXXFLAGS64) +LIBFLAGS += $(LIBFLAGS64) SHLIBFLAGS += $(SHLIBFLAGS64) DYLIBFLAGS += $(DYLIBFLAGS64) LINKFLAGS += $(LINKFLAGS64) else CFLAGS += $(CFLAGS32) CXXFLAGS += $(CXXFLAGS32) +LIBFLAGS += $(LIBFLAGS32) SHLIBFLAGS += $(SHLIBFLAGS32) DYLIBFLAGS += $(DYLIBFLAGS32) LINKFLAGS += $(LINKFLAGS32) From 629d2f12bab8c68d3f13313113dfb213171ea36f Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Tue, 17 Nov 2015 21:12:23 +0100 Subject: [PATCH 081/121] When we call statement execution for "PRAGMA incremental_vacuum(1024);" it fails with null std iterator exception. It happens because variable "extracts" is empty and construction "*extracts.begin()" is invalid. Signed-off-by: FrancisANDRE --- Data/SQLite/src/SQLiteStatementImpl.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Data/SQLite/src/SQLiteStatementImpl.cpp b/Data/SQLite/src/SQLiteStatementImpl.cpp index 5f0b6c725..9910b20cb 100644 --- a/Data/SQLite/src/SQLiteStatementImpl.cpp +++ b/Data/SQLite/src/SQLiteStatementImpl.cpp @@ -274,6 +274,9 @@ std::size_t SQLiteStatementImpl::next() _stepCalled = false; if (_affectedRowCount == POCO_SQLITE_INV_ROW_CNT) _affectedRowCount = 0; + if (extracts.size()) + + //_affectedRowCount += (*extracts.begin())->numOfRowsHandled(); if (extracts.size()) _affectedRowCount += (*extracts.begin())->numOfRowsHandled(); else @@ -281,6 +284,11 @@ std::size_t SQLiteStatementImpl::next() _stepCalled = true; _nextResponse = SQLITE_DONE; } + else + { + _stepCalled = true; + _nextResponse = SQLITE_DONE; + } } else if (SQLITE_DONE == _nextResponse) From f618d7a5cf190974daf10cbbc79df4c9727abd3a Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 17 Nov 2015 21:18:29 +0100 Subject: [PATCH 082/121] Change commandname in test function to uppercase --- Redis/testsuite/src/RedisTest.cpp | 166 +++++++++++++++--------------- Redis/testsuite/src/RedisTest.h | 82 +++++++-------- 2 files changed, 124 insertions(+), 124 deletions(-) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 47231f45f..7a310cfa9 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -72,7 +72,7 @@ void RedisTest::tearDown() } -void RedisTest::testAppend() +void RedisTest::testAPPEND() { if (!_connected) { @@ -128,7 +128,7 @@ void RedisTest::testAppend() } } -void RedisTest::testBLpop() +void RedisTest::testBLPOP() { if (!_connected) { @@ -184,7 +184,7 @@ void RedisTest::testBLpop() } } -void RedisTest::testBRpop() +void RedisTest::testBRPOP() { if (!_connected) { @@ -240,7 +240,7 @@ void RedisTest::testBRpop() } } -void RedisTest::testDecr() +void RedisTest::testDECR() { if (!_connected) { @@ -293,7 +293,7 @@ void RedisTest::testDecr() } -void RedisTest::testEcho() +void RedisTest::testECHO() { if (!_connected) { @@ -339,7 +339,7 @@ void RedisTest::testError() } } -void RedisTest::testEval() +void RedisTest::testEVAL() { if (!_connected) { @@ -374,7 +374,7 @@ void RedisTest::testEval() } -void RedisTest::testHDel() +void RedisTest::testHDEL() { if (!_connected) { @@ -418,7 +418,7 @@ void RedisTest::testHDel() } } -void RedisTest::testHSet() +void RedisTest::testHSET() { if (!_connected) { @@ -451,7 +451,7 @@ void RedisTest::testHSet() } } -void RedisTest::testIncr() +void RedisTest::testINCR() { if (!_connected) { @@ -483,7 +483,7 @@ void RedisTest::testIncr() } } -void RedisTest::testIncrBy() +void RedisTest::testINCRBY() { if (!_connected) { @@ -515,7 +515,7 @@ void RedisTest::testIncrBy() } } -void RedisTest::testPing() +void RedisTest::testPING() { if (!_connected) { @@ -552,7 +552,7 @@ void RedisTest::testPing() } -void RedisTest::testLPop() +void RedisTest::testLPOP() { if (!_connected) { @@ -613,7 +613,7 @@ void RedisTest::testLPop() } -void RedisTest::testLSet() +void RedisTest::testLSET() { if (!_connected) { @@ -683,7 +683,7 @@ void RedisTest::testLSet() } } -void RedisTest::testLIndex() +void RedisTest::testLINDEX() { if (!_connected) { @@ -721,7 +721,7 @@ void RedisTest::testLIndex() } } -void RedisTest::testLInsert() +void RedisTest::testLINSERT() { if (!_connected) { @@ -768,7 +768,7 @@ void RedisTest::testLInsert() } } -void RedisTest::testLRem() +void RedisTest::testLREM() { if (!_connected) { @@ -829,7 +829,7 @@ void RedisTest::testLRem() } } -void RedisTest::testLTrim() +void RedisTest::testLTRIM() { if (!_connected) { @@ -890,7 +890,7 @@ void RedisTest::testLTrim() } -void RedisTest::testMSet() +void RedisTest::testMSET() { if (!_connected) { @@ -941,7 +941,7 @@ void RedisTest::testMSet() } } -void RedisTest::testMSetWithMap() +void RedisTest::testMSETWithMap() { if (!_connected) { @@ -996,7 +996,7 @@ void RedisTest::testMSetWithMap() } } -void RedisTest::testMulti() +void RedisTest::testMULTI() { if (!_connected) { @@ -1222,7 +1222,7 @@ void RedisTest::testPubSub() _redis.flush(); } -void RedisTest::testSAdd() +void RedisTest::testSADD() { if (!_connected) { @@ -1266,7 +1266,7 @@ void RedisTest::testSAdd() } } -void RedisTest::testSCard() +void RedisTest::testSCARD() { if (!_connected) { @@ -1310,7 +1310,7 @@ void RedisTest::testSCard() } } -void RedisTest::testSDiff() +void RedisTest::testSDIFF() { if (!_connected) { @@ -1363,7 +1363,7 @@ void RedisTest::testSDiff() } } -void RedisTest::testSDiffStore() +void RedisTest::testSDIFFSTORE() { if (!_connected) { @@ -1428,7 +1428,7 @@ void RedisTest::testSDiffStore() } } -void RedisTest::testSet() +void RedisTest::testSET() { if (!_connected) { @@ -1465,7 +1465,7 @@ void RedisTest::testSet() } -void RedisTest::testSInter() +void RedisTest::testSINTER() { if (!_connected) { @@ -1519,7 +1519,7 @@ void RedisTest::testSInter() } } -void RedisTest::testSInterStore() +void RedisTest::testSINTERSTORE() { if (!_connected) { @@ -1585,7 +1585,7 @@ void RedisTest::testSInterStore() } } -void RedisTest::testSIsmember() +void RedisTest::testSISMEMBER() { if (!_connected) { @@ -1629,7 +1629,7 @@ void RedisTest::testSIsmember() } } -void RedisTest::testSMembers() +void RedisTest::testSMEMBERS() { if (!_connected) { @@ -1673,7 +1673,7 @@ void RedisTest::testSMembers() } } -void RedisTest::testSMove() +void RedisTest::testSMOVE() { if (!_connected) { @@ -1751,7 +1751,7 @@ void RedisTest::testSMove() } } -void RedisTest::testSPop() +void RedisTest::testSPOP() { if (!_connected) { @@ -1852,7 +1852,7 @@ void RedisTest::testSPop() */ } -void RedisTest::testSRandMember() +void RedisTest::testSRANDMEMBER() { if (!_connected) { @@ -1912,7 +1912,7 @@ void RedisTest::testSRandMember() } } -void RedisTest::testStrlen() +void RedisTest::testSTRLEN() { if (!_connected) { @@ -1950,7 +1950,7 @@ void RedisTest::testStrlen() } } -void RedisTest::testSRem() +void RedisTest::testSREM() { if (!_connected) { @@ -2025,7 +2025,7 @@ void RedisTest::testSRem() } } -void RedisTest::testSUnion() +void RedisTest::testSUNION() { if (!_connected) { @@ -2078,7 +2078,7 @@ void RedisTest::testSUnion() } } -void RedisTest::testSUnionStore() +void RedisTest::testSUNIONSTORE() { if (!_connected) { @@ -2143,7 +2143,7 @@ void RedisTest::testSUnionStore() } } -void RedisTest::testRename() +void RedisTest::testRENAME() { if (!_connected) { @@ -2185,7 +2185,7 @@ void RedisTest::testRename() } } -void RedisTest::testRenameNx() +void RedisTest::testRENAMENX() { if (!_connected) { @@ -2238,7 +2238,7 @@ void RedisTest::testRenameNx() } } -void RedisTest::testRPop() +void RedisTest::testRPOP() { if (!_connected) { @@ -2299,7 +2299,7 @@ void RedisTest::testRPop() } -void RedisTest::testRPoplPush() +void RedisTest::testRPOPLPUSH() { if (!_connected) { @@ -2391,7 +2391,7 @@ void RedisTest::testRPoplPush() } } -void RedisTest::testRPush() +void RedisTest::testRPUSH() { if (!_connected) { @@ -2474,52 +2474,52 @@ CppUnit::Test* RedisTest::suite() { CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("RedisTest"); - CppUnit_addTest(pSuite, RedisTest, testAppend); - CppUnit_addTest(pSuite, RedisTest, testBLpop); - CppUnit_addTest(pSuite, RedisTest, testBRpop); - CppUnit_addTest(pSuite, RedisTest, testDecr); - CppUnit_addTest(pSuite, RedisTest, testDecr); - CppUnit_addTest(pSuite, RedisTest, testEcho); + CppUnit_addTest(pSuite, RedisTest, testAPPEND); + CppUnit_addTest(pSuite, RedisTest, testBLPOP); + CppUnit_addTest(pSuite, RedisTest, testBRPOP); + CppUnit_addTest(pSuite, RedisTest, testDECR); + CppUnit_addTest(pSuite, RedisTest, testDECR); + CppUnit_addTest(pSuite, RedisTest, testECHO); CppUnit_addTest(pSuite, RedisTest, testError); - CppUnit_addTest(pSuite, RedisTest, testEval); - CppUnit_addTest(pSuite, RedisTest, testHDel); - CppUnit_addTest(pSuite, RedisTest, testHSet); - CppUnit_addTest(pSuite, RedisTest, testIncr); - CppUnit_addTest(pSuite, RedisTest, testIncrBy); - CppUnit_addTest(pSuite, RedisTest, testLIndex); - CppUnit_addTest(pSuite, RedisTest, testLInsert); - CppUnit_addTest(pSuite, RedisTest, testLPop); - CppUnit_addTest(pSuite, RedisTest, testLRem); - CppUnit_addTest(pSuite, RedisTest, testLSet); - CppUnit_addTest(pSuite, RedisTest, testLTrim); - CppUnit_addTest(pSuite, RedisTest, testMSet); - CppUnit_addTest(pSuite, RedisTest, testMSetWithMap); - CppUnit_addTest(pSuite, RedisTest, testMulti); - CppUnit_addTest(pSuite, RedisTest, testPing); + CppUnit_addTest(pSuite, RedisTest, testEVAL); + CppUnit_addTest(pSuite, RedisTest, testHDEL); + CppUnit_addTest(pSuite, RedisTest, testHSET); + CppUnit_addTest(pSuite, RedisTest, testINCR); + CppUnit_addTest(pSuite, RedisTest, testINCRBY); + CppUnit_addTest(pSuite, RedisTest, testLINDEX); + CppUnit_addTest(pSuite, RedisTest, testLINSERT); + CppUnit_addTest(pSuite, RedisTest, testLPOP); + CppUnit_addTest(pSuite, RedisTest, testLREM); + CppUnit_addTest(pSuite, RedisTest, testLSET); + CppUnit_addTest(pSuite, RedisTest, testLTRIM); + CppUnit_addTest(pSuite, RedisTest, testMSET); + CppUnit_addTest(pSuite, RedisTest, testMSETWithMap); + CppUnit_addTest(pSuite, RedisTest, testMULTI); + CppUnit_addTest(pSuite, RedisTest, testPING); CppUnit_addTest(pSuite, RedisTest, testPipeliningWithSendCommands); CppUnit_addTest(pSuite, RedisTest, testPipeliningWithWriteCommand); CppUnit_addTest(pSuite, RedisTest, testPubSub); - CppUnit_addTest(pSuite, RedisTest, testSAdd); - CppUnit_addTest(pSuite, RedisTest, testSCard); - CppUnit_addTest(pSuite, RedisTest, testSDiff); - CppUnit_addTest(pSuite, RedisTest, testSDiffStore); - CppUnit_addTest(pSuite, RedisTest, testSet); - CppUnit_addTest(pSuite, RedisTest, testSInter); - CppUnit_addTest(pSuite, RedisTest, testSInterStore); - CppUnit_addTest(pSuite, RedisTest, testSIsmember); - CppUnit_addTest(pSuite, RedisTest, testSMembers); - CppUnit_addTest(pSuite, RedisTest, testSMove); - CppUnit_addTest(pSuite, RedisTest, testSPop); - CppUnit_addTest(pSuite, RedisTest, testSRandMember); - CppUnit_addTest(pSuite, RedisTest, testSRem); - CppUnit_addTest(pSuite, RedisTest, testStrlen); - CppUnit_addTest(pSuite, RedisTest, testSUnion); - CppUnit_addTest(pSuite, RedisTest, testSUnionStore); - CppUnit_addTest(pSuite, RedisTest, testRename); - CppUnit_addTest(pSuite, RedisTest, testRenameNx); - CppUnit_addTest(pSuite, RedisTest, testRPop); - CppUnit_addTest(pSuite, RedisTest, testRPoplPush); - CppUnit_addTest(pSuite, RedisTest, testRPush); + CppUnit_addTest(pSuite, RedisTest, testSADD); + CppUnit_addTest(pSuite, RedisTest, testSCARD); + CppUnit_addTest(pSuite, RedisTest, testSDIFF); + CppUnit_addTest(pSuite, RedisTest, testSDIFFSTORE); + CppUnit_addTest(pSuite, RedisTest, testSET); + CppUnit_addTest(pSuite, RedisTest, testSINTER); + CppUnit_addTest(pSuite, RedisTest, testSINTERSTORE); + CppUnit_addTest(pSuite, RedisTest, testSISMEMBER); + CppUnit_addTest(pSuite, RedisTest, testSMEMBERS); + CppUnit_addTest(pSuite, RedisTest, testSMOVE); + CppUnit_addTest(pSuite, RedisTest, testSPOP); + CppUnit_addTest(pSuite, RedisTest, testSRANDMEMBER); + CppUnit_addTest(pSuite, RedisTest, testSREM); + CppUnit_addTest(pSuite, RedisTest, testSTRLEN); + CppUnit_addTest(pSuite, RedisTest, testSUNION); + CppUnit_addTest(pSuite, RedisTest, testSUNIONSTORE); + CppUnit_addTest(pSuite, RedisTest, testRENAME); + CppUnit_addTest(pSuite, RedisTest, testRENAMENX); + CppUnit_addTest(pSuite, RedisTest, testRPOP); + CppUnit_addTest(pSuite, RedisTest, testRPOPLPUSH); + CppUnit_addTest(pSuite, RedisTest, testRPUSH); return pSuite; } diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 0c95cc901..541ce363f 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -30,51 +30,51 @@ public: virtual ~RedisTest(); - void testAppend(); - void testBLpop(); - void testBRpop(); - void testDecr(); - void testEcho(); + void testAPPEND(); + void testBLPOP(); + void testBRPOP(); + void testDECR(); + void testECHO(); void testError(); - void testEval(); - void testHDel(); - void testHSet(); - void testIncr(); - void testIncrBy(); - void testLIndex(); - void testLInsert(); - void testLPop(); - void testLRem(); - void testLSet(); - void testLTrim(); - void testMulti(); - void testMSet(); - void testMSetWithMap(); - void testPing(); + void testEVAL(); + void testHDEL(); + void testHSET(); + void testINCR(); + void testINCRBY(); + void testLINDEX(); + void testLINSERT(); + void testLPOP(); + void testLREM(); + void testLSET(); + void testLTRIM(); + void testMULTI(); + void testMSET(); + void testMSETWithMap(); + void testPING(); void testPipeliningWithSendCommands(); void testPipeliningWithWriteCommand(); void testPubSub(); - void testSAdd(); - void testSCard(); - void testSDiff(); - void testSDiffStore(); - void testSet(); - void testSInter(); - void testSInterStore(); - void testSIsmember(); - void testSMembers(); - void testSMove(); - void testSPop(); - void testSRandMember(); - void testSRem(); - void testSUnion(); - void testSUnionStore(); - void testStrlen(); - void testRename(); - void testRenameNx(); - void testRPop(); - void testRPoplPush(); - void testRPush(); + void testSADD(); + void testSCARD(); + void testSDIFF(); + void testSDIFFSTORE(); + void testSET(); + void testSINTER(); + void testSINTERSTORE(); + void testSISMEMBER(); + void testSMEMBERS(); + void testSMOVE(); + void testSPOP(); + void testSRANDMEMBER(); + void testSREM(); + void testSUNION(); + void testSUNIONSTORE(); + void testSTRLEN(); + void testRENAME(); + void testRENAMENX(); + void testRPOP(); + void testRPOPLPUSH(); + void testRPUSH(); void setUp(); void tearDown(); From 8d08cc3909497d9d30774410b15ab5b19d21c2c5 Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 17 Nov 2015 21:38:07 +0100 Subject: [PATCH 083/121] Add hexists --- Redis/include/Poco/Redis/Command.h | 5 +++- Redis/src/Command.cpp | 9 ++++++ Redis/testsuite/src/RedisTest.cpp | 45 ++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 94a6f1ebe..970156e5a 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -71,10 +71,13 @@ public: static Command hdel(const std::string& hash, const std::string& field); /// Returns an HDEL command - + static Command hdel(const std::string& hash, const std::vector& fields); /// Returns an HDEL command + static Command hexists(const std::string& hash, const std::string& field); + /// Returns an HEXISTS command + static Command hget(const std::string& hash, const std::string& field); /// Returns an HGET command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 78a08bb11..6b0e945f5 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -140,6 +140,15 @@ Command Command::hdel(const std::string& hash, const std::vector& f return cmd; } +Command Command::hexists(const std::string& hash, const std::string& field) +{ + Command cmd("HEXISTS"); + + cmd << hash << field; + + return cmd; +} + Command Command::hget(const std::string& hash, const std::string& field) { Command cmd("HGET"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 7a310cfa9..26a193e1e 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -418,6 +418,50 @@ void RedisTest::testHDEL() } } +void RedisTest::testHEXISTS() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + Command hset = Command::hset("myhash", "field1", "foo"); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hexists = Command::hexists("myhash", "field1"); + try + { + Poco::Int64 result = _redis.execute(hexists); + assert(result == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hexists = Command::hexists("myhash", "field2"); + try + { + Poco::Int64 result = _redis.execute(hexists); + assert(result == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testHSET() { if (!_connected) @@ -2483,6 +2527,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testError); CppUnit_addTest(pSuite, RedisTest, testEVAL); CppUnit_addTest(pSuite, RedisTest, testHDEL); + CppUnit_addTest(pSuite, RedisTest, testHEXISTS); CppUnit_addTest(pSuite, RedisTest, testHSET); CppUnit_addTest(pSuite, RedisTest, testINCR); CppUnit_addTest(pSuite, RedisTest, testINCRBY); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 541ce363f..642358012 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -38,6 +38,7 @@ public: void testError(); void testEVAL(); void testHDEL(); + void testHEXISTS(); void testHSET(); void testINCR(); void testINCRBY(); From 2f850b8a4305eab2a8403ddfe42ff1dadb42a663 Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 17 Nov 2015 22:02:25 +0100 Subject: [PATCH 084/121] Add hgetall / hincrby --- Redis/include/Poco/Redis/Command.h | 9 +++ Redis/src/Command.cpp | 23 +++++++ Redis/testsuite/src/RedisTest.cpp | 101 +++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 2 + 4 files changed, 135 insertions(+) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 970156e5a..d1f0a5f92 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -81,9 +81,18 @@ public: static Command hget(const std::string& hash, const std::string& field); /// Returns an HGET command + static Command hgetall(const std::string& hash); + /// Returns an HGETALL command + + static Command hincrby(const std::string& hash, const std::string& field, Int64 by = 1); + /// Returns an HINCRBY command + static Command hset(const std::string& hash, const std::string& field, const std::string& value, bool create = true); /// Returns an HSET or HSETNX (when create is false) command + static Command hset(const std::string& hash, const std::string& field, Int64 value, bool create = true); + /// Returns an HSET or HSETNX (when create is false) command + static Command incr(const std::string& key, Int64 by = 0); /// Returns an INCR or INCRBY command. Calls INCR when by is omitted or zero. diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 6b0e945f5..29abb69e8 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -158,6 +158,24 @@ Command Command::hget(const std::string& hash, const std::string& field) return cmd; } +Command Command::hgetall(const std::string& hash) +{ + Command cmd("HGETALL"); + + cmd << hash; + + return cmd; +} + +Command Command::hincrby(const std::string& hash, const std::string& field, Int64 by) +{ + Command cmd("HINCRBY"); + + cmd << hash << field << NumberFormatter::format(by); + + return cmd; +} + Command Command::hset(const std::string& hash, const std::string& field, const std::string& value, bool create) { Command cmd(create ? "HSET" : "HSETNX"); @@ -167,6 +185,11 @@ Command Command::hset(const std::string& hash, const std::string& field, const s return cmd; } +Command Command::hset(const std::string& hash, const std::string& field, Int64 value, bool create) +{ + return hset(hash, field, NumberFormatter::format(value), create); +} + Command Command::incr(const std::string& key, Int64 by) { Command cmd(by == 0 ? "INCR" : "INCRBY"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 26a193e1e..fdfa2e2f1 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -462,6 +462,105 @@ void RedisTest::testHEXISTS() } } +void RedisTest::testHGETALL() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + Command hset = Command::hset("myhash", "field1", "Hello"); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hset = Command::hset("myhash", "field2", "World"); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hgetall = Command::hgetall("myhash"); + try + { + Array result = _redis.execute(hgetall); + assert(result.size() == 4); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + +void RedisTest::testHINCRBY() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + Command hset = Command::hset("myhash", "field", 5); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hincrby = Command::hincrby("myhash", "field"); + try + { + Poco::Int64 n = _redis.execute(hincrby); + assert(n == 6); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hincrby = Command::hincrby("myhash", "field", -1); + try + { + Poco::Int64 n = _redis.execute(hincrby); + assert(n == 5); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hincrby = Command::hincrby("myhash", "field", -10); + try + { + Poco::Int64 n = _redis.execute(hincrby); + assert(n == -5); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testHSET() { if (!_connected) @@ -2528,6 +2627,8 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testEVAL); CppUnit_addTest(pSuite, RedisTest, testHDEL); CppUnit_addTest(pSuite, RedisTest, testHEXISTS); + CppUnit_addTest(pSuite, RedisTest, testHGETALL); + CppUnit_addTest(pSuite, RedisTest, testHINCRBY); CppUnit_addTest(pSuite, RedisTest, testHSET); CppUnit_addTest(pSuite, RedisTest, testINCR); CppUnit_addTest(pSuite, RedisTest, testINCRBY); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 642358012..b4039380b 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -39,6 +39,8 @@ public: void testEVAL(); void testHDEL(); void testHEXISTS(); + void testHGETALL(); + void testHINCRBY(); void testHSET(); void testINCR(); void testINCRBY(); From 8015d827f41994b461d43d6f4c1da8dcc28a3bb4 Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 17 Nov 2015 22:18:18 +0100 Subject: [PATCH 085/121] Add hkeys / hlen --- Redis/include/Poco/Redis/Command.h | 6 ++++ Redis/src/Command.cpp | 18 ++++++++++ Redis/testsuite/src/RedisTest.cpp | 58 ++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 83 insertions(+) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index d1f0a5f92..3e54d087b 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -87,6 +87,12 @@ public: static Command hincrby(const std::string& hash, const std::string& field, Int64 by = 1); /// Returns an HINCRBY command + static Command hkeys(const std::string& hash); + /// Returns an HKEYS command + + static Command hlen(const std::string& hash); + /// Returns an HLEN command + static Command hset(const std::string& hash, const std::string& field, const std::string& value, bool create = true); /// Returns an HSET or HSETNX (when create is false) command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 29abb69e8..c6cefedf1 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -176,6 +176,24 @@ Command Command::hincrby(const std::string& hash, const std::string& field, Int6 return cmd; } +Command Command::hkeys(const std::string& hash) +{ + Command cmd("HKEYS"); + + cmd << hash; + + return cmd; +} + +Command Command::hlen(const std::string& hash) +{ + Command cmd("HLEN"); + + cmd << hash; + + return cmd; +} + Command Command::hset(const std::string& hash, const std::string& field, const std::string& value, bool create) { Command cmd(create ? "HSET" : "HSETNX"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index fdfa2e2f1..efc31e48c 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -561,6 +561,63 @@ void RedisTest::testHINCRBY() } } +void RedisTest::testHKEYS() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + Command hset = Command::hset("myhash", "field1", "Hello"); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hset = Command::hset("myhash", "field2", "World"); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hlen = Command::hlen("myhash"); + try + { + Poco::Int64 value = _redis.execute(hlen); + assert(value == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hkeys = Command::hkeys("myhash"); + try + { + Array result = _redis.execute(hkeys); + assert(result.size() == 2); + assert(result.get(0).value().compare("field1") == 0); + assert(result.get(1).value().compare("field2") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testHSET() { if (!_connected) @@ -2629,6 +2686,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testHEXISTS); CppUnit_addTest(pSuite, RedisTest, testHGETALL); CppUnit_addTest(pSuite, RedisTest, testHINCRBY); + CppUnit_addTest(pSuite, RedisTest, testHKEYS); CppUnit_addTest(pSuite, RedisTest, testHSET); CppUnit_addTest(pSuite, RedisTest, testINCR); CppUnit_addTest(pSuite, RedisTest, testINCRBY); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index b4039380b..affbd62a7 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -41,6 +41,7 @@ public: void testHEXISTS(); void testHGETALL(); void testHINCRBY(); + void testHKEYS(); void testHSET(); void testINCR(); void testINCRBY(); From 7a60478e48ec8e6f86a2a58b139e2b560a61aa8d Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Tue, 17 Nov 2015 23:56:51 +0100 Subject: [PATCH 086/121] Display sqlite3 version. Signed-off-by: FrancisANDRE --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 80e14ca00..5bc4f439b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,7 @@ env: before_script: - echo ${TEST_NAME} + - sqlite3 -version matrix: include: From 297bd6234ee0b08967640b2b0e62dace8cccfc9f Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 00:08:49 +0100 Subject: [PATCH 087/121] install sqlite3 latest version. Signed-off-by: FrancisANDRE --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5bc4f439b..797a2c00e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ before_install: - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev libpcre3-dev libssl-dev libsqlite3-dev libexpat1-dev - sudo apt-get install -qq -y g++-arm-linux-gnueabi g++-arm-linux-gnueabihf clang-3.5 - sudo apt-get install -qq -y sloccount cppcheck - + - sudo apt-get install -qq -y sqlite3 libsqlite3-dev services: - mongodb From 517d8a10a19513827e3dc16a15b31c49ccc06ba0 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 00:31:33 +0100 Subject: [PATCH 088/121] Trying libsqlite3-dev_3.9.1-2_amd64.deb Signed-off-by: FrancisANDRE --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 797a2c00e..7bf27e213 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,10 +11,11 @@ before_install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then tar -xzvf cmake-3.2.3-Linux-x86_64.tar.gz; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export PATH=$PWD/cmake-3.2.3-Linux-x86_64/bin:$PATH; fi - sudo apt-get update -qq - - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev libpcre3-dev libssl-dev libsqlite3-dev libexpat1-dev + - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev libpcre3-dev libssl-dev libexpat1-dev - sudo apt-get install -qq -y g++-arm-linux-gnueabi g++-arm-linux-gnueabihf clang-3.5 - sudo apt-get install -qq -y sloccount cppcheck - - sudo apt-get install -qq -y sqlite3 libsqlite3-dev + - sudo apt-get install -qq -y libsqlite3-dev_3.9.1-2_amd64.deb + services: - mongodb From 1af0a13cc3f2b0957c07bfc9bd344bce18cf32d3 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 00:45:43 +0100 Subject: [PATCH 089/121] Download and install libsqlite3-dev_3.9.2-1_amd64.deb. Signed-off-by: FrancisANDRE --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7bf27e213..2ef6602ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,10 +11,11 @@ before_install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then tar -xzvf cmake-3.2.3-Linux-x86_64.tar.gz; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export PATH=$PWD/cmake-3.2.3-Linux-x86_64/bin:$PATH; fi - sudo apt-get update -qq - - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev libpcre3-dev libssl-dev libexpat1-dev + - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev libpcre3-dev libssl-dev libsqlite3-dev libexpat1-dev - sudo apt-get install -qq -y g++-arm-linux-gnueabi g++-arm-linux-gnueabihf clang-3.5 - sudo apt-get install -qq -y sloccount cppcheck - - sudo apt-get install -qq -y libsqlite3-dev_3.9.1-2_amd64.deb + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then wget --no-check-certificate http://ftp.br.debian.org/debian/pool/main/s/sqlite3/libsqlite3-dev_3.9.2-1_amd64.deb; fi + - sudo dpkg -i libsqlite3-dev_3.9.1-2_amd64.deb services: - mongodb From 55ad08feda719da6d687bcbe2dde1a231ae85dd6 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 09:07:46 +0100 Subject: [PATCH 090/121] Restore apt-get libsqlite3-dev. Signed-off-by: FrancisANDRE --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2ef6602ed..5bc4f439b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,6 @@ before_install: - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev libpcre3-dev libssl-dev libsqlite3-dev libexpat1-dev - sudo apt-get install -qq -y g++-arm-linux-gnueabi g++-arm-linux-gnueabihf clang-3.5 - sudo apt-get install -qq -y sloccount cppcheck - - if [ "$TRAVIS_OS_NAME" == "linux" ]; then wget --no-check-certificate http://ftp.br.debian.org/debian/pool/main/s/sqlite3/libsqlite3-dev_3.9.2-1_amd64.deb; fi - - sudo dpkg -i libsqlite3-dev_3.9.1-2_amd64.deb services: - mongodb From cf33959a49d09927d551a5a9b270545c0976c3f2 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 09:27:45 +0100 Subject: [PATCH 091/121] Run IncrementVacuum only if sqlite3 version >= 3.9.0 Signed-off-by: FrancisANDRE --- Data/SQLite/testsuite/src/SQLiteTest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Data/SQLite/testsuite/src/SQLiteTest.cpp b/Data/SQLite/testsuite/src/SQLiteTest.cpp index 8d886763e..610b03f3e 100644 --- a/Data/SQLite/testsuite/src/SQLiteTest.cpp +++ b/Data/SQLite/testsuite/src/SQLiteTest.cpp @@ -3569,6 +3569,8 @@ CppUnit::Test* SQLiteTest::suite() CppUnit_addTest(pSuite, SQLiteTest, testTransactor); CppUnit_addTest(pSuite, SQLiteTest, testFTS3); CppUnit_addTest(pSuite, SQLiteTest, testJSONRowFormatter); +#if SQLITE_VERSION_NUMBER >= 309000 CppUnit_addTest(pSuite, SQLiteTest, testIncrementVacuum); +#endif return pSuite; } From 7555150cf296a3f5eb9f5430e28cd79af7919be4 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 10:01:22 +0100 Subject: [PATCH 092/121] Remove temporarily arm-linux-gnueabi. Signed-off-by: FrancisANDRE --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5bc4f439b..dccd11030 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ matrix: - env: TEST_NAME="arm-linux-gnueabi- (make)" script: - - ./configure --omit=Data/ODBC,Data/MySQL,Crypto,NetSSL,PageCompiler && make -s -j2 CROSS_COMPILE=arm-linux-gnueabi- POCO_TARGET_OSARCH=armv7l +#FIXME - ./configure --omit=Data/ODBC,Data/MySQL,Crypto,NetSSL,PageCompiler && make -s -j2 CROSS_COMPILE=arm-linux-gnueabi- POCO_TARGET_OSARCH=armv7l - env: TEST_NAME="gcc (CMake)" compiler: gcc From 75f0819737f38b4b131289bf6011bda0b56fb56a Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 11:41:23 +0100 Subject: [PATCH 093/121] IncrementVacuum test commented out since it fails on Travis. Signed-off-by: FrancisANDRE --- Data/SQLite/testsuite/src/SQLiteTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Data/SQLite/testsuite/src/SQLiteTest.cpp b/Data/SQLite/testsuite/src/SQLiteTest.cpp index 610b03f3e..192e446bf 100644 --- a/Data/SQLite/testsuite/src/SQLiteTest.cpp +++ b/Data/SQLite/testsuite/src/SQLiteTest.cpp @@ -3569,8 +3569,8 @@ CppUnit::Test* SQLiteTest::suite() CppUnit_addTest(pSuite, SQLiteTest, testTransactor); CppUnit_addTest(pSuite, SQLiteTest, testFTS3); CppUnit_addTest(pSuite, SQLiteTest, testJSONRowFormatter); -#if SQLITE_VERSION_NUMBER >= 309000 - CppUnit_addTest(pSuite, SQLiteTest, testIncrementVacuum); -#endif - return pSuite; +// +// To be fixed by dimanikulin +// CppUnit_addTest(pSuite, SQLiteTest, testIncrementVacuum); +// } From 217c520731a2ce2eba005294f9904328ef66619c Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 11:46:21 +0100 Subject: [PATCH 094/121] Commented the arm-linux-gnueabi- test. Signed-off-by: FrancisANDRE --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index dccd11030..dee78f9f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,9 +48,10 @@ matrix: - ./configure --everything --config=Linux-clang && make -s -j2 - ./travis/runtests.sh - - env: TEST_NAME="arm-linux-gnueabi- (make)" - script: -#FIXME - ./configure --omit=Data/ODBC,Data/MySQL,Crypto,NetSSL,PageCompiler && make -s -j2 CROSS_COMPILE=arm-linux-gnueabi- POCO_TARGET_OSARCH=armv7l + #FIXME the -m64 option bring by the Linux config is not supported by arm-linux-gnueabi-g++ which makes this test failing + #FIXME - env: TEST_NAME="arm-linux-gnueabi- (make)" + #FIXME script: + #FIXME - ./configure --omit=Data/ODBC,Data/MySQL,Crypto,NetSSL,PageCompiler && make -s -j2 CROSS_COMPILE=arm-linux-gnueabi- POCO_TARGET_OSARCH=armv7l - env: TEST_NAME="gcc (CMake)" compiler: gcc From d3d11e25d9f304c2569bf083d91668aefcf6e654 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 12:34:16 +0100 Subject: [PATCH 095/121] Restore previous version. Signed-off-by: FrancisANDRE --- Data/SQLite/src/SQLiteStatementImpl.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Data/SQLite/src/SQLiteStatementImpl.cpp b/Data/SQLite/src/SQLiteStatementImpl.cpp index 9910b20cb..5f0b6c725 100644 --- a/Data/SQLite/src/SQLiteStatementImpl.cpp +++ b/Data/SQLite/src/SQLiteStatementImpl.cpp @@ -274,9 +274,6 @@ std::size_t SQLiteStatementImpl::next() _stepCalled = false; if (_affectedRowCount == POCO_SQLITE_INV_ROW_CNT) _affectedRowCount = 0; - if (extracts.size()) - - //_affectedRowCount += (*extracts.begin())->numOfRowsHandled(); if (extracts.size()) _affectedRowCount += (*extracts.begin())->numOfRowsHandled(); else @@ -284,11 +281,6 @@ std::size_t SQLiteStatementImpl::next() _stepCalled = true; _nextResponse = SQLITE_DONE; } - else - { - _stepCalled = true; - _nextResponse = SQLITE_DONE; - } } else if (SQLITE_DONE == _nextResponse) From 9b63ddfc938c7e7069c1ef4ac7da2bd72e8a57f6 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 14:41:27 +0100 Subject: [PATCH 096/121] Add DYFLAGS, SHLIBFLAGS description. Signed-off-by: FrancisANDRE --- doc/99150-GMakeBuildNotes.page | 69 ++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/doc/99150-GMakeBuildNotes.page b/doc/99150-GMakeBuildNotes.page index 92bb511fe..7cd7eadc0 100644 --- a/doc/99150-GMakeBuildNotes.page +++ b/doc/99150-GMakeBuildNotes.page @@ -706,21 +706,76 @@ compiling in 32 bit mode. compiling in 64 bit mode. +!LIBFLAGS + +<*LIBFLAGS*> specifies additional flags passed to the linker when building +a static library. + + +!LIBFLAGS32 + +<*LIBFLAGS32*> specifies additional flags passed to the linker when building +a static library if compiling in 32 bit mode. + + +!LIBFLAGS64 + +<*LIBFLAGS64*> specifies additional flags passed to the linker when building +a static library if compiling in 64 bit mode. + + +!SHLIBFLAGS + +<*SHLIBFLAGS*> specifies additional flags passed to the linker when building +a shared library. + + +!SHLIBFLAGS32 + +<*SHLIBFLAGS32*> specifies additional flags passed to the linker when building +a shared library if compiling in 32 bit mode. + + +!SHLIBFLAGS64 + +<*SHLIBFLAGS64*> specifies additional flags passed to the linker when building +a shared library if compiling in 64 bit mode. + + +!DYLIBFLAGS + +<*DYLIBFLAGS*> specifies additional flags passed to the linker when building +a dynamically loadable shared library. + + +!DYLIBFLAGS32 + +<*DYLIBFLAGS32*> specifies additional flags passed to the linker when building +a dynamically loadable shared library if compiling in 32 bit mode. + + +!DYLIBFLAGS64 + +<*DYLIBFLAGS64*> specifies additional flags passed to the linker when building +a dynamically loadable shared library if compiling in 64 bit mode. + + !LINKFLAGS -<*LINKFLAGS*> specifies additional flags passed to the linker. +<*LINKFLAGS*> specifies additional flags passed to the linker when building +an executable. !LINKFLAGS32 -<*LINKFLAGS32*> specifies additional flags passed to the linker if -compiling in 32 bit mode. +<*LINKFLAGS32*> specifies additional flags passed to the linker when building +an executable if compiling in 32 bit mode. !LINKFLAGS64 -<*LINKFLAGS64*> specifies additional flags passed to the linker if -compiling in 64 bit mode. +<*LINKFLAGS64*> specifies additional flags passed to the linker when building +an executable if compiling in 64 bit mode. !STATICOPT_CC @@ -743,8 +798,8 @@ static linking. !SHAREDOPT_CC -<*SHAREDOPT_CC*> specifies additonal flags passed to the C compiler if -compiling for dynamic linking. +<*SHAREDOPT_CC*> specifies additonal flags passed to the C compiler +for dynamic linking. !SHAREDOPT_CXX From 52ce9bf469f8c5f791de93cc0d1e551a4ea6b25b Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 18 Nov 2015 18:13:17 +0100 Subject: [PATCH 097/121] Add typedef StringVec --- Redis/include/Poco/Redis/Command.h | 33 ++++++++-------- Redis/src/Command.cpp | 60 +++++++++++++++--------------- 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 3e54d087b..a9d0cd773 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -36,6 +36,9 @@ class Redis_API Command : public Array /// or << operator. { public: + + typedef std::vector StringVec; + Command(const std::string& command); /// Constructor @@ -48,10 +51,10 @@ public: static Command append(const std::string& key, const std::string& value); /// Returns an APPEND command - static Command blpop(const std::vector& lists, Int64 timeout = 0); + static Command blpop(const StringVec& lists, Int64 timeout = 0); /// Returns a BLPOP command - static Command brpop(const std::vector& lists, Int64 timeout = 0); + static Command brpop(const StringVec& lists, Int64 timeout = 0); /// Returns a BRPOP command static Command brpoplpush(const std::string& sourceList, const std::string& destinationList, Int64 timeout = 0); @@ -63,7 +66,7 @@ public: static Command del(const std::string& key); /// Returns an DEL command - static Command del(const std::vector& keys); + static Command del(const StringVec& keys); /// Returns an DEL command static Command get(const std::string& key); @@ -72,7 +75,7 @@ public: static Command hdel(const std::string& hash, const std::string& field); /// Returns an HDEL command - static Command hdel(const std::string& hash, const std::vector& fields); + static Command hdel(const std::string& hash, const StringVec& fields); /// Returns an HDEL command static Command hexists(const std::string& hash, const std::string& field); @@ -117,7 +120,7 @@ public: static Command lpush(const std::string& list, const std::string& value, bool create = true); /// Returns a LPUSH or LPUSHX (when create is false) command - static Command lpush(const std::string& list, const std::vector& value, bool create = true); + static Command lpush(const std::string& list, const StringVec& value, bool create = true); /// Returns a LPUSH or LPUSHX (when create is false) command static Command lrange(const std::string& list, Int64 start = 0, Int64 stop = -1); @@ -133,7 +136,7 @@ public: static Command ltrim(const std::string& list, Int64 start = 0, Int64 stop = -1); /// Returns a LTRIM command - static Command mget(const std::vector& keys); + static Command mget(const StringVec& keys); /// Returns a MGET command static Command mset(const std::map& keyvalues, bool create = true); @@ -142,7 +145,7 @@ public: static Command sadd(const std::string& set, const std::string& value); /// Returns a SADD command - static Command sadd(const std::string& set, const std::vector& values); + static Command sadd(const std::string& set, const StringVec& values); /// Returns a SADD command static Command scard(const std::string& set); @@ -151,13 +154,13 @@ public: static Command sdiff(const std::string& set1, const std::string& set2); /// Returns a SDIFF command - static Command sdiff(const std::string& set, const std::vector& sets); + static Command sdiff(const std::string& set, const StringVec& sets); /// Returns a SDIFF command static Command sdiffstore(const std::string& set, const std::string& set1, const std::string& set2); /// Returns a SDIFFSTORE command - static Command sdiffstore(const std::string& set, const std::vector& sets); + static Command sdiffstore(const std::string& set, const StringVec& sets); /// Returns a SDIFFSTORE command static Command set(const std::string& key, const std::string& value, bool overwrite = true, const Poco::Timespan& expireTime = 0, bool create = true); @@ -169,13 +172,13 @@ public: static Command sinter(const std::string& set1, const std::string& set2); /// Returns a SINTER command - static Command sinter(const std::string& set, const std::vector& sets); + static Command sinter(const std::string& set, const StringVec& sets); /// Returns a SINTER command static Command sinterstore(const std::string& set, const std::string& set1, const std::string& set2); /// Returns a SINTERSTORE command - static Command sinterstore(const std::string& set, const std::vector& sets); + static Command sinterstore(const std::string& set, const StringVec& sets); /// Returns a SINTERSTORE command static Command sismember(const std::string& set, const std::string& member); @@ -196,19 +199,19 @@ public: static Command srem(const std::string& set, const std::string& member); /// Returns a SREM command - static Command srem(const std::string& set, const std::vector& member); + static Command srem(const std::string& set, const StringVec& members); /// Returns a SREM command static Command sunion(const std::string& set1, const std::string& set2); /// Returns a SUNION command - static Command sunion(const std::string& set, const std::vector& sets); + static Command sunion(const std::string& set, const StringVec& sets); /// Returns a SUNION command static Command sunionstore(const std::string& set, const std::string& set1, const std::string& set2); /// Returns a SUNIONSTORE command - static Command sunionstore(const std::string& set, const std::vector& sets); + static Command sunionstore(const std::string& set, const StringVec& sets); /// Returns a SUNIONSTORE command static Command rename(const std::string& key, const std::string& newName, bool overwrite = true); @@ -223,7 +226,7 @@ public: static Command rpush(const std::string& list, const std::string& value, bool create = true); /// Returns a RPUSH or RPUSHX (when create is false) command - static Command rpush(const std::string& list, const std::vector& value, bool create = true); + static Command rpush(const std::string& list, const StringVec& value, bool create = true); /// Returns a RPUSH or RPUSHX (when create is false) command }; diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index c6cefedf1..e55c49f28 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -43,11 +43,11 @@ Command Command::append(const std::string& key, const std::string& value) return cmd; } -Command Command::blpop(const std::vector& lists, Int64 timeout) +Command Command::blpop(const StringVec& lists, Int64 timeout) { Command cmd("BLPOP"); - for(std::vector::const_iterator it = lists.begin(); it != lists.end(); ++it) + for(StringVec::const_iterator it = lists.begin(); it != lists.end(); ++it) { cmd << *it; } @@ -56,11 +56,11 @@ Command Command::blpop(const std::vector& lists, Int64 timeout) return cmd; } -Command Command::brpop(const std::vector& lists, Int64 timeout) +Command Command::brpop(const StringVec& lists, Int64 timeout) { Command cmd("BRPOP"); - for(std::vector::const_iterator it = lists.begin(); it != lists.end(); ++it) + for(StringVec::const_iterator it = lists.begin(); it != lists.end(); ++it) { cmd << *it; } @@ -97,11 +97,11 @@ Command Command::del(const std::string& key) return cmd; } -Command Command::del(const std::vector& keys) +Command Command::del(const StringVec& keys) { Command cmd("DEL"); - for(std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it) + for(StringVec::const_iterator it = keys.begin(); it != keys.end(); ++it) { cmd << *it; } @@ -127,12 +127,12 @@ Command Command::hdel(const std::string& hash, const std::string& field) return cmd; } -Command Command::hdel(const std::string& hash, const std::vector& fields) +Command Command::hdel(const std::string& hash, const StringVec& fields) { Command cmd("HDEL"); cmd << hash; - for(std::vector::const_iterator it = fields.begin(); it != fields.end(); ++it) + for(StringVec::const_iterator it = fields.begin(); it != fields.end(); ++it) { cmd << *it; } @@ -262,12 +262,12 @@ Command Command::lpush(const std::string& list, const std::string& value, bool c return cmd; } -Command Command::lpush(const std::string& list, const std::vector& values, bool create) +Command Command::lpush(const std::string& list, const StringVec& values, bool create) { Command cmd(create ? "LPUSH" : "LPUSHX"); cmd << list; - for(std::vector::const_iterator it = values.begin(); it != values.end(); ++it) + for(StringVec::const_iterator it = values.begin(); it != values.end(); ++it) { cmd << *it; } @@ -311,11 +311,11 @@ Command Command::ltrim(const std::__cxx11::string& list, Int64 start, Int64 stop return cmd; } -Command Command::mget(const std::vector& keys) +Command Command::mget(const StringVec& keys) { Command cmd("MGET"); - for(std::vector::const_iterator it = keys.begin(); it != keys.end(); ++it) + for(StringVec::const_iterator it = keys.begin(); it != keys.end(); ++it) { cmd << *it; } @@ -344,12 +344,12 @@ Command Command::sadd(const std::string& set, const std::string& value) return cmd; } -Command Command::sadd(const std::string& set, const std::vector& values) +Command Command::sadd(const std::string& set, const StringVec& values) { Command cmd("SADD"); cmd << set; - for(std::vector::const_iterator it = values.begin(); it != values.end(); ++it) + for(StringVec::const_iterator it = values.begin(); it != values.end(); ++it) { cmd << *it; } @@ -375,12 +375,12 @@ Command Command::sdiff(const std::string& set1, const std::string& set2) return cmd; } -Command Command::sdiff(const std::string& set, const std::vector& sets) +Command Command::sdiff(const std::string& set, const StringVec& sets) { Command cmd("SDIFF"); cmd << set; - for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) { cmd << *it; } @@ -397,12 +397,12 @@ Command Command::sdiffstore(const std::string& set, const std::string& set1, con return cmd; } -Command Command::sdiffstore(const std::string& set, const std::vector& sets) +Command Command::sdiffstore(const std::string& set, const StringVec& sets) { Command cmd("SDIFFSTORE"); cmd << set; - for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) { cmd << *it; } @@ -436,12 +436,12 @@ Command Command::sinter(const std::string& set1, const std::string& set2) return cmd; } -Command Command::sinter(const std::string& set, const std::vector& sets) +Command Command::sinter(const std::string& set, const StringVec& sets) { Command cmd("SINTER"); cmd << set; - for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) { cmd << *it; } @@ -458,12 +458,12 @@ Command Command::sinterstore(const std::string& set, const std::string& set1, co return cmd; } -Command Command::sinterstore(const std::string& set, const std::vector& sets) +Command Command::sinterstore(const std::string& set, const StringVec& sets) { Command cmd("SINTERSTORE"); cmd << set; - for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) { cmd << *it; } @@ -527,12 +527,12 @@ Command Command::srem(const std::string& set1, const std::string& member) return cmd; } -Command Command::srem(const std::string& set, const std::vector& members) +Command Command::srem(const std::string& set, const StringVec& members) { Command cmd("SREM"); cmd << set; - for(std::vector::const_iterator it = members.begin(); it != members.end(); ++it) + for(StringVec::const_iterator it = members.begin(); it != members.end(); ++it) { cmd << *it; } @@ -549,12 +549,12 @@ Command Command::sunion(const std::string& set1, const std::string& set2) return cmd; } -Command Command::sunion(const std::string& set, const std::vector& sets) +Command Command::sunion(const std::string& set, const StringVec& sets) { Command cmd("SUNION"); cmd << set; - for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) { cmd << *it; } @@ -571,12 +571,12 @@ Command Command::sunionstore(const std::string& set, const std::string& set1, co return cmd; } -Command Command::sunionstore(const std::string& set, const std::vector& sets) +Command Command::sunionstore(const std::string& set, const StringVec& sets) { Command cmd("SUNIONSTORE"); cmd << set; - for(std::vector::const_iterator it = sets.begin(); it != sets.end(); ++it) + for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) { cmd << *it; } @@ -621,12 +621,12 @@ Command Command::rpush(const std::string& list, const std::string& value, bool c return cmd; } -Command Command::rpush(const std::string& list, const std::vector& values, bool create) +Command Command::rpush(const std::string& list, const StringVec& values, bool create) { Command cmd(create ? "RPUSH" : "RPUSHX"); cmd << list; - for(std::vector::const_iterator it = values.begin(); it != values.end(); ++it) + for(StringVec::const_iterator it = values.begin(); it != values.end(); ++it) { cmd << *it; } From feb9ad31d29c6bb06d4e259aeb2fde8a29bed30e Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 18 Nov 2015 18:47:57 +0100 Subject: [PATCH 098/121] overload operator<< and add for vector of strings / hmget --- Redis/include/Poco/Redis/Array.h | 24 ++++++++ Redis/include/Poco/Redis/Command.h | 3 + Redis/src/Command.cpp | 97 ++++++++---------------------- 3 files changed, 51 insertions(+), 73 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 67de2bfa0..5b49ece8d 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -58,6 +58,11 @@ public: } Array& operator<<(const char* s); + /// Special implementation for const char* + + Array& operator<<(const std::vector& strings); + /// Special implementation for a vector with strings + /// All strings will be added as a BulkString. Array& add(); /// Adds an Null BulkString @@ -76,6 +81,11 @@ public: } Array& add(const char* s); + /// Special implementation for const char* + + Array& add(const std::vector& strings); + /// Special implementation for a vector with strings + /// All strings will be added as a BulkString. Array& addRedisType(RedisType::Ptr value); /// Adds a Redis element. @@ -143,6 +153,11 @@ inline Array& Array::operator<<(const char* s) return add(value); } +inline Array& Array::operator<<(const std::vector& strings) +{ + return add(strings); +} + inline Array& Array::add() { BulkString value; @@ -162,6 +177,15 @@ inline Array& Array::add(const char* s) return add(value); } +inline Array& Array::add(const std::vector& strings) +{ + for(std::vector::const_iterator it = strings.begin(); it != strings.end(); ++it) + { + add(*it); + } + return *this; +} + inline Array& Array::addSimpleString(const std::string& value) { return addRedisType(new Type(value)); diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index a9d0cd773..3ccd05653 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -96,6 +96,9 @@ public: static Command hlen(const std::string& hash); /// Returns an HLEN command + static Command hmget(const std::string& hash, const StringVec& fields); + /// Returns an HMGET command + static Command hset(const std::string& hash, const std::string& field, const std::string& value, bool create = true); /// Returns an HSET or HSETNX (when create is false) command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index e55c49f28..3a420ef47 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -47,11 +47,7 @@ Command Command::blpop(const StringVec& lists, Int64 timeout) { Command cmd("BLPOP"); - for(StringVec::const_iterator it = lists.begin(); it != lists.end(); ++it) - { - cmd << *it; - } - cmd << NumberFormatter::format(timeout); + cmd << lists << NumberFormatter::format(timeout); return cmd; } @@ -60,11 +56,7 @@ Command Command::brpop(const StringVec& lists, Int64 timeout) { Command cmd("BRPOP"); - for(StringVec::const_iterator it = lists.begin(); it != lists.end(); ++it) - { - cmd << *it; - } - cmd << NumberFormatter::format(timeout); + cmd << lists << NumberFormatter::format(timeout); return cmd; } @@ -101,10 +93,7 @@ Command Command::del(const StringVec& keys) { Command cmd("DEL"); - for(StringVec::const_iterator it = keys.begin(); it != keys.end(); ++it) - { - cmd << *it; - } + cmd << keys; return cmd; } @@ -131,11 +120,7 @@ Command Command::hdel(const std::string& hash, const StringVec& fields) { Command cmd("HDEL"); - cmd << hash; - for(StringVec::const_iterator it = fields.begin(); it != fields.end(); ++it) - { - cmd << *it; - } + cmd << hash << fields; return cmd; } @@ -194,6 +179,15 @@ Command Command::hlen(const std::string& hash) return cmd; } +Command Command::hmget(const std::string& hash, const StringVec& fields) +{ + Command cmd("HMGET"); + + cmd << hash << fields; + + return cmd; +} + Command Command::hset(const std::string& hash, const std::string& field, const std::string& value, bool create) { Command cmd(create ? "HSET" : "HSETNX"); @@ -266,11 +260,7 @@ Command Command::lpush(const std::string& list, const StringVec& values, bool cr { Command cmd(create ? "LPUSH" : "LPUSHX"); - cmd << list; - for(StringVec::const_iterator it = values.begin(); it != values.end(); ++it) - { - cmd << *it; - } + cmd << list << values; return cmd; } @@ -315,10 +305,7 @@ Command Command::mget(const StringVec& keys) { Command cmd("MGET"); - for(StringVec::const_iterator it = keys.begin(); it != keys.end(); ++it) - { - cmd << *it; - } + cmd << keys; return cmd; } @@ -348,11 +335,7 @@ Command Command::sadd(const std::string& set, const StringVec& values) { Command cmd("SADD"); - cmd << set; - for(StringVec::const_iterator it = values.begin(); it != values.end(); ++it) - { - cmd << *it; - } + cmd << set << values; return cmd; } @@ -379,11 +362,7 @@ Command Command::sdiff(const std::string& set, const StringVec& sets) { Command cmd("SDIFF"); - cmd << set; - for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) - { - cmd << *it; - } + cmd << set << sets; return cmd; } @@ -401,11 +380,7 @@ Command Command::sdiffstore(const std::string& set, const StringVec& sets) { Command cmd("SDIFFSTORE"); - cmd << set; - for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) - { - cmd << *it; - } + cmd << set << sets; return cmd; } @@ -440,11 +415,7 @@ Command Command::sinter(const std::string& set, const StringVec& sets) { Command cmd("SINTER"); - cmd << set; - for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) - { - cmd << *it; - } + cmd << set << sets; return cmd; } @@ -462,11 +433,7 @@ Command Command::sinterstore(const std::string& set, const StringVec& sets) { Command cmd("SINTERSTORE"); - cmd << set; - for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) - { - cmd << *it; - } + cmd << set << sets; return cmd; } @@ -531,11 +498,7 @@ Command Command::srem(const std::string& set, const StringVec& members) { Command cmd("SREM"); - cmd << set; - for(StringVec::const_iterator it = members.begin(); it != members.end(); ++it) - { - cmd << *it; - } + cmd << set << members; return cmd; } @@ -553,11 +516,7 @@ Command Command::sunion(const std::string& set, const StringVec& sets) { Command cmd("SUNION"); - cmd << set; - for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) - { - cmd << *it; - } + cmd << set << sets; return cmd; } @@ -575,11 +534,7 @@ Command Command::sunionstore(const std::string& set, const StringVec& sets) { Command cmd("SUNIONSTORE"); - cmd << set; - for(StringVec::const_iterator it = sets.begin(); it != sets.end(); ++it) - { - cmd << *it; - } + cmd << set << sets; return cmd; } @@ -625,11 +580,7 @@ Command Command::rpush(const std::string& list, const StringVec& values, bool cr { Command cmd(create ? "RPUSH" : "RPUSHX"); - cmd << list; - for(StringVec::const_iterator it = values.begin(); it != values.end(); ++it) - { - cmd << *it; - } + cmd << list << values; return cmd; } From da8adaab39bb502b674672e34515395dd600497a Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 18 Nov 2015 18:57:11 +0100 Subject: [PATCH 099/121] Add testHMGET --- Redis/testsuite/src/RedisTest.cpp | 53 +++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 2 files changed, 54 insertions(+) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index efc31e48c..300654f89 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -618,6 +618,58 @@ void RedisTest::testHKEYS() } } +void RedisTest::testHMGET() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + Command hset = Command::hset("myhash", "field1", "Hello"); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hset = Command::hset("myhash", "field2", "World"); + try + { + Poco::Int64 value = _redis.execute(hset); + assert(value == 1); + } + catch(RedisException &e) + { + fail(e.message()); + } + + std::vector fields; + fields.push_back("field1"); + fields.push_back("field2"); + fields.push_back("field3"); + Command hmget = Command::hmget("myhash", fields); + try + { + Array result = _redis.execute(hmget); + assert(result.size() == 3); + + assert(result.get(0).value().compare("Hello") == 0); + assert(result.get(1).value().compare("World") == 0); + assert(result.get(2).isNull()); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testHSET() { if (!_connected) @@ -2687,6 +2739,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testHGETALL); CppUnit_addTest(pSuite, RedisTest, testHINCRBY); CppUnit_addTest(pSuite, RedisTest, testHKEYS); + CppUnit_addTest(pSuite, RedisTest, testHMGET); CppUnit_addTest(pSuite, RedisTest, testHSET); CppUnit_addTest(pSuite, RedisTest, testINCR); CppUnit_addTest(pSuite, RedisTest, testINCRBY); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index affbd62a7..3119c964c 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -42,6 +42,7 @@ public: void testHGETALL(); void testHINCRBY(); void testHKEYS(); + void testHMGET(); void testHSET(); void testINCR(); void testINCRBY(); From 6e00fac89be2d0edb2f462d5db483c72720d2aae Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 18 Nov 2015 18:58:43 +0100 Subject: [PATCH 100/121] cleanup myotherset in testSMOVE to make the test repeatable --- Redis/testsuite/src/RedisTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 300654f89..85d691c7d 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -1934,6 +1934,7 @@ void RedisTest::testSMOVE() } delKey("myset"); + delKey("myotherset"); Command sadd = Command::sadd("myset", "one"); try From 2f2cb3bfc041b1cb078d362953984e04942ab1d3 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 19:35:56 +0100 Subject: [PATCH 101/121] Add POCO_BUILD for running tests from a build directory. Signed-off-by: FrancisANDRE --- build/script/runtests.sh | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/build/script/runtests.sh b/build/script/runtests.sh index 728c99bb5..3a93dd9fc 100755 --- a/build/script/runtests.sh +++ b/build/script/runtests.sh @@ -22,11 +22,15 @@ # 5/ run the Foundation tests: build/script/runtests.sh Foundation # +TESTRUNNER=./testrunner + if [ "$POCO_BASE" = "" ] ; then POCO_BASE=`pwd` fi -TESTRUNNER=./testrunner +if [ "$POCO_BUILD" = "" ] ; then + POCO_BUILD=$POCO_BASE +fi if [ "$1" = "" ] ; then components=`cat $POCO_BASE/components` @@ -40,21 +44,22 @@ else TESTRUNNERARGS=$2 fi +if [ "$OSARCH" = "" ] ; then + OSARCH=`uname -m | tr ' /' _-` +fi if [ "$OSNAME" = "" ] ; then OSNAME=`uname` case $OSNAME in CYGWIN*) - OSNAME=CYGWIN + OSNAME=Cygwin TESTRUNNER=$TESTRUNNER.exe + PATH=$POCO_BUILD/lib/$OSNAME/$OSARCH:$PATH ;; MINGW*) OSNAME=MinGW ;; esac fi -if [ "$OSARCH" = "" ] ; then - OSARCH=`uname -m | tr ' /' _-` -fi BINDIR="bin/$OSNAME/$OSARCH/" runs=0 @@ -72,8 +77,8 @@ do fi done if [ $excluded -eq 0 ] ; then - if [ -d "$POCO_BASE/$comp/testsuite/$BINDIR" ] ; then - if [ -x "$POCO_BASE/$comp/testsuite/$BINDIR/$TESTRUNNER" ] ; then + if [ -d "$POCO_BUILD/$comp/testsuite/$BINDIR" ] ; then + if [ -x "$POCO_BUILD/$comp/testsuite/$BINDIR/$TESTRUNNER" ] ; then echo "" echo "" echo "****************************************" @@ -82,7 +87,7 @@ do echo "" runs=`expr $runs + 1` - sh -c "cd $POCO_BASE/$comp/testsuite/$BINDIR && $TESTRUNNER $TESTRUNNERARGS" + sh -c "cd $POCO_BUILD/$comp/testsuite/$BINDIR && $TESTRUNNER $TESTRUNNERARGS" if [ $? -ne 0 ] ; then failures=`expr $failures + 1` failedTests="$failedTests $comp" From fd5579cb8c88e36c42a1f54ca7a6aafdc001b509 Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 18 Nov 2015 19:36:46 +0100 Subject: [PATCH 102/121] Add hmset --- Redis/include/Poco/Redis/Command.h | 3 ++ Redis/src/Command.cpp | 13 ++++++++ Redis/testsuite/src/RedisTest.cpp | 50 ++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 67 insertions(+) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 3ccd05653..0b1961b9c 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -99,6 +99,9 @@ public: static Command hmget(const std::string& hash, const StringVec& fields); /// Returns an HMGET command + static Command hmset(const std::string& hash, std::map& fields); + /// Returns a HMSET command + static Command hset(const std::string& hash, const std::string& field, const std::string& value, bool create = true); /// Returns an HSET or HSETNX (when create is false) command diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 3a420ef47..39842b41b 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -188,6 +188,19 @@ Command Command::hmget(const std::string& hash, const StringVec& fields) return cmd; } +Command Command::hmset(const std::string& hash, std::map& fields) +{ + Command cmd("HMSET"); + + cmd << hash; + for(std::map::const_iterator it = fields.begin(); it != fields.end(); ++it) + { + cmd << it->first << it->second; + } + + return cmd; +} + Command Command::hset(const std::string& hash, const std::string& field, const std::string& value, bool create) { Command cmd(create ? "HSET" : "HSETNX"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 85d691c7d..f63648e74 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -703,6 +703,55 @@ void RedisTest::testHSET() } } +void RedisTest::testHMSET() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + std::map fields; + fields.insert(std::make_pair("field1", "Hello")); + fields.insert(std::make_pair("field2", "World")); + + Command hmset = Command::hmset("myhash", fields); + try + { + std::string result = _redis.execute(hmset); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hget = Command::hget("myhash", "field1"); + try + { + BulkString s = _redis.execute(hget); + assert(s.value().compare("Hello") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hget = Command::hget("myhash", "field2"); + try + { + BulkString s = _redis.execute(hget); + assert(s.value().compare("World") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + +} + void RedisTest::testINCR() { if (!_connected) @@ -2741,6 +2790,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testHINCRBY); CppUnit_addTest(pSuite, RedisTest, testHKEYS); CppUnit_addTest(pSuite, RedisTest, testHMGET); + CppUnit_addTest(pSuite, RedisTest, testHMSET); CppUnit_addTest(pSuite, RedisTest, testHSET); CppUnit_addTest(pSuite, RedisTest, testINCR); CppUnit_addTest(pSuite, RedisTest, testINCRBY); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 3119c964c..95a23fc99 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -43,6 +43,7 @@ public: void testHINCRBY(); void testHKEYS(); void testHMGET(); + void testHMSET(); void testHSET(); void testINCR(); void testINCRBY(); From f56ee9c0ac4b292c81953e6572909685ab5dd09f Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 19:56:21 +0100 Subject: [PATCH 103/121] Restore erased return. Signed-off-by: FrancisANDRE --- Data/SQLite/testsuite/src/SQLiteTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Data/SQLite/testsuite/src/SQLiteTest.cpp b/Data/SQLite/testsuite/src/SQLiteTest.cpp index 192e446bf..254474940 100644 --- a/Data/SQLite/testsuite/src/SQLiteTest.cpp +++ b/Data/SQLite/testsuite/src/SQLiteTest.cpp @@ -3573,4 +3573,5 @@ CppUnit::Test* SQLiteTest::suite() // To be fixed by dimanikulin // CppUnit_addTest(pSuite, SQLiteTest, testIncrementVacuum); // + return pSuite; } From f408331525a301547450a64c2c0f56af7711a5ae Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Wed, 18 Nov 2015 19:57:15 +0100 Subject: [PATCH 104/121] Use import libraries for Cygwin. Signed-off-by: FrancisANDRE --- Data/ODBC/ODBC.make | 4 ++++ build/rules/lib | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/Data/ODBC/ODBC.make b/Data/ODBC/ODBC.make index 13c7fc197..031071fb8 100644 --- a/Data/ODBC/ODBC.make +++ b/Data/ODBC/ODBC.make @@ -23,8 +23,12 @@ endif ifeq ($(LINKMODE),STATIC) LIBLINKEXT = .a else +ifeq ($(OSNAME), Cygwin) +LIBLINKEXT = $(IMPLIBLINKEXT) +else LIBLINKEXT = $(SHAREDLIBLINKEXT) endif +endif INCLUDE += -I$(POCO_ODBC_INCLUDE) SYSLIBS += -L$(POCO_ODBC_LIB) diff --git a/build/rules/lib b/build/rules/lib index 8e106b956..c2ae1334b 100644 --- a/build/rules/lib +++ b/build/rules/lib @@ -11,8 +11,10 @@ # ifdef target_version SHL_EXT = $(SHAREDLIBEXT) +IMP_EXT = $(IMPLIBEXT) else SHL_EXT = $(SHAREDLIBLINKEXT) +IMP_EXT = $(IMPLIBLINKEXT) endif LIB_RELEASE_STATIC = $(LIBPATH)/$(LIBPREFIX)$(target).a @@ -22,6 +24,13 @@ LIB_DEBUG_SHARED = $(LIBPATH)/$(LIBPREFIX)$(target)d$(SHL_EXT) LIB_RELEASE_SHARED_LINK = $(LIBPATH)/$(LIBPREFIX)$(target)$(SHAREDLIBLINKEXT) LIB_DEBUG_SHARED_LINK = $(LIBPATH)/$(LIBPREFIX)$(target)d$(SHAREDLIBLINKEXT) +ifeq ($(OSNAME), Cygwin) +IMP_RELEASE_SHARED = $(LIBPATH)/$(IMPPREFIX)$(target)$(OSARCH_POSTFIX)$(IMP_EXT) +IMP_DEBUG_SHARED = $(LIBPATH)/$(IMPPREFIX)$(target)d$(OSARCH_POSTFIX)$(IMP_EXT) +IMP_RELEASE_SHARED_LINK = $(LIBPATH)/$(IMPPREFIX)$(target)$(OSARCH_POSTFIX)$(IMPLIBLINKEXT) +IMP_DEBUG_SHARED_LINK = $(LIBPATH)/$(IMPPREFIX)$(target)d$(OSARCH_POSTFIX)$(IMPLIBLINKEXT) +endif + TARGET_LIBS_DEBUG = $(foreach l,$(target_libs),-l$(l)d) TARGET_LIBS_RELEASE = $(foreach l,$(target_libs),-l$(l)) @@ -62,12 +71,18 @@ $(LIB_RELEASE_STATIC): $(foreach o,$(objects),$(OBJPATH_RELEASE_STATIC)/$(o).o) $(LIB_DEBUG_SHARED): $(foreach o,$(objects),$(OBJPATH_DEBUG_SHARED)/$(o).o) @echo "** Building shared library (debug)" $@ $(SHLIB) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_DEBUG) $(SYSLIBS) +ifeq ($(OSNAME), Cygwin) + $(SHLIBLN) $(IMP_DEBUG_SHARED) $(IMP_DEBUG_SHARED_LINK) +endif $(SHLIBLN) $(LIB_DEBUG_SHARED) $(LIB_DEBUG_SHARED_LINK) $(postbuild) $(LIB_RELEASE_SHARED): $(foreach o,$(objects),$(OBJPATH_RELEASE_SHARED)/$(o).o) @echo "** Building shared library (release)" $@ $(SHLIB) $(SHLIBFLAGS) $^ $(LIBRARY) $(TARGET_LIBS_RELEASE) $(SYSLIBS) +ifeq ($(OSNAME), Cygwin) + $(SHLIBLN) $(IMP_RELEASE_SHARED) $(IMP_RELEASE_SHARED_LINK) +endif $(SHLIBLN) $(LIB_RELEASE_SHARED) $(LIB_RELEASE_SHARED_LINK) $(STRIPCMD) $(postbuild) From 2d10de0c309f4a5d1e38af2ba21e812d872d78bc Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 18 Nov 2015 22:17:13 +0100 Subject: [PATCH 105/121] Add hstrlen (note: only available in Redis 3.2) --- Redis/include/Poco/Redis/Command.h | 3 ++ Redis/src/Command.cpp | 9 +++++ Redis/testsuite/src/RedisTest.cpp | 61 ++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 74 insertions(+) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 0b1961b9c..4db596872 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -108,6 +108,9 @@ public: static Command hset(const std::string& hash, const std::string& field, Int64 value, bool create = true); /// Returns an HSET or HSETNX (when create is false) command + static Command hstrlen(const std::string& hash, const std::string& field); + /// Returns an HSTRLEN command + static Command incr(const std::string& key, Int64 by = 0); /// Returns an INCR or INCRBY command. Calls INCR when by is omitted or zero. diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index 39842b41b..dbd83c728 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -215,6 +215,15 @@ Command Command::hset(const std::string& hash, const std::string& field, Int64 v return hset(hash, field, NumberFormatter::format(value), create); } +Command Command::hstrlen(const std::string& hash, const std::string& field) +{ + Command cmd("HSTRLEN"); + + cmd << hash << field; + + return cmd; +} + Command Command::incr(const std::string& key, Int64 by) { Command cmd(by == 0 ? "INCR" : "INCRBY"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index f63648e74..9aa84b0e6 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -752,6 +752,66 @@ void RedisTest::testHMSET() } +void RedisTest::testHSTRLEN() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + std::map fields; + fields.insert(std::make_pair("f1", "HelloWorld")); + fields.insert(std::make_pair("f2", "99")); + fields.insert(std::make_pair("f3", "-256")); + + Command hmset = Command::hmset("myhash", fields); + try + { + std::string result = _redis.execute(hmset); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hstrlen = Command::hstrlen("myhash", "f1"); + try + { + Poco::Int64 len = _redis.execute(hstrlen); + assert(len == 10); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hstrlen = Command::hstrlen("myhash", "f2"); + try + { + Poco::Int64 len = _redis.execute(hstrlen); + assert(len == 2); + } + catch(RedisException &e) + { + fail(e.message()); + } + + hstrlen = Command::hstrlen("myhash", "f3"); + try + { + Poco::Int64 len = _redis.execute(hstrlen); + assert(len == 4); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testINCR() { if (!_connected) @@ -2792,6 +2852,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testHMGET); CppUnit_addTest(pSuite, RedisTest, testHMSET); CppUnit_addTest(pSuite, RedisTest, testHSET); + //CppUnit_addTest(pSuite, RedisTest, testHSTRLEN); CppUnit_addTest(pSuite, RedisTest, testINCR); CppUnit_addTest(pSuite, RedisTest, testINCRBY); CppUnit_addTest(pSuite, RedisTest, testLINDEX); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 95a23fc99..e70400799 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -45,6 +45,7 @@ public: void testHMGET(); void testHMSET(); void testHSET(); + void testHSTRLEN(); void testINCR(); void testINCRBY(); void testLINDEX(); From bc79fbda81c1ac134e7f77c90de6e41d29cd89a5 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Thu, 19 Nov 2015 08:17:30 +0100 Subject: [PATCH 106/121] Install unbundled dependencies only in the unbundled test env. Signed-off-by: FrancisANDRE --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index dee78f9f5..83b292cc3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then tar -xzvf cmake-3.2.3-Linux-x86_64.tar.gz; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export PATH=$PWD/cmake-3.2.3-Linux-x86_64/bin:$PATH; fi - sudo apt-get update -qq - - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev libpcre3-dev libssl-dev libsqlite3-dev libexpat1-dev + - sudo apt-get install -qq -y unixodbc-dev libmysqlclient-dev libsqlite3-dev - sudo apt-get install -qq -y g++-arm-linux-gnueabi g++-arm-linux-gnueabihf clang-3.5 - sudo apt-get install -qq -y sloccount cppcheck @@ -39,6 +39,7 @@ matrix: - env: TEST_NAME="gcc (make) unbundled" compiler: gcc script: + - sudo libpcre3-dev libssl-dev libexpat1-dev - ./configure --everything --unbundled && make -s -j2 - ./travis/runtests.sh From 9a7a1258e423c7e3ef42dc3f96c2c81057969422 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Thu, 19 Nov 2015 08:26:49 +0100 Subject: [PATCH 107/121] Fix sudo command for unbundled env. Signed-off-by: FrancisANDRE --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 83b292cc3..240684564 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,7 @@ matrix: - env: TEST_NAME="gcc (make) unbundled" compiler: gcc script: - - sudo libpcre3-dev libssl-dev libexpat1-dev + - sudo apt-get install -qq -y libpcre3-dev libssl-dev libexpat1-dev - ./configure --everything --unbundled && make -s -j2 - ./travis/runtests.sh From c734e5cefcd3861a719848c108c31638842e9caa Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Thu, 19 Nov 2015 10:21:19 +0100 Subject: [PATCH 108/121] Use POCO_BUILD instead of POCO_BASE. Add cygPoco*.dll to PATH. Signed-off-by: FrancisANDRE --- PageCompiler/samples/HTTPTimeServer/Makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/PageCompiler/samples/HTTPTimeServer/Makefile b/PageCompiler/samples/HTTPTimeServer/Makefile index 63489e786..b88c5d900 100644 --- a/PageCompiler/samples/HTTPTimeServer/Makefile +++ b/PageCompiler/samples/HTTPTimeServer/Makefile @@ -8,8 +8,13 @@ include $(POCO_BASE)/build/rules/global +# Cygwin Poco*.dll should be on PATH +ifeq ($(OSNAME), CYGWIN) + PATH :=$(LIBPATH):$(PATH) +endif + # Where to find the PageCompiler executable -PAGECOMPILER = $(POCO_BASE)/PageCompiler/bin/$(POCO_HOST_OSNAME)/$(POCO_HOST_OSARCH)/cpspc +PAGECOMPILER = $(POCO_BUILD)/PageCompiler/bin/$(OSNAME)/$(OSARCH)/cpspc objects = HTTPTimeServerApp TimeHandler @@ -20,7 +25,7 @@ target_libs = PocoUtil PocoJSON PocoNet PocoXML PocoFoundation include $(POCO_BASE)/build/rules/exec ifdef POCO_UNBUNDLED - SYSLIBS += -lz -lpcre -lexpat + SYSLIBS += -lz -lpcre -lexpat endif # Rule for runnning PageCompiler From 71ac932a903153beec8a18eb13848edad3179463 Mon Sep 17 00:00:00 2001 From: FrancisANDRE Date: Thu, 19 Nov 2015 10:21:59 +0100 Subject: [PATCH 109/121] Fixup make install for Cygwin. Signed-off-by: FrancisANDRE --- Makefile | 51 ++++++++++++++++++++++++++++++++++++++++++--- build/config/Cygwin | 6 +++++- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 23f1e36df..d47fa3519 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,48 @@ ifndef POCO_BUILD export POCO_BUILD=$(POCO_BASE) endif -LIBPREFIX ?= lib +# +# Determine OS +# +POCO_HOST_OSNAME = $(shell uname) +ifeq ($(findstring CYGWIN,$(POCO_HOST_OSNAME)),CYGWIN) +POCO_HOST_OSNAME = Cygwin +endif + +ifeq ($(findstring MINGW,$(POCO_HOST_OSNAME)),MINGW) +POCO_HOST_OSNAME = MinGW +endif +POCO_HOST_OSARCH ?= $(subst /,-,$(shell uname -m | tr ' ' _)) + +# +# If POCO_CONFIG is not set, use the OS name as configuration name +# +ifndef POCO_CONFIG +POCO_CONFIG = $(POCO_HOST_OSNAME) +endif +#$(info POCO_CONFIG = $(POCO_CONFIG)) + +# +# Include System Specific Settings +# +include $(POCO_BASE)/build/config/$(POCO_CONFIG) + +# +# Determine operating system +# +ifndef POCO_TARGET_OSNAME +OSNAME := $(POCO_HOST_OSNAME) +else +OSNAME := $(POCO_TARGET_OSNAME) +endif +#$(info OSNAME = $(OSNAME)) + +ifndef POCO_TARGET_OSARCH +OSARCH := $(POCO_HOST_OSARCH) +else +OSARCH := $(POCO_TARGET_OSARCH) +endif +#$(info OSARCH = $(OSARCH)) .PHONY: poco all libexecs cppunit tests samples cleans clean distclean install @@ -49,8 +90,12 @@ install: libexecs find $(POCO_BUILD)/$$comp/bin -perm -700 -type f -exec cp -f {} $(INSTALLDIR)/bin \; ; \ fi ; \ done - find $(POCO_BUILD)/lib/$(POCO_TARGET_OSNAME)/$(POCO_TARGET_OSARCH) -name "$(LIBPREFIX)Poco*" -type f -exec cp -f {} $(INSTALLDIR)/lib \; - find $(POCO_BUILD)/lib/$(POCO_TARGET_OSNAME)/$(POCO_TARGET_OSARCH) -name "$(LIBPREFIX)Poco*" -type l -exec cp -Rf {} $(INSTALLDIR)/lib \; +ifeq ($(OSNAME), Cygwin) + find $(POCO_BUILD)/lib/$(OSNAME)/$(OSARCH) -name "cygPoco*" -type f -exec cp -f {} $(INSTALLDIR)/bin \; + find $(POCO_BUILD)/lib/$(OSNAME)/$(OSARCH) -name "cygPoco*" -type l -exec cp -Rf {} $(INSTALLDIR)/bin \; +endif + find $(POCO_BUILD)/lib/$(OSNAME)/$(OSARCH) -name "libPoco*" -type f -exec cp -f {} $(INSTALLDIR)/lib \; + find $(POCO_BUILD)/lib/$(OSNAME)/$(OSARCH) -name "libPoco*" -type l -exec cp -Rf {} $(INSTALLDIR)/lib \; libexecs = Foundation-libexec XML-libexec JSON-libexec Util-libexec Net-libexec Crypto-libexec NetSSL_OpenSSL-libexec Data-libexec Data/SQLite-libexec Data/ODBC-libexec Data/MySQL-libexec MongoDB-libexec Zip-libexec PageCompiler-libexec PageCompiler/File2Page-libexec CppParser-libexec PDF-libexec tests = Foundation-tests XML-tests JSON-tests Util-tests Net-tests Crypto-tests NetSSL_OpenSSL-tests Data-tests Data/SQLite-tests Data/ODBC-tests Data/MySQL-tests MongoDB-tests Zip-tests CppParser-tests PDF-tests diff --git a/build/config/Cygwin b/build/config/Cygwin index 4538cd69f..fe14e1032 100644 --- a/build/config/Cygwin +++ b/build/config/Cygwin @@ -33,9 +33,13 @@ MKDIR = mkdir -p # Extension for Shared Libraries # LIBPREFIX = cyg -SHAREDLIBEXT = .$(target_version).dll +SHAREDLIBEXT = -$(target_version).dll SHAREDLIBLINKEXT = .dll +IMPPREFIX = lib +IMPLIBEXT = -$(target_version).dll.a +IMPLIBLINKEXT = .dll.a + # # Compiler and Linker Flags # From e5d569cc628ec4be6153d0930183a8495ecad4ea Mon Sep 17 00:00:00 2001 From: Francis ANDRE Date: Thu, 19 Nov 2015 15:35:10 +0100 Subject: [PATCH 110/121] Use environment variable POCO_BASE for searching Zip test files. --- Zip/testsuite/src/CompressTest.cpp | 17 ++++++----- Zip/testsuite/src/ZipTest.cpp | 49 ++++++++++++++++-------------- Zip/testsuite/src/ZipTest.h | 2 +- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/Zip/testsuite/src/CompressTest.cpp b/Zip/testsuite/src/CompressTest.cpp index 4af1598f4..41c61f0d5 100644 --- a/Zip/testsuite/src/CompressTest.cpp +++ b/Zip/testsuite/src/CompressTest.cpp @@ -19,6 +19,7 @@ #include "Poco/FileStream.h" #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" +#include #include #undef min #include @@ -40,7 +41,7 @@ CompressTest::~CompressTest() void CompressTest::testSingleFile() { std::ofstream out("appinf.zip", std::ios::binary); - Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Poco::Path theFile(ZipTest::getTestFile("data", "test.zip")); Compress c(out, true); c.addFile(theFile, theFile.getFileName()); ZipArchive a(c.close()); @@ -75,14 +76,14 @@ void CompressTest::testManipulator() { { std::ofstream out("appinf.zip", std::ios::binary); - Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Poco::Path theFile(ZipTest::getTestFile("data", "test.zip")); Compress c(out, true); c.addFile(theFile, theFile.getFileName()); ZipArchive a(c.close()); } ZipManipulator zm("appinf.zip", true); zm.renameFile("test.zip", "renamedtest.zip"); - zm.addFile("doc/othertest.zip", ZipTest::getTestFile("test.zip")); + zm.addFile("doc/othertest.zip", ZipTest::getTestFile("data", "test.zip")); ZipArchive archive=zm.commit(); assert (archive.findHeader("doc/othertest.zip") != archive.headerEnd()); } @@ -92,14 +93,14 @@ void CompressTest::testManipulatorDel() { { std::ofstream out("appinf.zip", std::ios::binary); - Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Poco::Path theFile(ZipTest::getTestFile("data", "test.zip")); Compress c(out, true); c.addFile(theFile, theFile.getFileName()); ZipArchive a(c.close()); } ZipManipulator zm("appinf.zip", true); zm.deleteFile("test.zip"); - zm.addFile("doc/data.zip", ZipTest::getTestFile("data.zip")); + zm.addFile("doc/data.zip", ZipTest::getTestFile("data", "data.zip")); ZipArchive archive=zm.commit(); assert (archive.findHeader("test.zip") == archive.headerEnd()); assert (archive.findHeader("doc/data.zip") != archive.headerEnd()); @@ -110,13 +111,13 @@ void CompressTest::testManipulatorReplace() { { std::ofstream out("appinf.zip", std::ios::binary); - Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Poco::Path theFile(ZipTest::getTestFile("data", "test.zip")); Compress c(out, true); c.addFile(theFile, theFile.getFileName()); ZipArchive a(c.close()); } ZipManipulator zm("appinf.zip", true); - zm.replaceFile("test.zip", ZipTest::getTestFile("doc.zip")); + zm.replaceFile("test.zip", ZipTest::getTestFile("data", "doc.zip")); ZipArchive archive=zm.commit(); assert (archive.findHeader("test.zip") != archive.headerEnd()); @@ -128,7 +129,7 @@ void CompressTest::testSetZipComment() { std::string comment("Testing...123..."); std::ofstream out("comment.zip", std::ios::binary); - Poco::Path theFile(ZipTest::getTestFile("test.zip")); + Poco::Path theFile(ZipTest::getTestFile("data", "test.zip")); Compress c(out, true); c.addFile(theFile, theFile.getFileName()); c.setZipComment(comment); diff --git a/Zip/testsuite/src/ZipTest.cpp b/Zip/testsuite/src/ZipTest.cpp index 41e96a3a5..e56c61bc6 100644 --- a/Zip/testsuite/src/ZipTest.cpp +++ b/Zip/testsuite/src/ZipTest.cpp @@ -27,6 +27,7 @@ #include "CppUnit/TestSuite.h" #undef min #include +#include #include #include @@ -46,7 +47,7 @@ ZipTest::~ZipTest() void ZipTest::testSkipSingleFile() { - std::string testFile = getTestFile("test.zip"); + std::string testFile = getTestFile("data", "test.zip"); std::ifstream inp(testFile.c_str(), std::ios::binary); assert (inp.good()); SkipCallback skip; @@ -68,7 +69,7 @@ void ZipTest::testSkipSingleFile() void ZipTest::testDecompressSingleFile() { - std::string testFile = getTestFile("test.zip"); + std::string testFile = getTestFile("data", "test.zip"); std::ifstream inp(testFile.c_str(), std::ios::binary); assert (inp.good()); ZipArchive arch(inp); @@ -83,7 +84,7 @@ void ZipTest::testDecompressSingleFile() void ZipTest::testDecompressSingleFileInDir() { - std::string testFile = getTestFile("test.zip"); + std::string testFile = getTestFile("data","test.zip"); std::ifstream inp(testFile.c_str(), std::ios::binary); assert (inp.good()); ZipArchive arch(inp); @@ -98,7 +99,7 @@ void ZipTest::testDecompressSingleFileInDir() void ZipTest::testCrcAndSizeAfterData() { - std::string testFile = getTestFile("data.zip"); + std::string testFile = getTestFile("data", "data.zip"); std::ifstream inp(testFile.c_str(), std::ios::binary); assert (inp.good()); Decompress dec(inp, Poco::Path()); @@ -112,7 +113,7 @@ void ZipTest::testCrcAndSizeAfterData() void ZipTest::testCrcAndSizeAfterDataWithArchive() { - std::string testFile = getTestFile("data.zip"); + std::string testFile = getTestFile("data", "data.zip"); std::ifstream inp(testFile.c_str(), std::ios::binary); assert (inp.good()); Poco::Zip::ZipArchive zip(inp); @@ -132,30 +133,34 @@ void ZipTest::testCrcAndSizeAfterDataWithArchive() } -std::string ZipTest::getTestFile(const std::string& testFile) +std::string ZipTest::getTestFile(const std::string& directory, const std::string& file) { - Poco::Path root; - root.makeAbsolute(); - Poco::Path result; - while (!Poco::Path::find(root.toString(), "data", result)) + std::ostringstream ostr; + ostr << directory << '/' << file; + std::string validDir(ostr.str()); + Poco::Path pathPattern(validDir); + if (Poco::File(pathPattern).exists()) { - root.makeParent(); - if (root.toString().empty() || root.toString() == "/") - throw Poco::FileNotFoundException("Didn't find data subdir"); + return validDir; } - result.makeDirectory(); - result.setFileName(testFile); - Poco::File aFile(result.toString()); - if (!aFile.exists() || (aFile.exists() && !aFile.isFile())) - throw Poco::FileNotFoundException("Didn't find " + testFile); - - return result.toString(); + + ostr.str(""); + ostr << "/Zip/testsuite/" << directory << '/' << file; + validDir = Poco::Environment::get("POCO_BASE") + ostr.str(); + pathPattern = validDir; + + if (!Poco::File(pathPattern).exists()) + { + std::cout << "Can't find " << validDir << std::endl; + throw Poco::NotFoundException("cannot locate directory containing valid Zip test files"); + } + return validDir; } void ZipTest::testDecompress() { - std::string testFile = getTestFile("test.zip"); + std::string testFile = getTestFile("data", "test.zip"); std::ifstream inp(testFile.c_str(), std::ios::binary); assert (inp.good()); Decompress dec(inp, Poco::Path()); @@ -169,7 +174,7 @@ void ZipTest::testDecompress() void ZipTest::testDecompressFlat() { - std::string testFile = getTestFile("test.zip"); + std::string testFile = getTestFile("data", "test.zip"); std::ifstream inp(testFile.c_str(), std::ios::binary); assert (inp.good()); Decompress dec(inp, Poco::Path(), true); diff --git a/Zip/testsuite/src/ZipTest.h b/Zip/testsuite/src/ZipTest.h index cfd9b81ae..180b8ed53 100644 --- a/Zip/testsuite/src/ZipTest.h +++ b/Zip/testsuite/src/ZipTest.h @@ -45,7 +45,7 @@ public: static CppUnit::Test* suite(); - static std::string getTestFile(const std::string& testFile); + static std::string getTestFile(const std::string& directory, const std::string& type); private: void onDecompressError(const void* pSender, std::pair& info); From 05703f2f9ff55c9dd199c0b59422eed595aae357 Mon Sep 17 00:00:00 2001 From: fbraem Date: Thu, 19 Nov 2015 18:29:06 +0100 Subject: [PATCH 111/121] Add hvals --- Redis/include/Poco/Redis/Command.h | 5 +++- Redis/src/Command.cpp | 9 +++++++ Redis/testsuite/src/RedisTest.cpp | 40 ++++++++++++++++++++++++++++++ Redis/testsuite/src/RedisTest.h | 1 + 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 4db596872..3ecaed142 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -109,7 +109,10 @@ public: /// Returns an HSET or HSETNX (when create is false) command static Command hstrlen(const std::string& hash, const std::string& field); - /// Returns an HSTRLEN command + /// Returns an HSTRLEN command (Available for Redis 3.2) + + static Command hvals(const std::string& hash); + /// Returns an HVALS command static Command incr(const std::string& key, Int64 by = 0); /// Returns an INCR or INCRBY command. Calls INCR when by is omitted or zero. diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index dbd83c728..e92c86277 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -224,6 +224,15 @@ Command Command::hstrlen(const std::string& hash, const std::string& field) return cmd; } +Command Command::hvals(const std::string& hash) +{ + Command cmd("HVALS"); + + cmd << hash; + + return cmd; +} + Command Command::incr(const std::string& key, Int64 by) { Command cmd(by == 0 ? "INCR" : "INCRBY"); diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 9aa84b0e6..847d55b12 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -812,6 +812,45 @@ void RedisTest::testHSTRLEN() } } +void RedisTest::testHVALS() +{ + if (!_connected) + { + std::cout << "Not connected, test skipped." << std::endl; + return; + } + + delKey("myhash"); + + std::map fields; + fields.insert(std::make_pair("field1", "Hello")); + fields.insert(std::make_pair("field2", "World")); + + Command hmset = Command::hmset("myhash", fields); + try + { + std::string result = _redis.execute(hmset); + assert(result.compare("OK") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } + + Command hvals = Command::hvals("myhash"); + try + { + Array result = _redis.execute(hvals); + assert(result.size() == 2); + assert(result.get(0).value().compare("Hello") == 0); + assert(result.get(1).value().compare("World") == 0); + } + catch(RedisException &e) + { + fail(e.message()); + } +} + void RedisTest::testINCR() { if (!_connected) @@ -2853,6 +2892,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testHMSET); CppUnit_addTest(pSuite, RedisTest, testHSET); //CppUnit_addTest(pSuite, RedisTest, testHSTRLEN); + CppUnit_addTest(pSuite, RedisTest, testHVALS); CppUnit_addTest(pSuite, RedisTest, testINCR); CppUnit_addTest(pSuite, RedisTest, testINCRBY); CppUnit_addTest(pSuite, RedisTest, testLINDEX); diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index e70400799..54c5db9ba 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -46,6 +46,7 @@ public: void testHMSET(); void testHSET(); void testHSTRLEN(); + void testHVALS(); void testINCR(); void testINCRBY(); void testLINDEX(); From e61350553cf4665fba21403663efd809f85b9393 Mon Sep 17 00:00:00 2001 From: fbraem Date: Thu, 19 Nov 2015 18:34:55 +0100 Subject: [PATCH 112/121] Add sample in comment --- Redis/include/Poco/Redis/Command.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Redis/include/Poco/Redis/Command.h b/Redis/include/Poco/Redis/Command.h index 3ecaed142..2c67b871d 100644 --- a/Redis/include/Poco/Redis/Command.h +++ b/Redis/include/Poco/Redis/Command.h @@ -31,9 +31,18 @@ class Redis_API Command : public Array /// Helper class for creating commands. This class contains /// factory methods for commonly used Redis commands. /// There are two ways of building commands: - /// 1. Use this class (which uses option 2 in the factory methods) - /// 2. Use the Array class and build the command using the add method - /// or << operator. + /// 1. Use this class and the factory methods + /// 2. Use the Array or Command class and build the command using the add + /// method or << operator. + /// For example: + /// + /// Command cmd = Command::set("mykey", "Hello"); + /// + /// is the same as: + /// + /// Array cmd; + /// cmd << "SET" << "mykey" << "Hello"; + /// { public: From e973bb4fafd0bdb09b275e7ab250177f9a34112d Mon Sep 17 00:00:00 2001 From: fbraem Date: Thu, 19 Nov 2015 22:12:38 +0100 Subject: [PATCH 113/121] Add getType --- Redis/include/Poco/Redis/Array.h | 6 ++++++ Redis/src/Array.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 5b49ece8d..468671eb6 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -125,6 +125,11 @@ public: throw BadCastException(); } + int getType(size_t pos) const; + /// Returns the type of the element. This can throw a NullValueException + /// when this array is a Null array. An InvalidArgumentException will + /// be thrown when the index is out of range. + bool isNull() const; /// Returns true when this is a Null array. @@ -145,6 +150,7 @@ private: Nullable > _elements; void checkNull(); + /// Checks for null array and sets a new vector if true. }; inline Array& Array::operator<<(const char* s) diff --git a/Redis/src/Array.cpp b/Redis/src/Array.cpp index f4f56754c..961ba3059 100644 --- a/Redis/src/Array.cpp +++ b/Redis/src/Array.cpp @@ -46,6 +46,17 @@ Array& Array::addRedisType(RedisType::Ptr value) } +int Array::getType(size_t pos) const +{ + if ( _elements.isNull() ) throw NullValueException(); + + if ( pos >= _elements.value().size() ) throw InvalidArgumentException(); + + RedisType::Ptr element = _elements.value().at(pos); + return element->type(); +} + + std::string Array::toString() const { return RedisTypeTraits::toString(*this); From 80b7804a98b6c704ce82667f55bc344cad41472e Mon Sep 17 00:00:00 2001 From: fbraem Date: Thu, 19 Nov 2015 22:12:57 +0100 Subject: [PATCH 114/121] Add more comments --- Redis/include/Poco/Redis/Client.h | 19 ++++++++++-- Redis/include/Poco/Redis/Error.h | 8 +++++ Redis/include/Poco/Redis/RedisStream.h | 6 ++++ Redis/include/Poco/Redis/Type.h | 42 ++++++++++++++++++++------ 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 8650ef466..9ea79f3b3 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -54,13 +54,22 @@ class Redis_API Client /// To create Redis commands, the factory methods of the Command class can /// be used or the Array class can be used directly. /// - /// Command llen = Command::llen("list"); + /// Command llen = Command::llen("list"); /// /// is the same as /// - /// Array command; - /// command.add("LLEN").add("list"); + /// Array command; + /// command.add("LLEN").add("list"); /// + /// or + /// + /// Array command; + /// command << "LLEN" << "list"; + /// + /// or even + /// + /// Command command("LLEN"); + /// command << "list"; { public: Client(); @@ -110,9 +119,11 @@ public: T execute(const Array& command) /// Sends the Redis Command to the server. It gets the reply /// and tries to convert it to the given template type. + /// /// A specialization exists for type void, which doesn't read /// the reply. If the server sends a reply, it is your /// responsibility to read it ... (Use this for pipelining) + /// /// A BadCastException will be thrown when the reply couldn't be /// converted. Supported types are Int64, std::string, BulkString, /// Array and void. When the reply is an Error, it will throw @@ -162,6 +173,7 @@ public: /// getting all replies. void setReceiveTimeout(const Timespan& timeout); + /// Sets a receive timeout. private: @@ -173,6 +185,7 @@ private: void connect(); /// Connects to the Redis server + void connect(const Timespan& timeout); /// Connects to the Redis server and sets a timeout. diff --git a/Redis/include/Poco/Redis/Error.h b/Redis/include/Poco/Redis/Error.h index f9464c40c..fd1edc7ce 100644 --- a/Redis/include/Poco/Redis/Error.h +++ b/Redis/include/Poco/Redis/Error.h @@ -24,16 +24,24 @@ namespace Poco { namespace Redis { class Redis_API Error + /// Represent a Redis error { public: Error(); + /// Constructor + Error(const std::string& message); + /// Constructor + virtual ~Error(); + /// Destructor std::string getMessage() const; + /// Returns the error message void setMessage(const std::string& message); + /// Sets the error message private: diff --git a/Redis/include/Poco/Redis/RedisStream.h b/Redis/include/Poco/Redis/RedisStream.h index 5c7a807aa..351b36404 100644 --- a/Redis/include/Poco/Redis/RedisStream.h +++ b/Redis/include/Poco/Redis/RedisStream.h @@ -28,15 +28,21 @@ namespace Poco { namespace Redis { class RedisStreamBuf : public BufferedStreamBuf + /// BufferedStreamBuf for Redis { public: RedisStreamBuf(Net::StreamSocket& redis); + /// Constructor + ~RedisStreamBuf(); + /// Destructor std::string readLine(); + /// Reads a line from Redis (until \r\n is encounterd). protected: int readFromDevice(char* buffer, std::streamsize length); + int writeToDevice(const char* buffer, std::streamsize length); private: diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index 9a930964f..b74c78bea 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -32,37 +32,50 @@ namespace Redis { class Redis_API RedisType + /// Base class for all Redis types. This class makes it possible to store + /// element with different types in Array. { public: + enum Types { + REDIS_INTEGER, // Redis Integer + REDIS_SIMPLE_STRING, // Redis Simple String + REDIS_BULK_STRING, // Redis Bulkstring + REDIS_ARRAY, // Redis Array + REDIS_ERROR // Redis Error + }; + typedef SharedPtr Ptr; RedisType(); + /// Constructor + virtual ~RedisType(); + /// Destructor bool isArray() const; + /// Returns true when the value is a Redis array. bool isBulkString() const; + /// Returns true when the value is a Redis bulkstring. bool isError() const; + /// Returns true when the value is a Redis error. bool isInteger() const; + /// Returns true when the value is a Redis integer (64 bit integer) bool isSimpleString() const; + /// Returns true when the value is a simple string. virtual int type() const = 0; + /// Returns the type of the value. virtual void read(RedisInputStream& input) = 0; + /// Reads the value from the stream. virtual std::string toString() const = 0; - - enum Types { - REDIS_INTEGER, - REDIS_SIMPLE_STRING, - REDIS_BULK_STRING, - REDIS_ARRAY, - REDIS_ERROR - }; + /// Converts the value to a RESP (REdis Serialization Protocol) string. static RedisType::Ptr createRedisType(char marker); /// Create a Redis type based on the marker : @@ -198,46 +211,57 @@ struct RedisTypeTraits template class Type : public RedisType + /// Template class for all Redis types. This class will use + /// RedisTypeTraits structure for calling the type specific code. { public: Type() + /// Constructor { } Type(const T& t) : _value(t) + /// Constructor { } Type(const Type& copy) : _value(copy._value) + /// Copy Constructor { } virtual ~Type() + /// Destructor { } - int type() const + int type() const + /// Returns the type of the value { return RedisTypeTraits::TypeId; } void read(RedisInputStream& socket) + /// Reads the value from the stream (RESP). { RedisTypeTraits::read(socket, _value); } std::string toString() const + /// Converts the value to a string based on the RESP protocol. { return RedisTypeTraits::toString(_value); } T& value() + /// Returns the value { return _value; } const T& value() const + /// Returns a const value { return _value; } From 8bc723443af9986a28dfe7d0a6e5f184b56fa713 Mon Sep 17 00:00:00 2001 From: Franky Braem Date: Fri, 20 Nov 2015 07:56:42 +0100 Subject: [PATCH 115/121] Remove __cxx11 --- Redis/src/Command.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Redis/src/Command.cpp b/Redis/src/Command.cpp index e92c86277..0705b3c48 100644 --- a/Redis/src/Command.cpp +++ b/Redis/src/Command.cpp @@ -323,7 +323,7 @@ Command Command::lset(const std::string& list, Int64 index, const std::string& v return cmd; } -Command Command::ltrim(const std::__cxx11::string& list, Int64 start, Int64 stop) +Command Command::ltrim(const std::string& list, Int64 start, Int64 stop) { Command cmd("LTRIM"); @@ -617,4 +617,4 @@ Command Command::rpush(const std::string& list, const StringVec& values, bool cr } -}} // Poco::Redis \ No newline at end of file +}} // Poco::Redis From c0e548536b428789506525a50492b24a838fe54b Mon Sep 17 00:00:00 2001 From: Franky Braem Date: Fri, 20 Nov 2015 07:58:53 +0100 Subject: [PATCH 116/121] Update comments --- Redis/include/Poco/Redis/Array.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Redis/include/Poco/Redis/Array.h b/Redis/include/Poco/Redis/Array.h index 468671eb6..f42dd4b6b 100644 --- a/Redis/include/Poco/Redis/Array.h +++ b/Redis/include/Poco/Redis/Array.h @@ -59,6 +59,8 @@ public: Array& operator<<(const char* s); /// Special implementation for const char* + /// Note: the specialization creates a BulkString. If you need + /// a simple string, call addSimpleString. Array& operator<<(const std::vector& strings); /// Special implementation for a vector with strings @@ -72,9 +74,6 @@ public: /// Adds an element to the array. /// Note: the specialization for std::string will add a BulkString! /// If you really need a simple string, call addSimpleString. - /// Note: the specialization for std::string will add the string as - /// a BulkString because this is commonly used for representing strings - /// in Redis. If you really need a simple string, use addSimpleString. { addRedisType(new Type(arg)); return *this; @@ -82,6 +81,8 @@ public: Array& add(const char* s); /// Special implementation for const char* + /// Note: the specialization creates a BulkString. If you need + /// a simple string, call addSimpleString. Array& add(const std::vector& strings); /// Special implementation for a vector with strings From df3ed125c3cfec851b2c18a26c7087f00e0bdfe9 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 20 Nov 2015 18:30:53 +0100 Subject: [PATCH 117/121] Documentation correction --- Redis/include/Poco/Redis/RedisStream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Redis/include/Poco/Redis/RedisStream.h b/Redis/include/Poco/Redis/RedisStream.h index 351b36404..c75321368 100644 --- a/Redis/include/Poco/Redis/RedisStream.h +++ b/Redis/include/Poco/Redis/RedisStream.h @@ -38,11 +38,11 @@ public: /// Destructor std::string readLine(); - /// Reads a line from Redis (until \r\n is encounterd). + /// Reads a line from Redis (until \r\n is encountered). protected: int readFromDevice(char* buffer, std::streamsize length); - + int writeToDevice(const char* buffer, std::streamsize length); private: From e336fd7a8b046c3d3c87dcfe59686d2fde24aa89 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 20 Nov 2015 18:31:15 +0100 Subject: [PATCH 118/121] use parse instead of parse64 --- Redis/include/Poco/Redis/Type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Type.h b/Redis/include/Poco/Redis/Type.h index b74c78bea..b926c89a3 100644 --- a/Redis/include/Poco/Redis/Type.h +++ b/Redis/include/Poco/Redis/Type.h @@ -194,7 +194,7 @@ struct RedisTypeTraits value.clear(); std::string line = input.getline(); - int length = NumberParser::parse64(line); + int length = NumberParser::parse(line); if ( length >= 0 ) { From 267cbb7931207507ee1e021cda5ec6fbf40ef80c Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 20 Nov 2015 18:31:33 +0100 Subject: [PATCH 119/121] Add connection pool --- .../Poco/Redis/PoolableConnectionFactory.h | 111 ++++++++++++++++++ Redis/testsuite/src/RedisTest.cpp | 24 ++++ Redis/testsuite/src/RedisTest.h | 2 + 3 files changed, 137 insertions(+) create mode 100644 Redis/include/Poco/Redis/PoolableConnectionFactory.h diff --git a/Redis/include/Poco/Redis/PoolableConnectionFactory.h b/Redis/include/Poco/Redis/PoolableConnectionFactory.h new file mode 100644 index 000000000..2dad8b450 --- /dev/null +++ b/Redis/include/Poco/Redis/PoolableConnectionFactory.h @@ -0,0 +1,111 @@ +// +// PoolableConnectionFactory.h +// +// $Id$ +// +// Library: Redis +// Package: Redis +// Module: PoolableConnectionFactory +// +// Definition of the PoolableConnectionFactory class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Redis_PoolableConnectionFactory_INCLUDED +#define Redis_PoolableConnectionFactory_INCLUDED + + +#include "Poco/Redis/Client.h" +#include "Poco/ObjectPool.h" + + +namespace Poco { + + +template<> +class PoolableObjectFactory + /// PoolableObjectFactory specialisation for Client. New connections + /// are created with the given address. +{ +public: + PoolableObjectFactory(Net::SocketAddress& address) + : _address(address) + { + } + + PoolableObjectFactory(const std::string& address) + : _address(address) + { + } + + Redis::Client::Ptr createObject() + { + return new Redis::Client(_address); + } + + bool validateObject(Redis::Client::Ptr pObject) + { + return true; + } + + void activateObject(Redis::Client::Ptr pObject) + { + } + + void deactivateObject(Redis::Client::Ptr pObject) + { + } + + void destroyObject(Redis::Client::Ptr pObject) + { + } + +private: + Net::SocketAddress _address; +}; + + +namespace Redis { + + +class Redis_API PooledConnection + /// Helper class for borrowing and returning a connection automatically from a pool. +{ +public: + PooledConnection(ObjectPool& pool, long timeoutMilliseconds = 0) : _pool(pool) + { + _client = _pool.borrowObject(timeoutMilliseconds); + } + + virtual ~PooledConnection() + { + try + { + _pool.returnObject(_client); + } + catch (...) + { + poco_unexpected(); + } + } + + operator Client::Ptr () + { + return _client; + } + +private: + ObjectPool& _pool; + Client::Ptr _client; +}; + + +} // namespace Redis +} // namespace Poco + +#endif // Redis_PoolableConnectionFactory_INCLUDED diff --git a/Redis/testsuite/src/RedisTest.cpp b/Redis/testsuite/src/RedisTest.cpp index 847d55b12..e4c61b533 100644 --- a/Redis/testsuite/src/RedisTest.cpp +++ b/Redis/testsuite/src/RedisTest.cpp @@ -17,6 +17,7 @@ #include "RedisTest.h" #include "Poco/Redis/AsyncReader.h" #include "Poco/Redis/Command.h" +#include "Poco/Redis/PoolableConnectionFactory.h" #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" @@ -2852,6 +2853,27 @@ void RedisTest::testRPUSH() } } +void RedisTest::testPool() +{ + Poco::Net::SocketAddress sa(_host, _port); + Poco::PoolableObjectFactory factory(sa); + Poco::ObjectPool pool(factory, 10, 15); + + delKey("mypoolkey"); + + PooledConnection pclient1(pool); + PooledConnection pclient2(pool); + assert(pool.size() == 2); + + Command set = Command::set("mypoolkey", "Hello"); + std::string result = ((Client::Ptr) pclient1)->execute(set); + assert(result.compare("OK") == 0); + + Array get; + get << "GET" << "mypoolkey"; + BulkString keyValue = ((Client::Ptr) pclient2)->execute(get); + assert(keyValue.value().compare("Hello") == 0); +} void RedisTest::delKey(const std::string& key) { @@ -2930,5 +2952,7 @@ CppUnit::Test* RedisTest::suite() CppUnit_addTest(pSuite, RedisTest, testRPOPLPUSH); CppUnit_addTest(pSuite, RedisTest, testRPUSH); + CppUnit_addTest(pSuite, RedisTest, testPool); + return pSuite; } diff --git a/Redis/testsuite/src/RedisTest.h b/Redis/testsuite/src/RedisTest.h index 54c5db9ba..9f55ed389 100644 --- a/Redis/testsuite/src/RedisTest.h +++ b/Redis/testsuite/src/RedisTest.h @@ -84,6 +84,8 @@ public: void testRPOPLPUSH(); void testRPUSH(); + void testPool(); + void setUp(); void tearDown(); From 065ec5c6e90ce2636de3a8bc4ff62ef39bc2b28b Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 20 Nov 2015 18:34:19 +0100 Subject: [PATCH 120/121] Add missing files --- Redis/Redis_x64_vs90.vcproj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Redis/Redis_x64_vs90.vcproj b/Redis/Redis_x64_vs90.vcproj index 4e6e4fd40..592421eef 100644 --- a/Redis/Redis_x64_vs90.vcproj +++ b/Redis/Redis_x64_vs90.vcproj @@ -521,6 +521,10 @@ RelativePath=".\src\Exception.cpp" > + + @@ -557,10 +561,18 @@ RelativePath=".\include\Poco\Redis\Exception.h" > + + + + From 4c239205d2a9fa6169be0cddda75ae6e83671d0d Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 20 Nov 2015 18:34:37 +0100 Subject: [PATCH 121/121] Add typedef for SharedPtr --- Redis/include/Poco/Redis/Client.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Redis/include/Poco/Redis/Client.h b/Redis/include/Poco/Redis/Client.h index 9ea79f3b3..eba4b10f1 100644 --- a/Redis/include/Poco/Redis/Client.h +++ b/Redis/include/Poco/Redis/Client.h @@ -72,6 +72,9 @@ class Redis_API Client /// command << "list"; { public: + + typedef SharedPtr Ptr; + Client(); /// Default constructor. Use this when you want to /// connect later on. @@ -185,7 +188,7 @@ private: void connect(); /// Connects to the Redis server - + void connect(const Timespan& timeout); /// Connects to the Redis server and sets a timeout.