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: 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 60 deSocketResult getResult (void) const 61 { 62 return m_result; 63 } 64 65 private: 66 deSocketResult m_result; 67 }; 68 69 // Helpers. 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 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 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: 146 inline TestClock (void) 147 { 148 reset(); 149 } 150 151 inline void reset (void) 152 { 153 m_initTime = deGetMicroseconds(); 154 } 155 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: 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: 187 TestCase (TestContext& testCtx, const char* name) : m_testCtx(testCtx), m_name(name) {} 188 virtual ~TestCase (void) {} 189 190 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 213 TestExecutor::TestExecutor (TestContext& testCtx) 214 : m_testCtx(testCtx) 215 { 216 } 217 218 TestExecutor::~TestExecutor (void) 219 { 220 } 221 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: 239 FilePrinter (void) 240 : m_curFile(DE_NULL) 241 { 242 } 243 244 void start (deFile* file) 245 { 246 DE_ASSERT(!m_curFile); 247 m_curFile = file; 248 de::Thread::start(); 249 } 250 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 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: 339 ConnectTest (TestContext& testCtx) 340 : TestCase(testCtx, "connect") 341 { 342 } 343 344 void runClient (de::Socket& socket) 345 { 346 DE_UNREF(socket); 347 } 348 349 void runProgram (void) { /* nothing */ } 350 }; 351 352 class HelloTest : public TestCase 353 { 354 public: 355 HelloTest (TestContext& testCtx) 356 : TestCase(testCtx, "hello") 357 { 358 } 359 360 void runClient (de::Socket& socket) 361 { 362 xs::HelloMessage msg; 363 sendMessage(socket, (const xs::Message&)msg); 364 } 365 366 void runProgram (void) { /* nothing */ } 367 }; 368 369 class ExecFailTest : public TestCase 370 { 371 public: 372 ExecFailTest (TestContext& testCtx) 373 : TestCase(testCtx, "exec-fail") 374 { 375 } 376 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 406 void runProgram (void) { /* nothing */ } 407 }; 408 409 class SimpleExecTest : public TestCase 410 { 411 public: 412 SimpleExecTest (TestContext& testCtx) 413 : TestCase(testCtx, "simple-exec") 414 { 415 } 416 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 462 void runProgram (void) { /* print nothing. */ } 463 }; 464 465 class InfoTest : public TestCase 466 { 467 public: 468 std::string infoStr; 469 470 InfoTest (TestContext& testCtx) 471 : TestCase (testCtx, "info") 472 , infoStr ("Hello, World") 473 { 474 } 475 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 527 void runProgram (void) { printf("%s", infoStr.c_str()); } 528 }; 529 530 class LogDataTest : public TestCase 531 { 532 public: 533 LogDataTest (TestContext& testCtx) 534 : TestCase(testCtx, "logdata") 535 { 536 } 537 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 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 625 BigLogDataTest (TestContext& testCtx) 626 : TestCase(testCtx, "biglogdata") 627 { 628 } 629 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 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: 717 KeepAliveTest (TestContext& testCtx) 718 : TestCase(testCtx, "keepalive") 719 { 720 } 721 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 813 void runProgram (void) { /* nothing */ } 814 }; 815 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 832 CompareCaseName (const string& name_) : name(name_) {} 833 834 bool operator() (const TestCase* testCase) const 835 { 836 return name == testCase->getName(); 837 } 838 }; 839 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 1030 int main (int argc, const char* const* argv) 1031 { 1032 xs::runExecServerTests(argc, argv); 1033 return 0; 1034 } 1035