git-next/crates/config/src/tests.rs

772 lines
24 KiB
Rust
Raw Normal View History

//
type Result<T> = core::result::Result<T, Box<dyn std::error::Error>>;
type TestResult = Result<()>;
2024-05-14 07:59:31 +01:00
mod server_repo_config {
2024-05-17 20:19:47 +01:00
use std::path::PathBuf;
2024-05-14 07:59:31 +01:00
use assert2::let_assert;
2024-05-17 20:19:47 +01:00
use crate::{BranchName, GitDir, RepoBranches, RepoConfig, RepoConfigSource, RepoPath};
2024-05-14 07:59:31 +01:00
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);
2024-05-14 07:59:31 +01:00
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()),
);
2024-05-14 07:59:31 +01:00
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
)
2024-05-14 07:59:31 +01:00
);
}
2024-05-17 20:19:47 +01:00
#[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")))
);
}
2024-05-14 07:59:31 +01:00
}
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
)
2024-05-14 07:59:31 +01:00
);
Ok(())
}
2024-05-17 20:19:47 +01:00
#[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);
}
2024-05-14 07:59:31 +01:00
}
mod forge_config {
use std::collections::BTreeMap;
2024-05-17 20:19:47 +01:00
use secrecy::ExposeSecret;
use crate::{ForgeConfig, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User};
2024-05-14 07:59:31 +01:00
#[test]
2024-05-17 20:19:47 +01:00
fn should_return_repos() {
2024-05-14 07:59:31 +01:00
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,
);
2024-05-14 07:59:31 +01:00
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);
2024-05-14 07:59:31 +01:00
let returned_repos = fc.repos().collect::<Vec<_>>();
assert_eq!(
returned_repos,
vec![
// alphabetical order by key
(RepoAlias::new("blue"), &blue),
(RepoAlias::new("red"), &red),
]
);
2024-05-17 20:19:47 +01:00
}
#[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};
2024-05-17 20:19:47 +01:00
#[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());
2024-05-17 20:19:47 +01:00
let forge_details =
ForgeDetails::new(forge_name.clone(), forge_type, hostname, user, token);
let result = forge_details.forge_alias();
2024-05-17 20:19:47 +01:00
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());
2024-05-17 20:19:47 +01:00
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());
2024-05-17 20:19:47 +01:00
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());
2024-05-17 20:19:47 +01:00
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());
2024-05-17 20:19:47 +01:00
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());
2024-05-17 20:19:47 +01:00
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());
2024-05-17 20:19:47 +01:00
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));
2024-05-17 20:19:47 +01:00
assert_eq!(forge_details.forge_alias(), &forge_alias);
2024-05-17 20:19:47 +01:00
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;
2024-05-17 20:19:47 +01:00
#[test]
fn should_convert_to_pathbuf() {
let forge_alias = ForgeAlias::new("alpha".to_string());
2024-05-17 20:19:47 +01:00
let pathbuf: PathBuf = (&forge_alias).into();
2024-05-17 20:19:47 +01:00
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"));
2024-05-14 07:59:31 +01:00
}
}
mod server {
mod load {
//
2024-06-01 11:15:04 +01:00
use std::{
collections::{BTreeMap, HashMap},
net::SocketAddr,
str::FromStr as _,
};
use assert2::let_assert;
2024-06-01 11:15:04 +01:00
use pretty_assertions::assert_eq;
use crate::{
server::{Http, ServerConfig, ServerStorage, Webhook},
tests::TestResult,
2024-06-01 11:15:04 +01:00
ForgeAlias, ForgeConfig, ForgeType, RepoAlias, RepoBranches, RepoConfig,
RepoConfigSource, ServerRepoConfig,
};
#[test]
fn load_should_parse_server_config() -> TestResult {
let fs = kxio::fs::temp()?;
2024-06-01 11:15:04 +01:00
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::<Vec<_>>();
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]
2024-06-01 11:15:04 +01:00
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"
"#,
2024-06-01 11:15:04 +01:00
)
}
2024-06-01 11:15:04 +01:00
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(),
2024-06-01 11:15:04 +01:00
None,
Some("main".to_string()),
Some("next".to_string()),
Some("dev".to_string()),
),
2024-06-01 11:15:04 +01:00
),
(
"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 {
2024-06-01 11:15:04 +01:00
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()));
}
2024-06-01 11:15:04 +01:00
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<String, String> {
[("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(),
)
}
}