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 
31 using std::string;
32 using std::vector;
33 
34 #if 0
35 #	define DBG_PRINT(X) printf X
36 #else
37 #	define DBG_PRINT(X)
38 #endif
39 
40 namespace xs
41 {
42 
TestDriver(xs::TestProcess * testProcess)43 TestDriver::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 
~TestDriver(void)52 TestDriver::~TestDriver (void)
53 {
54 	reset();
55 }
56 
reset(void)57 void TestDriver::reset (void)
58 {
59 	m_process->cleanup();
60 
61 	m_state = STATE_NOT_STARTED;
62 }
63 
startProcess(const char * name,const char * params,const char * workingDir,const char * caseList)64 void 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 
stopProcess(void)79 void TestDriver::stopProcess (void)
80 {
81 	m_process->terminate();
82 }
83 
poll(ByteBuffer & messageBuffer)84 bool 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 
pollLogFile(ByteBuffer & messageBuffer)182 bool TestDriver::pollLogFile (ByteBuffer& messageBuffer)
183 {
184 	return pollBuffer(messageBuffer, MESSAGETYPE_PROCESS_LOG_DATA);
185 }
186 
pollInfo(ByteBuffer & messageBuffer)187 bool TestDriver::pollInfo (ByteBuffer& messageBuffer)
188 {
189 	return pollBuffer(messageBuffer, MESSAGETYPE_INFO);
190 }
191 
pollBuffer(ByteBuffer & messageBuffer,MessageType msgType)192 bool 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 
writeMessage(ByteBuffer & messageBuffer,const Message & message)227 bool 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