use super::*; use std::{ io::{BufRead, BufReader, Read, Write}, net::TcpStream, process::{Child, Command, Stdio}, time::{Duration, Instant}, }; struct Server(Child); impl Drop for Server { fn drop(&mut self) { let _ = self.0.kill(); let _ = self.0.wait(); } } #[test] fn native_stream_and_sse_deliver_before_handler_completes() { let directory = Directory::new(); let project = Project::load(&fixture().with_file_name("live-http.dever")).unwrap(); let program = project.check().unwrap(); let binary = build::build( &program, &project.sources, "serve", &directory.0.join("live"), ) .unwrap(); let mut server = Server( Command::new(binary) .current_dir(&directory.0) .stdout(Stdio::piped()) .stderr(Stdio::inherit()) .spawn() .unwrap(), ); let mut stdout = BufReader::new(server.0.stdout.take().unwrap()); let mut line = String::new(); stdout.read_line(&mut line).unwrap(); let port = line.trim().parse::().unwrap(); for path in ["/stream", "/sse"] { let mut stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); stream .set_read_timeout(Some(Duration::from_secs(3))) .unwrap(); write!( stream, "GET {path} HTTP/1.1\r\nHost: fixture.test\r\nConnection: close\r\n\r\n" ) .unwrap(); let mut stream = BufReader::new(stream); line.clear(); stream.read_line(&mut line).unwrap(); assert!(line.starts_with("HTTP/1.1 200"), "{line}"); loop { line.clear(); assert!(stream.read_line(&mut line).unwrap() > 0); if line == "\r\n" { break; } } let first = chunk(&mut stream); let received = Instant::now(); if path == "/stream" { assert_eq!(first, b"first"); assert_eq!(chunk(&mut stream), b"last"); assert!(received.elapsed() >= Duration::from_millis(100)); assert!(chunk(&mut stream).is_empty()); } else { assert_eq!( first, "event: change\nid: \nretry: 10\ndata: 一\ndata: 二\n\n".as_bytes() ); let mut count = 0; loop { let data = chunk(&mut stream); if data.is_empty() { break; } assert_eq!(data, b":\n\n"); count += 1; } assert!(count >= 2); } } } fn chunk(stream: &mut BufReader) -> Vec { let mut line = String::new(); assert!(stream.read_line(&mut line).unwrap() > 0); let size = usize::from_str_radix(line.trim(), 16).unwrap(); let mut bytes = vec![0; size]; stream.read_exact(&mut bytes).unwrap(); let mut ending = [0; 2]; stream.read_exact(&mut ending).unwrap(); assert_eq!(ending, *b"\r\n"); bytes }