docs(handoff): log 2026-07-08 — hexagonal architecture refactor, adapters, integration tests, notsecrets cleanup
- Completed hexagonal architecture refactor with adapter pattern - Added comprehensive integration tests - Cleaned up notsecrets integration - Moved config payload to notfiles-config repo Commits:6427d18,25624c9
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
project: notfiles
|
||||
id: notfile
|
||||
updated: 2026-07-07
|
||||
updated: 2026-07-08
|
||||
items:
|
||||
- id: uncommitted-work
|
||||
doob_uuid: null
|
||||
@@ -20,6 +20,11 @@ items:
|
||||
completed: null
|
||||
extra: []
|
||||
log:
|
||||
- date: 2026-07-08
|
||||
summary: hexagonal architecture refactor with adapters and integration tests, notsecrets cleanup, config payload moved to notfiles-config repo
|
||||
commits:
|
||||
- 6427d18
|
||||
- 25624c9
|
||||
- date: '20260606.135918'
|
||||
summary: done=13 running=0 pending=0 blocked=0
|
||||
commits: []
|
||||
|
||||
203
crates/notforge/tests/gitea.rs
Normal file
203
crates/notforge/tests/gitea.rs
Normal file
@@ -0,0 +1,203 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use notforge::config::RepoSpec;
|
||||
use notforge::error::NotforgeError;
|
||||
use notforge::gitea::{
|
||||
GiteaHttpApi, GiteaHttpRequest, GiteaHttpResponse, GiteaTransport, HttpMethod,
|
||||
};
|
||||
use notforge::ports::{ForgeApi, ForgeAuth};
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct RecordedRequest {
|
||||
method: HttpMethod,
|
||||
url: String,
|
||||
authorization: Option<String>,
|
||||
body: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FakeTransport {
|
||||
requests: Arc<Mutex<Vec<RecordedRequest>>>,
|
||||
responses: Arc<Mutex<Vec<Result<GiteaHttpResponse, NotforgeError>>>>,
|
||||
}
|
||||
|
||||
impl FakeTransport {
|
||||
fn new(responses: Vec<Result<GiteaHttpResponse, NotforgeError>>) -> Self {
|
||||
Self {
|
||||
requests: Arc::new(Mutex::new(Vec::new())),
|
||||
responses: Arc::new(Mutex::new(responses)),
|
||||
}
|
||||
}
|
||||
|
||||
fn requests(&self) -> Vec<RecordedRequest> {
|
||||
self.requests.lock().unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl GiteaTransport for FakeTransport {
|
||||
fn send(&self, request: GiteaHttpRequest) -> Result<GiteaHttpResponse, NotforgeError> {
|
||||
self.requests.lock().unwrap().push(RecordedRequest {
|
||||
method: request.method,
|
||||
url: request.url,
|
||||
authorization: request.authorization,
|
||||
body: request.body,
|
||||
});
|
||||
self.responses.lock().unwrap().remove(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_gets_gitea_server_version() {
|
||||
let transport = FakeTransport::new(vec![Ok(GiteaHttpResponse {
|
||||
status: 200,
|
||||
body: json!({ "version": "1.22.4" }),
|
||||
})]);
|
||||
let api = GiteaHttpApi::with_transport("http://gitea.local:3000/", transport.clone());
|
||||
|
||||
let version = api.version().unwrap();
|
||||
|
||||
assert_eq!(version.version, "1.22.4");
|
||||
let requests = transport.requests();
|
||||
assert_eq!(requests.len(), 1);
|
||||
assert_eq!(requests[0].method, HttpMethod::Get);
|
||||
assert_eq!(requests[0].url, "http://gitea.local:3000/api/v1/version");
|
||||
assert_eq!(requests[0].authorization, None);
|
||||
assert_eq!(requests[0].body, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repo_maps_found_and_not_found_responses() {
|
||||
let transport = FakeTransport::new(vec![
|
||||
Ok(GiteaHttpResponse {
|
||||
status: 200,
|
||||
body: json!({
|
||||
"owner": { "login": "joe" },
|
||||
"name": "notfiles-config",
|
||||
"clone_url": "http://gitea.local:3000/joe/notfiles-config.git",
|
||||
"ssh_url": "ssh://git@gitea.local:2222/joe/notfiles-config.git"
|
||||
}),
|
||||
}),
|
||||
Ok(GiteaHttpResponse {
|
||||
status: 404,
|
||||
body: json!({ "message": "not found" }),
|
||||
}),
|
||||
]);
|
||||
let api = GiteaHttpApi::with_transport("http://gitea.local:3000", transport.clone());
|
||||
|
||||
let found = api.repo("joe", "notfiles-config").unwrap().unwrap();
|
||||
let missing = api.repo("joe", "missing").unwrap();
|
||||
|
||||
assert_eq!(found.owner, "joe");
|
||||
assert_eq!(found.name, "notfiles-config");
|
||||
assert_eq!(
|
||||
found.clone_url,
|
||||
"http://gitea.local:3000/joe/notfiles-config.git"
|
||||
);
|
||||
assert_eq!(
|
||||
found.ssh_url,
|
||||
"ssh://git@gitea.local:2222/joe/notfiles-config.git"
|
||||
);
|
||||
assert_eq!(missing, None);
|
||||
|
||||
let requests = transport.requests();
|
||||
assert_eq!(
|
||||
requests[0].url,
|
||||
"http://gitea.local:3000/api/v1/repos/joe/notfiles-config"
|
||||
);
|
||||
assert_eq!(
|
||||
requests[1].url,
|
||||
"http://gitea.local:3000/api/v1/repos/joe/missing"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_repo_posts_json_with_token_auth() {
|
||||
let transport = FakeTransport::new(vec![Ok(GiteaHttpResponse {
|
||||
status: 201,
|
||||
body: json!({
|
||||
"owner": { "login": "joe" },
|
||||
"name": "notfiles-config",
|
||||
"clone_url": "http://gitea.local:3000/joe/notfiles-config.git",
|
||||
"ssh_url": "ssh://git@gitea.local:2222/joe/notfiles-config.git"
|
||||
}),
|
||||
})]);
|
||||
let api = GiteaHttpApi::with_transport("http://gitea.local:3000", transport.clone());
|
||||
let spec = RepoSpec {
|
||||
owner: "joe".to_string(),
|
||||
name: "notfiles-config".to_string(),
|
||||
private: true,
|
||||
description: Some("Personal config payload".to_string()),
|
||||
remote_name: "gitea".to_string(),
|
||||
};
|
||||
|
||||
let repo = api
|
||||
.create_repo(
|
||||
&spec,
|
||||
&ForgeAuth::Token {
|
||||
token: "redacted".to_string(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(repo.owner, "joe");
|
||||
let requests = transport.requests();
|
||||
assert_eq!(requests.len(), 1);
|
||||
assert_eq!(requests[0].method, HttpMethod::Post);
|
||||
assert_eq!(requests[0].url, "http://gitea.local:3000/api/v1/user/repos");
|
||||
assert_eq!(
|
||||
requests[0].authorization,
|
||||
Some("token redacted".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
requests[0].body,
|
||||
Some(json!({
|
||||
"name": "notfiles-config",
|
||||
"private": true,
|
||||
"description": "Personal config payload"
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_repo_posts_json_with_basic_auth() {
|
||||
let transport = FakeTransport::new(vec![Ok(GiteaHttpResponse {
|
||||
status: 201,
|
||||
body: json!({
|
||||
"owner": { "login": "joe" },
|
||||
"name": "notfiles-config",
|
||||
"clone_url": "http://gitea.local:3000/joe/notfiles-config.git",
|
||||
"ssh_url": "ssh://git@gitea.local:2222/joe/notfiles-config.git"
|
||||
}),
|
||||
})]);
|
||||
let api = GiteaHttpApi::with_transport("http://gitea.local:3000", transport.clone());
|
||||
let spec = RepoSpec {
|
||||
owner: "joe".to_string(),
|
||||
name: "notfiles-config".to_string(),
|
||||
private: true,
|
||||
description: None,
|
||||
remote_name: "gitea".to_string(),
|
||||
};
|
||||
|
||||
api.create_repo(
|
||||
&spec,
|
||||
&ForgeAuth::Basic {
|
||||
username: "joe".to_string(),
|
||||
password: "secret".to_string(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let requests = transport.requests();
|
||||
assert_eq!(
|
||||
requests[0].authorization,
|
||||
Some("Basic am9lOnNlY3JldA==".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
requests[0].body,
|
||||
Some(json!({
|
||||
"name": "notfiles-config",
|
||||
"private": true
|
||||
}))
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user