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 42using std::string; 43using std::vector; 44 45namespace xs 46{ 47 48typedef std::auto_ptr<Message> ScopedMsgPtr; 49 50class SocketError : public Error 51{ 52public: 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 59 deSocketResult getResult (void) const 60 { 61 return m_result; 62 } 63 64private: 65 deSocketResult m_result; 66}; 67 68// Helpers. 69void 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 90void 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 107Message* 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 142class TestClock 143{ 144public: 145 inline TestClock (void) 146 { 147 reset(); 148 } 149 150 inline void reset (void) 151 { 152 m_initTime = deGetMicroseconds(); 153 } 154 155 inline int getMilliseconds (void) 156 { 157 return (int)((deGetMicroseconds() - m_initTime) / 1000); 158 } 159 160private: 161 deUint64 m_initTime; 162}; 163 164class TestContext 165{ 166public: 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 178private: 179 TestContext (const TestContext& other); 180 TestContext& operator= (const TestContext& other); 181}; 182 183class TestCase 184{ 185public: 186 TestCase (TestContext& testCtx, const char* name) : m_testCtx(testCtx), m_name(name) {} 187 virtual ~TestCase (void) {} 188 189 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 194protected: 195 TestContext& m_testCtx; 196 std::string m_name; 197}; 198 199class TestExecutor 200{ 201public: 202 TestExecutor (TestContext& testCtx); 203 ~TestExecutor (void); 204 205 void runCases (const std::vector<TestCase*>& testCases); 206 bool runCase (TestCase* testCase); 207 208private: 209 TestContext& m_testCtx; 210}; 211 212TestExecutor::TestExecutor (TestContext& testCtx) 213 : m_testCtx(testCtx) 214{ 215} 216 217TestExecutor::~TestExecutor (void) 218{ 219} 220 221void 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 235class FilePrinter : public de::Thread 236{ 237public: 238 FilePrinter (void) 239 : m_curFile(DE_NULL) 240 { 241 } 242 243 void start (deFile* file) 244 { 245 DE_ASSERT(!m_curFile); 246 m_curFile = file; 247 de::Thread::start(); 248 } 249 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 261private: 262 deFile* m_curFile; 263}; 264 265bool 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 335class ConnectTest : public TestCase 336{ 337public: 338 ConnectTest (TestContext& testCtx) 339 : TestCase(testCtx, "connect") 340 { 341 } 342 343 void runClient (de::Socket& socket) 344 { 345 DE_UNREF(socket); 346 } 347 348 void runProgram (void) { /* nothing */ } 349}; 350 351class HelloTest : public TestCase 352{ 353public: 354 HelloTest (TestContext& testCtx) 355 : TestCase(testCtx, "hello") 356 { 357 } 358 359 void runClient (de::Socket& socket) 360 { 361 xs::HelloMessage msg; 362 sendMessage(socket, (const xs::Message&)msg); 363 } 364 365 void runProgram (void) { /* nothing */ } 366}; 367 368class ExecFailTest : public TestCase 369{ 370public: 371 ExecFailTest (TestContext& testCtx) 372 : TestCase(testCtx, "exec-fail") 373 { 374 } 375 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 405 void runProgram (void) { /* nothing */ } 406}; 407 408class SimpleExecTest : public TestCase 409{ 410public: 411 SimpleExecTest (TestContext& testCtx) 412 : TestCase(testCtx, "simple-exec") 413 { 414 } 415 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 461 void runProgram (void) { /* print nothing. */ } 462}; 463 464class InfoTest : public TestCase 465{ 466public: 467 std::string infoStr; 468 469 InfoTest (TestContext& testCtx) 470 : TestCase (testCtx, "info") 471 , infoStr ("Hello, World") 472 { 473 } 474 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 526 void runProgram (void) { printf("%s", infoStr.c_str()); } 527}; 528 529class LogDataTest : public TestCase 530{ 531public: 532 LogDataTest (TestContext& testCtx) 533 : TestCase(testCtx, "logdata") 534 { 535 } 536 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 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 616class BigLogDataTest : public TestCase 617{ 618public: 619 enum 620 { 621 DATA_SIZE = 100*1024*1024 622 }; 623 624 BigLogDataTest (TestContext& testCtx) 625 : TestCase(testCtx, "biglogdata") 626 { 627 } 628 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 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 713class KeepAliveTest : public TestCase 714{ 715public: 716 KeepAliveTest (TestContext& testCtx) 717 : TestCase(testCtx, "keepalive") 718 { 719 } 720 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 812 void runProgram (void) { /* nothing */ } 813}; 814 815void 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 827struct CompareCaseName 828{ 829 std::string name; 830 831 CompareCaseName (const string& name_) : name(name_) {} 832 833 bool operator() (const TestCase* testCase) const 834 { 835 return name == testCase->getName(); 836 } 837}; 838 839void 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 940void 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 973void 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 1029int main (int argc, const char* const* argv) 1030{ 1031 xs::runExecServerTests(argc, argv); 1032 return 0; 1033} 1034