Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Revert "Revert "Add configurable timeouts to commands.""

This reverts commit b1b3a4c.
  • Loading branch information...
commit cbb58d05f1608817539c963c9c39fc9b324f1203 1 parent b1b3a4c
Matthew Horan mhoran authored
24 lib/capybara/webkit/browser.rb
View
@@ -165,6 +165,14 @@ def render(path, width, height)
command "Render", path, width, height
end
+ def timeout=(timeout_in_seconds)
+ command "SetTimeout", timeout_in_seconds
+ end
+
+ def timeout
+ command("GetTimeout").to_i
+ end
+
def set_cookie(cookie)
command "SetCookie", cookie
end
@@ -199,12 +207,26 @@ def check
if result.nil?
raise NoResponseError, "No response received from the server."
elsif result != 'ok'
- raise InvalidResponseError, read_response
+ case response = read_response
+ when "timeout"
+ raise Capybara::TimeoutError, "Request timed out after #{timeout_seconds}"
+ else
+ raise InvalidResponseError, response
+ end
end
result
end
+ def timeout_seconds
+ seconds = timeout
+ if seconds > 1
+ "#{seconds} seconds"
+ else
+ "1 second"
+ end
+ end
+
def read_response
response_length = @connection.gets.to_i
if response_length > 0
72 spec/driver_spec.rb
View
@@ -1825,6 +1825,78 @@ def which_for(character)
end
end
+ describe "timeout for long requests" do
+ let(:driver) do
+ driver_for_app do
+ html = <<-HTML
+ <html>
+ <body>
+ <form action="/form" method="post">
+ <input type="submit" value="Submit"/>
+ </form>
+ </body>
+ </html>
+ HTML
+
+ get "/" do
+ sleep(2)
+ html
+ end
+
+ post "/form" do
+ sleep(4)
+ html
+ end
+ end
+ end
+
+ it "should not raise a timeout error when zero" do
+ driver.browser.timeout = 0
+ lambda { driver.visit("/") }.should_not raise_error(Capybara::TimeoutError)
+ end
+
+ it "should raise a timeout error" do
+ driver.browser.timeout = 1
+ lambda { driver.visit("/") }.should raise_error(Capybara::TimeoutError, "Request timed out after 1 second")
+ end
+
+ it "should not raise an error when the timeout is high enough" do
+ driver.browser.timeout = 10
+ lambda { driver.visit("/") }.should_not raise_error(Capybara::TimeoutError)
+ end
+
+ it "should set the timeout for each request" do
+ driver.browser.timeout = 10
+ lambda { driver.visit("/") }.should_not raise_error(Capybara::TimeoutError)
+ driver.browser.timeout = 1
+ lambda { driver.visit("/") }.should raise_error(Capybara::TimeoutError)
+ end
+
+ it "should set the timeout for each request" do
+ driver.browser.timeout = 1
+ lambda { driver.visit("/") }.should raise_error(Capybara::TimeoutError)
+ driver.reset!
+ driver.browser.timeout = 10
+ lambda { driver.visit("/") }.should_not raise_error(Capybara::TimeoutError)
+ end
+
+ it "should raise a timeout on a slow form" do
+ driver.browser.timeout = 3
+ driver.visit("/")
+ driver.status_code.should == 200
+ driver.browser.timeout = 1
+ driver.find("//input").first.click
+ lambda { driver.status_code }.should raise_error(Capybara::TimeoutError)
+ end
+
+ it "get timeout" do
+ driver.browser.timeout = 10
+ driver.browser.timeout.should == 10
+ driver.browser.timeout = 3
+ driver.browser.timeout.should == 3
+ end
+ end
+
describe "logger app" do
it "logs nothing before turning on the logger" do
driver.visit("/")
2  src/CommandFactory.cpp
View
@@ -22,6 +22,8 @@
#include "ConsoleMessages.h"
#include "RequestedUrl.h"
#include "CurrentUrl.h"
+#include "SetTimeout.h"
+#include "GetTimeout.h"
#include "ResizeWindow.h"
#include "IgnoreSslErrors.h"
#include "SetSkipImageLoading.h"
12 src/Connection.cpp
View
@@ -4,6 +4,7 @@
#include "CommandParser.h"
#include "CommandFactory.h"
#include "PageLoadingCommand.h"
+#include "TimeoutCommand.h"
#include "SocketCommand.h"
#include <QTcpSocket>
@@ -24,18 +25,14 @@ Connection::Connection(QTcpSocket *socket, WebPageManager *manager, QObject *par
void Connection::commandReady(Command *command) {
m_queuedCommand = command;
m_manager->logger() << "Received" << command->toString();
- if (m_manager->isLoading()) {
- m_manager->logger() << command->toString() << "waiting for load to finish";
- m_commandWaiting = true;
- } else {
- startCommand();
- }
+ startCommand();
}
void Connection::startCommand() {
m_commandWaiting = false;
if (m_pageSuccess) {
m_runningCommand = new PageLoadingCommand(m_queuedCommand, m_manager, this);
+ m_runningCommand = new TimeoutCommand(m_runningCommand, m_manager, this);
connect(m_runningCommand, SIGNAL(finished(Response *)), this, SLOT(finishCommand(Response *)));
m_runningCommand->start();
} else {
@@ -45,9 +42,6 @@ void Connection::startCommand() {
void Connection::pendingLoadFinished(bool success) {
m_pageSuccess = m_pageSuccess && success;
- if (m_commandWaiting) {
- startCommand();
- }
}
void Connection::writePageLoadFailure() {
2  src/Connection.h
View
@@ -31,7 +31,7 @@ class Connection : public QObject {
WebPageManager *m_manager;
CommandParser *m_commandParser;
CommandFactory *m_commandFactory;
- PageLoadingCommand *m_runningCommand;
+ Command *m_runningCommand;
bool m_pageSuccess;
bool m_commandWaiting;
WebPage *currentPage();
9 src/GetTimeout.cpp
View
@@ -0,0 +1,9 @@
+#include "GetTimeout.h"
+#include "WebPageManager.h"
+
+GetTimeout::GetTimeout(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
+}
+
+void GetTimeout::start() {
+ emit finished(new Response(true, QString::number(manager()->getTimeout())));
+}
11 src/GetTimeout.h
View
@@ -0,0 +1,11 @@
+#include "SocketCommand.h"
+
+class WebPageManager;
+
+class GetTimeout : public SocketCommand {
+ Q_OBJECT;
+
+ public:
+ GetTimeout(WebPageManager *page, QStringList &arguments, QObject *parent = 0);
+ virtual void start();
+};
19 src/SetTimeout.cpp
View
@@ -0,0 +1,19 @@
+#include "SetTimeout.h"
+#include "WebPageManager.h"
+
+SetTimeout::SetTimeout(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
+}
+
+void SetTimeout::start() {
+ QString timeoutString = arguments()[0];
+ bool ok;
+ int timeout = timeoutString.toInt(&ok);
+
+ if (ok) {
+ manager()->setTimeout(timeout);
+ emit finished(new Response(true));
+ } else {
+ emit finished(new Response(false, QString("Invalid value for timeout")));
+ }
+}
+
9 src/SetTimeout.h
View
@@ -0,0 +1,9 @@
+#include "SocketCommand.h"
+
+class SetTimeout : public SocketCommand {
+ Q_OBJECT
+
+ public:
+ SetTimeout(WebPageManager *manager, QStringList &arguments, QObject *parent = 0);
+ virtual void start();
+};
59 src/TimeoutCommand.cpp
View
@@ -0,0 +1,59 @@
+#include "TimeoutCommand.h"
+#include "Command.h"
+#include "WebPageManager.h"
+#include "WebPage.h"
+#include <QTimer>
+
+TimeoutCommand::TimeoutCommand(Command *command, WebPageManager *manager, QObject *parent) : Command(parent) {
+ m_command = command;
+ m_manager = manager;
+ m_timer = new QTimer(this);
+ m_timer->setSingleShot(true);
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(commandTimeout()));
+ connect(m_manager, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
+}
+
+void TimeoutCommand::start() {
+ if (m_manager->isLoading()) {
+ connect(m_manager, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
+ startTimeout();
+ } else {
+ startCommand();
+ }
+}
+
+void TimeoutCommand::startCommand() {
+ connect(m_command, SIGNAL(finished(Response *)), this, SLOT(commandFinished(Response *)));
+ m_command->start();
+}
+
+void TimeoutCommand::startTimeout() {
+ int timeout = m_manager->getTimeout();
+ if (timeout > 0) {
+ m_timer->start(timeout * 1000);
+ }
+}
+
+void TimeoutCommand::pendingLoadFinished(bool success) {
+ if (success) {
+ startCommand();
+ } else {
+ emit finished(new Response(false, m_manager->currentPage()->failureString()));
+ }
+}
+
+void TimeoutCommand::pageLoadingFromCommand() {
+ startTimeout();
+}
+
+void TimeoutCommand::commandTimeout() {
+ m_manager->currentPage()->triggerAction(QWebPage::Stop);
+ m_command->deleteLater();
+ emit finished(new Response(false, QString("timeout")));
+}
+
+void TimeoutCommand::commandFinished(Response *response) {
+ m_command->deleteLater();
+ emit finished(response);
+}
+
41 src/TimeoutCommand.h
View
@@ -0,0 +1,41 @@
+#include "Command.h"
+#include <QObject>
+#include <QStringList>
+
+class Response;
+class WebPageManager;
+class QTimer;
+
+/* Decorates a command with a timeout.
+ *
+ * If the timeout, using a QTimer is reached before
+ * the command is finished, the load page load will
+ * be stopped and failure response will be issued.
+ *
+ */
+class TimeoutCommand : public Command {
+ Q_OBJECT
+
+ public:
+ TimeoutCommand(Command *command, WebPageManager *page, QObject *parent = 0);
+ virtual void start();
+
+ public slots:
+ void commandTimeout();
+ void commandFinished(Response *response);
+ void pageLoadingFromCommand();
+ void pendingLoadFinished(bool);
+
+ signals:
+ void finished(Response *response);
+
+ protected:
+ void startCommand();
+ void startTimeout();
+
+ private:
+ WebPageManager *m_manager;
+ QTimer *m_timer;
+ Command *m_command;
+};
+
10 src/WebPageManager.cpp
View
@@ -8,6 +8,7 @@ WebPageManager::WebPageManager(QObject *parent) : QObject(parent) {
m_success = true;
m_loggingEnabled = false;
m_ignoredOutput = new QString();
+ m_timeout = -1;
createPage(this)->setFocus();
}
@@ -85,7 +86,16 @@ bool WebPageManager::ignoreSslErrors() {
return m_ignoreSslErrors;
}
+int WebPageManager::getTimeout() {
+ return m_timeout;
+}
+
+void WebPageManager::setTimeout(int timeout) {
+ m_timeout = timeout;
+}
+
void WebPageManager::reset() {
+ m_timeout = -1;
m_cookieJar->clearCookies();
m_pages.first()->deleteLater();
m_pages.clear();
3  src/WebPageManager.h
View
@@ -22,6 +22,8 @@ class WebPageManager : public QObject {
WebPage *createPage(QObject *parent);
void setIgnoreSslErrors(bool);
bool ignoreSslErrors();
+ void setTimeout(int);
+ int getTimeout();
void reset();
NetworkCookieJar *cookieJar();
bool isLoading() const;
@@ -50,6 +52,7 @@ class WebPageManager : public QObject {
bool m_success;
bool m_loggingEnabled;
QString *m_ignoredOutput;
+ int m_timeout;
};
#endif // _WEBPAGEMANAGER_H
3  src/find_command.h
View
@@ -39,3 +39,6 @@ CHECK_COMMAND(ClearPromptText)
CHECK_COMMAND(JavascriptAlertMessages)
CHECK_COMMAND(JavascriptConfirmMessages)
CHECK_COMMAND(JavascriptPromptMessages)
+CHECK_COMMAND(GetTimeout)
+CHECK_COMMAND(SetTimeout)
+
6 src/webkit_server.pro
View
@@ -53,6 +53,9 @@ HEADERS = \
WindowFocus.h \
GetWindowHandles.h \
GetWindowHandle.h \
+ GetTimeout.h \
+ SetTimeout.h \
+ TimeoutCommand.h \
SOURCES = \
EnableLogging.cpp \
@@ -102,11 +105,14 @@ SOURCES = \
SetProxy.cpp \
NullCommand.cpp \
PageLoadingCommand.cpp \
+ SetTimeout.cpp \
+ GetTimeout.cpp \
SetSkipImageLoading.cpp \
WebPageManager.cpp \
WindowFocus.cpp \
GetWindowHandles.cpp \
GetWindowHandle.cpp \
+ TimeoutCommand.cpp \
RESOURCES = webkit_server.qrc
QT += network webkit
Please sign in to comment.
Something went wrong with that request. Please try again.