Skip to content

Commit 262c780

Browse files
authored
Use auto-shutdown-in-seconds on test-proxy (#1975)
Have to check version to make sure parameter is valid. Depends on Azure/azure-sdk-tools#9584.
1 parent 8d23f00 commit 262c780

File tree

3 files changed

+179
-4
lines changed

3 files changed

+179
-4
lines changed

sdk/core/azure_core_test/examples/test_proxy.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ struct Args {
5050
#[arg(long)]
5151
insecure: bool,
5252

53+
/// Number of seconds to automatically shut down when no activity.
54+
#[arg(long, default_value_t = 300)]
55+
pub auto_shutdown_in_seconds: u32,
56+
5357
/// Enable verbose logging.
5458
#[arg(short, long)]
5559
verbose: bool,
@@ -70,6 +74,7 @@ impl From<Args> for azure_core_test::proxy::ProxyOptions {
7074
fn from(args: Args) -> Self {
7175
Self {
7276
insecure: args.insecure,
77+
auto_shutdown_in_seconds: args.auto_shutdown_in_seconds,
7378
}
7479
}
7580
}

sdk/core/azure_core_test/src/proxy.rs

Lines changed: 168 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
66
use azure_core::{error::ErrorKind, Result, Url};
77
use std::{
8-
env, io,
8+
env, fmt, io,
99
path::Path,
1010
process::{ExitStatus, Stdio},
11+
str::FromStr,
1112
sync::Arc,
1213
time::Duration,
1314
};
@@ -23,6 +24,11 @@ const KESTREL_CERT_PASSWORD_ENV: &str = "ASPNETCORE_Kestrel__Certificates__Defau
2324
const KESTREL_CERT_PASSWORD: &str = "password";
2425
const PROXY_MANUAL_START: &str = "PROXY_MANUAL_START";
2526
const SYSTEM_TEAMPROJECTID: &str = "SYSTEM_TEAMPROJECTID";
27+
const MIN_VERSION: Version = Version {
28+
major: 20241213,
29+
minor: 1,
30+
metadata: None,
31+
};
2632

2733
pub async fn start(
2834
test_data_dir: impl AsRef<Path>,
@@ -91,10 +97,27 @@ async fn wait_till_listening(stdout: &mut Option<ChildStdout>) -> Result<Url> {
9197
// Wait for the process to respond to requests and check output until pattern: "Now listening on: http://0.0.0.0:60583" (random port).
9298
let mut reader = BufReader::new(stdout).lines();
9399
while let Some(line) = reader.next_line().await? {
94-
const PATTERN: &str = "Now listening on: ";
100+
const RUNNING_PATTERN: &str = "Running proxy version is Azure.Sdk.Tools.TestProxy ";
101+
const LISTENING_PATTERN: &str = "Now listening on: ";
102+
103+
if let Some(idx) = line.find(RUNNING_PATTERN) {
104+
let idx = idx + RUNNING_PATTERN.len();
105+
let version: Version = line[idx..].parse()?;
106+
tracing::event!(target: crate::SPAN_TARGET, Level::INFO, "starting test-proxy version {version}");
107+
108+
// Need to check version since `test-proxy start` does not fail with unknown parameters.
109+
if version < MIN_VERSION {
110+
return Err(azure_core::Error::message(
111+
ErrorKind::Io,
112+
format!("test-proxy older than required version {MIN_VERSION}"),
113+
));
114+
}
115+
116+
continue;
117+
}
95118

96-
if let Some(idx) = line.find(PATTERN) {
97-
let idx = idx + PATTERN.len();
119+
if let Some(idx) = line.find(LISTENING_PATTERN) {
120+
let idx = idx + LISTENING_PATTERN.len();
98121
let url = line[idx..].parse()?;
99122
tracing::event!(target: crate::SPAN_TARGET, Level::INFO, "listening on {url}");
100123

@@ -166,13 +189,21 @@ impl Drop for Proxy {
166189
pub struct ProxyOptions {
167190
/// Allow insecure upstream SSL certs.
168191
pub insecure: bool,
192+
193+
/// Number of seconds to automatically shut down when no activity.
194+
pub auto_shutdown_in_seconds: u32,
169195
}
170196

171197
impl ProxyOptions {
172198
fn copy_to(&self, args: &mut Vec<String>) {
173199
if self.insecure {
174200
args.push("--insecure".into());
175201
}
202+
203+
args.extend_from_slice(&[
204+
"--auto-shutdown-in-seconds".into(),
205+
self.auto_shutdown_in_seconds.to_string(),
206+
]);
176207
}
177208
}
178209

@@ -184,3 +215,136 @@ pub struct Session {
184215
#[allow(dead_code)]
185216
pub(crate) span: Span,
186217
}
218+
219+
#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
220+
struct Version {
221+
major: i32,
222+
minor: i32,
223+
metadata: Option<String>,
224+
}
225+
226+
impl fmt::Display for Version {
227+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228+
if let Some(metadata) = &self.metadata {
229+
return write!(f, "{}.{}-{metadata}", self.major, self.minor);
230+
}
231+
write!(f, "{}.{}", self.major, self.minor)
232+
}
233+
}
234+
235+
impl FromStr for Version {
236+
type Err = azure_core::Error;
237+
238+
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
239+
let mut v = Version::default();
240+
241+
// cspell:ignore splitn
242+
let mut cur = s.splitn(2, '.');
243+
if let Some(major) = cur.next() {
244+
v.major = major.parse()?;
245+
} else {
246+
return Err(azure_core::Error::message(
247+
ErrorKind::DataConversion,
248+
"major version required",
249+
));
250+
}
251+
if let Some(minor) = cur.next() {
252+
let mut cur = minor.splitn(2, '-');
253+
if let Some(minor) = cur.next() {
254+
v.minor = minor.parse()?;
255+
}
256+
v.metadata = cur.next().map(String::from);
257+
}
258+
259+
Ok(v)
260+
}
261+
}
262+
263+
#[cfg(test)]
264+
mod tests {
265+
use super::*;
266+
267+
#[test]
268+
fn version_eq() {
269+
let a = Version {
270+
major: 1,
271+
..Default::default()
272+
};
273+
let b = Version {
274+
major: 1,
275+
..Default::default()
276+
};
277+
assert_eq!(a, b);
278+
279+
let a = Version {
280+
major: 1,
281+
minor: 2,
282+
metadata: Some("preview".into()),
283+
};
284+
let b = Version {
285+
major: 1,
286+
minor: 2,
287+
metadata: Some("preview".into()),
288+
};
289+
assert_eq!(a, b);
290+
}
291+
292+
#[test]
293+
fn version_cmp() {
294+
let a = Version {
295+
major: 20240107,
296+
minor: 1,
297+
..Default::default()
298+
};
299+
let b = Version {
300+
major: 20240107,
301+
minor: 2,
302+
..Default::default()
303+
};
304+
let c = Version {
305+
major: 20240109,
306+
minor: 1,
307+
metadata: Some("1".into()),
308+
};
309+
let d = Version {
310+
major: 20240109,
311+
minor: 1,
312+
metadata: Some("2".into()),
313+
};
314+
assert!(a == a);
315+
assert!(a < b);
316+
assert!(b > a);
317+
assert!(b < c);
318+
assert!(c != d);
319+
assert!(c < d);
320+
}
321+
322+
#[test]
323+
fn version_fmt() {
324+
let mut v = Version {
325+
major: 1,
326+
..Default::default()
327+
};
328+
assert_eq!(v.to_string(), "1.0");
329+
330+
v.minor = 2;
331+
v.metadata = Some("preview".into());
332+
assert_eq!(v.to_string(), "1.2-preview");
333+
}
334+
335+
#[test]
336+
fn version_parse() {
337+
let mut v = Version {
338+
major: 1,
339+
..Default::default()
340+
};
341+
assert!(matches!("1".parse::<Version>(), Ok(ver) if ver == v));
342+
assert!(matches!("1.0".parse::<Version>(), Ok(ver) if ver == v));
343+
344+
v.minor = 2;
345+
assert!(matches!("1.2".parse::<Version>(), Ok(ver) if ver == v));
346+
347+
v.metadata = Some("preview".into());
348+
assert!(matches!("1.2-preview".parse::<Version>(), Ok(ver) if ver == v));
349+
}
350+
}

sdk/typespec/src/error/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,12 @@ impl From<std::io::Error> for Error {
247247
}
248248
}
249249

250+
impl From<std::num::ParseIntError> for Error {
251+
fn from(error: std::num::ParseIntError) -> Self {
252+
Self::new(ErrorKind::DataConversion, error)
253+
}
254+
}
255+
250256
impl From<base64::DecodeError> for Error {
251257
fn from(error: base64::DecodeError) -> Self {
252258
Self::new(ErrorKind::DataConversion, error)

0 commit comments

Comments
 (0)