7183a3d3de
Change-Id: Ice934380029bf27054e830fffc07a5d037d1430f Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
316 lines
8 KiB
C++
316 lines
8 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 <algorithm>
|
|
#include <condition_variable>
|
|
#include <mutex>
|
|
#include <thread>
|
|
#include <regex>
|
|
#include <vector>
|
|
|
|
#include <test/lokassert.hpp>
|
|
|
|
#include <cppunit/BriefTestProgressListener.h>
|
|
#include <cppunit/CompilerOutputter.h>
|
|
#include <cppunit/TestResult.h>
|
|
#include <cppunit/TestResultCollector.h>
|
|
#include <cppunit/TestRunner.h>
|
|
#include <cppunit/TextTestProgressListener.h>
|
|
#include <cppunit/extensions/HelperMacros.h>
|
|
#include <cppunit/extensions/TestFactoryRegistry.h>
|
|
|
|
#undef MOBILEAPP
|
|
#define MOBILEAPP 1 // A bit ugly, but currently FakeSocket.hpp is surrounded by a MOBILEAPP ifdef,
|
|
// and probably it is not a good idea to remove that?
|
|
#include "FakeSocket.hpp"
|
|
|
|
bool EnableExperimental = false;
|
|
|
|
class FakeSocketTest : public CPPUNIT_NS::TestFixture
|
|
{
|
|
CPPUNIT_TEST_SUITE(FakeSocketTest);
|
|
|
|
CPPUNIT_TEST(testBasic);
|
|
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
void testBasic();
|
|
|
|
public:
|
|
FakeSocketTest()
|
|
{
|
|
}
|
|
|
|
void setUp()
|
|
{
|
|
fakeSocketSetLoggingCallback([](const std::string& line)
|
|
{
|
|
std::cerr << line << '\n';
|
|
});
|
|
}
|
|
|
|
void tearDown()
|
|
{
|
|
}
|
|
};
|
|
|
|
void FakeSocketTest::testBasic()
|
|
{
|
|
constexpr auto testname = __func__;
|
|
|
|
int rc;
|
|
char buf[100];
|
|
|
|
// First check invalid fds.
|
|
|
|
rc = fakeSocketListen(10);
|
|
LOK_ASSERT(rc == -1);
|
|
LOK_ASSERT(errno == EBADF);
|
|
|
|
rc = fakeSocketWrite(20, "hah", 3);
|
|
LOK_ASSERT(rc == -1);
|
|
LOK_ASSERT(errno == EBADF);
|
|
|
|
rc = fakeSocketRead(30, buf, 3);
|
|
LOK_ASSERT(rc == -1);
|
|
LOK_ASSERT(errno == EBADF);
|
|
|
|
// Create three sockets: s0, s1 and s2.
|
|
int s0 = fakeSocketSocket();
|
|
LOK_ASSERT(s0 >= 0);
|
|
int s1 = fakeSocketSocket();
|
|
LOK_ASSERT(s1 >= 0);
|
|
int s2 = fakeSocketSocket();
|
|
LOK_ASSERT(s2 >= 0);
|
|
|
|
LOK_ASSERT(s0 != s1);
|
|
LOK_ASSERT(s1 != s2);
|
|
|
|
// Close s1 and create it anew
|
|
fakeSocketClose(s1);
|
|
|
|
s1 = fakeSocketSocket();
|
|
LOK_ASSERT(s1 >= 0);
|
|
|
|
// Listen on s0
|
|
rc = fakeSocketListen(s0);
|
|
LOK_ASSERT(rc != -1);
|
|
|
|
// Start a thread that accepts two connections to s0, producing sockets s3 and s4.
|
|
int s3 = -1, s4 = -1;
|
|
std::thread t0([&] {
|
|
// Cannot use LOK_ASSERT here as that throws and this thread has no Cppunit
|
|
// exception handler. We check below after joining this thread.
|
|
s3 = fakeSocketAccept4(s0);
|
|
s4 = fakeSocketAccept4(s0);
|
|
});
|
|
|
|
// Connect s1 and s2 to s0 (that is, to the sockets produced by accepting connections to
|
|
// s0).
|
|
rc = fakeSocketConnect(s1, s0);
|
|
LOK_ASSERT(rc != -1);
|
|
|
|
rc = fakeSocketConnect(s2, s0);
|
|
LOK_ASSERT(rc != -1);
|
|
|
|
// Verify that we got the accepts.
|
|
t0.join();
|
|
LOK_ASSERT(s3 != -1);
|
|
LOK_ASSERT(s4 != -1);
|
|
|
|
// s1 should now be connected to s3, and s2 to s4.
|
|
LOK_ASSERT(fakeSocketPeer(s1) == s3);
|
|
LOK_ASSERT(fakeSocketPeer(s3) == s1);
|
|
LOK_ASSERT(fakeSocketPeer(s2) == s4);
|
|
LOK_ASSERT(fakeSocketPeer(s4) == s2);
|
|
|
|
// Some writing and reading
|
|
rc = fakeSocketWrite(s1, "hello", 5);
|
|
LOK_ASSERT(rc != -1);
|
|
|
|
rc = fakeSocketWrite(s1, "greetings", 9);
|
|
LOK_ASSERT(rc != -1);
|
|
|
|
rc = fakeSocketWrite(s2, "moin", 4);
|
|
LOK_ASSERT(rc != -1);
|
|
|
|
rc = fakeSocketAvailableDataLength(s3);
|
|
LOK_ASSERT(rc == 5);
|
|
|
|
rc = fakeSocketRead(s3, buf, 100);
|
|
LOK_ASSERT(rc == 5);
|
|
|
|
rc = fakeSocketAvailableDataLength(s3);
|
|
LOK_ASSERT(rc == 9);
|
|
|
|
rc = fakeSocketRead(s4, buf, 100);
|
|
LOK_ASSERT(rc == 4);
|
|
|
|
rc = fakeSocketWrite(s3, "goodbye", 7);
|
|
LOK_ASSERT(rc > 0);
|
|
|
|
rc = fakeSocketRead(s1, buf, 4);
|
|
LOK_ASSERT(rc == -1);
|
|
LOK_ASSERT(errno == EAGAIN); // Note: not really the right errno, but what else? See
|
|
// FakeSocket.cpp.
|
|
|
|
rc = fakeSocketRead(s1, buf, 100);
|
|
LOK_ASSERT(rc > 0);
|
|
|
|
// Close s3. Reading from s1 should then return an EOF indication (0).
|
|
fakeSocketClose(s3);
|
|
|
|
rc = fakeSocketAvailableDataLength(s1);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketRead(s1, buf, 100);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketAvailableDataLength(s1);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketRead(s1, buf, 100);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
// Test the "pipe" functionality, that creates an already connected socket pair.
|
|
int pipe[2];
|
|
rc = fakeSocketPipe2(pipe);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketWrite(pipe[0], "x", 1);
|
|
LOK_ASSERT(rc == 1);
|
|
|
|
rc = fakeSocketAvailableDataLength(pipe[1]);
|
|
LOK_ASSERT(rc == 1);
|
|
|
|
rc = fakeSocketRead(pipe[1], buf, 1);
|
|
LOK_ASSERT(rc == 1);
|
|
|
|
LOK_ASSERT(buf[0] == 'x');
|
|
|
|
rc = fakeSocketWrite(pipe[1], "y", 1);
|
|
LOK_ASSERT(rc == 1);
|
|
|
|
rc = fakeSocketRead(pipe[0], buf, 1);
|
|
LOK_ASSERT(rc == 1);
|
|
LOK_ASSERT(buf[0] == 'y');
|
|
|
|
rc = fakeSocketWrite(pipe[0], "z", 1);
|
|
LOK_ASSERT(rc == 1);
|
|
|
|
rc = fakeSocketShutdown(pipe[0]);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketRead(pipe[1], buf, 1);
|
|
LOK_ASSERT(rc == 1);
|
|
LOK_ASSERT(buf[0] == 'z');
|
|
|
|
rc = fakeSocketWrite(pipe[0], "a", 1);
|
|
LOK_ASSERT(rc == -1);
|
|
LOK_ASSERT(errno == EPIPE);
|
|
|
|
rc = fakeSocketRead(pipe[0], buf, 1);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketRead(pipe[0], buf, 1);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketClose(pipe[0]);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketClose(pipe[0]);
|
|
LOK_ASSERT(rc == -1);
|
|
LOK_ASSERT(errno == EBADF);
|
|
|
|
rc = fakeSocketClose(pipe[1]);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketClose(pipe[1]);
|
|
LOK_ASSERT(rc == -1);
|
|
LOK_ASSERT(errno == EBADF);
|
|
|
|
// Create a pipe again.
|
|
|
|
rc = fakeSocketPipe2(pipe);
|
|
LOK_ASSERT(rc == 0);
|
|
|
|
rc = fakeSocketAvailableDataLength(pipe[0]);
|
|
LOK_ASSERT(rc == -1);
|
|
LOK_ASSERT(errno == EAGAIN);
|
|
|
|
rc = fakeSocketAvailableDataLength(pipe[1]);
|
|
LOK_ASSERT(rc == -1);
|
|
LOK_ASSERT(errno == EAGAIN);
|
|
|
|
// Test poll functionality.
|
|
|
|
struct pollfd pollfds[4];
|
|
|
|
pollfds[0].fd = s0;
|
|
pollfds[0].events = POLLIN | POLLOUT;
|
|
pollfds[1].fd = s1;
|
|
pollfds[1].events = POLLIN | POLLOUT;
|
|
pollfds[2].fd = s2;
|
|
pollfds[2].events = POLLIN | POLLOUT;
|
|
pollfds[3].fd = 40;
|
|
pollfds[3].events = POLLIN | POLLOUT;
|
|
|
|
rc = fakeSocketPoll(pollfds, 4, -1);
|
|
// Hmm, does a real poll() set POLLIN for a listening socket? Probably only if there is a
|
|
// connection in progress, and that is not the case here for s0.
|
|
LOK_ASSERT(rc == 3);
|
|
LOK_ASSERT(pollfds[0].revents == 0);
|
|
LOK_ASSERT(pollfds[1].revents == POLLIN);
|
|
LOK_ASSERT(pollfds[2].revents == POLLOUT);
|
|
LOK_ASSERT(pollfds[3].revents == POLLNVAL);
|
|
}
|
|
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(FakeSocketTest);
|
|
|
|
int main(int, char**)
|
|
{
|
|
const char* envar = std::getenv("CPPUNIT_TEST_NAME");
|
|
std::string testName;
|
|
if (envar)
|
|
{
|
|
testName = std::string(envar);
|
|
}
|
|
if (!testName.empty() && testName != "FakeSocketTest")
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
CPPUNIT_NS::TestResult controller;
|
|
CPPUNIT_NS::TestResultCollector result;
|
|
controller.addListener(&result);
|
|
CPPUNIT_NS::BriefTestProgressListener progress;
|
|
controller.addListener(&progress);
|
|
CPPUNIT_NS::TextTestProgressListener listener;
|
|
controller.addListener(&listener);
|
|
|
|
CPPUNIT_NS::Test* testRegistry = CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest();
|
|
|
|
CPPUNIT_NS::TestRunner runner;
|
|
runner.addTest(testRegistry);
|
|
runner.run(controller);
|
|
|
|
CPPUNIT_NS::CompilerOutputter outputter(&result, std::cerr);
|
|
outputter.setNoWrap();
|
|
outputter.write();
|
|
|
|
fakeSocketDumpState();
|
|
|
|
return result.wasSuccessful() ? 0 : 1;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|