stream: the proxy-environment test is an integration target, so the lib carries no environment read
Moves the_stream_agent_ignores_the_proxy_environment to crates/mind-body/tests/stream_proxy.rs, as control.rs carries its env-touching tests. It asserts through the public surface: with a proxy in the child's environment the stream's agent reaches its endpoint directly and follows no redirect, and a plain ureq agent in the same environment takes the proxy. No behaviour change. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
98a3741d4b
commit
77ce0465ea
2 changed files with 87 additions and 21 deletions
|
|
@ -840,24 +840,3 @@ fn identical_memory_lines_are_each_cited_once() {
|
|||
let cited = seed.reads.iter().filter(|read| read.kind == PipelineKind::Memory).count();
|
||||
assert!(shown >= 1 && cited == shown, "{shown} lines shown, {cited} cited");
|
||||
}
|
||||
|
||||
/// The environment's proxy settings are read when an agent is built, so the check runs in a child process that has them.
|
||||
#[test]
|
||||
fn the_stream_agent_ignores_the_proxy_environment() {
|
||||
if std::env::var("STREAM_PROXY_CHILD").is_ok() {
|
||||
let plain: ureq::Agent = ureq::Agent::config_builder().build().into();
|
||||
assert!(plain.config().proxy().is_some(), "the child's environment names a proxy");
|
||||
let stream = OllamaStream::open("http://127.0.0.1:9", "p", "b").unwrap();
|
||||
assert!(stream.agent.config().proxy().is_none(), "the stream's agent took the environment's proxy");
|
||||
assert_eq!(stream.agent.config().max_redirects(), 0);
|
||||
return;
|
||||
}
|
||||
let child = std::process::Command::new(std::env::current_exe().unwrap())
|
||||
.args(["--exact", "stream::tests::the_stream_agent_ignores_the_proxy_environment", "--nocapture"])
|
||||
.env("STREAM_PROXY_CHILD", "1")
|
||||
.env("ALL_PROXY", "http://192.0.2.1:3128")
|
||||
.env("HTTP_PROXY", "http://192.0.2.1:3128")
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(child.status.success(), "{}{}", String::from_utf8_lossy(&child.stdout), String::from_utf8_lossy(&child.stderr));
|
||||
}
|
||||
|
|
|
|||
87
crates/mind-body/tests/stream_proxy.rs
Normal file
87
crates/mind-body/tests/stream_proxy.rs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
//! The stream's HTTP agent ignores the process environment's proxy settings and follows no redirects.
|
||||
//!
|
||||
//! An agent reads `ALL_PROXY` and friends when it is built, so the check runs in a child process
|
||||
//! that has them. The parent hosts three loopback listeners: the model host (it answers every
|
||||
//! request with a redirect), the proxy the child's environment names, and the redirect's target.
|
||||
|
||||
// The suite re-executes its own test binary as the child and hands it the endpoint through the
|
||||
// environment. That is test plumbing in its own crate: it reaches no library code, which
|
||||
// `#![forbid]`s these readers.
|
||||
#![allow(clippy::disallowed_methods, reason = "the test re-executes itself and hands the child its role through the environment")]
|
||||
|
||||
use std::io::{Read, Write};
|
||||
use std::net::TcpListener;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
use mind_body::stream::{OllamaStream, StreamModel};
|
||||
|
||||
/// Counts the connections a loopback listener accepts, answering each with `reply` when given.
|
||||
fn listen(reply: Option<String>) -> (String, Arc<AtomicUsize>) {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let address = listener.local_addr().unwrap();
|
||||
let hits = Arc::new(AtomicUsize::new(0));
|
||||
let counted = Arc::clone(&hits);
|
||||
std::thread::spawn(move || {
|
||||
for connection in listener.incoming().flatten() {
|
||||
let mut connection = connection;
|
||||
counted.fetch_add(1, Ordering::SeqCst);
|
||||
if let Some(reply) = &reply {
|
||||
let mut seen = [0u8; 4096];
|
||||
let _ = connection.read(&mut seen);
|
||||
let _ = connection.write_all(reply.as_bytes());
|
||||
}
|
||||
}
|
||||
});
|
||||
(format!("http://{address}"), hits)
|
||||
}
|
||||
|
||||
fn settled(hits: &AtomicUsize, wanted: bool) -> bool {
|
||||
for _ in 0..40 {
|
||||
if (hits.load(Ordering::SeqCst) > 0) == wanted {
|
||||
return true;
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn child(role: &str, endpoint: &str, proxy: &str) {
|
||||
let status = std::process::Command::new(std::env::current_exe().unwrap())
|
||||
.args(["--exact", "the_stream_agent_ignores_the_proxy_environment", "--nocapture"])
|
||||
.env("STREAM_PROXY_CHILD", role)
|
||||
.env("STREAM_PROXY_ENDPOINT", endpoint)
|
||||
.env("ALL_PROXY", proxy)
|
||||
.env("HTTP_PROXY", proxy)
|
||||
.status()
|
||||
.unwrap();
|
||||
assert!(status.success(), "the {role} child failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_stream_agent_ignores_the_proxy_environment() {
|
||||
if let Ok(role) = std::env::var("STREAM_PROXY_CHILD") {
|
||||
let endpoint = std::env::var("STREAM_PROXY_ENDPOINT").unwrap();
|
||||
if role == "plain" {
|
||||
let plain: ureq::Agent = ureq::Agent::config_builder().timeout_global(Some(Duration::from_secs(2))).build().into();
|
||||
let _ = plain.get(&endpoint).call();
|
||||
} else {
|
||||
let _ = OllamaStream::open(&endpoint, "p", "b").unwrap().project("hello");
|
||||
}
|
||||
return;
|
||||
}
|
||||
let (target, target_hits) = listen(None);
|
||||
let (proxy, proxy_hits) = listen(None);
|
||||
let redirect = format!("HTTP/1.1 302 Found\r\nLocation: {target}/elsewhere\r\nContent-Length: 0\r\nConnection: close\r\n\r\n");
|
||||
let (endpoint, endpoint_hits) = listen(Some(redirect));
|
||||
|
||||
child("stream", &endpoint, &proxy);
|
||||
assert!(settled(&endpoint_hits, true), "the stream never reached its own endpoint");
|
||||
std::thread::sleep(Duration::from_millis(300));
|
||||
assert_eq!(proxy_hits.load(Ordering::SeqCst), 0, "the stream's agent took the environment's proxy");
|
||||
assert_eq!(target_hits.load(Ordering::SeqCst), 0, "the stream's agent followed a redirect");
|
||||
|
||||
child("plain", &endpoint, &proxy);
|
||||
assert!(settled(&proxy_hits, true), "the child's environment names a proxy");
|
||||
}
|
||||
Loading…
Reference in a new issue