aefd4606f5
Enable Caolan's unit test, pass the proper 'disconnect' message to the Kit so it can close the underlying window / resource for the view. Potentially this also removes 'phantom' users in the user-list which might be another symptom of this issue. Signed-off-by: Michael Meeks <michael.meeks@collabora.com> Change-Id: Ib0d0c5cefa7033fff5827d0a825a932cc12f8323
203 lines
6.2 KiB
C++
203 lines
6.2 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
/*
|
|
* Copyright the Collabora Online contributors.
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* 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 "lokassert.hpp"
|
|
#include "Unit.hpp"
|
|
#include <WopiTestServer.hpp>
|
|
#include <Log.hpp>
|
|
#include <helpers.hpp>
|
|
#include <wsd/ClientSession.hpp>
|
|
|
|
#include <Poco/Net/HTTPRequest.h>
|
|
|
|
#include <chrono>
|
|
|
|
/// This is to test that dropping connection is seen as leaving the document
|
|
class SecondJoinQuit : public WopiTestServer
|
|
{
|
|
STATE_ENUM(Phase, LoadUser1, WaitUser1Loaded, User1Loaded, LoadUser2, WaitUser2Loaded, User2Loaded, DropUser2, ModifyDoc, Done) _phase;
|
|
|
|
bool _earlyQuit;
|
|
|
|
std::size_t _checkFileInfoCount;
|
|
std::size_t _viewCount;
|
|
std::size_t _viewsActive;
|
|
|
|
public:
|
|
SecondJoinQuit(const std::string& name, bool earlyQuit)
|
|
: WopiTestServer(name)
|
|
, _phase(Phase::LoadUser1)
|
|
, _earlyQuit(earlyQuit)
|
|
, _checkFileInfoCount(0)
|
|
, _viewCount(0)
|
|
, _viewsActive(0)
|
|
{
|
|
}
|
|
|
|
void configCheckFileInfo(const Poco::Net::HTTPRequest& /*request*/,
|
|
Poco::JSON::Object::Ptr& fileInfo) override
|
|
{
|
|
const bool firstView = _checkFileInfoCount++ == 0;
|
|
|
|
LOG_TST("CheckFileInfo: " << (firstView ? "User#1" : "User#2"));
|
|
|
|
fileInfo->set("UserCanWrite", "true");
|
|
}
|
|
|
|
bool onFilterSendWebSocketMessage(const char* data, const std::size_t len,
|
|
const WSOpCode /* code */, const bool /* flush */,
|
|
int& /*unitReturn*/) override
|
|
{
|
|
const std::string message(data, len);
|
|
|
|
if (message.starts_with("viewinfo:"))
|
|
{
|
|
Poco::JSON::Parser parser0;
|
|
Poco::JSON::Array::Ptr array = parser0.parse(message.substr(9)).extract<Poco::JSON::Array::Ptr>();
|
|
_viewsActive = array->size();
|
|
if (_phase == Phase::Done && _viewsActive == 1)
|
|
passTest("View disconnection seen");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void onDocBrokerViewLoaded(const std::string&,
|
|
const std::shared_ptr<ClientSession>& session) override
|
|
{
|
|
LOG_TST("View #" << _viewCount + 1 << " [" << session->getName() << "] loaded");
|
|
|
|
++_viewCount;
|
|
|
|
if (_viewCount == 1 && _phase == Phase::WaitUser1Loaded)
|
|
TRANSITION_STATE(_phase, Phase::User1Loaded);
|
|
|
|
if (_viewCount == 2 && _phase == Phase::WaitUser2Loaded)
|
|
TRANSITION_STATE(_phase, Phase::User2Loaded);
|
|
}
|
|
|
|
void invokeWSDTest() override
|
|
{
|
|
switch (_phase)
|
|
{
|
|
case Phase::LoadUser1:
|
|
{
|
|
// Always transition before issuing commands.
|
|
TRANSITION_STATE(_phase, Phase::WaitUser1Loaded);
|
|
|
|
LOG_TST("Creating first connection");
|
|
initWebsocket("/wopi/files/0?access_token=anything");
|
|
|
|
LOG_TST("Loading first view");
|
|
WSD_CMD_BY_CONNECTION_INDEX(0, "load url=" + getWopiSrc());
|
|
break;
|
|
}
|
|
case Phase::User1Loaded:
|
|
{
|
|
TRANSITION_STATE(_phase, Phase::LoadUser2);
|
|
break;
|
|
}
|
|
case Phase::LoadUser2:
|
|
{
|
|
if (!_earlyQuit)
|
|
{
|
|
// normal case, user 2 loads then then quits after
|
|
// they have joined
|
|
TRANSITION_STATE(_phase, Phase::WaitUser2Loaded);
|
|
}
|
|
else
|
|
{
|
|
// abnormal case, user 2 loses connection right
|
|
// after launching their load
|
|
TRANSITION_STATE(_phase, Phase::DropUser2);
|
|
}
|
|
|
|
LOG_TST("Creating second connection");
|
|
addWebSocket();
|
|
|
|
LOG_TST("Loading second view");
|
|
WSD_CMD_BY_CONNECTION_INDEX(1, "load url=" + getWopiSrc());
|
|
break;
|
|
}
|
|
case Phase::User2Loaded:
|
|
{
|
|
TRANSITION_STATE(_phase, Phase::DropUser2);
|
|
break;
|
|
}
|
|
case Phase::DropUser2:
|
|
{
|
|
TRANSITION_STATE(_phase, Phase::ModifyDoc);
|
|
|
|
LOG_TST("Disconnecting first view right after load start");
|
|
deleteSocketAt(1);
|
|
break;
|
|
}
|
|
case Phase::ModifyDoc:
|
|
{
|
|
TRANSITION_STATE(_phase, Phase::Done);
|
|
|
|
// Modify the document.
|
|
LOG_TST("Modifying");
|
|
WSD_CMD_BY_CONNECTION_INDEX(0, "key type=input char=97 key=0");
|
|
WSD_CMD_BY_CONNECTION_INDEX(0, "key type=up char=0 key=512");
|
|
break;
|
|
}
|
|
case Phase::WaitUser1Loaded:
|
|
case Phase::WaitUser2Loaded:
|
|
case Phase::Done:
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
class SecondJoinQuitNormal : public SecondJoinQuit
|
|
{
|
|
public:
|
|
SecondJoinQuitNormal()
|
|
: SecondJoinQuit("SecondJoinQuitNormal", false)
|
|
{
|
|
}
|
|
};
|
|
|
|
/* In this case, we are currently failing.
|
|
|
|
We have one user connected, the 2nd user join, and immediately drop
|
|
connection after "load" is dispatched. While in the normal case we wait
|
|
until the 2nd user join has completed, and then close the connection.
|
|
|
|
In both cases we receive:
|
|
|
|
ToClient-007: Send: [viewinfo: [{"id":4,...},
|
|
{"id":5,...}]]| common/Session.cpp:62
|
|
|
|
so two users are seen as joined, but in the 2nd case we don't get a
|
|
follow up indicating that the 2nd user has dropped.
|
|
*/
|
|
class SecondJoinQuitEarly : public SecondJoinQuit
|
|
{
|
|
public:
|
|
SecondJoinQuitEarly()
|
|
: SecondJoinQuit("SecondJoinQuitNormal", true)
|
|
{
|
|
}
|
|
};
|
|
|
|
UnitBase** unit_create_wsd_multi(void)
|
|
{
|
|
return new UnitBase* [3]
|
|
{
|
|
new SecondJoinQuitNormal(), new SecondJoinQuitEarly(), nullptr
|
|
};
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|