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