You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
411 lines
8.5 KiB
411 lines
8.5 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program Tester Core
|
|
* ----------------------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*//*!
|
|
* \file
|
|
* \brief iOS App Wrapper.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "tcuIOSApp.h"
|
|
#include "tcuIOSPlatform.hh"
|
|
#include "tcuApp.hpp"
|
|
#include "tcuCommandLine.hpp"
|
|
#include "tcuRenderTarget.hpp"
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuResource.hpp"
|
|
#include "deThread.hpp"
|
|
#include "deMutex.hpp"
|
|
#include "xsExecutionServer.hpp"
|
|
#include "xsTestProcess.hpp"
|
|
#include "xsPosixFileReader.hpp"
|
|
#include "deFilePath.hpp"
|
|
#include "deClock.h"
|
|
#include "deMemory.h"
|
|
|
|
#include <string>
|
|
|
|
#import <Foundation/NSObject.h>
|
|
#import <Foundation/NSString.h>
|
|
#import <Foundation/NSBundle.h>
|
|
#import <Foundation/NSPathUtilities.h>
|
|
|
|
using std::string;
|
|
|
|
namespace
|
|
{
|
|
|
|
class TestThreadState
|
|
{
|
|
public:
|
|
enum State
|
|
{
|
|
STATE_NOT_RUNNING = 0,
|
|
STATE_RUNNING,
|
|
STATE_STOP_REQUESTED,
|
|
|
|
STATE_LAST
|
|
};
|
|
|
|
TestThreadState (void);
|
|
~TestThreadState (void);
|
|
|
|
void requestStart (const char* cmdLine);
|
|
void requestStop (void);
|
|
State getState (void);
|
|
|
|
void testExecFinished (void);
|
|
|
|
const char* getCommandLine (void) const { return m_cmdLine.c_str(); }
|
|
|
|
private:
|
|
de::Mutex m_lock;
|
|
|
|
State m_state;
|
|
std::string m_cmdLine;
|
|
};
|
|
|
|
TestThreadState::TestThreadState (void)
|
|
: m_state(STATE_NOT_RUNNING)
|
|
{
|
|
}
|
|
|
|
TestThreadState::~TestThreadState (void)
|
|
{
|
|
}
|
|
|
|
void TestThreadState::requestStart (const char* cmdLine)
|
|
{
|
|
de::ScopedLock stateLock(m_lock);
|
|
|
|
TCU_CHECK(m_state == STATE_NOT_RUNNING);
|
|
|
|
m_cmdLine = cmdLine;
|
|
m_state = STATE_RUNNING;
|
|
}
|
|
|
|
void TestThreadState::requestStop (void)
|
|
{
|
|
de::ScopedLock stateLock(m_lock);
|
|
|
|
if (m_state != STATE_NOT_RUNNING)
|
|
m_state = STATE_STOP_REQUESTED;
|
|
}
|
|
|
|
void TestThreadState::testExecFinished (void)
|
|
{
|
|
de::ScopedLock stateLock(m_lock);
|
|
m_state = STATE_NOT_RUNNING;
|
|
}
|
|
|
|
TestThreadState::State TestThreadState::getState (void)
|
|
{
|
|
de::ScopedLock stateLock(m_lock);
|
|
return m_state;
|
|
}
|
|
|
|
class LocalTestProcess : public xs::TestProcess
|
|
{
|
|
public:
|
|
LocalTestProcess (TestThreadState& state, const char* logFileName);
|
|
~LocalTestProcess (void);
|
|
|
|
void start (const char* name, const char* params, const char* workingDir, const char* caseList);
|
|
void terminate (void);
|
|
void cleanup (void);
|
|
|
|
bool isRunning (void);
|
|
int getExitCode (void) const { return 0; /* not available */ }
|
|
|
|
int readInfoLog (deUint8* dst, int numBytes) { DE_UNREF(dst && numBytes); return 0; /* not supported */ }
|
|
int readTestLog (deUint8* dst, int numBytes);
|
|
|
|
const char* getLogFileName (void) const { return m_logFileName.c_str(); }
|
|
|
|
private:
|
|
TestThreadState& m_state;
|
|
string m_logFileName;
|
|
xs::posix::FileReader m_logReader;
|
|
deUint64 m_processStartTime;
|
|
};
|
|
|
|
LocalTestProcess::LocalTestProcess (TestThreadState& state, const char* logFileName)
|
|
: m_state (state)
|
|
, m_logFileName (logFileName)
|
|
, m_logReader (xs::LOG_BUFFER_BLOCK_SIZE, xs::LOG_BUFFER_NUM_BLOCKS)
|
|
, m_processStartTime (0)
|
|
{
|
|
}
|
|
|
|
LocalTestProcess::~LocalTestProcess (void)
|
|
{
|
|
}
|
|
|
|
void LocalTestProcess::start (const char* name, const char* params, const char* workingDir, const char* caseList)
|
|
{
|
|
DE_UNREF(name && workingDir);
|
|
|
|
// Delete old log file.
|
|
if (deFileExists(m_logFileName.c_str()))
|
|
TCU_CHECK(deDeleteFile(m_logFileName.c_str()));
|
|
|
|
string cmdLine = string("deqp");
|
|
if (caseList && strlen(caseList) > 0)
|
|
cmdLine += string(" --deqp-caselist=") + caseList;
|
|
|
|
if (params && strlen(params) > 0)
|
|
cmdLine += string(" ") + params;
|
|
|
|
m_state.requestStart(cmdLine.c_str());
|
|
m_processStartTime = deGetMicroseconds();
|
|
}
|
|
|
|
void LocalTestProcess::terminate (void)
|
|
{
|
|
m_state.requestStop();
|
|
}
|
|
|
|
void LocalTestProcess::cleanup (void)
|
|
{
|
|
if (isRunning())
|
|
{
|
|
m_state.requestStop();
|
|
|
|
// Wait until stopped.
|
|
while (isRunning())
|
|
deSleep(50);
|
|
}
|
|
|
|
m_logReader.stop();
|
|
}
|
|
|
|
bool LocalTestProcess::isRunning (void)
|
|
{
|
|
return m_state.getState() != TestThreadState::STATE_NOT_RUNNING;
|
|
}
|
|
|
|
int LocalTestProcess::readTestLog (deUint8* dst, int numBytes)
|
|
{
|
|
if (!m_logReader.isRunning())
|
|
{
|
|
if (deGetMicroseconds() - m_processStartTime > xs::LOG_FILE_TIMEOUT*1000)
|
|
{
|
|
// Timeout, kill execution.
|
|
terminate();
|
|
return 0; // \todo [2013-08-13 pyry] Throw exception?
|
|
}
|
|
|
|
if (!deFileExists(m_logFileName.c_str()))
|
|
return 0;
|
|
|
|
// Start reader.
|
|
m_logReader.start(m_logFileName.c_str());
|
|
}
|
|
|
|
DE_ASSERT(m_logReader.isRunning());
|
|
return m_logReader.read(dst, numBytes);
|
|
}
|
|
|
|
class ServerThread : public de::Thread
|
|
{
|
|
public:
|
|
ServerThread (xs::TestProcess* testProcess, int port);
|
|
~ServerThread (void);
|
|
|
|
void run (void);
|
|
void stop (void);
|
|
|
|
private:
|
|
xs::ExecutionServer m_server;
|
|
bool m_isRunning;
|
|
};
|
|
|
|
ServerThread::ServerThread (xs::TestProcess* testProcess, int port)
|
|
: m_server (testProcess, DE_SOCKETFAMILY_INET4, port, xs::ExecutionServer::RUNMODE_FOREVER)
|
|
, m_isRunning (false)
|
|
{
|
|
}
|
|
|
|
ServerThread::~ServerThread (void)
|
|
{
|
|
stop();
|
|
}
|
|
|
|
void ServerThread::run (void)
|
|
{
|
|
m_isRunning = true;
|
|
m_server.runServer();
|
|
}
|
|
|
|
void ServerThread::stop (void)
|
|
{
|
|
if (m_isRunning)
|
|
{
|
|
m_server.stopServer();
|
|
join();
|
|
m_isRunning = false;
|
|
}
|
|
}
|
|
|
|
string getAppBundleDir (void)
|
|
{
|
|
NSString* dataPath = [[NSBundle mainBundle] bundlePath];
|
|
const char* utf8Str = [dataPath UTF8String];
|
|
|
|
return string(utf8Str);
|
|
}
|
|
|
|
string getAppDocumentsDir (void)
|
|
{
|
|
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
|
NSString* docPath = [paths objectAtIndex:0];
|
|
const char* utf8Str = [docPath UTF8String];
|
|
|
|
return string(utf8Str);
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
struct tcuIOSApp_s
|
|
{
|
|
public:
|
|
tcuIOSApp_s (void* view);
|
|
~tcuIOSApp_s (void);
|
|
|
|
void iterate (void);
|
|
|
|
protected:
|
|
void createTestApp (void);
|
|
void destroyTestApp (void);
|
|
|
|
TestThreadState m_state;
|
|
LocalTestProcess m_testProcess;
|
|
ServerThread m_server;
|
|
|
|
tcu::DirArchive m_archive;
|
|
tcu::ios::ScreenManager m_screenManager;
|
|
tcu::ios::Platform m_platform;
|
|
|
|
tcu::TestLog* m_log;
|
|
tcu::CommandLine* m_cmdLine;
|
|
tcu::App* m_app;
|
|
};
|
|
|
|
tcuIOSApp_s::tcuIOSApp_s (void* view)
|
|
: m_testProcess (m_state, de::FilePath::join(getAppDocumentsDir(), "TestResults.qpa").getPath())
|
|
, m_server (&m_testProcess, 50016)
|
|
, m_archive (getAppBundleDir().c_str())
|
|
, m_screenManager ((tcuEAGLView*)view)
|
|
, m_platform (&m_screenManager)
|
|
, m_log (DE_NULL)
|
|
, m_cmdLine (DE_NULL)
|
|
, m_app (DE_NULL)
|
|
{
|
|
// Start server.
|
|
m_server.start();
|
|
}
|
|
|
|
tcuIOSApp_s::~tcuIOSApp_s (void)
|
|
{
|
|
m_server.stop();
|
|
destroyTestApp();
|
|
}
|
|
|
|
void tcuIOSApp::createTestApp (void)
|
|
{
|
|
DE_ASSERT(!m_app && !m_log && !m_cmdLine && !m_platform);
|
|
|
|
try
|
|
{
|
|
m_log = new tcu::TestLog(m_testProcess.getLogFileName());
|
|
m_cmdLine = new tcu::CommandLine(m_state.getCommandLine());
|
|
m_app = new tcu::App(m_platform, m_archive, *m_log, *m_cmdLine);
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
destroyTestApp();
|
|
tcu::die("%s", e.what());
|
|
}
|
|
}
|
|
|
|
void tcuIOSApp::destroyTestApp (void)
|
|
{
|
|
delete m_app;
|
|
delete m_cmdLine;
|
|
delete m_log;
|
|
m_app = DE_NULL;
|
|
m_cmdLine = DE_NULL;
|
|
m_log = DE_NULL;
|
|
}
|
|
|
|
void tcuIOSApp::iterate (void)
|
|
{
|
|
TestThreadState::State curState = m_state.getState();
|
|
|
|
if (curState == TestThreadState::STATE_RUNNING)
|
|
{
|
|
if (!m_app)
|
|
createTestApp();
|
|
|
|
TCU_CHECK(m_app);
|
|
|
|
if (!m_app->iterate())
|
|
{
|
|
destroyTestApp();
|
|
m_state.testExecFinished();
|
|
}
|
|
}
|
|
else if (curState == TestThreadState::STATE_STOP_REQUESTED)
|
|
{
|
|
destroyTestApp();
|
|
m_state.testExecFinished();
|
|
}
|
|
// else wait until state has changed?
|
|
}
|
|
|
|
tcuIOSApp* tcuIOSApp_create (void* view)
|
|
{
|
|
try
|
|
{
|
|
return new tcuIOSApp(view);
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
tcu::die("FATAL ERROR: %s", e.what());
|
|
return DE_NULL;
|
|
}
|
|
}
|
|
|
|
void tcuIOSApp_destroy (tcuIOSApp* app)
|
|
{
|
|
delete app;
|
|
}
|
|
|
|
deBool tcuIOSApp_iterate (tcuIOSApp* app)
|
|
{
|
|
try
|
|
{
|
|
app->iterate();
|
|
return DE_TRUE;
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
tcu::print("FATAL ERROR: %s\n", e.what());
|
|
return DE_FALSE;
|
|
}
|
|
}
|