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