Files
Sergio 53dbdf0f1d chore: monorepo inicial con arje + minga + yahweh absorbidos
Workspace en 4 ejes (core/modules/apps/shared):

- core/: 24 crates de arje (Init systemd-compatible: ente-card, ente-zero,
  ente-kernel, ente-bus, ente-cas, ente-soma, ente-wasm, ente-snapshot,
  ente-brain, ente-echo, ente-policy-provider, + 12 crates *-compat)
- modules/semantic_dht/: 5 crates de minga (minga-core con AST/CAS/MST,
  minga-p2p con libp2p Kad, minga-store, minga-vfs, minga-cli)
- modules/ui_engine/: 11 crates de yahweh (libs/{core,theme,bus,providers},
  widgets/{tree,splitter,tabs,tiled,container_core,text_input})
- apps/: 5 crates de yahweh (file_explorer, database_explorer, text_viewer,
  image_viewer, yahweh-shell)
- shared_wit/protocol.wit: handshake/lifecycle inicial

Cargo.toml unificado: thiserror bumped a 2 (transparente para arje), tokio
"full", paths intra-workspace de yahweh redirigidos a su nueva ubicación.

cargo check --workspace: 0 errores, 17 warnings (dead code preexistente).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 04:45:44 +00:00

162 lines
5.6 KiB
Rust

