test: add some tests
All checks were successful
ci/woodpecker/push/cron-docker-builder Pipeline was successful
ci/woodpecker/push/push-next Pipeline was successful
ci/woodpecker/push/tag-created Pipeline was successful

This commit is contained in:
Paul Campbell 2024-05-14 07:59:31 +01:00
parent a7e7d12928
commit ac3e1be261
14 changed files with 206 additions and 47 deletions

View file

@ -56,10 +56,10 @@ derive_more = { workspace = true }
# actix-rt = { workspace = true } # actix-rt = { workspace = true }
# tokio = { workspace = true } # tokio = { workspace = true }
# #
# [dev-dependencies] [dev-dependencies]
# # Testing # # Testing
# assert2 = { workspace = true } assert2 = { workspace = true }
# pretty_assertions = { workspace = true } pretty_assertions = { workspace = true }
# test-log = { workspace = true } # test-log = { workspace = true }
# anyhow = { workspace = true } # anyhow = { workspace = true }

View file

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::collections::BTreeMap;
use crate::{ApiToken, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User}; use crate::{ApiToken, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User};
@ -11,7 +11,7 @@ pub struct ForgeConfig {
pub hostname: String, pub hostname: String,
pub user: String, pub user: String,
pub token: String, pub token: String,
pub repos: HashMap<String, ServerRepoConfig>, pub repos: BTreeMap<String, ServerRepoConfig>,
} }
impl ForgeConfig { impl ForgeConfig {
pub const fn forge_type(&self) -> ForgeType { pub const fn forge_type(&self) -> ForgeType {
@ -19,7 +19,7 @@ impl ForgeConfig {
} }
pub fn hostname(&self) -> Hostname { pub fn hostname(&self) -> Hostname {
Hostname(self.hostname.clone()) Hostname::new(&self.hostname)
} }
pub fn user(&self) -> User { pub fn user(&self) -> User {
@ -33,6 +33,6 @@ impl ForgeConfig {
pub fn repos(&self) -> impl Iterator<Item = (RepoAlias, &ServerRepoConfig)> { pub fn repos(&self) -> impl Iterator<Item = (RepoAlias, &ServerRepoConfig)> {
self.repos self.repos
.iter() .iter()
.map(|(name, repo)| (RepoAlias(name.clone()), repo)) .map(|(name, repo)| (RepoAlias::new(name), repo))
} }
} }

View file

@ -1,3 +1,8 @@
/// The hostname of a forge /// The hostname of a forge
#[derive(Clone, Debug, PartialEq, Eq, derive_more::Display)] #[derive(Clone, Debug, PartialEq, Eq, derive_more::Display)]
pub struct Hostname(pub String); pub struct Hostname(String);
impl Hostname {
pub fn new(str: impl Into<String>) -> Self {
Self(str.into())
}
}

View file

@ -15,6 +15,9 @@ mod repo_path;
mod server_repo_config; mod server_repo_config;
mod user; mod user;
#[cfg(test)]
mod tests;
pub use api_token::ApiToken; pub use api_token::ApiToken;
pub use branch_name::BranchName; pub use branch_name::BranchName;
pub use forge_config::ForgeConfig; pub use forge_config::ForgeConfig;

View file

@ -1,4 +1,9 @@
/// The alias of a repo /// The alias of a repo
/// This is the alias for the repo within `git-next-server.toml` /// This is the alias for the repo within `git-next-server.toml`
#[derive(Clone, Debug, PartialEq, Eq, Hash, derive_more::Display)] #[derive(Clone, Debug, PartialEq, Eq, Hash, derive_more::Display)]
pub struct RepoAlias(pub String); pub struct RepoAlias(String);
impl RepoAlias {
pub fn new(str: impl Into<String>) -> Self {
Self(str.into())
}
}

132
crates/config/src/tests.rs Normal file
View file

@ -0,0 +1,132 @@
type TestResult = Result<(), Box<dyn std::error::Error>>;
mod server_repo_config {
use assert2::let_assert;
use crate::{RepoBranches, RepoConfig, RepoConfigSource};
use super::super::server_repo_config::*;
#[test]
fn should_not_return_repo_config_when_no_branches() {
let src = ServerRepoConfig {
repo: "".to_string(),
branch: "".to_string(),
gitdir: None,
main: None,
next: None,
dev: None,
};
let_assert!(None = src.repo_config());
}
#[test]
fn should_return_repo_config_when_branches() {
let src = ServerRepoConfig {
repo: "".to_string(),
branch: "".to_string(),
gitdir: None,
main: Some("main".to_string()),
next: Some("next".to_string()),
dev: Some("dev".to_string()),
};
let_assert!(Some(rc) = src.repo_config());
assert_eq!(
rc,
RepoConfig {
branches: RepoBranches {
main: "main".to_string(),
next: "next".to_string(),
dev: "dev".to_string()
},
source: RepoConfigSource::Server
}
);
}
}
mod repo_config {
use crate::{RepoBranches, RepoConfigSource};
use super::super::repo_config::*;
use super::*;
#[test]
fn should_parse_toml() -> TestResult {
let toml = r#"
[branches]
main = "main"
next = "next"
dev = "dev"
"#;
let rc = RepoConfig::load(toml)?;
assert_eq!(
rc,
RepoConfig {
branches: RepoBranches {
main: "main".to_string(),
next: "next".to_string(),
dev: "dev".to_string(),
},
source: RepoConfigSource::Repo // reading from repo is the default
}
);
Ok(())
}
}
mod forge_config {
use std::collections::BTreeMap;
use crate::{ForgeConfig, ForgeType, RepoAlias, ServerRepoConfig};
use super::*;
#[test]
fn should_return_repos() -> TestResult {
let forge_type = ForgeType::MockForge;
let hostname = "localhost".to_string();
let user = "bob".to_string();
let token = "alpha".to_string();
let red = ServerRepoConfig {
repo: "red".to_string(),
branch: "main".to_string(),
main: None,
next: None,
dev: None,
gitdir: None,
};
let blue = ServerRepoConfig {
repo: "blue".to_string(),
branch: "main".to_string(),
main: None,
next: None,
dev: None,
gitdir: None,
};
let mut repos = BTreeMap::new();
repos.insert("red".to_string(), red.clone());
repos.insert("blue".to_string(), blue.clone());
let fc = ForgeConfig {
forge_type,
hostname,
user,
token,
repos,
};
let returned_repos = fc.repos().collect::<Vec<_>>();
assert_eq!(
returned_repos,
vec![
// alphabetical order by key
(RepoAlias::new("blue"), &blue),
(RepoAlias::new("red"), &red),
]
);
Ok(())
}
}

View file

@ -47,7 +47,7 @@ pub fn find_default_remote(
let path = path.strip_suffix(".git").map_or(path, |path| path); let path = path.strip_suffix(".git").map_or(path, |path| path);
info!(%host, %path, "found"); info!(%host, %path, "found");
Ok(GitRemote::new( Ok(GitRemote::new(
Hostname(host.to_string()), Hostname::new(host),
RepoPath(path.to_string()), RepoPath(path.to_string()),
)) ))
} }

View file

@ -62,7 +62,7 @@ fn validate_commit_message(message: &git::commit::Message) -> Option<String> {
} }
} }
fn find_next_commit_on_dev( pub fn find_next_commit_on_dev(
next: git::Commit, next: git::Commit,
dev_commit_history: Vec<git::Commit>, dev_commit_history: Vec<git::Commit>,
) -> Option<git::Commit> { ) -> Option<git::Commit> {
@ -100,22 +100,3 @@ pub async fn advance_main(
RepoConfigSource::Server => addr.do_send(ValidateRepo { message_token }), RepoConfigSource::Server => addr.do_send(ValidateRepo { message_token }),
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[actix_rt::test]
async fn test_find_next_commit_on_dev() {
let next = git::Commit::new("current-next", "foo");
let expected = git::Commit::new("dev-next", "next-should-go-here");
let dev_commit_history = vec![
git::Commit::new("dev", "future"),
expected.clone(),
next.clone(),
git::Commit::new("current-main", "history"),
];
let next_commit = find_next_commit_on_dev(next, dev_commit_history);
assert_eq!(next_commit, Some(expected));
}
}

View file

@ -3,6 +3,9 @@ mod config;
pub mod status; pub mod status;
pub mod webhook; pub mod webhook;
#[cfg(test)]
mod tests;
use actix::prelude::*; use actix::prelude::*;
use git_next_config::{ForgeType, RepoConfig}; use git_next_config::{ForgeType, RepoConfig};
use git_next_git::{self as git, Generation, RepoDetails}; use git_next_git::{self as git, Generation, RepoDetails};

View file

@ -0,0 +1,31 @@
//
use super::*;
mod branch {
use super::super::branch::*;
use super::*;
#[actix_rt::test]
async fn test_find_next_commit_on_dev() {
let next = git::Commit::new("current-next", "foo");
let expected = git::Commit::new("dev-next", "next-should-go-here");
let dev_commit_history = vec![
git::Commit::new("dev", "future"),
expected.clone(),
next.clone(),
git::Commit::new("current-main", "history"),
];
let next_commit = find_next_commit_on_dev(next, dev_commit_history);
assert_eq!(next_commit, Some(expected), "Found the wrong commit");
}
}
mod webhook {
use super::super::webhook::*;
#[test]
fn should_split_ref() {
assert_eq!(split_ref("refs/heads/next"), ("refs/heads/", "next"));
}
}

View file

@ -285,7 +285,7 @@ impl Push {
warn!(r#ref = self.reference, "Unexpected ref"); warn!(r#ref = self.reference, "Unexpected ref");
return None; return None;
} }
let (_, branch) = self.reference.split_at(11); let (_, branch) = split_ref(&self.reference);
let branch = BranchName::new(branch); let branch = BranchName::new(branch);
if branch == repo_branches.main() { if branch == repo_branches.main() {
return Some(Branch::Main); return Some(Branch::Main);
@ -299,11 +299,16 @@ impl Push {
warn!(%branch, "Unexpected branch"); warn!(%branch, "Unexpected branch");
None None
} }
pub fn commit(&self) -> git::Commit { pub fn commit(&self) -> git::Commit {
git::Commit::new(&self.after, &self.head_commit.message) git::Commit::new(&self.after, &self.head_commit.message)
} }
} }
pub fn split_ref(reference: &str) -> (&str, &str) {
reference.split_at(11)
}
#[derive(Debug)] #[derive(Debug)]
enum Branch { enum Branch {
Main, Main,
@ -315,11 +320,3 @@ enum Branch {
struct HeadCommit { struct HeadCommit {
message: String, message: String,
} }
#[cfg(test)]
mod tests {
#[test]
fn splt_ref() {
assert_eq!("refs/heads/next".split_at(11), ("refs/heads/", "next"));
}
}

View file

@ -28,7 +28,7 @@ impl Handler<WebhookMessage> for WebhookRouter {
fn handle(&mut self, msg: WebhookMessage, _ctx: &mut Self::Context) -> Self::Result { fn handle(&mut self, msg: WebhookMessage, _ctx: &mut Self::Context) -> Self::Result {
let _gaurd = self.span.enter(); let _gaurd = self.span.enter();
let repo_alias = RepoAlias(msg.path().clone()); let repo_alias = RepoAlias::new(msg.path());
debug!(repo = %repo_alias, "Router..."); debug!(repo = %repo_alias, "Router...");
if let Some(recipient) = self.repos.get(&repo_alias) { if let Some(recipient) = self.repos.get(&repo_alias) {
info!(repo = %repo_alias, "Sending to Recipient"); info!(repo = %repo_alias, "Sending to Recipient");

View file

@ -1,3 +1,5 @@
use std::collections::BTreeMap;
use assert2::let_assert; use assert2::let_assert;
use git_next_config::{ use git_next_config::{
ForgeType, GitDir, Hostname, RepoBranches, RepoConfig, RepoConfigSource, RepoPath, ForgeType, GitDir, Hostname, RepoBranches, RepoConfig, RepoConfigSource, RepoPath,
@ -68,7 +70,7 @@ fn load_should_parse_server_config() -> Result<()> {
hostname: "git.example.net".to_string(), hostname: "git.example.net".to_string(),
user: "Bob".to_string(), user: "Bob".to_string(),
token: "API-Token".to_string(), token: "API-Token".to_string(),
repos: HashMap::from([ repos: BTreeMap::from([
( (
"hello".to_string(), "hello".to_string(),
ServerRepoConfig { ServerRepoConfig {
@ -176,7 +178,7 @@ fn repo_details_find_default_push_remote_finds_correct_remote() -> Result<()> {
None, None,
GitDir::new(root), // Server GitDir - should be ignored GitDir::new(root), // Server GitDir - should be ignored
); );
repo_details.forge.hostname = Hostname("git.kemitix.net".to_string()); repo_details.forge.hostname = Hostname::new("git.kemitix.net");
repo_details.repo_path = RepoPath("kemitix/git-next".to_string()); repo_details.repo_path = RepoPath("kemitix/git-next".to_string());
let gitdir = &repo_details.gitdir; let gitdir = &repo_details.gitdir;
let repository = Repository::open(gitdir)?; let repository = Repository::open(gitdir)?;
@ -202,7 +204,7 @@ fn gitdir_validate_should_pass_a_valid_git_repo() -> Result<()> {
None, None,
GitDir::new(root), // Server GitDir - should be ignored GitDir::new(root), // Server GitDir - should be ignored
); );
repo_details.forge.hostname = Hostname("git.kemitix.net".to_string()); repo_details.forge.hostname = Hostname::new("git.kemitix.net");
repo_details.repo_path = RepoPath("kemitix/git-next".to_string()); repo_details.repo_path = RepoPath("kemitix/git-next".to_string());
let gitdir = &repo_details.gitdir; let gitdir = &repo_details.gitdir;
let repository = Repository::open(gitdir)?; let repository = Repository::open(gitdir)?;
@ -222,7 +224,7 @@ fn gitdir_validate_should_fail_a_git_repo_with_wrong_remote() -> Result<()> {
None, None,
GitDir::new(root), // Server GitDir - should be ignored GitDir::new(root), // Server GitDir - should be ignored
); );
repo_details.forge.hostname = Hostname("localhost".to_string()); repo_details.forge.hostname = Hostname::new("localhost");
repo_details.repo_path = RepoPath("hello/world".to_string()); repo_details.repo_path = RepoPath("hello/world".to_string());
let gitdir = &repo_details.gitdir; let gitdir = &repo_details.gitdir;
let repository = Repository::open(gitdir)?; let repository = Repository::open(gitdir)?;
@ -233,7 +235,7 @@ fn gitdir_validate_should_fail_a_git_repo_with_wrong_remote() -> Result<()> {
#[test] #[test]
fn git_remote_to_string_is_as_expected() { fn git_remote_to_string_is_as_expected() {
let git_remote = GitRemote::new(Hostname("foo".to_string()), RepoPath("bar".to_string())); let git_remote = GitRemote::new(Hostname::new("foo"), RepoPath("bar".to_string()));
let as_string = git_remote.to_string(); let as_string = git_remote.to_string();
assert_eq!(as_string, "foo:bar"); assert_eq!(as_string, "foo:bar");

View file

@ -24,7 +24,7 @@ pub fn user(n: u32) -> User {
} }
pub fn hostname(n: u32) -> Hostname { pub fn hostname(n: u32) -> Hostname {
Hostname(format!("hostname-{}", n)) Hostname::new(format!("hostname-{}", n))
} }
pub fn forge_name(n: u32) -> ForgeName { pub fn forge_name(n: u32) -> ForgeName {
@ -57,7 +57,7 @@ pub fn repo_path(n: u32) -> RepoPath {
} }
pub fn repo_alias(n: u32) -> RepoAlias { pub fn repo_alias(n: u32) -> RepoAlias {
RepoAlias(format!("repo-alias-{}", n)) RepoAlias::new(format!("repo-alias-{}", n))
} }
pub fn repo_config(n: u32, source: RepoConfigSource) -> RepoConfig { pub fn repo_config(n: u32, source: RepoConfigSource) -> RepoConfig {