Skip to content

Commit

Permalink
Merge pull request #30 from swayam-agrahari/master
Browse files Browse the repository at this point in the history
Updating the deploy.yml action
  • Loading branch information
hrideshmg authored Dec 12, 2024
2 parents 2ad8866 + 3673c4c commit 9031f52
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 58 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Start PostgreSQL
run: |
docker run --name postgres-test -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=test_db -p 5432:5432 -d postgres:15
- name: Set TEST_DATABASE_URL
run: echo "TEST_DATABASE_URL=postgres://postgres:postgres@localhost:5432/test_db" >> $GITHUB_ENV

- uses: shuttle-hq/deploy-action@main
with:
name: "root"
Expand Down
7 changes: 3 additions & 4 deletions src/db/member.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use sqlx::FromRow;
use async_graphql::SimpleObject;

use sqlx::FromRow;

//Struct for the Member table
#[derive(FromRow, SimpleObject)]
Expand All @@ -15,12 +14,12 @@ pub struct Member {
pub year: i32,
pub macaddress: String,
pub discord_id: Option<String>,
pub group_id: Option<i32>,
pub group_id: i32,
}

#[derive(FromRow, SimpleObject)]
pub struct StreakUpdate {
pub id: i32,
pub streak: Option<i32>,
pub max_streak: Option<i32>,
}
}
174 changes: 120 additions & 54 deletions tests/integration_tests.rs
Original file line number Diff line number Diff line change
@@ -1,61 +1,142 @@
use config::{Config, File, FileFormat};
use root::db::leaderboard::Leaderboard;
use root::db::member::Member;
use root::leaderboard::fetch_stats::{fetch_codeforces_stats, fetch_leetcode_stats};
use root::leaderboard::update_leaderboard::update_leaderboard;
use sqlx::{postgres::PgPoolOptions, PgPool};
use std::env;
use std::sync::Arc;

pub fn get_database_url() -> String {
// Create a configuration instance to read Secrets.toml
let settings = Config::builder()
.add_source(File::new("Secrets", FileFormat::Toml))
.build()
.expect("Failed to load Secrets.toml");

// Retrieve the `DATABASE_URL` from the file
settings
.get_string("DATABASE_URL")
.expect("Missing 'DATABASE_URL' in Secrets.toml")
match env::var("TEST_DATABASE_URL") {
Ok(db_url) => db_url,
Err(_) => "postgres://localhost:5432/default_db".to_string(),
}
}

// Helper function to create a test database connection
async fn setup_test_db() -> PgPool {
let database_url = get_database_url();
PgPoolOptions::new()
let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&database_url)
.await
.expect("Failed to create test database pool")
.expect("Failed to create test database pool");

// Create tables if they do not already exist
let queries = vec![
r#"
CREATE TABLE IF NOT EXISTS member (
id SERIAL PRIMARY KEY,
rollno VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
hostel VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
sex VARCHAR(10) NOT NULL,
year INT NOT NULL,
macaddress VARCHAR(17) NOT NULL,
discord_id VARCHAR(255),
group_id INT NOT NULL
)"#,
r#"
CREATE TABLE IF NOT EXISTS leaderboard (
id SERIAL PRIMARY KEY,
member_id INT UNIQUE NOT NULL,
leetcode_score INT,
codeforces_score INT,
unified_score INT NOT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (member_id) REFERENCES member(id)
)"#,
r#"
CREATE TABLE IF NOT EXISTS leetcode_stats (
id SERIAL PRIMARY KEY,
member_id INT UNIQUE NOT NULL,
leetcode_username VARCHAR(255) NOT NULL,
problems_solved INT NOT NULL,
easy_solved INT NOT NULL,
medium_solved INT NOT NULL,
hard_solved INT NOT NULL,
contests_participated INT NOT NULL,
best_rank INT NOT NULL,
total_contests INT NOT NULL,
FOREIGN KEY (member_id) REFERENCES member(id)
)"#,
r#"
CREATE TABLE IF NOT EXISTS codeforces_stats (
id SERIAL PRIMARY KEY,
member_id INT UNIQUE NOT NULL,
codeforces_handle VARCHAR(255) NOT NULL,
codeforces_rating INT NOT NULL,
max_rating INT NOT NULL,
contests_participated INT NOT NULL,
FOREIGN KEY (member_id) REFERENCES member(id)
)"#,
];

for query in queries {
sqlx::query(query)
.execute(&pool)
.await
.expect("Failed to execute query");
}
pool
}

// Helper function to clean up test data

