migrate to tracing and remove log

This commit is contained in:
Rohan Sircar 2021-05-10 12:17:06 +05:30
parent d3a3b1e1f2
commit 88430a3e51
13 changed files with 326 additions and 163 deletions

1
.env
View File

@ -5,4 +5,5 @@ ACTIX_DEMO_RUST_LOG=debug
ACTIX_DEMO_TEST_RUST_LOG=debug
ACTIX_DEMO_HTTP_HOST=127.0.0.1
ACTIX_DEMO_HASH_COST=8
ACTIX_DEMO_LOGGER_FORMAT=plain

194
Cargo.lock generated
View File

@ -57,12 +57,10 @@ dependencies = [
"diesel",
"diesel_migrations",
"dotenv",
"env_logger",
"envy",
"futures",
"lazy-regex",
"lazy_static",
"log",
"nanoid",
"r2d2",
"rand 0.8.3",
@ -71,6 +69,12 @@ dependencies = [
"serde",
"serde_json",
"timeago",
"tracing",
"tracing-actix-web",
"tracing-bunyan-formatter",
"tracing-futures",
"tracing-log",
"tracing-subscriber",
"uuid",
"validator",
"validator_derive",
@ -453,17 +457,6 @@ dependencies = [
"syn",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi 0.3.9",
]
[[package]]
name = "autocfg"
version = "0.1.7"
@ -975,19 +968,6 @@ dependencies = [
"syn",
]
[[package]]
name = "env_logger"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "envy"
version = "0.4.2"
@ -1176,6 +1156,16 @@ dependencies = [
"version_check 0.9.3",
]
[[package]]
name = "gethostname"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e692e296bfac1d2533ef168d0b60ff5897b8b70a4009276834014dd8924cc028"
dependencies = [
"libc",
"winapi 0.3.9",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@ -1319,12 +1309,6 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "idna"
version = "0.2.3"
@ -1529,6 +1513,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matchers"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
dependencies = [
"regex-automata",
]
[[package]]
name = "matches"
version = "0.1.8"
@ -1700,6 +1693,12 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]]
name = "opaque-debug"
version = "0.3.0"
@ -2179,6 +2178,16 @@ dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
dependencies = [
"byteorder",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.23"
@ -2359,6 +2368,15 @@ dependencies = [
"opaque-debug",
]
[[package]]
name = "sharded-slab"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3"
dependencies = [
"lazy_static",
]
[[package]]
name = "signal-hook-registry"
version = "1.3.0"
@ -2472,15 +2490,6 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.24"
@ -2501,6 +2510,15 @@ dependencies = [
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"once_cell",
]
[[package]]
name = "threadpool"
version = "1.8.1"
@ -2627,9 +2645,51 @@ dependencies = [
"cfg-if 1.0.0",
"log",
"pin-project-lite 0.2.6",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-actix-web"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc36fc2f840643e49d220d07cd7ca81bc31c7f6df25f164d4257971533dab354"
dependencies = [
"actix-web",
"futures",
"tracing",
"tracing-futures",
"uuid",
]
[[package]]
name = "tracing-attributes"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-bunyan-formatter"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce1eae70720bd6bb3944f7cf501761aeae658bd1f9293aa373c71a195064910"
dependencies = [
"chrono",
"gethostname",
"log",
"serde",
"serde_json",
"tracing",
"tracing-core",
"tracing-log",
"tracing-subscriber",
]
[[package]]
name = "tracing-core"
version = "0.1.17"
@ -2649,6 +2709,49 @@ dependencies = [
"tracing",
]
[[package]]
name = "tracing-log"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3"
dependencies = [
"lazy_static",
"log",
"tracing-core",
]
[[package]]
name = "tracing-serde"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
dependencies = [
"serde",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa5553bf0883ba7c9cbe493b085c29926bd41b66afc31ff72cf17ff4fb60dcd5"
dependencies = [
"ansi_term",
"chrono",
"lazy_static",
"matchers",
"regex",
"serde",
"serde_json",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
"tracing-serde",
]
[[package]]
name = "trust-dns-proto"
version = "0.19.7"
@ -2959,15 +3062,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"

View File

@ -11,8 +11,6 @@ actix-files = "0.5.0"
actix-http = "2.2.0"
bytes = "1.0.1"
futures = "0.3.14"
log = "0.4.14"
env_logger = "0.8.3"
serde_json = "1.0.64"
# json = "0.12.4"
# listenfd = "0.3.3"
@ -36,6 +34,12 @@ derive-new = "0.5.9"
diesel_migrations = "1.4.0"
actix-threadpool = "0.3.3"
envy = "0.4"
tracing = { version = "0.1" }
tracing-log = "0.1.2"
tracing-subscriber = { version = "0.2.18", features = ["fmt", "registry", "env-filter"] }
tracing-futures = "0.2.5"
tracing-actix-web = "0.2.1"
tracing-bunyan-formatter = "0.2.4"
[dependencies.build-info]
version = "=0.0.23"

View File

@ -44,7 +44,7 @@ impl ResponseError for DomainError {
})
}
DomainError::DbError { source: _ } => {
log::error!("{}", err);
tracing::error!("{}", err);
HttpResponse::InternalServerError().json(ErrorModel {
// error_code: 500,
success: false,
@ -52,7 +52,7 @@ impl ResponseError for DomainError {
})
}
DomainError::DbPoolError { source: _ } => {
log::error!("{}", err);
tracing::error!("{}", err);
HttpResponse::InternalServerError().json(ErrorModel {
// error_code: 500,
success: false,
@ -67,14 +67,14 @@ impl ResponseError for DomainError {
})
}
DomainError::EntityDoesNotExistError { message: _ } => {
HttpResponse::Accepted().json(ErrorModel {
HttpResponse::NotFound().json(ErrorModel {
// error_code: 400,
success: false,
reason: err.to_string(),
})
}
DomainError::ThreadPoolError { message: _ } => {
log::error!("{}", err);
tracing::error!("{}", err);
HttpResponse::InternalServerError().json(ErrorModel {
// error_code: 400,
success: false,
@ -82,7 +82,7 @@ impl ResponseError for DomainError {
})
}
DomainError::AuthError { message: _ } => {
HttpResponse::Accepted().json(ErrorModel {
HttpResponse::Forbidden().json(ErrorModel {
// error_code: 400,
success: false,
reason: err.to_string(),

View File

@ -16,21 +16,31 @@ mod utils;
use actix_files as fs;
use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_web::{cookie::SameSite, middleware, web, App, HttpServer};
use actix_web::{middleware::Logger, web::ServiceConfig};
use actix_web::web::ServiceConfig;
use actix_web::{cookie::SameSite, web, App, HttpServer};
use rand::Rng;
use serde::Deserialize;
use std::io;
use tracing_actix_web::TracingLogger;
use types::DbPool;
build_info::build_info!(pub fn get_build_info);
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum LoggerFormat {
Json,
Plain,
}
#[derive(Deserialize, Debug, Clone)]
pub struct EnvConfig {
pub database_url: String,
pub http_host: String,
#[serde(default = "default_hash_cost")]
pub hash_cost: u8,
pub logger_format: LoggerFormat,
}
#[derive(Deserialize, Debug, Clone)]
@ -91,13 +101,9 @@ pub fn id_service(
)
}
pub fn app_logger() -> Logger {
middleware::Logger::default()
}
pub async fn run(addr: String, app_data: AppData) -> io::Result<()> {
let bi = get_build_info();
log::info!("Starting {} {}", bi.crate_info.name, bi.crate_info.version);
tracing::info!("Starting {} {}", bi.crate_info.name, bi.crate_info.version);
println!(
r#"
__ .__ .___
@ -113,7 +119,7 @@ pub async fn run(addr: String, app_data: AppData) -> io::Result<()> {
App::new()
.configure(configure_app(app_data.clone()))
.wrap(id_service(&private_key))
.wrap(app_logger())
.wrap(TracingLogger)
};
HttpServer::new(app).bind(addr)?.run().await
}

View File

@ -1,9 +1,15 @@
#![forbid(unsafe_code)]
use actix_demo::{AppConfig, AppData, EnvConfig};
use actix_demo::{AppConfig, AppData, EnvConfig, LoggerFormat};
use diesel::{r2d2::ConnectionManager, SqliteConnection};
use env_logger::Env;
use io::ErrorKind;
use std::io;
use tracing::subscriber::set_global_default;
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
use tracing_log::LogTracer;
use tracing_subscriber::fmt::format::FmtSpan;
use tracing_subscriber::{
layer::SubscriberExt, EnvFilter, FmtSubscriber, Registry,
};
#[actix_web::main]
async fn main() -> io::Result<()> {
@ -14,16 +20,6 @@ async fn main() -> io::Result<()> {
)
})?;
let _ = env_logger::try_init_from_env(
Env::default().filter("ACTIX_DEMO_RUST_LOG"),
)
.map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set up env logger: {:?}", err),
)
})?;
let env_config = envy::prefixed("ACTIX_DEMO_")
.from_env::<EnvConfig>()
.map_err(|err| {
@ -33,6 +29,8 @@ async fn main() -> io::Result<()> {
)
})?;
let _ = setup_logger(env_config.logger_format)?;
let connspec = &env_config.database_url;
let manager = ConnectionManager::<SqliteConnection>::new(connspec);
let pool = r2d2::Pool::builder().build(manager).map_err(|err| {
@ -68,3 +66,58 @@ async fn main() -> io::Result<()> {
actix_demo::run(format!("{}:7800", env_config.http_host), app_data).await
}
pub fn setup_logger(format: LoggerFormat) -> io::Result<()> {
let env_filter =
EnvFilter::try_from_env("ACTIX_DEMO_RUST_LOG").map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set up env filter: {:?}", err),
)
})?;
let _ = LogTracer::init().map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set up log tracer: {:?}", err),
)
})?;
let bi = actix_demo::get_build_info();
let _ = match format {
LoggerFormat::Json => {
let formatting_layer = BunyanFormattingLayer::new(
format!("actix-demo-{}", bi.crate_info.version),
// Output the formatted spans to stdout.
std::io::stdout,
);
let subscriber = Registry::default()
.with(env_filter)
.with(JsonStorageLayer)
.with(formatting_layer);
let _ = set_global_default(subscriber).map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set subscriber: {:?}", err),
)
})?;
}
LoggerFormat::Plain => {
let subscriber = FmtSubscriber::builder()
.pretty()
.with_span_events(FmtSpan::NEW)
.with_span_events(FmtSpan::CLOSE)
.with_env_filter(env_filter)
.finish();
let _ = set_global_default(subscriber).map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set subscriber: {:?}", err),
)
})?;
}
};
Ok(())
}

