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