datadog_api_client/datadogV2/api/
api_test_optimization.rs1use crate::datadog;
5use async_stream::try_stream;
6use flate2::{
7 write::{GzEncoder, ZlibEncoder},
8 Compression,
9};
10use futures_core::stream::Stream;
11use log::warn;
12use reqwest::header::{HeaderMap, HeaderValue};
13use serde::{Deserialize, Serialize};
14use std::io::Write;
15
16#[non_exhaustive]
18#[derive(Clone, Default, Debug)]
19pub struct SearchFlakyTestsOptionalParams {
20 pub body: Option<crate::datadogV2::model::FlakyTestsSearchRequest>,
21}
22
23impl SearchFlakyTestsOptionalParams {
24 pub fn body(mut self, value: crate::datadogV2::model::FlakyTestsSearchRequest) -> Self {
25 self.body = Some(value);
26 self
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32#[serde(untagged)]
33pub enum SearchFlakyTestsError {
34 APIErrorResponse(crate::datadogV2::model::APIErrorResponse),
35 UnknownValue(serde_json::Value),
36}
37
38#[derive(Debug, Clone)]
40pub struct TestOptimizationAPI {
41 config: datadog::Configuration,
42 client: reqwest_middleware::ClientWithMiddleware,
43}
44
45impl Default for TestOptimizationAPI {
46 fn default() -> Self {
47 Self::with_config(datadog::Configuration::default())
48 }
49}
50
51impl TestOptimizationAPI {
52 pub fn new() -> Self {
53 Self::default()
54 }
55 pub fn with_config(config: datadog::Configuration) -> Self {
56 let mut reqwest_client_builder = reqwest::Client::builder();
57
58 if let Some(proxy_url) = &config.proxy_url {
59 let proxy = reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL");
60 reqwest_client_builder = reqwest_client_builder.proxy(proxy);
61 }
62
63 let mut middleware_client_builder =
64 reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap());
65
66 if config.enable_retry {
67 struct RetryableStatus;
68 impl reqwest_retry::RetryableStrategy for RetryableStatus {
69 fn handle(
70 &self,
71 res: &Result<reqwest::Response, reqwest_middleware::Error>,
72 ) -> Option<reqwest_retry::Retryable> {
73 match res {
74 Ok(success) => reqwest_retry::default_on_request_success(success),
75 Err(_) => None,
76 }
77 }
78 }
79 let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder()
80 .build_with_max_retries(config.max_retries);
81
82 let retry_middleware =
83 reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy(
84 backoff_policy,
85 RetryableStatus,
86 );
87
88 middleware_client_builder = middleware_client_builder.with(retry_middleware);
89 }
90
91 let client = middleware_client_builder.build();
92
93 Self { config, client }
94 }
95
96 pub fn with_client_and_config(
97 config: datadog::Configuration,
98 client: reqwest_middleware::ClientWithMiddleware,
99 ) -> Self {
100 Self { config, client }
101 }
102
103 pub async fn search_flaky_tests(
105 &self,
106 params: SearchFlakyTestsOptionalParams,
107 ) -> Result<
108 crate::datadogV2::model::FlakyTestsSearchResponse,
109 datadog::Error<SearchFlakyTestsError>,
110 > {
111 match self.search_flaky_tests_with_http_info(params).await {
112 Ok(response_content) => {
113 if let Some(e) = response_content.entity {
114 Ok(e)
115 } else {
116 Err(datadog::Error::Serde(serde::de::Error::custom(
117 "response content was None",
118 )))
119 }
120 }
121 Err(err) => Err(err),
122 }
123 }
124
125 pub fn search_flaky_tests_with_pagination(
126 &self,
127 mut params: SearchFlakyTestsOptionalParams,
128 ) -> impl Stream<
129 Item = Result<crate::datadogV2::model::FlakyTest, datadog::Error<SearchFlakyTestsError>>,
130 > + '_ {
131 try_stream! {
132 let mut page_size: i64 = 10;
133 if params.body.is_none() {
134 params.body = Some(crate::datadogV2::model::FlakyTestsSearchRequest::new());
135 }
136 if params.body.as_ref().unwrap().data.is_none() {
137 params.body.as_mut().unwrap().data = Some(crate::datadogV2::model::FlakyTestsSearchRequestData::new());
138 }
139 if params.body.as_ref().unwrap().data.as_ref().unwrap().attributes.is_none() {
140 params.body.as_mut().unwrap().data.as_mut().unwrap().attributes = Some(crate::datadogV2::model::FlakyTestsSearchRequestAttributes::new());
141 }
142 if params.body.as_ref().unwrap().data.as_ref().unwrap().attributes.as_ref().unwrap().page.is_none() {
143 params.body.as_mut().unwrap().data.as_mut().unwrap().attributes.as_mut().unwrap().page = Some(crate::datadogV2::model::FlakyTestsSearchPageOptions::new());
144 }
145 if params.body.as_ref().unwrap().data.as_ref().unwrap().attributes.as_ref().unwrap().page.as_ref().unwrap().limit.is_none() {
146 params.body.as_mut().unwrap().data.as_mut().unwrap().attributes.as_mut().unwrap().page.as_mut().unwrap().limit = Some(page_size);
147 } else {
148 page_size = params.body.as_ref().unwrap().data.as_ref().unwrap().attributes.as_ref().unwrap().page.as_ref().unwrap().limit.unwrap().clone();
149 }
150 loop {
151 let resp = self.search_flaky_tests(params.clone()).await?;
152 let Some(data) = resp.data else { break };
153
154 let r = data;
155 let count = r.len();
156 for team in r {
157 yield team;
158 }
159
160 if count < page_size as usize {
161 break;
162 }
163 let Some(meta) = resp.meta else { break };
164 let Some(pagination) = meta.pagination else { break };
165 let Some(next_page) = pagination.next_page.unwrap() else { break };
166
167 params.body.as_mut().unwrap().data.as_mut().unwrap().attributes.as_mut().unwrap().page.as_mut().unwrap().cursor = Some(next_page);
168 }
169 }
170 }
171
172 pub async fn search_flaky_tests_with_http_info(
174 &self,
175 params: SearchFlakyTestsOptionalParams,
176 ) -> Result<
177 datadog::ResponseContent<crate::datadogV2::model::FlakyTestsSearchResponse>,
178 datadog::Error<SearchFlakyTestsError>,
179 > {
180 let local_configuration = &self.config;
181 let operation_id = "v2.search_flaky_tests";
182 if local_configuration.is_unstable_operation_enabled(operation_id) {
183 warn!("Using unstable operation {operation_id}");
184 } else {
185 let local_error = datadog::UnstableOperationDisabledError {
186 msg: "Operation 'v2.search_flaky_tests' is not enabled".to_string(),
187 };
188 return Err(datadog::Error::UnstableOperationDisabledError(local_error));
189 }
190
191 let body = params.body;
193
194 let local_client = &self.client;
195
196 let local_uri_str = format!(
197 "{}/api/v2/test/flaky-test-management/tests",
198 local_configuration.get_operation_host(operation_id)
199 );
200 let mut local_req_builder =
201 local_client.request(reqwest::Method::POST, local_uri_str.as_str());
202
203 let mut headers = HeaderMap::new();
205 headers.insert("Content-Type", HeaderValue::from_static("application/json"));
206 headers.insert("Accept", HeaderValue::from_static("application/json"));
207
208 match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
210 Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
211 Err(e) => {
212 log::warn!("Failed to parse user agent header: {e}, falling back to default");
213 headers.insert(
214 reqwest::header::USER_AGENT,
215 HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
216 )
217 }
218 };
219
220 if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
222 headers.insert(
223 "DD-API-KEY",
224 HeaderValue::from_str(local_key.key.as_str())
225 .expect("failed to parse DD-API-KEY header"),
226 );
227 };
228 if let Some(local_key) = local_configuration.auth_keys.get("appKeyAuth") {
229 headers.insert(
230 "DD-APPLICATION-KEY",
231 HeaderValue::from_str(local_key.key.as_str())
232 .expect("failed to parse DD-APPLICATION-KEY header"),
233 );
234 };
235
236 let output = Vec::new();
238 let mut ser = serde_json::Serializer::with_formatter(output, datadog::DDFormatter);
239 if body.serialize(&mut ser).is_ok() {
240 if let Some(content_encoding) = headers.get("Content-Encoding") {
241 match content_encoding.to_str().unwrap_or_default() {
242 "gzip" => {
243 let mut enc = GzEncoder::new(Vec::new(), Compression::default());
244 let _ = enc.write_all(ser.into_inner().as_slice());
245 match enc.finish() {
246 Ok(buf) => {
247 local_req_builder = local_req_builder.body(buf);
248 }
249 Err(e) => return Err(datadog::Error::Io(e)),
250 }
251 }
252 "deflate" => {
253 let mut enc = ZlibEncoder::new(Vec::new(), Compression::default());
254 let _ = enc.write_all(ser.into_inner().as_slice());
255 match enc.finish() {
256 Ok(buf) => {
257 local_req_builder = local_req_builder.body(buf);
258 }
259 Err(e) => return Err(datadog::Error::Io(e)),
260 }
261 }
262 "zstd1" => {
263 let mut enc = zstd::stream::Encoder::new(Vec::new(), 0).unwrap();
264 let _ = enc.write_all(ser.into_inner().as_slice());
265 match enc.finish() {
266 Ok(buf) => {
267 local_req_builder = local_req_builder.body(buf);
268 }
269 Err(e) => return Err(datadog::Error::Io(e)),
270 }
271 }
272 _ => {
273 local_req_builder = local_req_builder.body(ser.into_inner());
274 }
275 }
276 } else {
277 local_req_builder = local_req_builder.body(ser.into_inner());
278 }
279 }
280
281 local_req_builder = local_req_builder.headers(headers);
282 let local_req = local_req_builder.build()?;
283 log::debug!("request content: {:?}", local_req.body());
284 let local_resp = local_client.execute(local_req).await?;
285
286 let local_status = local_resp.status();
287 let local_content = local_resp.text().await?;
288 log::debug!("response content: {}", local_content);
289
290 if !local_status.is_client_error() && !local_status.is_server_error() {
291 match serde_json::from_str::<crate::datadogV2::model::FlakyTestsSearchResponse>(
292 &local_content,
293 ) {
294 Ok(e) => {
295 return Ok(datadog::ResponseContent {
296 status: local_status,
297 content: local_content,
298 entity: Some(e),
299 })
300 }
301 Err(e) => return Err(datadog::Error::Serde(e)),
302 };
303 } else {
304 let local_entity: Option<SearchFlakyTestsError> =
305 serde_json::from_str(&local_content).ok();
306 let local_error = datadog::ResponseContent {
307 status: local_status,
308 content: local_content,
309 entity: local_entity,
310 };
311 Err(datadog::Error::ResponseError(local_error))
312 }
313 }
314}