Fix internal format/type for 3D + depth/stencil negative API tests.
[platform/upstream/VK-GL-CTS.git] / execserver / tools / xsTest.cpp
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 ExecServer Tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "xsDefs.hpp"
25
26 #include "xsProtocol.hpp"
27 #include "deSocket.hpp"
28 #include "deRingBuffer.hpp"
29 #include "deFilePath.hpp"
30 #include "deBlockBuffer.hpp"
31 #include "deThread.hpp"
32 #include "deStringUtil.hpp"
33
34 #include "deClock.h"
35 #include "deProcess.h"
36 #include "deString.h"
37 #include "deRandom.h"
38
39 #include <memory>
40 #include <algorithm>
41
42 using std::string;
43 using std::vector;
44
45 namespace xs
46 {
47
48 typedef std::auto_ptr<Message> ScopedMsgPtr;
49
50 class SocketError : public Error
51 {
52 public:
53         SocketError (deSocketResult result, const char* message, const char* file, int line)
54                 : Error         (message, deGetSocketResultName(result), file, line)
55                 , m_result      (result)
56         {
57         }
58
59         deSocketResult getResult (void) const
60         {
61                 return m_result;
62         }
63
64 private:
65         deSocketResult m_result;
66 };
67
68 // Helpers.
69 void sendMessage (de::Socket& socket, const Message& message)
70 {
71         // Format message.
72         vector<deUint8> buf;
73         message.write(buf);
74
75         // Write to socket.
76         size_t pos = 0;
77         while (pos < buf.size())
78         {
79                 size_t                  numLeft         = buf.size() - pos;
80                 size_t                  numSent         = 0;
81                 deSocketResult  result          = socket.send(&buf[pos], numLeft, &numSent);
82
83                 if (result != DE_SOCKETRESULT_SUCCESS)
84                         throw SocketError(result, "send() failed", __FILE__, __LINE__);
85
86                 pos += numSent;
87         }
88 }
89
90 void readBytes (de::Socket& socket, vector<deUint8>& dst, size_t numBytes)
91 {
92         size_t numRead = 0;
93         dst.resize(numBytes);
94         while (numRead < numBytes)
95         {
96                 size_t                  numLeft         = numBytes - numRead;
97                 size_t                  curNumRead      = 0;
98                 deSocketResult  result          = socket.receive(&dst[numRead], numLeft, &curNumRead);
99
100                 if (result != DE_SOCKETRESULT_SUCCESS)
101                         throw SocketError(result, "receive() failed", __FILE__, __LINE__);
102
103                 numRead += curNumRead;
104         }
105 }
106
107 Message* readMessage (de::Socket& socket)
108 {
109         // Header.
110         vector<deUint8> header;
111         readBytes(socket, header, MESSAGE_HEADER_SIZE);
112
113         MessageType     type;
114         size_t          messageSize;
115         Message::parseHeader(&header[0], (int)header.size(), type, messageSize);
116
117         // Simple messages without any data.
118         switch (type)
119         {
120                 case MESSAGETYPE_KEEPALIVE:                             return new KeepAliveMessage();
121                 case MESSAGETYPE_PROCESS_STARTED:               return new ProcessStartedMessage();
122                 default:
123                         break; // Read message with data.
124         }
125
126         vector<deUint8> messageBuf;
127         readBytes(socket, messageBuf, messageSize-MESSAGE_HEADER_SIZE);
128
129         switch (type)
130         {
131                 case MESSAGETYPE_HELLO:                                 return new HelloMessage(&messageBuf[0], (int)messageBuf.size());
132                 case MESSAGETYPE_TEST:                                  return new TestMessage(&messageBuf[0], (int)messageBuf.size());
133                 case MESSAGETYPE_PROCESS_LOG_DATA:              return new ProcessLogDataMessage(&messageBuf[0], (int)messageBuf.size());
134                 case MESSAGETYPE_INFO:                                  return new InfoMessage(&messageBuf[0], (int)messageBuf.size());
135                 case MESSAGETYPE_PROCESS_LAUNCH_FAILED: return new ProcessLaunchFailedMessage(&messageBuf[0], (int)messageBuf.size());
136                 case MESSAGETYPE_PROCESS_FINISHED:              return new ProcessFinishedMessage(&messageBuf[0], (int)messageBuf.size());
137                 default:
138                         XS_FAIL("Unknown message");
139         }
140 }
141
142 class TestClock
143 {
144 public:
145         inline TestClock (void)
146         {
147                 reset();
148         }
149
150         inline void reset (void)
151         {
152                 m_initTime = deGetMicroseconds();
153         }
154
155         inline int getMilliseconds (void)
156         {
157                 return (int)((deGetMicroseconds() - m_initTime) / 1000);
158         }
159
160 private:
161         deUint64 m_initTime;
162 };
163
164 class TestContext
165 {
166 public:
167                                                 TestContext             (void) : startServer(false) {}
168
169         std::string                     serverPath;
170         std::string                     testerPath;
171         de::SocketAddress       address;
172         bool                            startServer;
173
174         // Passed from execserver.
175         std::string                     logFileName;
176         std::string                     caseList;
177
178 private:
179                                                 TestContext             (const TestContext& other);
180         TestContext&            operator=               (const TestContext& other);
181 };
182
183 class TestCase
184 {
185 public:
186                                         TestCase                (TestContext& testCtx, const char* name) : m_testCtx(testCtx), m_name(name) {}
187         virtual                 ~TestCase               (void) {}
188
189         const char*             getName                 (void) const { return m_name.c_str(); }
190
191         virtual void    runClient               (de::Socket& socket) = DE_NULL;
192         virtual void    runProgram              (void) = DE_NULL;
193
194 protected:
195         TestContext&    m_testCtx;
196         std::string             m_name;
197 };
198
199 class TestExecutor
200 {
201 public:
202                                         TestExecutor    (TestContext& testCtx);
203                                         ~TestExecutor   (void);
204
205         void                    runCases                (const std::vector<TestCase*>& testCases);
206         bool                    runCase                 (TestCase* testCase);
207
208 private:
209         TestContext&    m_testCtx;
210 };
211
212 TestExecutor::TestExecutor (TestContext& testCtx)
213         : m_testCtx(testCtx)
214 {
215 }
216
217 TestExecutor::~TestExecutor (void)
218 {
219 }
220
221 void TestExecutor::runCases (const std::vector<TestCase*>& testCases)
222 {
223         int numPassed   = 0;
224         int numCases    = (int)testCases.size();
225
226         for (std::vector<TestCase*>::const_iterator i = testCases.begin(); i != testCases.end(); i++)
227         {
228                 if (runCase(*i))
229                         numPassed += 1;
230         }
231
232         printf("\n  %d/%d passed!\n", numPassed, numCases);
233 }
234
235 class FilePrinter : public de::Thread
236 {
237 public:
238         FilePrinter (void)
239                 : m_curFile(DE_NULL)
240         {
241         }
242
243         void start (deFile* file)
244         {
245                 DE_ASSERT(!m_curFile);
246                 m_curFile = file;
247                 de::Thread::start();
248         }
249
250         void run (void)
251         {
252                 char    buf[256];
253                 deInt64 numRead = 0;
254
255                 while (deFile_read(m_curFile, &buf[0], (deInt64)sizeof(buf), &numRead) == DE_FILERESULT_SUCCESS)
256                         fwrite(&buf[0], 1, (size_t)numRead, stdout);
257
258                 m_curFile = DE_NULL;
259         }
260
261 private:
262         deFile* m_curFile;
263 };
264
265 bool TestExecutor::runCase (TestCase* testCase)
266 {
267         printf("%s\n", testCase->getName());
268
269         bool            success         = false;
270         deProcess*      serverProc      = DE_NULL;
271         FilePrinter     stdoutPrinter;
272         FilePrinter     stderrPrinter;
273
274         try
275         {
276                 if (m_testCtx.startServer)
277                 {
278                         string cmdLine = m_testCtx.serverPath + " --port=" + de::toString(m_testCtx.address.getPort());
279                         serverProc = deProcess_create();
280                         XS_CHECK(serverProc);
281
282                         if (!deProcess_start(serverProc, cmdLine.c_str(), DE_NULL))
283                         {
284                                 string errMsg = deProcess_getLastError(serverProc);
285                                 deProcess_destroy(serverProc);
286                                 XS_FAIL(errMsg.c_str());
287                         }
288
289                         deSleep(200); /* Give 200ms for server to start. */
290                         XS_CHECK(deProcess_isRunning(serverProc));
291
292                         // Start stdout/stderr printers.
293                         stdoutPrinter.start(deProcess_getStdOut(serverProc));
294                         stderrPrinter.start(deProcess_getStdErr(serverProc));
295                 }
296
297                 // Connect.
298                 de::Socket socket;
299                 socket.connect(m_testCtx.address);
300
301                 // Flags.
302                 socket.setFlags(DE_SOCKET_CLOSE_ON_EXEC);
303
304                 // Run case.
305                 testCase->runClient(socket);
306
307                 // Disconnect.
308                 if (socket.isConnected())
309                         socket.shutdown();
310
311                 // Kill server.
312                 if (serverProc && deProcess_isRunning(serverProc))
313                 {
314                         XS_CHECK(deProcess_terminate(serverProc));
315                         deSleep(100);
316                         XS_CHECK(deProcess_waitForFinish(serverProc));
317
318                         stdoutPrinter.join();
319                         stderrPrinter.join();
320                 }
321
322                 success = true;
323         }
324         catch (const std::exception& e)
325         {
326                 printf("FAIL: %s\n\n", e.what());
327         }
328
329         if (serverProc)
330                 deProcess_destroy(serverProc);
331
332         return success;
333 }
334
335 class ConnectTest : public TestCase
336 {
337 public:
338         ConnectTest (TestContext& testCtx)
339                 : TestCase(testCtx, "connect")
340         {
341         }
342
343         void runClient (de::Socket& socket)
344         {
345                 DE_UNREF(socket);
346         }
347
348         void runProgram (void) { /* nothing */ }
349 };
350
351 class HelloTest : public TestCase
352 {
353 public:
354         HelloTest (TestContext& testCtx)
355                 : TestCase(testCtx, "hello")
356         {
357         }
358
359         void runClient (de::Socket& socket)
360         {
361                 xs::HelloMessage msg;
362                 sendMessage(socket, (const xs::Message&)msg);
363         }
364
365         void runProgram (void) { /* nothing */ }
366 };
367
368 class ExecFailTest : public TestCase
369 {
370 public:
371         ExecFailTest (TestContext& testCtx)
372                 : TestCase(testCtx, "exec-fail")
373         {
374         }
375
376         void runClient (de::Socket& socket)
377         {
378                 xs::ExecuteBinaryMessage execMsg;
379                 execMsg.name            = "foobar-notfound";
380                 execMsg.params          = "";
381                 execMsg.caseList        = "";
382                 execMsg.workDir         = "";
383
384                 sendMessage(socket, execMsg);
385
386                 const int               timeout         = 100; // 100ms.
387                 TestClock               clock;
388
389                 for (;;)
390                 {
391                         if (clock.getMilliseconds() > timeout)
392                                 XS_FAIL("Didn't receive PROCESS_LAUNCH_FAILED");
393
394                         ScopedMsgPtr msg(readMessage(socket));
395
396                         if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
397                                 break;
398                         else if (msg->type == MESSAGETYPE_KEEPALIVE)
399                                 continue;
400                         else
401                                 XS_FAIL("Invalid message");
402                 }
403         }
404
405         void runProgram (void) { /* nothing */ }
406 };
407
408 class SimpleExecTest : public TestCase
409 {
410 public:
411         SimpleExecTest (TestContext& testCtx)
412                 : TestCase(testCtx, "simple-exec")
413         {
414         }
415
416         void runClient (de::Socket& socket)
417         {
418                 xs::ExecuteBinaryMessage execMsg;
419                 execMsg.name            = m_testCtx.testerPath;
420                 execMsg.params          = "--program=simple-exec";
421                 execMsg.caseList        = "";
422                 execMsg.workDir         = "";
423
424                 sendMessage(socket, execMsg);
425
426                 const int               timeout         = 5000; // 5s.
427                 TestClock               clock;
428
429                 bool    gotProcessStarted       = false;
430                 bool    gotProcessFinished      = false;
431
432                 for (;;)
433                 {
434                         if (clock.getMilliseconds() > timeout)
435                                 break;
436
437                         ScopedMsgPtr msg(readMessage(socket));
438
439                         if (msg->type == MESSAGETYPE_PROCESS_STARTED)
440                                 gotProcessStarted = true;
441                         else if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
442                                 XS_FAIL("Got PROCESS_LAUNCH_FAILED");
443                         else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_FINISHED)
444                         {
445                                 gotProcessFinished = true;
446                                 break;
447                         }
448                         else if (msg->type == MESSAGETYPE_KEEPALIVE || msg->type == MESSAGETYPE_INFO)
449                                 continue;
450                         else
451                                 XS_FAIL((string("Invalid message: ") + de::toString(msg->type)).c_str());
452                 }
453
454                 if (!gotProcessStarted)
455                         XS_FAIL("Did't get PROCESS_STARTED message");
456
457                 if (!gotProcessFinished)
458                         XS_FAIL("Did't get PROCESS_FINISHED message");
459         }
460
461         void runProgram (void) { /* print nothing. */ }
462 };
463
464 class InfoTest : public TestCase
465 {
466 public:
467         std::string infoStr;
468
469         InfoTest (TestContext& testCtx)
470                 : TestCase      (testCtx, "info")
471                 , infoStr       ("Hello, World")
472         {
473         }
474
475         void runClient (de::Socket& socket)
476         {
477                 xs::ExecuteBinaryMessage execMsg;
478                 execMsg.name            = m_testCtx.testerPath;
479                 execMsg.params          = "--program=info";
480                 execMsg.caseList        = "";
481                 execMsg.workDir         = "";
482
483                 sendMessage(socket, execMsg);
484
485                 const int               timeout         = 10000; // 10s.
486                 TestClock               clock;
487
488                 bool                    gotProcessStarted       = false;
489                 bool                    gotProcessFinished      = false;
490                 std::string             receivedInfo            = "";
491
492                 for (;;)
493                 {
494                         if (clock.getMilliseconds() > timeout)
495                                 break;
496
497                         ScopedMsgPtr msg(readMessage(socket));
498
499                         if (msg->type == MESSAGETYPE_PROCESS_STARTED)
500                                 gotProcessStarted = true;
501                         else if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
502                                 XS_FAIL("Got PROCESS_LAUNCH_FAILED");
503                         else if (gotProcessStarted && msg->type == MESSAGETYPE_INFO)
504                                 receivedInfo += static_cast<const InfoMessage*>(msg.get())->info;
505                         else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_FINISHED)
506                         {
507                                 gotProcessFinished = true;
508                                 break;
509                         }
510                         else if (msg->type == MESSAGETYPE_KEEPALIVE)
511                                 continue;
512                         else
513                                 XS_FAIL("Invalid message");
514                 }
515
516                 if (!gotProcessStarted)
517                         XS_FAIL("Did't get PROCESS_STARTED message");
518
519                 if (!gotProcessFinished)
520                         XS_FAIL("Did't get PROCESS_FINISHED message");
521
522                 if (receivedInfo != infoStr)
523                         XS_FAIL("Info data doesn't match");
524         }
525
526         void runProgram (void) { printf("%s", infoStr.c_str()); }
527 };
528
529 class LogDataTest : public TestCase
530 {
531 public:
532         LogDataTest (TestContext& testCtx)
533                 : TestCase(testCtx, "logdata")
534         {
535         }
536
537         void runClient (de::Socket& socket)
538         {
539                 xs::ExecuteBinaryMessage execMsg;
540                 execMsg.name            = m_testCtx.testerPath;
541                 execMsg.params          = "--program=logdata";
542                 execMsg.caseList        = "";
543                 execMsg.workDir         = "";
544
545                 sendMessage(socket, execMsg);
546
547                 const int               timeout         = 10000; // 10s.
548                 TestClock               clock;
549
550                 bool                    gotProcessStarted       = false;
551                 bool                    gotProcessFinished      = false;
552                 std::string             receivedData            = "";
553
554                 for (;;)
555                 {
556                         if (clock.getMilliseconds() > timeout)
557                                 break;
558
559                         ScopedMsgPtr msg(readMessage(socket));
560
561                         if (msg->type == MESSAGETYPE_PROCESS_STARTED)
562                                 gotProcessStarted = true;
563                         else if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
564                                 XS_FAIL("Got PROCESS_LAUNCH_FAILED");
565                         else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_LOG_DATA)
566                                 receivedData += static_cast<const ProcessLogDataMessage*>(msg.get())->logData;
567                         else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_FINISHED)
568                         {
569                                 gotProcessFinished = true;
570                                 break;
571                         }
572                         else if (msg->type == MESSAGETYPE_KEEPALIVE)
573                                 continue;
574                         else if (msg->type == MESSAGETYPE_INFO)
575                                 XS_FAIL(static_cast<const InfoMessage*>(msg.get())->info.c_str());
576                         else
577                                 XS_FAIL("Invalid message");
578                 }
579
580                 if (!gotProcessStarted)
581                         XS_FAIL("Did't get PROCESS_STARTED message");
582
583                 if (!gotProcessFinished)
584                         XS_FAIL("Did't get PROCESS_FINISHED message");
585
586                 const char* expected = "Foo\nBar\n";
587                 if (receivedData != expected)
588                 {
589                         printf("  received: '%s'\n  expected: '%s'\n", receivedData.c_str(), expected);
590                         XS_FAIL("Log data doesn't match");
591                 }
592         }
593
594         void runProgram (void)
595         {
596                 deFile* file = deFile_create(m_testCtx.logFileName.c_str(), DE_FILEMODE_OPEN|DE_FILEMODE_CREATE|DE_FILEMODE_TRUNCATE|DE_FILEMODE_WRITE);
597                 XS_CHECK(file);
598
599                 const char line0[] = "Foo\n";
600                 const char line1[] = "Bar\n";
601                 deInt64 numWritten = 0;
602
603                 // Write first line.
604                 XS_CHECK(deFile_write(file, line0, sizeof(line0)-1, &numWritten) == DE_FILERESULT_SUCCESS);
605                 XS_CHECK(numWritten == sizeof(line0)-1);
606
607                 // Sleep for 0.5s and write line 2.
608                 deSleep(500);
609                 XS_CHECK(deFile_write(file, line1, sizeof(line1)-1, &numWritten) == DE_FILERESULT_SUCCESS);
610                 XS_CHECK(numWritten == sizeof(line1)-1);
611
612                 deFile_destroy(file);
613         }
614 };
615
616 class BigLogDataTest : public TestCase
617 {
618 public:
619         enum
620         {
621                 DATA_SIZE = 100*1024*1024
622         };
623
624         BigLogDataTest (TestContext& testCtx)
625                 : TestCase(testCtx, "biglogdata")
626         {
627         }
628
629         void runClient (de::Socket& socket)
630         {
631                 xs::ExecuteBinaryMessage execMsg;
632                 execMsg.name            = m_testCtx.testerPath;
633                 execMsg.params          = "--program=biglogdata";
634                 execMsg.caseList        = "";
635                 execMsg.workDir         = "";
636
637                 sendMessage(socket, execMsg);
638
639                 const int               timeout         = 30000; // 30s.
640                 TestClock               clock;
641
642                 bool                    gotProcessStarted       = false;
643                 bool                    gotProcessFinished      = false;
644                 int                             receivedBytes           = 0;
645
646                 for (;;)
647                 {
648                         if (clock.getMilliseconds() > timeout)
649                                 break;
650
651                         ScopedMsgPtr msg(readMessage(socket));
652
653                         if (msg->type == MESSAGETYPE_PROCESS_STARTED)
654                                 gotProcessStarted = true;
655                         else if (msg->type == MESSAGETYPE_PROCESS_LAUNCH_FAILED)
656                                 XS_FAIL("Got PROCESS_LAUNCH_FAILED");
657                         else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_LOG_DATA)
658                                 receivedBytes += (int)static_cast<const ProcessLogDataMessage*>(msg.get())->logData.length();
659                         else if (gotProcessStarted && msg->type == MESSAGETYPE_PROCESS_FINISHED)
660                         {
661                                 gotProcessFinished = true;
662                                 break;
663                         }
664                         else if (msg->type == MESSAGETYPE_KEEPALIVE)
665                         {
666                                 // Reply with keepalive.
667                                 sendMessage(socket, KeepAliveMessage());
668                                 continue;
669                         }
670                         else if (msg->type == MESSAGETYPE_INFO)
671                                 printf("%s", static_cast<const InfoMessage*>(msg.get())->info.c_str());
672                         else
673                                 XS_FAIL("Invalid message");
674                 }
675
676                 if (!gotProcessStarted)
677                         XS_FAIL("Did't get PROCESS_STARTED message");
678
679                 if (!gotProcessFinished)
680                         XS_FAIL("Did't get PROCESS_FINISHED message");
681
682                 if (receivedBytes != DATA_SIZE)
683                 {
684                         printf("  received: %d bytes\n  expected: %d bytes\n", receivedBytes, DATA_SIZE);
685                         XS_FAIL("Log data size doesn't match");
686                 }
687
688                 int timeMs = clock.getMilliseconds();
689                 printf("  Streamed %d bytes in %d ms: %.2f MiB/s\n", DATA_SIZE, timeMs, ((float)DATA_SIZE / (float)(1024*1024)) / ((float)timeMs / 1000.0f));
690         }
691
692         void runProgram (void)
693         {
694                 deFile* file = deFile_create(m_testCtx.logFileName.c_str(), DE_FILEMODE_OPEN|DE_FILEMODE_CREATE|DE_FILEMODE_TRUNCATE|DE_FILEMODE_WRITE);
695                 XS_CHECK(file);
696
697                 deUint8 tmpBuf[1024*16];
698                 int numWritten = 0;
699
700                 deMemset(&tmpBuf, 'a', sizeof(tmpBuf));
701
702                 while (numWritten < DATA_SIZE)
703                 {
704                         deInt64 numWrittenInBatch = 0;
705                         XS_CHECK(deFile_write(file, &tmpBuf[0], de::min((int)sizeof(tmpBuf), DATA_SIZE-numWritten), &numWrittenInBatch) == DE_FILERESULT_SUCCESS);
706                         numWritten += (int)numWrittenInBatch;
707                 }
708
709                 deFile_destroy(file);
710         }
711 };
712
713 class KeepAliveTest : public TestCase
714 {
715 public:
716         KeepAliveTest (TestContext& testCtx)
717                 : TestCase(testCtx, "keepalive")
718         {
719         }
720
721         void runClient (de::Socket& socket)
722         {
723                 // In milliseconds.
724                 const int       sendInterval                    = 5000;
725                 const int       minReceiveInterval              = 10000;
726                 const int       testTime                                = 30000;
727                 const int       sleepTime                               = 200;
728                 const int       expectedTimeout                 = 40000;
729                 int                     curTime                                 = 0;
730                 int                     lastSendTime                    = 0;
731                 int                     lastReceiveTime                 = 0;
732                 TestClock       clock;
733
734                 DE_ASSERT(sendInterval < minReceiveInterval);
735
736                 curTime = clock.getMilliseconds();
737
738                 while (curTime < testTime)
739                 {
740                         bool tryGetKeepalive = false;
741
742                         if (curTime-lastSendTime > sendInterval)
743                         {
744                                 printf("  %d ms: sending keepalive\n", curTime);
745                                 sendMessage(socket, KeepAliveMessage());
746                                 curTime = clock.getMilliseconds();
747                                 lastSendTime = curTime;
748                                 tryGetKeepalive = true;
749                         }
750
751                         if (tryGetKeepalive)
752                         {
753                                 // Try to acquire keepalive.
754                                 printf("  %d ms: waiting for keepalive\n", curTime);
755                                 ScopedMsgPtr msg(readMessage(socket));
756                                 int recvTime = clock.getMilliseconds();
757
758                                 if (msg->type != MESSAGETYPE_KEEPALIVE)
759                                         XS_FAIL("Got invalid message");
760
761                                 printf("  %d ms: got keepalive\n", curTime);
762
763                                 if (recvTime-lastReceiveTime > minReceiveInterval)
764                                         XS_FAIL("Server doesn't send keepalives");
765
766                                 lastReceiveTime = recvTime;
767                         }
768
769                         deSleep(sleepTime);
770                         curTime = clock.getMilliseconds();
771                 }
772
773                 // Verify that server actually kills the connection upon timeout.
774                 sendMessage(socket, KeepAliveMessage());
775                 printf("  waiting %d ms for keepalive timeout...\n", expectedTimeout);
776                 bool isClosed = false;
777
778                 try
779                 {
780                         // Reset timer.
781                         clock.reset();
782                         curTime = clock.getMilliseconds();
783
784                         while (curTime < expectedTimeout)
785                         {
786                                 // Try to get keepalive message.
787                                 ScopedMsgPtr msg(readMessage(socket));
788                                 if (msg->type != MESSAGETYPE_KEEPALIVE)
789                                         XS_FAIL("Got invalid message");
790
791                                 curTime = clock.getMilliseconds();
792                                 printf("  %d ms: got keepalive\n", curTime);
793                         }
794                 }
795                 catch (const SocketError& e)
796                 {
797                         if (e.getResult() == DE_SOCKETRESULT_CONNECTION_CLOSED)
798                         {
799                                 printf("  %d ms: server closed connection", clock.getMilliseconds());
800                                 isClosed = true;
801                         }
802                         else
803                                 throw;
804                 }
805
806                 if (isClosed)
807                         printf("  ok!\n");
808                 else
809                         XS_FAIL("Server didn't close connection");
810         }
811
812         void runProgram (void) { /* nothing */ }
813 };
814
815 void printHelp (const char* binName)
816 {
817         printf("%s:\n", binName);
818         printf("  --client=[name]       Run test [name]\n");
819         printf("  --program=[name]      Run program for test [name]\n");
820         printf("  --host=[host]         Connect to host [host]\n");
821         printf("  --port=[name]         Use port [port]\n");
822         printf("  --tester-cmd=[cmd]    Launch tester with [cmd]\n");
823         printf("  --server-cmd=[cmd]    Launch server with [cmd]\n");
824         printf("  --start-server        Start server for test execution\n");
825 }
826
827 struct CompareCaseName
828 {
829         std::string name;
830
831         CompareCaseName (const string& name_) : name(name_) {}
832
833         bool operator() (const TestCase* testCase) const
834         {
835                 return name == testCase->getName();
836         }
837 };
838
839 void runExecServerTests (int argc, const char* const* argv)
840 {
841         // Construct test context.
842         TestContext testCtx;
843
844         testCtx.serverPath      = "execserver";
845         testCtx.testerPath      = argv[0];
846         testCtx.startServer     = false;
847         testCtx.address.setHost("127.0.0.1");
848         testCtx.address.setPort(50016);
849
850         std::string runClient = "";
851         std::string runProgram = "";
852
853         // Parse command line.
854         for (int argNdx = 1; argNdx < argc; argNdx++)
855         {
856                 const char* arg = argv[argNdx];
857
858                 if (deStringBeginsWith(arg, "--client="))
859                         runClient = arg+9;
860                 else if (deStringBeginsWith(arg, "--program="))
861                         runProgram = arg+10;
862                 else if (deStringBeginsWith(arg, "--port="))
863                         testCtx.address.setPort(atoi(arg+7));
864                 else if (deStringBeginsWith(arg, "--host="))
865                         testCtx.address.setHost(arg+7);
866                 else if (deStringBeginsWith(arg, "--server-cmd="))
867                         testCtx.serverPath = arg+13;
868                 else if (deStringBeginsWith(arg, "--tester-cmd="))
869                         testCtx.testerPath = arg+13;
870                 else if (deStringBeginsWith(arg, "--deqp-log-filename="))
871                         testCtx.logFileName = arg+20;
872                 else if (deStringBeginsWith(arg, "--deqp-caselist="))
873                         testCtx.caseList = arg+16;
874                 else if (deStringEqual(arg, "--deqp-stdin-caselist"))
875                 {
876                         // \todo [pyry] This is rather brute-force solution...
877                         char c;
878                         while (fread(&c, 1, 1, stdin) == 1 && c != 0)
879                                 testCtx.caseList += c;
880                 }
881                 else if (deStringEqual(arg, "--start-server"))
882                         testCtx.startServer = true;
883                 else
884                 {
885                         printHelp(argv[0]);
886                         return;
887                 }
888         }
889
890         // Test case list.
891         std::vector<TestCase*> testCases;
892         testCases.push_back(new ConnectTest(testCtx));
893         testCases.push_back(new HelloTest(testCtx));
894         testCases.push_back(new ExecFailTest(testCtx));
895         testCases.push_back(new SimpleExecTest(testCtx));
896         testCases.push_back(new InfoTest(testCtx));
897         testCases.push_back(new LogDataTest(testCtx));
898         testCases.push_back(new KeepAliveTest(testCtx));
899         testCases.push_back(new BigLogDataTest(testCtx));
900
901         try
902         {
903                 if (!runClient.empty())
904                 {
905                         // Run single case.
906                         vector<TestCase*>::iterator casePos = std::find_if(testCases.begin(), testCases.end(), CompareCaseName(runClient));
907                         XS_CHECK(casePos != testCases.end());
908                         TestExecutor executor(testCtx);
909                         executor.runCase(*casePos);
910                 }
911                 else if (!runProgram.empty())
912                 {
913                         // Run program part.
914                         vector<TestCase*>::iterator casePos = std::find_if(testCases.begin(), testCases.end(), CompareCaseName(runProgram));
915                         XS_CHECK(casePos != testCases.end());
916                         (*casePos)->runProgram();
917                         fflush(stdout); // Make sure handles are flushed.
918                         fflush(stderr);
919                 }
920                 else
921                 {
922                         // Run all tests.
923                         TestExecutor executor(testCtx);
924                         executor.runCases(testCases);
925                 }
926         }
927         catch (const std::exception& e)
928         {
929                 printf("ERROR: %s\n", e.what());
930         }
931
932         // Destroy cases.
933         for (std::vector<TestCase*>::const_iterator i = testCases.begin(); i != testCases.end(); i++)
934                 delete *i;
935 }
936
937 } // xs
938
939 #if 0
940 void testProcFile (void)
941 {
942         /* Test file api. */
943         if (deFileExists("test.txt"))
944                 deDeleteFile("test.txt");
945         deFile* file = deFile_create("test.txt", DE_FILEMODE_CREATE|DE_FILEMODE_WRITE);
946         const char test[] = "Hello";
947         XS_CHECK(deFile_write(file, test, sizeof(test), DE_NULL) == DE_FILERESULT_SUCCESS);
948         deFile_destroy(file);
949
950         /* Read. */
951         char buf[10] = { 0 };
952         file = deFile_create("test.txt", DE_FILEMODE_OPEN|DE_FILEMODE_READ);
953         XS_CHECK(deFile_read(file, buf, sizeof(test), DE_NULL) == DE_FILERESULT_SUCCESS);
954         printf("buf: %s\n", buf);
955         deFile_destroy(file);
956
957         /* Process test. */
958         deProcess* proc = deProcess_create("ls -lah /Users/pyry", DE_NULL);
959         deFile* out = deProcess_getStdOut(proc);
960
961         deInt64 numRead = 0;
962         printf("ls:\n");
963         while (deFile_read(out, buf, sizeof(buf)-1, &numRead) == DE_FILERESULT_SUCCESS)
964         {
965                 buf[numRead] = 0;
966                 printf("%s", buf);
967         }
968         deProcess_destroy(proc);
969 }
970 #endif
971
972 #if 0
973 void testBlockingFile (const char* filename)
974 {
975         deRandom        rnd;
976         int                     dataSize        = 1024*1024;
977         deUint8*        data            = (deUint8*)deCalloc(dataSize);
978         deFile*         file;
979
980         deRandom_init(&rnd, 0);
981
982         if (deFileExists(filename))
983                 DE_VERIFY(deDeleteFile(filename));
984
985         /* Fill in with random data. */
986         DE_ASSERT(dataSize % sizeof(int) == 0);
987         for (int ndx = 0; ndx < (int)(dataSize/sizeof(int)); ndx++)
988                 ((deUint32*)data)[ndx] = deRandom_getUint32(&rnd);
989
990         /* Write with random-sized blocks. */
991         file = deFile_create(filename, DE_FILEMODE_CREATE|DE_FILEMODE_WRITE);
992         DE_VERIFY(file);
993
994         int curPos = 0;
995         while (curPos < dataSize)
996         {
997                 int                             blockSize       = 1 + deRandom_getUint32(&rnd) % (dataSize-curPos);
998                 deInt64                 numWritten      = 0;
999                 deFileResult    result          = deFile_write(file, &data[curPos], blockSize, &numWritten);
1000
1001                 DE_VERIFY(result == DE_FILERESULT_SUCCESS);
1002                 DE_VERIFY(numWritten == blockSize);
1003
1004                 curPos += blockSize;
1005         }
1006
1007         deFile_destroy(file);
1008
1009         /* Read and verify file. */
1010         file    = deFile_create(filename, DE_FILEMODE_OPEN|DE_FILEMODE_READ);
1011         curPos  = 0;
1012         while (curPos < dataSize)
1013         {
1014                 deUint8                 block[1024];
1015                 int                             numToRead       = 1 + deRandom_getUint32(&rnd) % deMin(dataSize-curPos, DE_LENGTH_OF_ARRAY(block));
1016                 deInt64                 numRead         = 0;
1017                 deFileResult    result          = deFile_read(file, block, numToRead, &numRead);
1018
1019                 DE_VERIFY(result == DE_FILERESULT_SUCCESS);
1020                 DE_VERIFY((int)numRead == numToRead);
1021                 DE_VERIFY(deMemCmp(block, &data[curPos], numToRead) == 0);
1022
1023                 curPos += numToRead;
1024         }
1025         deFile_destroy(file);
1026 }
1027 #endif
1028
1029 int main (int argc, const char* const* argv)
1030 {
1031         xs::runExecServerTests(argc, argv);
1032         return 0;
1033 }