Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 53 additions & 13 deletions lib/dsc-lib-osinfo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,43 +184,83 @@ pub fn perform_test(input_json: &str) -> Result<OsInfo, String> {
// name is ignored for test since it's only generated for export and not a property of the actual OS state.
let actual = OsInfo::new(false);

Ok(test_state(&desired, actual))
}

fn test_state(desired: &OsInfo, actual: OsInfo) -> OsInfo {
let mut in_desired_state = true;

if let Some(ref desired_family) = desired.family
&& let Some(ref actual_family) = actual.family
&& desired_family != actual_family {
&& actual.family.as_ref() != Some(desired_family) {
in_desired_state = false;
}

if let Some(ref desired_version) = desired.version
&& let Some(ref actual_version) = actual.version
&& !version_matches(desired_version, actual_version) {
&& actual.version.as_ref().is_none_or(|actual_version| !version_matches(desired_version, actual_version)) {
in_desired_state = false;
}

if let Some(ref desired_edition) = desired.edition
&& let Some(ref actual_edition) = actual.edition
&& actual_edition != desired_edition {
&& actual.edition.as_ref() != Some(desired_edition) {
in_desired_state = false;
}

if let Some(ref desired_codename) = desired.codename
&& let Some(ref actual_codename) = actual.codename
&& actual_codename != desired_codename {
&& actual.codename.as_ref() != Some(desired_codename) {
in_desired_state = false;
}

if let Some(desired_bitness) = desired.bitness
&& let Some(actual_bitness) = actual.bitness
&& actual_bitness != desired_bitness {
&& actual.bitness != Some(desired_bitness) {
in_desired_state = false;
}

if let Some(ref desired_architecture) = desired.architecture
&& let Some(ref actual_architecture) = actual.architecture
&& actual_architecture != desired_architecture {
&& actual.architecture.as_ref() != Some(desired_architecture) {
in_desired_state = false;
}

Ok(OsInfo { in_desired_state: Some(in_desired_state), ..actual })
OsInfo { in_desired_state: Some(in_desired_state), ..actual }
}

#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;

#[test]
fn requested_properties_must_be_present() {
let state = json!({
"family": "Linux",
"version": "Rolling Release",
"edition": "Example Edition",
"codename": "example",
"bitness": 64,
"architecture": "x86_64"
});

for property in ["family", "version", "edition", "codename", "bitness", "architecture"] {
let desired: OsInfo = serde_json::from_value(json!({ property: state[property] })).unwrap();
let actual: OsInfo = serde_json::from_value(state.clone()).unwrap();
assert_eq!(test_state(&desired, actual).in_desired_state, Some(true), "{property}");

let mut missing = state.clone();
missing.as_object_mut().unwrap().remove(property);
let actual: OsInfo = serde_json::from_value(missing).unwrap();
assert_eq!(test_state(&desired, actual).in_desired_state, Some(false), "{property}");
}
}

#[test]
fn rolling_release_without_optional_properties_matches() {
let actual: OsInfo = serde_json::from_value(json!({
"family": "Linux",
"version": "Rolling Release",
"bitness": 64,
"architecture": "x86_64"
})).unwrap();
let desired: OsInfo = serde_json::from_value(json!({ "version": "Rolling Release" })).unwrap();
let result = test_state(&desired, actual.clone());
assert_eq!(result, OsInfo { in_desired_state: Some(true), ..actual });
}
}
40 changes: 28 additions & 12 deletions resources/osinfo/tests/osinfo.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,15 @@ Describe 'osinfo test subcommand version operator tests' {
BeforeDiscovery {
$osGetResult = dsc resource get -r Microsoft/OSInfo | ConvertFrom-Json
$currentVersion = $osGetResult.actualState.version
$skipVersionOperators = $currentVersion -notmatch '^[0-9]'

$versionTestCases = @(
@{ constraint = $currentVersion; expectedState = $true; description = 'exact version without operator' }
@{ constraint = "= $currentVersion"; expectedState = $true; description = 'exact version with = operator' }
@{ constraint = ">= $currentVersion"; expectedState = $true; description = '>= current version' }
@{ constraint = "<= $currentVersion"; expectedState = $true; description = '<= current version' }
@{ constraint = "> $currentVersion"; expectedState = $false; description = '> current version' }
@{ constraint = "< $currentVersion"; expectedState = $false; description = '< current version' }
@{ constraint = $currentVersion; expectedState = $true; description = 'exact version without operator'; skip = $false }
@{ constraint = "= $currentVersion"; expectedState = $true; description = 'exact version with = operator'; skip = $skipVersionOperators }
@{ constraint = ">= $currentVersion"; expectedState = $true; description = '>= current version'; skip = $skipVersionOperators }
@{ constraint = "<= $currentVersion"; expectedState = $true; description = '<= current version'; skip = $skipVersionOperators }
@{ constraint = "> $currentVersion"; expectedState = $false; description = '> current version'; skip = $skipVersionOperators }
@{ constraint = "< $currentVersion"; expectedState = $false; description = '< current version'; skip = $skipVersionOperators }
)

$invalidSyntaxCases = @(
Expand All @@ -80,11 +81,13 @@ Describe 'osinfo test subcommand version operator tests' {
}

Context 'valid version constraints' {
It 'version constraint "<constraint>" (<description>) should report inDesiredState = <expectedState>' -ForEach $versionTestCases {
$json = "{`"version`": `"$constraint`"}"
$out = $json | dsc resource test -r Microsoft/OSInfo -f - | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
$out.inDesiredState | Should -Be $expectedState
foreach ($versionTestCase in $versionTestCases) {
It 'version constraint "<constraint>" (<description>) should report inDesiredState = <expectedState>' -ForEach @($versionTestCase) -Skip:$versionTestCase.skip {
$json = "{`"version`": `"$constraint`"}"
$out = $json | dsc resource test -r Microsoft/OSInfo -f - | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
$out.inDesiredState | Should -Be $expectedState
}
}
}

Expand All @@ -99,6 +102,10 @@ Describe 'osinfo test subcommand version operator tests' {
}

Describe 'osinfo test subcommand property tests' {
BeforeDiscovery {
$hasCodename = -not [string]::IsNullOrEmpty((dsc resource get -r Microsoft/OSInfo | ConvertFrom-Json).actualState.codename)
}

BeforeAll {
$actual = (dsc resource get -r Microsoft/OSInfo | ConvertFrom-Json).actualState
}
Expand All @@ -119,7 +126,7 @@ Describe 'osinfo test subcommand property tests' {
}
}

Context 'codename property' -Skip:(-not $IsLinux) {
Context 'codename property' -Skip:(-not $hasCodename) {
It 'should be in desired state when codename matches actual' {
$json = @{ codename = $actual.codename } | ConvertTo-Json -Compress
$out = $json | dsc resource test -r Microsoft/OSInfo -f - | ConvertFrom-Json
Expand All @@ -135,6 +142,15 @@ Describe 'osinfo test subcommand property tests' {
}
}

It 'should not be in desired state when a requested codename is not reported' -Skip:$hasCodename {
$json = @{ codename = 'nonexistentcodename' } | ConvertTo-Json -Compress
$out = $json | dsc resource test -r Microsoft/OSInfo -f - | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
$out.inDesiredState | Should -BeFalse
$out.actualState._inDesiredState | Should -BeFalse
$out.differingProperties | Should -Contain 'codename'
}

Context 'bitness property' {
It 'should be in desired state when bitness matches actual' {
$json = @{ bitness = [int]$actual.bitness } | ConvertTo-Json -Compress
Expand Down
Loading