1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program Execution Server
3e5c31af7Sopenharmony_ci * ---------------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief ExecServer Tests.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "xsDefs.hpp"
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ci#include "xsProtocol.hpp"
27e5c31af7Sopenharmony_ci#include "deSocket.hpp"
28e5c31af7Sopenharmony_ci#include "deRingBuffer.hpp"
29e5c31af7Sopenharmony_ci#include "deFilePath.hpp"
30e5c31af7Sopenharmony_ci#include "deBlockBuffer.hpp"
31e5c31af7Sopenharmony_ci#include "deThread.hpp"
32e5c31af7Sopenharmony_ci#include "deStringUtil.hpp"
33e5c31af7Sopenharmony_ci#include "deUniquePtr.hpp"
34e5c31af7Sopenharmony_ci
35e5c31af7Sopenharmony_ci#include "deClock.h"
36e5c31af7Sopenharmony_ci#include "deProcess.h"
37e5c31af7Sopenharmony_ci#include "deString.h"
38e5c31af7Sopenharmony_ci#include "deRandom.h"
39e5c31af7Sopenharmony_ci
40e5c31af7Sopenharmony_ci#include <memory>
41e5c31af7Sopenharmony_ci#include <algorithm>
42e5c31af7Sopenharmony_ci
43e5c31af7Sopenharmony_ciusing std::string;
44e5c31af7Sopenharmony_ciusing std::vector;
45e5c31af7Sopenharmony_ci
46e5c31af7Sopenharmony_cinamespace xs
47e5c31af7Sopenharmony_ci{
48e5c31af7Sopenharmony_ci
49e5c31af7Sopenharmony_citypedef de::UniquePtr<Message> ScopedMsgPtr;
50e5c31af7Sopenharmony_ci
51e5c31af7Sopenharmony_ciclass SocketError : public Error
52e5c31af7Sopenharmony_ci{
53e5c31af7Sopenharmony_cipublic:
54e5c31af7Sopenharmony_ci	SocketError (deSocketResult result, const char* message, const char* file, int line)
55e5c31af7Sopenharmony_ci		: Error		(message, deGetSocketResultName(result), file, line)
56e5c31af7Sopenharmony_ci		, m_result	(result)
57e5c31af7Sopenharmony_ci	{
58e5c31af7Sopenharmony_ci	}
59e5c31af7Sopenharmony_ci
60e5c31af7Sopenharmony_ci	deSocketResult getResult (void) const
61e5c31af7Sopenharmony_ci	{
62e5c31af7Sopenharmony_ci		return m_result;
63e5c31af7Sopenharmony_ci	}
64e5c31af7Sopenharmony_ci
65e5c31af7Sopenharmony_ciprivate:
66e5c31af7Sopenharmony_ci	deSocketResult m_result;
67e5c31af7Sopenharmony_ci};
68e5c31af7Sopenharmony_ci
69e5c31af7Sopenharmony_ci// Helpers.
70e5c31af7Sopenharmony_civoid sendMessage (de::Socket& socket, const Message& message)
71e5c31af7Sopenharmony_ci{
72e5c31af7Sopenharmony_ci	// Format message.
73e5c31af7Sopenharmony_ci	vector<deUint8> buf;
74e5c31af7Sopenharmony_ci	message.write(buf);
75e5c31af7Sopenharmony_ci
76e5c31af7Sopenharmony_ci	// Write to socket.
77e5c31af7Sopenharmony_ci	size_t pos = 0;
78e5c31af7Sopenharmony_ci	while (pos < buf.size())
79e5c31af7Sopenharmony_ci	{
80e5c31af7Sopenharmony_ci		size_t			numLeft		= buf.size() - pos;
81e5c31af7Sopenharmony_ci		size_t			numSent		= 0;
82e5c31af7Sopenharmony_ci		deSocketResult	result		= socket.send(&buf[pos], numLeft, &numSent);
83e5c31af7Sopenharmony_ci
84e5c31af7Sopenharmony_ci		if (result != DE_SOCKETRESULT_SUCCESS)
85e5c31af7Sopenharmony_ci			throw SocketError(result, "send() failed", __FILE__, __LINE__);
86e5c31af7Sopenharmony_ci
87e5c31af7Sopenharmony_ci		pos += numSent;
88e5c31af7Sopenharmony_ci	}
89e5c31af7Sopenharmony_ci}
90e5c31af7Sopenharmony_ci
91e5c31af7Sopenharmony_civoid readBytes (de::Socket& socket, vector<deUint8>& dst, size_t numBytes)
92e5c31af7Sopenharmony_ci{
93e5c31af7Sopenharmony_ci	size_t numRead = 0;
94e5c31af7Sopenharmony_ci	dst.resize(numBytes);
95e5c31af7Sopenharmony_ci	while (numRead < numBytes)
96e5c31af7Sopenharmony_ci	{
97e5c31af7Sopenharmony_ci		size_t			numLeft		= numBytes - numRead;
98e5c31af7Sopenharmony_ci		size_t			curNumRead	= 0;
99e5c31af7Sopenharmony_ci		deSocketResult	result		= socket.receive(&dst[numRead], numLeft, &curNumRead);
100e5c31af7Sopenharmony_ci
101e5c31af7Sopenharmony_ci		if (result != DE_SOCKETRESULT_SUCCESS)
102e5c31af7Sopenharmony_ci			throw SocketError(result, "receive() failed", __FILE__, __LINE__);
103e5c31af7Sopenharmony_ci
104e5c31af7Sopenharmony_ci		numRead += curNumRead;
105e5c31af7Sopenharmony_ci	}
106e5c31af7Sopenharmony_ci}
107e5c31af7Sopenharmony_ci
108e5c31af7Sopenharmony_ciMessage* readMessage (de::Socket& socket)
109e5c31af7Sopenharmony_ci{
110e5c31af7Sopenharmony_ci	// Header.
111e5c31af7Sopenharmony_ci	vector<deUint8> header;
112e5c31af7Sopenharmony_ci	readBytes(socket, header, MESSAGE_HEADER_SIZE);
113e5c31af7Sopenharmony_ci
114e5c31af7Sopenharmony_ci	MessageType	type;
115e5c31af7Sopenharmony_ci	size_t		messageSize;
116e5c31af7Sopenharmony_ci	Message::parseHeader(&header[0], (int)header.size(), type, messageSize);
117e5c31af7Sopenharmony_ci
118e5c31af7Sopenharmony_ci	// Simple messages without any data.
119e5c31af7Sopenharmony_ci	switch (type)
120e5c31af7Sopenharmony_ci	{
121e5c31af7Sopenharmony_ci		case MESSAGETYPE_KEEPALIVE:				return new KeepAliveMessage();
122e5c31af7Sopenharmony_ci		case MESSAGETYPE_PROCESS_STARTED:		return new ProcessStartedMessage();
123e5c31af7Sopenharmony_ci		default:
124e5c31af7Sopenharmony_ci			break; // Read message with data.
125e5c31af7Sopenharmony_ci	}
126e5c31af7Sopenharmony_ci
127e5c31af7Sopenharmony_ci	vector<deUint8> messageBuf;
128e5c31af7Sopenharmony_ci	readBytes(socket, messageBuf, messageSize-MESSAGE_HEADER_SIZE);
129e5c31af7Sopenharmony_ci
130e5c31af7Sopenharmony_ci	switch (type)
131e5c31af7Sopenharmony_ci	{
132e5c31af7Sopenharmony_ci		case MESSAGETYPE_HELLO:					return new HelloMessage(&messageBuf[0], (int)messageBuf.size());
133e5c31af7Sopenharmony_ci		case MESSAGETYPE_TEST:					return new TestMessage(&messageBuf[0], (int)messageBuf.size());
134e5c31af7Sopenharmony_ci		case MESSAGETYPE_PROCESS_LOG_DATA:		return new ProcessLogDataMessage(&messageBuf[0], (int)messageBuf.size());
135e5c31af7Sopenharmony_ci		case MESSAGETYPE_INFO:					return new InfoMessage(&messageBuf[0], (int)messageBuf.size());
136e5c31af7Sopenharmony_ci		case MESSAGETYPE_PROCESS_LAUNCH_FAILED:	return new ProcessLaunchFailedMessage(&messageBuf[0], (int)messageBuf.size());
137e5c31af7Sopenharmony_ci		case MESSAGETYPE_PROCESS_FINISHED:		return new ProcessFinishedMessage(&messageBuf[0], (int)messageBuf.size());
138e5c31af7Sopenharmony_ci		default:
139e5c31af7Sopenharmony_ci			XS_FAIL("Unknown message");
140e5c31af7Sopenharmony_ci	}
141e5c31af7Sopenharmony_ci}
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_ciclass TestClock
144e5c31af7Sopenharmony_ci{
145e5c31af7Sopenharmony_cipublic:
146e5c31af7Sopenharmony_ci	inline TestClock (void)
147e5c31af7Sopenharmony_ci	{
148e5c31af7Sopenharmony_ci		reset();
149e5c31af7Sopenharmony_ci	}
150e5c31af7Sopenharmony_ci
151e5c31af7Sopenharmony_ci	inline void reset (void)
152e5c31af7Sopenharmony_ci	{
153e5c31af7Sopenharmony_ci		m_initTime = deGetMicroseconds();
154e5c31af7Sopenharmony_ci	}
155e5c31af7Sopenharmony_ci
156e5c31af7Sopenharmony_ci	inline int getMilliseconds (void)
157e5c31af7Sopenharmony_ci	{
158e5c31af7Sopenharmony_ci		return (int)((deGetMicroseconds() - m_initTime) / 1000);
159e5c31af7Sopenharmony_ci	}
160e5c31af7Sopenharmony_ci
161e5c31af7Sopenharmony_ciprivate:
162e5c31af7Sopenharmony_ci	deUint64 m_initTime;
163e5c31af7Sopenharmony_ci};
164e5c31af7Sopenharmony_ci
165e5c31af7Sopenharmony_ciclass TestContext
166e5c31af7Sopenharmony_ci{
167e5c31af7Sopenharmony_cipublic:
168e5c31af7Sopenharmony_ci						TestContext		(void) : startServer(false) {}
169e5c31af7Sopenharmony_ci
170e5c31af7Sopenharmony_ci	std::string			serverPath;
171e5c31af7Sopenharmony_ci	std::string			testerPath;
172e5c31af7Sopenharmony_ci	de::SocketAddress	address;
173e5c31af7Sopenharmony_ci	bool				startServer;
174e5c31af7Sopenharmony_ci
175e5c31af7Sopenharmony_ci	// Passed from execserver.
176e5c31af7Sopenharmony_ci	std::string			logFileName;
177e5c31af7Sopenharmony_ci	std::string			caseList;
178e5c31af7Sopenharmony_ci
179e5c31af7Sopenharmony_ciprivate:
180e5c31af7Sopenharmony_ci						TestContext		(const TestContext& other);
181e5c31af7Sopenharmony_ci	TestContext&		operator=		(const TestContext& other);
182e5c31af7Sopenharmony_ci};
183e5c31af7Sopenharmony_ci
184e5c31af7Sopenharmony_ciclass TestCase
185e5c31af7Sopenharmony_ci{
186e5c31af7Sopenharmony_cipublic:
187e5c31af7Sopenharmony_ci					TestCase		(TestContext& testCtx, const char* name) : m_testCtx(testCtx), m_name(name) {}
188e5c31af7Sopenharmony_ci	virtual			~TestCase		(void) {}
189e5c31af7Sopenharmony_ci
190e5c31af7Sopenharmony_ci	const char*		getName			(void) const { return m_name.c_str(); }
191e5c31af7Sopenharmony_ci
192e5c31af7Sopenharmony_ci	virtual void	runClient		(de::Socket& socket) = DE_NULL;
193e5c31af7Sopenharmony_ci	virtual void	runProgram		(void) = DE_NULL;
194e5c31af7Sopenharmony_ci
195e5c31af7Sopenharmony_ciprotected:
196e5c31af7Sopenharmony_ci	TestContext&	m_testCtx;
197e5c31af7Sopenharmony_ci	std::string		m_name;
198e5c31af7Sopenharmony_ci};
199e5c31af7Sopenharmony_ci
200e5c31af7Sopenharmony_ciclass TestExecutor
201e5c31af7Sopenharmony_ci{
202e5c31af7Sopenharmony_cipublic:
203e5c31af7Sopenharmony_ci					TestExecutor	(TestContext& testCtx);
204e5c31af7Sopenharmony_ci					~TestExecutor	(void);
205e5c31af7Sopenharmony_ci
206e5c31af7Sopenharmony_ci	void			runCases		(const std::vector<TestCase*>& testCases);
207e5c31af7Sopenharmony_ci	bool			runCase			(TestCase* testCase);
208e5c31af7Sopenharmony_ci
209e5c31af7Sopenharmony_ciprivate:
210e5c31af7Sopenharmony_ci	TestContext&	m_testCtx;
211e5c31af7Sopenharmony_ci};
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_ciTestExecutor::TestExecutor (TestContext& testCtx)
214e5c31af7Sopenharmony_ci	: m_testCtx(testCtx)
215e5c31af7Sopenharmony_ci{
216e5c31af7Sopenharmony_ci}
217e5c31af7Sopenharmony_ci
218e5c31af7Sopenharmony_ciTestExecutor::~TestExecutor (void)
219e5c31af7Sopenharmony_ci{
220e5c31af7Sopenharmony_ci}
221e5c31af7Sopenharmony_ci
222e5c31af7Sopenharmony_civoid TestExecutor::runCases (const std::vector<TestCase*>& testCases)
223e5c31af7Sopenharmony_ci{
224e5c31af7Sopenharmony_ci	int numPassed	= 0;
225e5c31af7Sopenharmony_ci	int numCases	= (int)testCases.size();
226e5c31af7Sopenharmony_ci
227e5c31af7Sopenharmony_ci	for (std::vector<TestCase*>::const_iterator i = testCases.begin(); i != testCases.end(); i++)
228e5c31af7Sopenharmony_ci	{
229e5c31af7Sopenharmony_ci		if (runCase(*i))
230e5c31af7Sopenharmony_ci			numPassed += 1;
231e5c31af7Sopenharmony_ci	}
232e5c31af7Sopenharmony_ci
233e5c31af7Sopenharmony_ci	printf("\n  %d/%d passed!\n", numPassed, numCases);
234e5c31af7Sopenharmony_ci}
235e5c31af7Sopenharmony_ci
236e5c31af7Sopenharmony_ciclass FilePrinter : public de::Thread
237e5c31af7Sopenharmony_ci{
238e5c31af7Sopenharmony_cipublic:
239e5c31af7Sopenharmony_ci	FilePrinter (void)
240e5c31af7Sopenharmony_ci		: m_curFile(DE_NULL)
241e5c31af7Sopenharmony_ci	{
242e5c31af7Sopenharmony_ci	}
243e5c31af7Sopenharmony_ci
244e5c31af7Sopenharmony_ci	void start (deFile* file)
245e5c31af7Sopenharmony_ci	{
246e5c31af7Sopenharmony_ci		DE_ASSERT(!m_curFile);
247e5c31af7Sopenharmony_ci		m_curFile = file;
248e5c31af7Sopenharmony_ci		de::Thread::start();
249e5c31af7Sopenharmony_ci	}
250e5c31af7Sopenharmony_ci
251e5c31af7Sopenharmony_ci	void run (void)
252e5c31af7Sopenharmony_ci	{
253e5c31af7Sopenharmony_ci		char	buf[256];
254e5c31af7Sopenharmony_ci		deInt64 numRead	= 0;
255e5c31af7Sopenharmony_ci
256e5c31af7Sopenharmony_ci		while (deFile_read(m_curFile, &buf[0], (deInt64)sizeof(buf), &numRead) == DE_FILERESULT_SUCCESS)
257e5c31af7Sopenharmony_ci			fwrite(&buf[0], 1, (size_t)numRead, stdout);
258e5c31af7Sopenharmony_ci
259e5c31af7Sopenharmony_ci		m_curFile = DE_NULL;
260e5c31af7Sopenharmony_ci	}
261e5c31af7Sopenharmony_ci
262e5c31af7Sopenharmony_ciprivate:
263e5c31af7Sopenharmony_ci	deFile* m_curFile;
264e5c31af7Sopenharmony_ci};
265e5c31af7Sopenharmony_ci
266e5c31af7Sopenharmony_cibool TestExecutor::runCase (TestCase* testCase)
267e5c31af7Sopenharmony_ci{
268e5c31af7Sopenharmony_ci	printf("%s\n", testCase->getName());
269e5c31af7Sopenharmony_ci
270e5c31af7Sopenharmony_ci	bool		success		= false;
271e5c31af7Sopenharmony_ci	deProcess*	serverProc	= DE_NULL;
272e5c31af7Sopenharmony_ci	FilePrinter	stdoutPrinter;
273e5c31af7Sopenharmony_ci	FilePrinter	stderrPrinter;
274e5c31af7Sopenharmony_ci
275e5c31af7Sopenharmony_ci	try
276e5c31af7Sopenharmony_ci	{
277e5c31af7Sopenharmony_ci		if (m_testCtx.startServer)
278e5c31af7Sopenharmony_ci		{
279e5c31af7Sopenharmony_ci			string cmdLine = m_testCtx.serverPath + " --port=" + de::toString(m_testCtx.address.getPort());
280e5c31af7Sopenharmony_ci			serverProc = deProcess_create();
281e5c31af7Sopenharmony_ci			XS_CHECK(serverProc);
282e5c31af7Sopenharmony_ci
283e5c31af7Sopenharmony_ci			if (!deProcess_start(serverProc, cmdLine.c_str(), DE_NULL))
284e5c31af7Sopenharmony_ci			{
285e5c31af7Sopenharmony_ci				string errMsg = deProcess_getLastError(serverProc);
286e5c31af7Sopenharmony_ci				deProcess_destroy(serverProc);
287e5c31af7Sopenharmony_ci				XS_FAIL(errMsg.c_str());
288e5c31af7Sopenharmony_ci			}
289e5c31af7Sopenharmony_ci
290e5c31af7Sopenharmony_ci			deSleep(200); /* Give 200ms for server to start. */
291e5c31af7Sopenharmony_ci			XS_CHECK(deProcess_isRunning(serverProc));
292e5c31af7Sopenharmony_ci
293e5c31af7Sopenharmony_ci			// Start stdout/stderr printers.
294e5c31af7Sopenharmony_ci			stdoutPrinter.start(deProcess_getStdOut(serverProc));
295e5c31af7Sopenharmony_ci			stderrPrinter.start(deProcess_getStdErr(serverProc));
296e5c31af7Sopenharmony_ci		}
297e5c31af7Sopenharmony_ci
298e5c31af7Sopenharmony_ci		// Connect.
299e5c31af7Sopenharmony_ci		de::Socket socket;
300e5c31af7Sopenharmony_ci		socket.connect(m_testCtx.address);
301e5c31af7Sopenharmony_ci
302e5c31af7Sopenharmony_ci		// Flags.
303e5c31af7Sopenharmony_ci		socket.setFlags(DE_SOCKET_CLOSE_ON_EXEC);
304e5c31af7Sopenharmony_ci
305e5c31af7Sopenharmony_ci		// Run case.
306e5c31af7Sopenharmony_ci		testCase->runClient(socket);
307e5c31af7Sopenharmony_ci
308e5c31af7Sopenharmony_ci		// Disconnect.
309e5c31af7Sopenharmony_ci		if (socket.isConnected())
310e5c31af7Sopenharmony_ci			socket.shutdown();
311e5c31af7Sopenharmony_ci
312e5c31af7Sopenharmony_ci		// Kill server.
313e5c31af7Sopenharmony_ci		if (serverProc && deProcess_isRunning(serverProc))
314e5c31af7Sopenharmony_ci		{
315e5c31af7Sopenharmony_ci			XS_CHECK(deProcess_terminate(serverProc));
316e5c31af7Sopenharmony_ci			deSleep(100);
317e5c31af7Sopenharmony_ci			XS_CHECK(deProcess_waitForFinish(serverProc));
318e5c31af7Sopenharmony_ci
319e5c31af7Sopenharmony_ci			stdoutPrinter.join();
320e5c31af7Sopenharmony_ci			stderrPrinter.join();
321e5c31af7Sopenharmony_ci		}
322e5c31af7Sopenharmony_ci
323e5c31af7Sopenharmony_ci		success = true;
324e5c31af7Sopenharmony_ci	}
325e5c31af7Sopenharmony_ci	catch (const std::exception& e)
326e5c31af7Sopenharmony_ci	{
327e5c31af7Sopenharmony_ci		printf("FAIL: %s\n\n", e.what());
328e5c31af7Sopenharmony_ci	}
329e5c31af7Sopenharmony_ci
330e5c31af7Sopenharmony_ci	if (serverProc)
331e5c31af7Sopenharmony_ci		deProcess_destroy(serverProc);
332e5c31af7Sopenharmony_ci
333e5c31af7Sopenharmony_ci	return success;
334e5c31af7Sopenharmony_ci}
335e5c31af7Sopenharmony_ci
336e5c31af7Sopenharmony_ciclass ConnectTest : public TestCase
337e5c31af7Sopenharmony_ci{
338e5c31af7Sopenharmony_cipublic:
339e5c31af7Sopenharmony_ci	ConnectTest (TestContext& testCtx)
340e5c31af7Sopenharmony_ci		: TestCase(testCtx, "connect")
341e5c31af7Sopenharmony_ci	{
342e5c31af7Sopenharmony_ci	}
343e5c31af7Sopenharmony_ci
344e5c31af7Sopenharmony_ci	void runClient (de::Socket& socket)
345e5c31af7Sopenharmony_ci	{
346e5c31af7Sopenharmony_ci		DE_UNREF(socket);
347e5c31af7Sopenharmony_ci	}
348e5c31af7Sopenharmony_ci
349e5c31af7Sopenharmony_ci	void runProgram (void) { /* nothing */ }
350e5c31af7Sopenharmony_ci};
351e5c31af7Sopenharmony_ci
352e5c31af7Sopenharmony_ciclass HelloTest : public TestCase
353e5c31af7Sopenharmony_ci{
354e5c31af7Sopenharmony_cipublic:
355e5c31af7Sopenharmony_ci	HelloTest (TestContext& testCtx)
356e5c31af7Sopenharmony_ci		: TestCase(testCtx, "hello")
357e5c31af7Sopenharmony_ci	{
358e5c31af7Sopenharmony_ci	}
359e5c31af7Sopenharmony_ci
360e5c31af7Sopenharmony_ci	void runClient (de::Socket& socket)
361e5c31af7Sopenharmony_ci	{
362e5c31af7Sopenharmony_ci		xs::HelloMessage msg;
363e5c31af7Sopenharmony_ci		sendMessage(socket, (const xs::Message&)msg);
364e5c31af7Sopenharmony_ci	}
365e5c31af7Sopenharmony_ci
366e5c31af7Sopenharmony_ci	void runProgram (void) { /* nothing */ }
367e5c31af7Sopenharmony_ci};
368e5c31af7Sopenharmony_ci
369e5c31af7Sopenharmony_ciclass ExecFailTest : public TestCase
370e5c31af7Sopenharmony_ci{
371e5c31af7Sopenharmony_cipublic:
372e5c31af7Sopenharmony_ci	ExecFailTest (TestContext& testCtx)
373e5c31af7Sopenharmony_ci		: TestCase(testCtx, "exec-fail")
374e5c31af7Sopenharmony_ci	{
375e5c31af7Sopenharmony_ci	}
376e5c31af7Sopenharmony_ci
377e5c31af7Sopenharmony_ci	void runClient (de::Socket& socket)
378e5c31af7Sopenharmony_ci	{
379e5c31af7Sopenharmony_ci		xs::ExecuteBinaryMessage execMsg;
380e5c31af7Sopenharmony_ci		execMsg.name		= "foobar-notfound";
381e5c31af7Sopenharmony_ci		execMsg.params		= "";
382e5c31af7Sopenharmony_ci		execMsg.caseList	= "";
383e5c31af7Sopenharmony_ci		execMsg.workDir		= "";
384e5c31af7Sopenharmony_ci
385e5c31af7Sopenharmony_ci		sendMessage(socket, execMsg);
386e5c31af7Sopenharmony_ci
387e5c31af7Sopenharmony_ci		const int		timeout		= 100; // 100ms.
388e5c31af7Sopenharmony_ci		TestClock		clock;
389e5c31af7Sopenharmony_ci
390e5c31af7Sopenharmony_ci		for (;;)
391e5c31af7Sopenharmony_ci		{
392e5c31af7Sopenharmony_ci			if (clock.getMilliseconds() > timeout)
393e5c31af7Sopenharmony_ci				XS_FAIL("Didn't receive PROCESS_LAUNCH_FAILED");
394e5c31af7Sopenharmony_ci
395e5c31af7Sopenharmony_ci			ScopedMsgPtr msg(readMessage(socket));
396e5c31af7Sopenharmony_ci
397e5c31af7Sopenharmony_ci			if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
398e5c31af7Sopenharmony_ci				break;
399e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_KEEPALIVE)
400e5c31af7Sopenharmony_ci				continue;
401e5c31af7Sopenharmony_ci			else
402e5c31af7Sopenharmony_ci				XS_FAIL("Invalid message");
403e5c31af7Sopenharmony_ci		}
404e5c31af7Sopenharmony_ci	}
405e5c31af7Sopenharmony_ci
406e5c31af7Sopenharmony_ci	void runProgram (void) { /* nothing */ }
407e5c31af7Sopenharmony_ci};
408e5c31af7Sopenharmony_ci
409e5c31af7Sopenharmony_ciclass SimpleExecTest : public TestCase
410e5c31af7Sopenharmony_ci{
411e5c31af7Sopenharmony_cipublic:
412e5c31af7Sopenharmony_ci	SimpleExecTest (TestContext& testCtx)
413e5c31af7Sopenharmony_ci		: TestCase(testCtx, "simple-exec")
414e5c31af7Sopenharmony_ci	{
415e5c31af7Sopenharmony_ci	}
416e5c31af7Sopenharmony_ci
417e5c31af7Sopenharmony_ci	void runClient (de::Socket& socket)
418e5c31af7Sopenharmony_ci	{
419e5c31af7Sopenharmony_ci		xs::ExecuteBinaryMessage execMsg;
420e5c31af7Sopenharmony_ci		execMsg.name		= m_testCtx.testerPath;
421e5c31af7Sopenharmony_ci		execMsg.params		= "--program=simple-exec";
422e5c31af7Sopenharmony_ci		execMsg.caseList	= "";
423e5c31af7Sopenharmony_ci		execMsg.workDir		= "";
424e5c31af7Sopenharmony_ci
425e5c31af7Sopenharmony_ci		sendMessage(socket, execMsg);
426e5c31af7Sopenharmony_ci
427e5c31af7Sopenharmony_ci		const int		timeout		= 5000; // 5s.
428e5c31af7Sopenharmony_ci		TestClock		clock;
429e5c31af7Sopenharmony_ci
430e5c31af7Sopenharmony_ci		bool	gotProcessStarted	= false;
431e5c31af7Sopenharmony_ci		bool	gotProcessFinished	= false;
432e5c31af7Sopenharmony_ci
433e5c31af7Sopenharmony_ci		for (;;)
434e5c31af7Sopenharmony_ci		{
435e5c31af7Sopenharmony_ci			if (clock.getMilliseconds() > timeout)
436e5c31af7Sopenharmony_ci				break;
437e5c31af7Sopenharmony_ci
438e5c31af7Sopenharmony_ci			ScopedMsgPtr msg(readMessage(socket));
439e5c31af7Sopenharmony_ci
440e5c31af7Sopenharmony_ci			if (msg->type == MESSAGETYPE_PROCESS_STARTED)
441e5c31af7Sopenharmony_ci				gotProcessStarted = true;
442e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
443e5c31af7Sopenharmony_ci				XS_FAIL("Got PROCESS_LAUNCH_FAILED");
444e5c31af7Sopenharmony_ci			else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_FINISHED)
445e5c31af7Sopenharmony_ci			{
446e5c31af7Sopenharmony_ci				gotProcessFinished = true;
447e5c31af7Sopenharmony_ci				break;
448e5c31af7Sopenharmony_ci			}
449e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_KEEPALIVE || msg->type == MESSAGETYPE_INFO)
450e5c31af7Sopenharmony_ci				continue;
451e5c31af7Sopenharmony_ci			else
452e5c31af7Sopenharmony_ci				XS_FAIL((string("Invalid message: ") + de::toString(msg->type)).c_str());
453e5c31af7Sopenharmony_ci		}
454e5c31af7Sopenharmony_ci
455e5c31af7Sopenharmony_ci		if (!gotProcessStarted)
456e5c31af7Sopenharmony_ci			XS_FAIL("Did't get PROCESS_STARTED message");
457e5c31af7Sopenharmony_ci
458e5c31af7Sopenharmony_ci		if (!gotProcessFinished)
459e5c31af7Sopenharmony_ci			XS_FAIL("Did't get PROCESS_FINISHED message");
460e5c31af7Sopenharmony_ci	}
461e5c31af7Sopenharmony_ci
462e5c31af7Sopenharmony_ci	void runProgram (void) { /* print nothing. */ }
463e5c31af7Sopenharmony_ci};
464e5c31af7Sopenharmony_ci
465e5c31af7Sopenharmony_ciclass InfoTest : public TestCase
466e5c31af7Sopenharmony_ci{
467e5c31af7Sopenharmony_cipublic:
468e5c31af7Sopenharmony_ci	std::string infoStr;
469e5c31af7Sopenharmony_ci
470e5c31af7Sopenharmony_ci	InfoTest (TestContext& testCtx)
471e5c31af7Sopenharmony_ci		: TestCase	(testCtx, "info")
472e5c31af7Sopenharmony_ci		, infoStr	("Hello, World")
473e5c31af7Sopenharmony_ci	{
474e5c31af7Sopenharmony_ci	}
475e5c31af7Sopenharmony_ci
476e5c31af7Sopenharmony_ci	void runClient (de::Socket& socket)
477e5c31af7Sopenharmony_ci	{
478e5c31af7Sopenharmony_ci		xs::ExecuteBinaryMessage execMsg;
479e5c31af7Sopenharmony_ci		execMsg.name		= m_testCtx.testerPath;
480e5c31af7Sopenharmony_ci		execMsg.params		= "--program=info";
481e5c31af7Sopenharmony_ci		execMsg.caseList	= "";
482e5c31af7Sopenharmony_ci		execMsg.workDir		= "";
483e5c31af7Sopenharmony_ci
484e5c31af7Sopenharmony_ci		sendMessage(socket, execMsg);
485e5c31af7Sopenharmony_ci
486e5c31af7Sopenharmony_ci		const int		timeout		= 10000; // 10s.
487e5c31af7Sopenharmony_ci		TestClock		clock;
488e5c31af7Sopenharmony_ci
489e5c31af7Sopenharmony_ci		bool			gotProcessStarted	= false;
490e5c31af7Sopenharmony_ci		bool			gotProcessFinished	= false;
491e5c31af7Sopenharmony_ci		std::string		receivedInfo		= "";
492e5c31af7Sopenharmony_ci
493e5c31af7Sopenharmony_ci		for (;;)
494e5c31af7Sopenharmony_ci		{
495e5c31af7Sopenharmony_ci			if (clock.getMilliseconds() > timeout)
496e5c31af7Sopenharmony_ci				break;
497e5c31af7Sopenharmony_ci
498e5c31af7Sopenharmony_ci			ScopedMsgPtr msg(readMessage(socket));
499e5c31af7Sopenharmony_ci
500e5c31af7Sopenharmony_ci			if (msg->type == MESSAGETYPE_PROCESS_STARTED)
501e5c31af7Sopenharmony_ci				gotProcessStarted = true;
502e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
503e5c31af7Sopenharmony_ci				XS_FAIL("Got PROCESS_LAUNCH_FAILED");
504e5c31af7Sopenharmony_ci			else if (gotProcessStarted && msg->type == MESSAGETYPE_INFO)
505e5c31af7Sopenharmony_ci				receivedInfo += static_cast<const InfoMessage*>(msg.get())->info;
506e5c31af7Sopenharmony_ci			else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_FINISHED)
507e5c31af7Sopenharmony_ci			{
508e5c31af7Sopenharmony_ci				gotProcessFinished = true;
509e5c31af7Sopenharmony_ci				break;
510e5c31af7Sopenharmony_ci			}
511e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_KEEPALIVE)
512e5c31af7Sopenharmony_ci				continue;
513e5c31af7Sopenharmony_ci			else
514e5c31af7Sopenharmony_ci				XS_FAIL("Invalid message");
515e5c31af7Sopenharmony_ci		}
516e5c31af7Sopenharmony_ci
517e5c31af7Sopenharmony_ci		if (!gotProcessStarted)
518e5c31af7Sopenharmony_ci			XS_FAIL("Did't get PROCESS_STARTED message");
519e5c31af7Sopenharmony_ci
520e5c31af7Sopenharmony_ci		if (!gotProcessFinished)
521e5c31af7Sopenharmony_ci			XS_FAIL("Did't get PROCESS_FINISHED message");
522e5c31af7Sopenharmony_ci
523e5c31af7Sopenharmony_ci		if (receivedInfo != infoStr)
524e5c31af7Sopenharmony_ci			XS_FAIL("Info data doesn't match");
525e5c31af7Sopenharmony_ci	}
526e5c31af7Sopenharmony_ci
527e5c31af7Sopenharmony_ci	void runProgram (void) { printf("%s", infoStr.c_str()); }
528e5c31af7Sopenharmony_ci};
529e5c31af7Sopenharmony_ci
530e5c31af7Sopenharmony_ciclass LogDataTest : public TestCase
531e5c31af7Sopenharmony_ci{
532e5c31af7Sopenharmony_cipublic:
533e5c31af7Sopenharmony_ci	LogDataTest (TestContext& testCtx)
534e5c31af7Sopenharmony_ci		: TestCase(testCtx, "logdata")
535e5c31af7Sopenharmony_ci	{
536e5c31af7Sopenharmony_ci	}
537e5c31af7Sopenharmony_ci
538e5c31af7Sopenharmony_ci	void runClient (de::Socket& socket)
539e5c31af7Sopenharmony_ci	{
540e5c31af7Sopenharmony_ci		xs::ExecuteBinaryMessage execMsg;
541e5c31af7Sopenharmony_ci		execMsg.name		= m_testCtx.testerPath;
542e5c31af7Sopenharmony_ci		execMsg.params		= "--program=logdata";
543e5c31af7Sopenharmony_ci		execMsg.caseList	= "";
544e5c31af7Sopenharmony_ci		execMsg.workDir		= "";
545e5c31af7Sopenharmony_ci
546e5c31af7Sopenharmony_ci		sendMessage(socket, execMsg);
547e5c31af7Sopenharmony_ci
548e5c31af7Sopenharmony_ci		const int		timeout		= 10000; // 10s.
549e5c31af7Sopenharmony_ci		TestClock		clock;
550e5c31af7Sopenharmony_ci
551e5c31af7Sopenharmony_ci		bool			gotProcessStarted	= false;
552e5c31af7Sopenharmony_ci		bool			gotProcessFinished	= false;
553e5c31af7Sopenharmony_ci		std::string		receivedData		= "";
554e5c31af7Sopenharmony_ci
555e5c31af7Sopenharmony_ci		for (;;)
556e5c31af7Sopenharmony_ci		{
557e5c31af7Sopenharmony_ci			if (clock.getMilliseconds() > timeout)
558e5c31af7Sopenharmony_ci				break;
559e5c31af7Sopenharmony_ci
560e5c31af7Sopenharmony_ci			ScopedMsgPtr msg(readMessage(socket));
561e5c31af7Sopenharmony_ci
562e5c31af7Sopenharmony_ci			if (msg->type == MESSAGETYPE_PROCESS_STARTED)
563e5c31af7Sopenharmony_ci				gotProcessStarted = true;
564e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
565e5c31af7Sopenharmony_ci				XS_FAIL("Got PROCESS_LAUNCH_FAILED");
566e5c31af7Sopenharmony_ci			else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_LOG_DATA)
567e5c31af7Sopenharmony_ci				receivedData += static_cast<const ProcessLogDataMessage*>(msg.get())->logData;
568e5c31af7Sopenharmony_ci			else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_FINISHED)
569e5c31af7Sopenharmony_ci			{
570e5c31af7Sopenharmony_ci				gotProcessFinished = true;
571e5c31af7Sopenharmony_ci				break;
572e5c31af7Sopenharmony_ci			}
573e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_KEEPALIVE)
574e5c31af7Sopenharmony_ci				continue;
575e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_INFO)
576e5c31af7Sopenharmony_ci				XS_FAIL(static_cast<const InfoMessage*>(msg.get())->info.c_str());
577e5c31af7Sopenharmony_ci			else
578e5c31af7Sopenharmony_ci				XS_FAIL("Invalid message");
579e5c31af7Sopenharmony_ci		}
580e5c31af7Sopenharmony_ci
581e5c31af7Sopenharmony_ci		if (!gotProcessStarted)
582e5c31af7Sopenharmony_ci			XS_FAIL("Did't get PROCESS_STARTED message");
583e5c31af7Sopenharmony_ci
584e5c31af7Sopenharmony_ci		if (!gotProcessFinished)
585e5c31af7Sopenharmony_ci			XS_FAIL("Did't get PROCESS_FINISHED message");
586e5c31af7Sopenharmony_ci
587e5c31af7Sopenharmony_ci		const char* expected = "Foo\nBar\n";
588e5c31af7Sopenharmony_ci		if (receivedData != expected)
589e5c31af7Sopenharmony_ci		{
590e5c31af7Sopenharmony_ci			printf("  received: '%s'\n  expected: '%s'\n", receivedData.c_str(), expected);
591e5c31af7Sopenharmony_ci			XS_FAIL("Log data doesn't match");
592e5c31af7Sopenharmony_ci		}
593e5c31af7Sopenharmony_ci	}
594e5c31af7Sopenharmony_ci
595e5c31af7Sopenharmony_ci	void runProgram (void)
596e5c31af7Sopenharmony_ci	{
597e5c31af7Sopenharmony_ci		deFile* file = deFile_create(m_testCtx.logFileName.c_str(), DE_FILEMODE_OPEN|DE_FILEMODE_CREATE|DE_FILEMODE_TRUNCATE|DE_FILEMODE_WRITE);
598e5c31af7Sopenharmony_ci		XS_CHECK(file);
599e5c31af7Sopenharmony_ci
600e5c31af7Sopenharmony_ci		const char line0[] = "Foo\n";
601e5c31af7Sopenharmony_ci		const char line1[] = "Bar\n";
602e5c31af7Sopenharmony_ci		deInt64 numWritten = 0;
603e5c31af7Sopenharmony_ci
604e5c31af7Sopenharmony_ci		// Write first line.
605e5c31af7Sopenharmony_ci		XS_CHECK(deFile_write(file, line0, sizeof(line0)-1, &numWritten) == DE_FILERESULT_SUCCESS);
606e5c31af7Sopenharmony_ci		XS_CHECK(numWritten == sizeof(line0)-1);
607e5c31af7Sopenharmony_ci
608e5c31af7Sopenharmony_ci		// Sleep for 0.5s and write line 2.
609e5c31af7Sopenharmony_ci		deSleep(500);
610e5c31af7Sopenharmony_ci		XS_CHECK(deFile_write(file, line1, sizeof(line1)-1, &numWritten) == DE_FILERESULT_SUCCESS);
611e5c31af7Sopenharmony_ci		XS_CHECK(numWritten == sizeof(line1)-1);
612e5c31af7Sopenharmony_ci
613e5c31af7Sopenharmony_ci		deFile_destroy(file);
614e5c31af7Sopenharmony_ci	}
615e5c31af7Sopenharmony_ci};
616e5c31af7Sopenharmony_ci
617e5c31af7Sopenharmony_ciclass BigLogDataTest : public TestCase
618e5c31af7Sopenharmony_ci{
619e5c31af7Sopenharmony_cipublic:
620e5c31af7Sopenharmony_ci	enum
621e5c31af7Sopenharmony_ci	{
622e5c31af7Sopenharmony_ci		DATA_SIZE = 100*1024*1024
623e5c31af7Sopenharmony_ci	};
624e5c31af7Sopenharmony_ci
625e5c31af7Sopenharmony_ci	BigLogDataTest (TestContext& testCtx)
626e5c31af7Sopenharmony_ci		: TestCase(testCtx, "biglogdata")
627e5c31af7Sopenharmony_ci	{
628e5c31af7Sopenharmony_ci	}
629e5c31af7Sopenharmony_ci
630e5c31af7Sopenharmony_ci	void runClient (de::Socket& socket)
631e5c31af7Sopenharmony_ci	{
632e5c31af7Sopenharmony_ci		xs::ExecuteBinaryMessage execMsg;
633e5c31af7Sopenharmony_ci		execMsg.name		= m_testCtx.testerPath;
634e5c31af7Sopenharmony_ci		execMsg.params		= "--program=biglogdata";
635e5c31af7Sopenharmony_ci		execMsg.caseList	= "";
636e5c31af7Sopenharmony_ci		execMsg.workDir		= "";
637e5c31af7Sopenharmony_ci
638e5c31af7Sopenharmony_ci		sendMessage(socket, execMsg);
639e5c31af7Sopenharmony_ci
640e5c31af7Sopenharmony_ci		const int		timeout		= 30000; // 30s.
641e5c31af7Sopenharmony_ci		TestClock		clock;
642e5c31af7Sopenharmony_ci
643e5c31af7Sopenharmony_ci		bool			gotProcessStarted	= false;
644e5c31af7Sopenharmony_ci		bool			gotProcessFinished	= false;
645e5c31af7Sopenharmony_ci		int				receivedBytes		= 0;
646e5c31af7Sopenharmony_ci
647e5c31af7Sopenharmony_ci		for (;;)
648e5c31af7Sopenharmony_ci		{
649e5c31af7Sopenharmony_ci			if (clock.getMilliseconds() > timeout)
650e5c31af7Sopenharmony_ci				break;
651e5c31af7Sopenharmony_ci
652e5c31af7Sopenharmony_ci			ScopedMsgPtr msg(readMessage(socket));
653e5c31af7Sopenharmony_ci
654e5c31af7Sopenharmony_ci			if (msg->type == MESSAGETYPE_PROCESS_STARTED)
655e5c31af7Sopenharmony_ci				gotProcessStarted = true;
656e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
657e5c31af7Sopenharmony_ci				XS_FAIL("Got PROCESS_LAUNCH_FAILED");
658e5c31af7Sopenharmony_ci			else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_LOG_DATA)
659e5c31af7Sopenharmony_ci				receivedBytes += (int)static_cast<const ProcessLogDataMessage*>(msg.get())->logData.length();
660e5c31af7Sopenharmony_ci			else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_FINISHED)
661e5c31af7Sopenharmony_ci			{
662e5c31af7Sopenharmony_ci				gotProcessFinished = true;
663e5c31af7Sopenharmony_ci				break;
664e5c31af7Sopenharmony_ci			}
665e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_KEEPALIVE)
666e5c31af7Sopenharmony_ci			{
667e5c31af7Sopenharmony_ci				// Reply with keepalive.
668e5c31af7Sopenharmony_ci				sendMessage(socket, KeepAliveMessage());
669e5c31af7Sopenharmony_ci				continue;
670e5c31af7Sopenharmony_ci			}
671e5c31af7Sopenharmony_ci			else if (msg->type == MESSAGETYPE_INFO)
672e5c31af7Sopenharmony_ci				printf("%s", static_cast<const InfoMessage*>(msg.get())->info.c_str());
673e5c31af7Sopenharmony_ci			else
674e5c31af7Sopenharmony_ci				XS_FAIL("Invalid message");
675e5c31af7Sopenharmony_ci		}
676e5c31af7Sopenharmony_ci
677e5c31af7Sopenharmony_ci		if (!gotProcessStarted)
678e5c31af7Sopenharmony_ci			XS_FAIL("Did't get PROCESS_STARTED message");
679e5c31af7Sopenharmony_ci
680e5c31af7Sopenharmony_ci		if (!gotProcessFinished)
681e5c31af7Sopenharmony_ci			XS_FAIL("Did't get PROCESS_FINISHED message");
682e5c31af7Sopenharmony_ci
683e5c31af7Sopenharmony_ci		if (receivedBytes != DATA_SIZE)
684e5c31af7Sopenharmony_ci		{
685e5c31af7Sopenharmony_ci			printf("  received: %d bytes\n  expected: %d bytes\n", receivedBytes, DATA_SIZE);
686e5c31af7Sopenharmony_ci			XS_FAIL("Log data size doesn't match");
687e5c31af7Sopenharmony_ci		}
688e5c31af7Sopenharmony_ci
689e5c31af7Sopenharmony_ci		int timeMs = clock.getMilliseconds();
690e5c31af7Sopenharmony_ci		printf("  Streamed %d bytes in %d ms: %.2f MiB/s\n", DATA_SIZE, timeMs, ((float)DATA_SIZE / (float)(1024*1024)) / ((float)timeMs / 1000.0f));
691e5c31af7Sopenharmony_ci	}
692e5c31af7Sopenharmony_ci
693e5c31af7Sopenharmony_ci	void runProgram (void)
694e5c31af7Sopenharmony_ci	{
695e5c31af7Sopenharmony_ci		deFile* file = deFile_create(m_testCtx.logFileName.c_str(), DE_FILEMODE_OPEN|DE_FILEMODE_CREATE|DE_FILEMODE_TRUNCATE|DE_FILEMODE_WRITE);
696e5c31af7Sopenharmony_ci		XS_CHECK(file);
697e5c31af7Sopenharmony_ci
698e5c31af7Sopenharmony_ci		deUint8 tmpBuf[1024*16];
699e5c31af7Sopenharmony_ci		int numWritten = 0;
700e5c31af7Sopenharmony_ci
701e5c31af7Sopenharmony_ci		deMemset(&tmpBuf, 'a', sizeof(tmpBuf));
702e5c31af7Sopenharmony_ci
703e5c31af7Sopenharmony_ci		while (numWritten < DATA_SIZE)
704e5c31af7Sopenharmony_ci		{
705e5c31af7Sopenharmony_ci			deInt64 numWrittenInBatch = 0;
706e5c31af7Sopenharmony_ci			XS_CHECK(deFile_write(file, &tmpBuf[0], de::min((int)sizeof(tmpBuf), DATA_SIZE-numWritten), &numWrittenInBatch) == DE_FILERESULT_SUCCESS);
707e5c31af7Sopenharmony_ci			numWritten += (int)numWrittenInBatch;
708e5c31af7Sopenharmony_ci		}
709e5c31af7Sopenharmony_ci
710e5c31af7Sopenharmony_ci		deFile_destroy(file);
711e5c31af7Sopenharmony_ci	}
712e5c31af7Sopenharmony_ci};
713e5c31af7Sopenharmony_ci
714e5c31af7Sopenharmony_ciclass KeepAliveTest : public TestCase
715e5c31af7Sopenharmony_ci{
716e5c31af7Sopenharmony_cipublic:
717e5c31af7Sopenharmony_ci	KeepAliveTest (TestContext& testCtx)
718e5c31af7Sopenharmony_ci		: TestCase(testCtx, "keepalive")
719e5c31af7Sopenharmony_ci	{
720e5c31af7Sopenharmony_ci	}
721e5c31af7Sopenharmony_ci
722e5c31af7Sopenharmony_ci	void runClient (de::Socket& socket)
723e5c31af7Sopenharmony_ci	{
724e5c31af7Sopenharmony_ci		// In milliseconds.
725e5c31af7Sopenharmony_ci		const int	sendInterval			= 5000;
726e5c31af7Sopenharmony_ci		const int	minReceiveInterval		= 10000;
727e5c31af7Sopenharmony_ci		const int	testTime				= 30000;
728e5c31af7Sopenharmony_ci		const int	sleepTime				= 200;
729e5c31af7Sopenharmony_ci		const int	expectedTimeout			= 40000;
730e5c31af7Sopenharmony_ci		int			curTime					= 0;
731e5c31af7Sopenharmony_ci		int			lastSendTime			= 0;
732e5c31af7Sopenharmony_ci		int			lastReceiveTime			= 0;
733e5c31af7Sopenharmony_ci		TestClock	clock;
734e5c31af7Sopenharmony_ci
735e5c31af7Sopenharmony_ci		DE_ASSERT(sendInterval < minReceiveInterval);
736e5c31af7Sopenharmony_ci
737e5c31af7Sopenharmony_ci		curTime = clock.getMilliseconds();
738e5c31af7Sopenharmony_ci
739e5c31af7Sopenharmony_ci		while (curTime < testTime)
740e5c31af7Sopenharmony_ci		{
741e5c31af7Sopenharmony_ci			bool tryGetKeepalive = false;
742e5c31af7Sopenharmony_ci
743e5c31af7Sopenharmony_ci			if (curTime-lastSendTime > sendInterval)
744e5c31af7Sopenharmony_ci			{
745e5c31af7Sopenharmony_ci				printf("  %d ms: sending keepalive\n", curTime);
746e5c31af7Sopenharmony_ci				sendMessage(socket, KeepAliveMessage());
747e5c31af7Sopenharmony_ci				curTime = clock.getMilliseconds();
748e5c31af7Sopenharmony_ci				lastSendTime = curTime;
749e5c31af7Sopenharmony_ci				tryGetKeepalive = true;
750e5c31af7Sopenharmony_ci			}
751e5c31af7Sopenharmony_ci
752e5c31af7Sopenharmony_ci			if (tryGetKeepalive)
753e5c31af7Sopenharmony_ci			{
754e5c31af7Sopenharmony_ci				// Try to acquire keepalive.
755e5c31af7Sopenharmony_ci				printf("  %d ms: waiting for keepalive\n", curTime);
756e5c31af7Sopenharmony_ci				ScopedMsgPtr msg(readMessage(socket));
757e5c31af7Sopenharmony_ci				int recvTime = clock.getMilliseconds();
758e5c31af7Sopenharmony_ci
759e5c31af7Sopenharmony_ci				if (msg->type != MESSAGETYPE_KEEPALIVE)
760e5c31af7Sopenharmony_ci					XS_FAIL("Got invalid message");
761e5c31af7Sopenharmony_ci
762e5c31af7Sopenharmony_ci				printf("  %d ms: got keepalive\n", curTime);
763e5c31af7Sopenharmony_ci
764e5c31af7Sopenharmony_ci				if (recvTime-lastReceiveTime > minReceiveInterval)
765e5c31af7Sopenharmony_ci					XS_FAIL("Server doesn't send keepalives");
766e5c31af7Sopenharmony_ci
767e5c31af7Sopenharmony_ci				lastReceiveTime = recvTime;
768e5c31af7Sopenharmony_ci			}
769e5c31af7Sopenharmony_ci
770e5c31af7Sopenharmony_ci			deSleep(sleepTime);
771e5c31af7Sopenharmony_ci			curTime = clock.getMilliseconds();
772e5c31af7Sopenharmony_ci		}
773e5c31af7Sopenharmony_ci
774e5c31af7Sopenharmony_ci		// Verify that server actually kills the connection upon timeout.
775e5c31af7Sopenharmony_ci		sendMessage(socket, KeepAliveMessage());
776e5c31af7Sopenharmony_ci		printf("  waiting %d ms for keepalive timeout...\n", expectedTimeout);
777e5c31af7Sopenharmony_ci		bool isClosed = false;
778e5c31af7Sopenharmony_ci
779e5c31af7Sopenharmony_ci		try
780e5c31af7Sopenharmony_ci		{
781e5c31af7Sopenharmony_ci			// Reset timer.
782e5c31af7Sopenharmony_ci			clock.reset();
783e5c31af7Sopenharmony_ci			curTime = clock.getMilliseconds();
784e5c31af7Sopenharmony_ci
785e5c31af7Sopenharmony_ci			while (curTime < expectedTimeout)
786e5c31af7Sopenharmony_ci			{
787e5c31af7Sopenharmony_ci				// Try to get keepalive message.
788e5c31af7Sopenharmony_ci				ScopedMsgPtr msg(readMessage(socket));
789e5c31af7Sopenharmony_ci				if (msg->type != MESSAGETYPE_KEEPALIVE)
790e5c31af7Sopenharmony_ci					XS_FAIL("Got invalid message");
791e5c31af7Sopenharmony_ci
792e5c31af7Sopenharmony_ci				curTime = clock.getMilliseconds();
793e5c31af7Sopenharmony_ci				printf("  %d ms: got keepalive\n", curTime);
794e5c31af7Sopenharmony_ci			}
795e5c31af7Sopenharmony_ci		}
796e5c31af7Sopenharmony_ci		catch (const SocketError& e)
797e5c31af7Sopenharmony_ci		{
798e5c31af7Sopenharmony_ci			if (e.getResult() == DE_SOCKETRESULT_CONNECTION_CLOSED)
799e5c31af7Sopenharmony_ci			{
800e5c31af7Sopenharmony_ci				printf("  %d ms: server closed connection", clock.getMilliseconds());
801e5c31af7Sopenharmony_ci				isClosed = true;
802e5c31af7Sopenharmony_ci			}
803e5c31af7Sopenharmony_ci			else
804e5c31af7Sopenharmony_ci				throw;
805e5c31af7Sopenharmony_ci		}
806e5c31af7Sopenharmony_ci
807e5c31af7Sopenharmony_ci		if (isClosed)
808e5c31af7Sopenharmony_ci			printf("  ok!\n");
809e5c31af7Sopenharmony_ci		else
810e5c31af7Sopenharmony_ci			XS_FAIL("Server didn't close connection");
811e5c31af7Sopenharmony_ci	}
812e5c31af7Sopenharmony_ci
813e5c31af7Sopenharmony_ci	void runProgram (void) { /* nothing */ }
814e5c31af7Sopenharmony_ci};
815e5c31af7Sopenharmony_ci
816e5c31af7Sopenharmony_civoid printHelp (const char* binName)
817e5c31af7Sopenharmony_ci{
818e5c31af7Sopenharmony_ci	printf("%s:\n", binName);
819e5c31af7Sopenharmony_ci	printf("  --client=[name]       Run test [name]\n");
820e5c31af7Sopenharmony_ci	printf("  --program=[name]      Run program for test [name]\n");
821e5c31af7Sopenharmony_ci	printf("  --host=[host]         Connect to host [host]\n");
822e5c31af7Sopenharmony_ci	printf("  --port=[name]         Use port [port]\n");
823e5c31af7Sopenharmony_ci	printf("  --tester-cmd=[cmd]    Launch tester with [cmd]\n");
824e5c31af7Sopenharmony_ci	printf("  --server-cmd=[cmd]    Launch server with [cmd]\n");
825e5c31af7Sopenharmony_ci	printf("  --start-server        Start server for test execution\n");
826e5c31af7Sopenharmony_ci}
827e5c31af7Sopenharmony_ci
828e5c31af7Sopenharmony_cistruct CompareCaseName
829e5c31af7Sopenharmony_ci{
830e5c31af7Sopenharmony_ci	std::string name;
831e5c31af7Sopenharmony_ci
832e5c31af7Sopenharmony_ci	CompareCaseName (const string& name_) : name(name_) {}
833e5c31af7Sopenharmony_ci
834e5c31af7Sopenharmony_ci	bool operator() (const TestCase* testCase) const
835e5c31af7Sopenharmony_ci	{
836e5c31af7Sopenharmony_ci		return name == testCase->getName();
837e5c31af7Sopenharmony_ci	}
838e5c31af7Sopenharmony_ci};
839e5c31af7Sopenharmony_ci
840e5c31af7Sopenharmony_civoid runExecServerTests (int argc, const char* const* argv)
841e5c31af7Sopenharmony_ci{
842e5c31af7Sopenharmony_ci	// Construct test context.
843e5c31af7Sopenharmony_ci	TestContext testCtx;
844e5c31af7Sopenharmony_ci
845e5c31af7Sopenharmony_ci	testCtx.serverPath	= "execserver";
846e5c31af7Sopenharmony_ci	testCtx.testerPath	= argv[0];
847e5c31af7Sopenharmony_ci	testCtx.startServer	= false;
848e5c31af7Sopenharmony_ci	testCtx.address.setHost("127.0.0.1");
849e5c31af7Sopenharmony_ci	testCtx.address.setPort(50016);
850e5c31af7Sopenharmony_ci
851e5c31af7Sopenharmony_ci	std::string runClient = "";
852e5c31af7Sopenharmony_ci	std::string runProgram = "";
853e5c31af7Sopenharmony_ci
854e5c31af7Sopenharmony_ci	// Parse command line.
855e5c31af7Sopenharmony_ci	for (int argNdx = 1; argNdx < argc; argNdx++)
856e5c31af7Sopenharmony_ci	{
857e5c31af7Sopenharmony_ci		const char* arg = argv[argNdx];
858e5c31af7Sopenharmony_ci
859e5c31af7Sopenharmony_ci		if (deStringBeginsWith(arg, "--client="))
860e5c31af7Sopenharmony_ci			runClient = arg+9;
861e5c31af7Sopenharmony_ci		else if (deStringBeginsWith(arg, "--program="))
862e5c31af7Sopenharmony_ci			runProgram = arg+10;
863e5c31af7Sopenharmony_ci		else if (deStringBeginsWith(arg, "--port="))
864e5c31af7Sopenharmony_ci			testCtx.address.setPort(atoi(arg+7));
865e5c31af7Sopenharmony_ci		else if (deStringBeginsWith(arg, "--host="))
866e5c31af7Sopenharmony_ci			testCtx.address.setHost(arg+7);
867e5c31af7Sopenharmony_ci		else if (deStringBeginsWith(arg, "--server-cmd="))
868e5c31af7Sopenharmony_ci			testCtx.serverPath = arg+13;
869e5c31af7Sopenharmony_ci		else if (deStringBeginsWith(arg, "--tester-cmd="))
870e5c31af7Sopenharmony_ci			testCtx.testerPath = arg+13;
871e5c31af7Sopenharmony_ci		else if (deStringBeginsWith(arg, "--deqp-log-filename="))
872e5c31af7Sopenharmony_ci			testCtx.logFileName = arg+20;
873e5c31af7Sopenharmony_ci		else if (deStringBeginsWith(arg, "--deqp-caselist="))
874e5c31af7Sopenharmony_ci			testCtx.caseList = arg+16;
875e5c31af7Sopenharmony_ci		else if (deStringEqual(arg, "--deqp-stdin-caselist"))
876e5c31af7Sopenharmony_ci		{
877e5c31af7Sopenharmony_ci			// \todo [pyry] This is rather brute-force solution...
878e5c31af7Sopenharmony_ci			char c;
879e5c31af7Sopenharmony_ci			while (fread(&c, 1, 1, stdin) == 1 && c != 0)
880e5c31af7Sopenharmony_ci				testCtx.caseList += c;
881e5c31af7Sopenharmony_ci		}
882e5c31af7Sopenharmony_ci		else if (deStringEqual(arg, "--start-server"))
883e5c31af7Sopenharmony_ci			testCtx.startServer = true;
884e5c31af7Sopenharmony_ci		else
885e5c31af7Sopenharmony_ci		{
886e5c31af7Sopenharmony_ci			printHelp(argv[0]);
887e5c31af7Sopenharmony_ci			return;
888e5c31af7Sopenharmony_ci		}
889e5c31af7Sopenharmony_ci	}
890e5c31af7Sopenharmony_ci
891e5c31af7Sopenharmony_ci	// Test case list.
892e5c31af7Sopenharmony_ci	std::vector<TestCase*> testCases;
893e5c31af7Sopenharmony_ci	testCases.push_back(new ConnectTest(testCtx));
894e5c31af7Sopenharmony_ci	testCases.push_back(new HelloTest(testCtx));
895e5c31af7Sopenharmony_ci	testCases.push_back(new ExecFailTest(testCtx));
896e5c31af7Sopenharmony_ci	testCases.push_back(new SimpleExecTest(testCtx));
897e5c31af7Sopenharmony_ci	testCases.push_back(new InfoTest(testCtx));
898e5c31af7Sopenharmony_ci	testCases.push_back(new LogDataTest(testCtx));
899e5c31af7Sopenharmony_ci	testCases.push_back(new KeepAliveTest(testCtx));
900e5c31af7Sopenharmony_ci	testCases.push_back(new BigLogDataTest(testCtx));
901e5c31af7Sopenharmony_ci
902e5c31af7Sopenharmony_ci	try
903e5c31af7Sopenharmony_ci	{
904e5c31af7Sopenharmony_ci		if (!runClient.empty())
905e5c31af7Sopenharmony_ci		{
906e5c31af7Sopenharmony_ci			// Run single case.
907e5c31af7Sopenharmony_ci			vector<TestCase*>::iterator casePos = std::find_if(testCases.begin(), testCases.end(), CompareCaseName(runClient));
908e5c31af7Sopenharmony_ci			XS_CHECK(casePos != testCases.end());
909e5c31af7Sopenharmony_ci			TestExecutor executor(testCtx);
910e5c31af7Sopenharmony_ci			executor.runCase(*casePos);
911e5c31af7Sopenharmony_ci		}
912e5c31af7Sopenharmony_ci		else if (!runProgram.empty())
913e5c31af7Sopenharmony_ci		{
914e5c31af7Sopenharmony_ci			// Run program part.
915e5c31af7Sopenharmony_ci			vector<TestCase*>::iterator casePos = std::find_if(testCases.begin(), testCases.end(), CompareCaseName(runProgram));
916e5c31af7Sopenharmony_ci			XS_CHECK(casePos != testCases.end());
917e5c31af7Sopenharmony_ci			(*casePos)->runProgram();
918e5c31af7Sopenharmony_ci			fflush(stdout);	// Make sure handles are flushed.
919e5c31af7Sopenharmony_ci			fflush(stderr);
920e5c31af7Sopenharmony_ci		}
921e5c31af7Sopenharmony_ci		else
922e5c31af7Sopenharmony_ci		{
923e5c31af7Sopenharmony_ci			// Run all tests.
924e5c31af7Sopenharmony_ci			TestExecutor executor(testCtx);
925e5c31af7Sopenharmony_ci			executor.runCases(testCases);
926e5c31af7Sopenharmony_ci		}
927e5c31af7Sopenharmony_ci	}
928e5c31af7Sopenharmony_ci	catch (const std::exception& e)
929e5c31af7Sopenharmony_ci	{
930e5c31af7Sopenharmony_ci		printf("ERROR: %s\n", e.what());
931e5c31af7Sopenharmony_ci	}
932e5c31af7Sopenharmony_ci
933e5c31af7Sopenharmony_ci	// Destroy cases.
934e5c31af7Sopenharmony_ci	for (std::vector<TestCase*>::const_iterator i = testCases.begin(); i != testCases.end(); i++)
935e5c31af7Sopenharmony_ci		delete *i;
936e5c31af7Sopenharmony_ci}
937e5c31af7Sopenharmony_ci
938e5c31af7Sopenharmony_ci} // xs
939e5c31af7Sopenharmony_ci
940e5c31af7Sopenharmony_ci#if 0
941e5c31af7Sopenharmony_civoid testProcFile (void)
942e5c31af7Sopenharmony_ci{
943e5c31af7Sopenharmony_ci	/* Test file api. */
944e5c31af7Sopenharmony_ci	if (deFileExists("test.txt"))
945e5c31af7Sopenharmony_ci		deDeleteFile("test.txt");
946e5c31af7Sopenharmony_ci	deFile* file = deFile_create("test.txt", DE_FILEMODE_CREATE|DE_FILEMODE_WRITE);
947e5c31af7Sopenharmony_ci	const char test[] = "Hello";
948e5c31af7Sopenharmony_ci	XS_CHECK(deFile_write(file, test, sizeof(test), DE_NULL) == DE_FILERESULT_SUCCESS);
949e5c31af7Sopenharmony_ci	deFile_destroy(file);
950e5c31af7Sopenharmony_ci
951e5c31af7Sopenharmony_ci	/* Read. */
952e5c31af7Sopenharmony_ci	char buf[10] = { 0 };
953e5c31af7Sopenharmony_ci	file = deFile_create("test.txt", DE_FILEMODE_OPEN|DE_FILEMODE_READ);
954e5c31af7Sopenharmony_ci	XS_CHECK(deFile_read(file, buf, sizeof(test), DE_NULL) == DE_FILERESULT_SUCCESS);
955e5c31af7Sopenharmony_ci	printf("buf: %s\n", buf);
956e5c31af7Sopenharmony_ci	deFile_destroy(file);
957e5c31af7Sopenharmony_ci
958e5c31af7Sopenharmony_ci	/* Process test. */
959e5c31af7Sopenharmony_ci	deProcess* proc = deProcess_create("ls -lah /Users/pyry", DE_NULL);
960e5c31af7Sopenharmony_ci	deFile* out = deProcess_getStdOut(proc);
961e5c31af7Sopenharmony_ci
962e5c31af7Sopenharmony_ci	deInt64 numRead = 0;
963e5c31af7Sopenharmony_ci	printf("ls:\n");
964e5c31af7Sopenharmony_ci	while (deFile_read(out, buf, sizeof(buf)-1, &numRead) == DE_FILERESULT_SUCCESS)
965e5c31af7Sopenharmony_ci	{
966e5c31af7Sopenharmony_ci		buf[numRead] = 0;
967e5c31af7Sopenharmony_ci		printf("%s", buf);
968e5c31af7Sopenharmony_ci	}
969e5c31af7Sopenharmony_ci	deProcess_destroy(proc);
970e5c31af7Sopenharmony_ci}
971e5c31af7Sopenharmony_ci#endif
972e5c31af7Sopenharmony_ci
973e5c31af7Sopenharmony_ci#if 0
974e5c31af7Sopenharmony_civoid testBlockingFile (const char* filename)
975e5c31af7Sopenharmony_ci{
976e5c31af7Sopenharmony_ci	deRandom	rnd;
977e5c31af7Sopenharmony_ci	int			dataSize	= 1024*1024;
978e5c31af7Sopenharmony_ci	deUint8*	data		= (deUint8*)deCalloc(dataSize);
979e5c31af7Sopenharmony_ci	deFile*		file;
980e5c31af7Sopenharmony_ci
981e5c31af7Sopenharmony_ci	deRandom_init(&rnd, 0);
982e5c31af7Sopenharmony_ci
983e5c31af7Sopenharmony_ci	if (deFileExists(filename))
984e5c31af7Sopenharmony_ci		DE_VERIFY(deDeleteFile(filename));
985e5c31af7Sopenharmony_ci
986e5c31af7Sopenharmony_ci	/* Fill in with random data. */
987e5c31af7Sopenharmony_ci	DE_ASSERT(dataSize % sizeof(int) == 0);
988e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < (int)(dataSize/sizeof(int)); ndx++)
989e5c31af7Sopenharmony_ci		((deUint32*)data)[ndx] = deRandom_getUint32(&rnd);
990e5c31af7Sopenharmony_ci
991e5c31af7Sopenharmony_ci	/* Write with random-sized blocks. */
992e5c31af7Sopenharmony_ci	file = deFile_create(filename, DE_FILEMODE_CREATE|DE_FILEMODE_WRITE);
993e5c31af7Sopenharmony_ci	DE_VERIFY(file);
994e5c31af7Sopenharmony_ci
995e5c31af7Sopenharmony_ci	int curPos = 0;
996e5c31af7Sopenharmony_ci	while (curPos < dataSize)
997e5c31af7Sopenharmony_ci	{
998e5c31af7Sopenharmony_ci		int				blockSize	= 1 + deRandom_getUint32(&rnd) % (dataSize-curPos);
999e5c31af7Sopenharmony_ci		deInt64			numWritten	= 0;
1000e5c31af7Sopenharmony_ci		deFileResult	result		= deFile_write(file, &data[curPos], blockSize, &numWritten);
1001e5c31af7Sopenharmony_ci
1002e5c31af7Sopenharmony_ci		DE_VERIFY(result == DE_FILERESULT_SUCCESS);
1003e5c31af7Sopenharmony_ci		DE_VERIFY(numWritten == blockSize);
1004e5c31af7Sopenharmony_ci
1005e5c31af7Sopenharmony_ci		curPos += blockSize;
1006e5c31af7Sopenharmony_ci	}
1007e5c31af7Sopenharmony_ci
1008e5c31af7Sopenharmony_ci	deFile_destroy(file);
1009e5c31af7Sopenharmony_ci
1010e5c31af7Sopenharmony_ci	/* Read and verify file. */
1011e5c31af7Sopenharmony_ci	file	= deFile_create(filename, DE_FILEMODE_OPEN|DE_FILEMODE_READ);
1012e5c31af7Sopenharmony_ci	curPos	= 0;
1013e5c31af7Sopenharmony_ci	while (curPos < dataSize)
1014e5c31af7Sopenharmony_ci	{
1015e5c31af7Sopenharmony_ci		deUint8			block[1024];
1016e5c31af7Sopenharmony_ci		int				numToRead	= 1 + deRandom_getUint32(&rnd) % deMin(dataSize-curPos, DE_LENGTH_OF_ARRAY(block));
1017e5c31af7Sopenharmony_ci		deInt64			numRead		= 0;
1018e5c31af7Sopenharmony_ci		deFileResult	result		= deFile_read(file, block, numToRead, &numRead);
1019e5c31af7Sopenharmony_ci
1020e5c31af7Sopenharmony_ci		DE_VERIFY(result == DE_FILERESULT_SUCCESS);
1021e5c31af7Sopenharmony_ci		DE_VERIFY((int)numRead == numToRead);
1022e5c31af7Sopenharmony_ci		DE_VERIFY(deMemCmp(block, &data[curPos], numToRead) == 0);
1023e5c31af7Sopenharmony_ci
1024e5c31af7Sopenharmony_ci		curPos += numToRead;
1025e5c31af7Sopenharmony_ci	}
1026e5c31af7Sopenharmony_ci	deFile_destroy(file);
1027e5c31af7Sopenharmony_ci}
1028e5c31af7Sopenharmony_ci#endif
1029e5c31af7Sopenharmony_ci
1030e5c31af7Sopenharmony_ciint main (int argc, const char* const* argv)
1031e5c31af7Sopenharmony_ci{
1032e5c31af7Sopenharmony_ci	xs::runExecServerTests(argc, argv);
1033e5c31af7Sopenharmony_ci	return 0;
1034e5c31af7Sopenharmony_ci}
1035