lava_api_mock/
lava_mock.rs1use crate::junit_endpoint;
2use crate::state::{SharedState, State};
3use crate::{Alias, Device, DeviceType, Job, Tag, TestCase, TestSuite, Worker};
4
5use boulder::Buildable;
6use clone_replace::MutateGuard;
7use django_query::mock::{nested_endpoint_matches, NestedEndpointParams};
8use std::sync::Arc;
9
10#[derive(Buildable, Clone, Default)]
22pub struct PaginationLimits {
23 aliases: Option<usize>,
24 test_cases: Option<usize>,
25 test_suites: Option<usize>,
26 jobs: Option<usize>,
27 device_types: Option<usize>,
28 devices: Option<usize>,
29 tags: Option<usize>,
30 workers: Option<usize>,
31}
32
33impl PaginationLimits {
34 pub fn new() -> Self {
39 Default::default()
40 }
41}
42
43pub struct LavaMock {
68 server: wiremock::MockServer,
69 state: SharedState,
70}
71
72impl LavaMock {
73 pub async fn new(p: SharedState, limits: PaginationLimits) -> LavaMock {
80 let s = wiremock::MockServer::start().await;
81
82 wiremock::Mock::given(wiremock::matchers::method("GET"))
83 .and(wiremock::matchers::path("/api/v0.2/aliases/"))
84 .respond_with(p.endpoint::<Alias<State>>(Some(&s.uri()), limits.aliases))
85 .mount(&s)
86 .await;
87
88 wiremock::Mock::given(wiremock::matchers::method("GET"))
89 .and(nested_endpoint_matches("/api/v0.2", "jobs", "tests"))
90 .respond_with(p.nested_endpoint::<TestCase<State>>(
91 NestedEndpointParams {
92 root: "/api/v0.2",
93 parent: "jobs",
94 child: "tests",
95 parent_query: "suite__job__id",
96 base_uri: Some(&s.uri()),
97 },
98 limits.test_cases,
99 ))
100 .mount(&s)
101 .await;
102
103 wiremock::Mock::given(wiremock::matchers::method("GET"))
104 .and(nested_endpoint_matches("/api/v0.2", "jobs", "suites"))
105 .respond_with(p.nested_endpoint::<TestSuite<State>>(
106 NestedEndpointParams {
107 root: "/api/v0.2",
108 parent: "jobs",
109 child: "suites",
110 parent_query: "suite__job__id",
111 base_uri: Some(&s.uri()),
112 },
113 limits.test_suites,
114 ))
115 .mount(&s)
116 .await;
117
118 wiremock::Mock::given(wiremock::matchers::method("GET"))
119 .and(nested_endpoint_matches("/api/v0.2", "jobs", "junit"))
120 .respond_with(junit_endpoint(p.clone()))
121 .mount(&s)
122 .await;
123
124 wiremock::Mock::given(wiremock::matchers::method("GET"))
125 .and(wiremock::matchers::path("/api/v0.2/jobs/"))
126 .respond_with(p.endpoint::<Job<State>>(Some(&s.uri()), limits.jobs))
127 .mount(&s)
128 .await;
129
130 wiremock::Mock::given(wiremock::matchers::method("GET"))
131 .and(wiremock::matchers::path("/api/v0.2/devicetypes/"))
132 .respond_with(p.endpoint::<DeviceType<State>>(Some(&s.uri()), limits.device_types))
133 .mount(&s)
134 .await;
135
136 wiremock::Mock::given(wiremock::matchers::method("GET"))
137 .and(wiremock::matchers::path("/api/v0.2/devices/"))
138 .respond_with(p.endpoint::<Device<State>>(Some(&s.uri()), limits.devices))
139 .mount(&s)
140 .await;
141
142 wiremock::Mock::given(wiremock::matchers::method("GET"))
143 .and(wiremock::matchers::path("/api/v0.2/tags/"))
144 .respond_with(p.endpoint::<Tag<State>>(Some(&s.uri()), limits.tags))
145 .mount(&s)
146 .await;
147
148 wiremock::Mock::given(wiremock::matchers::method("GET"))
149 .and(wiremock::matchers::path("/api/v0.2/workers/"))
150 .respond_with(p.endpoint::<Worker<State>>(Some(&s.uri()), limits.workers))
151 .mount(&s)
152 .await;
153
154 LavaMock {
155 server: s,
156 state: p,
157 }
158 }
159
160 pub async fn start() -> Self {
167 Self::new(Default::default(), Default::default()).await
168 }
169
170 pub fn uri(&self) -> String {
175 self.server.uri()
176 }
177
178 pub fn state(&self) -> Arc<State> {
185 self.state.access()
186 }
187
188 pub fn state_mut(&mut self) -> MutateGuard<State> {
199 self.state.mutate()
200 }
201}
202
203#[cfg(test)]
204mod test {
205 use super::*;
206
207 use crate::{devicetypes::DeviceType, Device, Job, JobState};
208
209 use anyhow::Result;
210 use boulder::{
211 BuildableWithPersianRug, BuilderWithPersianRug, GeneratableWithPersianRug,
212 TryRepeatFromPersianRug,
213 };
214 use boulder::{GeneratorToGeneratorWithPersianRugWrapper, GeneratorWithPersianRugMutIterator};
215 use chrono::Utc;
216 use persian_rug::Proxy;
217 use rand::{Rng, SeedableRng};
218 use serde_json::Value;
219
220 async fn make_request<T, U>(server_uri: T, endpoint: U) -> Result<Value>
221 where
222 T: AsRef<str>,
223 U: AsRef<str>,
224 {
225 let url = format!("{}/api/v0.2/{}", server_uri.as_ref(), endpoint.as_ref());
226 Ok(reqwest::get(&url).await?.json().await?)
227 }
228
229 #[tokio::test]
230 async fn test() {
231 let mut s = SharedState::new();
232
233 let mut rng = rand::rngs::StdRng::seed_from_u64(0xdeadbeef);
234 let device_types = ["device-type-1", "device-type-2"]
235 .into_iter()
236 .map(|name| {
237 Proxy::<DeviceType<State>>::builder()
238 .name(name)
239 .build(s.mutate())
240 .0
241 })
242 .collect::<Vec<_>>();
243
244 let types = device_types.clone();
245 let mut devices = Proxy::<Device<State>>::generator().device_type(
246 GeneratorToGeneratorWithPersianRugWrapper::new(move || {
247 types[rng.gen_range(0..types.len())]
248 }),
249 );
250
251 let _ = GeneratorWithPersianRugMutIterator::new(&mut devices, s.mutate())
252 .take(90)
253 .collect::<Vec<_>>();
254
255 let mut rng = rand::rngs::StdRng::seed_from_u64(0xdeadbeef);
256
257 let types = device_types.clone();
258 let mut jobs = Proxy::<Job<State>>::generator()
259 .actual_device(TryRepeatFromPersianRug::new())
260 .state(GeneratorToGeneratorWithPersianRugWrapper::new(|| {
261 JobState::Submitted
262 }))
263 .submit_time(GeneratorToGeneratorWithPersianRugWrapper::new(|| {
264 Some(Utc::now())
265 }))
266 .requested_device_type(GeneratorToGeneratorWithPersianRugWrapper::new(move || {
267 Some(types[rng.gen_range(0..types.len())])
268 }));
269
270 let _ = GeneratorWithPersianRugMutIterator::new(&mut jobs, s.mutate())
271 .take(500)
272 .collect::<Vec<_>>();
273
274 let mock = LavaMock::new(s, Default::default()).await;
275
276 let devices = make_request(mock.uri(), "devices/")
277 .await
278 .expect("failed to query devices");
279
280 assert_eq!(devices["results"].as_array().unwrap().len(), 90);
281
282 let jobs = make_request(mock.uri(), "jobs/")
283 .await
284 .expect("failed to query jobs");
285
286 assert_eq!(jobs["results"].as_array().unwrap().len(), 500);
287 }
288}