// type Result = core::result::Result>; type TestResult = Result<()>; mod server_repo_config { use std::path::PathBuf; use assert2::let_assert; use crate::{BranchName, GitDir, RepoBranches, RepoConfig, RepoConfigSource, RepoPath}; use super::super::server_repo_config::*; #[test] fn should_not_return_repo_config_when_no_branches() { let src = ServerRepoConfig::new("".to_string(), "".to_string(), None, None, None, None); let_assert!(None = src.repo_config()); } #[test] fn should_return_repo_config_when_branches() { let src = ServerRepoConfig::new( "".to_string(), "".to_string(), None, Some("main".to_string()), Some("next".to_string()), Some("dev".to_string()), ); let_assert!(Some(rc) = src.repo_config()); assert_eq!( rc, RepoConfig::new( RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string()), RepoConfigSource::Server ) ); } #[test] fn should_return_repo() { let src = ServerRepoConfig::new( "repo".to_string(), "branch".to_string(), None, Some("main".to_string()), Some("next".to_string()), Some("dev".to_string()), ); assert_eq!(src.repo(), RepoPath::new("repo".to_string())); } #[test] fn should_return_branch() { let src = ServerRepoConfig::new( "repo".to_string(), "branch".to_string(), None, Some("main".to_string()), Some("next".to_string()), Some("dev".to_string()), ); assert_eq!(src.branch(), BranchName::new("branch".to_string())); } #[test] fn should_return_gitdir() { let src = ServerRepoConfig::new( "repo".to_string(), "branch".to_string(), Some("gitdir".into()), Some("main".to_string()), Some("next".to_string()), Some("dev".to_string()), ); assert_eq!( src.gitdir(), Some(GitDir::new(&PathBuf::default().join("gitdir"))) ); } } 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::new( RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string(),), RepoConfigSource::Repo // reading from repo is the default ) ); Ok(()) } #[test] fn should_return_branches() { let branches = RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string()); let repo_config = RepoConfig::new(branches.clone(), RepoConfigSource::Repo); assert_eq!(repo_config.branches(), &branches); } #[test] fn should_return_source() { let repo_config = RepoConfig::new( RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string()), RepoConfigSource::Repo, ); assert_eq!(repo_config.source(), RepoConfigSource::Repo); } } mod forge_config { use std::collections::BTreeMap; use secrecy::ExposeSecret; use crate::{ForgeConfig, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User}; #[test] fn should_return_repos() { let forge_type = ForgeType::MockForge; let hostname = "localhost".to_string(); let user = "bob".to_string(); let token = "alpha".to_string(); let red = ServerRepoConfig::new( "red".to_string(), "main".to_string(), None, None, None, None, ); let blue = ServerRepoConfig::new( "blue".to_string(), "main".to_string(), None, None, None, None, ); let mut repos = BTreeMap::new(); repos.insert("red".to_string(), red.clone()); repos.insert("blue".to_string(), blue.clone()); let fc = ForgeConfig::new(forge_type, hostname, user, token, repos); let returned_repos = fc.repos().collect::>(); assert_eq!( returned_repos, vec![ // alphabetical order by key (RepoAlias::new("blue"), &blue), (RepoAlias::new("red"), &red), ] ); } #[test] fn should_return_forge_type() { let forge_type = ForgeType::MockForge; let hostname = "localhost".to_string(); let user = "bob".to_string(); let token = "alpha".to_string(); let repos = BTreeMap::new(); let fc = ForgeConfig::new(forge_type, hostname, user, token, repos); assert_eq!(fc.forge_type(), ForgeType::MockForge); } #[test] fn should_return_hostname() { let forge_type = ForgeType::MockForge; let hostname = "localhost".to_string(); let user = "bob".to_string(); let token = "alpha".to_string(); let repos = BTreeMap::new(); let fc = ForgeConfig::new(forge_type, hostname, user, token, repos); assert_eq!(fc.hostname(), Hostname::new("localhost")); } #[test] fn should_return_user() { let forge_type = ForgeType::MockForge; let hostname = "localhost".to_string(); let user = "bob".to_string(); let token = "alpha".to_string(); let repos = BTreeMap::new(); let fc = ForgeConfig::new(forge_type, hostname, user, token, repos); assert_eq!(fc.user(), User::new("bob".to_string())); } #[test] fn should_return_token() { let forge_type = ForgeType::MockForge; let hostname = "localhost".to_string(); let user = "bob".to_string(); let token = "alpha".to_string(); let repos = BTreeMap::new(); let fc = ForgeConfig::new(forge_type, hostname, user, token, repos); assert_eq!(fc.token().expose_secret(), "alpha"); } #[test] fn should_return_repo() { let forge_type = ForgeType::MockForge; let hostname = "localhost".to_string(); let user = "bob".to_string(); let token = "alpha".to_string(); let red = ServerRepoConfig::new( "red".to_string(), "main".to_string(), None, None, None, None, ); let blue = ServerRepoConfig::new( "blue".to_string(), "main".to_string(), None, None, None, None, ); let mut repos = BTreeMap::new(); repos.insert("red".to_string(), red.clone()); repos.insert("blue".to_string(), blue); let fc = ForgeConfig::new(forge_type, hostname, user, token, repos); let returned_repo = fc.get_repo("red"); assert_eq!(returned_repo, Some(&red),); } } mod forge_details { use std::collections::BTreeMap; use secrecy::ExposeSecret; use crate::{ApiToken, ForgeAlias, ForgeConfig, ForgeDetails, ForgeType, Hostname, User}; #[test] fn should_return_forge_name() { let forge_type = ForgeType::MockForge; let hostname = Hostname::new("localhost".to_string()); let user = User::new("bob".to_string()); let token = ApiToken::new("alpha".to_string().into()); let forge_name = ForgeAlias::new("gamma".to_string()); let forge_details = ForgeDetails::new(forge_name.clone(), forge_type, hostname, user, token); let result = forge_details.forge_alias(); assert_eq!(result, &forge_name); } #[test] fn should_return_forge_type() { let forge_type = ForgeType::MockForge; let hostname = Hostname::new("localhost".to_string()); let user = User::new("bob".to_string()); let token = ApiToken::new("alpha".to_string().into()); let forge_name = ForgeAlias::new("gamma".to_string()); let forge_details = ForgeDetails::new(forge_name, forge_type, hostname, user, token); let result = forge_details.forge_type(); assert_eq!(result, forge_type); } #[test] fn should_return_hostname() { let forge_type = ForgeType::MockForge; let hostname = Hostname::new("localhost".to_string()); let user = User::new("bob".to_string()); let token = ApiToken::new("alpha".to_string().into()); let forge_name = ForgeAlias::new("gamma".to_string()); let forge_details = ForgeDetails::new(forge_name, forge_type, hostname.clone(), user, token); let result = forge_details.hostname(); assert_eq!(result, &hostname); } #[test] fn should_return_user() { let forge_type = ForgeType::MockForge; let hostname = Hostname::new("localhost".to_string()); let user = User::new("bob".to_string()); let token = ApiToken::new("alpha".to_string().into()); let forge_name = ForgeAlias::new("gamma".to_string()); let forge_details = ForgeDetails::new(forge_name, forge_type, hostname, user.clone(), token); let result = forge_details.user(); assert_eq!(result, &user); } #[test] fn should_return_token() { let forge_type = ForgeType::MockForge; let hostname = Hostname::new("localhost".to_string()); let user = User::new("bob".to_string()); let token = ApiToken::new("alpha".to_string().into()); let forge_name = ForgeAlias::new("gamma".to_string()); let forge_details = ForgeDetails::new(forge_name, forge_type, hostname, user, token.clone()); let result = forge_details.token(); assert_eq!(result.expose_secret(), token.expose_secret()); } #[test] fn with_hostname_should_return_new_instance() { let forge_type = ForgeType::MockForge; let hostname = Hostname::new("localhost".to_string()); let user = User::new("bob".to_string()); let token = ApiToken::new("alpha".to_string().into()); let forge_name = ForgeAlias::new("gamma".to_string()); let forge_details = ForgeDetails::new(forge_name, forge_type, hostname, user, token); let result = forge_details.with_hostname(Hostname::new("remotehost".to_string())); assert_eq!(result.hostname(), &Hostname::new("remotehost".to_string())); } #[test] fn should_convert_from_name_and_config() { let forge_type = ForgeType::MockForge; let hostname = Hostname::new("localhost".to_string()); let user = User::new("bob".to_string()); let token = ApiToken::new("alpha".to_string().into()); let forge_alias = ForgeAlias::new("gamma".to_string()); let forge_config = ForgeConfig::new( forge_type, "localhost".to_string(), "bob".to_string(), "alpha".to_string(), BTreeMap::new(), ); let forge_details = ForgeDetails::from((&forge_alias, &forge_config)); assert_eq!(forge_details.forge_alias(), &forge_alias); assert_eq!(forge_details.hostname(), &hostname); assert_eq!(forge_details.user(), &user); assert_eq!(forge_details.token().expose_secret(), token.expose_secret()); } } mod forge_name { use std::path::PathBuf; use crate::ForgeAlias; #[test] fn should_convert_to_pathbuf() { let forge_alias = ForgeAlias::new("alpha".to_string()); let pathbuf: PathBuf = (&forge_alias).into(); assert_eq!(pathbuf, PathBuf::new().join("alpha")); } } mod forge_type { use crate::ForgeType; #[test] fn should_display_as_lowercase() { assert_eq!(ForgeType::MockForge.to_string(), "mockforge".to_string()); } } mod gitdir { use std::path::PathBuf; use crate::GitDir; #[test] fn should_return_pathbuf() { let pathbuf = PathBuf::default().join("foo"); let gitdir = GitDir::new(&pathbuf); let result = gitdir.pathbuf(); assert_eq!(result, &pathbuf); } #[test] fn should_display() { let pathbuf = PathBuf::default().join("foo"); let gitdir = GitDir::new(&pathbuf); let result = gitdir.to_string(); assert_eq!(result, "foo"); } #[test] fn should_convert_from_str() { let pathbuf = PathBuf::default().join("foo"); let gitdir: GitDir = "foo".into(); assert_eq!(gitdir, GitDir::new(&pathbuf)); } #[test] fn should_convert_to_pathbuf_from_ref() { let pathbuf = PathBuf::default().join("foo"); let gitdir: GitDir = "foo".into(); let result: PathBuf = (&gitdir).into(); assert_eq!(result, pathbuf); } #[test] fn should_convert_to_pathbuf_from_inst() { let pathbuf = PathBuf::default().join("foo"); let gitdir: GitDir = "foo".into(); let result: PathBuf = gitdir.into(); assert_eq!(result, pathbuf); } } mod repo_branches { use crate::{BranchName, RepoBranches}; #[test] fn should_return_main() { let repo_branches = RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string()); assert_eq!(repo_branches.main(), BranchName::new("main")); } #[test] fn should_return_next() { let repo_branches = RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string()); assert_eq!(repo_branches.next(), BranchName::new("next")); } #[test] fn should_return_dev() { let repo_branches = RepoBranches::new("main".to_string(), "next".to_string(), "dev".to_string()); assert_eq!(repo_branches.dev(), BranchName::new("dev")); } } mod server { mod load { // use std::{ collections::{BTreeMap, HashMap}, net::SocketAddr, str::FromStr as _, }; use assert2::let_assert; use pretty_assertions::assert_eq; use crate::{ server::{Http, ServerConfig, ServerStorage, Webhook}, tests::TestResult, ForgeAlias, ForgeConfig, ForgeType, RepoAlias, RepoBranches, RepoConfig, RepoConfigSource, ServerRepoConfig, }; #[test] fn load_should_parse_server_config() -> TestResult { let fs = kxio::fs::temp()?; given_server_config(&fs)?; let_assert!(Ok(config) = ServerConfig::load(&fs)); let expected = ServerConfig::new( Http::new("0.0.0.0".to_string(), 8080), expected_webhook(), expected_storage(), HashMap::from([("default".to_string(), expected_forge_config())]), ); assert_eq!(config, expected, "ServerConfig"); if let Some(forge) = config.forge.get("world") { if let Some(repo) = forge.get_repo("sam") { let repo_config = repo.repo_config(); let expected = Some(RepoConfig::new( RepoBranches::new( "master".to_string(), "upcoming".to_string(), "sam-dev".to_string(), ), RepoConfigSource::Server, )); assert_eq!(repo_config, expected, "RepoConfig"); } } Ok(()) } #[test] fn should_return_forges() -> TestResult { let fs = kxio::fs::temp()?; given_server_config(&fs)?; let config = ServerConfig::load(&fs)?; let forges = config.forges().collect::>(); let forge_config = expected_forge_config(); let expected = vec![(ForgeAlias::new("default".to_string()), &forge_config)]; assert_eq!(forges, expected); Ok(()) } #[test] fn should_return_storage() -> TestResult { let fs = kxio::fs::temp()?; given_server_config(&fs)?; let config = ServerConfig::load(&fs)?; let storage = config.storage(); assert_eq!(storage, &expected_storage()); assert_eq!(storage.path(), std::path::Path::new("/opt/git-next/data")); Ok(()) } #[test] fn should_return_webhook() -> TestResult { let fs = kxio::fs::temp()?; given_server_config(&fs)?; let config = ServerConfig::load(&fs)?; let webhook = config.webhook(); assert_eq!(webhook, &expected_webhook()); assert_eq!( webhook .url(&ForgeAlias::new("a".to_string()), &RepoAlias::new("b")) .as_ref(), "http://localhost:9909/a/b" ); Ok(()) } #[test] fn should_return_http() -> TestResult { let fs = kxio::fs::temp()?; given_server_config(&fs)?; let config = ServerConfig::load(&fs)?; let_assert!(Ok(http) = config.http()); assert_eq!(http, expected_http()); Ok(()) } fn given_server_config(fs: &kxio::fs::FileSystem) -> Result<(), kxio::fs::Error> { fs.file_write( &fs.base().join("git-next-server.toml"), r#" [http] addr = "0.0.0.0" port = 8080 [webhook] url = "http://localhost:9909" [storage] path = "/opt/git-next/data" [forge.default] forge_type = "MockForge" hostname = "git.example.net" user = "Bob" token = "API-Token" [forge.default.repos] hello = { repo = "user/hello", branch = "main", gitdir = "/opt/git/user/hello.git" } world = { repo = "user/world", branch = "master", main = "main", next = "next", dev = "dev" } [forge.default.repos.sam] repo = "user/sam" branch = "main" main = "master" next = "upcoming" dev = "sam-dev" "#, ) } fn expected_storage() -> ServerStorage { ServerStorage::new("/opt/git-next/data".into()) } fn expected_webhook() -> Webhook { Webhook::new("http://localhost:9909".to_string()) } fn expected_http() -> SocketAddr { SocketAddr::from_str("0.0.0.0:8080").unwrap_or_else(|_| panic!()) } fn expected_forge_config() -> ForgeConfig { ForgeConfig::new( ForgeType::MockForge, "git.example.net".to_string(), "Bob".to_string(), "API-Token".to_string(), BTreeMap::from([ ( "hello".to_string(), ServerRepoConfig::new( "user/hello".to_string(), "main".to_string(), Some("/opt/git/user/hello.git".into()), None, None, None, ), ), ( "world".to_string(), ServerRepoConfig::new( "user/world".to_string(), "master".to_string(), None, Some("main".to_string()), Some("next".to_string()), Some("dev".to_string()), ), ), ( "sam".to_string(), ServerRepoConfig::new( "user/sam".to_string(), "main".to_string(), None, Some("master".to_string()), Some("upcoming".to_string()), Some("sam-dev".to_string()), ), ), ]), ) } } } mod registered_webhook { use crate::{RegisteredWebhook, WebhookAuth, WebhookId}; #[test] fn should_return_id() { let id = WebhookId::new("a".to_string()); let auth = WebhookAuth::generate(); let rw = RegisteredWebhook::new(id.clone(), auth); assert_eq!(rw.id(), &id); } #[test] fn should_return_auth() { let id = WebhookId::new("a".to_string()); let auth = WebhookAuth::generate(); let rw = RegisteredWebhook::new(id, auth.clone()); assert_eq!(rw.auth(), &auth); } } mod webhook { mod message { use crate::{webhook::message::Body, ForgeAlias, RepoAlias, WebhookMessage}; #[test] fn should_return_forge_alias() { let message = given_message(); assert_eq!(message.forge_alias(), &expected_forge_alias()); } #[test] fn should_return_repo_alias() { let message = given_message(); assert_eq!(message.repo_alias(), &expected_repo_alias()); } #[test] fn should_return_body() { let message = given_message(); assert_eq!(message.body().as_bytes(), expected_body().as_bytes()); } #[test] fn should_return_header() { let message = given_message(); assert_eq!(message.header("c"), Some("d".to_string())); } fn given_message() -> WebhookMessage { WebhookMessage::new( expected_forge_alias(), expected_repo_alias(), expected_headers(), expected_body(), ) } fn expected_forge_alias() -> ForgeAlias { ForgeAlias::new("a".to_string()) } fn expected_repo_alias() -> RepoAlias { RepoAlias::new("b") } fn expected_headers() -> std::collections::HashMap { [("c", "d"), ("e", "f")] .into_iter() .map(|(k, v)| (k.to_string(), v.to_string())) .collect() } fn expected_body() -> Body { Body::new("g".to_string()) } } } mod push { use crate::{ webhook::{push::Branch, Push}, BranchName, RepoBranches, }; #[test] fn should_return_main_branch() { let repo_branches = given_repo_branches(); let push_event = given_push_event(repo_branches.main()); assert_eq!(push_event.branch(&repo_branches), Some(Branch::Main)); } #[test] fn should_return_next_branch() { let repo_branches = given_repo_branches(); let push_event = given_push_event(repo_branches.next()); assert_eq!(push_event.branch(&repo_branches), Some(Branch::Next)); } #[test] fn should_return_dev_branch() { let repo_branches = given_repo_branches(); let push_event = given_push_event(repo_branches.dev()); assert_eq!(push_event.branch(&repo_branches), Some(Branch::Dev)); } #[test] fn should_not_return_other_branches() { let repo_branches = given_repo_branches(); let push_event = given_push_event(BranchName::new("foo")); assert_eq!(push_event.branch(&repo_branches), None); } #[test] fn should_return_sha() { let repo_branches = given_repo_branches(); let push_event = given_push_event(repo_branches.main()); assert_eq!(push_event.sha(), "sha"); } #[test] fn should_return_message() { let repo_branches = given_repo_branches(); let push_event = given_push_event(repo_branches.main()); assert_eq!(push_event.message(), "message"); } fn given_push_event(branch_name: BranchName) -> Push { Push::new(branch_name, "sha".to_string(), "message".to_string()) } fn given_repo_branches() -> RepoBranches { RepoBranches::new( "a-main".to_string(), "b-next".to_string(), "c-dev".to_string(), ) } }