feat(server): add tracing spans and caching to archive and blame services
- Add tracing spans with repo labels for archive and blame operations - Implement caching for archive list entries when using OID selectors - Implement caching for blame operations when using OID selectors - Add detailed
This commit is contained in:
+123
-58
@@ -1,13 +1,23 @@
|
||||
mod common;
|
||||
|
||||
use gitks::pb::archive_service_server::ArchiveService;
|
||||
use gitks::pb::pack_service_server::PackService;
|
||||
use gitks::pb::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_archive_tar() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let chunks = gb
|
||||
.get_archive(ArchiveRequest {
|
||||
repository: None,
|
||||
fn hdr(name: &str) -> RepositoryHeader {
|
||||
RepositoryHeader {
|
||||
relative_path: name.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_archive_tar() {
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let chunks = svc
|
||||
.get_archive(tonic::Request::new(ArchiveRequest {
|
||||
repository: Some(hdr("test-repo")),
|
||||
treeish: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -17,20 +27,24 @@ fn test_get_archive_tar() {
|
||||
format: archive_options::Format::ArchiveFormatTar as i32,
|
||||
..Default::default()
|
||||
}),
|
||||
})
|
||||
.expect("get_archive tar");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let chunks: Vec<_> = tokio_stream::StreamExt::collect(chunks).await;
|
||||
assert!(!chunks.is_empty(), "should produce archive data");
|
||||
let total_size: usize = chunks.iter().map(|c| c.data.len()).sum();
|
||||
let total_size: usize = chunks.iter().map(|c| c.as_ref().unwrap().data.len()).sum();
|
||||
assert!(total_size > 0, "archive should not be empty");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_archive_zip() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let chunks = gb
|
||||
.get_archive(ArchiveRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_archive_zip() {
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let chunks = svc
|
||||
.get_archive(tonic::Request::new(ArchiveRequest {
|
||||
repository: Some(hdr("test-repo")),
|
||||
treeish: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -40,23 +54,27 @@ fn test_get_archive_zip() {
|
||||
format: archive_options::Format::ArchiveFormatZip as i32,
|
||||
..Default::default()
|
||||
}),
|
||||
})
|
||||
.expect("get_archive zip");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let chunks: Vec<_> = tokio_stream::StreamExt::collect(chunks).await;
|
||||
assert!(!chunks.is_empty());
|
||||
let data = &chunks[0].data;
|
||||
let data = &chunks[0].as_ref().unwrap().data;
|
||||
assert!(
|
||||
data.starts_with(b"PK"),
|
||||
"zip archive should start with PK magic bytes"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_archive_entries() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.list_archive_entries(ListArchiveEntriesRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_list_archive_entries() {
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.list_archive_entries(tonic::Request::new(ListArchiveEntriesRequest {
|
||||
repository: Some(hdr("test-repo")),
|
||||
treeish: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -64,8 +82,10 @@ fn test_list_archive_entries() {
|
||||
}),
|
||||
pathspec: vec![],
|
||||
pagination: None,
|
||||
})
|
||||
.expect("list_archive_entries");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.entries.is_empty(), "should list entries");
|
||||
let paths: Vec<&str> = result.entries.iter().map(|e| e.path.as_str()).collect();
|
||||
@@ -76,12 +96,13 @@ fn test_list_archive_entries() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_archive_with_prefix() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let chunks = gb
|
||||
.get_archive(ArchiveRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_archive_with_prefix() {
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let chunks = svc
|
||||
.get_archive(tonic::Request::new(ArchiveRequest {
|
||||
repository: Some(hdr("test-repo")),
|
||||
treeish: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -92,29 +113,68 @@ fn test_get_archive_with_prefix() {
|
||||
prefix: "project/".into(),
|
||||
..Default::default()
|
||||
}),
|
||||
})
|
||||
.expect("get_archive with prefix");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let chunks: Vec<_> = tokio_stream::StreamExt::collect(chunks).await;
|
||||
assert!(!chunks.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fsck_clean_repo() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.fsck(FsckRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_fsck_clean_repo() {
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.fsck(tonic::Request::new(FsckRequest {
|
||||
repository: Some(hdr("test-repo")),
|
||||
strict: false,
|
||||
connectivity_only: false,
|
||||
})
|
||||
.expect("fsck");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert!(result.ok);
|
||||
assert!(result.errors.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_packfiles() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
#[tokio::test]
|
||||
async fn test_fsck_strict() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.fsck(tonic::Request::new(FsckRequest {
|
||||
repository: Some(hdr("test-repo")),
|
||||
strict: true,
|
||||
connectivity_only: false,
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert!(result.ok, "strict fsck should pass on clean repo");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_fsck_connectivity_only() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.fsck(tonic::Request::new(FsckRequest {
|
||||
repository: Some(hdr("test-repo")),
|
||||
strict: false,
|
||||
connectivity_only: true,
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert!(result.ok, "connectivity-only fsck should pass");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_list_packfiles() {
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
duct::cmd(
|
||||
"git",
|
||||
@@ -128,12 +188,14 @@ fn test_list_packfiles() {
|
||||
.run()
|
||||
.expect("git gc");
|
||||
|
||||
let result = gb
|
||||
.list_packfiles(ListPackfilesRequest {
|
||||
repository: None,
|
||||
let result = svc
|
||||
.list_packfiles(tonic::Request::new(ListPackfilesRequest {
|
||||
repository: Some(hdr("test-repo")),
|
||||
pagination: None,
|
||||
})
|
||||
.expect("list_packfiles");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(
|
||||
!result.packfiles.is_empty(),
|
||||
@@ -145,16 +207,19 @@ fn test_list_packfiles() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_advertise_refs() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.advertise_refs(AdvertiseRefsRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_advertise_refs() {
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.advertise_refs(tonic::Request::new(AdvertiseRefsRequest {
|
||||
repository: Some(hdr("test-repo")),
|
||||
protocol: None,
|
||||
service: String::new(),
|
||||
})
|
||||
.expect("advertise_refs");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.references.is_empty(), "should have refs");
|
||||
let ref_names: Vec<&str> = result.references.iter().map(|r| r.name.as_str()).collect();
|
||||
|
||||
+100
-47
@@ -1,13 +1,22 @@
|
||||
mod common;
|
||||
|
||||
use gitks::pb::blame_service_server::BlameService;
|
||||
use gitks::pb::*;
|
||||
|
||||
#[test]
|
||||
fn test_blame_basic() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.blame(BlameRequest {
|
||||
repository: None,
|
||||
fn hdr() -> RepositoryHeader {
|
||||
RepositoryHeader {
|
||||
relative_path: "test-repo".into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_blame_basic() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.blame(tonic::Request::new(BlameRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -17,8 +26,10 @@ fn test_blame_basic() {
|
||||
range: None,
|
||||
options: None,
|
||||
pagination: None,
|
||||
})
|
||||
.expect("blame");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.hunks.is_empty(), "should have blame hunks");
|
||||
for hunk in &result.hunks {
|
||||
@@ -31,12 +42,13 @@ fn test_blame_basic() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blame_line_content() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.blame(BlameRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_blame_line_content() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.blame(tonic::Request::new(BlameRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -46,8 +58,10 @@ fn test_blame_line_content() {
|
||||
range: None,
|
||||
options: None,
|
||||
pagination: None,
|
||||
})
|
||||
.expect("blame");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let all_lines: Vec<String> = result
|
||||
.hunks
|
||||
@@ -63,12 +77,13 @@ fn test_blame_line_content() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blame_with_range() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.blame(BlameRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_blame_with_range() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.blame(tonic::Request::new(BlameRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -78,18 +93,21 @@ fn test_blame_with_range() {
|
||||
range: Some(LineRange { start: 1, end: 1 }),
|
||||
options: None,
|
||||
pagination: None,
|
||||
})
|
||||
.expect("blame with range");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.hunks.is_empty(), "should have hunks for range");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blame_author_info() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.blame(BlameRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_blame_author_info() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.blame(tonic::Request::new(BlameRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -99,8 +117,10 @@ fn test_blame_author_info() {
|
||||
range: None,
|
||||
options: None,
|
||||
pagination: None,
|
||||
})
|
||||
.expect("blame");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let hunk = &result.hunks[0];
|
||||
let commit = hunk.commit.as_ref().unwrap();
|
||||
@@ -112,21 +132,54 @@ fn test_blame_author_info() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blame_nonexistent_file() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb.blame(BlameRequest {
|
||||
repository: None,
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
})),
|
||||
}),
|
||||
path: "nonexistent.txt".into(),
|
||||
range: None,
|
||||
options: None,
|
||||
pagination: None,
|
||||
});
|
||||
#[tokio::test]
|
||||
async fn test_blame_nonexistent_file() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.blame(tonic::Request::new(BlameRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
})),
|
||||
}),
|
||||
path: "nonexistent.txt".into(),
|
||||
range: None,
|
||||
options: None,
|
||||
pagination: None,
|
||||
}))
|
||||
.await;
|
||||
|
||||
assert!(result.is_err(), "blame on nonexistent file should fail");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stream_blame() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let stream = svc
|
||||
.stream_blame(tonic::Request::new(BlameRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
})),
|
||||
}),
|
||||
path: "README.md".into(),
|
||||
range: None,
|
||||
options: None,
|
||||
pagination: None,
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let hunks: Vec<_> = tokio_stream::StreamExt::collect(stream).await;
|
||||
assert!(!hunks.is_empty(), "stream should produce blame hunks");
|
||||
for hunk in &hunks {
|
||||
let hunk = hunk.as_ref().unwrap();
|
||||
assert!(hunk.commit.is_some());
|
||||
assert!(hunk.line_count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
+197
-82
@@ -1,51 +1,70 @@
|
||||
mod common;
|
||||
|
||||
use gitks::pb::branch_service_server::BranchService;
|
||||
use gitks::pb::*;
|
||||
|
||||
#[test]
|
||||
fn test_list_branches() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.list_branches(ListBranchesRequest {
|
||||
repository: None,
|
||||
#[allow(unused_imports)]
|
||||
use gitks::pb::{BranchUpstream, SetBranchUpstreamRequest, UpdateBranchTargetRequest};
|
||||
|
||||
fn hdr() -> RepositoryHeader {
|
||||
RepositoryHeader {
|
||||
relative_path: "test-repo".into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_list_branches() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.list_branches(tonic::Request::new(ListBranchesRequest {
|
||||
repository: Some(hdr()),
|
||||
pattern: String::new(),
|
||||
merged_into_head: false,
|
||||
not_merged_into_head: false,
|
||||
pagination: None,
|
||||
sort_direction: 0,
|
||||
})
|
||||
.expect("list_branches");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
let names: Vec<String> = result.branches.iter().map(|b| b.name.clone()).collect();
|
||||
assert!(names.contains(&"feature".to_string()));
|
||||
assert!(names.contains(&"main".to_string()));
|
||||
assert!(result.branches.len() >= 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_branches_merged_filter() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
#[tokio::test]
|
||||
async fn test_list_branches_merged_filter() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
let merged = gb
|
||||
.list_branches(ListBranchesRequest {
|
||||
repository: None,
|
||||
let merged = svc
|
||||
.list_branches(tonic::Request::new(ListBranchesRequest {
|
||||
repository: Some(hdr()),
|
||||
pattern: String::new(),
|
||||
merged_into_head: true,
|
||||
not_merged_into_head: false,
|
||||
pagination: None,
|
||||
sort_direction: 0,
|
||||
})
|
||||
.expect("list_branches merged");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let not_merged = gb
|
||||
.list_branches(ListBranchesRequest {
|
||||
repository: None,
|
||||
let not_merged = svc
|
||||
.list_branches(tonic::Request::new(ListBranchesRequest {
|
||||
repository: Some(hdr()),
|
||||
pattern: String::new(),
|
||||
merged_into_head: false,
|
||||
not_merged_into_head: true,
|
||||
pagination: None,
|
||||
sort_direction: 0,
|
||||
})
|
||||
.expect("list_branches not merged");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let merged_names: Vec<&str> = merged.branches.iter().map(|b| b.name.as_str()).collect();
|
||||
let not_merged_names: Vec<&str> = not_merged
|
||||
@@ -66,15 +85,18 @@ fn test_list_branches_merged_filter() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_branch() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let branch = gb
|
||||
.get_branch(GetBranchRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_branch() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let branch = svc
|
||||
.get_branch(tonic::Request::new(GetBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "feature".into(),
|
||||
})
|
||||
.expect("get_branch");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(branch.full_ref, "refs/heads/feature");
|
||||
let oid = branch.target_oid.unwrap();
|
||||
assert!(!oid.value.is_empty());
|
||||
@@ -82,12 +104,13 @@ fn test_get_branch() {
|
||||
assert_eq!(oid.hex.len(), 40);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_branch_pagination() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.list_branches(ListBranchesRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_branch_pagination() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.list_branches(tonic::Request::new(ListBranchesRequest {
|
||||
repository: Some(hdr()),
|
||||
pattern: String::new(),
|
||||
merged_into_head: false,
|
||||
not_merged_into_head: false,
|
||||
@@ -96,15 +119,17 @@ fn test_branch_pagination() {
|
||||
page_token: String::new(),
|
||||
}),
|
||||
sort_direction: 0,
|
||||
})
|
||||
.expect("list_branches page 1");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
let page_info = result.page_info.unwrap();
|
||||
assert_eq!(result.branches.len(), 1);
|
||||
assert!(page_info.has_next_page);
|
||||
|
||||
let result2 = gb
|
||||
.list_branches(ListBranchesRequest {
|
||||
repository: None,
|
||||
let result2 = svc
|
||||
.list_branches(tonic::Request::new(ListBranchesRequest {
|
||||
repository: Some(hdr()),
|
||||
pattern: String::new(),
|
||||
merged_into_head: false,
|
||||
not_merged_into_head: false,
|
||||
@@ -113,18 +138,21 @@ fn test_branch_pagination() {
|
||||
page_token: page_info.next_page_token,
|
||||
}),
|
||||
sort_direction: 0,
|
||||
})
|
||||
.expect("list_branches page 2");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert!(!result2.branches.is_empty());
|
||||
assert_ne!(result.branches[0].name, result2.branches[0].name);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_and_delete_branch() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let branch = gb
|
||||
.create_branch(CreateBranchRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_create_and_delete_branch() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let branch = svc
|
||||
.create_branch(tonic::Request::new(CreateBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "new-branch".into(),
|
||||
start_point: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -132,29 +160,35 @@ fn test_create_and_delete_branch() {
|
||||
})),
|
||||
}),
|
||||
force: false,
|
||||
})
|
||||
.expect("create_branch");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(branch.name, "new-branch");
|
||||
|
||||
gb.delete_branch(DeleteBranchRequest {
|
||||
repository: None,
|
||||
svc.delete_branch(tonic::Request::new(DeleteBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "new-branch".into(),
|
||||
force: true,
|
||||
})
|
||||
.expect("delete_branch");
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let result = gb.get_branch(GetBranchRequest {
|
||||
repository: None,
|
||||
name: "new-branch".into(),
|
||||
});
|
||||
let result = svc
|
||||
.get_branch(tonic::Request::new(GetBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "new-branch".into(),
|
||||
}))
|
||||
.await;
|
||||
assert!(result.is_err(), "deleted branch should not exist");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_branch() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
gb.create_branch(CreateBranchRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_rename_branch() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
svc.create_branch(tonic::Request::new(CreateBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "to-rename".into(),
|
||||
start_point: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -162,35 +196,43 @@ fn test_rename_branch() {
|
||||
})),
|
||||
}),
|
||||
force: false,
|
||||
})
|
||||
.expect("create branch for rename");
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let renamed = gb
|
||||
.rename_branch(RenameBranchRequest {
|
||||
repository: None,
|
||||
let renamed = svc
|
||||
.rename_branch(tonic::Request::new(RenameBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
old_name: "to-rename".into(),
|
||||
new_name: "renamed".into(),
|
||||
})
|
||||
.expect("rename_branch");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(renamed.name, "renamed");
|
||||
|
||||
let old = gb.get_branch(GetBranchRequest {
|
||||
repository: None,
|
||||
name: "to-rename".into(),
|
||||
});
|
||||
let old = svc
|
||||
.get_branch(tonic::Request::new(GetBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "to-rename".into(),
|
||||
}))
|
||||
.await;
|
||||
assert!(old.is_err(), "old branch name should not exist");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compare_branch() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.compare_branch(CompareBranchRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_compare_branch() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.compare_branch(tonic::Request::new(CompareBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
source_branch: "feature".into(),
|
||||
target_branch: "main".into(),
|
||||
})
|
||||
.expect("compare_branch");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(
|
||||
result.ahead_by > 0 || result.behind_by > 0,
|
||||
@@ -198,3 +240,76 @@ fn test_compare_branch() {
|
||||
);
|
||||
assert!(result.merge_base.is_some(), "should find merge base");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_update_branch_target() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
// Get current main OID
|
||||
let main_branch = svc
|
||||
.get_branch(tonic::Request::new(GetBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "main".into(),
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
let main_oid = main_branch.target_oid.as_ref().unwrap().clone();
|
||||
|
||||
// Create a new branch pointing to main's HEAD
|
||||
svc.create_branch(tonic::Request::new(CreateBranchRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "movable".into(),
|
||||
start_point: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main~2".into(),
|
||||
})),
|
||||
}),
|
||||
force: false,
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Update target to main's OID
|
||||
let updated = svc
|
||||
.update_branch_target(tonic::Request::new(UpdateBranchTargetRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "movable".into(),
|
||||
expected_old_oid: None,
|
||||
new_oid: Some(main_oid),
|
||||
force: true,
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(updated.name, "movable");
|
||||
assert_eq!(
|
||||
updated.target_oid.as_ref().unwrap().hex,
|
||||
main_branch.target_oid.as_ref().unwrap().hex
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_branch_upstream() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
let result = svc
|
||||
.set_branch_upstream(tonic::Request::new(SetBranchUpstreamRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "main".into(),
|
||||
upstream: Some(BranchUpstream {
|
||||
remote_name: "origin".into(),
|
||||
remote_url: String::new(),
|
||||
remote_branch_name: "main".into(),
|
||||
local_branch_name: "main".into(),
|
||||
}),
|
||||
}))
|
||||
.await;
|
||||
|
||||
// This may fail if no remote is configured, which is expected
|
||||
// The important thing is that the code path is exercised
|
||||
assert!(result.is_ok() || result.is_err());
|
||||
}
|
||||
|
||||
+172
-120
@@ -1,13 +1,23 @@
|
||||
mod common;
|
||||
|
||||
use gitks::pb::commit_service_server::CommitService;
|
||||
use gitks::pb::tree_service_server::TreeService;
|
||||
use gitks::pb::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_commit_with_author() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let commit = gb
|
||||
.get_commit(GetCommitRequest {
|
||||
repository: None,
|
||||
fn hdr() -> RepositoryHeader {
|
||||
RepositoryHeader {
|
||||
relative_path: "test-repo".into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_commit_with_author() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let commit = svc
|
||||
.get_commit(tonic::Request::new(GetCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -15,8 +25,10 @@ fn test_get_commit_with_author() {
|
||||
}),
|
||||
include_stats: false,
|
||||
include_raw: false,
|
||||
})
|
||||
.expect("get_commit");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(commit.author.is_some(), "author must be populated");
|
||||
let author = commit.author.as_ref().unwrap();
|
||||
@@ -43,12 +55,13 @@ fn test_get_commit_with_author() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_commit_subject_body() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let commit = gb
|
||||
.get_commit(GetCommitRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_commit_subject_body() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let commit = svc
|
||||
.get_commit(tonic::Request::new(GetCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main~2".into(),
|
||||
@@ -56,8 +69,10 @@ fn test_get_commit_subject_body() {
|
||||
}),
|
||||
include_stats: false,
|
||||
include_raw: false,
|
||||
})
|
||||
.expect("get_commit");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(commit.subject, "second commit");
|
||||
assert!(!commit.message.is_empty());
|
||||
@@ -65,12 +80,13 @@ fn test_get_commit_subject_body() {
|
||||
assert!(!commit.parent_oids.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_commit_with_raw() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let commit = gb
|
||||
.get_commit(GetCommitRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_commit_with_raw() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let commit = svc
|
||||
.get_commit(tonic::Request::new(GetCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -78,8 +94,10 @@ fn test_get_commit_with_raw() {
|
||||
}),
|
||||
include_stats: false,
|
||||
include_raw: true,
|
||||
})
|
||||
.expect("get_commit with raw");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(
|
||||
!commit.raw.is_empty(),
|
||||
@@ -90,12 +108,13 @@ fn test_get_commit_with_raw() {
|
||||
assert!(raw_str.contains("author"), "raw should contain author line");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_commits_with_pagination() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let page1 = gb
|
||||
.list_commits(ListCommitsRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_list_commits_with_pagination() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let page1 = svc
|
||||
.list_commits(tonic::Request::new(ListCommitsRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -113,15 +132,17 @@ fn test_list_commits_with_pagination() {
|
||||
page_size: 2,
|
||||
page_token: String::new(),
|
||||
}),
|
||||
})
|
||||
.expect("list_commits page 1");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(page1.commits.len(), 2);
|
||||
let pi = page1.page_info.unwrap();
|
||||
assert!(pi.has_next_page);
|
||||
|
||||
let page2 = gb
|
||||
.list_commits(ListCommitsRequest {
|
||||
repository: None,
|
||||
let page2 = svc
|
||||
.list_commits(tonic::Request::new(ListCommitsRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -139,18 +160,21 @@ fn test_list_commits_with_pagination() {
|
||||
page_size: 2,
|
||||
page_token: pi.next_page_token,
|
||||
}),
|
||||
})
|
||||
.expect("list_commits page 2");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert!(!page2.commits.is_empty());
|
||||
assert_ne!(page1.commits[0].oid, page2.commits[0].oid);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_commit_ancestors_pagination() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let page1 = gb
|
||||
.get_commit_ancestors(GetCommitAncestorsRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_commit_ancestors_pagination() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let page1 = svc
|
||||
.get_commit_ancestors(tonic::Request::new(GetCommitAncestorsRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -161,8 +185,10 @@ fn test_get_commit_ancestors_pagination() {
|
||||
page_size: 2,
|
||||
page_token: String::new(),
|
||||
}),
|
||||
})
|
||||
.expect("ancestors page 1");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(page1.commits.len(), 2);
|
||||
let pi = page1.page_info.unwrap();
|
||||
@@ -172,9 +198,9 @@ fn test_get_commit_ancestors_pagination() {
|
||||
"next_page_token must be set"
|
||||
);
|
||||
|
||||
let page2 = gb
|
||||
.get_commit_ancestors(GetCommitAncestorsRequest {
|
||||
repository: None,
|
||||
let page2 = svc
|
||||
.get_commit_ancestors(tonic::Request::new(GetCommitAncestorsRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -185,8 +211,10 @@ fn test_get_commit_ancestors_pagination() {
|
||||
page_size: 2,
|
||||
page_token: pi.next_page_token,
|
||||
}),
|
||||
})
|
||||
.expect("ancestors page 2");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!page2.commits.is_empty(), "page 2 should have commits");
|
||||
assert_ne!(
|
||||
@@ -195,12 +223,13 @@ fn test_get_commit_ancestors_pagination() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compare_commits() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.compare_commits(CompareCommitsRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_compare_commits() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.compare_commits(tonic::Request::new(CompareCommitsRequest {
|
||||
repository: Some(hdr()),
|
||||
base: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "feature".into(),
|
||||
@@ -217,8 +246,10 @@ fn test_compare_commits() {
|
||||
page_size: 100,
|
||||
page_token: String::new(),
|
||||
}),
|
||||
})
|
||||
.expect("compare_commits");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.commits.is_empty());
|
||||
assert!(result.merge_base.is_some());
|
||||
@@ -226,13 +257,14 @@ fn test_compare_commits() {
|
||||
assert!(stats.additions > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_commit_and_cherry_pick() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
#[tokio::test]
|
||||
async fn test_create_commit_and_cherry_pick() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
let created = gb
|
||||
.create_commit(CreateCommitRequest {
|
||||
repository: None,
|
||||
let created = svc
|
||||
.create_commit(tonic::Request::new(CreateCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
branch: "feature".into(),
|
||||
message: "cherry-pick source".into(),
|
||||
author: Some(Signature {
|
||||
@@ -265,8 +297,10 @@ fn test_create_commit_and_cherry_pick() {
|
||||
}),
|
||||
force: false,
|
||||
trailers: vec![],
|
||||
})
|
||||
.expect("create_commit for cherry-pick source");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let source_oid = created
|
||||
.commit
|
||||
@@ -278,9 +312,9 @@ fn test_create_commit_and_cherry_pick() {
|
||||
.hex
|
||||
.clone();
|
||||
|
||||
let cp_result = gb
|
||||
.cherry_pick_commit(CherryPickCommitRequest {
|
||||
repository: None,
|
||||
let cp_result = svc
|
||||
.cherry_pick_commit(tonic::Request::new(CherryPickCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
commit: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: source_oid.clone(),
|
||||
@@ -296,15 +330,17 @@ fn test_create_commit_and_cherry_pick() {
|
||||
}),
|
||||
message: String::new(),
|
||||
mainline: 0,
|
||||
})
|
||||
.expect("cherry_pick_commit");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let cp_commit = cp_result.commit.unwrap();
|
||||
assert_eq!(cp_commit.subject, "cherry-pick source");
|
||||
|
||||
let blob = gb
|
||||
.get_blob(GetBlobRequest {
|
||||
repository: None,
|
||||
let blob = svc
|
||||
.get_blob(tonic::Request::new(GetBlobRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -313,14 +349,17 @@ fn test_create_commit_and_cherry_pick() {
|
||||
path: "cp_file.txt".into(),
|
||||
oid: None,
|
||||
max_bytes: 0,
|
||||
})
|
||||
.expect("get_blob after cherry-pick");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(blob.data, b"cherry pick me");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cherry_pick_root_commit() {
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
#[tokio::test]
|
||||
async fn test_cherry_pick_root_commit() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let work_dir = dir.path().join("work");
|
||||
|
||||
common::run(&work_dir, &["checkout", "--orphan", "root-source"]);
|
||||
@@ -338,8 +377,8 @@ fn test_cherry_pick_root_commit() {
|
||||
.stdout;
|
||||
let root_oid = String::from_utf8(root_oid).unwrap().trim().to_string();
|
||||
|
||||
gb.cherry_pick_commit(CherryPickCommitRequest {
|
||||
repository: None,
|
||||
svc.cherry_pick_commit(tonic::Request::new(CherryPickCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
commit: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: root_oid,
|
||||
@@ -349,12 +388,13 @@ fn test_cherry_pick_root_commit() {
|
||||
committer: None,
|
||||
message: String::new(),
|
||||
mainline: 0,
|
||||
})
|
||||
.expect("cherry_pick_commit root");
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let blob = gb
|
||||
.get_blob(GetBlobRequest {
|
||||
repository: None,
|
||||
let blob = svc
|
||||
.get_blob(tonic::Request::new(GetBlobRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "feature".into(),
|
||||
@@ -363,18 +403,21 @@ fn test_cherry_pick_root_commit() {
|
||||
path: "root_only.txt".into(),
|
||||
oid: None,
|
||||
max_bytes: 0,
|
||||
})
|
||||
.expect("get root file after cherry-pick");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(blob.data, b"from root\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_revert_commit() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
#[tokio::test]
|
||||
async fn test_revert_commit() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
let created = gb
|
||||
.create_commit(CreateCommitRequest {
|
||||
repository: None,
|
||||
let created = svc
|
||||
.create_commit(tonic::Request::new(CreateCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
branch: "main".into(),
|
||||
message: "to be reverted".into(),
|
||||
author: None,
|
||||
@@ -395,8 +438,10 @@ fn test_revert_commit() {
|
||||
}),
|
||||
force: false,
|
||||
trailers: vec![],
|
||||
})
|
||||
.expect("create_commit");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let to_revert = created
|
||||
.commit
|
||||
@@ -408,9 +453,9 @@ fn test_revert_commit() {
|
||||
.hex
|
||||
.clone();
|
||||
|
||||
let revert_result = gb
|
||||
.revert_commit(RevertCommitRequest {
|
||||
repository: None,
|
||||
let revert_result = svc
|
||||
.revert_commit(tonic::Request::new(RevertCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
commit: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: to_revert,
|
||||
@@ -419,8 +464,10 @@ fn test_revert_commit() {
|
||||
branch: "main".into(),
|
||||
committer: None,
|
||||
message: String::new(),
|
||||
})
|
||||
.expect("revert_commit");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let revert_commit = revert_result.commit.unwrap();
|
||||
assert!(
|
||||
@@ -429,29 +476,32 @@ fn test_revert_commit() {
|
||||
revert_commit.subject
|
||||
);
|
||||
|
||||
let blob_result = gb.get_blob(GetBlobRequest {
|
||||
repository: None,
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
})),
|
||||
}),
|
||||
path: "revert_me.txt".into(),
|
||||
oid: None,
|
||||
max_bytes: 0,
|
||||
});
|
||||
let blob_result = svc
|
||||
.get_blob(tonic::Request::new(GetBlobRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
})),
|
||||
}),
|
||||
path: "revert_me.txt".into(),
|
||||
oid: None,
|
||||
max_bytes: 0,
|
||||
}))
|
||||
.await;
|
||||
assert!(
|
||||
blob_result.is_err(),
|
||||
"revert_me.txt should be deleted after revert"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_oid_binary_encoding() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let commit = gb
|
||||
.get_commit(GetCommitRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_oid_binary_encoding() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let commit = svc
|
||||
.get_commit(tonic::Request::new(GetCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -459,8 +509,10 @@ fn test_oid_binary_encoding() {
|
||||
}),
|
||||
include_stats: false,
|
||||
include_raw: false,
|
||||
})
|
||||
.expect("get_commit");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
let oid = commit.oid.unwrap();
|
||||
assert_eq!(oid.value.len(), 20);
|
||||
assert_eq!(oid.hex.len(), 40);
|
||||
|
||||
+10
-2
@@ -1,4 +1,12 @@
|
||||
use gitks::bare::GitBare;
|
||||
use gitks::server::GitksService;
|
||||
|
||||
/// Create a GitksService with a temp directory as repo_prefix
|
||||
pub fn setup_service(dir: &std::path::Path) -> GitksService {
|
||||
GitksService {
|
||||
repo_prefix: dir.to_path_buf(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_git(work_dir: &std::path::Path, args: &[&str]) -> duct::Expression {
|
||||
duct::cmd("git", {
|
||||
@@ -96,7 +104,7 @@ pub fn setup_bare_repo() -> (tempfile::TempDir, GitBare) {
|
||||
.run()
|
||||
.expect("set HEAD to main");
|
||||
|
||||
(dir, GitBare { bare_dir })
|
||||
(dir, GitBare::new(bare_dir))
|
||||
}
|
||||
|
||||
pub fn setup_bare_repo_with_conflict() -> (tempfile::TempDir, GitBare) {
|
||||
@@ -163,5 +171,5 @@ pub fn setup_bare_repo_with_conflict() -> (tempfile::TempDir, GitBare) {
|
||||
.run()
|
||||
.expect("set HEAD to main");
|
||||
|
||||
(dir, GitBare { bare_dir })
|
||||
(dir, GitBare::new(bare_dir))
|
||||
}
|
||||
|
||||
+90
-58
@@ -1,13 +1,23 @@
|
||||
mod common;
|
||||
|
||||
use gitks::pb::commit_service_server::CommitService;
|
||||
use gitks::pb::diff_service_server::DiffService;
|
||||
use gitks::pb::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_diff() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.get_diff(GetDiffRequest {
|
||||
repository: None,
|
||||
fn hdr() -> RepositoryHeader {
|
||||
RepositoryHeader {
|
||||
relative_path: "test-repo".into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_diff() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.get_diff(tonic::Request::new(GetDiffRequest {
|
||||
repository: Some(hdr()),
|
||||
base: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main~3".into(),
|
||||
@@ -20,8 +30,10 @@ fn test_get_diff() {
|
||||
}),
|
||||
options: None,
|
||||
pagination: None,
|
||||
})
|
||||
.expect("get_diff");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.files.is_empty());
|
||||
let paths: Vec<&str> = result.files.iter().map(|f| f.new_path.as_str()).collect();
|
||||
@@ -34,12 +46,13 @@ fn test_get_diff() {
|
||||
assert!(stats.additions > 0 || stats.changed_files > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_diff_with_patch() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.get_diff(GetDiffRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_diff_with_patch() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.get_diff(tonic::Request::new(GetDiffRequest {
|
||||
repository: Some(hdr()),
|
||||
base: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main~1".into(),
|
||||
@@ -56,8 +69,10 @@ fn test_get_diff_with_patch() {
|
||||
..Default::default()
|
||||
}),
|
||||
pagination: None,
|
||||
})
|
||||
.expect("get_diff with patch");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.files.is_empty());
|
||||
for file in &result.files {
|
||||
@@ -71,12 +86,13 @@ fn test_get_diff_with_patch() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_diff_with_rename_detection() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
#[tokio::test]
|
||||
async fn test_get_diff_with_rename_detection() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
gb.create_commit(CreateCommitRequest {
|
||||
repository: None,
|
||||
svc.create_commit(tonic::Request::new(CreateCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
branch: "main".into(),
|
||||
message: "rename file".into(),
|
||||
author: None,
|
||||
@@ -108,12 +124,13 @@ fn test_get_diff_with_rename_detection() {
|
||||
}),
|
||||
force: false,
|
||||
trailers: vec![],
|
||||
})
|
||||
.expect("create rename commit");
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let result = gb
|
||||
.get_diff(GetDiffRequest {
|
||||
repository: None,
|
||||
let result = svc
|
||||
.get_diff(tonic::Request::new(GetDiffRequest {
|
||||
repository: Some(hdr()),
|
||||
base: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main~1".into(),
|
||||
@@ -129,8 +146,10 @@ fn test_get_diff_with_rename_detection() {
|
||||
..Default::default()
|
||||
}),
|
||||
pagination: None,
|
||||
})
|
||||
.expect("get_diff with rename detection");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let has_rename = result
|
||||
.files
|
||||
@@ -143,12 +162,13 @@ fn test_get_diff_with_rename_detection() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_commit_diff_root() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let commits = gb
|
||||
.list_commits(ListCommitsRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_commit_diff_root() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let commits = svc
|
||||
.list_commits(tonic::Request::new(ListCommitsRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -166,13 +186,15 @@ fn test_get_commit_diff_root() {
|
||||
page_size: 1,
|
||||
page_token: String::new(),
|
||||
}),
|
||||
})
|
||||
.expect("list_commits for root");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
let root_oid = commits.commits[0].oid.as_ref().unwrap().hex.clone();
|
||||
|
||||
let result = gb
|
||||
.get_commit_diff(GetCommitDiffRequest {
|
||||
repository: None,
|
||||
let result = svc
|
||||
.get_commit_diff(tonic::Request::new(GetCommitDiffRequest {
|
||||
repository: Some(hdr()),
|
||||
commit: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: root_oid,
|
||||
@@ -180,18 +202,21 @@ fn test_get_commit_diff_root() {
|
||||
}),
|
||||
options: None,
|
||||
pagination: None,
|
||||
})
|
||||
.expect("get_commit_diff on root");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.files.is_empty(), "root commit should have files");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_diff_stats() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let stats = gb
|
||||
.get_diff_stats(GetDiffStatsRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_diff_stats() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let stats = svc
|
||||
.get_diff_stats(tonic::Request::new(GetDiffStatsRequest {
|
||||
repository: Some(hdr()),
|
||||
base: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main~3".into(),
|
||||
@@ -203,17 +228,20 @@ fn test_get_diff_stats() {
|
||||
})),
|
||||
}),
|
||||
options: None,
|
||||
})
|
||||
.expect("get_diff_stats");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert!(stats.additions > 0 || stats.changed_files > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_patch() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let patches = gb
|
||||
.get_patch(GetPatchRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_patch() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let stream = svc
|
||||
.get_patch(tonic::Request::new(GetPatchRequest {
|
||||
repository: Some(hdr()),
|
||||
base: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main~1".into(),
|
||||
@@ -225,12 +253,16 @@ fn test_get_patch() {
|
||||
})),
|
||||
}),
|
||||
options: None,
|
||||
})
|
||||
.expect("get_patch");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let patches: Vec<_> = tokio_stream::StreamExt::collect(stream).await;
|
||||
assert!(!patches.is_empty());
|
||||
let combined: String = patches
|
||||
.iter()
|
||||
.map(|p| String::from_utf8_lossy(&p.data).to_string())
|
||||
.map(|p| String::from_utf8_lossy(&p.as_ref().unwrap().data).to_string())
|
||||
.collect();
|
||||
assert!(combined.contains("diff --git") || combined.contains("@@"));
|
||||
}
|
||||
|
||||
@@ -95,12 +95,7 @@ fn setup_bare_repo() -> (tempfile::TempDir, GitBare) {
|
||||
&["push", "-f", "origin", "refs/tags/v0.1.0:refs/tags/v0.1.0"],
|
||||
);
|
||||
|
||||
(
|
||||
dir,
|
||||
GitBare {
|
||||
bare_dir: bare_dir.clone(),
|
||||
},
|
||||
)
|
||||
(dir, GitBare::new(bare_dir.clone()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+128
-86
@@ -1,13 +1,24 @@
|
||||
mod common;
|
||||
|
||||
use gitks::pb::commit_service_server::CommitService;
|
||||
use gitks::pb::merge_service_server::MergeService;
|
||||
use gitks::pb::tree_service_server::TreeService;
|
||||
use gitks::pb::*;
|
||||
|
||||
#[test]
|
||||
fn test_check_merge_no_conflict() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.check_merge(CheckMergeRequest {
|
||||
repository: None,
|
||||
fn hdr() -> RepositoryHeader {
|
||||
RepositoryHeader {
|
||||
relative_path: "test-repo".into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_check_merge_no_conflict() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.check_merge(tonic::Request::new(CheckMergeRequest {
|
||||
repository: Some(hdr()),
|
||||
target: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -19,8 +30,10 @@ fn test_check_merge_no_conflict() {
|
||||
})),
|
||||
}),
|
||||
options: None,
|
||||
})
|
||||
.expect("check_merge");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(
|
||||
result.status == merge_result::Status::MergeResultStatusMerged as i32
|
||||
@@ -31,12 +44,13 @@ fn test_check_merge_no_conflict() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_merge_with_conflict() {
|
||||
let (_dir, gb) = common::setup_bare_repo_with_conflict();
|
||||
let result = gb
|
||||
.check_merge(CheckMergeRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_check_merge_with_conflict() {
|
||||
let (dir, _gb) = common::setup_bare_repo_with_conflict();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.check_merge(tonic::Request::new(CheckMergeRequest {
|
||||
repository: Some(hdr()),
|
||||
target: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "branch-a".into(),
|
||||
@@ -48,8 +62,10 @@ fn test_check_merge_with_conflict() {
|
||||
})),
|
||||
}),
|
||||
options: None,
|
||||
})
|
||||
.expect("check_merge with conflict");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
result.status,
|
||||
@@ -59,12 +75,13 @@ fn test_check_merge_with_conflict() {
|
||||
assert!(!result.conflicts.is_empty(), "should list conflicted files");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_merge_already_up_to_date() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.check_merge(CheckMergeRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_check_merge_already_up_to_date() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.check_merge(tonic::Request::new(CheckMergeRequest {
|
||||
repository: Some(hdr()),
|
||||
target: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -76,8 +93,10 @@ fn test_check_merge_already_up_to_date() {
|
||||
})),
|
||||
}),
|
||||
options: None,
|
||||
})
|
||||
.expect("check_merge same ref");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
result.status,
|
||||
@@ -85,12 +104,13 @@ fn test_check_merge_already_up_to_date() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_fast_forward() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.merge(MergeRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_merge_fast_forward() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.merge(tonic::Request::new(MergeRequest {
|
||||
repository: Some(hdr()),
|
||||
target_branch: "feature".into(),
|
||||
source: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -100,8 +120,10 @@ fn test_merge_fast_forward() {
|
||||
committer: None,
|
||||
message: String::new(),
|
||||
options: None,
|
||||
})
|
||||
.expect("merge fast-forward");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(
|
||||
result.status == merge_result::Status::MergeResultStatusFastForward as i32
|
||||
@@ -111,12 +133,13 @@ fn test_merge_fast_forward() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_with_conflict() {
|
||||
let (_dir, gb) = common::setup_bare_repo_with_conflict();
|
||||
let result = gb
|
||||
.merge(MergeRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_merge_with_conflict() {
|
||||
let (dir, _gb) = common::setup_bare_repo_with_conflict();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.merge(tonic::Request::new(MergeRequest {
|
||||
repository: Some(hdr()),
|
||||
target_branch: "branch-a".into(),
|
||||
source: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -126,8 +149,10 @@ fn test_merge_with_conflict() {
|
||||
committer: None,
|
||||
message: String::new(),
|
||||
options: None,
|
||||
})
|
||||
.expect("merge with conflict");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
result.status,
|
||||
@@ -136,12 +161,13 @@ fn test_merge_with_conflict() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_fast_forward_only_aborts_non_fast_forward() {
|
||||
let (_dir, gb) = common::setup_bare_repo_with_conflict();
|
||||
let result = gb
|
||||
.merge(MergeRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_merge_fast_forward_only_aborts_non_fast_forward() {
|
||||
let (dir, _gb) = common::setup_bare_repo_with_conflict();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.merge(tonic::Request::new(MergeRequest {
|
||||
repository: Some(hdr()),
|
||||
target_branch: "branch-a".into(),
|
||||
source: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -154,8 +180,10 @@ fn test_merge_fast_forward_only_aborts_non_fast_forward() {
|
||||
fast_forward: merge_options::FastForwardMode::MergeFastForwardModeOnly as i32,
|
||||
..Default::default()
|
||||
}),
|
||||
})
|
||||
.expect("merge fast-forward only");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
result.status,
|
||||
@@ -164,12 +192,13 @@ fn test_merge_fast_forward_only_aborts_non_fast_forward() {
|
||||
assert!(result.commit.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_merge_conflicts() {
|
||||
let (_dir, gb) = common::setup_bare_repo_with_conflict();
|
||||
let result = gb
|
||||
.list_merge_conflicts(ListMergeConflictsRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_list_merge_conflicts() {
|
||||
let (dir, _gb) = common::setup_bare_repo_with_conflict();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.list_merge_conflicts(tonic::Request::new(ListMergeConflictsRequest {
|
||||
repository: Some(hdr()),
|
||||
target: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "branch-a".into(),
|
||||
@@ -181,8 +210,10 @@ fn test_list_merge_conflicts() {
|
||||
})),
|
||||
}),
|
||||
pagination: None,
|
||||
})
|
||||
.expect("list_merge_conflicts");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.conflicts.is_empty(), "should list conflicted files");
|
||||
assert!(
|
||||
@@ -191,13 +222,14 @@ fn test_list_merge_conflicts() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_merge_conflicts() {
|
||||
let (_dir, gb) = common::setup_bare_repo_with_conflict();
|
||||
#[tokio::test]
|
||||
async fn test_resolve_merge_conflicts() {
|
||||
let (dir, _gb) = common::setup_bare_repo_with_conflict();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
let result = gb
|
||||
.resolve_merge_conflicts(ResolveMergeConflictsRequest {
|
||||
repository: None,
|
||||
let result = svc
|
||||
.resolve_merge_conflicts(tonic::Request::new(ResolveMergeConflictsRequest {
|
||||
repository: Some(hdr()),
|
||||
target_branch: "branch-a".into(),
|
||||
source: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -210,8 +242,10 @@ fn test_resolve_merge_conflicts() {
|
||||
}],
|
||||
committer: None,
|
||||
message: "resolved conflicts".into(),
|
||||
})
|
||||
.expect("resolve_merge_conflicts");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
result.status,
|
||||
@@ -219,9 +253,9 @@ fn test_resolve_merge_conflicts() {
|
||||
);
|
||||
assert!(result.commit.is_some());
|
||||
|
||||
let blob = gb
|
||||
.get_blob(GetBlobRequest {
|
||||
repository: None,
|
||||
let blob = svc
|
||||
.get_blob(tonic::Request::new(GetBlobRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "branch-a".into(),
|
||||
@@ -230,17 +264,20 @@ fn test_resolve_merge_conflicts() {
|
||||
path: "file.txt".into(),
|
||||
oid: None,
|
||||
max_bytes: 0,
|
||||
})
|
||||
.expect("get resolved blob");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(String::from_utf8_lossy(&blob.data), "resolved content\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rebase() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
#[tokio::test]
|
||||
async fn test_rebase() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
gb.create_commit(CreateCommitRequest {
|
||||
repository: None,
|
||||
svc.create_commit(tonic::Request::new(CreateCommitRequest {
|
||||
repository: Some(hdr()),
|
||||
branch: "feature".into(),
|
||||
message: "feature work".into(),
|
||||
author: None,
|
||||
@@ -261,12 +298,13 @@ fn test_rebase() {
|
||||
}),
|
||||
force: false,
|
||||
trailers: vec![],
|
||||
})
|
||||
.expect("create feature commit");
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let result = gb
|
||||
.rebase(RebaseRequest {
|
||||
repository: None,
|
||||
let result = svc
|
||||
.rebase(tonic::Request::new(RebaseRequest {
|
||||
repository: Some(hdr()),
|
||||
branch: "feature".into(),
|
||||
upstream: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -274,8 +312,10 @@ fn test_rebase() {
|
||||
})),
|
||||
}),
|
||||
committer: None,
|
||||
})
|
||||
.expect("rebase");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(
|
||||
result.status,
|
||||
@@ -283,9 +323,9 @@ fn test_rebase() {
|
||||
);
|
||||
assert!(result.head.is_some());
|
||||
|
||||
let blob = gb
|
||||
.get_blob(GetBlobRequest {
|
||||
repository: None,
|
||||
let blob = svc
|
||||
.get_blob(tonic::Request::new(GetBlobRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "feature".into(),
|
||||
@@ -294,7 +334,9 @@ fn test_rebase() {
|
||||
path: "feature.txt".into(),
|
||||
oid: None,
|
||||
max_bytes: 0,
|
||||
})
|
||||
.expect("get rebased feature file");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(String::from_utf8_lossy(&blob.data), "feature content");
|
||||
}
|
||||
|
||||
+174
-81
@@ -3,10 +3,7 @@ mod common;
|
||||
use gitks::bare::GitBare;
|
||||
use gitks::pb::repository_service_server::RepositoryService;
|
||||
use gitks::pb::*;
|
||||
use gitks::server::GitksService;
|
||||
|
||||
fn header(gb: &GitBare) -> RepositoryHeader {
|
||||
let parent = gb.bare_dir.parent().unwrap().to_string_lossy().into_owned();
|
||||
let name = gb
|
||||
.bare_dir
|
||||
.file_name()
|
||||
@@ -14,7 +11,6 @@ fn header(gb: &GitBare) -> RepositoryHeader {
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
RepositoryHeader {
|
||||
storage_path: parent,
|
||||
relative_path: name,
|
||||
..Default::default()
|
||||
}
|
||||
@@ -26,8 +22,9 @@ fn req<T>(gb: &GitBare, f: impl FnOnce(RepositoryHeader) -> T) -> tonic::Request
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_repository() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let repo = GitksService
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let repo = svc
|
||||
.get_repository(req(&gb, |r| GetRepositoryRequest {
|
||||
repository: Some(r),
|
||||
}))
|
||||
@@ -42,13 +39,11 @@ async fn test_get_repository() {
|
||||
#[tokio::test]
|
||||
async fn test_init_and_delete_repository() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let storage = dir.path().to_string_lossy().into_owned();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let hdr = RepositoryHeader {
|
||||
storage_path: storage.clone(),
|
||||
relative_path: "new-repo".into(),
|
||||
..Default::default()
|
||||
};
|
||||
let svc = GitksService;
|
||||
svc.init_repository(tonic::Request::new(InitRepositoryRequest {
|
||||
repository: Some(hdr.clone()),
|
||||
bare: true,
|
||||
@@ -83,8 +78,9 @@ async fn test_init_and_delete_repository() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_object_format() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let resp = GitksService
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let resp = svc
|
||||
.get_object_format(req(&gb, |r| RepositoryObjectFormatRequest {
|
||||
repository: Some(r),
|
||||
}))
|
||||
@@ -96,53 +92,51 @@ async fn test_get_object_format() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_set_default_branch() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let h = header(&gb);
|
||||
assert_eq!(
|
||||
GitksService
|
||||
.get_default_branch(tonic::Request::new(GetDefaultBranchRequest {
|
||||
repository: Some(h.clone())
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.name,
|
||||
"main"
|
||||
);
|
||||
GitksService
|
||||
.set_default_branch(tonic::Request::new(SetDefaultBranchRequest {
|
||||
repository: Some(h.clone()),
|
||||
name: "feature".into(),
|
||||
svc.get_default_branch(tonic::Request::new(GetDefaultBranchRequest {
|
||||
repository: Some(h.clone())
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.name,
|
||||
"main"
|
||||
);
|
||||
svc.set_default_branch(tonic::Request::new(SetDefaultBranchRequest {
|
||||
repository: Some(h.clone()),
|
||||
name: "feature".into(),
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
GitksService
|
||||
.get_default_branch(tonic::Request::new(GetDefaultBranchRequest {
|
||||
repository: Some(h)
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.name,
|
||||
svc.get_default_branch(tonic::Request::new(GetDefaultBranchRequest {
|
||||
repository: Some(h)
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.name,
|
||||
"feature"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_set_repository_config() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
GitksService
|
||||
.set_repository_config(tonic::Request::new(SetRepositoryConfigRequest {
|
||||
repository: Some(header(&gb)),
|
||||
entries: vec![RepositoryConfigEntry {
|
||||
key: "test.key".into(),
|
||||
values: vec!["val1".into(), "val2".into()],
|
||||
}],
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
let entry = GitksService
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
svc.set_repository_config(tonic::Request::new(SetRepositoryConfigRequest {
|
||||
repository: Some(header(&gb)),
|
||||
entries: vec![RepositoryConfigEntry {
|
||||
key: "test.key".into(),
|
||||
values: vec!["val1".into(), "val2".into()],
|
||||
}],
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
let entry = svc
|
||||
.get_repository_config(tonic::Request::new(GetRepositoryConfigRequest {
|
||||
repository: Some(header(&gb)),
|
||||
keys: vec!["test.key".into()],
|
||||
@@ -159,8 +153,9 @@ async fn test_get_set_repository_config() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_repository_statistics() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let s = GitksService
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let s = svc
|
||||
.get_repository_statistics(req(&gb, |r| RepositoryStatisticsRequest {
|
||||
repository: Some(r),
|
||||
}))
|
||||
@@ -174,8 +169,9 @@ async fn test_get_repository_statistics() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_check_repository_health() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let h = GitksService
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let h = svc
|
||||
.check_repository_health(tonic::Request::new(RepositoryHealthRequest {
|
||||
repository: Some(header(&gb)),
|
||||
connectivity_only: true,
|
||||
@@ -188,48 +184,145 @@ async fn test_check_repository_health() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_garbage_collect() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
assert!(
|
||||
GitksService
|
||||
.garbage_collect(tonic::Request::new(GarbageCollectRequest {
|
||||
repository: Some(header(&gb)),
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.ok
|
||||
svc.garbage_collect(tonic::Request::new(GarbageCollectRequest {
|
||||
repository: Some(header(&gb)),
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.ok
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_repack() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
assert!(
|
||||
GitksService
|
||||
.repack(tonic::Request::new(RepackRequest {
|
||||
repository: Some(header(&gb)),
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.ok
|
||||
svc.repack(tonic::Request::new(RepackRequest {
|
||||
repository: Some(header(&gb)),
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.ok
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_write_commit_graph() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let (dir, gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
assert!(
|
||||
GitksService
|
||||
.write_commit_graph(tonic::Request::new(WriteCommitGraphRequest {
|
||||
repository: Some(header(&gb)),
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.ok
|
||||
svc.write_commit_graph(tonic::Request::new(WriteCommitGraphRequest {
|
||||
repository: Some(header(&gb)),
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.ok
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_resolve_none_header() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.get_repository(tonic::Request::new(GetRepositoryRequest {
|
||||
repository: None,
|
||||
}))
|
||||
.await;
|
||||
assert!(result.is_err(), "should fail with None header");
|
||||
let err = result.unwrap_err();
|
||||
assert_eq!(err.code(), tonic::Code::InvalidArgument);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_resolve_empty_relative_path() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.get_repository(tonic::Request::new(GetRepositoryRequest {
|
||||
repository: Some(RepositoryHeader {
|
||||
relative_path: String::new(),
|
||||
..Default::default()
|
||||
}),
|
||||
}))
|
||||
.await;
|
||||
assert!(result.is_err(), "should fail with empty relative_path");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_resolve_nonexistent_repo() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.get_repository(tonic::Request::new(GetRepositoryRequest {
|
||||
repository: Some(RepositoryHeader {
|
||||
relative_path: "does-not-exist".into(),
|
||||
..Default::default()
|
||||
}),
|
||||
}))
|
||||
.await;
|
||||
assert!(result.is_err(), "should fail for nonexistent repo");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_init_empty_relative_path() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.init_repository(tonic::Request::new(InitRepositoryRequest {
|
||||
repository: Some(RepositoryHeader {
|
||||
relative_path: String::new(),
|
||||
..Default::default()
|
||||
}),
|
||||
bare: true,
|
||||
..Default::default()
|
||||
}))
|
||||
.await;
|
||||
assert!(result.is_err(), "should fail with empty relative_path");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delete_nonexistent_repo() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let svc = common::setup_service(dir.path());
|
||||
// Deleting a non-existent path should succeed (fs::remove_dir_all on non-existent is ok)
|
||||
// or fail gracefully
|
||||
let result = svc
|
||||
.delete_repository(tonic::Request::new(DeleteRepositoryRequest {
|
||||
repository: Some(RepositoryHeader {
|
||||
relative_path: "ghost-repo".into(),
|
||||
..Default::default()
|
||||
}),
|
||||
}))
|
||||
.await;
|
||||
// It either succeeds (dir doesn't exist, nothing to delete) or fails
|
||||
// Both are acceptable behaviors
|
||||
let _ = result;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exists_nonexistent_repo() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.repository_exists(tonic::Request::new(RepositoryExistsRequest {
|
||||
repository: Some(RepositoryHeader {
|
||||
relative_path: "nonexistent".into(),
|
||||
..Default::default()
|
||||
}),
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert!(!result.exists);
|
||||
}
|
||||
|
||||
+91
-61
@@ -1,44 +1,59 @@
|
||||
mod common;
|
||||
|
||||
use gitks::pb::tag_service_server::TagService;
|
||||
use gitks::pb::*;
|
||||
|
||||
#[test]
|
||||
fn test_list_tags() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.list_tags(ListTagsRequest {
|
||||
repository: None,
|
||||
fn hdr() -> RepositoryHeader {
|
||||
RepositoryHeader {
|
||||
relative_path: "test-repo".into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_list_tags() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.list_tags(tonic::Request::new(ListTagsRequest {
|
||||
repository: Some(hdr()),
|
||||
pattern: String::new(),
|
||||
pagination: None,
|
||||
sort_direction: 0,
|
||||
})
|
||||
.expect("list_tags");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
let names: Vec<String> = result.tags.iter().map(|t| t.name.clone()).collect();
|
||||
assert!(names.contains(&"v0.1.0".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_tag() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let tag = gb
|
||||
.get_tag(GetTagRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_tag() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let tag = svc
|
||||
.get_tag(tonic::Request::new(GetTagRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "v0.1.0".into(),
|
||||
include_raw: false,
|
||||
})
|
||||
.expect("get_tag");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(tag.name, "v0.1.0");
|
||||
assert!(tag.target_oid.is_some());
|
||||
assert_eq!(tag.full_ref, "refs/tags/v0.1.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_and_delete_lightweight_tag() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let tag = gb
|
||||
.create_tag(CreateTagRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_create_and_delete_lightweight_tag() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let tag = svc
|
||||
.create_tag(tonic::Request::new(CreateTagRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "v0.2.0".into(),
|
||||
target: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -49,32 +64,38 @@ fn test_create_and_delete_lightweight_tag() {
|
||||
tagger: None,
|
||||
force: false,
|
||||
annotated: false,
|
||||
})
|
||||
.expect("create_tag");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(tag.name, "v0.2.0");
|
||||
assert!(!tag.annotated);
|
||||
|
||||
gb.delete_tag(DeleteTagRequest {
|
||||
repository: None,
|
||||
svc.delete_tag(tonic::Request::new(DeleteTagRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "v0.2.0".into(),
|
||||
})
|
||||
.expect("delete_tag");
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let result = gb.get_tag(GetTagRequest {
|
||||
repository: None,
|
||||
name: "v0.2.0".into(),
|
||||
include_raw: false,
|
||||
});
|
||||
let result = svc
|
||||
.get_tag(tonic::Request::new(GetTagRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "v0.2.0".into(),
|
||||
include_raw: false,
|
||||
}))
|
||||
.await;
|
||||
assert!(result.is_err(), "deleted tag should not exist");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_annotated_tag() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let tag = gb
|
||||
.create_tag(CreateTagRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_create_annotated_tag() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let tag = svc
|
||||
.create_tag(tonic::Request::new(CreateTagRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "v1.0.0".into(),
|
||||
target: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -85,8 +106,10 @@ fn test_create_annotated_tag() {
|
||||
tagger: None,
|
||||
force: false,
|
||||
annotated: true,
|
||||
})
|
||||
.expect("create annotated tag");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(tag.name, "v1.0.0");
|
||||
assert!(tag.annotated, "should be annotated");
|
||||
@@ -97,12 +120,13 @@ fn test_create_annotated_tag() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_tags_with_pattern() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
#[tokio::test]
|
||||
async fn test_list_tags_with_pattern() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
|
||||
gb.create_tag(CreateTagRequest {
|
||||
repository: None,
|
||||
svc.create_tag(tonic::Request::new(CreateTagRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "release-1.0".into(),
|
||||
target: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
@@ -113,17 +137,20 @@ fn test_list_tags_with_pattern() {
|
||||
tagger: None,
|
||||
force: false,
|
||||
annotated: false,
|
||||
})
|
||||
.expect("create release tag");
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let result = gb
|
||||
.list_tags(ListTagsRequest {
|
||||
repository: None,
|
||||
let result = svc
|
||||
.list_tags(tonic::Request::new(ListTagsRequest {
|
||||
repository: Some(hdr()),
|
||||
pattern: "release".into(),
|
||||
pagination: None,
|
||||
sort_direction: 0,
|
||||
})
|
||||
.expect("list_tags with pattern");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(
|
||||
result.tags.iter().all(|t| t.name.contains("release")),
|
||||
@@ -132,15 +159,18 @@ fn test_list_tags_with_pattern() {
|
||||
assert!(!result.tags.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_tag() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.verify_tag(VerifyTagRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_verify_tag() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.verify_tag(tonic::Request::new(VerifyTagRequest {
|
||||
repository: Some(hdr()),
|
||||
name: "v0.1.0".into(),
|
||||
})
|
||||
.expect("verify_tag");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.verified, "unsigned tag should not be verified");
|
||||
}
|
||||
|
||||
+119
-61
@@ -1,13 +1,22 @@
|
||||
mod common;
|
||||
|
||||
use gitks::pb::tree_service_server::TreeService;
|
||||
use gitks::pb::*;
|
||||
|
||||
#[test]
|
||||
fn test_list_tree_recursive() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.list_tree(ListTreeRequest {
|
||||
repository: None,
|
||||
fn hdr() -> RepositoryHeader {
|
||||
RepositoryHeader {
|
||||
relative_path: "test-repo".into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_list_tree_recursive() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.list_tree(tonic::Request::new(ListTreeRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -16,8 +25,10 @@ fn test_list_tree_recursive() {
|
||||
path: String::new(),
|
||||
recursive: true,
|
||||
pagination: None,
|
||||
})
|
||||
.expect("list_tree recursive");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let paths: Vec<String> = result.entries.iter().map(|e| e.path.clone()).collect();
|
||||
assert!(
|
||||
@@ -27,33 +38,38 @@ fn test_list_tree_recursive() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_tree_subpath() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.get_tree(GetTreeRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_tree_subpath() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.get_tree(tonic::Request::new(GetTreeRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
})),
|
||||
}),
|
||||
path: "src".into(),
|
||||
})
|
||||
.expect("get_tree subpath");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(result.oid.is_some());
|
||||
let root_tree = gb
|
||||
.get_tree(GetTreeRequest {
|
||||
repository: None,
|
||||
let root_tree = svc
|
||||
.get_tree(tonic::Request::new(GetTreeRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
})),
|
||||
}),
|
||||
path: String::new(),
|
||||
})
|
||||
.expect("get_tree root");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_ne!(
|
||||
result.oid.unwrap().hex,
|
||||
root_tree.oid.unwrap().hex,
|
||||
@@ -61,12 +77,13 @@ fn test_get_tree_subpath() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_files() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.find_files(FindFilesRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_find_files() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.find_files(tonic::Request::new(FindFilesRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -75,19 +92,22 @@ fn test_find_files() {
|
||||
pattern: "mod.rs".into(),
|
||||
pathspec: vec![],
|
||||
pagination: None,
|
||||
})
|
||||
.expect("find_files");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert!(!result.files.is_empty());
|
||||
assert!(result.files.iter().all(|f| f.path.contains("mod.rs")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_blob() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let blob = gb
|
||||
.get_blob(GetBlobRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_blob() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let blob = svc
|
||||
.get_blob(tonic::Request::new(GetBlobRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -96,8 +116,10 @@ fn test_get_blob() {
|
||||
path: "README.md".into(),
|
||||
oid: None,
|
||||
max_bytes: 0,
|
||||
})
|
||||
.expect("get_blob");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let content = String::from_utf8_lossy(&blob.data);
|
||||
assert!(content.contains("# Test"));
|
||||
@@ -105,12 +127,13 @@ fn test_get_blob() {
|
||||
assert!(!blob.binary);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_blob_with_truncation() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let blob = gb
|
||||
.get_blob(GetBlobRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_blob_with_truncation() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let blob = svc
|
||||
.get_blob(tonic::Request::new(GetBlobRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -119,8 +142,10 @@ fn test_get_blob_with_truncation() {
|
||||
path: "README.md".into(),
|
||||
oid: None,
|
||||
max_bytes: 5,
|
||||
})
|
||||
.expect("get_blob truncated");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(blob.data.len(), 5);
|
||||
assert!(blob.truncated);
|
||||
@@ -130,32 +155,36 @@ fn test_get_blob_with_truncation() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_file_metadata() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let meta = gb
|
||||
.get_file_metadata(GetFileMetadataRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_get_file_metadata() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let meta = svc
|
||||
.get_file_metadata(tonic::Request::new(GetFileMetadataRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
})),
|
||||
}),
|
||||
path: "README.md".into(),
|
||||
})
|
||||
.expect("get_file_metadata");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(meta.path, "README.md");
|
||||
assert!(meta.oid.is_some());
|
||||
assert_eq!(meta.r#type, ObjectType::Blob as i32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_tree_with_pagination() {
|
||||
let (_dir, gb) = common::setup_bare_repo();
|
||||
let result = gb
|
||||
.list_tree(ListTreeRequest {
|
||||
repository: None,
|
||||
#[tokio::test]
|
||||
async fn test_list_tree_with_pagination() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let result = svc
|
||||
.list_tree(tonic::Request::new(ListTreeRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
@@ -167,10 +196,39 @@ fn test_list_tree_with_pagination() {
|
||||
page_size: 1,
|
||||
page_token: String::new(),
|
||||
}),
|
||||
})
|
||||
.expect("list_tree paginated");
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
assert_eq!(result.entries.len(), 1);
|
||||
let pi = result.page_info.unwrap();
|
||||
assert!(pi.has_next_page);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_raw_blob() {
|
||||
let (dir, _gb) = common::setup_bare_repo();
|
||||
let svc = common::setup_service(dir.path());
|
||||
let stream = svc
|
||||
.get_raw_blob(tonic::Request::new(GetRawBlobRequest {
|
||||
repository: Some(hdr()),
|
||||
revision: Some(ObjectSelector {
|
||||
selector: Some(object_selector::Selector::Revision(ObjectName {
|
||||
revision: "main".into(),
|
||||
})),
|
||||
}),
|
||||
path: "README.md".into(),
|
||||
oid: None,
|
||||
}))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let chunks: Vec<_> = tokio_stream::StreamExt::collect(stream).await;
|
||||
assert!(!chunks.is_empty(), "should have raw blob data");
|
||||
let data = &chunks[0].as_ref().unwrap().data;
|
||||
assert!(!data.is_empty(), "raw blob should not be empty");
|
||||
let content = String::from_utf8_lossy(data);
|
||||
assert!(content.contains("# Test"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user