async fn cleanup_test_data(pool: &PgPool) {
// sqlx::query("DELETE FROM leaderboard")
// .execute(pool)
// .await
// .unwrap();
// sqlx::query("DELETE FROM leetcode_stats")
// .execute(pool)
// .await
// .unwrap();
// sqlx::query("DELETE FROM codeforces_stats")
// .execute(pool)
// .await
// .unwrap();
// sqlx::query("DELETE FROM Member")
// .execute(pool)
// .await
// .unwrap();
print!("called");
let cleanup_query = r#"
DO $$
DECLARE
seq RECORD;
BEGIN
-- Droppign all the tables for cleanup purpose
BEGIN
TRUNCATE TABLE leaderboard, leetcode_stats, codeforces_stats, member RESTART IDENTITY CASCADE;
EXCEPTION
WHEN undefined_table THEN
-- Ignore errors if tables don't exist
RAISE NOTICE 'Tables do not exist, skipping TRUNCATE.';
END;
-- Postgres stores the sequences of unique id outside of respective tables, so need to delete those too.
FOR seq IN
SELECT c.relname
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'S' AND n.nspname = 'public'
LOOP
BEGIN
EXECUTE 'ALTER SEQUENCE ' || seq.relname || ' RESTART WITH 1';
EXCEPTION
WHEN undefined_object THEN
-- Ignore errors if sequences don't exist
RAISE NOTICE 'Sequence % does not exist, skipping.', seq.relname;
END;
END LOOP;
END $$;
"#;

sqlx::query(cleanup_query)
.execute(pool)
.await
.expect("Failed to clean up and reset database state");
}

#[tokio::test]
// Additional helper test to verify database connections and basic operations
async fn test_database_connection() {
let database_url = get_database_url();
println!("Database URL: {}", database_url);
assert!(!database_url.is_empty(), "Database URL should not be empty");
}

//test
#[tokio::test]
async fn test_insert_members_and_update_stats() {
let pool = setup_test_db().await;

cleanup_test_data(&pool).await;

// Define test members
let members = vec![
(
Expand All @@ -67,6 +148,7 @@ async fn test_insert_members_and_update_stats() {
2021,
"00:11:22:33:44:55",
Some("john_discord"),
1,
"swayam-agrahari",
"tourist",
),
Expand All @@ -79,6 +161,7 @@ async fn test_insert_members_and_update_stats() {
2021,
"66:77:88:99:AA:BB",
Some("jane_discord"),
2,
"rihaan1810",
"tourist",
),
Expand All @@ -90,8 +173,8 @@ async fn test_insert_members_and_update_stats() {
for member in &members {
// Insert Member
let member_result = sqlx::query_as::<_, Member>(
"INSERT INTO Member (rollno, name, hostel, email, sex, year, macaddress, discord_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
"INSERT INTO member (rollno, name, hostel, email, sex, year, macaddress, discord_id, group_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING *",
)
.bind(&member.0)
Expand All @@ -102,6 +185,7 @@ async fn test_insert_members_and_update_stats() {
.bind(member.5)
.bind(&member.6)
.bind(&member.7)
.bind(&member.8)
.fetch_one(&pool)
.await
.expect("Failed to insert member");
Expand All @@ -112,7 +196,7 @@ async fn test_insert_members_and_update_stats() {
VALUES ($1, $2, 0,0,0,0,0,0,0)",
)
.bind(member_result.id)
.bind(&member.8)
.bind(&member.9)
.execute(&pool)
.await
.expect("Failed to insert LeetCode stats");
Expand All @@ -123,7 +207,7 @@ async fn test_insert_members_and_update_stats() {
VALUES ($1, $2, 0,0,0)",
)
.bind(member_result.id)
.bind(&member.9)
.bind(&member.10)
.execute(&pool)
.await
.expect("Failed to insert Codeforces stats");
Expand All @@ -132,7 +216,7 @@ async fn test_insert_members_and_update_stats() {
}

// Test LeetCode stats fetching
for (member_id, leetcode_username) in inserted_members.iter().zip(members.iter().map(|m| m.8)) {
for (member_id, leetcode_username) in inserted_members.iter().zip(members.iter().map(|m| m.9)) {
match fetch_leetcode_stats(Arc::new(pool.clone()), *member_id, leetcode_username).await {
Ok(_) => println!(
"Successfully fetched LeetCode stats for member ID: {}",
Expand All @@ -155,8 +239,6 @@ async fn test_insert_members_and_update_stats() {
),
Err(e) => {
println!("Error fetching Codeforces stats: {:?}", e);
// Uncomment to fail test on fetch error
// panic!("Failed to fetch Codeforces stats")
}
}
}
Expand Down Expand Up @@ -192,21 +274,5 @@ async fn test_insert_members_and_update_stats() {
);
}

// Clean up
cleanup_test_data(&pool).await;
}

// Additional helper test to verify database connections and basic operations
#[tokio::test]
async fn test_database_connection() {
let pool = setup_test_db().await;
let database_url = get_database_url();

// Print the URL to verify (optional, for debugging purposes)
println!("Database URL: {}", database_url);

// Basic database connectivity test
let result = sqlx::query("SELECT 1").fetch_one(&pool).await;

assert!(result.is_ok(), "Database connection and query should work");
}

0 comments on commit 9031f52

Please sign in to comment.