From 67a0ec44880018d244b736e3fd78887a67a64991 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 28 Oct 2026 17:47:15 +0000 Subject: [PATCH 1/3] Initial plan From 190c48e28c2ad01c8c94ab46be1b78bfbfb82efd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 28 Oct 2026 17:52:18 +0000 Subject: [PATCH 2/3] Fix OSInfo absent-property checks and rolling-release tests Co-authored-by: SteveL-MSFT <11859881+SteveL-MSFT@users.noreply.github.com> --- lib/dsc-lib-osinfo/src/lib.rs | 66 ++++++++++++++++++++----- resources/osinfo/tests/osinfo.tests.ps1 | 30 ++++++++--- 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/lib/dsc-lib-osinfo/src/lib.rs b/lib/dsc-lib-osinfo/src/lib.rs index 7ee7bdc84..3ce28aa12 100644 --- a/lib/dsc-lib-osinfo/src/lib.rs +++ b/lib/dsc-lib-osinfo/src/lib.rs @@ -184,43 +184,83 @@ pub fn perform_test(input_json: &str) -> Result { // 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 }); + } } diff --git a/resources/osinfo/tests/osinfo.tests.ps1 b/resources/osinfo/tests/osinfo.tests.ps1 index f7b5ed262..d23c72da2 100644 --- a/resources/osinfo/tests/osinfo.tests.ps1 +++ b/resources/osinfo/tests/osinfo.tests.ps1 @@ -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 = @( @@ -80,7 +81,7 @@ Describe 'osinfo test subcommand version operator tests' { } Context 'valid version constraints' { - It 'version constraint "" () should report inDesiredState = ' -ForEach $versionTestCases { + It 'version constraint "" () should report inDesiredState = ' -ForEach $versionTestCases -Skip:$skip { $json = "{`"version`": `"$constraint`"}" $out = $json | dsc resource test -r Microsoft/OSInfo -f - | ConvertFrom-Json $LASTEXITCODE | Should -Be 0 @@ -99,6 +100,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 } @@ -119,7 +124,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 @@ -135,6 +140,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 From 8808572889b30445f59725f6b9885415777425e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 28 Oct 2026 19:07:43 +0000 Subject: [PATCH 3/3] Fix per-case OSInfo version test skips Co-authored-by: SteveL-MSFT <11859881+SteveL-MSFT@users.noreply.github.com> --- resources/osinfo/tests/osinfo.tests.ps1 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/resources/osinfo/tests/osinfo.tests.ps1 b/resources/osinfo/tests/osinfo.tests.ps1 index d23c72da2..1b9117157 100644 --- a/resources/osinfo/tests/osinfo.tests.ps1 +++ b/resources/osinfo/tests/osinfo.tests.ps1 @@ -81,11 +81,13 @@ Describe 'osinfo test subcommand version operator tests' { } Context 'valid version constraints' { - It 'version constraint "" () should report inDesiredState = ' -ForEach $versionTestCases -Skip:$skip { - $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 "" () should report inDesiredState = ' -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 + } } }