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:
+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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user