TestEventHandler.java revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
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 void 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
532    /**
533     * Use the low level net runner with no delayed response
534     * @param runner The LowLevelNetRunner object
535     */
536    public void setNetRunner(LowLevelNetRunner runner) {
537      setNetRunner(runner, false);
538    }
539
540    /**
541     * Use the low level net runner and specify if the response
542     * should be delayed
543     * @param runner The LowLevelNetRunner object
544     * @param delayedResponse Set to true is you will use the
545     * waitForRequestSent/waitForRequestResponse routines
546     */
547    public void setNetRunner(LowLevelNetRunner runner,
548        boolean delayedResponse) {
549      netRunner = runner;
550      useLowLevel = true;
551      delayResponse = delayedResponse;
552
553      if (!delayResponse)
554        netRunner.incrementRunCount();
555    }
556
557    /**
558     * Enable this listeners Request object to read server responses.
559     * This should only be used in conjunction with setDelayResponse(true)
560     */
561    public void waitForRequestResponse() {
562      if (!delayResponse || !useLowLevel) {
563        Log.d(LOGTAG, " Cant do this without delayReponse set ");
564        return;
565      }
566
567      //if (mRequest != null) {
568          // mRequest.startReadingResponse();
569      // }
570      /* Now wait for the response to be completed either through endData
571       * or an error
572       */
573      synchronized (syncObj) {
574        try {
575          syncObj.wait();
576        } catch (InterruptedException e) {
577        }
578      }
579    }
580
581    /**
582     * Enable this listeners Request object to read server responses.
583     * This should only be used in conjunction with setDelayResponse(true)
584     */
585    public void waitForRequestSent() {
586      if (!delayResponse || !useLowLevel) {
587        Log.d(LOGTAG, " Cant do this without delayReponse set ");
588        return;
589      }
590
591      /* Now wait for the response to be completed either through endData
592       * or an error
593       */
594      synchronized (syncObj) {
595        try {
596          syncObj.wait();
597        } catch (InterruptedException e) {
598        }
599      }
600    }
601
602    /* Test expected values - these routines set the tests expectations */
603
604    public void expectRequestSent() {
605        expects[TEST_REQUEST_SENT] = true;
606    }
607
608    public void expectNoRequestSent() {
609        notExpecting[TEST_REQUEST_SENT] = true;
610    }
611
612    public void expectStatus() {
613        expects[TEST_STATUS] = true;
614    }
615
616    public void expectNoStatus() {
617        notExpecting[TEST_STATUS] = true;
618    }
619
620    public void expectStatus(int major, int minor, int code) {
621        expects[TEST_STATUS] = true;
622        expectMajor = major;
623        expectMinor = minor;
624        expectCode = code;
625    }
626
627    public void expectStatus(int code) {
628        expects[TEST_STATUS] = true;
629        expectCode = code;
630    }
631
632    public void expectHeaders() {
633        expects[TEST_HEADERS] = true;
634    }
635
636    public void expectNoHeaders() {
637        notExpecting[TEST_HEADERS] = true;
638    }
639
640    public void expectHeaderAdd(String name) {
641        expects[TEST_HEADERS] = true;
642        TestHeader h = new TestHeader(name.toLowerCase(), null);
643        expectHeaders.add(h);
644    }
645
646    public void expectHeaderAdd(String name, String value) {
647        expects[TEST_HEADERS] = true;
648        TestHeader h = new TestHeader(name.toLowerCase(), value);
649        expectHeaders.add(h);
650    }
651
652    public void expectLocationChanged() {
653        expects[TEST_LOCATION_CHANGED] = true;
654    }
655
656    public void expectNoLocationChanged() {
657            notExpecting[TEST_LOCATION_CHANGED] = true;
658    }
659
660    public void expectLocationChanged(String newLocation) {
661        expects[TEST_LOCATION_CHANGED] = true;
662        expectLocation = newLocation;
663    }
664
665    public void expectLocationChanged(String newLocation, boolean permanent) {
666        expects[TEST_LOCATION_CHANGED] = true;
667        expectLocation = newLocation;
668        expectPermanent = permanent ? 1 : 0;
669    }
670
671    public void expectData() {
672        expects[TEST_DATA] = true;
673    }
674
675    public void expectNoData() {
676        notExpecting[TEST_DATA] = true;
677    }
678
679    public void expectData(int len) {
680        expects[TEST_DATA] = true;
681        expectDataLength = len;
682    }
683
684    public void expectData(byte[] data, int len) {
685        expects[TEST_DATA] = true;
686        expectData = new byte[len];
687        expectDataLength = len;
688
689        for (int i = 0; i < len; i++) {
690            expectData[i] = data[i];
691        }
692    }
693
694    public void expectEndData() {
695        expects[TEST_ENDDATA] = true;
696    }
697
698    public void expectNoEndData() {
699            notExpecting[TEST_ENDDATA] = true;
700    }
701
702    public void expectError() {
703        expects[TEST_ERROR] = true;
704    }
705
706    public void expectNoError() {
707        notExpecting[TEST_ERROR] = true;
708    }
709
710    public void expectError(int errorId) {
711        expects[TEST_ERROR] = true;
712        expectErrorId = errorId;
713    }
714
715    public void expectSSLCertificateError() {
716        expects[TEST_SSL_CERTIFICATE_ERROR] = true;
717    }
718
719    public void expectNoSSLCertificateError() {
720            notExpecting[TEST_SSL_CERTIFICATE_ERROR] = true;
721    }
722
723    public void expectSSLCertificateError(int errors) {
724        expects[TEST_SSL_CERTIFICATE_ERROR] = true;
725        expectSslErrors = errors;
726    }
727
728    public void expectSSLCertificateError(SslCertificate certificate) {
729        expects[TEST_SSL_CERTIFICATE_ERROR] = true;
730        expectCertificate = certificate;
731    }
732
733    /**
734     * Test to see if current expectations match recieved information
735     * @return True is all expected results have been matched
736     */
737    public boolean expectPassed() {
738        for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
739            if (expects[i] == true) {
740                return false;
741            }
742        }
743
744        for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
745            if (eventsReceived[i] && notExpecting[i]) {
746                return false;
747            }
748        }
749        return true;
750    }
751
752    /**
753     * Return message indicating expectation failures
754     */
755    public String getFailureMessage() {
756        return expectDetails.toString();
757    }
758
759    /**
760     * Reset all expectation values for re-use
761     */
762    public void resetExpects() {
763        expectMajor = -1;
764        expectMinor = -1;
765        expectCode = -1;
766        expectLocation = null;
767        expectPermanent = -1;
768        expectErrorId = -1;
769        expectSslErrors = -1;
770        expectCertificate = null;
771        expectDetails.setLength(0);
772        expectHeaders.clear();
773
774        for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
775            expects[i] = false;
776            notExpecting[i] = false;
777            eventsReceived[i] = false;
778        }
779
780        for (int i = 0; i < expectDataLength; i++) {
781            expectData[i] = 0;
782        }
783
784        expectDataLength = -1;
785    }
786
787    /**
788     * Attach the RequestHandle to this handler
789     * @param requestHandle The RequestHandle
790     */
791    public void attachRequestHandle(RequestHandle requestHandle) {
792        if (Config.LOGV) {
793            Log.v(LOGTAG, "TestEventHandler.attachRequestHandle(): " +
794                    "requestHandle: " +  requestHandle);
795        }
796        mRequestHandle = requestHandle;
797    }
798
799    /**
800     * Detach the RequestHandle
801     */
802    public void detachRequestHandle() {
803        if (Config.LOGV) {
804            Log.v(LOGTAG, "TestEventHandler.detachRequestHandle(): " +
805                    "requestHandle: " + mRequestHandle);
806        }
807        mRequestHandle = null;
808    }
809
810    protected final static String LOGTAG = "http";
811}
812