added unit tests
This commit is contained in:
3
.env
3
.env
@@ -4,3 +4,6 @@ PGUSER=postgres
|
||||
PGHOST=127.0.0.1
|
||||
PGPASSWORD=password
|
||||
INTRASYS_LOG=trace
|
||||
|
||||
#Only use for tests
|
||||
DATABASE_URL=postgres://postgres:password@localhost:5432
|
||||
|
233
Cargo.lock
generated
233
Cargo.lock
generated
@@ -47,6 +47,22 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "assert-json-diff"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atoi"
|
||||
version = "2.0.0"
|
||||
@@ -56,6 +72,12 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "auto-future"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c1e7e457ea78e524f48639f551fd79703ac3f2237f5ecccdf4708f8a75ad373"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
@@ -116,6 +138,36 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-test"
|
||||
version = "17.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eb1dfb84bd48bad8e4aa1acb82ed24c2bb5e855b659959b4e03b4dca118fcac"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert-json-diff",
|
||||
"auto-future",
|
||||
"axum",
|
||||
"bytes",
|
||||
"bytesize",
|
||||
"cookie",
|
||||
"http",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"mime",
|
||||
"pretty_assertions",
|
||||
"reserve-port",
|
||||
"rust-multipart-rfc7578_2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"tower",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
@@ -193,6 +245,12 @@ version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||
|
||||
[[package]]
|
||||
name = "bytesize"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3c8f83209414aacf0eeae3cf730b18d6981697fba62f200fcfb92b9f082acba"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.27"
|
||||
@@ -235,6 +293,16 @@ version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
||||
dependencies = [
|
||||
"time",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
@@ -301,6 +369,21 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@@ -638,6 +721,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -647,13 +731,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"libc",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -802,6 +891,7 @@ name = "intrasys"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-test",
|
||||
"bigdecimal",
|
||||
"dotenv",
|
||||
"serde",
|
||||
@@ -983,11 +1073,17 @@ dependencies = [
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"smallvec",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
@@ -1131,6 +1227,12 @@ dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
@@ -1140,6 +1242,16 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
||||
dependencies = [
|
||||
"diff",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
@@ -1171,8 +1283,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1182,7 +1304,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1194,6 +1326,15 @@ dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.13"
|
||||
@@ -1247,6 +1388,15 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "reserve-port"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21918d6644020c6f6ef1993242989bf6d4952d2e025617744f184c02df51c356"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.8"
|
||||
@@ -1260,13 +1410,28 @@ dependencies = [
|
||||
"num-traits",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"signature",
|
||||
"spki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-multipart-rfc7578_2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c839d037155ebc06a571e305af66ff9fd9063a6e662447051737e1ac75beea41"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"mime",
|
||||
"rand 0.9.1",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.25"
|
||||
@@ -1398,7 +1563,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1563,7 +1728,7 @@ dependencies = [
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rsa",
|
||||
"serde",
|
||||
"sha1",
|
||||
@@ -1604,7 +1769,7 @@ dependencies = [
|
||||
"memchr",
|
||||
"num-bigint",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
@@ -1721,6 +1886,37 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.8.1"
|
||||
@@ -1878,6 +2074,12 @@ dependencies = [
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.18.0"
|
||||
@@ -1957,6 +2159,15 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
||||
dependencies = [
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
@@ -2290,6 +2501,12 @@ version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.8.0"
|
||||
|
@@ -15,3 +15,9 @@ tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
dotenv = "0.15"
|
||||
bigdecimal = { version = "0.4", features = ["serde"] }
|
||||
|
||||
[lib]
|
||||
crate-type = ["bin"]
|
||||
|
||||
[dev-dependencies]
|
||||
axum-test = "17.3"
|
||||
|
10
README.md
10
README.md
@@ -26,7 +26,7 @@ Intrasys is an internal financial transfers application built with Rust and Axum
|
||||
|
||||
### 1. Provision PostgreSQL Database
|
||||
|
||||
Run a PostgreSQL container with Docker:
|
||||
The easiest way is to run a PostgreSQL container with Docker:
|
||||
|
||||
```bash
|
||||
docker run --name intrasys-pg -d -e POSTGRES_PASSWORD=password -p 127.0.0.1:5432:5432 postgres:alpine
|
||||
@@ -101,14 +101,6 @@ The application will be available at `http://localhost:3000`
|
||||
sqlx migrate run
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Run the test suite with:
|
||||
|
||||
```bash
|
||||
cargo test
|
||||
```
|
||||
|
||||
## Assumptions
|
||||
|
||||
- All accounts use the same currency
|
||||
|
@@ -1,8 +1,9 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use axum::{
|
||||
Json,
|
||||
Json, Router,
|
||||
extract::{Path, State},
|
||||
routing::{get, post},
|
||||
};
|
||||
use bigdecimal::BigDecimal;
|
||||
use sqlx::types::BigDecimal as SqlxBigDecimal;
|
||||
@@ -14,7 +15,7 @@ use crate::{
|
||||
models::{Account, CreateAccount, TransactionRequest},
|
||||
};
|
||||
|
||||
pub(crate) async fn create_account(
|
||||
async fn create_account(
|
||||
State(pool): State<DbPool>,
|
||||
Json(payload): Json<CreateAccount>,
|
||||
) -> Result<(), AppError> {
|
||||
@@ -48,7 +49,7 @@ pub(crate) async fn create_account(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_account(
|
||||
async fn get_account(
|
||||
State(pool): State<DbPool>,
|
||||
Path(account_id): Path<i64>,
|
||||
) -> Result<Json<Account>, AppError> {
|
||||
@@ -74,7 +75,7 @@ pub(crate) async fn get_account(
|
||||
Ok(Json(account))
|
||||
}
|
||||
|
||||
pub(crate) async fn process_transaction(
|
||||
async fn process_transaction(
|
||||
State(pool): State<DbPool>,
|
||||
Json(payload): Json<TransactionRequest>,
|
||||
) -> Result<(), AppError> {
|
||||
@@ -165,3 +166,11 @@ pub(crate) async fn process_transaction(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn create_router(pool: DbPool) -> Router {
|
||||
Router::new()
|
||||
.route("/accounts", post(create_account))
|
||||
.route("/accounts/{account_id}", get(get_account))
|
||||
.route("/transactions", post(process_transaction))
|
||||
.with_state(pool)
|
||||
}
|
||||
|
@@ -1,10 +1,5 @@
|
||||
use std::env;
|
||||
|
||||
use axum::{
|
||||
Router,
|
||||
routing::{get, post},
|
||||
};
|
||||
use dotenv::dotenv;
|
||||
use std::env;
|
||||
use tracing::info;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
|
||||
@@ -34,11 +29,7 @@ async fn main() {
|
||||
.expect("Failed to run migrations");
|
||||
|
||||
// Build the application's routes
|
||||
let app = Router::new()
|
||||
.route("/accounts", post(handlers::create_account))
|
||||
.route("/accounts/{account_id}", get(handlers::get_account))
|
||||
.route("/transactions", post(handlers::process_transaction))
|
||||
.with_state(pool);
|
||||
let app = handlers::create_router(pool);
|
||||
|
||||
// Run the server
|
||||
let host = env::var("INTRASYS_HOST").unwrap_or(String::from("127.0.0.1"));
|
||||
@@ -49,3 +40,6 @@ async fn main() {
|
||||
info!("listening on {}", listener.local_addr().unwrap());
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
149
src/tests.rs
Normal file
149
src/tests.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::handlers::create_router;
|
||||
use axum::http::StatusCode;
|
||||
use axum_test::TestServer;
|
||||
use bigdecimal::BigDecimal;
|
||||
use serde_json::{Value, json};
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_get_account(pool: Pool<Postgres>) {
|
||||
let app = create_router(pool.clone());
|
||||
let server = TestServer::new(app).unwrap();
|
||||
|
||||
let response = server.get("/accounts/3").await;
|
||||
|
||||
//Account does not exist yet
|
||||
assert_eq!(response.status_code(), StatusCode::NOT_FOUND);
|
||||
// Create test account
|
||||
sqlx::query("INSERT INTO accounts (account_id, balance) VALUES (3, 150.50)")
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let response = server.get("/accounts/3").await;
|
||||
|
||||
assert_eq!(response.status_code(), StatusCode::OK);
|
||||
|
||||
let account: Value = response.json();
|
||||
assert_eq!(3, account["account_id"]);
|
||||
assert_eq!(
|
||||
BigDecimal::from_str("150.50"),
|
||||
BigDecimal::from_str(account["balance"].as_str().unwrap())
|
||||
);
|
||||
let response = server.get("/accounts/4").await;
|
||||
|
||||
//Account does not exist
|
||||
assert_eq!(response.status_code(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_create_account_success(pool: Pool<Postgres>) {
|
||||
let app = create_router(pool.clone());
|
||||
let server = TestServer::new(app).unwrap();
|
||||
|
||||
let response = server
|
||||
.post("/accounts")
|
||||
.json(&json!({
|
||||
"account_id": 1,
|
||||
"initial_balance": "100.00"
|
||||
}))
|
||||
.await;
|
||||
|
||||
assert_eq!(response.status_code(), StatusCode::OK);
|
||||
|
||||
// Verify account was created
|
||||
let account = sqlx::query_as::<_, (i64, BigDecimal)>(
|
||||
"SELECT account_id, balance FROM accounts WHERE account_id = 1",
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(account.0, 1);
|
||||
assert_eq!(account.1, BigDecimal::from(100));
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_process_transaction_success(pool: Pool<Postgres>) {
|
||||
let app = create_router(pool.clone());
|
||||
let server = TestServer::new(app).unwrap();
|
||||
|
||||
// Create test accounts
|
||||
sqlx::query("INSERT INTO accounts (account_id, balance) VALUES (4, 200.00), (5, 50.00)")
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let response = server
|
||||
.post("/transactions")
|
||||
.json(&json!({
|
||||
"source_account_id": 4,
|
||||
"destination_account_id": 5,
|
||||
"amount": "75.25"
|
||||
}))
|
||||
.await;
|
||||
|
||||
assert_eq!(response.status_code(), StatusCode::OK);
|
||||
|
||||
// Verify balances were updated
|
||||
let source = sqlx::query_as::<_, (i64, BigDecimal)>(
|
||||
"SELECT account_id, balance FROM accounts WHERE account_id = 4",
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let destination = sqlx::query_as::<_, (i64, BigDecimal)>(
|
||||
"SELECT account_id, balance FROM accounts WHERE account_id = 5",
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(source.1, BigDecimal::from_str("124.75").unwrap());
|
||||
assert_eq!(destination.1, BigDecimal::from_str("125.25").unwrap());
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_process_transaction_insufficient_funds(pool: Pool<Postgres>) {
|
||||
let app = create_router(pool.clone());
|
||||
let server = TestServer::new(app).unwrap();
|
||||
|
||||
// Create test accounts
|
||||
sqlx::query("INSERT INTO accounts (account_id, balance) VALUES (6, 50.00), (7, 100.00)")
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let response = server
|
||||
.post("/transactions")
|
||||
.json(&json!({
|
||||
"source_account_id": 6,
|
||||
"destination_account_id": 7,
|
||||
"amount": "75.00"
|
||||
}))
|
||||
.await;
|
||||
|
||||
assert_eq!(response.status_code(), StatusCode::BAD_REQUEST);
|
||||
assert_eq!(response.text(), "Insufficient funds");
|
||||
|
||||
// Verify balances were not changed
|
||||
let source = sqlx::query_as::<_, (i64, BigDecimal)>(
|
||||
"SELECT account_id, balance FROM accounts WHERE account_id = 6",
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let destination = sqlx::query_as::<_, (i64, BigDecimal)>(
|
||||
"SELECT account_id, balance FROM accounts WHERE account_id = 7",
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(source.1, BigDecimal::from_str("50.00").unwrap());
|
||||
assert_eq!(destination.1, BigDecimal::from_str("100.00").unwrap());
|
||||
}
|
Reference in New Issue
Block a user