View File

@ -38,6 +38,7 @@ pub async fn login(
response
}
//TODO: fix the response
#[get("/logout")]
pub async fn logout(
id: Identity,
@ -45,7 +46,7 @@ pub async fn logout(
) -> Result<HttpResponse, Error> {
let maybe_identity = id.identity();
let response = if let Some(identity) = maybe_identity {
log::info!("Logging out {user}", user = identity);
tracing::info!("Logging out {user}", user = identity);
id.forget();
HttpResponse::Found().header("location", "/").finish()
} else {

View File

@ -7,11 +7,19 @@ use actix_web::error::ResponseError;
use validator::Validate;
/// Finds user by UID.
#[tracing::instrument(
level = "debug",
skip(app_data),
fields(
user_id = %user_id.0
)
)]
pub async fn get_user(
app_data: web::Data<AppData>,
user_id: web::Path<i32>,
) -> Result<HttpResponse, DomainError> {
let u_id = user_id.into_inner();
tracing::info!("Getting user with id {}", u_id);
// use web::block to offload blocking Diesel code without blocking server thread
let res = web::block(move || {
let pool = &app_data.pool;
@ -20,6 +28,7 @@ pub async fn get_user(
})
.await
.map_err(|err| DomainError::new_thread_pool_error(err.to_string()))?;
tracing::trace!("{:?}", res);
if let Some(user) = res {
Ok(HttpResponse::Ok().json(user))
} else {
@ -61,7 +70,7 @@ pub async fn get_all_users(
.await
.map_err(|err| DomainError::new_thread_pool_error(err.to_string()))?;
log::debug!("{:?}", users);
tracing::debug!("{:?}", users);
if !users.is_empty() {
Ok(HttpResponse::Ok().json(users))
@ -87,7 +96,7 @@ pub async fn add_user(
})
.await
.map(|user| {
log::debug!("{:?}", user);
tracing::debug!("{:?}", user);
HttpResponse::Created().json(user)
}),

View File

@ -2,5 +2,3 @@ pub mod auth;
pub mod regexs;
pub use self::auth::*;
pub use self::regexs::*;
pub mod ops;
pub use self::ops::*;

View File

@ -1,34 +0,0 @@
use std::fmt::Display;
pub trait LogErrorResult<T, E> {
fn log_err(self) -> Result<T, E>;
}
impl<T, E: Display> LogErrorResult<T, E> for Result<T, E> {
fn log_err(self) -> Result<T, E> {
self.map_err(|err| {
log::error!("{}", err.to_string());
err
})
}
}
trait ResultOps<T, E> {
fn tap<U, F: FnOnce(T) -> U>(self, op: F) -> Result<T, E>;
fn tap_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T, E>;
}
impl<T: Clone, E: Clone> ResultOps<T, E> for Result<T, E> {
fn tap<U, F: FnOnce(T) -> U>(self, op: F) -> Result<T, E> {
self.map(|x| {
op(x.clone());
x
})
}
fn tap_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T, E> {
self.map_err(|err| {
op(err.clone());
err
})
}
}

View File

@ -1,59 +1,92 @@
extern crate actix_demo;
use actix_demo::{AppConfig, AppData};
use actix_demo::{AppConfig, AppData, EnvConfig};
use actix_web::test;
use actix_web::App;
use diesel::SqliteConnection;
use diesel::r2d2::{self, ConnectionManager};
use env_logger::Env;
use std::io;
use std::io::ErrorKind;
use tracing::subscriber::set_global_default;
use tracing_actix_web::TracingLogger;
use tracing_log::LogTracer;
use tracing_subscriber::fmt::{format::FmtSpan, Subscriber as FmtSubscriber};
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
use actix_demo::configure_app;
use actix_http::Request;
use actix_web::{dev as ax_dev, Error as AxError};
pub async fn test_app() -> impl ax_dev::Service<
Request = Request,
Response = ax_dev::ServiceResponse<impl ax_dev::MessageBody>,
Error = AxError,
pub async fn test_app() -> io::Result<
impl ax_dev::Service<
Request = Request,
Response = ax_dev::ServiceResponse<impl ax_dev::MessageBody>,
Error = AxError,
>,
> {
let _ = dotenv::dotenv()
let _ = dotenv::dotenv().map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set up env: {:?}", err),
)
})?;
let _ = envy::prefixed("ACTIX_DEMO_")
.from_env::<EnvConfig>()
.map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set up env: {:?}", err),
format!("Failed to parse config: {:?}", err),
)
})
.unwrap();
let _ = env_logger::builder()
.is_test(true)
.parse_env(Env::default().filter("ACTIX_DEMO_TEST_RUST_LOG"))
.try_init();
})?;
let env_filter =
EnvFilter::try_from_env("ACTIX_DEMO_RUST_LOG").map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set up env logger: {:?}", err),
)
})?;
let _ = LogTracer::init().map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set up log tracer: {:?}", err),
)
});
let subscriber = FmtSubscriber::builder()
.pretty()
.with_test_writer()
.with_span_events(FmtSpan::NEW)
.with_span_events(FmtSpan::CLOSE)
.finish()
.with(env_filter);
let _ = set_global_default(subscriber).map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to set subscriber: {:?}", err),
)
});
let connspec = ":memory:";
let manager = ConnectionManager::<SqliteConnection>::new(connspec);
let pool = r2d2::Pool::builder()
.build(manager)
.map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to create pool: {:?}", err),
)
})
.unwrap();
let pool = r2d2::Pool::builder().build(manager).map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to create pool: {:?}", err),
)
})?;
let _ = {
let conn = &pool
.get()
.map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to get connection: {:?}", err),
)
})
.unwrap();
let conn = &pool.get().map_err(|err| {
io::Error::new(
ErrorKind::Other,
format!("Failed to get connection: {:?}", err),
)
})?;
let migrations_dir = diesel_migrations::find_migrations_directory()
.map_err(|err| {
@ -61,8 +94,7 @@ pub async fn test_app() -> impl ax_dev::Service<
ErrorKind::Other,
format!("Error finding migrations dir: {:?}", err),
)
})
.unwrap();
})?;
let _ = diesel_migrations::run_pending_migrations_in_directory(
conn,
&migrations_dir,
@ -73,17 +105,16 @@ pub async fn test_app() -> impl ax_dev::Service<
ErrorKind::Other,
format!("Error running migrations: {:?}", err),
)
})
.unwrap();
})?;
};
test::init_service(
Ok(test::init_service(
App::new()
.configure(configure_app(AppData {
config: AppConfig { hash_cost: 8 },
pool,
}))
.wrap(actix_web::middleware::Logger::default()),
.wrap(TracingLogger),
)
.await
.await)
}

