1/*-------------------------------------------------------------------------
2 * drawElements Quality Program Execution Server
3 * ---------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Test Driver.
22 *//*--------------------------------------------------------------------*/
23
24#include "xsTestDriver.hpp"
25#include "deClock.h"
26
27#include <string>
28#include <vector>
29#include <cstdio>
30
31using std::string;
32using std::vector;
33
34#if 0
35#	define DBG_PRINT(X) printf X
36#else
37#	define DBG_PRINT(X)
38#endif
39
40namespace xs
41{
42
43TestDriver::TestDriver (xs::TestProcess* testProcess)
44	: m_state				(STATE_NOT_STARTED)
45	, m_lastExitCode		(0)
46	, m_process				(testProcess)
47	, m_lastProcessDataTime	(0)
48	, m_dataMsgTmpBuf		(SEND_RECV_TMP_BUFFER_SIZE)
49{
50}
51
52TestDriver::~TestDriver (void)
53{
54	reset();
55}
56
57void TestDriver::reset (void)
58{
59	m_process->cleanup();
60
61	m_state = STATE_NOT_STARTED;
62}
63
64void TestDriver::startProcess (const char* name, const char* params, const char* workingDir, const char* caseList)
65{
66	try
67	{
68		m_process->start(name, params, workingDir, caseList);
69		m_state = STATE_PROCESS_STARTED;
70	}
71	catch (const TestProcessException& e)
72	{
73		printf("Failed to launch test process: %s\n", e.what());
74		m_state				= STATE_PROCESS_LAUNCH_FAILED;
75		m_lastLaunchFailure	= e.what();
76	}
77}
78
79void TestDriver::stopProcess (void)
80{
81	m_process->terminate();
82}
83
84bool TestDriver::poll (ByteBuffer& messageBuffer)
85{
86	switch (m_state)
87	{
88		case STATE_NOT_STARTED:
89			return false; // Nothing to report.
90
91		case STATE_PROCESS_LAUNCH_FAILED:
92			DBG_PRINT(("  STATE_PROCESS_LAUNCH_FAILED\n"));
93			if (writeMessage(messageBuffer, ProcessLaunchFailedMessage(m_lastLaunchFailure.c_str())))
94			{
95				m_state				= STATE_NOT_STARTED;
96				m_lastLaunchFailure	= "";
97				return true;
98			}
99			else
100				return false;
101
102		case STATE_PROCESS_STARTED:
103			DBG_PRINT(("  STATE_PROCESS_STARTED\n"));
104			if (writeMessage(messageBuffer, ProcessStartedMessage()))
105			{
106				m_state = STATE_PROCESS_RUNNING;
107				return true;
108			}
109			else
110				return false;
111
112		case STATE_PROCESS_RUNNING:
113		{
114			DBG_PRINT(("  STATE_PROCESS_RUNNING\n"));
115			bool gotProcessData = false;
116
117			// Poll log file and info buffer.
118			gotProcessData = pollLogFile(messageBuffer)	|| gotProcessData;
119			gotProcessData = pollInfo(messageBuffer)	|| gotProcessData;
120
121			if (gotProcessData)
122				return true; // Got IO.
123
124			if (!m_process->isRunning())
125			{
126				// Process died.
127				m_state					= STATE_READING_DATA;
128				m_lastExitCode			= m_process->getExitCode();
129				m_lastProcessDataTime	= deGetMicroseconds();
130
131				return true; // Got state change.
132			}
133
134			return false; // Nothing to report.
135		}
136
137		case STATE_READING_DATA:
138		{
139			DBG_PRINT(("  STATE_READING_DATA\n"));
140			bool gotProcessData = false;
141
142			// Poll log file and info buffer.
143			gotProcessData = pollLogFile(messageBuffer)	|| gotProcessData;
144			gotProcessData = pollInfo(messageBuffer)	|| gotProcessData;
145
146			if (gotProcessData)
147			{
148				// Got data.
149				m_lastProcessDataTime = deGetMicroseconds();
150				return true;
151			}
152			else if (deGetMicroseconds() - m_lastProcessDataTime > READ_DATA_TIMEOUT*1000)
153			{
154				// Read timeout occurred.
155				m_state = STATE_PROCESS_FINISHED;
156				return true; // State change.
157			}
158			else
159				return false; // Still waiting for data.
160		}
161
162		case STATE_PROCESS_FINISHED:
163			DBG_PRINT(("  STATE_PROCESS_FINISHED\n"));
164			if (writeMessage(messageBuffer, ProcessFinishedMessage(m_lastExitCode)))
165			{
166				// Signal TestProcess to clean up any remaining resources.
167				m_process->cleanup();
168
169				m_state			= STATE_NOT_STARTED;
170				m_lastExitCode	= 0;
171				return true;
172			}
173			else
174				return false;
175
176		default:
177			DE_ASSERT(DE_FALSE);
178			return false;
179	}
180}
181
182bool TestDriver::pollLogFile (ByteBuffer& messageBuffer)
183{
184	return pollBuffer(messageBuffer, MESSAGETYPE_PROCESS_LOG_DATA);
185}
186
187bool TestDriver::pollInfo (ByteBuffer& messageBuffer)
188{
189	return pollBuffer(messageBuffer, MESSAGETYPE_INFO);
190}
191
192bool TestDriver::pollBuffer (ByteBuffer& messageBuffer, MessageType msgType)
193{
194	const int minBytesAvailable = MESSAGE_HEADER_SIZE + MIN_MSG_PAYLOAD_SIZE;
195
196	if (messageBuffer.getNumFree() < minBytesAvailable)
197		return false; // Not enough space in message buffer.
198
199	const int	maxMsgSize	= de::min((int)m_dataMsgTmpBuf.size(), messageBuffer.getNumFree());
200	int			numRead		= 0;
201	int			msgSize		= MESSAGE_HEADER_SIZE+1; // One byte is reserved for terminating 0.
202
203	// Fill in data \note Last byte is reserved for 0.
204	numRead = msgType == MESSAGETYPE_PROCESS_LOG_DATA
205			? m_process->readTestLog(&m_dataMsgTmpBuf[MESSAGE_HEADER_SIZE], maxMsgSize-MESSAGE_HEADER_SIZE-1)
206			: m_process->readInfoLog(&m_dataMsgTmpBuf[MESSAGE_HEADER_SIZE], maxMsgSize-MESSAGE_HEADER_SIZE-1);
207
208	if (numRead <= 0)
209		return false; // Didn't get any data.
210
211	msgSize += numRead;
212
213	// Terminate with 0.
214	m_dataMsgTmpBuf[msgSize-1] = 0;
215
216	// Write header.
217	Message::writeHeader(msgType, msgSize, &m_dataMsgTmpBuf[0], MESSAGE_HEADER_SIZE);
218
219	// Write to messagebuffer.
220	messageBuffer.pushFront(&m_dataMsgTmpBuf[0], msgSize);
221
222	DBG_PRINT(("  wrote %d bytes of %s data\n", msgSize, msgType == MESSAGETYPE_INFO ? "info" : "log"));
223
224	return true;
225}
226
227bool TestDriver::writeMessage (ByteBuffer& messageBuffer, const Message& message)
228{
229	vector<deUint8> buf;
230	message.write(buf);
231
232	if (messageBuffer.getNumFree() < (int)buf.size())
233		return false;
234
235	messageBuffer.pushFront(&buf[0], (int)buf.size());
236	return true;
237}
238
239} // xs
240