{"record":{"id":"0319294ea7cedca0","repo":"stamparm/maltrail","slug":"connect","errorCode":null,"errorMessage":"connect","messagePattern":"connect","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sensor/src/stats.rs","lineNumber":337,"sourceCode":"        ] {\n            assert!(text.contains(&format!(\"# HELP {name} \")), \"missing HELP for {name}:\\n{text}\");\n            assert!(text.contains(&format!(\"# TYPE {name} \")), \"missing TYPE for {name}\");\n        }\n        assert!(text.contains(\"maltrail_trails 1505265\"), \"{text}\");\n        assert!(text.contains(\"maltrail_workers 2\"), \"{text}\");\n        assert!(text.contains(\"maltrail_worker_packets_total{worker=\\\"1\\\"}\"), \"{text}\");\n        // Monotonic counters must end in _total so `rate()` works.\n        for line in text.lines().filter(|l| l.starts_with(\"# TYPE \") && l.ends_with(\" counter\")) {\n            let name = line.split_whitespace().nth(2).unwrap();\n            assert!(name.ends_with(\"_total\"), \"counter {name} must end in _total\");\n        }\n    }\n\n    #[test]\n    fn a_scrape_returns_the_metrics_over_http() {\n        let registry = Arc::new(Registry::new(1));\n        let bound = spawn(\"127.0.0.1:0\", registry, std::time::Instant::now()).expect(\"bind\");\n        let mut stream = std::net::TcpStream::connect(bound).expect(\"connect\");\n        stream.write_all(b\"GET /metrics HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n\").unwrap();\n        let mut response = String::new();\n        stream.read_to_string(&mut response).unwrap();\n        assert!(response.starts_with(\"HTTP/1.1 200 OK\"), \"{response}\");\n        assert!(response.contains(\"text/plain; version=0.0.4\"), \"{response}\");\n        assert!(response.contains(\"maltrail_up 1\"), \"{response}\");\n    }\n\n    #[test]\n    fn a_bad_address_is_reported_not_fatal() {\n        let registry = Arc::new(Registry::new(1));\n        assert!(spawn(\"300.300.300.300:1\", registry, std::time::Instant::now()).is_err());\n    }\n}\n","sourceCodeStart":319,"sourceCodeEnd":352,"githubUrl":"https://github.com/stamparm/maltrail/blob/77cfb06d7606506d101bbcec0786c77166c4255e/sensor/src/stats.rs#L319-L352","documentation":"The test connects a TcpStream to the listener returned by spawn() and .expect(\"connect\") panics if the connection cannot be established. Since the address is a just-bound loopback listener, failure indicates the server thread died, the listener was closed, or the connection was refused/timed out in the environment.","triggerScenarios":"TcpStream::connect(bound) in a_scrape_returns_the_metrics_over_http returns Err because the spawned metrics server thread exited or never accepted, the listener was dropped, or loopback connections are blocked.","commonSituations":"Server thread panicking before accept; spawn() returning an address whose listener was immediately dropped; sandboxed CI blocking loopback connect; firewall or seccomp policy refusing local sockets.","solutions":["Check whether the spawned server thread panicked (capture its JoinHandle/panic output) before connecting","Add a readiness wait (poll until the port accepts) instead of connecting immediately after spawn","Verify loopback connections are permitted in the CI/sandbox environment","Surface the io::Error in the panic message for diagnosis"],"exampleFix":"// before\nlet mut stream = std::net::TcpStream::connect(bound).expect(\"connect\");\n// after\nlet mut stream = std::net::TcpStream::connect(bound)\n    .unwrap_or_else(|e| panic!(\"connect to metrics server {bound} failed: {e}\"));","handlingStrategy":"retry","validationCode":"std::net::TcpStream::connect_timeout(&bound, std::time::Duration::from_secs(2)).map(|s| drop(s)).map_err(|e| format!(\"metrics server not accepting: {e}\"))?;","typeGuard":null,"tryCatchPattern":"let mut stream = std::net::TcpStream::connect(bound).unwrap_or_else(|e| panic!(\"connect to {bound}: {e}\"));","preventionTips":["Wait for the spawned server to be ready before connecting","Assert the server thread is alive (JoinHandle::is_finished) before scraping","Allow loopback sockets in sandboxed CI"],"tags":["rust","network","tcp","test","connection"],"backgroundTag":"connection-refused","analyzedSha":"77cfb06d7606506d101bbcec0786c77166c4255e","analyzedAt":"2026-09-13T03:50:16.010Z","contentChangedAt":"2026-09-13T03:50:16.010Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}