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.net.http.*;
25
26/**
27 * Implements EventHandler and provides test functionality to validate
28 * responses to requests from the test server
29 */
30public 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