diff --git a/Cargo.lock b/Cargo.lock index 46edaa8cb..1823284c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -183,6 +183,7 @@ dependencies = [ "net_gen 0.1.0", "net_util 0.1.0", "qcow 0.1.0", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "ssh2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "vhost_rs 0.1.0", diff --git a/Cargo.toml b/Cargo.toml index e4b7054aa..12007d847 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ dirs = "2.0.2" credibility = "0.1.3" tempdir= "0.3.7" lazy_static= "1.4.0" +serde_json = ">=1.0.9" [dependencies.vhost_rs] path = "vhost_rs" diff --git a/src/main.rs b/src/main.rs index 1f8d7a3f4..e410fa3c1 100755 --- a/src/main.rs +++ b/src/main.rs @@ -382,10 +382,1025 @@ fn main() { } #[cfg(test)] -#[cfg(feature = "integration_tests")] #[macro_use] extern crate credibility; +#[cfg(test)] +mod unit_tests { + use crate::{create_app, prepare_default_values}; + use std::path::PathBuf; + use vmm::config::{ + CmdlineConfig, ConsoleConfig, ConsoleOutputMode, CpusConfig, MemoryConfig, RngConfig, + VmConfig, VmParams, + }; + + fn get_vm_config_from_vec(args: &[&str]) -> VmConfig { + let (default_vcpus, default_memory, default_rng) = prepare_default_values(); + let api_server_path = ""; + + let cmd_arguments = create_app( + &default_vcpus, + &default_memory, + &default_rng, + &api_server_path, + ) + .get_matches_from(args); + + let vm_params = VmParams::from_arg_matches(&cmd_arguments); + + VmConfig::parse(vm_params).unwrap() + } + + fn compare_vm_config_cli_vs_json( + cli: &[&str], + openapi: &str, + equal: bool, + ) -> (VmConfig, VmConfig) { + let cli_vm_config = get_vm_config_from_vec(cli); + let openapi_vm_config: VmConfig = serde_json::from_str(openapi).unwrap(); + + test_block!(tb, "", { + if equal { + aver_eq!(tb, cli_vm_config, openapi_vm_config); + } else { + aver_ne!(tb, cli_vm_config, openapi_vm_config); + } + + Ok(()) + }); + + (cli_vm_config, openapi_vm_config) + } + + #[test] + fn test_valid_vm_config_default() { + let cli = vec!["cloud-hypervisor"]; + let openapi = r#"{}"#; + + // First we check we get identical VmConfig structures. + let (result_vm_config, _) = compare_vm_config_cli_vs_json(&cli, openapi, true); + + // As a second step, we validate all the default values. + test_block!(tb, "", { + let expected_vm_config = VmConfig { + cpus: CpusConfig { + boot_vcpus: 1, + max_vcpus: 1, + }, + memory: MemoryConfig { + size: 536_870_912, + file: None, + mergeable: false, + }, + kernel: None, + cmdline: CmdlineConfig { + args: String::from(""), + }, + disks: None, + net: None, + rng: RngConfig { + src: PathBuf::from("/dev/urandom"), + iommu: false, + }, + fs: None, + pmem: None, + serial: ConsoleConfig { + file: None, + mode: ConsoleOutputMode::Null, + iommu: false, + }, + console: ConsoleConfig { + file: None, + mode: ConsoleOutputMode::Tty, + iommu: false, + }, + devices: None, + vhost_user_net: None, + vhost_user_blk: None, + vsock: None, + iommu: false, + }; + + aver_eq!(tb, expected_vm_config, result_vm_config); + Ok(()) + }) + } + + #[test] + fn test_valid_vm_config_cpus() { + vec![ + ( + vec!["cloud-hypervisor", "--cpus", "boot=1"], + r#"{ + "cpus": {"boot_vcpus": 1, "max_vcpus": 1} + }"#, + true, + ), + ( + vec!["cloud-hypervisor", "--cpus", "boot=1,max=3"], + r#"{ + "cpus": {"boot_vcpus": 1, "max_vcpus": 3} + }"#, + true, + ), + ( + vec!["cloud-hypervisor", "--cpus", "boot=2,max=4"], + r#"{ + "cpus": {"boot_vcpus": 1, "max_vcpus": 3} + }"#, + false, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_memory() { + vec![ + ( + vec!["cloud-hypervisor", "--memory", "size=1073741824"], + r#"{ + "memory": {"size": 1073741824} + }"#, + true, + ), + ( + vec!["cloud-hypervisor", "--memory", "size=1G"], + r#"{ + "memory": {"size": 1073741824} + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--memory", + "size=1G,file=/path/to/shared/file", + ], + r#"{ + "memory": {"size": 1073741824, "file": "/path/to/shared/file"} + }"#, + true, + ), + ( + vec!["cloud-hypervisor", "--memory", "size=1G,mergeable=on"], + r#"{ + "memory": {"size": 1073741824, "mergeable": true} + }"#, + true, + ), + ( + vec!["cloud-hypervisor", "--memory", "size=1G,mergeable=off"], + r#"{ + "memory": {"size": 1073741824, "mergeable": false} + }"#, + true, + ), + ( + vec!["cloud-hypervisor", "--memory", "size=1G,mergeable=on"], + r#"{ + "memory": {"size": 1073741824, "mergeable": false} + }"#, + false, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_kernel() { + vec![( + vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"], + r#"{ + "kernel": {"path": "/path/to/kernel"} + }"#, + true, + )] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_cmdline() { + vec![( + vec!["cloud-hypervisor", "--cmdline", "arg1=foo arg2=bar"], + r#"{ + "cmdline": {"args": "arg1=foo arg2=bar"} + }"#, + true, + )] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_disks() { + vec![ + ( + vec![ + "cloud-hypervisor", + "--disk", + "path=/path/to/disk/1", + "path=/path/to/disk/2", + ], + r#"{ + "disks": [ + {"path": "/path/to/disk/1"}, + {"path": "/path/to/disk/2"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--disk", + "path=/path/to/disk/1", + "path=/path/to/disk/2", + ], + r#"{ + "disks": [ + {"path": "/path/to/disk/1"} + ] + }"#, + false, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_net() { + vec![ + // This test is expected to fail because the default MAC address is + // randomly generated. There's no way we can have twice the same + // default value. + ( + vec!["cloud-hypervisor", "--net", "mac="], + r#"{ + "net": [] + }"#, + false, + ), + ( + vec!["cloud-hypervisor", "--net", "mac=12:34:56:78:90:ab"], + r#"{ + "net": [ + {"mac": "12:34:56:78:90:ab"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--net", + "mac=12:34:56:78:90:ab,tap=tap0", + ], + r#"{ + "net": [ + {"mac": "12:34:56:78:90:ab", "tap": "tap0"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--net", + "mac=12:34:56:78:90:ab,tap=tap0,ip=1.2.3.4", + ], + r#"{ + "net": [ + {"mac": "12:34:56:78:90:ab", "tap": "tap0", "ip": "1.2.3.4"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--net", + "mac=12:34:56:78:90:ab,tap=tap0,ip=1.2.3.4,mask=5.6.7.8", + ], + r#"{ + "net": [ + {"mac": "12:34:56:78:90:ab", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--net", + "mac=12:34:56:78:90:ab,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,iommu=on", + ], + r#"{ + "net": [ + {"mac": "12:34:56:78:90:ab", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "iommu": true} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--net", + "mac=12:34:56:78:90:ab,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,iommu=on", + ], + r#"{ + "net": [ + {"mac": "12:34:56:78:90:ab", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "iommu": true} + ], + "iommu": true + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--net", + "mac=12:34:56:78:90:ab,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,iommu=off", + ], + r#"{ + "net": [ + {"mac": "12:34:56:78:90:ab", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "iommu": false} + ] + }"#, + true, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_rng() { + vec![( + vec!["cloud-hypervisor", "--rng", "src=/path/to/entropy/source"], + r#"{ + "rng": {"src": "/path/to/entropy/source"} + }"#, + true, + )] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_fs() { + vec![ + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1", + "tag=virtiofs2,sock=/path/to/sock2", + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1"}, + {"tag": "virtiofs2", "sock": "/path/to/sock2"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1", + "tag=virtiofs2,sock=/path/to/sock2", + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1"} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1,num_queues=4", + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1", "num_queues": 4} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1,num_queues=4,queue_size=128" + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1", "num_queues": 4, "queue_size": 128} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1,num_queues=4,queue_size=128,dax=on" + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1", "num_queues": 4, "queue_size": 128} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1,num_queues=4,queue_size=128,dax=on" + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "dax": true} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1,num_queues=4,queue_size=128" + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "dax": true} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1,num_queues=4,queue_size=128,cache_size=8589934592" + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1", "num_queues": 4, "queue_size": 128} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1,num_queues=4,queue_size=128" + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "cache_size": 8589934592} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1,num_queues=4,queue_size=128,cache_size=4294967296" + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "cache_size": 4294967296} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--fs", + "tag=virtiofs1,sock=/path/to/sock1,num_queues=4,queue_size=128,cache_size=4294967296" + ], + r#"{ + "fs": [ + {"tag": "virtiofs1", "sock": "/path/to/sock1", "num_queues": 4, "queue_size": 128} + ] + }"#, + false, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_pmem() { + vec![ + ( + vec![ + "cloud-hypervisor", + "--pmem", + "file=/path/to/img/1,size=1G", + "file=/path/to/img/2,size=2G", + ], + r#"{ + "pmem": [ + {"file": "/path/to/img/1", "size": 1073741824}, + {"file": "/path/to/img/2", "size": 2147483648} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--pmem", + "file=/path/to/img/1,size=1G,iommu=on", + ], + r#"{ + "pmem": [ + {"file": "/path/to/img/1", "size": 1073741824, "iommu": true} + ], + "iommu": true + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--pmem", + "file=/path/to/img/1,size=1G,iommu=on", + ], + r#"{ + "pmem": [ + {"file": "/path/to/img/1", "size": 1073741824, "iommu": true} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--pmem", + "file=/path/to/img/1,size=1G,mergeable=on", + ], + r#"{ + "pmem": [ + {"file": "/path/to/img/1", "size": 1073741824, "mergeable": true} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--pmem", + "file=/path/to/img/1,size=1G,mergeable=off", + ], + r#"{ + "pmem": [ + {"file": "/path/to/img/1", "size": 1073741824, "mergeable": false} + ] + }"#, + true, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_serial_console() { + vec![ + ( + vec!["cloud-hypervisor"], + r#"{ + "serial": {"mode": "Null"}, + "console": {"mode": "Tty"} + }"#, + true, + ), + ( + vec!["cloud-hypervisor", "--serial", "null", "--console", "tty"], + r#"{}"#, + true, + ), + ( + vec!["cloud-hypervisor", "--serial", "tty", "--console", "off"], + r#"{ + "serial": {"mode": "Tty"}, + "console": {"mode": "Off"} + }"#, + true, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_devices() { + vec![ + ( + vec![ + "cloud-hypervisor", + "--device", + "path=/path/to/device/1", + "path=/path/to/device/2", + ], + r#"{ + "devices": [ + {"path": "/path/to/device/1"}, + {"path": "/path/to/device/2"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--device", + "path=/path/to/device/1", + "path=/path/to/device/2", + ], + r#"{ + "devices": [ + {"path": "/path/to/device/1"} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--device", + "path=/path/to/device,iommu=on", + ], + r#"{ + "devices": [ + {"path": "/path/to/device", "iommu": true} + ], + "iommu": true + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--device", + "path=/path/to/device,iommu=on", + ], + r#"{ + "devices": [ + {"path": "/path/to/device", "iommu": true} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--device", + "path=/path/to/device,iommu=off", + ], + r#"{ + "devices": [ + {"path": "/path/to/device", "iommu": false} + ] + }"#, + true, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_vunet() { + vec![ + // This test is expected to fail because the default MAC address is + // randomly generated. There's no way we can have twice the same + // default value. + ( + vec![ + "cloud-hypervisor", + "--vhost-user-net", + "sock=/path/to/sock/1", + "sock=/path/to/sock/2", + ], + r#"{ + "vhost_user_net": [ + {"sock": "/path/to/sock/1"}, + {"sock": "/path/to/sock/2"} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-net", + "sock=/path/to/sock/1,mac=12:34:56:78:90:ab", + "sock=/path/to/sock/2,mac=12:34:56:78:90:cd", + ], + r#"{ + "vhost_user_net": [ + {"sock": "/path/to/sock/1", "mac": "12:34:56:78:90:ab"}, + {"sock": "/path/to/sock/2", "mac": "12:34:56:78:90:cd"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-net", + "sock=/path/to/sock,mac=12:34:56:78:90:ab,num_queues=4", + ], + r#"{ + "vhost_user_net": [ + {"sock": "/path/to/sock", "mac": "12:34:56:78:90:ab", "num_queues": 4} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-net", + "sock=/path/to/sock,mac=12:34:56:78:90:ab,num_queues=4,queue_size=128", + ], + r#"{ + "vhost_user_net": [ + {"sock": "/path/to/sock", "mac": "12:34:56:78:90:ab", "num_queues": 4, "queue_size": 128} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-net", + "sock=/path/to/sock,mac=12:34:56:78:90:ab,num_queues=2,queue_size=256", + ], + r#"{ + "vhost_user_net": [ + {"sock": "/path/to/sock", "mac": "12:34:56:78:90:ab"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-net", + "sock=/path/to/sock,mac=12:34:56:78:90:ab", + ], + r#"{ + "vhost_user_net": [ + {"sock": "/path/to/sock", "mac": "12:34:56:78:90:ab", "num_queues": 2, "queue_size": 256} + ] + }"#, + true, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_vublk() { + vec![ + ( + vec![ + "cloud-hypervisor", + "--vhost-user-blk", + "sock=/path/to/sock/1", + "sock=/path/to/sock/2", + ], + r#"{ + "vhost_user_blk": [ + {"sock": "/path/to/sock/1"}, + {"sock": "/path/to/sock/2"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-blk", + "sock=/path/to/sock/1", + "sock=/path/to/sock/2", + ], + r#"{ + "vhost_user_blk": [ + {"sock": "/path/to/sock/1"} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-blk", + "sock=/path/to/sock/1,num_queues=4", + ], + r#"{ + "vhost_user_blk": [ + {"sock": "/path/to/sock/1", "num_queues": 4} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-blk", + "sock=/path/to/sock/1,num_queues=4,queue_size=1024", + ], + r#"{ + "vhost_user_blk": [ + {"sock": "/path/to/sock/1", "num_queues": 4, "queue_size": 1024} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-blk", + "sock=/path/to/sock/1,num_queues=4,queue_size=1024,wce=true", + ], + r#"{ + "vhost_user_blk": [ + {"sock": "/path/to/sock/1", "num_queues": 4, "queue_size": 1024, "wce": true} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-blk", + "sock=/path/to/sock/1,num_queues=1,queue_size=128,wce=true", + ], + r#"{ + "vhost_user_blk": [ + {"sock": "/path/to/sock/1"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vhost-user-blk", + "sock=/path/to/sock/1", + ], + r#"{ + "vhost_user_blk": [ + {"sock": "/path/to/sock/1", "num_queues": 1, "queue_size": 128, "wce": true} + ] + }"#, + true, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } + + #[test] + fn test_valid_vm_config_vsock() { + vec![ + ( + vec![ + "cloud-hypervisor", + "--vsock", + "cid=123,sock=/path/to/sock/1", + "cid=456,sock=/path/to/sock/2", + ], + r#"{ + "vsock": [ + {"cid": 123, "sock": "/path/to/sock/1"}, + {"cid": 456, "sock": "/path/to/sock/2"} + ] + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vsock", + "cid=123,sock=/path/to/sock/1", + "cid=456,sock=/path/to/sock/2", + ], + r#"{ + "vsock": [ + {"cid": 123, "sock": "/path/to/sock/1"} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--vsock", + "cid=124,sock=/path/to/sock/1", + ], + r#"{ + "vsock": [ + {"cid": 123, "sock": "/path/to/sock/1"} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--vsock", + "cid=123,sock=/path/to/sock/1,iommu=on", + ], + r#"{ + "vsock": [ + {"cid": 123, "sock": "/path/to/sock/1", "iommu": true} + ], + "iommu": true + }"#, + true, + ), + ( + vec![ + "cloud-hypervisor", + "--vsock", + "cid=123,sock=/path/to/sock/1,iommu=on", + ], + r#"{ + "vsock": [ + {"cid": 123, "sock": "/path/to/sock/1", "iommu": true} + ] + }"#, + false, + ), + ( + vec![ + "cloud-hypervisor", + "--vsock", + "cid=123,sock=/path/to/sock/1,iommu=off", + ], + r#"{ + "vsock": [ + {"cid": 123, "sock": "/path/to/sock/1", "iommu": false} + ] + }"#, + true, + ), + ] + .iter() + .for_each(|(cli, openapi, equal)| { + compare_vm_config_cli_vs_json(cli, openapi, *equal); + }); + } +} + #[cfg(test)] #[cfg(feature = "integration_tests")] #[macro_use]