From aee07b0f8d8c0d9af66dd7507938d83985d53833 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Fri, 25 Nov 2016 14:20:29 +0100 Subject: [PATCH] simple test for client --- src/server/ServerState.cpp | 3 + tst/integration/ClientTest.cpp | 51 ++++++++++++++ tst/integration/ClientTest.hpp | 37 ++++++++++ tst/integration/InvocationTest.cpp | 2 +- tst/integration/ServerTest.cpp | 12 +++- tst/integration/StandaloneTest.cpp | 11 +-- tst/integration/TestInstance.cpp | 109 ++++++++++++++++++++++------- tst/integration/TestInstance.hpp | 7 ++ tst/test.cpp | 2 +- 9 files changed, 200 insertions(+), 34 deletions(-) create mode 100644 tst/integration/ClientTest.cpp create mode 100644 tst/integration/ClientTest.hpp diff --git a/src/server/ServerState.cpp b/src/server/ServerState.cpp index d3001c1..76686b0 100644 --- a/src/server/ServerState.cpp +++ b/src/server/ServerState.cpp @@ -33,6 +33,9 @@ ServerState::ServerState( spawner.LimitModels(1, res.models.size()); server.SetPlayerModel(res.models[0]); + std::cout << "loading spawn chunks" << std::endl; + chunk_loader.LoadN(chunk_loader.ToLoad()); + loop_timer.Start(); std::cout << "listening on UDP port " << config.net.port << std::endl; diff --git a/tst/integration/ClientTest.cpp b/tst/integration/ClientTest.cpp new file mode 100644 index 0000000..93a17d4 --- /dev/null +++ b/tst/integration/ClientTest.cpp @@ -0,0 +1,51 @@ +#include "ClientTest.hpp" + +#include "TestInstance.hpp" + +#include + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(blank::test::ClientTest, "headed"); + + +namespace blank { +namespace test { + +void ClientTest::setUp() { + server.reset(new TestInstance({ "--server" }, true)); + server->AssertRunning(); + server->AssertOutputLine("loading spawn chunks"); + server->AssertOutputLine("listening on UDP port 12354"); + client.reset(new TestInstance({ "--client" })); + client->AssertRunning(); + client->AssertOutputLine("got message before interface was created: player \"default\" joined"); + client->AssertOutputLine("joined game \"default\""); + server->AssertOutputLine("player \"default\" joined"); + server->AssertOutputLine("accepted login from player \"default\""); +} + +void ClientTest::tearDown() { + std::unique_ptr srv(std::move(server)); + std::unique_ptr cln(std::move(client)); + if (cln) { + cln->Terminate(); + cln->AssertNoOutput(); + cln->AssertNoError(); + cln->AssertExitStatus(0); + } + if (srv) { + srv->Terminate(); + srv->AssertOutputLine("player \"default\" left"); + srv->AssertOutputLine("saving remaining chunks"); + srv->AssertNoOutput(); + srv->AssertNoError(); + srv->AssertExitStatus(0); + } +} + + +void ClientTest::testStartup() { + +} + +} +} diff --git a/tst/integration/ClientTest.hpp b/tst/integration/ClientTest.hpp new file mode 100644 index 0000000..4bf7fa4 --- /dev/null +++ b/tst/integration/ClientTest.hpp @@ -0,0 +1,37 @@ +#ifndef BLANK_TEST_INTEGRATION_CLIENTTEST_HPP_ +#define BLANK_TEST_INTEGRATION_CLIENTTEST_HPP_ + +#include +#include + + +namespace blank { +namespace test { + +class TestInstance; + +class ClientTest +: public CppUnit::TestFixture { + +CPPUNIT_TEST_SUITE(ClientTest); + +CPPUNIT_TEST(testStartup); + +CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testStartup(); + +private: + std::unique_ptr server; + std::unique_ptr client; + +}; + +} +} + +#endif diff --git a/tst/integration/InvocationTest.cpp b/tst/integration/InvocationTest.cpp index fd9c98f..70fd47f 100644 --- a/tst/integration/InvocationTest.cpp +++ b/tst/integration/InvocationTest.cpp @@ -2,7 +2,7 @@ #include "TestInstance.hpp" -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(blank::test::InvocationTest, "integration"); +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(blank::test::InvocationTest, "headed"); namespace blank { diff --git a/tst/integration/ServerTest.cpp b/tst/integration/ServerTest.cpp index 8fe7788..8f55914 100644 --- a/tst/integration/ServerTest.cpp +++ b/tst/integration/ServerTest.cpp @@ -11,13 +11,19 @@ namespace test { void ServerTest::setUp() { instance.reset(new TestInstance({ "--server" }, true)); instance->AssertRunning(); + instance->AssertOutputLine("loading spawn chunks"); + instance->AssertOutputLine("listening on UDP port 12354"); } void ServerTest::tearDown() { std::unique_ptr inst(std::move(instance)); - inst->Terminate(); - inst->AssertExitStatus(0); - inst->AssertNoError(); + if (inst) { + inst->Terminate(); + inst->AssertOutputLine("saving remaining chunks"); + inst->AssertNoOutput(); + inst->AssertNoError(); + inst->AssertExitStatus(0); + } } diff --git a/tst/integration/StandaloneTest.cpp b/tst/integration/StandaloneTest.cpp index 2407775..95dfc3a 100644 --- a/tst/integration/StandaloneTest.cpp +++ b/tst/integration/StandaloneTest.cpp @@ -3,7 +3,7 @@ #include "TestInstance.hpp" -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(blank::test::StandaloneTest, "integration"); +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(blank::test::StandaloneTest, "headed"); namespace blank { @@ -16,9 +16,12 @@ void StandaloneTest::setUp() { void StandaloneTest::tearDown() { std::unique_ptr inst(std::move(instance)); - inst->Terminate(); - inst->AssertExitStatus(0); - inst->AssertNoError(); + if (inst) { + inst->Terminate(); + inst->AssertNoOutput(); + inst->AssertNoError(); + inst->AssertExitStatus(0); + } } diff --git a/tst/integration/TestInstance.cpp b/tst/integration/TestInstance.cpp index 71bc194..fe61fdc 100644 --- a/tst/integration/TestInstance.cpp +++ b/tst/integration/TestInstance.cpp @@ -32,13 +32,18 @@ TestInstance::TestInstance(const Process::Arguments &args, bool cmd) , conn() , out_buf() , err_buf() -, cmd_buf() { +, cmd_buf() +, name("blank" BLANK_SUFFIX) { if (cmd) { // wait for command service startup WaitOutputLine("listening on TCP port 12354"); // connect to command service conn = tcp::Socket("localhost", 12354); } + for (const auto &arg : args) { + name += ' '; + name += arg; + } } TestInstance::~TestInstance() { @@ -53,7 +58,7 @@ void TestInstance::WriteInput(const string &data) { while (i != end) { size_t len = proc.WriteIn(i, end - i); if (len == 0) { - throw runtime_error("failed write to child process' stdin"); + throw runtime_error("failed write to stdin of " + name); } i += len; } @@ -64,7 +69,7 @@ void TestInstance::ReadOutputLine(string &line) { // buffer exhausted, fetch more data int len = proc.ReadOut(out_buf.WriteHead(), out_buf.Remain(), 5000); if (len == 0) { - throw runtime_error("failed read from child process' stdout"); + throw runtime_error("failed read from stdout of " + name); } out_buf.Update(len); } @@ -72,30 +77,56 @@ void TestInstance::ReadOutputLine(string &line) { void TestInstance::AssertOutputLine(const string &expected) { string line; - ReadOutputLine(line); + if (past_out.empty()) { + ReadOutputLine(line); + } else { + line = past_out.front(); + past_out.pop_front(); + } CPPUNIT_ASSERT_EQUAL_MESSAGE( - "unexpected line in stdout", + "unexpected line in stdout of " + name, expected, line); } void TestInstance::WaitOutputLine(const string &expected) { + for (list::iterator i(past_out.begin()); i != past_out.end(); ++i) { + if (*i == expected) { + past_out.erase(i); + return; + } + } string line; while (true) { ReadOutputLine(line); if (line == expected) { return; + } else { + past_out.push_back(line); } } } void TestInstance::ExhaustOutput(string &output) { - while (!out_buf.Extract(output)) { - // buffer exhausted, fetch more data - int len = proc.ReadOut(out_buf.WriteHead(), out_buf.Remain(), 5000); - if (len == 0) { - return; + output.clear(); + for (const auto &line : past_out) { + output += line; + output += '\n'; + } + past_out.clear(); + string line; + while (true) { + if (out_buf.Extract(line)) { + output += line; + output += '\n'; + } else { + // buffer exhausted, fetch more data + int len = proc.ReadOut(out_buf.WriteHead(), out_buf.Remain(), 5000); + if (len == 0) { + // eof + return; + } + out_buf.Update(len); } - out_buf.Update(len); } } @@ -103,7 +134,7 @@ void TestInstance::AssertNoOutput() { string output; ExhaustOutput(output); CPPUNIT_ASSERT_EQUAL_MESSAGE( - "test instance produced unexpected output", + "unexpected output of test instance " + name, string(""), output); } @@ -113,7 +144,7 @@ void TestInstance::ReadErrorLine(string &line) { // buffer exhausted, fetch more data int len = proc.ReadErr(err_buf.WriteHead(), err_buf.Remain(), 5000); if (len == 0) { - throw runtime_error("failed read from child process' stderr"); + throw runtime_error("failed read from stderr of " + name); } err_buf.Update(len); } @@ -121,30 +152,56 @@ void TestInstance::ReadErrorLine(string &line) { void TestInstance::AssertErrorLine(const string &expected) { string line; - ReadErrorLine(line); + if (past_err.empty()) { + ReadErrorLine(line); + } else { + line = past_err.front(); + past_err.pop_front(); + } CPPUNIT_ASSERT_EQUAL_MESSAGE( "unexpected line in stderr", expected, line); } void TestInstance::WaitErrorLine(const string &expected) { + for (list::iterator i(past_err.begin()); i != past_err.end(); ++i) { + if (*i == expected) { + past_err.erase(i); + return; + } + } string line; while (true) { ReadErrorLine(line); if (line == expected) { return; + } else { + past_err.push_back(line); } } } void TestInstance::ExhaustError(string &error) { - while (!err_buf.Extract(error)) { - // buffer exhausted, fetch more data - int len = proc.ReadErr(err_buf.WriteHead(), err_buf.Remain(), 5000); - if (len == 0) { - return; + error.clear(); + for (const auto &line : past_err) { + error += line; + error += '\n'; + } + past_err.clear(); + string line; + while (true) { + if (err_buf.Extract(line)) { + error += line; + error += '\n'; + } else { + // buffer exhausted, fetch more data + int len = proc.ReadErr(err_buf.WriteHead(), err_buf.Remain(), 5000); + if (len == 0) { + // eof + return; + } + err_buf.Update(len); } - err_buf.Update(len); } } @@ -152,30 +209,32 @@ void TestInstance::AssertNoError() { string error; ExhaustError(error); CPPUNIT_ASSERT_EQUAL_MESSAGE( - "test instance produced unexpected error output", + "unexpected error output of test instance " + name, string(""), error); } void TestInstance::Terminate() { - proc.Terminate(); + if (!proc.Terminated()) { + proc.Terminate(); + } } void TestInstance::AssertRunning() { CPPUNIT_ASSERT_MESSAGE( - "test instance terminated unexpectedly", + "test instance " + name + " terminated unexpectedly", !proc.Terminated()); } void TestInstance::AssertTerminated() { CPPUNIT_ASSERT_MESSAGE( - "test instance did not terminate as expected", + "test instance " + name + " did not terminate as expected", proc.Terminated()); } void TestInstance::AssertExitStatus(int expected) { CPPUNIT_ASSERT_EQUAL_MESSAGE( - "unexpected exit status from child program", + "unexpected exit status from child program " + name, expected, proc.Join()); } diff --git a/tst/integration/TestInstance.hpp b/tst/integration/TestInstance.hpp index 354a668..25fb08c 100644 --- a/tst/integration/TestInstance.hpp +++ b/tst/integration/TestInstance.hpp @@ -6,6 +6,9 @@ #include "io/LineBuffer.hpp" #include "net/tcp.hpp" +#include +#include + namespace blank { namespace test { @@ -81,6 +84,10 @@ private: LineBuffer out_buf; LineBuffer err_buf; LineBuffer cmd_buf; + std::string name; + std::list past_out; + std::list past_err; + std::list past_cmd; }; diff --git a/tst/test.cpp b/tst/test.cpp index 0424467..55534af 100644 --- a/tst/test.cpp +++ b/tst/test.cpp @@ -19,7 +19,7 @@ int main(int argc, char **argv) { runner.addTest(registry.makeTest()); } if (!headless) { - TestFactoryRegistry ®istry = TestFactoryRegistry::getRegistry("integration"); + TestFactoryRegistry ®istry = TestFactoryRegistry::getRegistry("headed"); runner.addTest(registry.makeTest()); } -- 2.39.2