View File

@ -12,10 +12,10 @@ mod tests {
#[actix_rt::test]
async fn get_build_info_should_succeed() {
let req = test::TestRequest::get().uri("/api/build-info").to_request();
let resp = common::test_app().await.call(req).await.unwrap();
let resp = common::test_app().await.unwrap().call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let body: build_info::BuildInfo = test::read_body_json(resp).await;
tracing::debug!("{:?}", body);
assert_eq!(body, *get_build_info());
log::debug!("{:?}", body);
}
}

View File

@ -11,9 +11,10 @@ mod tests {
#[actix_rt::test]
async fn get_users_api_should_return_error_message_if_no_users_exist() {
let req = test::TestRequest::get().uri("/api/users").to_request();
let resp = common::test_app().await.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::ACCEPTED);
let resp = common::test_app().await.unwrap().call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let body: ErrorModel = test::read_body_json(resp).await;
tracing::debug!("{:?}", body);
assert_eq!(
body,
ErrorModel {
@ -21,16 +22,16 @@ mod tests {
reason: "Entity does not exist - No users available".to_owned()
}
);
log::debug!("{:?}", body);
}
#[actix_rt::test]
async fn get_user_api_should_return_error_message_if_user_with_id_does_not_exist(
) {
let req = test::TestRequest::get().uri("/api/users/1").to_request();
let resp = common::test_app().await.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::ACCEPTED);
let resp = common::test_app().await.unwrap().call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let body: ErrorModel = test::read_body_json(resp).await;
tracing::debug!("{:?}", body);
assert_eq!(
body,
ErrorModel {
@ -39,6 +40,5 @@ mod tests {
.to_owned()
}
);
log::debug!("{:?}", body);
}
}