Skip to content
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
27 changes: 5 additions & 22 deletions src/http/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,15 @@ mod tests {
use super::update::update_subscription_inner;
use crate::domain::{BranchName, EventType, RepoUrl, TargetRepo};
use crate::http::error::HandlerError;
use crate::http::state::AppState;
use crate::model::{CreateSubscription, UpdateSubscription};
use crate::test_utils::create_test_db;
use crate::test_utils::{create_test_db, create_test_state};
use axum::Json;
use axum::extract::{Path, Query, State};

#[tokio::test]
async fn test_crud_subscription() {
let pool = create_test_db().await;
let config = crate::test_utils::create_test_config();
let state = AppState {
config: std::sync::Arc::new(config),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
};
let state = create_test_state(pool.clone());
let payload = CreateSubscription {
source_repo_url: RepoUrl::new("https://github.com/org/repo".to_string()).unwrap(),
source_branch_name: BranchName::new("main".to_string()).unwrap(),
Expand Down Expand Up @@ -120,11 +115,7 @@ mod tests {
#[tokio::test]
async fn test_non_existent_subscription_returns_not_found() {
let pool = create_test_db().await;
let config = crate::test_utils::create_test_config();
let state = AppState {
config: std::sync::Arc::new(config),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
};
let state = create_test_state(pool.clone());

// Try getting a non-existent subscription
let get_res = get_subscription_inner(State(state.clone()), Path(999)).await;
Expand All @@ -148,11 +139,7 @@ mod tests {
#[tokio::test]
async fn test_list_subscriptions_pagination() {
let pool = create_test_db().await;
let config = crate::test_utils::create_test_config();
let state = AppState {
config: std::sync::Arc::new(config),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
};
let state = create_test_state(pool.clone());

// Create 3 subscriptions
//
Expand Down Expand Up @@ -205,11 +192,7 @@ mod tests {
#[tokio::test]
async fn test_cascading_branch_cleanup() {
let pool = create_test_db().await;
let config = crate::test_utils::create_test_config();
let state = AppState {
config: std::sync::Arc::new(config),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
};
let state = create_test_state(pool.clone());
let payload = CreateSubscription {
source_repo_url: RepoUrl::new("https://github.com/org/repo".to_string()).unwrap(),
source_branch_name: BranchName::new("main".to_string()).unwrap(),
Expand Down
44 changes: 5 additions & 39 deletions src/polling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,9 @@ async fn followup_poll(res: Result<(), PollingError>, ctx: &SharedContext) {
clippy::indexing_slicing
)]
mod tests {
use crate::context::SharedContext;
use crate::domain::CommitHash;
use crate::polling::poll_branches;
use crate::test_utils::MockGitFetcher;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;
use crate::test_utils::create_test_context;

#[tokio::test]
async fn test_poll_branches_updates_db_and_queues_trigger() {
Expand Down Expand Up @@ -255,16 +252,7 @@ mod tests {
.await
.unwrap();

let mock_fetcher = Arc::new(MockGitFetcher {
hash: CommitHash::new("b".repeat(40)).unwrap(),
});

let ctx = SharedContext {
config: crate::test_utils::create_test_config(),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
git_fetcher: mock_fetcher,
token: CancellationToken::new(),
};
let ctx = create_test_context(pool.clone(), CommitHash::new("b".repeat(40)).unwrap());

poll_branches(&ctx).await.unwrap();

Expand Down Expand Up @@ -311,29 +299,14 @@ mod tests {
.await
.unwrap();

let ctx = SharedContext {
config: crate::test_utils::create_test_config(),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
git_fetcher: Arc::new(crate::test_utils::MockGitFetcher {
hash: CommitHash::new("b".repeat(40)).unwrap(),
}),
token: CancellationToken::new(),
};
let ctx = create_test_context(pool.clone(), CommitHash::new("b".repeat(40)).unwrap());

// First update
poll_branches(&ctx).await.unwrap();

// Second update (coalescing)
// Manually update the mock fetcher to a new hash
let mock_fetcher = Arc::new(crate::test_utils::MockGitFetcher {
hash: CommitHash::new("c".repeat(40)).unwrap(),
});
let ctx = SharedContext {
config: ctx.config,
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
git_fetcher: mock_fetcher,
token: ctx.token,
};
let ctx = create_test_context(pool.clone(), CommitHash::new("c".repeat(40)).unwrap());
poll_branches(&ctx).await.unwrap();

// Verify only one entry in queue
Expand Down Expand Up @@ -397,14 +370,7 @@ mod tests {
.await
.unwrap();

let ctx = SharedContext {
config: crate::test_utils::create_test_config(),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(pool.clone())),
git_fetcher: std::sync::Arc::new(crate::test_utils::MockGitFetcher {
hash: CommitHash::new("c".repeat(40)).unwrap(),
}),
token: tokio_util::sync::CancellationToken::new(),
};
let ctx = create_test_context(pool.clone(), CommitHash::new("c".repeat(40)).unwrap());

// Poll for both branches. The first branch updates to 'c'
// The second branch updates to 'c' and coalesces with the first one
Expand Down
49 changes: 44 additions & 5 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,22 @@
clippy::indexing_slicing
)]

use std::path::PathBuf;
use std::sync::Arc;

use async_trait::async_trait;
use sqlx::{SqlitePool, sqlite::SqlitePoolOptions};
use tokio_util::sync::CancellationToken;
use url::Url;

use crate::{
context::SharedContext,
domain::{AcceptHeader, ApiVersion, CommitHash, NonEmptyString},
http::state::AppState,
polling::git::GitFetcher,
trigger::{Authenticator, error::AuthError},
repository::SqliteRepository,
trigger::{Authenticator, TriggerEngine, error::AuthError},
};
use async_trait::async_trait;
use sqlx::{SqlitePool, sqlite::SqlitePoolOptions};
use std::path::PathBuf;
use url::Url;

pub struct MockGitFetcher {
pub hash: CommitHash,
Expand Down Expand Up @@ -103,3 +110,35 @@ pub fn create_test_config() -> crate::config::Config {
},
}
}

/// Creates an [`AppState`] with the default test configuration,
/// backed by `pool`.
pub fn create_test_state(pool: SqlitePool) -> AppState {
AppState {
config: Arc::new(create_test_config()),
repository: Arc::new(SqliteRepository::new(pool)),
}
}

/// Creates a [`SharedContext`] backed by `pool`,
/// whose git fetcher always reports `hash`.
pub fn create_test_context(pool: SqlitePool, hash: CommitHash) -> SharedContext {
SharedContext {
config: create_test_config(),
repository: Arc::new(SqliteRepository::new(pool)),
token: CancellationToken::new(),
git_fetcher: Arc::new(MockGitFetcher { hash }),
}
}

/// Creates a [`TriggerEngine`] with the default test mocks,
/// backed by `pool`.
pub fn create_test_engine(pool: SqlitePool) -> TriggerEngine {
TriggerEngine {
ctx: create_test_context(pool, CommitHash::new("a".repeat(40)).expect("valid hash")),
http_client: reqwest::Client::new(),
authenticator: Box::new(MockAuthenticator {
iat: "token".to_string(),
}),
}
}
41 changes: 3 additions & 38 deletions src/trigger/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,11 @@ mod tests {

use super::recover_stuck_tasks;
use super::schedule_retry;
use crate::context::SharedContext;
use crate::domain::{CommitHash, EventType, TargetRepo};
use crate::model::TriggerQueueItem;
use crate::repository::trigger::TriggerRepository;
use crate::test_utils::{MockAuthenticator, MockGitFetcher};
use crate::trigger::error::{RequestError, WorkflowTriggerError};
use crate::trigger::{TriggerEngine, process_queue};
use std::sync::Arc;

use tokio_util::sync::CancellationToken;
use crate::trigger::process_queue;
use wiremock::matchers::{method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};

Expand Down Expand Up @@ -335,22 +330,7 @@ mod tests {
span_context: None,
};

let engine = TriggerEngine {
ctx: SharedContext {
config: crate::test_utils::create_test_config(),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(
pool.clone(),
)),
token: CancellationToken::new(),
git_fetcher: Arc::new(MockGitFetcher {
hash: CommitHash::new("a".repeat(40)).unwrap(),
}),
},
http_client: reqwest::Client::new(),
authenticator: Box::new(MockAuthenticator {
iat: "token".to_string(),
}),
};
let engine = crate::test_utils::create_test_engine(pool.clone());

schedule_retry(
&engine,
Expand Down Expand Up @@ -421,22 +401,7 @@ mod tests {
.await
.unwrap();

let engine = TriggerEngine {
ctx: SharedContext {
config: crate::test_utils::create_test_config(),
repository: std::sync::Arc::new(crate::repository::SqliteRepository::new(
pool.clone(),
)),
token: CancellationToken::new(),
git_fetcher: Arc::new(MockGitFetcher {
hash: CommitHash::new("a".repeat(40)).unwrap(),
}),
},
http_client: reqwest::Client::new(),
authenticator: Box::new(MockAuthenticator {
iat: "token".to_string(),
}),
};
let engine = crate::test_utils::create_test_engine(pool.clone());

process_queue(&engine).await.unwrap();

Expand Down
Loading