Don't require supported binary formats in negative tests. am: 7cd59a4409 am: d7b53b80...
[platform/upstream/VK-GL-CTS.git] / framework / platform / ios / tcuIOSApp.mm
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
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 iOS App Wrapper.
22  *//*--------------------------------------------------------------------*/
23
24 #include "tcuIOSApp.h"
25 #include "tcuIOSPlatform.hh"
26 #include "tcuApp.hpp"
27 #include "tcuCommandLine.hpp"
28 #include "tcuRenderTarget.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuResource.hpp"
31 #include "deThread.hpp"
32 #include "deMutex.hpp"
33 #include "xsExecutionServer.hpp"
34 #include "xsTestProcess.hpp"
35 #include "xsPosixFileReader.hpp"
36 #include "deFilePath.hpp"
37 #include "deClock.h"
38 #include "deMemory.h"
39
40 #include <string>
41
42 #import <Foundation/NSObject.h>
43 #import <Foundation/NSString.h>
44 #import <Foundation/NSBundle.h>
45 #import <Foundation/NSPathUtilities.h>
46
47 using std::string;
48
49 namespace
50 {
51
52 class TestThreadState
53 {
54 public:
55         enum State
56         {
57                 STATE_NOT_RUNNING       = 0,
58                 STATE_RUNNING,
59                 STATE_STOP_REQUESTED,
60
61                 STATE_LAST
62         };
63
64                                                         TestThreadState                 (void);
65                                                         ~TestThreadState                (void);
66
67         void                                    requestStart                    (const char* cmdLine);
68         void                                    requestStop                             (void);
69         State                                   getState                                (void);
70
71         void                                    testExecFinished                (void);
72
73         const char*                             getCommandLine                  (void) const { return m_cmdLine.c_str(); }
74
75 private:
76         de::Mutex                               m_lock;
77
78         State                                   m_state;
79         std::string                             m_cmdLine;
80 };
81
82 TestThreadState::TestThreadState (void)
83         : m_state(STATE_NOT_RUNNING)
84 {
85 }
86
87 TestThreadState::~TestThreadState (void)
88 {
89 }
90
91 void TestThreadState::requestStart (const char* cmdLine)
92 {
93         de::ScopedLock stateLock(m_lock);
94
95         TCU_CHECK(m_state == STATE_NOT_RUNNING);
96
97         m_cmdLine       = cmdLine;
98         m_state         = STATE_RUNNING;
99 }
100
101 void TestThreadState::requestStop (void)
102 {
103         de::ScopedLock stateLock(m_lock);
104
105         if (m_state != STATE_NOT_RUNNING)
106                 m_state = STATE_STOP_REQUESTED;
107 }
108
109 void TestThreadState::testExecFinished (void)
110 {
111         de::ScopedLock stateLock(m_lock);
112         m_state = STATE_NOT_RUNNING;
113 }
114
115 TestThreadState::State TestThreadState::getState (void)
116 {
117         de::ScopedLock stateLock(m_lock);
118         return m_state;
119 }
120
121 class LocalTestProcess : public xs::TestProcess
122 {
123 public:
124                                                         LocalTestProcess                (TestThreadState& state, const char* logFileName);
125                                                         ~LocalTestProcess               (void);
126
127         void                                    start                                   (const char* name, const char* params, const char* workingDir, const char* caseList);
128         void                                    terminate                               (void);
129         void                                    cleanup                                 (void);
130
131         bool                                    isRunning                               (void);
132         int                                             getExitCode                             (void) const { return 0; /* not available */ }
133
134         int                                             readInfoLog                             (deUint8* dst, int numBytes) { DE_UNREF(dst && numBytes); return 0; /* not supported */ }
135         int                                             readTestLog                             (deUint8* dst, int numBytes);
136
137         const char*                             getLogFileName                  (void) const { return m_logFileName.c_str(); }
138
139 private:
140         TestThreadState&                m_state;
141         string                                  m_logFileName;
142         xs::posix::FileReader   m_logReader;
143         deUint64                                m_processStartTime;
144 };
145
146 LocalTestProcess::LocalTestProcess (TestThreadState& state, const char* logFileName)
147         : m_state                               (state)
148         , m_logFileName                 (logFileName)
149         , m_logReader                   (xs::LOG_BUFFER_BLOCK_SIZE, xs::LOG_BUFFER_NUM_BLOCKS)
150         , m_processStartTime    (0)
151 {
152 }
153
154 LocalTestProcess::~LocalTestProcess (void)
155 {
156 }
157
158 void LocalTestProcess::start (const char* name, const char* params, const char* workingDir, const char* caseList)
159 {
160         DE_UNREF(name && workingDir);
161
162         // Delete old log file.
163         if (deFileExists(m_logFileName.c_str()))
164                 TCU_CHECK(deDeleteFile(m_logFileName.c_str()));
165
166         string cmdLine = string("deqp");
167         if (caseList && strlen(caseList) > 0)
168                 cmdLine += string(" --deqp-caselist=") + caseList;
169
170         if (params && strlen(params) > 0)
171                 cmdLine += string(" ") + params;
172
173         m_state.requestStart(cmdLine.c_str());
174         m_processStartTime = deGetMicroseconds();
175 }
176
177 void LocalTestProcess::terminate (void)
178 {
179         m_state.requestStop();
180 }
181
182 void LocalTestProcess::cleanup (void)
183 {
184         if (isRunning())
185         {
186                 m_state.requestStop();
187
188                 // Wait until stopped.
189                 while (isRunning())
190                         deSleep(50);
191         }
192
193         m_logReader.stop();
194 }
195
196 bool LocalTestProcess::isRunning (void)
197 {
198         return m_state.getState() != TestThreadState::STATE_NOT_RUNNING;
199 }
200
201 int LocalTestProcess::readTestLog (deUint8* dst, int numBytes)
202 {
203         if (!m_logReader.isRunning())
204         {
205                 if (deGetMicroseconds() - m_processStartTime > xs::LOG_FILE_TIMEOUT*1000)
206                 {
207                         // Timeout, kill execution.
208                         terminate();
209                         return 0; // \todo [2013-08-13 pyry] Throw exception?
210                 }
211
212                 if (!deFileExists(m_logFileName.c_str()))
213                         return 0;
214
215                 // Start reader.
216                 m_logReader.start(m_logFileName.c_str());
217         }
218
219         DE_ASSERT(m_logReader.isRunning());
220         return m_logReader.read(dst, numBytes);
221 }
222
223 class ServerThread : public de::Thread
224 {
225 public:
226                                                 ServerThread            (xs::TestProcess* testProcess, int port);
227                                                 ~ServerThread           (void);
228
229         void                            run                                     (void);
230         void                            stop                            (void);
231
232 private:
233         xs::ExecutionServer     m_server;
234         bool                            m_isRunning;
235 };
236
237 ServerThread::ServerThread (xs::TestProcess* testProcess, int port)
238         : m_server              (testProcess, DE_SOCKETFAMILY_INET4, port, xs::ExecutionServer::RUNMODE_FOREVER)
239         , m_isRunning   (false)
240 {
241 }
242
243 ServerThread::~ServerThread (void)
244 {
245         stop();
246 }
247
248 void ServerThread::run (void)
249 {
250         m_isRunning = true;
251         m_server.runServer();
252 }
253
254 void ServerThread::stop (void)
255 {
256         if (m_isRunning)
257         {
258                 m_server.stopServer();
259                 join();
260                 m_isRunning = false;
261         }
262 }
263
264 string getAppBundleDir (void)
265 {
266         NSString*       dataPath        = [[NSBundle mainBundle] bundlePath];
267         const char*     utf8Str         = [dataPath UTF8String];
268
269         return string(utf8Str);
270 }
271
272 string getAppDocumentsDir (void)
273 {
274         NSArray*        paths           = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
275         NSString*       docPath         = [paths objectAtIndex:0];
276         const char*     utf8Str         = [docPath UTF8String];
277
278         return string(utf8Str);
279 }
280
281 } // anonymous
282
283 struct tcuIOSApp_s
284 {
285 public:
286                                                         tcuIOSApp_s             (void* view);
287                                                         ~tcuIOSApp_s    (void);
288
289         void                                    iterate                 (void);
290
291 protected:
292         void                                    createTestApp   (void);
293         void                                    destroyTestApp  (void);
294
295         TestThreadState                 m_state;
296         LocalTestProcess                m_testProcess;
297         ServerThread                    m_server;
298
299         tcu::DirArchive                 m_archive;
300         tcu::ios::ScreenManager m_screenManager;
301         tcu::ios::Platform              m_platform;
302
303         tcu::TestLog*                   m_log;
304         tcu::CommandLine*               m_cmdLine;
305         tcu::App*                               m_app;
306 };
307
308 tcuIOSApp_s::tcuIOSApp_s (void* view)
309         : m_testProcess         (m_state, de::FilePath::join(getAppDocumentsDir(), "TestResults.qpa").getPath())
310         , m_server                      (&m_testProcess, 50016)
311         , m_archive                     (getAppBundleDir().c_str())
312         , m_screenManager       ((tcuEAGLView*)view)
313         , m_platform            (&m_screenManager)
314         , m_log                         (DE_NULL)
315         , m_cmdLine                     (DE_NULL)
316         , m_app                         (DE_NULL)
317 {
318         // Start server.
319         m_server.start();
320 }
321
322 tcuIOSApp_s::~tcuIOSApp_s (void)
323 {
324         m_server.stop();
325         destroyTestApp();
326 }
327
328 void tcuIOSApp::createTestApp (void)
329 {
330         DE_ASSERT(!m_app && !m_log && !m_cmdLine && !m_platform);
331
332         try
333         {
334                 m_log           = new tcu::TestLog(m_testProcess.getLogFileName());
335                 m_cmdLine       = new tcu::CommandLine(m_state.getCommandLine());
336                 m_app           = new tcu::App(m_platform, m_archive, *m_log, *m_cmdLine);
337         }
338         catch (const std::exception& e)
339         {
340                 destroyTestApp();
341                 tcu::die("%s", e.what());
342         }
343 }
344
345 void tcuIOSApp::destroyTestApp (void)
346 {
347         delete m_app;
348         delete m_cmdLine;
349         delete m_log;
350         m_app           = DE_NULL;
351         m_cmdLine       = DE_NULL;
352         m_log           = DE_NULL;
353 }
354
355 void tcuIOSApp::iterate (void)
356 {
357         TestThreadState::State curState = m_state.getState();
358
359         if (curState == TestThreadState::STATE_RUNNING)
360         {
361                 if (!m_app)
362                         createTestApp();
363
364                 TCU_CHECK(m_app);
365
366                 if (!m_app->iterate())
367                 {
368                         destroyTestApp();
369                         m_state.testExecFinished();
370                 }
371         }
372         else if (curState == TestThreadState::STATE_STOP_REQUESTED)
373         {
374                 destroyTestApp();
375                 m_state.testExecFinished();
376         }
377         // else wait until state has changed?
378 }
379
380 tcuIOSApp* tcuIOSApp_create (void* view)
381 {
382         try
383         {
384                 return new tcuIOSApp(view);
385         }
386         catch (const std::exception& e)
387         {
388                 tcu::die("FATAL ERROR: %s", e.what());
389                 return DE_NULL;
390         }
391 }
392
393 void tcuIOSApp_destroy (tcuIOSApp* app)
394 {
395         delete app;
396 }
397
398 deBool tcuIOSApp_iterate (tcuIOSApp* app)
399 {
400         try
401         {
402                 app->iterate();
403                 return DE_TRUE;
404         }
405         catch (const std::exception& e)
406         {
407                 tcu::print("FATAL ERROR: %s\n", e.what());
408                 return DE_FALSE;
409         }
410 }