tests/Client/ReadingRows.Tests.ps1
|
<# Integration Test: reading rows (brief lot 2) Get-XrmMultipleRecords -AsArray / -AsEntity, Get-XrmRecord -AsEntity / -IfExists / -Unique / -Attributes, Get-XrmAttributeValue (Get-XrmRowValue) on converted rows, Get-XrmMetadataValue, Resolve-XrmEntityReference, Get-XrmRecordCount, Get-XrmTotalRecordCount -SkipRefused -AsHashtable, Get-XrmRecordIds. Known issues 2.0.0.65: @(... -AsArray) message (K04), FetchExpression paging (K13), aggregate limit detection (K01), Remove-XrmRecord -IfExists (K14). #> . "$PSScriptRoot\..\_TestConfig.ps1"; $prefix = Get-TestName -Prefix "Rows"; $accountIds = [System.Collections.Generic.List[Guid]]::new(); $contactIds = [System.Collections.Generic.List[Guid]]::new(); function New-TestAccount([string]$Name, [hashtable]$Attributes = @{}) { $columns = @{ name = $Name }; foreach ($key in $Attributes.Keys) { $columns[$key] = $Attributes[$key]; } $record = New-XrmEntity -LogicalName "account" -Attributes $columns; $record.Id = $Global:XrmClient | Add-XrmRecord -Record $record; $accountIds.Add($record.Id); return $record.ToEntityReference(); } function New-PrefixQuery { $query = New-XrmQueryExpression -LogicalName "account" -Columns "name", "industrycode", "donotemail", "creditlimit", "parentaccountid"; return ($query | Add-XrmQueryCondition -Field "name" -Condition BeginsWith -Values $prefix); } Write-Section "Setup"; $account1 = New-TestAccount -Name "$prefix-1" -Attributes @{ industrycode = (New-XrmOptionSetValue -Value 1); donotemail = $true; creditlimit = (New-XrmMoney -Value 100) }; $account2 = New-TestAccount -Name "$prefix-2" -Attributes @{ parentaccountid = $account1 }; $account3 = New-TestAccount -Name "$prefix-3"; foreach ($i in 1..2) { $contact = New-XrmEntity -LogicalName "contact" -Attributes @{ lastname = "$prefix-contact-$i"; parentcustomerid = $account1 }; $contactIds.Add(($Global:XrmClient | Add-XrmRecord -Record $contact)); } Assert-Test "3 accounts and 2 contacts created" { $accountIds.Count -eq 3 -and $contactIds.Count -eq 2 }; # ============================================================ # L01 / L02 Get-XrmMultipleRecords -AsArray / -AsEntity # ============================================================ Write-Section "Get-XrmMultipleRecords -AsArray / -AsEntity"; $none = New-XrmQueryExpression -LogicalName "account" | Add-XrmQueryCondition -Field "name" -Condition Equal -Values "$prefix-none"; $noneRows = Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query $none -AsArray; Assert-Test "-AsArray: no row gives an empty array" { $null -ne $noneRows -and $noneRows -is [array] -and $noneRows.Count -eq 0 }; $one = New-XrmQueryExpression -LogicalName "account" -Columns "name" | Add-XrmQueryCondition -Field "name" -Condition Equal -Values "$prefix-1"; $oneRows = Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query $one -AsArray; Assert-Test "-AsArray: one row gives an array of one" { $oneRows -is [array] -and $oneRows.Count -eq 1 -and $oneRows[0].name -eq "$prefix-1" }; $oneDefault = Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query $one; Assert-Test "Default output unchanged: one row gives a single object" { $oneDefault -isnot [array] -and $oneDefault.name -eq "$prefix-1" }; $entities = Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query (New-PrefixQuery) -AsEntity -AsArray; Assert-Test "-AsEntity -AsArray: 3 SDK entities" { $entities.Count -eq 3 -and @($entities | Where-Object { $_ -isnot [Microsoft.Xrm.Sdk.Entity] }).Count -eq 0 }; # @() around -AsArray nests the whole result in a one-element array: Get-XrmRowValue names the probable cause $wrapped = @(Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query (New-PrefixQuery) -AsArray); $wrapError = $null; try { foreach ($row in $wrapped) { Get-XrmRowValue -Record $row -Name "name" | Out-Null; } } catch { $wrapError = $_.Exception.Message; } Assert-Test "@(... -AsArray): one element, and Get-XrmRowValue points to -AsArray" { $wrapped.Count -eq 1 -and $wrapError -like "*-AsArray*@()*" }; # ============================================================ # K13 Get-XrmMultipleRecords with a FetchExpression # ============================================================ Write-Section "Get-XrmMultipleRecords with a FetchExpression"; $fetchXml = "<fetch><entity name='account'><attribute name='name' /><filter><condition attribute='name' operator='begins-with' value='$prefix' /></filter><order attribute='name' /></entity></fetch>"; $fetchExpression = New-XrmFetchExpression -FetchXml $fetchXml; $fetchRows = Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query $fetchExpression -PageSize 2 -AsArray; Assert-Test "FetchExpression: the 3 rows, read in pages of 2" { $fetchRows.Count -eq 3 -and $fetchRows[0].name -eq "$prefix-1" -and $fetchRows[2].name -eq "$prefix-3" }; Assert-Test "Caller's FetchExpression unchanged" { $fetchExpression.Query -eq $fetchXml }; $topFetch = New-XrmFetchExpression -FetchXml $fetchXml.Replace("<fetch>", "<fetch top='2'>"); Assert-Test "Fetch with top: one call, top rows only" { (Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query $topFetch -PageSize 1 -AsArray).Count -eq 2 }; $aggregateFetch = New-XrmFetchExpression -FetchXml "<fetch aggregate='true'><entity name='account'><attribute name='accountid' alias='total' aggregate='count' /><filter><condition attribute='name' operator='begins-with' value='$prefix' /></filter></entity></fetch>"; $aggregateRows = Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query $aggregateFetch -AsEntity -AsArray; Assert-Test "Aggregate fetch: one row, read in one call" { $aggregateRows.Count -eq 1 -and $aggregateRows[0]["total"].Value -eq 3 }; # ============================================================ # L03 Get-XrmAttributeValue / Get-XrmRowValue # ============================================================ Write-Section "Get-XrmAttributeValue on converted rows"; $row1 = $Global:XrmClient | Get-XrmRecord -LogicalName "account" -Id $account1.Id -Columns "industrycode", "donotemail", "creditlimit"; $row2 = $Global:XrmClient | Get-XrmRecord -LogicalName "account" -Id $account2.Id -Columns "parentaccountid", "telephone1"; Assert-Test "Converted row keeps the label under the column name (why this cmdlet exists)" { $row1.donotemail -is [string] }; Assert-Test "Boolean read from a converted row is a bool" { ($row1 | Get-XrmRowValue -Name "donotemail") -is [bool] -and ($row1 | Get-XrmRowValue -Name "donotemail") -eq $true }; Assert-Test "-Raw: OptionSetValue => int" { ($row1 | Get-XrmAttributeValue -Name "industrycode" -Raw) -eq 1 }; Assert-Test "-Raw: Money => decimal" { ($row1 | Get-XrmAttributeValue -Name "creditlimit" -Raw) -eq [decimal]100 }; Assert-Test "-FormattedValue: label" { ($row1 | Get-XrmAttributeValue -Name "industrycode" -FormattedValue) -is [string] }; Assert-Test "-AsId: lookup Guid" { ($row2 | Get-XrmAttributeValue -Name "parentaccountid" -AsId) -eq $account1.Id }; Assert-Test "Missing column gives `$null" { $null -eq ($row2 | Get-XrmAttributeValue -Name "telephone1") }; Assert-Test "`$null record gives `$null" { $null -eq (Get-XrmAttributeValue -Record $null -Name "name") }; $aliasQuery = New-XrmQueryExpression -LogicalName "account" -Columns "name" | Add-XrmQueryCondition -Field "accountid" -Condition Equal -Values $account2.Id; $aliasLink = $aliasQuery | Add-XrmQueryLink -ToEntityName "account" -FromAttributeName "parentaccountid" -ToAttributeName "accountid" -Alias "parent"; $aliasLink | Add-XrmQueryLinkColumns -Columns "industrycode" | Out-Null; $aliasRow = Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query $aliasQuery | Select-Object -First 1; Assert-Test "-Raw unwraps an AliasedValue (linked option set => int)" { ($aliasRow | Get-XrmRowValue -Name "parent.industrycode" -Raw) -eq 1 }; $typeError = $null; try { Get-XrmAttributeValue -Record "not a row" -Name "name" | Out-Null; } catch { $typeError = $_.Exception.Message; } Assert-Test "Another object type raises an error" { $typeError -like "*Entity*" }; Assert-Test "Parameter aliases -Row / -Column" { (Get-XrmRowValue -Row $row1 -Column "donotemail") -eq $true }; # Scripts that defined their own Get-XrmRowValue (-Row -Column) or Get-XrmAttributeValue (-Record -Attribute) before the module had the alias $shadowed = & { function Get-XrmRowValue { param($Row, $Column) "caller helper"; } function Get-XrmAttributeValue { param($Record, $Attribute) "caller helper"; } Get-XrmRowValue -Row $row1 -Column "donotemail"; }; Assert-Test "The alias reaches the module command even when the caller defines functions with the same names" { $shadowed -is [bool] -and $shadowed -eq $true }; # ============================================================ # L04 Get-XrmMetadataValue # ============================================================ Write-Section "Get-XrmMetadataValue"; $accountMetadata = $Global:XrmClient | Get-XrmEntityMetadata -LogicalName "account" -Filter ([Microsoft.Xrm.Sdk.Metadata.EntityFilters]::Entity); Assert-Test "Managed property => bool value" { (Get-XrmMetadataValue -Metadata $accountMetadata -Property "IsAuditEnabled") -is [bool] }; Assert-Test "-CanBeChanged => bool" { (Get-XrmMetadataValue -Metadata $accountMetadata -Property "IsAuditEnabled" -CanBeChanged) -is [bool] }; Assert-Test "Label => text for -LanguageCode 1033" { ($accountMetadata | Get-XrmMetadataValue -Property "DisplayName" -LanguageCode 1033) -eq "Account" }; Assert-Test "Dotted path" { ($accountMetadata | Get-XrmMetadataValue -Property "DisplayName.UserLocalizedLabel.LanguageCode") -gt 0 }; Assert-Test "Plain property" { ($accountMetadata | Get-XrmMetadataValue -Property "PrimaryIdAttribute") -eq "accountid" }; $canBeChangedError = $null; try { $accountMetadata | Get-XrmMetadataValue -Property "LogicalName" -CanBeChanged | Out-Null; } catch { $canBeChangedError = $_.Exception.Message; } Assert-Test "-CanBeChanged on a plain property raises an error" { $canBeChangedError -like "*not a managed property*" }; $nameColumn = $Global:XrmClient | Get-XrmColumn -EntityLogicalName "account" -LogicalName "name"; Assert-Test "AttributeRequiredLevelManagedProperty => enum value" { ($nameColumn | Get-XrmMetadataValue -Property "RequiredLevel") -is [Microsoft.Xrm.Sdk.Metadata.AttributeRequiredLevel] }; # ============================================================ # L05 / L06 Get-XrmRecord # ============================================================ Write-Section "Get-XrmRecord -IfExists / -Unique / -Attributes / -AsEntity"; $missingId = [Guid]::NewGuid(); $missingError = $null; $missing = "not set"; try { $missing = $Global:XrmClient | Get-XrmRecord -LogicalName "account" -Id $missingId -IfExists; } catch { $missingError = $_.Exception.Message; } Assert-Test "-IfExists: missing id gives `$null without error" { $null -eq $missingError -and $null -eq $missing }; $asEntity = $Global:XrmClient | Get-XrmRecord -LogicalName "account" -Id $account1.Id -Columns "name" -AsEntity; Assert-Test "-AsEntity: SDK entity" { $asEntity -is [Microsoft.Xrm.Sdk.Entity] -and $asEntity["name"] -eq "$prefix-1" }; $byAttributes = $Global:XrmClient | Get-XrmRecord -LogicalName "account" -Attributes @{ name = "$prefix-1"; industrycode = (New-XrmOptionSetValue -Value 1) } -Columns "name"; Assert-Test "-Attributes: AND of conditions, OptionSetValue compared on value" { $null -ne $byAttributes -and $byAttributes.Id -eq $account1.Id }; $byLookup = $Global:XrmClient | Get-XrmRecord -LogicalName "account" -Attributes @{ parentaccountid = $account1; name = "$prefix-2" }; Assert-Test "-Attributes: EntityReference compared on id" { $null -ne $byLookup -and $byLookup.Id -eq $account2.Id }; $byNull = $Global:XrmClient | Get-XrmRecord -LogicalName "account" -Attributes @{ name = "$prefix-3"; parentaccountid = $null }; Assert-Test "-Attributes: `$null value matches an empty column" { $null -ne $byNull -and $byNull.Id -eq $account3.Id }; $noMatch = $Global:XrmClient | Get-XrmRecord -LogicalName "account" -Attributes @{ name = "$prefix-3"; parentaccountid = $account1 }; Assert-Test "-Attributes: no match gives `$null" { $null -eq $noMatch }; $duplicate = New-TestAccount -Name "$prefix-1"; $uniqueError = $null; try { $Global:XrmClient | Get-XrmRecord -LogicalName "account" -AttributeName "name" -Value "$prefix-1" -Unique | Out-Null; } catch { $uniqueError = $_.Exception.Message; } Assert-Test "-Unique: two matches raise an error" { $uniqueError -like "*More than one*" }; # ============================================================ # L07 Resolve-XrmEntityReference # ============================================================ Write-Section "Resolve-XrmEntityReference"; $resolved = Resolve-XrmEntityReference -XrmClient $Global:XrmClient -LogicalName "account" -Attributes @{ name = "$prefix-2" }; Assert-Test "Found: EntityReference of the row" { $resolved -is [Microsoft.Xrm.Sdk.EntityReference] -and $resolved.Id -eq $account2.Id -and $resolved.LogicalName -eq "account" }; $notFoundError = $null; try { Resolve-XrmEntityReference -XrmClient $Global:XrmClient -LogicalName "account" -Attributes @{ name = "$prefix-none" } | Out-Null; } catch { $notFoundError = $_.Exception.Message; } Assert-Test "Not found raises an error" { $notFoundError -like "*No 'account' row*" }; Assert-Test "-IfExists: not found gives `$null" { $null -eq (Resolve-XrmEntityReference -XrmClient $Global:XrmClient -LogicalName "account" -Attributes @{ name = "$prefix-none" } -IfExists) }; $ambiguousError = $null; try { Resolve-XrmEntityReference -XrmClient $Global:XrmClient -LogicalName "account" -Attributes @{ name = "$prefix-1" } | Out-Null; } catch { $ambiguousError = $_.Exception.Message; } Assert-Test "Several matches raise an error" { $ambiguousError -like "*More than one*" }; $cache = @{}; $first = Resolve-XrmEntityReference -XrmClient $Global:XrmClient -LogicalName "account" -Attributes @{ name = "$prefix-3" } -Cache $cache; $Global:XrmClient | Remove-XrmRecord -LogicalName "account" -Id $account3.Id; $accountIds.Remove($account3.Id) | Out-Null; $second = Resolve-XrmEntityReference -XrmClient $Global:XrmClient -LogicalName "account" -Attributes @{ name = "$PREFIX-3".ToUpperInvariant() } -Cache $cache; Assert-Test "-Cache: second resolution served from the caller's cache (case-insensitive key)" { $cache.Count -eq 1 -and $second.Id -eq $first.Id }; # ============================================================ # L08 Get-XrmRecordCount / Get-XrmTotalRecordCount # ============================================================ Write-Section "Get-XrmRecordCount"; $countQuery = New-XrmQueryExpression -LogicalName "account" -Columns "name" | Add-XrmQueryCondition -Field "name" -Condition BeginsWith -Values $prefix; Assert-Test "Aggregate count (3 accounts: 2 + the duplicate)" { (Get-XrmRecordCount -XrmClient $Global:XrmClient -Query $countQuery) -eq 3 }; Assert-Test "-NoAggregate: same count by paging" { (Get-XrmRecordCount -XrmClient $Global:XrmClient -Query $countQuery -NoAggregate) -eq 3 }; Assert-Test "Caller's query columns untouched" { $countQuery.ColumnSet.Columns.Count -eq 1 -and $countQuery.ColumnSet.Columns[0] -eq "name" }; $linkedQuery = New-XrmQueryExpression -LogicalName "account" | Add-XrmQueryCondition -Field "name" -Condition BeginsWith -Values $prefix; $contactLink = $linkedQuery | Add-XrmQueryLink -ToEntityName "contact" -FromAttributeName "accountid" -ToAttributeName "parentcustomerid"; Assert-Test "One-to-many link: an account with 2 contacts counts once" { (Get-XrmRecordCount -XrmClient $Global:XrmClient -Query $linkedQuery) -eq 1 }; Assert-Test "One-to-many link with -NoAggregate: counts once" { (Get-XrmRecordCount -XrmClient $Global:XrmClient -Query $linkedQuery -NoAggregate) -eq 1 }; $fetch = "<fetch><entity name='contact'><attribute name='lastname' /><filter><condition attribute='lastname' operator='like' value='$prefix-contact-%' /></filter></entity></fetch>"; Assert-Test "-FetchXml: 2 contacts" { (Get-XrmRecordCount -XrmClient $Global:XrmClient -FetchXml $fetch) -eq 2 }; $topQuery = New-XrmQueryExpression -LogicalName "account" -TopCount 2 | Add-XrmQueryCondition -Field "name" -Condition BeginsWith -Values $prefix; Assert-Test "TopCount caps the count" { (Get-XrmRecordCount -XrmClient $Global:XrmClient -Query $topQuery) -eq 2 }; # K01: the refusal above 50,000 rows comes with two wordings and a fault code; the test instance has no such table, so the detection is checked on built exceptions $moduleScope = Get-Module PowerDataOps; Assert-Test "Aggregate limit recognized: 'AggregateQueryRecordLimit' wording" { & $moduleScope { Test-XrmAggregateLimitErrorInternal -Exception ([System.Exception]::new("AggregateQueryRecordLimit exceeded. Cannot perform this operation.")) } }; Assert-Test "Aggregate limit recognized: 'maximum record limit of 50000' wording, as an inner exception" { & $moduleScope { Test-XrmAggregateLimitErrorInternal -Exception ([System.Exception]::new("Request failed", [System.Exception]::new("The maximum record limit of 50000 is exceeded. Reduce the number of records."))) }; }; Assert-Test "Aggregate limit recognized: fault code 0x8004E023 whatever the text" { & $moduleScope { $fault = [Microsoft.Xrm.Sdk.OrganizationServiceFault]::new(); $fault.ErrorCode = -2147164125; Test-XrmAggregateLimitErrorInternal -Exception ([System.ServiceModel.FaultException[Microsoft.Xrm.Sdk.OrganizationServiceFault]]::new($fault, "Some other text")); }; }; Assert-Test "Another error is not taken for the limit" { -not (& $moduleScope { Test-XrmAggregateLimitErrorInternal -Exception ([System.Exception]::new("Principal user is missing prvReadAccount privilege")) }) }; $totals = Get-XrmTotalRecordCount -XrmClient $Global:XrmClient -LogicalNames "account", "contact" -AsHashtable; Assert-Test "Get-XrmTotalRecordCount -AsHashtable" { $totals -is [hashtable] -and $totals.ContainsKey("account") -and $totals.ContainsKey("contact") }; $skipped = Get-XrmTotalRecordCount -XrmClient $Global:XrmClient -LogicalNames "account", "pdo_nosuchtable" -SkipRefused -AsHashtable -WarningAction SilentlyContinue; Assert-Test "-SkipRefused: an unknown table does not fail the call" { $skipped.ContainsKey("account") -and -not $skipped.ContainsKey("pdo_nosuchtable") }; # ============================================================ # L09 Get-XrmRecordIds # ============================================================ Write-Section "Get-XrmRecordIds"; $idQuery = New-XrmQueryExpression -LogicalName "account" -Columns "name" | Add-XrmQueryCondition -Field "name" -Condition BeginsWith -Values $prefix; $ids = Get-XrmRecordIds -XrmClient $Global:XrmClient -Query $idQuery; Assert-Test "-Query: HashSet of the 3 ids" { $ids -is [System.Collections.Generic.HashSet[Guid]] -and $ids.Count -eq 3 -and $ids.Contains($account1.Id) -and $ids.Contains($duplicate.Id) }; Assert-Test "Caller's query columns restored" { $idQuery.ColumnSet.Columns.Count -eq 1 }; $emptyIds = Get-XrmRecordIds -XrmClient $Global:XrmClient -Query $none; Assert-Test "No row: empty HashSet, not `$null" { $emptyIds -is [System.Collections.Generic.HashSet[Guid]] -and $emptyIds.Count -eq 0 }; $businessUnitIds = Get-XrmRecordIds -XrmClient $Global:XrmClient -LogicalName "businessunit"; Assert-Test "-LogicalName: all rows of the table" { $businessUnitIds.Count -ge 1 }; # ============================================================ # K14 Remove-XrmRecord -IfExists # ============================================================ Write-Section "Remove-XrmRecord -IfExists"; $ifExistsError = $null; try { $Global:XrmClient | Remove-XrmRecord -LogicalName "account" -Id ([Guid]::NewGuid()) -IfExists -ErrorAction Stop; } catch { $ifExistsError = $_.Exception.Message; } Assert-Test "-IfExists: missing row, no error" { $null -eq $ifExistsError }; # Without -ErrorAction Stop: any error other than "not found" must stop the caller, like the other -IfExists switches $otherError = $null; $reached = $false; try { $Global:XrmClient | Remove-XrmRecord -LogicalName "organization" -Id ([Guid]::NewGuid()) -IfExists; $reached = $true; } catch { $otherError = $_.Exception.Message; } Assert-Test "-IfExists: another error is raised ($otherError)" { $null -ne $otherError -and -not $reached }; # ============================================================ # CLEANUP # ============================================================ Write-Section "Cleanup"; foreach ($id in $contactIds) { try { $Global:XrmClient | Remove-XrmRecord -LogicalName "contact" -Id $id; } catch { } } foreach ($id in $accountIds) { try { $Global:XrmClient | Remove-XrmRecord -LogicalName "account" -Id $id; } catch { } } Assert-Test "Cleanup complete" { $true }; Write-TestSummary; |