diff --git a/docs/spec/compat-tests.md b/docs/spec/compat-tests.md index 66c7a0f..4276fa9 100644 --- a/docs/spec/compat-tests.md +++ b/docs/spec/compat-tests.md @@ -99,6 +99,16 @@ copy of INBUXA's data any more. The script copies from the source for each test and removes the copy afterwards, so the source stays clean; take it from a stopped server or a snapshot, never from under a running one. +**Why the copy's own listeners are ignored.** A real server listens on 25, +443, 993 and the rest. Nothing in a test run is root, so every one of those +fails to bind and the run died before reading any data, with eight +`Permission denied (os error 13)` errors and nothing about what to do. +Under `NO_INSERT` the harness now drops build errors belonging to listeners +it did not add itself, and keeps every other error, including a bind that +fails on one of its own (`tests/src/utils/server.rs`). The copy is not +edited to achieve this; its listeners are simply not what a compat run +needs. + **Why `compat-` listeners appear in the copy.** The harness needs listeners on its own ports, and the registry keys listeners by name. A real server has its own, and a production listener called `jmap` or `imap` collided diff --git a/tests/src/utils/server.rs b/tests/src/utils/server.rs index c575c6f..c39800e 100644 --- a/tests/src/utils/server.rs +++ b/tests/src/utils/server.rs @@ -83,6 +83,9 @@ pub struct TestServer { pub struct TestServerBuilder { bootstrap: Bootstrap, temp_dir: TempDir, + // inbuxa: the listeners this builder added, so a compat run can tell + // them from the ones that came with a copy of someone else's store. + own_listeners: Vec, http_listener_port: u16, reset: bool, logging_enabled: bool, @@ -126,6 +129,7 @@ impl TestServerBuilder { ) .await, http_listener_port: 8899, + own_listeners: Vec::new(), temp_dir, reset, logging_enabled: false, @@ -212,17 +216,19 @@ impl TestServerBuilder { } else { name.to_string() }; - self.insert_object(NetworkListener { - bind: Map::new(vec![ - SocketAddr::from_str(&format!("0.0.0.0:{port}")).unwrap(), - ]), - name, - protocol, - use_tls: true, - tls_implicit, - ..Default::default() - }) - .await; + let id = self + .insert_object(NetworkListener { + bind: Map::new(vec![ + SocketAddr::from_str(&format!("0.0.0.0:{port}")).unwrap(), + ]), + name, + protocol, + use_tls: true, + tls_implicit, + ..Default::default() + }) + .await; + self.own_listeners.push(id); self } @@ -390,6 +396,24 @@ impl TestServerBuilder { .parse_tcp_acceptors(&mut self.bootstrap, inner.clone()) .await; + // inbuxa: a compat run opens a copy of a real server's store, which + // carries that server's listeners: 25, 443, 993 and the rest. Nothing + // here runs as root, so every one of them fails to bind and the run + // dies before it reads any data. Those are the copy's, not ours, and + // the tests reach the server over the compat- listeners added above, + // so drop their errors and keep every other one — including a bind + // that fails on a listener this builder added. + if std::env::var("NO_INSERT").is_ok() { + let own = &self.own_listeners; + self.bootstrap.errors.retain(|error| match error { + registry::types::error::Error::Build { object_id, .. } => { + object_id.object() != ObjectType::NetworkListener + || own.contains(&object_id.id()) + } + _ => true, + }); + } + // Start services self.bootstrap.assert_no_errors(); if !self.disable_services {