chore(deps): update rust crate kxio to v5
All checks were successful
Test / build (map[name:stable]) (push) Successful in 11m21s
Test / build (map[name:nightly]) (push) Successful in 12m40s
Release Please / Release-plz (push) Successful in 1m8s
Release Please / Docker image (push) Successful in 10m26s

This commit is contained in:
Renovate Bot 2025-01-16 16:42:44 +00:00 committed by Paul Campbell
parent f8625a59f8
commit a8298d943a
10 changed files with 267 additions and 140 deletions

40
Cargo.lock generated
View file

@ -1098,7 +1098,7 @@ dependencies = [
"rand", "rand",
"ratatui", "ratatui",
"regex", "regex",
"rstest", "rstest 0.24.0",
"secrecy", "secrecy",
"sendmail", "sendmail",
"serde_json", "serde_json",
@ -2747,9 +2747,9 @@ dependencies = [
[[package]] [[package]]
name = "kxio" name = "kxio"
version = "4.0.0" version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b711909378294af8b006b4df66e8b2de75fc0c2c98ff9ea7ef1422ae7c859a3d" checksum = "ec15c915b6fb790d4dac6c1c101c01d29bd4701e5d55e48ae47bad69356eb7b4"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bytes", "bytes",
@ -3692,7 +3692,19 @@ checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035"
dependencies = [ dependencies = [
"futures", "futures",
"futures-timer", "futures-timer",
"rstest_macros", "rstest_macros 0.23.0",
"rustc_version",
]
[[package]]
name = "rstest"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03e905296805ab93e13c1ec3a03f4b6c4f35e9498a3d5fa96dc626d22c03cd89"
dependencies = [
"futures-timer",
"futures-util",
"rstest_macros 0.24.0",
"rustc_version", "rustc_version",
] ]
@ -3714,6 +3726,24 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "rstest_macros"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef0053bbffce09062bee4bcc499b0fbe7a57b879f1efe088d6d8d4c7adcdef9b"
dependencies = [
"cfg-if",
"glob",
"proc-macro-crate",
"proc-macro2",
"quote",
"regex",
"relative-path",
"rustc_version",
"syn",
"unicode-ident",
]
[[package]] [[package]]
name = "rust-argon2" name = "rust-argon2"
version = "0.8.3" version = "0.8.3"
@ -4530,7 +4560,7 @@ checksum = "235ee99b9af57bc0bc8cf42604f5868641690ed652001120d63ca2784a41c3d3"
dependencies = [ dependencies = [
"indoc", "indoc",
"ratatui", "ratatui",
"rstest", "rstest 0.23.0",
] ]
[[package]] [[package]]

View file

@ -60,7 +60,7 @@ async-trait = "0.1"
git-url-parse = "0.4" git-url-parse = "0.4"
# fs/network # fs/network
kxio = "4.0" kxio = "5.0"
native-tls = { version = "0.2", features = ["vendored"] } native-tls = { version = "0.2", features = ["vendored"] }

View file

@ -11,19 +11,21 @@ use git_next_core::{
#[cfg(feature = "forgejo")] #[cfg(feature = "forgejo")]
#[test] #[test]
fn test_forgejo_name() { fn test_forgejo_name() {
let net = kxio::net::mock(); let mock_net = kxio::net::mock();
let repo_details = given_repo_details(git_next_core::ForgeType::ForgeJo); let repo_details = given_repo_details(git_next_core::ForgeType::ForgeJo);
let forge = Forge::create(repo_details, net.into()); let forge = Forge::create(repo_details, mock_net.clone().into());
assert_eq!(forge.name(), "forgejo"); assert_eq!(forge.name(), "forgejo");
mock_net.assert_no_unused_plans();
} }
#[cfg(feature = "github")] #[cfg(feature = "github")]
#[test] #[test]
fn test_github_name() { fn test_github_name() {
let net = kxio::net::mock(); let mock_net = kxio::net::mock();
let repo_details = given_repo_details(git_next_core::ForgeType::GitHub); let repo_details = given_repo_details(git_next_core::ForgeType::GitHub);
let forge = Forge::create(repo_details, net.into()); let forge = Forge::create(repo_details, mock_net.clone().into());
assert_eq!(forge.name(), "github"); assert_eq!(forge.name(), "github");
mock_net.assert_no_unused_plans();
} }
#[allow(dead_code)] #[allow(dead_code)]

View file

@ -35,7 +35,7 @@ async fn should_clone() -> TestResult {
repo_details, repo_details,
given::a_forge(), given::a_forge(),
fs.as_real(), fs.as_real(),
net, net.clone(),
); );
tell!(addr, CloneRepo::new())?; tell!(addr, CloneRepo::new())?;
//then //then
@ -44,6 +44,7 @@ async fn should_clone() -> TestResult {
.read() .read()
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
.map(|o| assert_eq!(o.len(), 1))?; .map(|o| assert_eq!(o.len(), 1))?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -78,7 +79,7 @@ async fn should_open() -> TestResult {
repo_details, repo_details,
given::a_forge(), given::a_forge(),
fs.as_real(), fs.as_real(),
net, net.clone(),
); );
tell!(addr, CloneRepo::new())?; tell!(addr, CloneRepo::new())?;
@ -88,6 +89,7 @@ async fn should_open() -> TestResult {
.read() .read()
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
.map(|o| assert_eq!(o.len(), 1))?; .map(|o| assert_eq!(o.len(), 1))?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -120,13 +122,14 @@ async fn when_server_has_no_repo_config_should_send_load_from_repo() -> TestResu
repo_details, repo_details,
given::a_forge(), given::a_forge(),
fs.as_real(), fs.as_real(),
net, net.clone(),
); );
tell!(addr, CloneRepo::new())?; tell!(addr, CloneRepo::new())?;
//then //then
log.require_message_containing("send: LoadConfigFromRepo") log.require_message_containing("send: LoadConfigFromRepo")
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -156,7 +159,7 @@ async fn when_server_has_repo_config_should_send_register_webhook() -> TestResul
repo_details, repo_details,
given::a_forge(), given::a_forge(),
fs.as_real(), fs.as_real(),
net, net.clone(),
); );
tell!(addr, CloneRepo::new())?; tell!(addr, CloneRepo::new())?;
@ -165,6 +168,7 @@ async fn when_server_has_repo_config_should_send_register_webhook() -> TestResul
debug!(?log, ""); debug!(?log, "");
log.require_message_containing("send: RegisterWebhook") log.require_message_containing("send: RegisterWebhook")
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }

View file

