122 lines
4.5 KiB
Rust
122 lines
4.5 KiB
Rust
use citygen_server::{
|
|
gateway::{router, App, Config},
|
|
generation::{cache_id, Request},
|
|
protocol::{CityJob, CreateCity},
|
|
};
|
|
use prost::Message;
|
|
use std::time::Duration;
|
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
|
|
async fn request(
|
|
address: std::net::SocketAddr,
|
|
method: &str,
|
|
path: &str,
|
|
body: &[u8],
|
|
) -> (u16, Vec<u8>) {
|
|
let mut stream = tokio::net::TcpStream::connect(address).await.unwrap();
|
|
stream.write_all(format!("{method} {path} HTTP/1.1\r\nHost: localhost\r\nContent-Type: application/x-protobuf\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",body.len()).as_bytes()).await.unwrap();
|
|
stream.write_all(body).await.unwrap();
|
|
let mut bytes = vec![];
|
|
stream.read_to_end(&mut bytes).await.unwrap();
|
|
let split = bytes.windows(4).position(|b| b == b"\r\n\r\n").unwrap();
|
|
let status = std::str::from_utf8(&bytes[..split])
|
|
.unwrap()
|
|
.split_whitespace()
|
|
.nth(1)
|
|
.unwrap()
|
|
.parse()
|
|
.unwrap();
|
|
(status, bytes[split + 4..].to_vec())
|
|
}
|
|
#[tokio::test]
|
|
async fn isolated_typescript_worker_exports_city_and_opens_room_without_network() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let fixture = dir.path().join("osm.json");
|
|
std::fs::write(&fixture,r#"{"elements":[{"type":"way","id":1,"tags":{"highway":"residential"},"geometry":[{"lat":47.001,"lon":9.0},{"lat":47.001,"lon":9.004}]},{"type":"way","id":2,"tags":{"building":"house","building:levels":"1"},"geometry":[{"lat":47.0011,"lon":9.001},{"lat":47.0011,"lon":9.0012},{"lat":47.0013,"lon":9.0012},{"lat":47.0013,"lon":9.001},{"lat":47.0011,"lon":9.001}]},{"type":"way","id":3,"tags":{"building":"industrial","building:levels":"1"},"geometry":[{"lat":47.0006,"lon":9.002},{"lat":47.0006,"lon":9.0023},{"lat":47.0009,"lon":9.0023},{"lat":47.0009,"lon":9.002},{"lat":47.0006,"lon":9.002}]}]}"#).unwrap();
|
|
let app = App::new(Config {
|
|
cities: dir.path().join("cities"),
|
|
saves: dir.path().join("rooms"),
|
|
osm_fixture: Some(fixture),
|
|
project_root: std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
|
.parent()
|
|
.unwrap()
|
|
.to_owned(),
|
|
..Default::default()
|
|
})
|
|
.unwrap();
|
|
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
let address = listener.local_addr().unwrap();
|
|
let serve_app = app.clone();
|
|
let server = tokio::spawn(async move {
|
|
axum::serve(
|
|
listener,
|
|
router(serve_app).into_make_service_with_connect_info::<std::net::SocketAddr>(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
});
|
|
let bbox = [47., 9., 47.002, 9.004];
|
|
let message = CreateCity {
|
|
bbox: bbox.to_vec(),
|
|
name: "Test town".into(),
|
|
seed: 1,
|
|
};
|
|
let (status, body) = request(
|
|
address,
|
|
"POST",
|
|
"/api/cities/jobs",
|
|
&message.encode_to_vec(),
|
|
)
|
|
.await;
|
|
assert_eq!(status, 200, "{}", String::from_utf8_lossy(&body));
|
|
let job = CityJob::decode(&body[..]).unwrap();
|
|
assert_eq!(job.city_id, cache_id(bbox, 1));
|
|
let ready = tokio::time::timeout(Duration::from_secs(30), async {
|
|
loop {
|
|
let (status, body) =
|
|
request(address, "GET", &format!("/api/cities/jobs/{}", job.id), &[]).await;
|
|
assert_eq!(status, 200);
|
|
let state = CityJob::decode(&body[..]).unwrap();
|
|
assert_ne!(state.status, "failed", "{}", state.error);
|
|
if state.status == "ready" {
|
|
break state;
|
|
}
|
|
tokio::time::sleep(Duration::from_millis(25)).await;
|
|
}
|
|
})
|
|
.await
|
|
.unwrap();
|
|
assert!(!ready.room_id.is_empty());
|
|
let city = citygen_server::city::City::load(&app.config.cities, &ready.city_id).unwrap();
|
|
assert!(!city.graph.points.is_empty());
|
|
assert!(city.manifest.navigation.is_some());
|
|
let duplicate = app
|
|
.jobs
|
|
.submit(
|
|
app.clone(),
|
|
Request {
|
|
bbox: [47.0000001, 9., 47.002, 9.004],
|
|
name: "Same area".into(),
|
|
seed: 1,
|
|
},
|
|
)
|
|
.unwrap();
|
|
assert_eq!(duplicate.id, job.id);
|
|
let (status, _) = request(
|
|
address,
|
|
"POST",
|
|
"/api/cities/jobs",
|
|
&message.encode_to_vec(),
|
|
)
|
|
.await;
|
|
assert_eq!(status, 429);
|
|
app.stop();
|
|
server.abort();
|
|
assert_eq!(
|
|
citygen_server::storage::load(&app.config.saves, &ready.room_id)
|
|
.unwrap()
|
|
.city_id,
|
|
ready.city_id
|
|
);
|
|
}
|