1 /* Copyright (C) 2022 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "lib/self_test.h"
20 #include "graphics/TerrainTextureManager.h"
21 #include "lib/external_libraries/enet.h"
22 #include "lib/external_libraries/libsdl.h"
23 #include "lib/tex/tex.h"
24 #include "network/NetServer.h"
25 #include "network/NetClient.h"
26 #include "network/NetMessage.h"
27 #include "network/NetMessages.h"
28 #include "ps/CLogger.h"
30 #include "ps/Filesystem.h"
31 #include "ps/Loader.h"
32 #include "ps/XML/Xeromyces.h"
33 #include "scriptinterface/ScriptInterface.h"
34 #include "simulation2/Simulation2.h"
35 #include "simulation2/system/TurnManager.h"
37 class TestNetComms
: public CxxTest::TestSuite
43 TS_ASSERT_OK(g_VFS
->Mount(L
"", DataDir() / "mods" / "public" / "", VFS_MOUNT_MUST_EXIST
));
44 TS_ASSERT_OK(g_VFS
->Mount(L
"cache", DataDir() / "_testcache" / "", 0, VFS_MAX_PRIORITY
));
45 CXeromyces::Startup();
54 CXeromyces::Terminate();
56 DeleteDirectory(DataDir()/"_testcache");
59 bool clients_are_all(const std::vector
<CNetClient
*>& clients
, uint state
)
61 for (size_t j
= 0; j
< clients
.size(); ++j
)
62 if (clients
[j
]->GetCurrState() != state
)
67 void connect(CNetServer
& server
, const std::vector
<CNetClient
*>& clients
)
69 TS_ASSERT(server
.SetupConnection(PS_DEFAULT_PORT
));
70 for (CNetClient
* client
: clients
)
72 client
->SetupServerData("127.0.0.1", PS_DEFAULT_PORT
, false);
73 TS_ASSERT(client
->SetupConnection(nullptr));
76 for (size_t i
= 0; ; ++i
)
79 for (size_t j
= 0; j
< clients
.size(); ++j
)
82 if (clients_are_all(clients
, NCS_PREGAME
))
87 TS_FAIL("connection timeout");
96 void disconnect(CNetServer
& server
, const std::vector
<CNetClient
*>& clients
)
98 for (size_t i
= 0; ; ++i
)
100 // debug_printf(".");
102 for (size_t j
= 0; j
< clients
.size(); ++j
)
105 if (server
.GetState() == SERVER_STATE_UNCONNECTED
&& clients_are_all(clients
, NCS_UNCONNECTED
))
110 TS_FAIL("disconnection timeout");
119 void wait(const std::vector
<CNetClient
*>& clients
, size_t msecs
)
121 for (size_t i
= 0; i
< msecs
/10; ++i
)
123 for (size_t j
= 0; j
< clients
.size(); ++j
)
130 void test_basic_DISABLED()
132 // This doesn't actually test much, it just runs a very quick multiplayer game
133 // and prints a load of debug output so you can see if anything funny's going on
135 ScriptInterface
scriptInterface("Engine", "Test", g_ScriptContext
);
136 ScriptRequest
rq(scriptInterface
);
138 TestStdoutLogger logger
;
140 std::vector
<CNetClient
*> clients
;
142 CGame
client1Game(false);
143 CGame
client2Game(false);
144 CGame
client3Game(false);
146 CNetServer
server("no_secret");
148 JS::RootedValue
attrs(rq
.cx
);
149 Script::CreateObject(
152 "mapType", "scenario",
153 "map", "maps/scenarios/Saharan Oases",
154 "mapPath", "maps/scenarios/",
157 server
.UpdateInitAttributes(&attrs
, scriptInterface
);
159 CNetClient
client1(&client1Game
);
160 CNetClient
client2(&client2Game
);
161 CNetClient
client3(&client3Game
);
163 clients
.push_back(&client1
);
164 clients
.push_back(&client2
);
165 clients
.push_back(&client3
);
167 connect(server
, clients
);
168 debug_printf("%s", client1
.TestReadGuiMessages().c_str());
172 for (size_t j
= 0; j
< clients
.size(); ++j
)
175 TS_ASSERT_OK(LDR_NonprogressiveLoad());
176 clients
[j
]->LoadFinished();
182 JS::RootedValue
cmd(rq
.cx
);
183 Script::CreateObject(
186 "type", "debug-print",
187 "message", "[>>> client1 test sim command]\\n");
188 client1Game
.GetTurnManager()->PostCommand(cmd
);
192 JS::RootedValue
cmd(rq
.cx
);
193 Script::CreateObject(
196 "type", "debug-print",
197 "message", "[>>> client2 test sim command]\\n");
198 client2Game
.GetTurnManager()->PostCommand(cmd
);
202 client1Game
.GetTurnManager()->Update(1.0f
, 1);
203 client2Game
.GetTurnManager()->Update(1.0f
, 1);
204 client3Game
.GetTurnManager()->Update(1.0f
, 1);
206 client1Game
.GetTurnManager()->Update(1.0f
, 1);
207 client2Game
.GetTurnManager()->Update(1.0f
, 1);
208 client3Game
.GetTurnManager()->Update(1.0f
, 1);
212 void test_rejoin_DISABLED()
214 ScriptInterface
scriptInterface("Engine", "Test", g_ScriptContext
);
215 ScriptRequest
rq(scriptInterface
);
217 TestStdoutLogger logger
;
219 std::vector
<CNetClient
*> clients
;
221 CGame
client1Game(false);
222 CGame
client2Game(false);
223 CGame
client3Game(false);
225 CNetServer
server("no_secret");
227 JS::RootedValue
attrs(rq
.cx
);
228 Script::CreateObject(
231 "mapType", "scenario",
232 "map", "maps/scenarios/Saharan Oases",
233 "mapPath", "maps/scenarios/",
236 server
.UpdateInitAttributes(&attrs
, scriptInterface
);
238 CNetClient
client1(&client1Game
);
239 CNetClient
client2(&client2Game
);
240 CNetClient
client3(&client3Game
);
242 client1
.SetUserName(L
"alice");
243 client2
.SetUserName(L
"bob");
244 client3
.SetUserName(L
"charlie");
246 clients
.push_back(&client1
);
247 clients
.push_back(&client2
);
248 clients
.push_back(&client3
);
250 connect(server
, clients
);
251 debug_printf("%s", client1
.TestReadGuiMessages().c_str());
255 for (size_t j
= 0; j
< clients
.size(); ++j
)
258 TS_ASSERT_OK(LDR_NonprogressiveLoad());
259 clients
[j
]->LoadFinished();
265 JS::RootedValue
cmd(rq
.cx
);
266 Script::CreateObject(
269 "type", "debug-print",
270 "message", "[>>> client1 test sim command 1]\\n");
272 client1Game
.GetTurnManager()->PostCommand(cmd
);
276 client1Game
.GetTurnManager()->Update(1.0f
, 1);
277 client2Game
.GetTurnManager()->Update(1.0f
, 1);
278 client3Game
.GetTurnManager()->Update(1.0f
, 1);
282 JS::RootedValue
cmd(rq
.cx
);
283 Script::CreateObject(
286 "type", "debug-print",
287 "message", "[>>> client1 test sim command 2]\\n");
288 client1Game
.GetTurnManager()->PostCommand(cmd
);
291 debug_printf("==== Disconnecting client 2\n");
293 client2
.DestroyConnection();
294 clients
.erase(clients
.begin()+1);
296 debug_printf("==== Connecting client 2B\n");
298 CGame
client2BGame(false);
299 CNetClient
client2B(&client2BGame
);
300 client2B
.SetUserName(L
"bob");
301 clients
.push_back(&client2B
);
303 client2B
.SetupServerData("127.0.0.1", PS_DEFAULT_PORT
, false);
304 TS_ASSERT(client2B
.SetupConnection(nullptr));
306 for (size_t i
= 0; ; ++i
)
308 debug_printf("[%u]\n", client2B
.GetCurrState());
310 if (client2B
.GetCurrState() == NCS_PREGAME
)
313 if (client2B
.GetCurrState() == NCS_UNCONNECTED
)
315 TS_FAIL("connection rejected");
321 TS_FAIL("connection timeout");
330 client1Game
.GetTurnManager()->Update(1.0f
, 1);
331 client3Game
.GetTurnManager()->Update(1.0f
, 1);
333 server
.SetTurnLength(100);
334 client1Game
.GetTurnManager()->Update(1.0f
, 1);
335 client3Game
.GetTurnManager()->Update(1.0f
, 1);
338 // (This SetTurnLength thing doesn't actually detect errors unless you change
339 // CTurnManager::TurnNeedsFullHash to always return true)
342 JS::RootedValue
cmd(rq
.cx
);
343 Script::CreateObject(
346 "type", "debug-print",
347 "message", "[>>> client1 test sim command 3]\\n");
348 client1Game
.GetTurnManager()->PostCommand(cmd
);
353 TS_ASSERT_OK(LDR_NonprogressiveLoad());
354 clients
[2]->LoadFinished();
359 JS::RootedValue
cmd(rq
.cx
);
360 Script::CreateObject(
363 "type", "debug-print",
364 "message", "[>>> client1 test sim command 4]\\n");
366 client1Game
.GetTurnManager()->PostCommand(cmd
);
369 for (size_t i
= 0; i
< 3; ++i
)
371 client1Game
.GetTurnManager()->Update(1.0f
, 1);
372 client2BGame
.GetTurnManager()->Update(1.0f
, 1);
373 client3Game
.GetTurnManager()->Update(1.0f
, 1);