//! Tests del `run_sync_async` sobre canales async in-memory.
//!
//! Equivalentes a los del harness síncrono pero ejecutados sobre
//! `tokio::io::duplex` — la misma lógica protocolar viajando sobre
//! bytes serializados con postcard, encuadrados con length-prefix, y
//! transportados por una pipa async. Si esto pasa, lo único que falta
//! para el sync sobre TCP/QUIC/libp2p es enchufar el transporte real.
use minga_core::{parse, ContentHash, Keypair, MemStore, Mst, NodeStore};
use minga_p2p::{run_sync_async, SyncSession};
fn kp(seed: u8) -> Keypair {
Keypair::from_seed(&[seed; 32])
}
fn build_repo(sources: &[&str]) -> (Mst, MemStore, Vec<ContentHash>) {
let mut mst = Mst::new();
let mut store = MemStore::new();
let mut roots = Vec::new();
for src in sources {
let n = parse::rust(src).unwrap();
let h = store.put(&n);
mst.insert(h);
roots.push(h);
}
(mst, store, roots)
}
#[tokio::test]
async fn async_sync_identical_repos() {
let sources = &["fn add(x: i32, y: i32) -> i32 { x + y }"];
let (mst_a, store_a, _) = build_repo(sources);
let (mst_b, store_b, _) = build_repo(sources);
let session_a = SyncSession::without_attestations(mst_a, store_a, kp(1));
let session_b = SyncSession::without_attestations(mst_b, store_b, kp(2));
let (a_stream, b_stream) = tokio::io::duplex(64 * 1024);
let task_a = tokio::spawn(run_sync_async(session_a, a_stream));
let task_b = tokio::spawn(run_sync_async(session_b, b_stream));
let a = task_a.await.unwrap().unwrap();
let b = task_b.await.unwrap().unwrap();
assert_eq!(a.mst().root_hash(), b.mst().root_hash());
}
#[tokio::test]
async fn async_sync_one_empty_pulls_everything() {
let sources = &["fn complex(x: i32) -> i32 { let y = x * 2; y + 1 }"];
let (mst_a, store_a, _) = build_repo(sources);
let (mst_b, store_b, _) = build_repo(&[]);
let store_a_size = store_a.len();
let session_a = SyncSession::without_attestations(mst_a, store_a, kp(1));
let session_b = SyncSession::without_attestations(mst_b, store_b, kp(2));
let (a_stream, b_stream) = tokio::io::duplex(64 * 1024);
let task_a = tokio::spawn(run_sync_async(session_a, a_stream));
let task_b = tokio::spawn(run_sync_async(session_b, b_stream));
let a = task_a.await.unwrap().unwrap();
let b = task_b.await.unwrap().unwrap();
assert_eq!(a.mst().root_hash(), b.mst().root_hash());
assert_eq!(a.store().len(), b.store().len());
assert_eq!(b.store().len(), store_a_size);
}
#[tokio::test]
async fn async_sync_disjoint_sets_merge() {
let only_a = &[
"fn alpha() -> i32 { 1 }",
"fn beta(x: i32) -> i32 { x + 1 }",
];
let only_b = &[
"fn gamma(y: i32) -> bool { y > 0 }",
"fn delta() -> &'static str { \"hello\" }",
];
let (mst_a, store_a, _) = build_repo(only_a);
let (mst_b, store_b, _) = build_repo(only_b);
let session_a = SyncSession::without_attestations(mst_a, store_a, kp(1));
let session_b = SyncSession::without_attestations(mst_b, store_b, kp(2));
let (a_stream, b_stream) = tokio::io::duplex(64 * 1024);
let task_a = tokio::spawn(run_sync_async(session_a, a_stream));
let task_b = tokio::spawn(run_sync_async(session_b, b_stream));
let a = task_a.await.unwrap().unwrap();
let b = task_b.await.unwrap().unwrap();
assert_eq!(a.mst().root_hash(), b.mst().root_hash());
assert_eq!(a.mst().len(), 4);
}
#[tokio::test]
async fn async_sync_propagates_authenticated_identity() {
// Cada peer debe acabar conociendo el DID verificado del otro,
// exactamente como en el harness síncrono.
let kp_a = kp(10);
let kp_b = kp(20);
let did_a = kp_a.did();
let did_b = kp_b.did();
let session_a = SyncSession::without_attestations(Mst::new(), MemStore::new(), kp_a);
let session_b = SyncSession::without_attestations(Mst::new(), MemStore::new(), kp_b);
let (a_stream, b_stream) = tokio::io::duplex(64 * 1024);
let task_a = tokio::spawn(run_sync_async(session_a, a_stream));
let task_b = tokio::spawn(run_sync_async(session_b, b_stream));
let a = task_a.await.unwrap().unwrap();
let b = task_b.await.unwrap().unwrap();
assert_eq!(a.peer_did(), Some(did_b));
assert_eq!(b.peer_did(), Some(did_a));
}
#[tokio::test]
async fn async_sync_propagates_attestations() {
use minga_core::{Attestation, AttestationStore};
let kp_a = kp(30);
let kp_b = kp(40);
let (mst_a, store_a, roots_a) = build_repo(&["fn from_a() -> i32 { 1 }"]);
let (mst_b, store_b, roots_b) = build_repo(&["fn from_b() -> i32 { 2 }"]);
let mut atts_a = AttestationStore::new();
atts_a
.add(Attestation::create(&kp_a, roots_a[0]))
.unwrap();
let mut atts_b = AttestationStore::new();
atts_b
.add(Attestation::create(&kp_b, roots_b[0]))
.unwrap();
let session_a = SyncSession::new(mst_a, store_a, atts_a, kp_a.clone());
let session_b = SyncSession::new(mst_b, store_b, atts_b, kp_b.clone());
let (a_stream, b_stream) = tokio::io::duplex(128 * 1024);
let task_a = tokio::spawn(run_sync_async(session_a, a_stream));
let task_b = tokio::spawn(run_sync_async(session_b, b_stream));
let a = task_a.await.unwrap().unwrap();
let b = task_b.await.unwrap().unwrap();
// Los DIDs y atestaciones cruzaron correctamente sobre el wire.
assert_eq!(a.attestations().authors_of(&roots_a[0]), vec![kp_a.did()]);
assert_eq!(a.attestations().authors_of(&roots_b[0]), vec![kp_b.did()]);
assert_eq!(b.attestations().authors_of(&roots_a[0]), vec![kp_a.did()]);
assert_eq!(b.attestations().authors_of(&roots_b[0]), vec![kp_b.did()]);
}