use std::process::Command;
use std::sync::Arc;
use actix_web::{App, HttpServer, web};
use aleph_types::account::{Account, EvmAccount};
use aleph_types::chain::Chain;
use heph::api::{AppState, configure_routes};
use heph::config::HephConfig;
use heph::db::Db;
use heph::files::FileStore;
const TEST_KEY: [u8; 32] = [1u8; 32];
fn start_test_server() -> String {
let db = Arc::new(Db::open_in_memory().unwrap());
let tmpdir = tempfile::tempdir().unwrap();
let file_store = Arc::new(FileStore::new(&tmpdir.keep().join("files")).unwrap());
let account = EvmAccount::new(Chain::Ethereum, &TEST_KEY).unwrap();
let addr = account.address().as_str().to_string();
db.with_conn(|c| heph::db::balances::set_credit_balance(c, &addr, 1_000_000_000))
.unwrap();
let config = HephConfig {
port: 0,
host: "127.0.0.1".to_string(),
data_dir: None,
accounts: vec![addr],
balance: 1_000_000_000,
log_level: "error".to_string(),
};
let (tx, rx) = std::sync::mpsc::channel::<u16>();
std::thread::spawn(move || {
let state = web::Data::new(AppState {
db,
file_store,
config,
corechannel: std::sync::Mutex::new(heph::corechannel::CoreChannelState::new()),
});
let sys = actix_web::rt::System::new();
sys.block_on(async move {
let server = HttpServer::new(move || {
App::new()
.app_data(state.clone())
.configure(configure_routes)
})
.bind("127.0.0.1:0")
.unwrap();
let port = server.addrs()[0].port();
tx.send(port).unwrap();
server.run().await.unwrap();
});
});
let port = rx.recv().unwrap();
format!("http://127.0.0.1:{port}/")
}
#[test]
fn dir_upload_default_uses_add_car_and_succeeds() {
let base_url = start_test_server();
let tmpdir = tempfile::tempdir().unwrap();
std::fs::write(tmpdir.path().join("a.txt"), b"hello").unwrap();
std::fs::write(tmpdir.path().join("b.txt"), b"world").unwrap();
let private_key_hex = hex::encode(TEST_KEY);
let output = Command::new(env!("CARGO_BIN_EXE_aleph"))
.args([
"--ccn",
&base_url,
"--json",
"file",
"upload",
"--private-key",
&private_key_hex,
"--chain",
"eth",
tmpdir.path().to_str().unwrap(),
])
.output()
.expect("failed to spawn aleph binary");
assert!(
output.status.success(),
"aleph exited with {:?}\nstdout: {}\nstderr: {}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
let stdout = String::from_utf8(output.stdout).unwrap();
assert!(
!stdout.trim().is_empty(),
"expected non-empty stdout from JSON envelope"
);
let envelope: serde_json::Value =
serde_json::from_str(&stdout).expect("stdout should be valid JSON");
let account = EvmAccount::new(Chain::Ethereum, &TEST_KEY).unwrap();
let expected_sender = Account::address(&account).as_str().to_string();
assert!(envelope["item_hash"].is_string(), "envelope: {envelope}");
assert_eq!(envelope["type"], "STORE");
assert_eq!(envelope["chain"], "ETH");
assert_eq!(envelope["sender"], expected_sender);
assert!(envelope["time"].is_number(), "envelope: {envelope}");
assert!(envelope["explorer_url"].is_string(), "envelope: {envelope}");
assert_eq!(envelope["publication_status"], "success");
assert_eq!(envelope["message_status"], "processed");
}
#[test]
fn dir_upload_with_use_gateway_relay_does_not_hit_add_car() {
let base_url = start_test_server();
let tmpdir = tempfile::tempdir().unwrap();
std::fs::write(tmpdir.path().join("a.txt"), b"hello").unwrap();
let private_key_hex = hex::encode(TEST_KEY);
let output = Command::new(env!("CARGO_BIN_EXE_aleph"))
.args([
"--ccn",
&base_url,
"file",
"upload",
"--private-key",
&private_key_hex,
"--chain",
"eth",
"--use-gateway-relay",
"--ipfs-gateway",
&base_url,
tmpdir.path().to_str().unwrap(),
])
.output()
.expect("failed to spawn aleph binary");
assert!(
!output.status.success(),
"expected gateway-relay path to fail against heph (no /api/v0/add endpoint)\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}