feat: require swapchain recreation evidence in smoke reports

This commit is contained in:
2026-06-23 23:45:08 +04:00
parent c71e706d69
commit 00ae9067d8
3 changed files with 71 additions and 0 deletions
+69
View File
@@ -57,6 +57,7 @@ struct SmokeOptions {
status: SmokeStatus, status: SmokeStatus,
frames: u32, frames: u32,
resize_count: u32, resize_count: u32,
swapchain_recreate_count: u32,
validation_error_count: Option<u32>, validation_error_count: Option<u32>,
probes: ProbeOptions, probes: ProbeOptions,
reason: Option<String>, reason: Option<String>,
@@ -69,6 +70,7 @@ impl SmokeOptions {
let mut status = SmokeStatus::Blocked; let mut status = SmokeStatus::Blocked;
let mut frames = 0; let mut frames = 0;
let mut resize_count = 0; let mut resize_count = 0;
let mut swapchain_recreate_count = 0;
let mut validation_error_count = None; let mut validation_error_count = None;
let mut probes = ProbeOptions::default(); let mut probes = ProbeOptions::default();
let mut reason = None; let mut reason = None;
@@ -105,6 +107,12 @@ impl SmokeOptions {
.ok_or_else(|| "--resize-count requires a value".to_string())?; .ok_or_else(|| "--resize-count requires a value".to_string())?;
resize_count = parse_u32("--resize-count", value)?; resize_count = parse_u32("--resize-count", value)?;
} }
"--swapchain-recreate-count" => {
let value = iter
.next()
.ok_or_else(|| "--swapchain-recreate-count requires a value".to_string())?;
swapchain_recreate_count = parse_u32("--swapchain-recreate-count", value)?;
}
"--validation-error-count" => { "--validation-error-count" => {
let value = iter let value = iter
.next() .next()
@@ -139,6 +147,7 @@ impl SmokeOptions {
status, status,
frames, frames,
resize_count, resize_count,
swapchain_recreate_count,
validation_error_count, validation_error_count,
probes, probes,
reason, reason,
@@ -433,6 +442,12 @@ fn validate_smoke_options(
if options.resize_count == 0 { if options.resize_count == 0 {
return Err("passed native smoke report requires --resize-count >= 1".to_string()); return Err("passed native smoke report requires --resize-count >= 1".to_string());
} }
if options.swapchain_recreate_count == 0 {
return Err(
"passed native smoke report requires --swapchain-recreate-count >= 1"
.to_string(),
);
}
if options.validation_error_count != Some(0) { if options.validation_error_count != Some(0) {
return Err( return Err(
"passed native smoke report requires --validation-error-count 0".to_string(), "passed native smoke report requires --validation-error-count 0".to_string(),
@@ -512,6 +527,7 @@ fn render_smoke_report_json(
" \"status\": \"{}\",\n", " \"status\": \"{}\",\n",
" \"frames\": {},\n", " \"frames\": {},\n",
" \"resize_count\": {},\n", " \"resize_count\": {},\n",
" \"swapchain_recreate_count\": {},\n",
" \"validation_error_count\": {},\n", " \"validation_error_count\": {},\n",
" \"shader_manifest_hash\": \"{}\",\n", " \"shader_manifest_hash\": \"{}\",\n",
" \"vulkan_loader_status\": \"{}\",\n", " \"vulkan_loader_status\": \"{}\",\n",
@@ -536,6 +552,7 @@ fn render_smoke_report_json(
options.status.as_str(), options.status.as_str(),
options.frames, options.frames,
options.resize_count, options.resize_count,
options.swapchain_recreate_count,
validation_error_count, validation_error_count,
json_escape(&shader_manifest.manifest_hash), json_escape(&shader_manifest.manifest_hash),
bootstrap.loader_status.as_str(), bootstrap.loader_status.as_str(),
@@ -658,6 +675,8 @@ mod tests {
"299", "299",
"--resize-count", "--resize-count",
"1", "1",
"--swapchain-recreate-count",
"1",
"--validation-error-count", "--validation-error-count",
"0", "0",
])) ]))
@@ -698,6 +717,8 @@ mod tests {
"300", "300",
"--resize-count", "--resize-count",
"1", "1",
"--swapchain-recreate-count",
"1",
"--validation-error-count", "--validation-error-count",
"0", "0",
])) ]))
@@ -725,6 +746,47 @@ mod tests {
); );
} }
#[test]
fn rejects_passed_without_swapchain_recreation() {
let options = SmokeOptions::parse(&strings(&[
"--platform",
"linux",
"--out",
"target/native.json",
"--status",
"passed",
"--frames",
"300",
"--resize-count",
"1",
"--validation-error-count",
"0",
"--probe-surface",
]))
.expect("options");
assert_eq!(
validate_smoke_options(
&options,
&VulkanBootstrapProbe {
loader_status: VulkanLoaderStatus::Available,
instance_api: Some("1.3.0".to_string()),
loader_error: None,
instance_status: VulkanInstanceStatus::Created,
instance_error: None,
portability_enumeration: false,
window_status: WinitWindowStatus::Planned,
window_width: Some(1280),
window_height: Some(720),
window_error: None,
surface_status: VulkanSurfaceStatus::Planned,
surface_error: None,
},
),
Err("passed native smoke report requires --swapchain-recreate-count >= 1".to_string())
);
}
#[test] #[test]
fn rejects_passed_without_instance_probe() { fn rejects_passed_without_instance_probe() {
let options = SmokeOptions::parse(&strings(&[ let options = SmokeOptions::parse(&strings(&[
@@ -738,6 +800,8 @@ mod tests {
"300", "300",
"--resize-count", "--resize-count",
"1", "1",
"--swapchain-recreate-count",
"1",
"--validation-error-count", "--validation-error-count",
"0", "0",
"--probe-loader", "--probe-loader",
@@ -779,6 +843,8 @@ mod tests {
"300", "300",
"--resize-count", "--resize-count",
"1", "1",
"--swapchain-recreate-count",
"1",
"--validation-error-count", "--validation-error-count",
"0", "0",
"--probe-instance", "--probe-instance",
@@ -820,6 +886,8 @@ mod tests {
"300", "300",
"--resize-count", "--resize-count",
"1", "1",
"--swapchain-recreate-count",
"1",
"--validation-error-count", "--validation-error-count",
"0", "0",
"--probe-window", "--probe-window",
@@ -886,6 +954,7 @@ mod tests {
assert!(json.contains("\"schema_version\": \"fparkan-native-smoke-v1\"")); assert!(json.contains("\"schema_version\": \"fparkan-native-smoke-v1\""));
assert!(json.contains("\"platform\": \"macos\"")); assert!(json.contains("\"platform\": \"macos\""));
assert!(json.contains("\"status\": \"blocked\"")); assert!(json.contains("\"status\": \"blocked\""));
assert!(json.contains("\"swapchain_recreate_count\": 0"));
assert!(json.contains("\"shader_manifest_hash\": \"")); assert!(json.contains("\"shader_manifest_hash\": \""));
assert!(json.contains("\"vulkan_loader_status\": \"unavailable\"")); assert!(json.contains("\"vulkan_loader_status\": \"unavailable\""));
assert!(json.contains("\"vulkan_instance_api\": null")); assert!(json.contains("\"vulkan_instance_api\": null"));
+1
View File
@@ -55,6 +55,7 @@ S0-VK-023 covered cargo test -p fparkan-vulkan-smoke --offline rejects_false_pas
S0-VK-024 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_loader_probe formats_vulkan_api_version S0-VK-024 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_loader_probe formats_vulkan_api_version
S0-VK-025 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_instance_probe parses_instance_probe_as_loader_probe S0-VK-025 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_instance_probe parses_instance_probe_as_loader_probe
S0-VK-026 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_window_probe rejects_passed_without_surface_probe parses_surface_probe_as_instance_probe S0-VK-026 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_window_probe rejects_passed_without_surface_probe parses_surface_probe_as_instance_probe
S0-VK-027 covered cargo test -p fparkan-vulkan-smoke --offline rejects_passed_without_swapchain_recreation blocked_report_includes_shader_manifest_and_bootstrap_status
S0-LIMIT-001 covered cargo test -p fparkan-binary --offline rejects_count_stride_overflow S0-LIMIT-001 covered cargo test -p fparkan-binary --offline rejects_count_stride_overflow
S0-LIMIT-002 covered cargo test -p fparkan-binary --offline rejects_oversized_declared_allocation_before_read S0-LIMIT-002 covered cargo test -p fparkan-binary --offline rejects_oversized_declared_allocation_before_read
L1-P1-NRES-001 covered cargo test -p fparkan-nres --offline licensed_corpora_nres_roundtrip_gates L1-P1-NRES-001 covered cargo test -p fparkan-nres --offline licensed_corpora_nres_roundtrip_gates
1 # Acceptance coverage manifest.
55 S0-VK-024
56 S0-VK-025
57 S0-VK-026
58 S0-VK-027
59 S0-LIMIT-001
60 S0-LIMIT-002
61 L1-P1-NRES-001
+1
View File
@@ -55,6 +55,7 @@
`S0-VK-024` `S0-VK-024`
`S0-VK-025` `S0-VK-025`
`S0-VK-026` `S0-VK-026`
`S0-VK-027`
`S0-LIMIT-001` `S0-LIMIT-001`
`S0-LIMIT-002` `S0-LIMIT-002`
`L1-P1-NRES-001` `L1-P1-NRES-001`