1 /*
2  * Copyright (C) 2024 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 android.adservices.utils;
18 
19 import com.google.auto.value.AutoValue;
20 import com.google.common.collect.ImmutableMap;
21 
22 import java.util.Map;
23 
24 /**
25  * The Scenario class represents a configuration for a mock HTTP server used in scenario-based
26  * testing. It encapsulates a mapping of requests to corresponding mock responses, along with
27  * options for verification.
28  *
29  * <p>You should ideally not construct this class directly, instead use {@link ScenarioLoader} and
30  * {@link ScenarioDispatcherFactory} to load scenarios from JSON.
31  */
32 public class Scenario {
33 
34     private final ImmutableMap<Request, MockResponse> mScenarioMap;
35 
36     /**
37      * Constructs a new Scenario instance.
38      *
39      * @param scenarioMap An immutable map containing Request-Mock pairs, defining the scenario's
40      *     behavior.
41      */
Scenario(ImmutableMap<Request, MockResponse> scenarioMap)42     Scenario(ImmutableMap<Request, MockResponse> scenarioMap) {
43         this.mScenarioMap = scenarioMap;
44     }
45 
46     /**
47      * Returns the immutable map defining the request-response associations for this scenario.
48      *
49      * @return An ImmutableMap containing the scenario's configuration.
50      */
getScenarioMap()51     public ImmutableMap<Request, MockResponse> getScenarioMap() {
52         return mScenarioMap;
53     }
54 
55     /** Represents a mock HTTP request within a scenario. */
56     @AutoValue
57     public abstract static class Request {
58         /**
59          * Returns the relative path of the HTTP request (e.g., "/api/data")
60          *
61          * @return the relative path as a String
62          */
getRelativePath()63         abstract String getRelativePath();
64 
65         /**
66          * Returns an immutable map of HTTP headers associated with the request.
67          *
68          * @return an ImmutableMap of headers
69          */
getHeaders()70         abstract ImmutableMap<String, String> getHeaders();
71 
72         /**
73          * Returns a new Builder instance for constructing Request objects.
74          *
75          * @return a Request.Builder instance
76          */
newBuilder()77         static Builder newBuilder() {
78             return new AutoValue_Scenario_Request.Builder();
79         }
80 
81         /** Builder class for creating Request instances. */
82         @AutoValue.Builder
83         public abstract static class Builder {
84             /**
85              * Sets the relative path of the request.
86              *
87              * @param path the relative path to set
88              * @return the Builder instance for chaining
89              */
setRelativePath(String path)90             abstract Builder setRelativePath(String path);
91 
92             /**
93              * Sets the HTTP headers for the request.
94              *
95              * @param headers an ImmutableMap containing headers
96              * @return the Builder instance for chaining
97              */
setHeaders(Map<String, String> headers)98             abstract Builder setHeaders(Map<String, String> headers);
99 
100             /**
101              * Builds a new Request instance based on the configured values.
102              *
103              * @return a Request instance
104              */
build()105             abstract Request build();
106         }
107     }
108 
109     /** Represents a mock HTTP response within a scenario. */
110     @AutoValue
111     public abstract static class MockResponse {
112         /**
113          * Returns the default response to be used for matching requests.
114          *
115          * @return a Response object representing the default response
116          */
getDefaultResponse()117         abstract Response getDefaultResponse();
118 
119         /**
120          * Indicates whether a call to this mock should be verified during testing.
121          *
122          * @return true if the call should be verified, false otherwise
123          */
getShouldVerifyCalled()124         abstract boolean getShouldVerifyCalled();
125 
126         /**
127          * Indicates whether a call to this mock should *not* be verified during testing.
128          *
129          * @return true if absence of a call should be verified, false otherwise
130          */
getShouldVerifyNotCalled()131         abstract boolean getShouldVerifyNotCalled();
132 
133         /**
134          * Returns a new Builder instance for constructing Mock objects.
135          *
136          * @return a Mock.Builder instance
137          */
newBuilder()138         static Builder newBuilder() {
139             return new AutoValue_Scenario_MockResponse.Builder();
140         }
141 
142         /** Builder class for creating {@link MockResponse} instances. */
143         @AutoValue.Builder
144         public abstract static class Builder {
145 
146             /**
147              * Sets the default response that the mock should return when a matching request is
148              * received.
149              *
150              * @param response The {@link Response} object representing the default response.
151              * @return This builder instance for method chaining.
152              */
setDefaultResponse(Response response)153             abstract Builder setDefaultResponse(Response response);
154 
155             /**
156              * t Sets a flag indicating whether calls to this mock should be verified during
157              * testing. This typically means ensuring the mock was invoked during the test scenario.
158              *
159              * @param verifyCalled true if calls to this mock should be verified, false otherwise.
160              * @return This builder instance for method chaining.
161              */
setShouldVerifyCalled(boolean verifyCalled)162             abstract Builder setShouldVerifyCalled(boolean verifyCalled);
163 
164             /**
165              * Sets a flag indicating whether the *absence* of calls to this mock should be verified
166              * during testing. This is useful when you want to ensure certain interactions with the
167              * mock HTTP server did *not* occur.
168              *
169              * @param verifyNotCalled true if the lack of calls to the mock should be verified,
170              *     false otherwise.
171              * @return This builder instance for method chaining.
172              */
setShouldVerifyNotCalled(boolean verifyNotCalled)173             abstract Builder setShouldVerifyNotCalled(boolean verifyNotCalled);
174 
175             /**
176              * Builds a new {@link MockResponse} instance using the values configured in this
177              * builder.
178              *
179              * @return A newly constructed Mock object.
180              */
build()181             abstract MockResponse build();
182         }
183     }
184 
185     /**
186      * Represents a mock HTTP response within a scenario. This class encapsulates the response body,
187      * headers, and an optional delay to simulate network latency.
188      */
189     @AutoValue
190     public abstract static class Response {
191 
192         /**
193          * Returns the body content of the HTTP response.
194          *
195          * @return The response body as a String.
196          */
getBody()197         abstract String getBody();
198 
199         /**
200          * Returns an immutable map of HTTP headers associated with the response.
201          *
202          * @return An immutable map of headers.
203          */
getHeaders()204         abstract ImmutableMap<String, String> getHeaders();
205 
206         /**
207          * Returns the delay in seconds to be applied to the response, simulating network latency.
208          *
209          * @return The delay in seconds.
210          */
getDelaySeconds()211         abstract int getDelaySeconds();
212 
213         /**
214          * Returns a new Builder instance for constructing Mock objects.
215          *
216          * @return a Response.Builder instance
217          */
newBuilder()218         static Response.Builder newBuilder() {
219             return new AutoValue_Scenario_Response.Builder();
220         }
221 
222         /**
223          * Builder class for creating {@link Response} instances. Use this class to fluently
224          * configure the response body, headers, and delay for your mock HTTP server scenarios.
225          */
226         @AutoValue.Builder
227         public abstract static class Builder {
228 
229             /**
230              * Sets the response body content.
231              *
232              * @param body The response body as a String.
233              * @return This builder instance for method chaining.
234              */
setBody(String body)235             abstract Builder setBody(String body);
236 
237             /**
238              * Sets the HTTP headers for the response.
239              *
240              * @param headers An immutable map containing headers.
241              * @return This builder instance for method chaining.
242              */
setHeaders(Map<String, String> headers)243             abstract Builder setHeaders(Map<String, String> headers);
244 
245             /**
246              * Sets an artificial delay (in seconds) for the response to simulate network
247              * conditions.
248              *
249              * @param delay The delay in seconds.
250              * @return This builder instance for method chaining.
251              */
setDelaySeconds(int delay)252             abstract Builder setDelaySeconds(int delay);
253 
254             /**
255              * Builds a new {@link Response} instance using the configured values.
256              *
257              * @return A newly constructed Response object.
258              */
build()259             abstract Response build();
260         }
261     }
262 }
263