diff --git a/.env b/.env new file mode 100644 index 0000000..85a342d --- /dev/null +++ b/.env @@ -0,0 +1 @@ +DATABASE_URL="postgres://postgres:password@127.0.0.1:5432/newsletter" diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index 6e5443a..b16ec48 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -5,6 +5,33 @@ on: [push, pull_request] name: MSRV jobs: + # Label of the container job + container-job: + # Containers must run in Linux based operating systems + runs-on: ubuntu-latest + # Docker Hub image that `container-job` executes in + container: node:10.18-jessie + + # Service containers to run with `container-job` + services: + # Label used to access the service container + postgres: + # Docker Hub image + image: postgres + # Provide the password for postgres + env: + POSTGRES_PASSWORD: passowrd + POSTGRES_USERNAME: postgres + POSTGRES_DB: newsletter + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + # Maps tcp port 5432 on service container to the host + - 5432:5432 check: name: Check runs-on: ubuntu-latest diff --git a/migrations/20240321030443_create_subscription_table.sql b/migrations/20240321030443_create_subscription_table.sql index 6febff9..0a9d32a 100644 --- a/migrations/20240321030443_create_subscription_table.sql +++ b/migrations/20240321030443_create_subscription_table.sql @@ -3,7 +3,7 @@ CREATE TABLE subscriptions( id UUID NOT NULL, PRIMARY KEY(id), - emil TEXT NOT NULL UNIQUE, + email TEXT NOT NULL UNIQUE, name TEXT NOT NULL, subscribed_at TIMESTAMPTZ NOT NULL ); diff --git a/src/configuration.rs b/src/configuration.rs index bc9ed7a..8c21509 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,29 +1,34 @@ #[derive(serde::Deserialize)] -pub struct Settings{ -pub database: DatabaseSettings, +pub struct Settings { + pub database: DatabaseSettings, pub application_port: u16, } #[derive(serde::Deserialize)] -pub struct DatabaseSettings{ +pub struct DatabaseSettings { pub username: String, - pub password:String, + pub password: String, pub port: u16, pub host: String, - pub database_name:String, + pub database_name: String, } impl DatabaseSettings { - pub fn connection_string(&self) -> String { - format!("postgres://{}:{}@{}:{}/{}", self.username, self.password, self.host, self.password, self.database_name) + pub fn connection_string(&self) -> String { + format!( + "postgres://{}:{}@{}:{}/{}", + self.username, self.password, self.host, self.port, self.database_name + ) } } - -pub fn get_configuration() -> Result{ +pub fn get_configuration() -> Result { let settings = config::Config::builder() - .add_source(config::File::new("configuration.yaml", config::FileFormat::Yaml)) - .build()?; + .add_source(config::File::new( + "configuration.yaml", + config::FileFormat::Yaml, + )) + .build()?; settings.try_deserialize() } diff --git a/src/routes/health_check.rs b/src/routes/health_check.rs index 740dcee..d7eb4e0 100644 --- a/src/routes/health_check.rs +++ b/src/routes/health_check.rs @@ -1,7 +1,5 @@ - use actix_web::HttpResponse; + pub async fn health_check() -> HttpResponse { HttpResponse::Ok().finish() } - - diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 2d0b51a..90ffeed 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,7 +1,5 @@ - mod health_check; mod subscriptions; pub use health_check::*; pub use subscriptions::*; - diff --git a/src/routes/subscriptions.rs b/src/routes/subscriptions.rs index a29a77e..c98a7eb 100644 --- a/src/routes/subscriptions.rs +++ b/src/routes/subscriptions.rs @@ -1,6 +1,5 @@ -use std::net::TcpListener; +use actix_web::{web, HttpResponse}; -use actix_web::{dev::Server, web, App, HttpResponse, HttpServer}; #[derive(serde::Deserialize, serde::Serialize)] pub struct FormData { name: String, @@ -10,5 +9,3 @@ pub struct FormData { pub async fn subscribe(_form: web::Form) -> HttpResponse { HttpResponse::Ok().finish() } - - diff --git a/src/startup.rs b/src/startup.rs index 5690bad..2418315 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -1,6 +1,6 @@ -use std::net::TcpListener; -use actix_web::{dev::Server, web, App, HttpServer}; use crate::routes::{health_check, subscribe}; +use actix_web::{dev::Server, web, App, HttpServer}; +use std::net::TcpListener; pub fn run(tcp_listener: TcpListener) -> Result { let server = HttpServer::new(|| { diff --git a/tests/health_check.rs b/tests/health_check.rs index c270e01..ed91e0d 100644 --- a/tests/health_check.rs +++ b/tests/health_check.rs @@ -1,6 +1,7 @@ +use sqlx::{Connection, PgConnection, Row}; use std::net::TcpListener; -use zero2prod::run; +use zero2prod::{get_configuration, run}; #[tokio::test] async fn health_check_works() { @@ -32,8 +33,22 @@ async fn subscribe_returns_200_for_valid_form_data() { .await .expect("Failed to execute request"); - assert_eq!(200, response.status().as_u16()) + assert_eq!(200, response.status().as_u16()); + + let config = get_configuration().expect("Failed to get configuration"); + let mut connection = PgConnection::connect(&config.database.connection_string()) + .await + .expect("Failed to connect to database"); + + let r = sqlx::query!("SELECT id, name, email, subscribed_at FROM subscriptions") + .fetch_one(&mut connection) + .await + .expect("Failed to execute query"); + + assert_eq!("le guin", r.name); + assert_eq!("le_guin@gmail.com", r.email); } + #[tokio::test] async fn subscribe_returns_400_for_missing_form_data() { let address = spawn_app();