From 0979104127535f192ad4eca835f7e041f4aa3ae2 Mon Sep 17 00:00:00 2001 From: Nathan Osman Date: Tue, 2 Jul 2013 15:26:19 -0700 Subject: [PATCH] Implemented sending of requests in tests and removed dependencies on C++11 features to allow older compilers to compile the client library and test suite. --- CMakeLists.txt | 13 ++-------- README.md | 6 ++--- include/qredis/client.h | 8 +++++- include/qredis/request.h | 54 ++++++++++++++++++---------------------- src/client.cpp | 8 ++++++ src/request.cpp | 23 +++++++++++++++++ src/request_p.h | 13 ++++++++-- tests/testclient.cpp | 8 ++++++ tests/testclient.h | 4 ++- 9 files changed, 89 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e257ee..195a674 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,16 +12,6 @@ set(QREDIS_MINOR 1) set(QREDIS_PATCH 0) set(QREDIS_VERSION "${QREDIS_MAJOR}.${QREDIS_MINOR}.${QREDIS_PATCH}") -# C++11 support must be enabled in GCC. -if(CMAKE_COMPILER_IS_GNUCXX) - # Ensure that we are using at least GCC 4.6+. - if(${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.6) - message(FATAL_ERROR "GCC 4.6+ is required (" ${CMAKE_CXX_COMPILER_VERSION} " detected).") - endif() - # Enable C++11 features. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") -endif() - # The QtCore and QtNetwork libraries are both required. find_package(Qt5Core REQUIRED) find_package(Qt5Network REQUIRED) @@ -38,7 +28,8 @@ set(QREDIS_SRC qt5_wrap_cpp(QREDIS_MOC include/qredis/client.h include/qredis/request.h - src/client_p.h) + src/client_p.h + src/request_p.h) # Create the client library. add_library(qredis SHARED diff --git a/README.md b/README.md index 63e8583..7b9138b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ QRedis provides a modern Qt client library for communicating with a [Redis serve To compile QRedis, the following requirements must be met: -* GCC 4.6+ or Microsoft Visual C++ 2010+ +* GCC or Microsoft Visual C++ * Qt 5+ *It is not necessary to have Redis installed in order to build the client library. However, you will be unable to run the test suite.* @@ -41,10 +41,10 @@ In order to send commands to a Redis server, you need to create an instance of t #include QRedis::Client client; - client.connectToHost(QHostAddress::LocalHost); + client.connectToHost("localhost"); Once the connection is complete, the client will emit the `connected()` signal. You can then begin executing commands. For example, to send the `PING` command: QRedis::Command * command = client.sendCommand("PING"); -The `sendCommand()` method returns a `Command *`, which provides signals to indicate when the command has completed or when an error occurs. \ No newline at end of file +The `sendCommand()` method returns a `Command *`, which provides signals to indicate when the command has completed or when an error occurs. diff --git a/include/qredis/client.h b/include/qredis/client.h index 46fa353..63f8803 100644 --- a/include/qredis/client.h +++ b/include/qredis/client.h @@ -24,13 +24,19 @@ namespace QRedis * @brief Creates a Redis client * @param parent the parent QObject */ - explicit Client(QObject * parent = nullptr); + explicit Client(QObject * parent = 0); /** * @brief Destroys the client */ virtual ~Client(); + /* + * Note: we specifically avoid an overload of connectToHost that + * uses QHostAddress since that would force anyone using the client + * library to use the QtNetwork module, which we wish to avoid. + */ + /** * @brief Attempts to connect to the specified Redis server * @param hostName the hostname of the Redis server diff --git a/include/qredis/request.h b/include/qredis/request.h index 7faae14..f6db126 100644 --- a/include/qredis/request.h +++ b/include/qredis/request.h @@ -4,7 +4,6 @@ #include #include #include -#include #include "qredis_export.h" @@ -13,7 +12,7 @@ namespace QRedis class QREDIS_EXPORT RequestPrivate; /** - * @brief Represents a request and its response + * @brief Represents a request and its reply */ class QREDIS_EXPORT Request : public QObject { @@ -21,48 +20,43 @@ namespace QRedis public: + /** + * @brief Types of replies received from the Redis server + */ + enum ReplyType { + Status, + Error, + Integer, + Bulk, + MultiBulk + }; + /** * @brief Creates a request * @param parent */ - explicit Request(QObject * parent = nullptr); + explicit Request(QObject * parent = 0); /** * @brief Destroys the request */ virtual ~Request(); + /** + * @brief Waits for the reply to be received + * @param msecs the amount of time in milliseconds to wait + * @return true if the reply was received + */ + bool waitForReply(int msecs = 30000); + Q_SIGNALS: /** - * @brief Emitted when a bulk reply is received - * @param value the bulk value + * @brief Emitted when a reply is received + * @param type the type of value received + * @param value the value received */ - void bulk(const QVariant & value); - - /** - * @brief Emitted when an error reply is received - * @param message a descriptive error message - */ - void error(const QString & message); - - /** - * @brief Emitted when an integer reply is received - * @param value the integer value - */ - void integer(qint64 value); - - /** - * @brief Emitted when a multi-bulk reply is received - * @param value the multi-bulk value - */ - void multiBulk(const QVariantList & value); - - /** - * @brief Emitted when a status reply is received - * @param message a descriptive status message - */ - void status(const QString & message); + void reply(ReplyType type, const QVariant & value); private: diff --git a/src/client.cpp b/src/client.cpp index dd885fc..4198d65 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -14,6 +14,14 @@ ClientPrivate::ClientPrivate(Client * client) bool ClientPrivate::readStatusOrError() { + /* Check if the reply contains \r\n. */ + int pos = buffer.indexOf("\r\n"); + if(pos != -1) + { + emit queue.dequeue()->reply(Request::Status, buffer.mid(1, pos - 1)); + buffer.remove(0, pos + 2); + } + return false; } diff --git a/src/request.cpp b/src/request.cpp index 55abb27..d0b88e9 100644 --- a/src/request.cpp +++ b/src/request.cpp @@ -1,8 +1,15 @@ +#include + #include #include "request_p.h" using namespace QRedis; +void RequestPrivate::quitEventLoop() +{ + loop.exit(1); +} + Request::Request(QObject * parent) : QObject(parent), d(new RequestPrivate) { @@ -11,3 +18,19 @@ Request::Request(QObject * parent) Request::~Request() { } + +bool Request::waitForReply(int msecs) +{ + QTimer timer; + timer.setInterval(msecs); + timer.setSingleShot(true); + + connect(&timer, SIGNAL(timeout()), &d->loop, SLOT(quit())); + connect(this, SIGNAL(reply(ReplyType,QVariant)), d.data(), SLOT(quitEventLoop())); + + /* + * If the timer fires, the return value will be 0. + * Otherwise, quitEventLoop() will terminate the loop with 1. + */ + return d->loop.exec(); +} diff --git a/src/request_p.h b/src/request_p.h index 3580e54..e204b69 100644 --- a/src/request_p.h +++ b/src/request_p.h @@ -1,13 +1,22 @@ #ifndef QREDIS_REQUEST_P_H #define QREDIS_REQUEST_P_H +#include +#include + namespace QRedis { - class RequestPrivate + class RequestPrivate : public QObject { + Q_OBJECT + public: - //... + QEventLoop loop; + + public Q_SLOTS: + + void quitEventLoop(); }; } diff --git a/tests/testclient.cpp b/tests/testclient.cpp index c61f860..50d26ed 100644 --- a/tests/testclient.cpp +++ b/tests/testclient.cpp @@ -1,5 +1,7 @@ +#include #include +#include #include "testclient.h" void TestClient::initTestCase() @@ -15,3 +17,9 @@ void TestClient::cleanupTestCase() if(client.isConnected()) QVERIFY(client.waitForDisconnected()); } + +void TestClient::testPing() +{ + QRedis::Request * request = client.sendCommand("PING"); + QVERIFY(request->waitForReply()); +} diff --git a/tests/testclient.h b/tests/testclient.h index 3431a8a..3e6b9d1 100644 --- a/tests/testclient.h +++ b/tests/testclient.h @@ -9,11 +9,13 @@ class TestClient : public QObject { Q_OBJECT - public Q_SLOTS: + private Q_SLOTS: void initTestCase(); void cleanupTestCase(); + void testPing(); + private: QRedis::Client client;