Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,62 @@ Describe 'Update-InstanceSizeFlexibility' {
}
}

Context 'Sort order' {
# Culture-aware collation interleaves case and orders "Dasv4 Series" before
# "DCadsv5-series DedicatedHost"; an ordinal comparison puts the uppercase letter first.
# Sorting with the current culture makes the same records reorder between hosts, turning
# a no-op regeneration into a few hundred lines of diff that bury any real change.
It 'Orders flexibility groups ordinally rather than by the current culture' {
Mock Invoke-AzRestMethod {
New-CatalogResponse -Items @(
(New-CatalogItem -Sku 'Standard_D2as_v4' -Group 'Dasv4 Series' -Ratio '1'),
(New-CatalogItem -Sku 'dcadsv5 type 1' -Group 'DCadsv5-series DedicatedHost' -Ratio '1')
)
}

Invoke-Generator $baseParams

@(Import-Csv $outFile).InstanceSizeFlexibilityGroup |
Should -Be @('DCadsv5-series DedicatedHost', 'Dasv4 Series')
}

It 'Orders SKUs within a group ordinally' {
Mock Invoke-AzRestMethod {
New-CatalogResponse -Items @(
(New-CatalogItem -Sku 'Standard_Dadsv5' -Group 'Dadsv5 Series' -Ratio '1'),
(New-CatalogItem -Sku 'Standard_DC2ads_v5' -Group 'Dadsv5 Series' -Ratio '1')
)
}

Invoke-Generator $baseParams

@(Import-Csv $outFile).ArmSkuName | Should -Be @('Standard_DC2ads_v5', 'Standard_Dadsv5')
}

It 'Orders identically under a culture with different collation rules' {
$originalCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
try
{
[System.Threading.Thread]::CurrentThread.CurrentCulture = [System.Globalization.CultureInfo]::new('de-DE')
Mock Invoke-AzRestMethod {
New-CatalogResponse -Items @(
(New-CatalogItem -Sku 'Standard_D2as_v4' -Group 'Dasv4 Series' -Ratio '1'),
(New-CatalogItem -Sku 'dcadsv5 type 1' -Group 'DCadsv5-series DedicatedHost' -Ratio '1')
)
}

Invoke-Generator $baseParams

@(Import-Csv $outFile).InstanceSizeFlexibilityGroup |
Should -Be @('DCadsv5-series DedicatedHost', 'Dasv4 Series')
}
finally
{
[System.Threading.Thread]::CurrentThread.CurrentCulture = $originalCulture
}
}
}

Context 'Published dataset' {
It 'Has globally unique ArmSkuName values' {
$csv = Import-Csv "$PSScriptRoot/../../../open-data/InstanceSizeFlexibility.csv"
Expand All @@ -388,6 +444,24 @@ Describe 'Update-InstanceSizeFlexibility' {
@($csv | Where-Object { [double]$_.Ratio -le 0 }).ArmSkuName | Should -BeNullOrEmpty
}

It 'Is written in ordinal sort order' {
Comment thread
flanakin marked this conversation as resolved.
# Catches a file regenerated on a host whose culture collates differently, which
# reorders hundreds of rows without changing a single value. The comparer mirrors the
# one in src/scripts/Update-InstanceSizeFlexibility.ps1 and must stay in sync with it:
# if the script gains a sort key, this test keeps asserting the old order until it does
# too.
$csv = @(Import-Csv "$PSScriptRoot/../../../open-data/InstanceSizeFlexibility.csv")
$sorted = [Collections.Generic.List[object]]::new([object[]]$csv)
$sorted.Sort([Comparison[object]] {
param($x, $y)
$byGroup = [string]::CompareOrdinal($x.InstanceSizeFlexibilityGroup, $y.InstanceSizeFlexibilityGroup)
if ($byGroup -ne 0) { return $byGroup }
[string]::CompareOrdinal($x.ArmSkuName, $y.ArmSkuName)
})

($sorted.ArmSkuName -join "`n") | Should -BeExactly ($csv.ArmSkuName -join "`n")
}

It 'Has the documented three-column schema' {
$csv = Import-Csv "$PSScriptRoot/../../../open-data/InstanceSizeFlexibility.csv"
@($csv[0].PSObject.Properties.Name) | Should -Be @('InstanceSizeFlexibilityGroup', 'ArmSkuName', 'Ratio')
Expand Down
21 changes: 19 additions & 2 deletions src/scripts/Update-InstanceSizeFlexibility.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,27 @@ if (-not $Raw)
$allRecords = Get-NormalizedRecords -Records $allRecords
}

# Sorted ordinally rather than with Sort-Object, whose comparer follows the current culture.
# Culture-aware collation orders "DCadsv5-series DedicatedHost" after "Dasv4 Series" while an
# ordinal comparison puts it before, so the same records regenerated on a differently configured
# host produce a few hundred lines of pure reordering that bury any real change in review.
#
# List.Sort is unstable where Sort-Object is stable, but no tie can reach it: $seen is keyed by
# group + ArmSkuName, and a duplicate ArmSkuName across groups throws above, so the two keys order
# every record uniquely in the normalized and the -Raw path alike. Keep the comparer in sync with
# the published-file order test in src/powershell/Tests/Unit/Update-InstanceSizeFlexibility.Tests.ps1.
$sortedRecords = [Collections.Generic.List[object]]::new()
if ($allRecords) { $sortedRecords.AddRange([object[]]@($allRecords)) } # an empty sweep leaves $allRecords null
$sortedRecords.Sort([Comparison[object]] {
Comment thread
flanakin marked this conversation as resolved.
param($x, $y)
$byGroup = [string]::CompareOrdinal($x.InstanceSizeFlexibilityGroup, $y.InstanceSizeFlexibilityGroup)
if ($byGroup -ne 0) { return $byGroup }
[string]::CompareOrdinal($x.ArmSkuName, $y.ArmSkuName)
})

# Ratio is formatted invariantly rather than left to Export-Csv, which uses the current culture:
# on a comma-decimal machine it would publish "2,1" and break every consumer of the file.
$rows = $allRecords |
Sort-Object InstanceSizeFlexibilityGroup, ArmSkuName |
$rows = $sortedRecords |
Select-Object InstanceSizeFlexibilityGroup, ArmSkuName,
@{ Name = 'Ratio'; Expression = { $_.Ratio.ToString([Globalization.CultureInfo]::InvariantCulture) } }

Expand Down
Loading