Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added codecov configuration #2

Merged
merged 6 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 30 additions & 9 deletions .github/workflows/general_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,33 @@ jobs:
- name: Generate documentation
run: cargo doc --no-deps --document-private-items

code_coverage:
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v3

- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc
# code_coverage:
# needs: build
# runs-on: ubuntu-latest
# if: github.event_name == 'push' || github.event_name == 'pull_request'
# steps:
# - uses: actions/checkout@v3
#
# - name: Install dependencies
# run: sudo apt-get update && sudo apt-get install -y libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc
# # Install tarpaulin, a Rust coverage tool
# - name: Install cargo-tarpaulin
# run: cargo install cargo-tarpaulin
#
# # Run tarpaulin to generate coverage report
# - name: Run coverage
# run: cargo tarpaulin --out Xml
#
# # Upload coverage report to Codecov
# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v3
# with:
# files: ./cobertura.xml # Specify the report generated by tarpaulin
# fail_ci_if_error: true
# verbose: true
#
# # Display coverage in GitHub PR
# - name: Coverage badge
# run: |
# curl -s https://codecov.io/gh/${{ github.repository }}/branch/${{ github.ref_name }}/graph/badge.svg \
# -o coverage-badge.svg
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ Cargo.lock
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
1 change: 1 addition & 0 deletions .idea/isotopes.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,19 @@ name = "isotopes"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
path = "src/lib.rs"

[[bin]]
path = "src/main.rs"
name = "isotopes"

[dependencies]
serde = "1.0"
actix-web = "4.9.0"
tokio = { version = "1.40.0", features = ["macros", "rt-multi-thread"] }
serde = {version = "1.0.130", features = ["derive"]}
[dev-dependencies]
reqwest = "0.12.7"

35 changes: 35 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use actix_web::{App, HttpRequest, HttpResponse, HttpServer, Responder, web};
use actix_web::dev::Server;
use std::net::TcpListener;
async fn greet(req: HttpRequest) -> impl Responder {
let name = req.match_info().get("name").unwrap_or("World");
format!("Hello {}!", &name)
}
async fn health_check() -> impl Responder {
HttpResponse::Ok().finish()
}

async fn subscribe(form: web::Form<FromData>) -> impl Responder {
let _x = form.email.clone();
let _y = form.name.clone();
HttpResponse::Ok().finish()
}

#[derive(serde::Deserialize)]
pub struct FromData {
email: String,
name: String,
}


pub async fn run(listener: TcpListener) -> Result<Server, std::io::Error> {
let server = HttpServer::new(|| {
App::new()
.route("/", web::get().to(greet))
.route("/{name}", web::get().to(greet))
.route("/health_check", web::get().to(health_check))
.route("/subscriptions", web::post().to(subscribe))
}).listen(listener)?
.run();
Ok(server)
}
14 changes: 12 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
fn main() {
println!("Hello, world!");
use std::net::TcpListener;
use isotopes::run;

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
// let address = "127.0.0.1:4000";

let listener = TcpListener::bind("127.0.0.1:4000").expect("failed to bind address");
// let port = listener.local_addr().unwrap().port();
// println!("{}", port);

run(listener).await?.await
}
10 changes: 0 additions & 10 deletions test/integration_test.rs

This file was deleted.

76 changes: 76 additions & 0 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use std::net::TcpListener;

// const ADDRESS: &str = "127.0.0.1:4100";

async fn spawn_app() -> String {
let listener = TcpListener::bind("127.0.0.1:0").expect("failed to bind address");
let port = listener.local_addr().unwrap().port();

let server = isotopes::run(listener).await.expect("failed to bind address");
let _ = tokio::spawn(server);
format!("http://127.0.0.1:{}", port)
}
#[tokio::test]
async fn health_check_works() {

// Arrange
let address = spawn_app().await;
let client = reqwest::Client::new();

// Act
let resp = client.get(&format!("{}/health_check", &address))
.send()
.await
.expect("failed to execute request");
// Assert
assert!(resp.status().is_success());
assert_eq!(Some(19), resp.content_length());
}

#[tokio::test]
async fn subscribe_return_a_200_for_valid_form_data() {
// Arrange
let app_address = spawn_app().await;
let client = reqwest::Client::new();

let body = "name=le%20guin&email=ursula_le_guin%40gmail.com";
let response = client
.post(&format!("{}/subscriptions", &app_address))
.header("Content-Type", "application/x-www-form-urlencoded")
.body(body)
.send()
.await
.expect("failed to execute request");

// Assert
assert_eq!(200, response.status().as_u16());
}

#[tokio::test]
async fn sibscribe_returns_a_400_when_date_is_missing() {
let app_address = spawn_app().await;
let client = reqwest::Client::new();

let test_cases = vec![
("name=le%20guin", "missing email"),
("email=ursula_le_guin%40gmail.com", "missing name"),
("", "missing name and email"),
];

for (invalid_body, _error_messages) in test_cases {
let response = client
.post(&format!("{}/subscriptions", &app_address))
.header("Content-Type", "application/x-www-form-urlencoded")
.body(invalid_body)
.send()
.await.
expect("failed to execute request");

assert_eq!(
400,
response.status().as_u16());
}



}
Loading