#![cfg(windows)]
#![allow(unsafe_code, clippy::borrow_as_ptr, clippy::items_after_statements)]
use zlayer_hcs::enumerate::{list as enum_list, list_by_owner, EnumerateQuery};
use zlayer_hcs::error::HcsError;
use zlayer_hcs::process::ComputeProcess;
use zlayer_hcs::schema::{
Chipset, ComputeSystem as CsDoc, SchemaVersion, Statistics, Topology, TopologyMemory,
TopologyProcessor, Uefi, UefiBootEntry, VirtualMachine,
};
use zlayer_hcs::system::ComputeSystem as System;
fn is_elevated() -> bool {
use windows::Win32::Foundation::HANDLE;
use windows::Win32::Security::{
GetTokenInformation, TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY,
};
use windows::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};
let mut token = HANDLE::default();
unsafe {
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token).is_err() {
return false;
}
let mut elev = TOKEN_ELEVATION::default();
let mut len = 0u32;
let size = u32::try_from(std::mem::size_of::<TOKEN_ELEVATION>()).unwrap_or(0);
let ok = GetTokenInformation(
token,
TokenElevation,
Some(std::ptr::from_mut(&mut elev).cast()),
size,
&mut len,
);
if ok.is_err() {
return false;
}
elev.TokenIsElevated != 0
}
}
fn skip_if_not_elevated(test_name: &str) -> bool {
if !is_elevated() {
println!("skipping {test_name} — requires Administrator");
return true;
}
false
}
fn is_session_zero() -> bool {
use windows::Win32::System::RemoteDesktop::ProcessIdToSessionId;
use windows::Win32::System::Threading::GetCurrentProcessId;
let mut session_id: u32 = u32::MAX;
unsafe {
let pid = GetCurrentProcessId();
if ProcessIdToSessionId(pid, &mut session_id).is_err() {
return false;
}
}
session_id == 0
}
fn skip_if_session_zero(test_name: &str) -> bool {
if is_session_zero() {
println!(
"skipping {test_name} — running in Windows services session 0; \
HCS null-handle behavior differs from interactive sessions"
);
return true;
}
false
}
fn empty_vm_document(owner: &str) -> CsDoc {
CsDoc {
owner: owner.to_string(),
schema_version: SchemaVersion::default(),
hosting_system_id: String::new(),
container: None,
virtual_machine: Some(VirtualMachine {
chipset: Some(Chipset {
uefi: Some(Uefi {
boot_this: Some(UefiBootEntry {
device_type: "VmbFs".to_string(),
device_path: String::new(),
disk_number: None,
}),
}),
}),
compute_topology: Some(Topology {
memory: Some(TopologyMemory { size_in_mb: 256 }),
processor: Some(TopologyProcessor { count: 1 }),
}),
devices: None,
guest_state: None,
runtime_state_file_path: None,
}),
should_terminate_on_last_handle_closed: Some(true),
}
}
#[test]
fn schema_round_trip() {
let doc = empty_vm_document("zlayer-test");
let json = serde_json::to_string(&doc).expect("serialize");
assert!(json.contains("\"Owner\":\"zlayer-test\""));
assert!(json.contains("\"SchemaVersion\":{\"Major\":2,\"Minor\":1}"));
assert!(json.contains("\"VirtualMachine\""));
assert!(json.contains("\"SizeInMB\":256"));
assert!(json.contains("\"Count\":1"));
let back: CsDoc = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back.owner, "zlayer-test");
assert_eq!(back.schema_version, SchemaVersion { major: 2, minor: 1 });
assert!(back.container.is_none());
assert_eq!(back.should_terminate_on_last_handle_closed, Some(true));
let vm = back.virtual_machine.expect("virtual machine present");
let topology = vm.compute_topology.expect("topology present");
assert_eq!(topology.memory.expect("memory").size_in_mb, 256);
assert_eq!(topology.processor.expect("processor").count, 1);
let chipset = vm.chipset.expect("chipset present");
let uefi = chipset.uefi.expect("uefi present");
let boot = uefi.boot_this.expect("boot_this present");
assert_eq!(boot.device_type, "VmbFs");
}
#[tokio::test(flavor = "current_thread")]
#[ignore = "requires physical host with Hyper-V role enabled"]
async fn empty_vm_create_and_terminate() {
if skip_if_not_elevated("empty_vm_create_and_terminate") {
return;
}
let id = "zlayer-test-integration";
let doc = empty_vm_document("zlayer-test");
let json = serde_json::to_string(&doc).expect("serialize");
let system = match System::create(id, &json).await {
Ok(sys) => sys,
Err(e) => {
println!("skipping empty_vm_create_and_terminate — create failed: {e:?}");
return;
}
};
if let Err(e) = system.terminate("{}").await {
println!("terminate returned: {e:?}");
}
drop(system);
let listed = enum_list(&EnumerateQuery::default())
.await
.expect("enumerate");
assert!(
!listed.iter().any(|s| s.id == id),
"test compute system still listed after terminate: {listed:?}"
);
}
#[tokio::test(flavor = "current_thread")]
async fn enumerate_self_empty() {
if skip_if_not_elevated("enumerate_self_empty") {
return;
}
let result = list_by_owner("zlayer-test-this-owner-should-not-exist").await;
match result {
Ok(list) => assert!(list.is_empty(), "expected empty, got {list:?}"),
Err(e) => {
println!("enumerate_self_empty skipped — enumerate failed: {e:?}");
}
}
}
#[test]
fn parse_statistics_fixture() {
let payload = r#"{
"Timestamp":"2026-04-21T12:34:56Z",
"Uptime100ns":2960000000,
"Processor":{"TotalRuntime100ns":1234567,"RuntimeUser100ns":900000,"RuntimeKernel100ns":334567},
"Memory":{"MemoryUsageCommitBytes":268435456,"MemoryUsageCommitPeakBytes":314572800,"MemoryUsagePrivateWorkingSetBytes":201326592},
"Storage":{"ReadCountNormalized":42,"ReadSizeBytes":1048576,"WriteCountNormalized":13,"WriteSizeBytes":262144}
}"#;
let stats: Statistics = serde_json::from_str(payload).expect("parse statistics");
assert_eq!(stats.timestamp.as_deref(), Some("2026-04-21T12:34:56Z"));
assert_eq!(stats.uptime_100ns, 2_960_000_000);
let cpu = stats.processor.expect("processor");
assert_eq!(cpu.total_runtime_100ns, 1_234_567);
assert_eq!(cpu.runtime_user_100ns, 900_000);
assert_eq!(cpu.runtime_kernel_100ns, 334_567);
let mem = stats.memory.expect("memory");
assert_eq!(mem.memory_usage_commit_bytes, 268_435_456);
assert_eq!(mem.memory_usage_commit_peak_bytes, 314_572_800);
assert_eq!(mem.memory_usage_private_working_set_bytes, 201_326_592);
let storage = stats.storage.expect("storage");
assert_eq!(storage.read_count_normalized, 42);
assert_eq!(storage.read_size_bytes, 1_048_576);
assert_eq!(storage.write_count_normalized, 13);
assert_eq!(storage.write_size_bytes, 262_144);
}
#[test]
fn open_nonexistent_process_errors_cleanly() {
if skip_if_not_elevated("open_nonexistent_process_errors_cleanly") {
return;
}
if skip_if_session_zero("open_nonexistent_process_errors_cleanly") {
return;
}
use windows::Win32::System::HostComputeSystem::HCS_SYSTEM;
let null_system: HCS_SYSTEM = HCS_SYSTEM::default();
let result = ComputeProcess::open(null_system, 999_999, 0);
match result {
Ok(_) => panic!("expected an error opening a non-existent process on a null system"),
Err(e) => {
assert!(
matches!(
e,
HcsError::NotFound { .. }
| HcsError::AccessDenied { .. }
| HcsError::Other { .. }
| HcsError::InvalidSchema { .. }
),
"unexpected error variant: {e:?}"
);
}
}
}