libreoffice-online/loolwsd/test/httpcrashtest.cpp
Ashod Nakashian a805b06874 loolwsd: fix unittest regressions
Change-Id: I502c87a2c6eb3d34c0e137c774c1c77bec8f50d9
Reviewed-on: https://gerrit.libreoffice.org/28144
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-08-15 12:12:39 +00:00

255 lines
7.7 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "config.h"
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <cstring>
#include <Poco/DirectoryIterator.h>
#include <Poco/Dynamic/Var.h>
#include <Poco/FileStream.h>
#include <Poco/JSON/JSON.h>
#include <Poco/JSON/Parser.h>
#include <Poco/Net/AcceptCertificateHandler.h>
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/Net/HTTPSClientSession.h>
#include <Poco/Net/InvalidCertificateHandler.h>
#include <Poco/Net/NetException.h>
#include <Poco/Net/PrivateKeyPassphraseHandler.h>
#include <Poco/Net/SSLManager.h>
#include <Poco/Net/Socket.h>
#include <Poco/Net/WebSocket.h>
#include <Poco/Path.h>
#include <Poco/StreamCopier.h>
#include <Poco/StringTokenizer.h>
#include <Poco/Thread.h>
#include <Poco/URI.h>
#include <cppunit/extensions/HelperMacros.h>
#include <Common.hpp>
#include <UserMessages.hpp>
#include <Util.hpp>
#include <LOOLProtocol.hpp>
#include "helpers.hpp"
#include "countloolkits.hpp"
using namespace helpers;
/// Tests the HTTP WebSocket API of loolwsd. The server has to be started manually before running this test.
class HTTPCrashTest : public CPPUNIT_NS::TestFixture
{
const Poco::URI _uri;
Poco::Net::HTTPResponse _response;
static int InitialLoolKitCount;
CPPUNIT_TEST_SUITE(HTTPCrashTest);
CPPUNIT_TEST(testBarren);
CPPUNIT_TEST(testCrashKit);
CPPUNIT_TEST_SUITE_END();
void testCountHowManyLoolkits();
void testBarren();
void testCrashKit();
void testNoExtraLoolKitsLeft();
static
void killLoKitProcesses();
public:
HTTPCrashTest()
: _uri(helpers::getTestServerURI())
{
#if ENABLE_SSL
Poco::Net::initializeSSL();
// Just accept the certificate anyway for testing purposes
Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> invalidCertHandler = new Poco::Net::AcceptCertificateHandler(false);
Poco::Net::Context::Params sslParams;
Poco::Net::Context::Ptr sslContext = new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, sslParams);
Poco::Net::SSLManager::instance().initializeClient(0, invalidCertHandler, sslContext);
#endif
}
#if ENABLE_SSL
~HTTPCrashTest()
{
Poco::Net::uninitializeSSL();
}
#endif
void setUp()
{
testCountHowManyLoolkits();
}
void tearDown()
{
testNoExtraLoolKitsLeft();
}
};
int HTTPCrashTest::InitialLoolKitCount = 1;
void HTTPCrashTest::testCountHowManyLoolkits()
{
InitialLoolKitCount = countLoolKitProcesses(InitialLoolKitCount);
CPPUNIT_ASSERT(InitialLoolKitCount > 0);
}
void HTTPCrashTest::testNoExtraLoolKitsLeft()
{
const auto countNow = countLoolKitProcesses(InitialLoolKitCount);
CPPUNIT_ASSERT_EQUAL(InitialLoolKitCount, countNow);
}
void HTTPCrashTest::testBarren()
{
// Kill all kit processes and try loading a document.
try
{
killLoKitProcesses();
countLoolKitProcesses(0);
std::cerr << "Loading after kill." << std::endl;
// Load a document and get its status.
std::string documentPath, documentURL;
getDocumentPathAndURL("hello.odt", documentPath, documentURL);
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, documentURL);
auto socket = connectLOKit(_uri, request, _response);
// First load should fail.
sendTextFrame(socket, "load url=" + documentURL);
SocketProcessor("Barren ", socket, [&](const std::string& msg)
{
const std::string prefix = "status: ";
if (msg.find(prefix) == 0)
{
const auto status = msg.substr(prefix.length());
CPPUNIT_ASSERT_EQUAL(std::string("type=text parts=1 current=0 width=12808 height=16408 viewid=0"), status);
return false;
}
else if (msg.find("Service") == 0)
{
// Service unavailable. Try again.
auto socket2 = loadDocAndGetSocket(_uri, documentURL);
sendTextFrame(socket2, "status");
const auto status = getResponseLine(socket2, "status");
CPPUNIT_ASSERT_EQUAL(std::string("type=text parts=1 current=0 width=12808 height=16408"), status);
return false;
}
return true;
});
}
catch (const Poco::Exception& exc)
{
CPPUNIT_FAIL(exc.displayText());
}
}
void HTTPCrashTest::testCrashKit()
{
try
{
// Load a document and get its status.
std::string documentPath, documentURL;
getDocumentPathAndURL("hello.odt", documentPath, documentURL);
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, documentURL);
auto socket = *connectLOKit(_uri, request, _response);
sendTextFrame(socket, "load url=" + documentURL);
CPPUNIT_ASSERT_MESSAGE("cannot load the document " + documentURL, isDocumentLoaded(socket));
killLoKitProcesses();
std::cerr << "Reading after kill." << std::endl;
// 5 seconds timeout
socket.setReceiveTimeout(5000000);
// receive close frame handshake
int bytes;
int flags;
char buffer[READ_BUFFER_SIZE];
do
{
bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
}
while ((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE);
// respond close frame
socket.shutdown();
// no more messages is received.
bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
CPPUNIT_ASSERT_EQUAL(0, bytes);
CPPUNIT_ASSERT_EQUAL(0, flags);
}
catch (const Poco::Exception& exc)
{
CPPUNIT_FAIL(exc.displayText());
}
}
void HTTPCrashTest::killLoKitProcesses()
{
// Crash all lokit processes.
for (auto it = Poco::DirectoryIterator(std::string("/proc")); it != Poco::DirectoryIterator(); ++it)
{
try
{
Poco::Path procEntry = it.path();
const std::string& fileName = procEntry.getFileName();
int pid;
std::size_t endPos = 0;
try
{
pid = std::stoi(fileName, &endPos);
}
catch (const std::invalid_argument&)
{
pid = 0;
}
if (pid > 1 && endPos == fileName.length())
{
Poco::FileInputStream stat(procEntry.toString() + "/stat");
std::string statString;
Poco::StreamCopier::copyToString(stat, statString);
Poco::StringTokenizer tokens(statString, " ");
if (tokens.count() > 3 && tokens[1] == "(loolkit)")
{
std::cerr << "Killing " << pid << std::endl;
if (kill(pid, SIGKILL) == -1)
{
std::cerr << "kill(" << pid << ",SIGKILL) failed: " << std::strerror(errno) << std::endl;
}
}
}
}
catch (const Poco::Exception&)
{
}
}
countLoolKitProcesses(0);
}
CPPUNIT_TEST_SUITE_REGISTRATION(HTTPCrashTest);
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */