Skip to content

Commit

Permalink
feat: slim docker image
Browse files Browse the repository at this point in the history
  • Loading branch information
koskeller committed Jul 13, 2023
1 parent f474f47 commit e6c6635
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 22 deletions.
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
target/
deploy/
tests/
scripts/
migrations/
.env
.dockerignore
Dockerfile
4 changes: 3 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ DATABASE_POOL_MAX_SIZE=50
# This variable is read by `tracing_subscriber`, not the application itself, so it won't appear on the `Settings` struct.
#
# The value here enables log messages from the backend application as well as log messages emitted for incoming requests.
RUST_LOG=server=debug,tower_http=info,sqlx=info
RUST_LOG=server=debug,tower_http=info,sqlx=info

APP_ENVIRONMENT=development
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
FROM lukemathwalker/cargo-chef:latest-rust-latest as chef
WORKDIR /app
RUN apt update && apt install lld clang -y

FROM chef as planner
COPY . .
# Compute a lock-like file for our project
RUN cargo chef prepare --recipe-path recipe.json

FROM chef as builder
COPY --from=planner /app/recipe.json recipe.json
# Build project dependencies, not our application!
RUN cargo chef cook --release --recipe-path recipe.json
COPY . .
ENV SQLX_OFFLINE true
# Build project
RUN cargo build --release --bin server

FROM debian:bullseye-slim AS runtime
WORKDIR /app
RUN apt-get update -y \
&& apt-get install -y --no-install-recommends openssl ca-certificates \
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/server server
ENV APP_ENVIRONMENT production
ENTRYPOINT ["./server"]
9 changes: 2 additions & 7 deletions tests/api/example.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
use axum::http::StatusCode;
use std::collections::HashMap;

use crate::helpers::*;

#[tokio::test]
async fn example_post_ok() {
let app = TestApp::new().await;
let url = app.get_url("/example");
let mut json = HashMap::new();
json.insert("ping", "hello");
let resp = app.reqwest.post(url).json(&json).send().await.unwrap();

let resp = app.post("/example", r#"{ "ping": "hello" }"#).await;
assert_eq!(resp.status(), StatusCode::OK);

let resp = sqlx::query!("SELECT id, uid, ping, created_at FROM example")
.fetch_one(&app.pool)
.fetch_one(&app.db)
.await
.expect("Failed to query db");

assert_eq!(resp.id, 1);
assert_eq!(resp.ping, "hello");
}
6 changes: 3 additions & 3 deletions tests/api/health_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::helpers::*;
#[tokio::test]
async fn health_check_ok() {
let app = TestApp::new().await;
let url = app.get_url("/health_check");
let resp = reqwest::get(url).await.unwrap();

let resp = app.get("/health_check").await;
assert_eq!(resp.status(), StatusCode::OK);

let request_id = resp.headers().get("x-request-id").unwrap();
Expand All @@ -16,5 +16,5 @@ async fn health_check_ok() {
#[tokio::test]
async fn db_connection_ok() {
let app = TestApp::new().await;
assert_eq!(app.pool.size(), 1);
assert_eq!(app.db.size(), 1);
}
42 changes: 31 additions & 11 deletions tests/api/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,64 @@ static TRACING: Once = Once::new();

pub struct TestApp {
pub addr: String,
pub pool: PgPool,
pub db: PgPool,
pub reqwest: reqwest::Client,
}

impl TestApp {
pub async fn new() -> Self {
dotenv::dotenv().ok();

// So tests can spawn multiple servers on OS assigned ports.
// We set port to 0 so tests can spawn multiple servers on OS assigned ports.
std::env::set_var("PORT", "0");

TRACING.call_once(setup_tracing);

let cfg = Configuration::new().expect("Failed to read configuration");

let url = create_temp_db(&cfg.db_dsn).await;
let url = create_test_db(&cfg.db_dsn).await;
let db = setup_db(&url, cfg.db_pool_max_size)
.await
.expect("Failed to configure db");
.expect("Failed to configure test db");

let reqwest = reqwest::Client::new();

let server = run(cfg, db.clone());
let addr = format!("http://{}", server.local_addr());
let _ = tokio::spawn(server);
Self {
pool: db,
addr,
reqwest,
}
Self { db, addr, reqwest }
}

pub fn get_url(&self, path: &str) -> String {
pub fn url(&self, path: &str) -> String {
format!("{}{}", self.addr, path)
}

pub async fn get(&self, path: &str) -> reqwest::Response {
self.reqwest.get(self.url(path)).send().await.unwrap()
}

pub async fn post(&self, path: &str, body: &str) -> reqwest::Response {
self.reqwest
.post(self.url(path))
.body(body.to_string())
.header("Content-Type", "application/json")
.send()
.await
.unwrap()
}

pub async fn put(&self, path: &str, body: &str) -> reqwest::Response {
self.reqwest
.put(self.url(path))
.body(body.to_string())
.header("Content-Type", "application/json")
.send()
.await
.unwrap()
}
}

pub async fn create_temp_db(db_dsn: &str) -> String {
pub async fn create_test_db(db_dsn: &str) -> String {
let randon_db_name = Uuid::new_v4().to_string();
let db_url = format!("{}/{}", &db_dsn, randon_db_name);
let mut conn = PgConnection::connect(db_dsn)
Expand Down

0 comments on commit e6c6635

Please sign in to comment.