| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.core; |
| |
| import java.util.ArrayList; |
| import java.util.Map; |
| |
| import org.apache.http.protocol.HTTP; |
| import android.util.Log; |
| import android.util.Config; |
| import android.net.http.*; |
| |
| /** |
| * Implements EventHandler and provides test functionality to validate |
| * responses to requests from the test server |
| */ |
| public class TestEventHandler implements EventHandler { |
| |
| /** |
| * Status variables |
| */ |
| private int majorVersion = -1; |
| private int minorVersion = -1; |
| private int responseCode = -1; |
| private String reasonPhrase; |
| |
| /* List of headers received */ |
| private Map<String, String> headerMap; |
| |
| /* Used to sync low level delayed requests */ |
| public static final Object syncObj = new Object(); |
| |
| /* Indicates whether the low level request testing is in operation */ |
| private boolean useLowLevel = false; |
| |
| /* Indicates whether responses should be automatically generated or |
| * delayed |
| */ |
| private boolean delayResponse = false; |
| |
| /* Test method expectation identifiers */ |
| public final static int TEST_REQUEST_SENT = 0; |
| public final static int TEST_STATUS = 1; |
| public final static int TEST_HEADERS = 2; |
| public final static int TEST_LOCATION_CHANGED = 3; |
| public final static int TEST_DATA = 4; |
| public final static int TEST_ENDDATA = 5; |
| public final static int TEST_ERROR = 6; |
| public final static int TEST_SSL_CERTIFICATE_ERROR = 7; |
| |
| public final static int TEST_NUM_EXPECTS = 8; |
| |
| /* Expected status codes */ |
| private int expectMajor = -1; |
| private int expectMinor = -1; |
| private int expectCode = -1; |
| |
| /* Array indicating which event types are expected */ |
| private boolean[] expects = new boolean[TEST_NUM_EXPECTS]; |
| |
| /* Array indicating which event types are not expected */ |
| private boolean[] notExpecting = new boolean[TEST_NUM_EXPECTS]; |
| |
| /* Indicates which events have been received */ |
| private boolean[] eventsReceived = new boolean[TEST_NUM_EXPECTS]; |
| |
| /* Redirection variables */ |
| private String expectLocation; |
| private int expectPermanent = -1; |
| |
| /* Content data expected to be received */ |
| private byte[] expectData; |
| private int expectDataLength = -1; |
| |
| private int expectErrorId = -1; |
| |
| private int expectSslErrors = -1; |
| private SslCertificate expectCertificate; |
| |
| public class TestHeader { |
| public TestHeader(String n, String v) { |
| name = n; |
| value = v; |
| } |
| public String name; |
| public String value; |
| } |
| |
| private ArrayList<TestHeader> expectHeaders = new ArrayList<TestHeader>(); |
| |
| /* Holds failure details */ |
| private StringBuffer expectDetails = new StringBuffer(); |
| |
| /* If we use a request handle, we retain a reference here for redirects |
| * using setupRedirect |
| */ |
| private RequestHandle mRequestHandle; |
| |
| /* The low level API uses this reference also for non-delayed requests */ |
| private LowLevelNetRunner netRunner; |
| |
| public TestEventHandler() { |
| for (int i = 0; i < TEST_NUM_EXPECTS; i++) { |
| expects[i] = false; |
| notExpecting[i] = false; |
| eventsReceived[i] = false; |
| } |
| } |
| |
| /** |
| * Implementation of EventHandler method called when a request has been |
| * sent. If the test is waiting for this call, it will be signalled, |
| * otherwise this method will trigger the response to be read |
| * automatically. |
| */ |
| public void requestSent() { |
| Log.v(LOGTAG, "TestEventHandler:requestSent()"); |
| expects[TEST_REQUEST_SENT] = false; |
| eventsReceived[TEST_REQUEST_SENT] = true; |
| if (notExpecting[TEST_REQUEST_SENT]) { |
| expectDetails.append("Request sent event received but not expected"); |
| expectDetails.append("\r\n"); |
| } |
| |
| if (useLowLevel) { |
| if (delayResponse) { |
| synchronized (syncObj) { |
| syncObj.notifyAll(); |
| } |
| } else { |
| // mRequest.startReadingResponse(); |
| } |
| } |
| } |
| |
| /** |
| * Implements the EventHandler status method called when a server status |
| * response is received. |
| * @param major_version The HTTP major version |
| * @param minor_version The HTTP minor version |
| * @param code The status code |
| * @param reason_phrase A reason phrase passed to us by the server |
| */ |
| public void status(int major_version, int minor_version, |
| int code, String reason_phrase) { |
| if (Config.LOGV) { |
| Log.v(LOGTAG, "TestEventHandler:status() major: " + major_version + |
| " minor: " + minor_version + |
| " code: " + code + |
| " reason: " + reason_phrase); |
| } |
| |
| eventsReceived[TEST_STATUS] = true; |
| if (notExpecting[TEST_STATUS]) { |
| expectDetails.append("Status event received but not expected"); |
| expectDetails.append("\r\n"); |
| } |
| |
| majorVersion = major_version; |
| minorVersion = minor_version; |
| responseCode = code; |
| reasonPhrase = reason_phrase; |
| |
| if (expectMajor != -1) { |
| if (expectMajor == major_version) { |
| expectMajor = -1; |
| } else { |
| expectDetails.append("Major version expected:"+expectMajor+ |
| " got:"+major_version); |
| expectDetails.append("\r\n"); |
| } |
| } |
| |
| if (expectMinor != -1) { |
| if (expectMinor == minor_version) { |
| expectMinor = -1; |
| } else { |
| expectDetails.append("Minor version expected:"+expectMinor+ |
| " got:"+minor_version); |
| expectDetails.append("\r\n"); |
| } |
| } |
| |
| if (expectCode != -1) { |
| if (expectCode == code) { |
| expectCode = -1; |
| } else { |
| expectDetails.append("Status code expected:"+expectCode+ |
| " got:"+code); |
| expectDetails.append("\r\n"); |
| } |
| } |
| |
| |
| if ((expectMajor == -1) && (expectMinor == -1) && (expectCode == -1)) { |
| expects[TEST_STATUS] = false; |
| } else { |
| System.out.println("MAJOR = "+expectMajor+" MINOR = "+expectMinor+ |
| " CODE = "+expectCode); |
| } |
| } |
| |
| /** |
| * Implements the EventHandler headers method called when a server |
| * sends header fields |
| */ |
| public void headers(Headers headers) { |
| if (Config.LOGV) { |
| Log.v(LOGTAG, "TestEventHandler:headers()"); |
| } |
| expects[TEST_HEADERS] = false; |
| |
| if (notExpecting[TEST_HEADERS]) { |
| expectDetails.append("Header event received but not expected"); |
| expectDetails.append("\r\n"); |
| } |
| |
| /* Check through headers received for matches with expected |
| * headers */ |
| if (expectHeaders.isEmpty()) { |
| return; |
| } |
| |
| for (int i = expectHeaders.size() - 1; i >= 0; i--) { |
| TestHeader h = expectHeaders.get(i); |
| System.out.println("Expected header name: " + h.name); |
| String s = null; |
| switch (h.name.hashCode()) { |
| case -1132779846: |
| s = Long.toString(headers.getContentLength()); |
| break; |
| case 785670158: |
| s = headers.getContentType(); |
| break; |
| case 2095084583: |
| s = headers.getContentEncoding(); |
| break; |
| case 1901043637: |
| s = headers.getLocation(); |
| break; |
| case -243037365: |
| s = headers.getWwwAuthenticate(); |
| break; |
| case -301767724: |
| s = headers.getProxyAuthenticate(); |
| break; |
| case -1267267485: |
| s = headers.getContentDisposition(); |
| break; |
| case 1397189435: |
| s = headers.getAcceptRanges(); |
| break; |
| case -1309235404: |
| s = headers.getExpires(); |
| break; |
| case -208775662: |
| s = headers.getCacheControl(); |
| break; |
| case 150043680: |
| s = headers.getLastModified(); |
| break; |
| case 3123477: |
| s = headers.getEtag(); |
| break; |
| case -775651618: |
| int ct = headers.getConnectionType(); |
| if (ct == Headers.CONN_CLOSE) { |
| s = HTTP.CONN_CLOSE; |
| } else if (ct == Headers.CONN_KEEP_ALIVE) { |
| s = HTTP.CONN_KEEP_ALIVE; |
| } |
| break; |
| default: |
| s = null; |
| |
| } |
| if (evaluateHeader(h, s)) { |
| expectHeaders.remove(i); |
| } |
| } |
| |
| } |
| |
| public boolean evaluateHeader(TestHeader h, String value) { |
| if (value == null) { |
| expects[TEST_HEADERS] = true; |
| System.out.print(" Missing! "); |
| expectDetails.append(" missing header " + h.name); |
| return false; |
| } |
| if (h.value == null) { |
| System.out.println("Expect value = null"); |
| return true; |
| } |
| System.out.println("Expect value = " + |
| (h.value.toLowerCase()) + " got " + |
| value.toLowerCase()); |
| |
| if (!h.value.equalsIgnoreCase(value)) { |
| expectDetails.append("expect header value " + h.value + |
| " got " + value); |
| expects[TEST_HEADERS] = true; |
| return false; |
| } |
| return true; |
| } |
| /** |
| * Implements the EventHandler locationChanged method called when a server |
| * sends a redirect message |
| * @param newLocation The URL to the new server |
| * @param permanent Indicator of whether this is a permanent change |
| */ |
| public void locationChanged(String newLocation, boolean permanent) { |
| if (Config.LOGV) { |
| Log.v(LOGTAG, "TestEventHandler: locationChanged() " + |
| newLocation + " permanent " + permanent); |
| } |
| |
| eventsReceived[TEST_LOCATION_CHANGED] = true; |
| if (notExpecting[TEST_LOCATION_CHANGED]) { |
| expectDetails.append("Location changed event received but "+ |
| "not expected"); |
| expectDetails.append("\r\n"); |
| } |
| |
| if (expectLocation != null) { |
| if (expectLocation.equals(newLocation)) { |
| expectLocation = null; |
| } else { |
| expectDetails.append("Location expected:"+expectLocation+ |
| " got:"+newLocation); |
| expectDetails.append("\r\n"); |
| } |
| } |
| |
| if (expectPermanent != -1) { |
| if (((expectPermanent == 0) && !permanent) || |
| ((expectPermanent == 1) && permanent)){ |
| expectPermanent = -1; |
| } else { |
| expectDetails.append("Location permanent expected:"+ |
| expectPermanent+" got"+permanent); |
| expectDetails.append("\r\n"); |
| } |
| } |
| |
| if ((expectLocation == null) && (expectPermanent == -1)) |
| expects[TEST_LOCATION_CHANGED] = false; |
| } |
| |
| /** |
| * Implements the EventHandler data method called when a server |
| * sends content data |
| * @param data The byte array content |
| * @param len The length of the data |
| */ |
| public void data(byte[] data, int len) { |
| boolean mismatch = false; |
| |
| if (Config.LOGV) { |
| Log.v(LOGTAG, "TestEventHandler: data() " + len + " bytes"); |
| } |
| |
| eventsReceived[TEST_DATA] = true; |
| if (notExpecting[TEST_DATA]) { |
| expectDetails.append("Data event received but not expected"); |
| expectDetails.append("\r\n"); |
| } |
| |
| Log.v(LOGTAG, new String(data, 0, len)); |
| |
| if (expectDataLength != -1) { |
| if (expectDataLength == len) { |
| expectDataLength = -1; |
| } else { |
| expectDetails.append("expect data length mismatch expected:"+ |
| expectDataLength+" got:"+len); |
| expectDetails.append("\r\n"); |
| } |
| |
| /* Check data only if length is the same */ |
| if ((expectDataLength == -1) && expectData != null) { |
| for (int i = 0; i < len; i++) { |
| if (expectData[i] != data[i]) { |
| mismatch = true; |
| expectDetails.append("Expect data mismatch at byte "+ |
| i+" expected:"+expectData[i]+" got:"+data[i]); |
| expectDetails.append("\r\n"); |
| break; |
| } |
| } |
| } |
| } |
| |
| if ((expectDataLength == -1) || !mismatch) |
| expects[TEST_DATA] = false; |
| } |
| |
| /** |
| * Implements the EventHandler endData method called to |
| * indicate completion or a request |
| */ |
| public void endData() { |
| if (Config.LOGV) { |
| Log.v(LOGTAG, "TestEventHandler: endData() called"); |
| } |
| |
| eventsReceived[TEST_ENDDATA] = true; |
| if (notExpecting[TEST_ENDDATA]) { |
| expectDetails.append("End data event received but not expected"); |
| expectDetails.append("\r\n"); |
| } |
| |
| expects[TEST_ENDDATA] = false; |
| |
| if (useLowLevel) { |
| if (delayResponse) { |
| synchronized (syncObj) { |
| syncObj.notifyAll(); |
| } |
| } else { |
| if (netRunner != null) { |
| System.out.println("TestEventHandler: endData() stopping "+ |
| netRunner); |
| netRunner.decrementRunCount(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Implements the EventHandler certificate method called every |
| * time a resource is loaded via a secure connection |
| */ |
| public void certificate(SslCertificate certificate) {} |
| |
| /** |
| * Implements the EventHandler error method called when a server |
| * sends header fields |
| * @param id Status code of the error |
| * @param description Brief description of the error |
| */ |
| public void error(int id, String description) { |
| if (Config.LOGV) { |
| Log.v(LOGTAG, "TestEventHandler: error() called Id:" + id + |
| " description " + description); |
| } |
| |
| eventsReceived[TEST_ERROR] = true; |
| if (notExpecting[TEST_ERROR]) { |
| expectDetails.append("Error event received but not expected"); |
| expectDetails.append("\r\n"); |
| } |
| if (expectErrorId != -1) { |
| if (expectErrorId == id) { |
| expectErrorId = -1; |
| } else { |
| expectDetails.append("Error Id expected:"+expectErrorId+ |
| " got:"+id); |
| expectDetails.append("\r\n"); |
| } |
| } |
| |
| if (expectErrorId == -1) |
| expects[TEST_ERROR] = false; |
| |
| if (useLowLevel) { |
| if (delayResponse) { |
| synchronized (syncObj) { |
| syncObj.notifyAll(); |
| } |
| } else { |
| if (netRunner != null) { |
| System.out.println("TestEventHandler: endData() stopping "+ |
| netRunner); |
| netRunner.decrementRunCount(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * SSL certificate error callback. Handles SSL error(s) on the way |
| * up to the user. |
| */ |
| public void handleSslErrorRequest(SslError error) { |
| int primaryError = error.getPrimaryError(); |
| |
| if (Config.LOGV) { |
| Log.v(LOGTAG, "TestEventHandler: handleSslErrorRequest(): "+ |
| " primary error:" + primaryError + |
| " certificate: " + error.getCertificate()); |
| } |
| |
| eventsReceived[TEST_SSL_CERTIFICATE_ERROR] = true; |
| if (notExpecting[TEST_SSL_CERTIFICATE_ERROR]) { |
| expectDetails.append("SSL Certificate error event received "+ |
| "but not expected"); |
| expectDetails.append("\r\n"); |
| } |
| |
| if (expectSslErrors != -1) { |
| if (expectSslErrors == primaryError) { |
| expectSslErrors = -1; |
| } else { |
| expectDetails.append("SslCertificateError id expected:"+ |
| expectSslErrors+" got: " + primaryError); |
| expectDetails.append("\r\n"); |
| } |
| } |
| |
| // SslCertificate match here? |
| |
| if (expectSslErrors == -1) // && expectSslCertificate == certificate? |
| expects[TEST_SSL_CERTIFICATE_ERROR] = false; |
| } |
| |
| /** |
| * Use the low level net runner with no delayed response |
| * @param runner The LowLevelNetRunner object |
| */ |
| public void setNetRunner(LowLevelNetRunner runner) { |
| setNetRunner(runner, false); |
| } |
| |
| /** |
| * Use the low level net runner and specify if the response |
| * should be delayed |
| * @param runner The LowLevelNetRunner object |
| * @param delayedResponse Set to true is you will use the |
| * waitForRequestSent/waitForRequestResponse routines |
| */ |
| public void setNetRunner(LowLevelNetRunner runner, |
| boolean delayedResponse) { |
| netRunner = runner; |
| useLowLevel = true; |
| delayResponse = delayedResponse; |
| |
| if (!delayResponse) |
| netRunner.incrementRunCount(); |
| } |
| |
| /** |
| * Enable this listeners Request object to read server responses. |
| * This should only be used in conjunction with setDelayResponse(true) |
| */ |
| public void waitForRequestResponse() { |
| if (!delayResponse || !useLowLevel) { |
| Log.d(LOGTAG, " Cant do this without delayReponse set "); |
| return; |
| } |
| |
| //if (mRequest != null) { |
| // mRequest.startReadingResponse(); |
| // } |
| /* Now wait for the response to be completed either through endData |
| * or an error |
| */ |
| synchronized (syncObj) { |
| try { |
| syncObj.wait(); |
| } catch (InterruptedException e) { |
| } |
| } |
| } |
| |
| /** |
| * Enable this listeners Request object to read server responses. |
| * This should only be used in conjunction with setDelayResponse(true) |
| */ |
| public void waitForRequestSent() { |
| if (!delayResponse || !useLowLevel) { |
| Log.d(LOGTAG, " Cant do this without delayReponse set "); |
| return; |
| } |
| |
| /* Now wait for the response to be completed either through endData |
| * or an error |
| */ |
| synchronized (syncObj) { |
| try { |
| syncObj.wait(); |
| } catch (InterruptedException e) { |
| } |
| } |
| } |
| |
| /* Test expected values - these routines set the tests expectations */ |
| |
| public void expectRequestSent() { |
| expects[TEST_REQUEST_SENT] = true; |
| } |
| |
| public void expectNoRequestSent() { |
| notExpecting[TEST_REQUEST_SENT] = true; |
| } |
| |
| public void expectStatus() { |
| expects[TEST_STATUS] = true; |
| } |
| |
| public void expectNoStatus() { |
| notExpecting[TEST_STATUS] = true; |
| } |
| |
| public void expectStatus(int major, int minor, int code) { |
| expects[TEST_STATUS] = true; |
| expectMajor = major; |
| expectMinor = minor; |
| expectCode = code; |
| } |
| |
| public void expectStatus(int code) { |
| expects[TEST_STATUS] = true; |
| expectCode = code; |
| } |
| |
| public void expectHeaders() { |
| expects[TEST_HEADERS] = true; |
| } |
| |
| public void expectNoHeaders() { |
| notExpecting[TEST_HEADERS] = true; |
| } |
| |
| public void expectHeaderAdd(String name) { |
| expects[TEST_HEADERS] = true; |
| TestHeader h = new TestHeader(name.toLowerCase(), null); |
| expectHeaders.add(h); |
| } |
| |
| public void expectHeaderAdd(String name, String value) { |
| expects[TEST_HEADERS] = true; |
| TestHeader h = new TestHeader(name.toLowerCase(), value); |
| expectHeaders.add(h); |
| } |
| |
| public void expectLocationChanged() { |
| expects[TEST_LOCATION_CHANGED] = true; |
| } |
| |
| public void expectNoLocationChanged() { |
| notExpecting[TEST_LOCATION_CHANGED] = true; |
| } |
| |
| public void expectLocationChanged(String newLocation) { |
| expects[TEST_LOCATION_CHANGED] = true; |
| expectLocation = newLocation; |
| } |
| |
| public void expectLocationChanged(String newLocation, boolean permanent) { |
| expects[TEST_LOCATION_CHANGED] = true; |
| expectLocation = newLocation; |
| expectPermanent = permanent ? 1 : 0; |
| } |
| |
| public void expectData() { |
| expects[TEST_DATA] = true; |
| } |
| |
| public void expectNoData() { |
| notExpecting[TEST_DATA] = true; |
| } |
| |
| public void expectData(int len) { |
| expects[TEST_DATA] = true; |
| expectDataLength = len; |
| } |
| |
| public void expectData(byte[] data, int len) { |
| expects[TEST_DATA] = true; |
| expectData = new byte[len]; |
| expectDataLength = len; |
| |
| for (int i = 0; i < len; i++) { |
| expectData[i] = data[i]; |
| } |
| } |
| |
| public void expectEndData() { |
| expects[TEST_ENDDATA] = true; |
| } |
| |
| public void expectNoEndData() { |
| notExpecting[TEST_ENDDATA] = true; |
| } |
| |
| public void expectError() { |
| expects[TEST_ERROR] = true; |
| } |
| |
| public void expectNoError() { |
| notExpecting[TEST_ERROR] = true; |
| } |
| |
| public void expectError(int errorId) { |
| expects[TEST_ERROR] = true; |
| expectErrorId = errorId; |
| } |
| |
| public void expectSSLCertificateError() { |
| expects[TEST_SSL_CERTIFICATE_ERROR] = true; |
| } |
| |
| public void expectNoSSLCertificateError() { |
| notExpecting[TEST_SSL_CERTIFICATE_ERROR] = true; |
| } |
| |
| public void expectSSLCertificateError(int errors) { |
| expects[TEST_SSL_CERTIFICATE_ERROR] = true; |
| expectSslErrors = errors; |
| } |
| |
| public void expectSSLCertificateError(SslCertificate certificate) { |
| expects[TEST_SSL_CERTIFICATE_ERROR] = true; |
| expectCertificate = certificate; |
| } |
| |
| /** |
| * Test to see if current expectations match recieved information |
| * @return True is all expected results have been matched |
| */ |
| public boolean expectPassed() { |
| for (int i = 0; i < TEST_NUM_EXPECTS; i++) { |
| if (expects[i] == true) { |
| return false; |
| } |
| } |
| |
| for (int i = 0; i < TEST_NUM_EXPECTS; i++) { |
| if (eventsReceived[i] && notExpecting[i]) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Return message indicating expectation failures |
| */ |
| public String getFailureMessage() { |
| return expectDetails.toString(); |
| } |
| |
| /** |
| * Reset all expectation values for re-use |
| */ |
| public void resetExpects() { |
| expectMajor = -1; |
| expectMinor = -1; |
| expectCode = -1; |
| expectLocation = null; |
| expectPermanent = -1; |
| expectErrorId = -1; |
| expectSslErrors = -1; |
| expectCertificate = null; |
| expectDetails.setLength(0); |
| expectHeaders.clear(); |
| |
| for (int i = 0; i < TEST_NUM_EXPECTS; i++) { |
| expects[i] = false; |
| notExpecting[i] = false; |
| eventsReceived[i] = false; |
| } |
| |
| for (int i = 0; i < expectDataLength; i++) { |
| expectData[i] = 0; |
| } |
| |
| expectDataLength = -1; |
| } |
| |
| /** |
| * Attach the RequestHandle to this handler |
| * @param requestHandle The RequestHandle |
| */ |
| public void attachRequestHandle(RequestHandle requestHandle) { |
| if (Config.LOGV) { |
| Log.v(LOGTAG, "TestEventHandler.attachRequestHandle(): " + |
| "requestHandle: " + requestHandle); |
| } |
| mRequestHandle = requestHandle; |
| } |
| |
| /** |
| * Detach the RequestHandle |
| */ |
| public void detachRequestHandle() { |
| if (Config.LOGV) { |
| Log.v(LOGTAG, "TestEventHandler.detachRequestHandle(): " + |
| "requestHandle: " + mRequestHandle); |
| } |
| mRequestHandle = null; |
| } |
| |
| protected final static String LOGTAG = "http"; |
| } |