1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.core; 18 19 import java.util.ArrayList; 20 import java.util.Map; 21 22 import org.apache.http.protocol.HTTP; 23 import android.util.Log; 24 import android.net.http.*; 25 26 /** 27 * Implements EventHandler and provides test functionality to validate 28 * responses to requests from the test server 29 */ 30 public class TestEventHandler implements EventHandler { 31 32 /** 33 * Status variables 34 */ 35 private int majorVersion = -1; 36 private int minorVersion = -1; 37 private int responseCode = -1; 38 private String reasonPhrase; 39 40 /* List of headers received */ 41 private Map<String, String> headerMap; 42 43 /* Used to sync low level delayed requests */ 44 public static final Object syncObj = new Object(); 45 46 /* Indicates whether the low level request testing is in operation */ 47 private boolean useLowLevel = false; 48 49 /* Indicates whether responses should be automatically generated or 50 * delayed 51 */ 52 private boolean delayResponse = false; 53 54 /* Test method expectation identifiers */ 55 public final static int TEST_REQUEST_SENT = 0; 56 public final static int TEST_STATUS = 1; 57 public final static int TEST_HEADERS = 2; 58 public final static int TEST_LOCATION_CHANGED = 3; 59 public final static int TEST_DATA = 4; 60 public final static int TEST_ENDDATA = 5; 61 public final static int TEST_ERROR = 6; 62 public final static int TEST_SSL_CERTIFICATE_ERROR = 7; 63 64 public final static int TEST_NUM_EXPECTS = 8; 65 66 /* Expected status codes */ 67 private int expectMajor = -1; 68 private int expectMinor = -1; 69 private int expectCode = -1; 70 71 /* Array indicating which event types are expected */ 72 private boolean[] expects = new boolean[TEST_NUM_EXPECTS]; 73 74 /* Array indicating which event types are not expected */ 75 private boolean[] notExpecting = new boolean[TEST_NUM_EXPECTS]; 76 77 /* Indicates which events have been received */ 78 private boolean[] eventsReceived = new boolean[TEST_NUM_EXPECTS]; 79 80 /* Redirection variables */ 81 private String expectLocation; 82 private int expectPermanent = -1; 83 84 /* Content data expected to be received */ 85 private byte[] expectData; 86 private int expectDataLength = -1; 87 88 private int expectErrorId = -1; 89 90 private int expectSslErrors = -1; 91 private SslCertificate expectCertificate; 92 93 public class TestHeader { 94 public TestHeader(String n, String v) { 95 name = n; 96 value = v; 97 } 98 public String name; 99 public String value; 100 } 101 102 private ArrayList<TestHeader> expectHeaders = new ArrayList<TestHeader>(); 103 104 /* Holds failure details */ 105 private StringBuffer expectDetails = new StringBuffer(); 106 107 /* If we use a request handle, we retain a reference here for redirects 108 * using setupRedirect 109 */ 110 private RequestHandle mRequestHandle; 111 112 /* The low level API uses this reference also for non-delayed requests */ 113 private LowLevelNetRunner netRunner; 114 115 public TestEventHandler() { 116 for (int i = 0; i < TEST_NUM_EXPECTS; i++) { 117 expects[i] = false; 118 notExpecting[i] = false; 119 eventsReceived[i] = false; 120 } 121 } 122 123 /** 124 * Implementation of EventHandler method called when a request has been 125 * sent. If the test is waiting for this call, it will be signalled, 126 * otherwise this method will trigger the response to be read 127 * automatically. 128 */ 129 public void requestSent() { 130 Log.v(LOGTAG, "TestEventHandler:requestSent()"); 131 expects[TEST_REQUEST_SENT] = false; 132 eventsReceived[TEST_REQUEST_SENT] = true; 133 if (notExpecting[TEST_REQUEST_SENT]) { 134 expectDetails.append("Request sent event received but not expected"); 135 expectDetails.append("\r\n"); 136 } 137 138 if (useLowLevel) { 139 if (delayResponse) { 140 synchronized (syncObj) { 141 syncObj.notifyAll(); 142 } 143 } else { 144 // mRequest.startReadingResponse(); 145 } 146 } 147 } 148 149 /** 150 * Implements the EventHandler status method called when a server status 151 * response is received. 152 * @param major_version The HTTP major version 153 * @param minor_version The HTTP minor version 154 * @param code The status code 155 * @param reason_phrase A reason phrase passed to us by the server 156 */ 157 public void status(int major_version, int minor_version, 158 int code, String reason_phrase) { 159 if (false) { 160 Log.v(LOGTAG, "TestEventHandler:status() major: " + major_version + 161 " minor: " + minor_version + 162 " code: " + code + 163 " reason: " + reason_phrase); 164 } 165 166 eventsReceived[TEST_STATUS] = true; 167 if (notExpecting[TEST_STATUS]) { 168 expectDetails.append("Status event received but not expected"); 169 expectDetails.append("\r\n"); 170 } 171 172 majorVersion = major_version; 173 minorVersion = minor_version; 174 responseCode = code; 175 reasonPhrase = reason_phrase; 176 177 if (expectMajor != -1) { 178 if (expectMajor == major_version) { 179 expectMajor = -1; 180 } else { 181 expectDetails.append("Major version expected:"+expectMajor+ 182 " got:"+major_version); 183 expectDetails.append("\r\n"); 184 } 185 } 186 187 if (expectMinor != -1) { 188 if (expectMinor == minor_version) { 189 expectMinor = -1; 190 } else { 191 expectDetails.append("Minor version expected:"+expectMinor+ 192 " got:"+minor_version); 193 expectDetails.append("\r\n"); 194 } 195 } 196 197 if (expectCode != -1) { 198 if (expectCode == code) { 199 expectCode = -1; 200 } else { 201 expectDetails.append("Status code expected:"+expectCode+ 202 " got:"+code); 203 expectDetails.append("\r\n"); 204 } 205 } 206 207 208 if ((expectMajor == -1) && (expectMinor == -1) && (expectCode == -1)) { 209 expects[TEST_STATUS] = false; 210 } else { 211 System.out.println("MAJOR = "+expectMajor+" MINOR = "+expectMinor+ 212 " CODE = "+expectCode); 213 } 214 } 215 216 /** 217 * Implements the EventHandler headers method called when a server 218 * sends header fields 219 */ 220 public void headers(Headers headers) { 221 if (false) { 222 Log.v(LOGTAG, "TestEventHandler:headers()"); 223 } 224 expects[TEST_HEADERS] = false; 225 226 if (notExpecting[TEST_HEADERS]) { 227 expectDetails.append("Header event received but not expected"); 228 expectDetails.append("\r\n"); 229 } 230 231 /* Check through headers received for matches with expected 232 * headers */ 233 if (expectHeaders.isEmpty()) { 234 return; 235 } 236 237 for (int i = expectHeaders.size() - 1; i >= 0; i--) { 238 TestHeader h = expectHeaders.get(i); 239 System.out.println("Expected header name: " + h.name); 240 String s = null; 241 switch (h.name.hashCode()) { 242 case -1132779846: 243 s = Long.toString(headers.getContentLength()); 244 break; 245 case 785670158: 246 s = headers.getContentType(); 247 break; 248 case 2095084583: 249 s = headers.getContentEncoding(); 250 break; 251 case 1901043637: 252 s = headers.getLocation(); 253 break; 254 case -243037365: 255 s = headers.getWwwAuthenticate(); 256 break; 257 case -301767724: 258 s = headers.getProxyAuthenticate(); 259 break; 260 case -1267267485: 261 s = headers.getContentDisposition(); 262 break; 263 case 1397189435: 264 s = headers.getAcceptRanges(); 265 break; 266 case -1309235404: 267 s = headers.getExpires(); 268 break; 269 case -208775662: 270 s = headers.getCacheControl(); 271 break; 272 case 150043680: 273 s = headers.getLastModified(); 274 break; 275 case 3123477: 276 s = headers.getEtag(); 277 break; 278 case -775651618: 279 int ct = headers.getConnectionType(); 280 if (ct == Headers.CONN_CLOSE) { 281 s = HTTP.CONN_CLOSE; 282 } else if (ct == Headers.CONN_KEEP_ALIVE) { 283 s = HTTP.CONN_KEEP_ALIVE; 284 } 285 break; 286 default: 287 s = null; 288 289 } 290 if (evaluateHeader(h, s)) { 291 expectHeaders.remove(i); 292 } 293 } 294 295 } 296 297 public boolean evaluateHeader(TestHeader h, String value) { 298 if (value == null) { 299 expects[TEST_HEADERS] = true; 300 System.out.print(" Missing! "); 301 expectDetails.append(" missing header " + h.name); 302 return false; 303 } 304 if (h.value == null) { 305 System.out.println("Expect value = null"); 306 return true; 307 } 308 System.out.println("Expect value = " + 309 (h.value.toLowerCase()) + " got " + 310 value.toLowerCase()); 311 312 if (!h.value.equalsIgnoreCase(value)) { 313 expectDetails.append("expect header value " + h.value + 314 " got " + value); 315 expects[TEST_HEADERS] = true; 316 return false; 317 } 318 return true; 319 } 320 /** 321 * Implements the EventHandler locationChanged method called when a server 322 * sends a redirect message 323 * @param newLocation The URL to the new server 324 * @param permanent Indicator of whether this is a permanent change 325 */ 326 public void locationChanged(String newLocation, boolean permanent) { 327 if (false) { 328 Log.v(LOGTAG, "TestEventHandler: locationChanged() " + 329 newLocation + " permanent " + permanent); 330 } 331 332 eventsReceived[TEST_LOCATION_CHANGED] = true; 333 if (notExpecting[TEST_LOCATION_CHANGED]) { 334 expectDetails.append("Location changed event received but "+ 335 "not expected"); 336 expectDetails.append("\r\n"); 337 } 338 339 if (expectLocation != null) { 340 if (expectLocation.equals(newLocation)) { 341 expectLocation = null; 342 } else { 343 expectDetails.append("Location expected:"+expectLocation+ 344 " got:"+newLocation); 345 expectDetails.append("\r\n"); 346 } 347 } 348 349 if (expectPermanent != -1) { 350 if (((expectPermanent == 0) && !permanent) || 351 ((expectPermanent == 1) && permanent)){ 352 expectPermanent = -1; 353 } else { 354 expectDetails.append("Location permanent expected:"+ 355 expectPermanent+" got"+permanent); 356 expectDetails.append("\r\n"); 357 } 358 } 359 360 if ((expectLocation == null) && (expectPermanent == -1)) 361 expects[TEST_LOCATION_CHANGED] = false; 362 } 363 364 /** 365 * Implements the EventHandler data method called when a server 366 * sends content data 367 * @param data The byte array content 368 * @param len The length of the data 369 */ 370 public void data(byte[] data, int len) { 371 boolean mismatch = false; 372 373 if (false) { 374 Log.v(LOGTAG, "TestEventHandler: data() " + len + " bytes"); 375 } 376 377 eventsReceived[TEST_DATA] = true; 378 if (notExpecting[TEST_DATA]) { 379 expectDetails.append("Data event received but not expected"); 380 expectDetails.append("\r\n"); 381 } 382 383 Log.v(LOGTAG, new String(data, 0, len)); 384 385 if (expectDataLength != -1) { 386 if (expectDataLength == len) { 387 expectDataLength = -1; 388 } else { 389 expectDetails.append("expect data length mismatch expected:"+ 390 expectDataLength+" got:"+len); 391 expectDetails.append("\r\n"); 392 } 393 394 /* Check data only if length is the same */ 395 if ((expectDataLength == -1) && expectData != null) { 396 for (int i = 0; i < len; i++) { 397 if (expectData[i] != data[i]) { 398 mismatch = true; 399 expectDetails.append("Expect data mismatch at byte "+ 400 i+" expected:"+expectData[i]+" got:"+data[i]); 401 expectDetails.append("\r\n"); 402 break; 403 } 404 } 405 } 406 } 407 408 if ((expectDataLength == -1) || !mismatch) 409 expects[TEST_DATA] = false; 410 } 411 412 /** 413 * Implements the EventHandler endData method called to 414 * indicate completion or a request 415 */ 416 public void endData() { 417 if (false) { 418 Log.v(LOGTAG, "TestEventHandler: endData() called"); 419 } 420 421 eventsReceived[TEST_ENDDATA] = true; 422 if (notExpecting[TEST_ENDDATA]) { 423 expectDetails.append("End data event received but not expected"); 424 expectDetails.append("\r\n"); 425 } 426 427 expects[TEST_ENDDATA] = false; 428 429 if (useLowLevel) { 430 if (delayResponse) { 431 synchronized (syncObj) { 432 syncObj.notifyAll(); 433 } 434 } else { 435 if (netRunner != null) { 436 System.out.println("TestEventHandler: endData() stopping "+ 437 netRunner); 438 netRunner.decrementRunCount(); 439 } 440 } 441 } 442 } 443 444 /** 445 * Implements the EventHandler certificate method called every 446 * time a resource is loaded via a secure connection 447 */ 448 public void certificate(SslCertificate certificate) {} 449 450 /** 451 * Implements the EventHandler error method called when a server 452 * sends header fields 453 * @param id Status code of the error 454 * @param description Brief description of the error 455 */ 456 public void error(int id, String description) { 457 if (false) { 458 Log.v(LOGTAG, "TestEventHandler: error() called Id:" + id + 459 " description " + description); 460 } 461 462 eventsReceived[TEST_ERROR] = true; 463 if (notExpecting[TEST_ERROR]) { 464 expectDetails.append("Error event received but not expected"); 465 expectDetails.append("\r\n"); 466 } 467 if (expectErrorId != -1) { 468 if (expectErrorId == id) { 469 expectErrorId = -1; 470 } else { 471 expectDetails.append("Error Id expected:"+expectErrorId+ 472 " got:"+id); 473 expectDetails.append("\r\n"); 474 } 475 } 476 477 if (expectErrorId == -1) 478 expects[TEST_ERROR] = false; 479 480 if (useLowLevel) { 481 if (delayResponse) { 482 synchronized (syncObj) { 483 syncObj.notifyAll(); 484 } 485 } else { 486 if (netRunner != null) { 487 System.out.println("TestEventHandler: endData() stopping "+ 488 netRunner); 489 netRunner.decrementRunCount(); 490 } 491 } 492 } 493 } 494 495 /** 496 * SSL certificate error callback. Handles SSL error(s) on the way 497 * up to the user. 498 */ 499 public boolean handleSslErrorRequest(SslError error) { 500 int primaryError = error.getPrimaryError(); 501 502 if (false) { 503 Log.v(LOGTAG, "TestEventHandler: handleSslErrorRequest(): "+ 504 " primary error:" + primaryError + 505 " certificate: " + error.getCertificate()); 506 } 507 508 eventsReceived[TEST_SSL_CERTIFICATE_ERROR] = true; 509 if (notExpecting[TEST_SSL_CERTIFICATE_ERROR]) { 510 expectDetails.append("SSL Certificate error event received "+ 511 "but not expected"); 512 expectDetails.append("\r\n"); 513 } 514 515 if (expectSslErrors != -1) { 516 if (expectSslErrors == primaryError) { 517 expectSslErrors = -1; 518 } else { 519 expectDetails.append("SslCertificateError id expected:"+ 520 expectSslErrors+" got: " + primaryError); 521 expectDetails.append("\r\n"); 522 } 523 } 524 525 // SslCertificate match here? 526 527 if (expectSslErrors == -1) // && expectSslCertificate == certificate? 528 expects[TEST_SSL_CERTIFICATE_ERROR] = false; 529 530 // return false so that we won't block the thread 531 return false; 532 } 533 534 /** 535 * Use the low level net runner with no delayed response 536 * @param runner The LowLevelNetRunner object 537 */ 538 public void setNetRunner(LowLevelNetRunner runner) { 539 setNetRunner(runner, false); 540 } 541 542 /** 543 * Use the low level net runner and specify if the response 544 * should be delayed 545 * @param runner The LowLevelNetRunner object 546 * @param delayedResponse Set to true is you will use the 547 * waitForRequestSent/waitForRequestResponse routines 548 */ 549 public void setNetRunner(LowLevelNetRunner runner, 550 boolean delayedResponse) { 551 netRunner = runner; 552 useLowLevel = true; 553 delayResponse = delayedResponse; 554 555 if (!delayResponse) 556 netRunner.incrementRunCount(); 557 } 558 559 /** 560 * Enable this listeners Request object to read server responses. 561 * This should only be used in conjunction with setDelayResponse(true) 562 */ 563 public void waitForRequestResponse() { 564 if (!delayResponse || !useLowLevel) { 565 Log.d(LOGTAG, " Cant do this without delayReponse set "); 566 return; 567 } 568 569 //if (mRequest != null) { 570 // mRequest.startReadingResponse(); 571 // } 572 /* Now wait for the response to be completed either through endData 573 * or an error 574 */ 575 synchronized (syncObj) { 576 try { 577 syncObj.wait(); 578 } catch (InterruptedException e) { 579 } 580 } 581 } 582 583 /** 584 * Enable this listeners Request object to read server responses. 585 * This should only be used in conjunction with setDelayResponse(true) 586 */ 587 public void waitForRequestSent() { 588 if (!delayResponse || !useLowLevel) { 589 Log.d(LOGTAG, " Cant do this without delayReponse set "); 590 return; 591 } 592 593 /* Now wait for the response to be completed either through endData 594 * or an error 595 */ 596 synchronized (syncObj) { 597 try { 598 syncObj.wait(); 599 } catch (InterruptedException e) { 600 } 601 } 602 } 603 604 /* Test expected values - these routines set the tests expectations */ 605 606 public void expectRequestSent() { 607 expects[TEST_REQUEST_SENT] = true; 608 } 609 610 public void expectNoRequestSent() { 611 notExpecting[TEST_REQUEST_SENT] = true; 612 } 613 614 public void expectStatus() { 615 expects[TEST_STATUS] = true; 616 } 617 618 public void expectNoStatus() { 619 notExpecting[TEST_STATUS] = true; 620 } 621 622 public void expectStatus(int major, int minor, int code) { 623 expects[TEST_STATUS] = true; 624 expectMajor = major; 625 expectMinor = minor; 626 expectCode = code; 627 } 628 629 public void expectStatus(int code) { 630 expects[TEST_STATUS] = true; 631 expectCode = code; 632 } 633 634 public void expectHeaders() { 635 expects[TEST_HEADERS] = true; 636 } 637 638 public void expectNoHeaders() { 639 notExpecting[TEST_HEADERS] = true; 640 } 641 642 public void expectHeaderAdd(String name) { 643 expects[TEST_HEADERS] = true; 644 TestHeader h = new TestHeader(name.toLowerCase(), null); 645 expectHeaders.add(h); 646 } 647 648 public void expectHeaderAdd(String name, String value) { 649 expects[TEST_HEADERS] = true; 650 TestHeader h = new TestHeader(name.toLowerCase(), value); 651 expectHeaders.add(h); 652 } 653 654 public void expectLocationChanged() { 655 expects[TEST_LOCATION_CHANGED] = true; 656 } 657 658 public void expectNoLocationChanged() { 659 notExpecting[TEST_LOCATION_CHANGED] = true; 660 } 661 662 public void expectLocationChanged(String newLocation) { 663 expects[TEST_LOCATION_CHANGED] = true; 664 expectLocation = newLocation; 665 } 666 667 public void expectLocationChanged(String newLocation, boolean permanent) { 668 expects[TEST_LOCATION_CHANGED] = true; 669 expectLocation = newLocation; 670 expectPermanent = permanent ? 1 : 0; 671 } 672 673 public void expectData() { 674 expects[TEST_DATA] = true; 675 } 676 677 public void expectNoData() { 678 notExpecting[TEST_DATA] = true; 679 } 680 681 public void expectData(int len) { 682 expects[TEST_DATA] = true; 683 expectDataLength = len; 684 } 685 686 public void expectData(byte[] data, int len) { 687 expects[TEST_DATA] = true; 688 expectData = new byte[len]; 689 expectDataLength = len; 690 691 for (int i = 0; i < len; i++) { 692 expectData[i] = data[i]; 693 } 694 } 695 696 public void expectEndData() { 697 expects[TEST_ENDDATA] = true; 698 } 699 700 public void expectNoEndData() { 701 notExpecting[TEST_ENDDATA] = true; 702 } 703 704 public void expectError() { 705 expects[TEST_ERROR] = true; 706 } 707 708 public void expectNoError() { 709 notExpecting[TEST_ERROR] = true; 710 } 711 712 public void expectError(int errorId) { 713 expects[TEST_ERROR] = true; 714 expectErrorId = errorId; 715 } 716 717 public void expectSSLCertificateError() { 718 expects[TEST_SSL_CERTIFICATE_ERROR] = true; 719 } 720 721 public void expectNoSSLCertificateError() { 722 notExpecting[TEST_SSL_CERTIFICATE_ERROR] = true; 723 } 724 725 public void expectSSLCertificateError(int errors) { 726 expects[TEST_SSL_CERTIFICATE_ERROR] = true; 727 expectSslErrors = errors; 728 } 729 730 public void expectSSLCertificateError(SslCertificate certificate) { 731 expects[TEST_SSL_CERTIFICATE_ERROR] = true; 732 expectCertificate = certificate; 733 } 734 735 /** 736 * Test to see if current expectations match recieved information 737 * @return True is all expected results have been matched 738 */ 739 public boolean expectPassed() { 740 for (int i = 0; i < TEST_NUM_EXPECTS; i++) { 741 if (expects[i] == true) { 742 return false; 743 } 744 } 745 746 for (int i = 0; i < TEST_NUM_EXPECTS; i++) { 747 if (eventsReceived[i] && notExpecting[i]) { 748 return false; 749 } 750 } 751 return true; 752 } 753 754 /** 755 * Return message indicating expectation failures 756 */ 757 public String getFailureMessage() { 758 return expectDetails.toString(); 759 } 760 761 /** 762 * Reset all expectation values for re-use 763 */ 764 public void resetExpects() { 765 expectMajor = -1; 766 expectMinor = -1; 767 expectCode = -1; 768 expectLocation = null; 769 expectPermanent = -1; 770 expectErrorId = -1; 771 expectSslErrors = -1; 772 expectCertificate = null; 773 expectDetails.setLength(0); 774 expectHeaders.clear(); 775 776 for (int i = 0; i < TEST_NUM_EXPECTS; i++) { 777 expects[i] = false; 778 notExpecting[i] = false; 779 eventsReceived[i] = false; 780 } 781 782 for (int i = 0; i < expectDataLength; i++) { 783 expectData[i] = 0; 784 } 785 786 expectDataLength = -1; 787 } 788 789 /** 790 * Attach the RequestHandle to this handler 791 * @param requestHandle The RequestHandle 792 */ 793 public void attachRequestHandle(RequestHandle requestHandle) { 794 if (false) { 795 Log.v(LOGTAG, "TestEventHandler.attachRequestHandle(): " + 796 "requestHandle: " + requestHandle); 797 } 798 mRequestHandle = requestHandle; 799 } 800 801 /** 802 * Detach the RequestHandle 803 */ 804 public void detachRequestHandle() { 805 if (false) { 806 Log.v(LOGTAG, "TestEventHandler.detachRequestHandle(): " + 807 "requestHandle: " + mRequestHandle); 808 } 809 mRequestHandle = null; 810 } 811 812 protected final static String LOGTAG = "http"; 813 } 814