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