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
@mhoran mhoran authored
View
24 lib/capybara/webkit/browser.rb
@@ -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
View
72 spec/driver_spec.rb
@@ -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("/")
View
2  src/CommandFactory.cpp
@@ -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"
View
12 src/Connection.cpp
@@ -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() {
View
2  src/Connection.h
@@ -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();
View
9 src/GetTimeout.cpp
@@ -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())));
+}
View
11 src/GetTimeout.h
@@ -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();
+};
View
19 src/SetTimeout.cpp
@@ -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")));
+ }
+}
+
View
9 src/SetTimeout.h
@@ -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();
+};
View
59 src/TimeoutCommand.cpp
@@ -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);
+}
+
View
41 src/TimeoutCommand.h
@@ -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;
+};
+
View
10 src/WebPageManager.cpp
@@ -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();
View
3  src/WebPageManager.h
@@ -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
View
3  src/find_command.h
@@ -39,3 +39,6 @@ CHECK_COMMAND(ClearPromptText)
CHECK_COMMAND(JavascriptAlertMessages)
CHECK_COMMAND(JavascriptConfirmMessages)
CHECK_COMMAND(JavascriptPromptMessages)
+CHECK_COMMAND(GetTimeout)
+CHECK_COMMAND(SetTimeout)
+
View
6 src/webkit_server.pro
@@ -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.