RecordingReceiver.java revision 3c938a3f6b61ce5e2dba0d039b03fe73b89fd26c
1/*
2 * Copyright (C) 2013 Square, Inc.
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 */
16package com.squareup.okhttp;
17
18import java.io.ByteArrayOutputStream;
19import java.io.IOException;
20import java.net.URL;
21import java.util.ArrayList;
22import java.util.LinkedHashMap;
23import java.util.List;
24import java.util.Map;
25import java.util.concurrent.TimeUnit;
26
27/**
28 * Records received HTTP responses so they can be later retrieved by tests.
29 */
30public class RecordingReceiver implements Response.Receiver {
31  public static final long TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(10);
32
33  private final Map<Response, ByteArrayOutputStream> inFlightResponses
34      = new LinkedHashMap<Response, ByteArrayOutputStream>();
35  private final List<RecordedResponse> responses = new ArrayList<RecordedResponse>();
36
37  @Override public synchronized void onFailure(Failure failure) {
38    responses.add(new RecordedResponse(failure.request(), null, null, failure));
39    notifyAll();
40  }
41
42  @Override public synchronized boolean onResponse(Response response) throws IOException {
43    ByteArrayOutputStream out = inFlightResponses.get(response);
44    if (out == null) {
45      out = new ByteArrayOutputStream();
46      inFlightResponses.put(response, out);
47    }
48
49    byte[] buffer = new byte[1024];
50    Response.Body body = response.body();
51
52    while (body.ready()) {
53      int c = body.byteStream().read(buffer);
54
55      if (c == -1) {
56        inFlightResponses.remove(response);
57        responses.add(new RecordedResponse(
58            response.request(), response, out.toString("UTF-8"), null));
59        notifyAll();
60        return true;
61      }
62
63      out.write(buffer, 0, c);
64    }
65
66    return false;
67  }
68
69  /**
70   * Returns the recorded response triggered by {@code request}. Throws if the
71   * response isn't enqueued before the timeout.
72   */
73  public synchronized RecordedResponse await(URL url) throws Exception {
74    long timeoutMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) + TIMEOUT_MILLIS;
75    while (true) {
76      for (RecordedResponse recordedResponse : responses) {
77        if (recordedResponse.request.url().equals(url)) {
78          return recordedResponse;
79        }
80      }
81
82      long nowMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
83      if (nowMillis >= timeoutMillis) break;
84      wait(timeoutMillis - nowMillis);
85    }
86
87    throw new AssertionError("Timed out waiting for response to " + url);
88  }
89
90  public synchronized void assertNoResponse(URL url) throws Exception {
91    for (RecordedResponse recordedResponse : responses) {
92      if (recordedResponse.request.url().equals(url)) {
93        throw new AssertionError("Expected no response for " + url);
94      }
95    }
96  }
97}
98