@ -396,7 +396,7 @@ async fn should_accept_message_with_current_token() -> TestResult {
git::repository::factory::mock(), git::repository::factory::mock(),
given::a_forge(), given::a_forge(),
server_actor_ref, server_actor_ref,
net, net.clone(),
); );
let actor = actor.with_message_token(MessageToken::new(2_u32)); let actor = actor.with_message_token(MessageToken::new(2_u32));
let addr = kameo::spawn(actor); let addr = kameo::spawn(actor);
@ -406,6 +406,7 @@ async fn should_accept_message_with_current_token() -> TestResult {
//then //then
log.require_message_containing("accepted token: 2").await?; log.require_message_containing("accepted token: 2").await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -422,7 +423,7 @@ async fn should_accept_message_with_new_token() -> TestResult {
git::repository::factory::mock(), git::repository::factory::mock(),
given::a_forge(), given::a_forge(),
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor.with_message_token(MessageToken::new(2_u32)); let actor = actor.with_message_token(MessageToken::new(2_u32));
let addr = kameo::spawn(actor); let addr = kameo::spawn(actor);
@ -430,6 +431,7 @@ async fn should_accept_message_with_new_token() -> TestResult {
//then //then
log.require_message_containing("accepted token: 3").await?; log.require_message_containing("accepted token: 3").await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -446,7 +448,7 @@ async fn should_reject_message_with_expired_token() -> TestResult {
git::repository::factory::mock(), git::repository::factory::mock(),
given::a_forge(), given::a_forge(),
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor.with_message_token(MessageToken::new(4_u32)); let actor = actor.with_message_token(MessageToken::new(4_u32));
let addr = kameo::spawn(actor); let addr = kameo::spawn(actor);
@ -454,6 +456,7 @@ async fn should_reject_message_with_expired_token() -> TestResult {
//then //then
log.no_message_contains("accepted token").await?; log.no_message_contains("accepted token").await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }

View file

@ -22,7 +22,7 @@ async fn when_no_expected_auth_token_drop_notification() -> TestResult {
Box::new(repository_factory), Box::new(repository_factory),
given::a_forge(), given::a_forge(),
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor.with_webhook_auth(None); let actor = actor.with_webhook_auth(None);
@ -36,6 +36,7 @@ async fn when_no_expected_auth_token_drop_notification() -> TestResult {
log.no_message_contains("send").await?; log.no_message_contains("send").await?;
log.require_message_containing("server has no auth token") log.require_message_containing("server has no auth token")
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -56,7 +57,7 @@ async fn when_no_repo_config_drop_notification() -> TestResult {
Box::new(repository_factory), Box::new(repository_factory),
given::a_forge(), given::a_forge(),
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor.with_webhook_auth(Some(given::a_webhook_auth())); let actor = actor.with_webhook_auth(Some(given::a_webhook_auth()));
@ -70,6 +71,7 @@ async fn when_no_repo_config_drop_notification() -> TestResult {
log.no_message_contains("send").await?; log.no_message_contains("send").await?;
log.require_message_containing("server has no repo config") log.require_message_containing("server has no repo config")
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -94,7 +96,7 @@ async fn when_message_auth_is_invalid_drop_notification() -> TestResult {
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor.with_webhook_auth(Some(given::a_webhook_auth())); let actor = actor.with_webhook_auth(Some(given::a_webhook_auth()));
@ -108,6 +110,7 @@ async fn when_message_auth_is_invalid_drop_notification() -> TestResult {
log.no_message_contains("send").await?; log.no_message_contains("send").await?;
log.require_message_containing("message authorisation is invalid") log.require_message_containing("message authorisation is invalid")
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -136,7 +139,7 @@ async fn when_message_is_ignorable_drop_notification() -> TestResult {
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor.with_webhook_auth(Some(given::a_webhook_auth())); let actor = actor.with_webhook_auth(Some(given::a_webhook_auth()));
@ -150,6 +153,7 @@ async fn when_message_is_ignorable_drop_notification() -> TestResult {
log.no_message_contains("send").await?; log.no_message_contains("send").await?;
log.require_message_containing("forge sent ignorable message") log.require_message_containing("forge sent ignorable message")
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -178,7 +182,7 @@ async fn when_message_is_not_a_push_drop_notification() -> TestResult {
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor.with_webhook_auth(Some(given::a_webhook_auth())); let actor = actor.with_webhook_auth(Some(given::a_webhook_auth()));
@ -192,6 +196,7 @@ async fn when_message_is_not_a_push_drop_notification() -> TestResult {
log.no_message_contains("send").await?; log.no_message_contains("send").await?;
log.require_message_containing("message parse error - not a push") log.require_message_containing("message parse error - not a push")
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -224,7 +229,7 @@ async fn when_message_is_push_on_unknown_branch_drop_notification() -> TestResul
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor let actor = actor
.with_webhook_auth(Some(given::a_webhook_auth())) .with_webhook_auth(Some(given::a_webhook_auth()))
@ -239,6 +244,7 @@ async fn when_message_is_push_on_unknown_branch_drop_notification() -> TestResul
//then //then
log.no_message_contains("send").await?; log.no_message_contains("send").await?;
log.require_message_containing("unknown branch").await?; log.require_message_containing("unknown branch").await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -272,7 +278,7 @@ async fn when_message_is_push_already_seen_commit_to_main() -> TestResult {
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor let actor = actor
.with_webhook_auth(Some(given::a_webhook_auth())) .with_webhook_auth(Some(given::a_webhook_auth()))
@ -288,6 +294,7 @@ async fn when_message_is_push_already_seen_commit_to_main() -> TestResult {
log.no_message_contains("send").await?; log.no_message_contains("send").await?;
log.require_message_containing(format!("not a new commit on {main}")) log.require_message_containing(format!("not a new commit on {main}"))
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -321,7 +328,7 @@ async fn when_message_is_push_already_seen_commit_to_next() -> TestResult {
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor let actor = actor
.with_webhook_auth(Some(given::a_webhook_auth())) .with_webhook_auth(Some(given::a_webhook_auth()))
@ -337,6 +344,7 @@ async fn when_message_is_push_already_seen_commit_to_next() -> TestResult {
log.no_message_contains("send").await?; log.no_message_contains("send").await?;
log.require_message_containing(format!("not a new commit on {next_branch}")) log.require_message_containing(format!("not a new commit on {next_branch}"))
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -370,7 +378,7 @@ async fn when_message_is_push_already_seen_commit_to_dev() -> TestResult {
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor let actor = actor
.with_webhook_auth(Some(given::a_webhook_auth())) .with_webhook_auth(Some(given::a_webhook_auth()))
@ -386,6 +394,7 @@ async fn when_message_is_push_already_seen_commit_to_dev() -> TestResult {
log.no_message_contains("send").await?; log.no_message_contains("send").await?;
log.require_message_containing(format!("not a new commit on {dev}")) log.require_message_containing(format!("not a new commit on {dev}"))
.await?; .await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -418,7 +427,7 @@ async fn when_message_is_push_new_commit_to_main_should_stash_and_validate_repo(
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor let actor = actor
.with_webhook_auth(Some(given::a_webhook_auth())) .with_webhook_auth(Some(given::a_webhook_auth()))
@ -435,6 +444,7 @@ async fn when_message_is_push_new_commit_to_main_should_stash_and_validate_repo(
.map_err(|e| format!("examine actor: {e:?}"))?; .map_err(|e| format!("examine actor: {e:?}"))?;
assert_eq!(view.last_main_commit, Some(push_commit)); assert_eq!(view.last_main_commit, Some(push_commit));
log.require_message_containing("send: ValidateRepo").await?; log.require_message_containing("send: ValidateRepo").await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -467,7 +477,7 @@ async fn when_message_is_push_new_commit_to_next_should_stash_and_validate_repo(
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor let actor = actor
.with_webhook_auth(Some(given::a_webhook_auth())) .with_webhook_auth(Some(given::a_webhook_auth()))
@ -484,6 +494,7 @@ async fn when_message_is_push_new_commit_to_next_should_stash_and_validate_repo(
.map_err(|e| format!("examine actor: {e:?}"))?; .map_err(|e| format!("examine actor: {e:?}"))?;
assert_eq!(view.last_next_commit, Some(push_commit)); assert_eq!(view.last_next_commit, Some(push_commit));
log.require_message_containing("send: ValidateRepo").await?; log.require_message_containing("send: ValidateRepo").await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }
@ -516,7 +527,7 @@ async fn when_message_is_push_new_commit_to_dev_should_stash_and_validate_repo()
Box::new(repository_factory), Box::new(repository_factory),
forge, forge,
given::a_server_actor(fs.as_real(), net.clone()), given::a_server_actor(fs.as_real(), net.clone()),
net, net.clone(),
); );
let actor = actor let actor = actor
.with_webhook_auth(Some(given::a_webhook_auth())) .with_webhook_auth(Some(given::a_webhook_auth()))
@ -533,5 +544,6 @@ async fn when_message_is_push_new_commit_to_dev_should_stash_and_validate_repo()
.map_err(|e| format!("examine actor: {e:?}"))?; .map_err(|e| format!("examine actor: {e:?}"))?;
assert_eq!(view.last_dev_commit, Some(push_commit)); assert_eq!(view.last_dev_commit, Some(push_commit));
log.require_message_containing("send: ValidateRepo").await?; log.require_message_containing("send: ValidateRepo").await?;
net.assert_no_unused_plans();
Ok(()) Ok(())
} }

View file

@ -23,8 +23,8 @@ async fn when_webhook_url_has_trailing_slash_should_not_send() -> TestResult {
//given //given
// parameters // parameters
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let net = given::a_network(); let mock_net = given::a_network();
let alerts = given::an_alerts_actor(net.clone().into()); let alerts = given::an_alerts_actor(mock_net.clone().into());
let repo = git::repository::factory::mock(); let repo = git::repository::factory::mock();
let duration = std::time::Duration::from_millis(1); let duration = std::time::Duration::from_millis(1);
@ -34,7 +34,7 @@ async fn when_webhook_url_has_trailing_slash_should_not_send() -> TestResult {
let server = ServerActor::new( let server = ServerActor::new(
false, // ui false, // ui
fs.as_real(), fs.as_real(),
net.into(), mock_net.clone().into(),
alerts, alerts,
file_update_subs, file_update_subs,
repo, repo,
@ -67,6 +67,7 @@ async fn when_webhook_url_has_trailing_slash_should_not_send() -> TestResult {
assert!(message_log.read().iter().any(|log| !log assert!(message_log.read().iter().any(|log| !log
.iter() .iter()
.any(|line| line == "send: ReceiveValidServerConfig"))); .any(|line| line == "send: ReceiveValidServerConfig")));
mock_net.assert_no_unused_plans();
Ok(()) Ok(())
} }

View file

@ -23,8 +23,10 @@ mod forgejo {
#[test] #[test]
fn should_return_name() { fn should_return_name() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), given::a_network()); let mock_net = given::a_network();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
assert_eq!(forge.name(), "forgejo"); assert_eq!(forge.name(), "forgejo");
mock_net.assert_no_unused_plans();
} }
mod is_message_authorised { mod is_message_authorised {
@ -34,42 +36,52 @@ mod forgejo {
#[test] #[test]
fn should_return_true_with_valid_header() { fn should_return_true_with_valid_header() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), given::a_network()); let mock_net = given::a_network();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
let auth = given::a_webhook_auth(); let auth = given::a_webhook_auth();
let message = given::a_webhook_message(given::Header::Valid(auth.clone())); let message = given::a_webhook_message(given::Header::Valid(auth.clone()));
assert!(forge.is_message_authorised(&message, &auth)); assert!(forge.is_message_authorised(&message, &auth));
mock_net.assert_no_unused_plans();
} }
#[test] #[test]
fn should_return_false_with_missing_header() { fn should_return_false_with_missing_header() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), given::a_network()); let mock_net = given::a_network();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
let auth = given::a_webhook_auth(); let auth = given::a_webhook_auth();
let message = given::a_webhook_message(given::Header::Missing); let message = given::a_webhook_message(given::Header::Missing);
assert!(!forge.is_message_authorised(&message, &auth)); assert!(!forge.is_message_authorised(&message, &auth));
mock_net.assert_no_unused_plans();
} }
#[test] #[test]
fn should_return_false_with_non_basic_prefix() { fn should_return_false_with_non_basic_prefix() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), given::a_network()); let mock_net = given::a_network();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
let auth = given::a_webhook_auth(); let auth = given::a_webhook_auth();
let message = given::a_webhook_message(given::Header::NonBasic); let message = given::a_webhook_message(given::Header::NonBasic);
assert!(!forge.is_message_authorised(&message, &auth)); assert!(!forge.is_message_authorised(&message, &auth));
mock_net.assert_no_unused_plans();
} }
#[test] #[test]
fn should_return_false_with_non_ulid_value() { fn should_return_false_with_non_ulid_value() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), given::a_network()); let mock_net = given::a_network();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
let auth = given::a_webhook_auth(); let auth = given::a_webhook_auth();
let message = given::a_webhook_message(given::Header::NonUlid); let message = given::a_webhook_message(given::Header::NonUlid);
assert!(!forge.is_message_authorised(&message, &auth)); assert!(!forge.is_message_authorised(&message, &auth));
mock_net.assert_no_unused_plans();
} }
#[test] #[test]
fn should_return_false_with_wrong_ulid_value() { fn should_return_false_with_wrong_ulid_value() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), given::a_network()); let mock_net = given::a_network();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
let auth = given::a_webhook_auth(); let auth = given::a_webhook_auth();
let message = given::a_webhook_message(given::Header::WrongUlid); let message = given::a_webhook_message(given::Header::WrongUlid);
assert!(!forge.is_message_authorised(&message, &auth)); assert!(!forge.is_message_authorised(&message, &auth));
mock_net.assert_no_unused_plans();
} }
} }
@ -80,7 +92,8 @@ mod forgejo {
#[test] #[test]
fn should_parse_valid_body() { fn should_parse_valid_body() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), given::a_network()); let mock_net = given::a_network();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
let repo_branches = given::repo_branches(); let repo_branches = given::repo_branches();
let next = repo_branches.next(); let next = repo_branches.next();
let sha = given::a_name(); let sha = given::a_name();
@ -96,16 +109,19 @@ mod forgejo {
push.branch(&repo_branches), push.branch(&repo_branches),
Some(git_next_core::webhook::push::Branch::Next) Some(git_next_core::webhook::push::Branch::Next)
); );
mock_net.assert_no_unused_plans();
} }
#[test] #[test]
fn should_error_invalid_body() { fn should_error_invalid_body() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), given::a_network()); let mock_net = given::a_network();
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
let body = git_next_core::webhook::forge_notification::Body::new( let body = git_next_core::webhook::forge_notification::Body::new(
r#"{"type":"invalid"}"#.to_string(), r#"{"type":"invalid"}"#.to_string(),
); );
let_assert!(Err(_) = forge.parse_webhook_body(&body)); let_assert!(Err(_) = forge.parse_webhook_body(&body));
mock_net.assert_no_unused_plans();
} }
} }
@ -118,73 +134,79 @@ mod forgejo {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let repo_details = given::repo_details(&fs); let repo_details = given::repo_details(&fs);
let commit = given::a_commit(); let commit = given::a_commit();
let net = given::a_network(); let mock_net = given::a_network();
given::a_commit_state("success", &net, &repo_details, &commit); given::a_commit_state("success", &mock_net, &repo_details, &commit);
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
assert_eq!( assert_eq!(
forge.commit_status(&commit).await.expect("status"), forge.commit_status(&commit).await.expect("status"),
Status::Pass Status::Pass
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
async fn should_return_pending_for_pending() { async fn should_return_pending_for_pending() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let repo_details = given::repo_details(&fs); let repo_details = given::repo_details(&fs);
let commit = given::a_commit(); let commit = given::a_commit();
let net = given::a_network(); let mock_net = given::a_network();
given::a_commit_state("pending", &net, &repo_details, &commit); given::a_commit_state("pending", &mock_net, &repo_details, &commit);
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
assert_eq!( assert_eq!(
forge.commit_status(&commit).await.expect("status"), forge.commit_status(&commit).await.expect("status"),
Status::Pending Status::Pending
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
async fn should_return_fail_for_failure() { async fn should_return_fail_for_failure() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let repo_details = given::repo_details(&fs); let repo_details = given::repo_details(&fs);
let commit = given::a_commit(); let commit = given::a_commit();
let net = given::a_network(); let mock_net = given::a_network();
given::a_commit_state("failure", &net, &repo_details, &commit); given::a_commit_state("failure", &mock_net, &repo_details, &commit);
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
assert_eq!( assert_eq!(
forge.commit_status(&commit).await.expect("status"), forge.commit_status(&commit).await.expect("status"),
Status::Fail Status::Fail
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
async fn should_return_fail_for_error() { async fn should_return_fail_for_error() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let repo_details = given::repo_details(&fs); let repo_details = given::repo_details(&fs);
let commit = given::a_commit(); let commit = given::a_commit();
let net = given::a_network(); let mock_net = given::a_network();
given::a_commit_state("error", &net, &repo_details, &commit); given::a_commit_state("error", &mock_net, &repo_details, &commit);
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
assert_eq!( assert_eq!(
forge.commit_status(&commit).await.expect("status"), forge.commit_status(&commit).await.expect("status"),
Status::Fail Status::Fail
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
async fn should_return_pending_for_blank() { async fn should_return_pending_for_blank() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let repo_details = given::repo_details(&fs); let repo_details = given::repo_details(&fs);
let commit = given::a_commit(); let commit = given::a_commit();
let net = given::a_network(); let mock_net = given::a_network();
given::a_commit_state("", &net, &repo_details, &commit); given::a_commit_state("", &mock_net, &repo_details, &commit);
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
assert_eq!( assert_eq!(
forge.commit_status(&commit).await.expect("status"), forge.commit_status(&commit).await.expect("status"),
Status::Pending Status::Pending
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
async fn should_return_pending_for_no_statuses() { async fn should_return_pending_for_no_statuses() {
let fs = given::a_filesystem(); let fs = given::a_filesystem();
let repo_details = given::repo_details(&fs); let repo_details = given::repo_details(&fs);
let commit = given::a_commit(); let commit = given::a_commit();
let net = given::a_network(); let mock_net = given::a_network();
net.on() mock_net
.on()
.get(given::a_commit_status_url(&repo_details, &commit)) .get(given::a_commit_status_url(&repo_details, &commit))
.respond(StatusCode::OK) .respond(StatusCode::OK)
.body( .body(
@ -194,11 +216,12 @@ mod forgejo {
.to_string(), .to_string(),
) )
.expect("mock"); .expect("mock");
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
assert_eq!( assert_eq!(
forge.commit_status(&commit).await.expect("status"), forge.commit_status(&commit).await.expect("status"),
Status::Pending Status::Pending
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
async fn should_return_pending_for_network_error() { async fn should_return_pending_for_network_error() {
@ -212,11 +235,12 @@ mod forgejo {
.respond(StatusCode::INTERNAL_SERVER_ERROR) .respond(StatusCode::INTERNAL_SERVER_ERROR)
.body("book today") .body("book today")
.expect("mock"); .expect("mock");
let forge = given::a_forgejo_forge(&repo_details, mock_net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
assert_eq!( assert_eq!(
forge.commit_status(&commit).await.expect("status"), forge.commit_status(&commit).await.expect("status"),
Status::Pending Status::Pending
); );
mock_net.assert_no_unused_plans();
} }
} }
@ -235,10 +259,10 @@ mod forgejo {
let hook_id_1 = given::a_forgejo_webhook_id(); let hook_id_1 = given::a_forgejo_webhook_id();
let hook_id_2 = given::a_forgejo_webhook_id(); let hook_id_2 = given::a_forgejo_webhook_id();
let hook_id_3 = given::a_forgejo_webhook_id(); let hook_id_3 = given::a_forgejo_webhook_id();
let mut net = given::a_network(); let mock_net = given::a_network();
let mut args = with::WebhookArgs { let mut args = with::WebhookArgs {
net: &mut net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
token, token,
@ -256,7 +280,7 @@ mod forgejo {
// page 2 with no items - stops pagination // page 2 with no items - stops pagination
with::get_webhooks_by_page(2, &[], &mut args); with::get_webhooks_by_page(2, &[], &mut args);
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
let_assert!(Ok(result) = forge.list_webhooks(&repo_listen_url).await); let_assert!(Ok(result) = forge.list_webhooks(&repo_listen_url).await);
assert_eq!( assert_eq!(
@ -266,6 +290,7 @@ mod forgejo {
WebhookId::new(format!("{hook_id_2}")) WebhookId::new(format!("{hook_id_2}"))
] ]
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -276,9 +301,10 @@ mod forgejo {
let hostname = repo_details.forge.hostname(); let hostname = repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let token = repo_details.forge.token().expose_secret(); let token = repo_details.forge.token().expose_secret();
let net = given::a_network(); let mock_net = given::a_network();
net.on() mock_net
.on()
.get(format!( .get(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks?page=1&token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks?page=1&token={token}"
)) ))
@ -286,9 +312,10 @@ mod forgejo {
.body("error_message") .body("error_message")
.expect("mock"); .expect("mock");
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
let_assert!(Err(_) = forge.list_webhooks(&repo_listen_url).await); let_assert!(Err(_) = forge.list_webhooks(&repo_listen_url).await);
mock_net.assert_no_unused_plans();
} }
} }
@ -303,9 +330,10 @@ mod forgejo {
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let token = repo_details.forge.token().expose_secret(); let token = repo_details.forge.token().expose_secret();
let webhook_id = given::a_webhook_id(); let webhook_id = given::a_webhook_id();
let net = given::a_network(); let mock_net = given::a_network();
net.on() mock_net
.on()
.delete(format!( .delete(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}"
)) ))
@ -313,9 +341,10 @@ mod forgejo {
.body("") .body("")
.expect("mock"); .expect("mock");
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
let_assert!(Ok(()) = forge.unregister_webhook(&webhook_id).await); let_assert!(Ok(()) = forge.unregister_webhook(&webhook_id).await);
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -326,9 +355,10 @@ mod forgejo {
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let token = repo_details.forge.token().expose_secret(); let token = repo_details.forge.token().expose_secret();
let webhook_id = given::a_webhook_id(); let webhook_id = given::a_webhook_id();
let net = given::a_network(); let mock_net = given::a_network();
net.on() mock_net
.on()
.delete(format!( .delete(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}"
)) ))
@ -336,13 +366,14 @@ mod forgejo {
.body("error") .body("error")
.expect("mock"); .expect("mock");
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
let_assert!(Err(err) = forge.unregister_webhook(&webhook_id).await); let_assert!(Err(err) = forge.unregister_webhook(&webhook_id).await);
assert!( assert!(
matches!(err, git::forge::webhook::Error::FailedToUnregister(_)), matches!(err, git::forge::webhook::Error::FailedToUnregister(_)),
"{err:?}" "{err:?}"
); );
mock_net.assert_no_unused_plans();
} }
} }
@ -362,9 +393,9 @@ mod forgejo {
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let token = repo_details.forge.token().expose_secret(); let token = repo_details.forge.token().expose_secret();
let mut net = given::a_network(); let mock_net = given::a_network();
let mut args = with::WebhookArgs { let mut args = with::WebhookArgs {
net: &mut net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
token, token,
@ -374,7 +405,8 @@ mod forgejo {
with::get_webhooks_by_page(1, &[], &mut args); with::get_webhooks_by_page(1, &[], &mut args);
// register the webhook will succeed // register the webhook will succeed
let webhook_id = given::a_forgejo_webhook_id(); let webhook_id = given::a_forgejo_webhook_id();
net.on() mock_net
.on()
.post(format!( .post(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}"
)) ))
@ -382,13 +414,14 @@ mod forgejo {
.body(json!({"id": webhook_id, "config":{}}).to_string()) .body(json!({"id": webhook_id, "config":{}}).to_string())
.expect("mock"); .expect("mock");
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
let_assert!(Ok(registered_webhook) = forge.register_webhook(&repo_listen_url).await); let_assert!(Ok(registered_webhook) = forge.register_webhook(&repo_listen_url).await);
assert_eq!( assert_eq!(
registered_webhook.id(), registered_webhook.id(),
&WebhookId::new(format!("{webhook_id}")) &WebhookId::new(format!("{webhook_id}"))
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -401,13 +434,14 @@ mod forgejo {
"repo_details needs to NOT have repo_config for this test" "repo_details needs to NOT have repo_config for this test"
); );
let repo_listen_url = given::a_repo_listen_url(&repo_details); let repo_listen_url = given::a_repo_listen_url(&repo_details);
let net = given::a_network(); let mock_net = given::a_network();
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await); let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await);
assert!( assert!(
matches!(err, git::forge::webhook::Error::NoRepoConfig), matches!(err, git::forge::webhook::Error::NoRepoConfig),
"{err:?}" "{err:?}"
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -423,9 +457,9 @@ mod forgejo {
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let token = repo_details.forge.token().expose_secret(); let token = repo_details.forge.token().expose_secret();
let mut net = given::a_network(); let mock_net = given::a_network();
let mut args = with::WebhookArgs { let mut args = with::WebhookArgs {
net: &mut net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
token, token,
@ -448,7 +482,8 @@ mod forgejo {
with::unregister_webhook(&hooks[1], &mut args); with::unregister_webhook(&hooks[1], &mut args);
// register the webhook will succeed // register the webhook will succeed
let webhook_id = given::a_forgejo_webhook_id(); let webhook_id = given::a_forgejo_webhook_id();
net.on() mock_net
.on()
.post(format!( .post(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}"
)) ))
@ -456,13 +491,14 @@ mod forgejo {
.body(json!({"id": webhook_id, "config":{}}).to_string()) .body(json!({"id": webhook_id, "config":{}}).to_string())
.expect("mock"); .expect("mock");
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
let_assert!(Ok(registered_webhook) = forge.register_webhook(&repo_listen_url).await); let_assert!(Ok(registered_webhook) = forge.register_webhook(&repo_listen_url).await);
assert_eq!( assert_eq!(
registered_webhook.id(), registered_webhook.id(),
&WebhookId::new(format!("{webhook_id}")) &WebhookId::new(format!("{webhook_id}"))
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -478,9 +514,9 @@ mod forgejo {
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let token = repo_details.forge.token().expose_secret(); let token = repo_details.forge.token().expose_secret();
let mut net = given::a_network(); let mock_net = given::a_network();
let mut args = with::WebhookArgs { let mut args = with::WebhookArgs {
net: &mut net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
token, token,
@ -489,7 +525,8 @@ mod forgejo {
// there are no existing matching webhooks // there are no existing matching webhooks
with::get_webhooks_by_page(1, &[], &mut args); with::get_webhooks_by_page(1, &[], &mut args);
// register the webhook will return empty response // register the webhook will return empty response
net.on() mock_net
.on()
.post(format!( .post(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}"
)) ))
@ -497,13 +534,14 @@ mod forgejo {
.body(json!({}).to_string()) // empty response) .body(json!({}).to_string()) // empty response)
.expect("mock"); .expect("mock");
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await); let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await);
assert!( assert!(
matches!(err, git::forge::webhook::Error::NetworkResponseEmpty), matches!(err, git::forge::webhook::Error::NetworkResponseEmpty),
"{err:?}" "{err:?}"
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -519,9 +557,9 @@ mod forgejo {
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let token = repo_details.forge.token().expose_secret(); let token = repo_details.forge.token().expose_secret();
let mut net = given::a_network(); let mock_net = given::a_network();
let mut args = with::WebhookArgs { let mut args = with::WebhookArgs {
net: &mut net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
token, token,
@ -530,7 +568,8 @@ mod forgejo {
// there are no existing matching webhooks // there are no existing matching webhooks
with::get_webhooks_by_page(1, &[], &mut args); with::get_webhooks_by_page(1, &[], &mut args);
// register the webhook will return empty response // register the webhook will return empty response
net.on() mock_net
.on()
.post(format!( .post(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}"
)) ))
@ -538,13 +577,14 @@ mod forgejo {
.body("error") .body("error")
.expect("mock"); .expect("mock");
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, mock_net.clone());
let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await); let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await);
assert!( assert!(
matches!(err, git::forge::webhook::Error::FailedToRegister(_)), matches!(err, git::forge::webhook::Error::FailedToRegister(_)),
"{err:?}" "{err:?}"
); );
mock_net.assert_no_unused_plans();
} }
} }
mod with { mod with {
@ -559,7 +599,7 @@ mod forgejo {
let hostname = args.hostname; let hostname = args.hostname;
let repo_path = args.repo_path; let repo_path = args.repo_path;
let token = args.token; let token = args.token;
args.net args.mock_net
.on() .on()
.get(format!( .get(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks?page={page}&token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks?page={page}&token={token}"
@ -573,7 +613,7 @@ mod forgejo {
let hostname = args.hostname; let hostname = args.hostname;
let repo_path = args.repo_path; let repo_path = args.repo_path;
let token = args.token; let token = args.token;
args.net args.mock_net
.on() .on()
.delete(format!( .delete(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}"
@ -583,7 +623,7 @@ mod forgejo {
.expect("mock"); .expect("mock");
} }
pub struct WebhookArgs<'a> { pub struct WebhookArgs<'a> {
pub net: &'a MockNet, pub mock_net: &'a MockNet,
pub hostname: &'a Hostname, pub hostname: &'a Hostname,
pub repo_path: &'a RepoPath, pub repo_path: &'a RepoPath,
pub token: &'a str, pub token: &'a str,

View file

@ -23,8 +23,10 @@ mod github {
#[test] #[test]
fn should_return_name() { fn should_return_name() {
let forge = given::a_github_forge(&given::repo_details(), given::a_network()); let mock_net = given::a_network();
let forge = given::a_github_forge(&given::repo_details(), mock_net.clone());
assert_eq!(forge.name(), "github"); assert_eq!(forge.name(), "github");
mock_net.assert_no_unused_plans();
} }
mod is_message_authorised { mod is_message_authorised {
@ -33,27 +35,33 @@ mod github {
#[test] #[test]
fn should_return_true_with_valid_header() { fn should_return_true_with_valid_header() {
let forge = given::a_github_forge(&given::repo_details(), given::a_network()); let mock_net = given::a_network();
let forge = given::a_github_forge(&given::repo_details(), mock_net.clone());
let auth = given::a_webhook_auth(); let auth = given::a_webhook_auth();
let message = given::a_webhook_message(given::Header::Valid( let message = given::a_webhook_message(given::Header::Valid(
auth.clone(), auth.clone(),
given::a_webhook_message_body(), given::a_webhook_message_body(),
)); ));
assert!(forge.is_message_authorised(&message, &auth)); assert!(forge.is_message_authorised(&message, &auth));
mock_net.assert_no_unused_plans();
} }
#[test] #[test]
fn should_return_false_with_missing_header() { fn should_return_false_with_missing_header() {
let forge = given::a_github_forge(&given::repo_details(), given::a_network()); let mock_net = given::a_network();
let forge = given::a_github_forge(&given::repo_details(), mock_net.clone());
let auth = given::a_webhook_auth(); let auth = given::a_webhook_auth();
let message = given::a_webhook_message(given::Header::Missing); let message = given::a_webhook_message(given::Header::Missing);
assert!(!forge.is_message_authorised(&message, &auth)); assert!(!forge.is_message_authorised(&message, &auth));
mock_net.assert_no_unused_plans();
} }
#[test] #[test]
fn should_return_false_with_invalid_header() { fn should_return_false_with_invalid_header() {
let forge = given::a_github_forge(&given::repo_details(), given::a_network()); let mock_net = given::a_network();
let forge = given::a_github_forge(&given::repo_details(), mock_net.clone());
let auth = given::a_webhook_auth(); let auth = given::a_webhook_auth();
let message = given::a_webhook_message(given::Header::Invalid); let message = given::a_webhook_message(given::Header::Invalid);
assert!(!forge.is_message_authorised(&message, &auth)); assert!(!forge.is_message_authorised(&message, &auth));
mock_net.assert_no_unused_plans();
} }
} }
@ -63,7 +71,8 @@ mod github {
#[test] #[test]
fn should_parse_valid_body() { fn should_parse_valid_body() {
let forge = given::a_github_forge(&given::repo_details(), given::a_network()); let mock_net = given::a_network();
let forge = given::a_github_forge(&given::repo_details(), mock_net.clone());
let repo_branches = given::repo_branches(); let repo_branches = given::repo_branches();
let next = repo_branches.next(); let next = repo_branches.next();
let sha = given::a_name(); let sha = given::a_name();
@ -79,13 +88,16 @@ mod github {
push.branch(&repo_branches), push.branch(&repo_branches),
Some(webhook::push::Branch::Next) Some(webhook::push::Branch::Next)
); );
mock_net.assert_no_unused_plans();
} }
#[test] #[test]
fn should_error_invalid_body() { fn should_error_invalid_body() {
let forge = given::a_github_forge(&given::repo_details(), given::a_network()); let mock_net = given::a_network();
let forge = given::a_github_forge(&given::repo_details(), mock_net.clone());
let body = Body::new(r#"{"type":"invalid"}"#.to_string()); let body = Body::new(r#"{"type":"invalid"}"#.to_string());
let_assert!(Err(_) = forge.parse_webhook_body(&body)); let_assert!(Err(_) = forge.parse_webhook_body(&body));
mock_net.assert_no_unused_plans();
} }
} }
@ -101,10 +113,11 @@ mod github {
let (states, expected) = $value; let (states, expected) = $value;
let repo_details = given::repo_details(); let repo_details = given::repo_details();
let commit = given::a_commit(); let commit = given::a_commit();
let net = given::a_network(); let mock_net = given::a_network();
given::commit_states(&states, &net, &repo_details, &commit); given::commit_states(&states, &mock_net, &repo_details, &commit);
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
assert_eq!(forge.commit_status(&commit).await.expect("status"), expected); assert_eq!(forge.commit_status(&commit).await.expect("status"), expected);
mock_net.assert_no_unused_plans();
} }
)* )*
} }
@ -130,34 +143,38 @@ mod github {
async fn should_return_pass_for_no_statuses() { async fn should_return_pass_for_no_statuses() {
let repo_details = given::repo_details(); let repo_details = given::repo_details();
let commit = given::a_commit(); let commit = given::a_commit();
let net = given::a_network(); let mock_net = given::a_network();
net.on() mock_net
.on()
.get(given::a_commit_status_url(&repo_details, &commit)) .get(given::a_commit_status_url(&repo_details, &commit))
.respond(StatusCode::OK) .respond(StatusCode::OK)
.body(json!([]).to_string()) .body(json!([]).to_string())
.expect("mock"); .expect("mock");
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
assert_eq!( assert_eq!(
forge.commit_status(&commit).await.expect("status"), forge.commit_status(&commit).await.expect("status"),
Status::Pass // no CI checks configured Status::Pass // no CI checks configured
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
async fn should_return_pending_for_network_error() { async fn should_return_pending_for_network_error() {
let repo_details = given::repo_details(); let repo_details = given::repo_details();
let commit = given::a_commit(); let commit = given::a_commit();
let net = given::a_network(); let mock_net = given::a_network();
net.on() mock_net
.on()
.get(given::a_commit_status_url(&repo_details, &commit)) .get(given::a_commit_status_url(&repo_details, &commit))
.respond(StatusCode::INTERNAL_SERVER_ERROR) .respond(StatusCode::INTERNAL_SERVER_ERROR)
.body("boom today") .body("boom today")
.expect("mock"); .expect("mock");
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
assert_eq!( assert_eq!(
forge.commit_status(&commit).await.expect("status"), forge.commit_status(&commit).await.expect("status"),
Status::Pending Status::Pending
); );
mock_net.assert_no_unused_plans();
} }
} }
@ -174,9 +191,9 @@ mod github {
let hook_id_1 = given::a_github_webhook_id(); let hook_id_1 = given::a_github_webhook_id();
let hook_id_2 = given::a_github_webhook_id(); let hook_id_2 = given::a_github_webhook_id();
let hook_id_3 = given::a_github_webhook_id(); let hook_id_3 = given::a_github_webhook_id();
let net = given::a_network(); let mock_net = given::a_network();
let args = with::WebhookArgs { let args = with::WebhookArgs {
net: &net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
}; };
@ -193,7 +210,7 @@ mod github {
// page 2 with no items - stops pagination // page 2 with no items - stops pagination
with::get_webhooks_by_page(2, &[], &args); with::get_webhooks_by_page(2, &[], &args);
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
let_assert!(Ok(result) = forge.list_webhooks(&repo_listen_url).await); let_assert!(Ok(result) = forge.list_webhooks(&repo_listen_url).await);
assert_eq!( assert_eq!(
@ -203,6 +220,7 @@ mod github {
WebhookId::new(format!("{hook_id_2}")) WebhookId::new(format!("{hook_id_2}"))
] ]
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -211,8 +229,9 @@ mod github {
let repo_listen_url = given::a_repo_listen_url(&repo_details); let repo_listen_url = given::a_repo_listen_url(&repo_details);
let hostname = repo_details.forge.hostname(); let hostname = repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let net = given::a_network(); let mock_net = given::a_network();
net.on() mock_net
.on()
.get(format!( .get(format!(
"https://api.{hostname}/repos/{repo_path}/hooks?page=1" "https://api.{hostname}/repos/{repo_path}/hooks?page=1"
)) ))
@ -220,9 +239,10 @@ mod github {
.body("error_message") .body("error_message")
.expect("mock"); .expect("mock");
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
let_assert!(Err(_) = forge.list_webhooks(&repo_listen_url).await); let_assert!(Err(_) = forge.list_webhooks(&repo_listen_url).await);
mock_net.assert_no_unused_plans();
} }
} }
@ -235,8 +255,9 @@ mod github {
let hostname = repo_details.forge.hostname(); let hostname = repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let webhook_id = given::a_webhook_id(); let webhook_id = given::a_webhook_id();
let net = given::a_network(); let mock_net = given::a_network();
net.on() mock_net
.on()
.delete(format!( .delete(format!(
"https://api.{hostname}/repos/{repo_path}/hooks/{webhook_id}" "https://api.{hostname}/repos/{repo_path}/hooks/{webhook_id}"
)) ))
@ -244,9 +265,10 @@ mod github {
.body("") .body("")
.expect("mock"); .expect("mock");
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
let_assert!(Ok(()) = forge.unregister_webhook(&webhook_id).await); let_assert!(Ok(()) = forge.unregister_webhook(&webhook_id).await);
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
async fn should_return_error_on_network_error() { async fn should_return_error_on_network_error() {
@ -257,10 +279,11 @@ mod github {
); );
let hostname = repo_details.forge.hostname(); let hostname = repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let net = given::a_network(); let mock_net = given::a_network();
// unregister the webhook will return empty response // unregister the webhook will return empty response
let webhook_id = given::a_webhook_id(); let webhook_id = given::a_webhook_id();
net.on() mock_net
.on()
.delete(format!( .delete(format!(
"https://api.{hostname}/repos/{repo_path}/hooks/{webhook_id}" "https://api.{hostname}/repos/{repo_path}/hooks/{webhook_id}"
)) ))
@ -268,13 +291,14 @@ mod github {
.mock() .mock()
.expect("mock"); .expect("mock");
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
let_assert!(Err(err) = forge.unregister_webhook(&webhook_id).await); let_assert!(Err(err) = forge.unregister_webhook(&webhook_id).await);
assert!( assert!(
matches!(err, git::forge::webhook::Error::FailedToRegister(_)), matches!(err, git::forge::webhook::Error::FailedToRegister(_)),
"{err:?}" "{err:?}"
); );
mock_net.assert_no_unused_plans();
} }
} }
@ -292,9 +316,9 @@ mod github {
let repo_listen_url = given::a_repo_listen_url(&repo_details); let repo_listen_url = given::a_repo_listen_url(&repo_details);
let hostname = repo_details.forge.hostname(); let hostname = repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let net = given::a_network(); let mock_net = given::a_network();
let args = with::WebhookArgs { let args = with::WebhookArgs {
net: &net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
}; };
@ -302,7 +326,8 @@ mod github {
with::get_webhooks_by_page(1, &[], &args); with::get_webhooks_by_page(1, &[], &args);
// register the webhook will succeed // register the webhook will succeed
let webhook_id = given::a_github_webhook_id(); let webhook_id = given::a_github_webhook_id();
net.on() mock_net
.on()
.post(format!("https://api.{hostname}/repos/{repo_path}/hooks")) .post(format!("https://api.{hostname}/repos/{repo_path}/hooks"))
.respond(StatusCode::OK) .respond(StatusCode::OK)
.body( .body(
@ -311,13 +336,14 @@ mod github {
) )
.expect("mock"); .expect("mock");
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
let_assert!(Ok(registered_webhook) = forge.register_webhook(&repo_listen_url).await); let_assert!(Ok(registered_webhook) = forge.register_webhook(&repo_listen_url).await);
assert_eq!( assert_eq!(
registered_webhook.id(), registered_webhook.id(),
&WebhookId::new(format!("{webhook_id}")) &WebhookId::new(format!("{webhook_id}"))
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -329,13 +355,14 @@ mod github {
"repo_details needs to NOT have repo_config for this test" "repo_details needs to NOT have repo_config for this test"
); );
let repo_listen_url = given::a_repo_listen_url(&repo_details); let repo_listen_url = given::a_repo_listen_url(&repo_details);
let net = given::a_network(); let mock_net = given::a_network();
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await); let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await);
assert!( assert!(
matches!(err, git::forge::webhook::Error::NoRepoConfig), matches!(err, git::forge::webhook::Error::NoRepoConfig),
"{err:?}" "{err:?}"
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -348,9 +375,9 @@ mod github {
let repo_listen_url = given::a_repo_listen_url(&repo_details); let repo_listen_url = given::a_repo_listen_url(&repo_details);
let hostname = repo_details.forge.hostname(); let hostname = repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let net = given::a_network(); let mock_net = given::a_network();
let args = with::WebhookArgs { let args = with::WebhookArgs {
net: &net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
}; };
@ -367,7 +394,8 @@ mod github {
with::unregister_webhook(&hooks[1], &args); with::unregister_webhook(&hooks[1], &args);
// register the webhook will succeed // register the webhook will succeed
let webhook_id = given::a_github_webhook_id(); let webhook_id = given::a_github_webhook_id();
net.on() mock_net
.on()
.post(format!("https://api.{hostname}/repos/{repo_path}/hooks")) .post(format!("https://api.{hostname}/repos/{repo_path}/hooks"))
.respond(StatusCode::OK) .respond(StatusCode::OK)
.body( .body(
@ -376,13 +404,14 @@ mod github {
) )
.expect("mock"); .expect("mock");
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
let_assert!(Ok(registered_webhook) = forge.register_webhook(&repo_listen_url).await); let_assert!(Ok(registered_webhook) = forge.register_webhook(&repo_listen_url).await);
assert_eq!( assert_eq!(
registered_webhook.id(), registered_webhook.id(),
&WebhookId::new(format!("{webhook_id}")) &WebhookId::new(format!("{webhook_id}"))
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -395,28 +424,30 @@ mod github {
let repo_listen_url = given::a_repo_listen_url(&repo_details); let repo_listen_url = given::a_repo_listen_url(&repo_details);
let hostname = repo_details.forge.hostname(); let hostname = repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let net = given::a_network(); let mock_net = given::a_network();
let args = with::WebhookArgs { let args = with::WebhookArgs {
net: &net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
}; };
// there are no existing matching webhooks // there are no existing matching webhooks
with::get_webhooks_by_page(1, &[], &args); with::get_webhooks_by_page(1, &[], &args);
// register the webhook will return empty response // register the webhook will return empty response
net.on() mock_net
.on()
.post(format!("https://api.{hostname}/repos/{repo_path}/hooks")) .post(format!("https://api.{hostname}/repos/{repo_path}/hooks"))
.respond(StatusCode::OK) .respond(StatusCode::OK)
.body(json!({}).to_string()) .body(json!({}).to_string())
.expect("mock"); .expect("mock");
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await); let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await);
assert!( assert!(
matches!(err, git::forge::webhook::Error::NetworkResponseEmpty), matches!(err, git::forge::webhook::Error::NetworkResponseEmpty),
"{err:?}" "{err:?}"
); );
mock_net.assert_no_unused_plans();
} }
#[tokio::test] #[tokio::test]
@ -429,28 +460,30 @@ mod github {
let repo_listen_url = given::a_repo_listen_url(&repo_details); let repo_listen_url = given::a_repo_listen_url(&repo_details);
let hostname = repo_details.forge.hostname(); let hostname = repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
let net = given::a_network(); let mock_net = given::a_network();
let args = with::WebhookArgs { let args = with::WebhookArgs {
net: &net, mock_net: &mock_net,
hostname, hostname,
repo_path, repo_path,
}; };
// there are no existing matching webhooks // there are no existing matching webhooks
with::get_webhooks_by_page(1, &[], &args); with::get_webhooks_by_page(1, &[], &args);
// register the webhook will return empty response // register the webhook will return empty response
net.on() mock_net
.on()
.post(format!("https://api.{hostname}/repos/{repo_path}/hooks")) .post(format!("https://api.{hostname}/repos/{repo_path}/hooks"))
.respond(StatusCode::INTERNAL_SERVER_ERROR) .respond(StatusCode::INTERNAL_SERVER_ERROR)
.body("error") .body("error")
.expect("mock"); .expect("mock");
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, mock_net.clone());
let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await); let_assert!(Err(err) = forge.register_webhook(&repo_listen_url).await);
assert!( assert!(
matches!(err, git::forge::webhook::Error::FailedToRegister(_)), matches!(err, git::forge::webhook::Error::FailedToRegister(_)),
"{err:?}" "{err:?}"
); );
mock_net.assert_no_unused_plans();
} }
} }
@ -462,7 +495,7 @@ mod github {
pub fn get_webhooks_by_page(page: u8, response: &[ReturnedWebhook], args: &WebhookArgs) { pub fn get_webhooks_by_page(page: u8, response: &[ReturnedWebhook], args: &WebhookArgs) {
let hostname = args.hostname; let hostname = args.hostname;
let repo_path = args.repo_path; let repo_path = args.repo_path;
args.net args.mock_net
.on() .on()
.get(format!( .get(format!(
"https://api.{hostname}/repos/{repo_path}/hooks?page={page}" "https://api.{hostname}/repos/{repo_path}/hooks?page={page}"
@ -476,7 +509,7 @@ mod github {
let webhook_id = hook1.id; let webhook_id = hook1.id;
let hostname = args.hostname; let hostname = args.hostname;
let repo_path = args.repo_path; let repo_path = args.repo_path;
args.net args.mock_net
.on() .on()
.delete(format!( .delete(format!(
"https://api.{hostname}/repos/{repo_path}/hooks/{webhook_id}" "https://api.{hostname}/repos/{repo_path}/hooks/{webhook_id}"
@ -486,7 +519,7 @@ mod github {
.expect("mock"); .expect("mock");
} }
pub struct WebhookArgs<'a> { pub struct WebhookArgs<'a> {
pub net: &'a kxio::net::MockNet, pub mock_net: &'a kxio::net::MockNet,
pub hostname: &'a Hostname, pub hostname: &'a Hostname,
pub repo_path: &'a RepoPath, pub repo_path: &'a RepoPath,
} }

2
mise.linux.toml Normal file
View file

@ -0,0 +1,2 @@
[tools]
"cargo:cargo-hack" = "latest"