test: check for relay health after startup

This commit is contained in:
Greg Heartsfield 2022-09-17 16:02:57 -05:00
parent baeb77af99
commit 36b9f628c7
2 changed files with 69 additions and 6 deletions

View File

@ -1,12 +1,15 @@
use anyhow::Result;
use anyhow::{anyhow, Result};
use log::*;
use nostr_rs_relay::config;
use nostr_rs_relay::server::start_server;
//use http::{Request, Response};
use hyper::{Client, StatusCode, Uri};
use std::net::TcpListener;
use std::sync::mpsc as syncmpsc;
use std::sync::mpsc::{Receiver as MpscReceiver, Sender as MpscSender};
use std::thread;
use std::thread::JoinHandle;
use std::time::Duration;
pub struct Relay {
pub port: u16,
@ -20,8 +23,9 @@ pub fn start_relay() -> Result<Relay> {
// replace default settings
let mut settings = config::Settings::default();
// identify open port
info!("Checking for address...");
let port = get_available_port().unwrap();
info!("Starting relay on port {}", port);
info!("Found open port: {}", port);
// bind to local interface only
settings.network.address = "127.0.0.1".to_owned();
settings.network.port = port;
@ -31,8 +35,10 @@ pub fn start_relay() -> Result<Relay> {
settings.database.max_conn = 8;
let (shutdown_tx, shutdown_rx): (MpscSender<()>, MpscReceiver<()>) = syncmpsc::channel();
let handle = thread::spawn(|| {
// server will block the thread it is run on.
let _ = start_server(settings, shutdown_rx);
});
// how do we know the relay has finished starting up?
return Ok(Relay {
port,
handle,
@ -40,11 +46,50 @@ pub fn start_relay() -> Result<Relay> {
});
}
// check if the server is healthy via HTTP request
async fn server_ready(relay: &Relay) -> Result<bool> {
let uri: String = format!("http://127.0.0.1:{}/", relay.port.to_string());
let client = Client::new();
let uri: Uri = uri.parse().unwrap();
let res = client.get(uri).await?;
Ok(res.status() == StatusCode::OK)
}
pub async fn wait_for_healthy_relay(relay: &Relay) -> Result<()> {
// TODO: maximum time to wait for server to become healthy.
// give it a little time to start up before we start polling
tokio::time::sleep(Duration::from_millis(10)).await;
loop {
let server_check = server_ready(&relay).await;
match server_check {
Ok(true) => {
// server responded with 200-OK.
break;
}
Ok(false) => {
// server responded with an error, we're done.
return Err(anyhow!("Got non-200-OK from relay"));
}
Err(_) => {
// server is not yet ready, probably connection refused...
debug!("Got ERR from Relay!");
tokio::time::sleep(Duration::from_millis(10)).await;
}
}
}
info!("relay is ready");
Ok(())
// simple message sent to web browsers
//let mut request = Request::builder()
// .uri("https://www.rust-lang.org/")
// .header("User-Agent", "my-awesome-agent/1.0");
}
// from https://elliotekj.com/posts/2017/07/25/find-available-tcp-port-rust/
fn get_available_port() -> Option<u16> {
(4000..20000).find(|port| port_is_available(*port))
(4030..20000).find(|port| port_is_available(*port))
}
fn port_is_available(port: u16) -> bool {
pub fn port_is_available(port: u16) -> bool {
match TcpListener::bind(("127.0.0.1", port)) {
Ok(_) => true,
Err(_) => false,

View File

@ -1,12 +1,20 @@
use anyhow::Result;
use log::*;
use std::thread;
use std::time::Duration;
mod common;
#[test]
fn startup() -> Result<()> {
#[tokio::test]
async fn start_and_stop() -> Result<()> {
// this will be the common pattern for acquiring a new relay:
// start a fresh relay, on a port to-be-provided back to us:
let relay = common::start_relay()?;
// wait for the relay's webserver to start up and deliver a page:
common::wait_for_healthy_relay(&relay).await?;
let relay = common::start_relay()?;
let port = relay.port;
// just make sure we can startup and shut down.
// if we send a shutdown message before the server is listening,
// we will get a SendError. Keep sending until someone is
@ -25,5 +33,15 @@ fn startup() -> Result<()> {
// wait for relay to shutdown
let thread_join = relay.handle.join();
assert!(thread_join.is_ok());
// assert that port is now available.
assert!(common::port_is_available(port));
Ok(())
}
#[tokio::test]
async fn relay_home_page() -> Result<()> {
// get a relay and wait for startup...
let relay = common::start_relay()?;
common::wait_for_healthy_relay(&relay).await?;
Ok(())
}