use std::str::FromStr;
use std::sync::Arc;
use std::sync::atomic::{AtomicI64, Ordering};
use std::time::Duration;
use tokio::select;
use shiny_application::{Application, CancellationSignalFactory, CreateInfrastructureConfigurationError, ConfigurationFactory, Module};
use shiny_application::controllers::Controllers;
use shiny_common::pointer_utils::ToArc;
use shiny_common::context::Context;
use shiny_common::error::ServiceError;
use shiny_configuration::Configuration;
use shiny_configuration::configuration_provider::json5_provider::Json5Provider;
use shiny_jobs::Job;
#[tokio::test]
async fn test_application() {
let counter = AtomicI64::new(0).arc();
let mut application = Application::new(counter.clone(), TestModule);
application.set_infrastructure_configuration_factory(TestableConfigurationFactory(r#"{
jobs: {
hello_world: {
schedule: "PT1S",
},
}
}"#.to_string()).arc());
application.set_cancellation_signal_factory(TimeoutCancellationToken(Duration::from_secs(3)).arc());
application.set_dynamic_configuration_factory(TestableConfigurationFactory(
r#"{}"#.to_string()
).arc());
select! {
_ = application.run() => {
}
_ = tokio::time::sleep(Duration::from_secs(5)) => {
panic!("application is not finished after 7 seconds")
}
}
let counter = counter.load(Ordering::SeqCst);
assert!(counter >= 2 && counter <= 3, "counter = {counter}")
}
struct TestModule;
impl Module for TestModule {
type Clients = Arc<AtomicI64>;
fn create(&self, client: Self::Clients) -> Controllers {
let mut controllers = Controllers::new();
controllers.jobs().add("hello_world", JobExample(client.clone()).arc());
controllers
}
}
struct JobExample(Arc<AtomicI64>);
#[async_trait::async_trait]
impl Job for JobExample {
async fn execute(&self, _: &mut Context) -> Result<(), ServiceError> {
self.0.fetch_add(1, Ordering::SeqCst);
Ok(())
}
}
struct TimeoutCancellationToken(Duration);
#[async_trait::async_trait]
impl CancellationSignalFactory for TimeoutCancellationToken {
async fn cancellation_signal(&self) -> std::io::Result<()> {
tokio::time::sleep(self.0).await;
Ok(())
}
}
struct TestableConfigurationFactory(String);
impl ConfigurationFactory for TestableConfigurationFactory {
fn configuration(&self) -> Result<Configuration, CreateInfrastructureConfigurationError> {
let root_provider = Json5Provider::from_str(&self.0).unwrap();
Ok(
Configuration::builder(root_provider)
.build()?
)
}
}