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