• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
17 package com.android.libraries.entitlement.testing;
18 
19 import static java.nio.charset.StandardCharsets.UTF_8;
20 
21 import com.google.auto.value.AutoValue;
22 import com.google.common.collect.ImmutableList;
23 import com.google.common.collect.ImmutableMap;
24 
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.net.URL;
31 import java.net.URLConnection;
32 import java.net.URLStreamHandler;
33 import java.net.URLStreamHandlerFactory;
34 import java.security.cert.Certificate;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.Map;
38 
39 import javax.annotation.Nullable;
40 import javax.net.ssl.HttpsURLConnection;
41 
42 /**
43  * A {@link URLStreamHandlerFactory} to return faked {@link URLConnection}, as {@link URL} is a
44  * final class and {@link URL#openConnection} cannot be mocked using mockito.
45  */
46 public class FakeURLStreamHandler extends URLStreamHandler implements URLStreamHandlerFactory {
47     private Map<String, FakeResponse> mResponses = ImmutableMap.of();
48     private List<FakeHttpsURLConnection> mConnections = new ArrayList<>();
49 
50     private static final String ACCESS_TOKEN = "8dGozfI6%2FEaSsE7LaTfJKwdy";
51     private static final String LOCATION = "Location";
52     private static final String CONTENT_TYPE = "Content-Type";
53     private static final String RETRY_AFTER = "Retry-After";
54 
55     @Override
openConnection(URL u)56     public URLConnection openConnection(URL u) {
57         FakeHttpsURLConnection connection =
58                 new FakeHttpsURLConnection(u, mResponses.get(u.toString()));
59         mConnections.add(connection);
60         return connection;
61     }
62 
63     @Override
createURLStreamHandler(String protocol)64     public URLStreamHandler createURLStreamHandler(String protocol) {
65         return this;
66     }
67 
68     /**
69      * Prepares canned responses. Must be called before using this handler to open any {@link
70      * URLConnection}.
71      */
stubResponse(Map<String, FakeResponse> response)72     public FakeURLStreamHandler stubResponse(Map<String, FakeResponse> response) {
73         mResponses = response;
74         mConnections = new ArrayList<>();
75         return this;
76     }
77 
78     /** Returns {@link URLConnection}s opened by this handler since last {@link #stubResponse}. */
getConnections()79     public ImmutableList<FakeHttpsURLConnection> getConnections() {
80         return ImmutableList.copyOf(mConnections);
81     }
82 
83     /** Faked {@link HttpsURLConnection} to avoid making any network connection. */
84     public static class FakeHttpsURLConnection extends HttpsURLConnection {
85         private final FakeResponse mResponse;
86         private final ByteArrayOutputStream mOutputStream = new ByteArrayOutputStream();
87 
FakeHttpsURLConnection(URL url, FakeResponse response)88         public FakeHttpsURLConnection(URL url, FakeResponse response) {
89             super(url);
90             mResponse = response;
91         }
92 
93         @Override
getInputStream()94         public InputStream getInputStream() throws IOException {
95             if (mResponse.hasException() && mResponse.responseBody().length == 0) {
96                 throw new IOException("stub exception");
97             }
98             return new ByteArrayInputStream(mResponse.responseBody());
99         }
100 
101         @Override
getOutputStream()102         public OutputStream getOutputStream() {
103             return mOutputStream;
104         }
105 
106         @Override
getErrorStream()107         public InputStream getErrorStream() {
108             return new ByteArrayInputStream("stub error".getBytes(UTF_8));
109         }
110 
getBytesWrittenToOutputStream()111         public byte[] getBytesWrittenToOutputStream() {
112             return mOutputStream.toByteArray();
113         }
114 
115         @Override
getResponseCode()116         public int getResponseCode() throws IOException {
117             if (mResponse.hasException() && mResponse.responseCode() == 0) {
118                 throw new IOException("stub exception");
119             }
120             return mResponse.responseCode();
121         }
122 
123         @Override
getHeaderFields()124         public Map<String, List<String>> getHeaderFields() {
125             List<String> locationList = ImmutableList.of("access_token=" + ACCESS_TOKEN);
126             return ImmutableMap.of("Location", locationList);
127         }
128 
129         @Override
getHeaderField(String name)130         public String getHeaderField(String name) {
131             switch (name) {
132                 case LOCATION:
133                     return "Location: " + mResponse.responseLocation();
134                 case CONTENT_TYPE:
135                     return mResponse.contentType();
136                 case RETRY_AFTER:
137                     return mResponse.retryAfter();
138                 default:
139                     return null;
140             }
141         }
142 
143         @Override
connect()144         public void connect() {
145         }
146 
147         @Override
disconnect()148         public void disconnect() {
149         }
150 
151         @Override
usingProxy()152         public boolean usingProxy() {
153             return false;
154         }
155 
156         @Override
getCipherSuite()157         public String getCipherSuite() {
158             return null;
159         }
160 
161         @Override
getLocalCertificates()162         public Certificate[] getLocalCertificates() {
163             return null;
164         }
165 
166         @Override
getServerCertificates()167         public Certificate[] getServerCertificates() {
168             return null;
169         }
170     }
171 
172     @AutoValue
173     public abstract static class FakeResponse {
responseCode()174         public abstract int responseCode();
175 
176         @Nullable
responseLocation()177         public abstract String responseLocation();
178 
179         @SuppressWarnings("mutable") // For test only
responseBody()180         public abstract byte[] responseBody();
181 
contentType()182         public abstract String contentType();
183 
retryAfter()184         public abstract String retryAfter();
185 
hasException()186         abstract boolean hasException();
187 
builder()188         public static Builder builder() {
189             return new AutoValue_FakeURLStreamHandler_FakeResponse.Builder()
190                     .setResponseBody(new byte[]{})
191                     .setContentType("")
192                     .setResponseCode(0)
193                     .setResponseLocation("")
194                     .setRetryAfter("")
195                     .setHasException(false);
196         }
197 
198         @AutoValue.Builder
199         public abstract static class Builder {
setResponseCode(int value)200             public abstract Builder setResponseCode(int value);
201 
setResponseLocation(String value)202             public abstract Builder setResponseLocation(String value);
203 
setResponseBody(byte[] value)204             public abstract Builder setResponseBody(byte[] value);
205 
setContentType(String contentType)206             public abstract Builder setContentType(String contentType);
207 
setRetryAfter(String retryAfter)208             public abstract Builder setRetryAfter(String retryAfter);
209 
setHasException(boolean hasException)210             public abstract Builder setHasException(boolean hasException);
211 
build()212             public abstract FakeResponse build();
213         }
214     }
215 }
216