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