use microvms_core::control::{ControlPlane, ops};
use microvms_core::region::Region;
const REGION: Region = Region::UsEast1;
#[tokio::test]
#[ignore = "needs real AWS credentials and an account; runs in the live lane"]
async fn a_successful_builds_snapshot_sizes_come_back_and_the_listing_has_none() {
let plane = ControlPlane::new(REGION)
.await
.expect("credentials resolve; `aws sts get-caller-identity` shows the same failure");
let Some((image, version)) = any_successful_version(&plane).await else {
eprintln!("SKIP: this account holds no image with a SUCCESSFUL version");
return;
};
let builds = plane
.list_image_builds(&image, &version)
.await
.expect("the build listing reads");
let Some(listed) = builds
.iter()
.find(|build| build.build_state == "SUCCESSFUL")
else {
eprintln!("SKIP: {image} version {version} has no SUCCESSFUL build");
return;
};
let deeper = plane
.get_image_build(&image, &version, &listed.build_id)
.await
.expect("GetMicrovmImageBuild reads");
assert_eq!(deeper.build_id, listed.build_id);
assert_eq!(deeper.build_state, listed.build_state);
assert_eq!(deeper.chipset_generation, listed.chipset_generation);
assert_eq!(deeper.architecture, "ARM_64");
assert_eq!(deeper.chipset, "GRAVITON");
let sizes = deeper
.snapshot_build
.expect("a SUCCESSFUL build reports its snapshot sizes");
println!(
"GetMicrovmImageBuild on {} generation {}: {}",
listed.build_id,
deeper.chipset_generation,
sizes.describe().unwrap_or_else(|| "no sizes".to_string()),
);
assert!(
sizes.memory_snapshot_size_in_bytes.is_some_and(|n| n > 0),
"a successful build wrote a memory snapshot: {sizes:?}"
);
assert!(
sizes.code_install_size_in_bytes.is_some_and(|n| n > 0),
"a successful build installed code: {sizes:?}"
);
assert!(
sizes.disk_snapshot_size_in_bytes.is_some_and(|n| n > 0),
"a successful build wrote a disk snapshot: {sizes:?}"
);
}
#[tokio::test]
#[ignore = "needs real AWS credentials and an account; runs in the live lane"]
async fn a_versions_readback_carries_its_config_and_a_status_beside_its_state() {
let plane = ControlPlane::new(REGION)
.await
.expect("credentials resolve");
let Some((image, version)) = any_successful_version(&plane).await else {
eprintln!("SKIP: this account holds no image with a SUCCESSFUL version");
return;
};
let got = plane
.get_image_version(&image, &version)
.await
.expect("GetMicrovmImageVersion reads");
println!("GetMicrovmImageVersion on {image}: {}", got.describe());
assert_eq!(got.image_version, version);
assert_eq!(got.state, "SUCCESSFUL");
assert!(
got.status == "ACTIVE" || got.status == "INACTIVE",
"the model declares exactly two statuses; the service answered {:?}",
got.status
);
assert!(
!got.status.is_empty(),
"status is required by the model and was present on all 22 versions measured"
);
let resources = got
.resources
.as_ref()
.expect("the readback carries the resources it was built with");
assert_eq!(
resources.len(),
1,
"ResourcesList is max 1, so two memory floors is unaskable"
);
assert!(resources[0].minimum_memory_in_mib >= 512);
assert!(
got.code_artifact.uri.starts_with("s3://"),
"the artifact URI comes back: {}",
got.code_artifact.uri
);
assert!(got.base_image_arn.contains(":microvm-image:"));
if let Some(egress) = got.egress_network_connectors.as_ref() {
assert!(
egress.len() <= microvms_core::constants::MAX_IMAGE_EGRESS_CONNECTORS,
"the image-level egress list is max 1, not the VM-level 10: {egress:?}"
);
}
if let Some(base_version) = got.base_image_version.as_deref() {
println!(
"baseImageVersion echoes as {base_version:?} — measured 2026-08-16, a build pinned \
with `--base-image-version 1` reads back \"1.0\", so the echoed value is not the \
value that was sent and cannot be compared with the managed listing's strings"
);
}
}
#[tokio::test]
#[ignore = "needs real AWS credentials and an account; runs in the live lane"]
async fn the_managed_base_answers_its_versions_and_a_bare_name_is_refused_locally() {
let plane = ControlPlane::new(REGION)
.await
.expect("credentials resolve");
let base = microvms_core::control::BaseImage::al2023();
let arn = base.arn(®ION);
let versions = plane
.managed_base_versions(&arn)
.await
.expect("the managed base's version listing reads");
let names: Vec<&str> = versions
.iter()
.map(|version| version.image_version.as_str())
.collect();
println!("{}: {} version(s) — {names:?}", base.name, names.len());
assert!(
!versions.is_empty(),
"the managed base must have at least one version, or nothing could be built"
);
for name in &names {
assert!(
!name.contains('.'),
"a managed base's versions are bare integers, measured 2026-08-16: {name:?}"
);
assert!(!name.is_empty(), "an empty version string is not a Version");
}
for version in &versions {
assert_eq!(
version.image_arn, arn,
"every item names the base it belongs to"
);
}
let refused = plane
.managed_base_versions(&base.name)
.await
.expect_err("a bare name is refused before the call");
let message = refused.to_string();
assert!(message.contains("Invalid ARN format"), "{message}");
assert!(
message.contains(&arn),
"the remedy is the ARN itself: {message}"
);
let bases = plane
.managed_base_images()
.await
.expect("the managed base listing reads");
println!(
"ListManagedMicrovmImages in {REGION}: {:?}",
bases
.iter()
.map(|base| base.image_arn.as_str())
.collect::<Vec<_>>()
);
assert!(
bases.iter().any(|listed| listed.image_arn == arn),
"the base this client builds on must be in the listing: {bases:?}"
);
for listed in &bases {
assert!(
!listed.image_arn.contains("public.ecr.aws"),
"no registry reference is derivable from the ARN, which is why a discovered base \
cannot construct a BaseImage: {}",
listed.image_arn
);
}
}
#[tokio::test]
#[ignore = "needs real AWS credentials and an account; MUTATES a version's status, launches one VM, and restores both"]
async fn a_version_set_inactive_refuses_a_launch_and_active_restores_it() {
let plane = ControlPlane::new(REGION)
.await
.expect("credentials resolve");
let Some((image, version)) = conformance_active_version(&plane).await else {
eprintln!(
"SKIP: no image named `microvm-cli-*` in this account has a single SUCCESSFUL/ACTIVE \
version. This test refuses to touch an image it did not identify as this \
project's."
);
return;
};
println!("subject: {image} version {version}");
let retired = plane
.set_image_version_status(&image, &version, ops::VersionStatus::Inactive)
.await
.expect("UpdateMicrovmImageVersion is accepted");
assert_eq!(
retired.status, "INACTIVE",
"the readback is checked inside set_image_version_status; this is belt and braces"
);
let read_back = plane.get_image_version(&image, &version).await;
let refused = pinned_launch(&plane, &image, &version).await;
let restored = plane
.set_image_version_status(&image, &version, ops::VersionStatus::Active)
.await;
let read_back = read_back.expect("GetMicrovmImageVersion reads the retired version");
assert_eq!(
read_back.status,
"INACTIVE",
"an independent GET must see the retire, not just the PATCH's echo: {}",
read_back.describe()
);
assert!(
!read_back.is_active(),
"is_active must agree with the wire: {}",
read_back.describe()
);
assert_eq!(
read_back.state,
"SUCCESSFUL",
"a retire does not change the build state — the version still built fine, it is just \
no longer launchable: {}",
read_back.describe()
);
let error = match refused {
Ok(id) => {
let _ = plane.terminate(&id).await;
panic!(
"a version set INACTIVE launched anyway and created {id} (terminated). The \
retire would then be advisory and the whole feature would not exist."
);
}
Err(error) => error,
};
let message = error.to_string();
println!("INACTIVE -> {message}");
assert!(
message.contains("No active version found"),
"the refusal has to be about the version rather than about the request, which is what \
makes it a retire: {message}"
);
assert_eq!(
error.kind(),
microvms_core::ErrorKind::Platform,
"a 404 about a version is a platform failure, not a credentials one: {message}"
);
let restored = restored.expect("the version is restored to ACTIVE");
assert_eq!(
restored.status,
"ACTIVE",
"the account must be left as it was found: {}",
restored.describe()
);
let confirmed = plane
.get_image_version(&image, &version)
.await
.expect("the restore reads back");
assert!(
confirmed.is_active(),
"an independent GET must confirm the restore: {}",
confirmed.describe()
);
let launched = pinned_launch(&plane, &image, &version)
.await
.expect("once ACTIVE again, the same pinned launch must be accepted");
println!("ACTIVE -> launched {launched}, terminating");
plane
.terminate(&launched)
.await
.expect("the verification VM is terminated immediately");
}
async fn pinned_launch(
plane: &ControlPlane,
image: &str,
version: &str,
) -> Result<String, microvms_core::Error> {
use microvms_core::control::{RunHookPayload, RunMicrovmRequest};
let payload = RunHookPayload::for_agent_token("live-verification").expect("a token fits");
let mut request = RunMicrovmRequest::new(image, payload).with_image_version(version);
request.execution_role_arn = std::env::var("MICROVM_EXECUTION_ROLE_ARN").ok();
request.max_duration_sec = 300;
plane.run_microvm(request).await.map(|vm| vm.id)
}
async fn any_successful_version(plane: &ControlPlane) -> Option<(String, String)> {
let mut unreadable = 0_usize;
let images = plane.list_images().await.ok()?;
for image in &images {
let Ok(versions) = plane.list_image_versions(&image.image_arn).await else {
unreadable += 1;
continue;
};
if let Some(version) = versions
.iter()
.find(|version| version.state == "SUCCESSFUL")
{
return Some((image.image_arn.clone(), version.image_version.clone()));
}
}
eprintln!(
"no SUCCESSFUL version across {} image(s); {unreadable} could not be read (an image in \
DELETING answers a listing error, which is data rather than a failure)",
images.len(),
);
None
}
async fn conformance_active_version(plane: &ControlPlane) -> Option<(String, String)> {
let images = plane.list_images().await.ok()?;
for image in &images {
if !image.name.starts_with("microvm-cli-") {
continue;
}
let Ok(versions) = plane.list_image_versions(&image.image_arn).await else {
continue;
};
if versions.len() != 1 {
continue;
}
let only = &versions[0];
if only.state == "SUCCESSFUL" && only.is_active() {
return Some((image.image_arn.clone(), only.image_version.clone()));
}
}
None
}