tests/AI.Module.Tests.ps1
|
#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' } #Requires -Modules ImportExcel <# .SYNOPSIS Pester tests for all AI / Machine Learning inventory modules. .DESCRIPTION Tests both Processing and Reporting phases for each AI module using synthetic mock data. No live Azure authentication is required. .NOTES Author: AzureScout Contributors Version: 1.0.0 Created: 2026-02-24 Phase: 14.6 — Phase 14 Testing (AI/Foundry/ML) #> # =================================================================== # DISCOVERY-TIME # =================================================================== $AIPath = Join-Path (Split-Path -Parent $PSScriptRoot) 'Modules' 'Public' 'InventoryModules' 'AI' $AIModules = @( @{ Name = 'OpenAIAccounts'; File = 'OpenAIAccounts.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'OpenAI'; Worksheet = 'Azure OpenAI Services' } @{ Name = 'SearchServices'; File = 'SearchServices.ps1'; Type = 'microsoft.search/searchservices'; Kind = ''; Worksheet = 'Search Services' } @{ Name = 'MachineLearning'; File = 'MachineLearning.ps1'; Type = 'microsoft.machinelearningservices/workspaces'; Kind = ''; Worksheet = 'ML Workspaces' } @{ Name = 'SpeechService'; File = 'SpeechService.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'SpeechServices'; Worksheet = 'Speech Service' } @{ Name = 'TextAnalytics'; File = 'TextAnalytics.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'TextAnalytics'; Worksheet = 'Language / Text Analytics' } @{ Name = 'ComputerVision'; File = 'ComputerVision.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'ComputerVision'; Worksheet = 'Computer Vision' } @{ Name = 'ContentSafety'; File = 'ContentSafety.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'ContentSafety'; Worksheet = 'Content Safety' } @{ Name = 'FormRecognizer'; File = 'FormRecognizer.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'FormRecognizer'; Worksheet = 'Document Intelligence' } @{ Name = 'BotServices'; File = 'BotServices.ps1'; Type = 'microsoft.botservice/botservices'; Kind = ''; Worksheet = 'Bot Services' } @{ Name = 'AIFoundryHubs'; File = 'AIFoundryHubs.ps1'; Type = 'microsoft.machinelearningservices/workspaces'; Kind = 'Hub'; Worksheet = 'AI Foundry Hubs' } @{ Name = 'AIFoundryProjects'; File = 'AIFoundryProjects.ps1'; Type = 'microsoft.machinelearningservices/workspaces'; Kind = 'Project'; Worksheet = 'AI Foundry Projects' } # --- New modules --- @{ Name = 'AppliedAIServices'; File = 'AppliedAIServices.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'FormRecognizer'; Worksheet = 'Applied AI' } @{ Name = 'AzureAI'; File = 'AzureAI.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'AIServices'; Worksheet = 'Azure AI' } @{ Name = 'ContentModerator'; File = 'ContentModerator.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'ContentModerator'; Worksheet = 'Content Moderator' } @{ Name = 'CustomVision'; File = 'CustomVision.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'CustomVision.Training'; Worksheet = 'Custom Vision' } @{ Name = 'FaceAPI'; File = 'FaceAPI.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'Face'; Worksheet = 'Face API' } @{ Name = 'HealthInsights'; File = 'HealthInsights.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'HealthInsights'; Worksheet = 'Health Insights' } @{ Name = 'ImmersiveReader'; File = 'ImmersiveReader.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'ImmersiveReader'; Worksheet = 'Immersive Reader' } @{ Name = 'Translator'; File = 'Translator.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'TextTranslation'; Worksheet = 'Translator' } @{ Name = 'MLComputes'; File = 'MLComputes.ps1'; Type = 'microsoft.machinelearningservices/workspaces'; Kind = ''; Worksheet = 'ML Computes' } @{ Name = 'MLDatasets'; File = 'MLDatasets.ps1'; Type = 'microsoft.machinelearningservices/workspaces'; Kind = ''; Worksheet = 'ML Datasets' } @{ Name = 'MLDatastores'; File = 'MLDatastores.ps1'; Type = 'microsoft.machinelearningservices/workspaces'; Kind = ''; Worksheet = 'ML Datastores' } @{ Name = 'MLEndpoints'; File = 'MLEndpoints.ps1'; Type = 'microsoft.machinelearningservices/workspaces'; Kind = ''; Worksheet = 'ML Endpoints' } @{ Name = 'MLModels'; File = 'MLModels.ps1'; Type = 'microsoft.machinelearningservices/workspaces'; Kind = ''; Worksheet = 'ML Models' } @{ Name = 'MLPipelines'; File = 'MLPipelines.ps1'; Type = 'microsoft.machinelearningservices/workspaces'; Kind = ''; Worksheet = 'ML Pipelines' } @{ Name = 'OpenAIDeployments'; File = 'OpenAIDeployments.ps1'; Type = 'microsoft.cognitiveservices/accounts'; Kind = 'OpenAI'; Worksheet = 'OpenAI Deployments' } @{ Name = 'SearchIndexes'; File = 'SearchIndexes.ps1'; Type = 'microsoft.search/searchservices'; Kind = ''; Worksheet = 'Search Indexes' } ) # =================================================================== # EXECUTION-TIME SETUP # =================================================================== BeforeAll { $script:ModuleRoot = Split-Path -Parent $PSScriptRoot $script:AIPath = Join-Path $script:ModuleRoot 'Modules' 'Public' 'InventoryModules' 'AI' $script:TempDir = Join-Path $env:TEMP 'AZSC_AITests' if (Test-Path $script:TempDir) { Remove-Item $script:TempDir -Recurse -Force } New-Item -ItemType Directory -Path $script:TempDir -Force | Out-Null function New-MockAIResource { param([string]$Id, [string]$Name, [string]$Type, [string]$Kind = '', [string]$Location = 'eastus', [string]$RG = 'rg-ai', [string]$SubscriptionId = 'sub-00000001', [object]$Props) [PSCustomObject]@{ id = $Id NAME = $Name TYPE = $Type KIND = $Kind LOCATION = $Location RESOURCEGROUP = $RG subscriptionId = $SubscriptionId tags = [PSCustomObject]@{} PROPERTIES = $Props } } $script:MockResources = @() # OpenAI Account (Kind = OpenAI) $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/oai/oai1' -Name 'oai-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'OpenAI' -Props ([PSCustomObject]@{ endpoint = 'https://oai-prod.openai.azure.com'; customSubDomainName = 'oai-prod' provisioningState = 'Succeeded' networkAcls = [PSCustomObject]@{ defaultAction = 'Allow' } sku = [PSCustomObject]@{ name = 'S0' } }) # Speech Service $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/speech/speech1' -Name 'speech-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'SpeechServices' -Props ([PSCustomObject]@{ endpoint = 'https://eastus.api.cognitive.microsoft.com/'; provisioningState = 'Succeeded' datecreated = '2025-08-15T10:30:00Z' sku = [PSCustomObject]@{ name = 'S0' } }) # Text Analytics / Language $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/ta/ta1' -Name 'lang-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'TextAnalytics' -Props ([PSCustomObject]@{ endpoint = 'https://lang-prod.cognitiveservices.azure.com/'; provisioningState = 'Succeeded' datecreated = '2025-06-01T08:00:00Z' sku = [PSCustomObject]@{ name = 'S' } }) # Computer Vision $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/cv/cv1' -Name 'cv-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'ComputerVision' -Props ([PSCustomObject]@{ endpoint = 'https://cv-prod.cognitiveservices.azure.com/'; provisioningState = 'Succeeded' datecreated = '2025-07-10T14:00:00Z' sku = [PSCustomObject]@{ name = 'S1' } }) # Content Safety $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/cs/cs1' -Name 'cs-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'ContentSafety' -Props ([PSCustomObject]@{ endpoint = 'https://cs-prod.cognitiveservices.azure.com/'; provisioningState = 'Succeeded' datecreated = '2025-09-20T12:00:00Z' sku = [PSCustomObject]@{ name = 'S0' } }) # Form Recognizer / Document Intelligence $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/fr/fr1' -Name 'fr-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'FormRecognizer' -Props ([PSCustomObject]@{ endpoint = 'https://fr-prod.cognitiveservices.azure.com/'; provisioningState = 'Succeeded' datecreated = '2025-05-05T09:00:00Z' sku = [PSCustomObject]@{ name = 'S0' } }) # Cognitive Search $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/srch/srch1' -Name 'srch-prod' ` -Type 'microsoft.search/searchservices' -Kind '' -Props ([PSCustomObject]@{ replicaCount = 1; partitionCount = 1; hostingMode = 'default'; provisioningState = 'Succeeded' sku = [PSCustomObject]@{ name = 'standard' } networkRuleSet = [PSCustomObject]@{ bypass = 'None' } }) # ML Workspace (generic) $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/mlws/mlws1' -Name 'mlws-prod' ` -Type 'microsoft.machinelearningservices/workspaces' -Kind 'Default' -Props ([PSCustomObject]@{ storageAccount = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.Storage/storageAccounts/saml01' keyVault = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.KeyVault/vaults/kvml01' applicationInsights = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.Insights/components/aiml01' containerRegistry = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.ContainerRegistry/registries/crml01' publicNetworkAccess = 'Enabled'; provisioningState = 'Succeeded' creationTime = '2025-03-01T10:00:00Z' managedNetwork = [PSCustomObject]@{ isolationMode = 'Disabled' } }) # AI Foundry Hub $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/mlws/hub1' -Name 'hub-prod' ` -Type 'microsoft.machinelearningservices/workspaces' -Kind 'Hub' -Props ([PSCustomObject]@{ storageAccount = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.Storage/storageAccounts/sahub01' keyVault = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.KeyVault/vaults/kvhub01' applicationInsights = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.Insights/components/aihub01' containerRegistry = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.ContainerRegistry/registries/crhub01' publicNetworkAccess = 'Enabled'; provisioningState = 'Succeeded' creationTime = '2025-04-15T09:00:00Z' }) # AI Foundry Project $script:MockResources += New-MockAIResource -Id '/sub/sub-00000001/mlws/proj1' -Name 'proj-chatapp' ` -Type 'microsoft.machinelearningservices/workspaces' -Kind 'Project' -Props ([PSCustomObject]@{ storageAccount = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.Storage/storageAccounts/saproj01' keyVault = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.KeyVault/vaults/kvproj01' applicationInsights = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.Insights/components/aiproj01' containerRegistry = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.ContainerRegistry/registries/crproj01' publicNetworkAccess = 'Enabled'; provisioningState = 'Succeeded' creationTime = '2025-05-20T11:00:00Z' hubResourceId = '/sub/sub-00000001/mlws/hub1' }) # Bot Service $script:MockResources += New-MockAIResource -Id '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/microsoft.botservice/botservices/bot-support' -Name 'bot-support' ` -Type 'microsoft.botservice/botservices' -Kind 'Bot' -Props ([PSCustomObject]@{ endpoint = 'https://bot-support.azurewebsites.net/api/messages'; msaAppId = 'app-id-001' provisioningState = 'Succeeded' sku = [PSCustomObject]@{ name = 'S1' } }) # --- New Cognitive Services mock resources --- $cogSvcBase = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/microsoft.cognitiveservices/accounts' $peMock = @([PSCustomObject]@{ id = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/Microsoft.Network/privateEndpoints/pe-cog' }) $cogProps = { param($kind) [PSCustomObject]@{ datecreated = '2025-06-15T10:00:00Z' endpoint = "https://$kind-prod.cognitiveservices.azure.com/" customsubdomainname = "$kind-prod" publicnetworkaccess = 'Enabled' ismigrated = $false networkacls = [PSCustomObject]@{ defaultaction = 'Allow'; iprules = @(); virtualnetworkrules = @() } privateendpointconnections = $peMock provisioningState = 'Succeeded' disableLocalAuth = $false apiProperties = [PSCustomObject]@{ TA4HResourceId = '/subscriptions/sub-00000001/resourceGroups/rg-ai/providers/microsoft.cognitiveservices/accounts/lang-prod' } } } # AppliedAIServices (uses KIND in appliedAIKinds array, including 'FormRecognizer') $aaiRes = New-MockAIResource -Id "$cogSvcBase/aai-prod" -Name 'aai-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'FormRecognizer' -Props (& $cogProps 'aai') $aaiRes | Add-Member -NotePropertyName 'sku' -NotePropertyValue ([PSCustomObject]@{ name = 'S0' }) -Force $script:MockResources += $aaiRes # AzureAI (Kind = AIServices) $aisvRes = New-MockAIResource -Id "$cogSvcBase/aisvc-prod" -Name 'aisvc-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'AIServices' -Props (& $cogProps 'aisvc') $aisvRes | Add-Member -NotePropertyName 'sku' -NotePropertyValue ([PSCustomObject]@{ name = 'S0' }) -Force $script:MockResources += $aisvRes # ContentModerator $cmRes = New-MockAIResource -Id "$cogSvcBase/cm-prod" -Name 'cm-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'ContentModerator' -Props (& $cogProps 'cm') $cmRes | Add-Member -NotePropertyName 'sku' -NotePropertyValue ([PSCustomObject]@{ name = 'S0' }) -Force $script:MockResources += $cmRes # CustomVision (Kind like 'CustomVision.*') $cvtRes = New-MockAIResource -Id "$cogSvcBase/cvtrain-prod" -Name 'cvtrain-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'CustomVision.Training' -Props (& $cogProps 'cvtrain') $cvtRes | Add-Member -NotePropertyName 'sku' -NotePropertyValue ([PSCustomObject]@{ name = 'S0' }) -Force $script:MockResources += $cvtRes # FaceAPI (Kind = Face) $faceRes = New-MockAIResource -Id "$cogSvcBase/face-prod" -Name 'face-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'Face' -Props (& $cogProps 'face') $faceRes | Add-Member -NotePropertyName 'sku' -NotePropertyValue ([PSCustomObject]@{ name = 'S0' }) -Force $script:MockResources += $faceRes # HealthInsights $hiRes = New-MockAIResource -Id "$cogSvcBase/hi-prod" -Name 'hi-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'HealthInsights' -Props (& $cogProps 'hi') $hiRes | Add-Member -NotePropertyName 'sku' -NotePropertyValue ([PSCustomObject]@{ name = 'S0' }) -Force $script:MockResources += $hiRes # ImmersiveReader $irRes = New-MockAIResource -Id "$cogSvcBase/ir-prod" -Name 'ir-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'ImmersiveReader' -Props (& $cogProps 'ir') $irRes | Add-Member -NotePropertyName 'sku' -NotePropertyValue ([PSCustomObject]@{ name = 'S0' }) -Force $script:MockResources += $irRes # Translator (Kind = TextTranslation) $trRes = New-MockAIResource -Id "$cogSvcBase/tr-prod" -Name 'tr-prod' ` -Type 'microsoft.cognitiveservices/accounts' -Kind 'TextTranslation' -Props (& $cogProps 'tr') $trRes | Add-Member -NotePropertyName 'sku' -NotePropertyValue ([PSCustomObject]@{ name = 'S0' }) -Force $script:MockResources += $trRes # --- Mock Invoke-AzRestMethod for ML/OpenAI/Search child modules --- function Invoke-AzRestMethod { param([string]$Path, [string]$Method = 'GET') $mockResponse = @{ value = @() } if ($Path -match '/computes\?') { $mockResponse = @{ value = @(@{ name = 'gpu-cluster'; properties = @{ computeType = 'AmlCompute'; vmSize = 'Standard_NC6'; scaleSettings = @{ minNodeCount = 0; maxNodeCount = 4 }; vmPriority = 'Dedicated'; provisioningState = 'Succeeded' } }) } } elseif ($Path -match '/data\?') { $mockResponse = @{ value = @(@{ name = 'train-data'; properties = @{ dataType = 'uri_file'; dataUri = 'azureml://datastores/default/data.csv'; description = 'Training data' }; systemData = @{ createdAt = '2025-06-01T10:00:00Z' } }) } } elseif ($Path -match '/data/[^/]+/versions') { $mockResponse = @{ value = @(@{ name = '1'; properties = @{ dataType = 'uri_file'; dataUri = 'azureml://datastores/default/data.csv'; description = 'v1' }; systemData = @{ createdAt = '2025-06-01T10:00:00Z' } }) } } elseif ($Path -match '/datastores\?') { $mockResponse = @{ value = @(@{ name = 'default'; properties = @{ datastoreType = 'AzureBlob'; accountName = 'saml01'; containerName = 'mldata'; isDefault = $true; credentials = @{ credentialsType = 'AccountKey' } } }) } } elseif ($Path -match '/onlineEndpoints\?|/batchEndpoints\?') { $mockResponse = @{ value = @(@{ name = 'ep-online'; properties = @{ authMode = 'Key'; scoringUri = 'https://ep-online.eastus.inference.ml.azure.com/score'; provisioningState = 'Succeeded' } }) } } elseif ($Path -match '/deployments\?') { $mockResponse = @{ value = @(@{ name = 'deploy1' }) } } elseif ($Path -match '/models\?') { $mockResponse = @{ value = @(@{ name = 'my-model'; properties = @{ flavors = @{ sklearn = @{}; python_function = @{} } }; systemData = @{ createdAt = '2025-06-01T10:00:00Z' } }) } } elseif ($Path -match '/models/[^/]+/versions') { $mockResponse = @{ value = @(@{ name = '1'; properties = @{ flavors = [PSCustomObject]@{ sklearn = @{} } }; systemData = @{ createdAt = '2025-06-01T10:00:00Z' } }) } } elseif ($Path -match '/jobs\?') { $mockResponse = @{ value = @(@{ name = 'pipeline-run-1'; properties = @{ displayName = 'training-pipeline'; status = 'Completed'; experimentName = 'exp1'; creationContext = @{ createdAt = '2025-06-01T10:00:00Z'; lastModifiedAt = '2025-06-01T12:00:00Z' }; settings = @{ defaultCompute = 'gpu-cluster' } } }) } } elseif ($Path -match 'cognitiveservices/accounts/.+/deployments\?') { $mockResponse = @{ value = @(@{ name = 'gpt-4'; properties = @{ model = @{ name = 'gpt-4'; version = '0613'; format = 'OpenAI' }; scaleSettings = @{ scaleType = 'Standard'; capacity = 10 }; dynamicThrottlingEnabled = $false; provisioningState = 'Succeeded' } }) } } elseif ($Path -match 'searchservices/.+/indexes\?') { $mockResponse = @{ value = @(@{ name = 'idx-main'; fields = @(@{name='id'},@{name='content'}); analyzers = @(); scoringProfiles = @(); suggesters = @(); corsOptions = @{ allowedOrigins = @('*') }; defaultScoringProfile = $null; '@odata.etag' = '"0x123"' }) } } [PSCustomObject]@{ Content = ($mockResponse | ConvertTo-Json -Depth 10); StatusCode = 200 } } } AfterAll { if (Test-Path $script:TempDir) { Remove-Item $script:TempDir -Recurse -Force } } # =================================================================== # TESTS # =================================================================== Describe 'AI Module Files Exist' { It 'AI module folder exists' { $script:AIPath | Should -Exist } It '<Name> module file exists' -ForEach $AIModules { Join-Path $script:AIPath $File | Should -Exist } } Describe 'AI Module Processing Phase — <Name>' -ForEach $AIModules { BeforeAll { $script:ModFile = Join-Path $script:AIPath $File $script:ResType = $Type $script:ResKind = $Kind } It 'Processing returns results for matching resources' { $matchedResources = $script:MockResources | Where-Object { $_.TYPE -eq $script:ResType -and ($script:ResKind -eq '' -or $_.KIND -eq $script:ResKind) } if ($matchedResources) { $content = Get-Content -Path $script:ModFile -Raw $sb = [ScriptBlock]::Create($content) $result = Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $script:MockResources, $null, 'Processing', $null, $null, 'Light20', $null $result | Should -Not -BeNullOrEmpty } else { Set-ItResult -Skipped -Because "No mock resource of type '$script:ResType' / kind '$script:ResKind'" } } It 'Processing does not throw when given an empty resource list' { $content = Get-Content -Path $script:ModFile -Raw $sb = [ScriptBlock]::Create($content) { Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, @(), $null, 'Processing', $null, $null, 'Light20', $null } | Should -Not -Throw } } Describe 'AI Module Reporting Phase — <Name>' -ForEach $AIModules { BeforeAll { $script:ModFile = Join-Path $script:AIPath $File $script:ResType = $Type $script:ResKind = $Kind $script:WsName = $Worksheet $script:XlsxFile = Join-Path $script:TempDir ("AI_{0}_{1}.xlsx" -f $Name, [System.IO.Path]::GetRandomFileName()) $matchedResources = $script:MockResources | Where-Object { $_.TYPE -eq $script:ResType -and ($script:ResKind -eq '' -or $_.KIND -eq $script:ResKind) } if ($matchedResources) { $content = Get-Content -Path $script:ModFile -Raw $sb = [ScriptBlock]::Create($content) $script:ProcessedData = Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $script:MockResources, $null, 'Processing', $null, $null, 'Light20', $null } else { $script:ProcessedData = $null } } It 'Reporting phase does not throw' { if ($script:ProcessedData) { $content = Get-Content -Path $script:ModFile -Raw $sb = [ScriptBlock]::Create($content) { Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $null, $null, 'Reporting', $script:XlsxFile, $script:ProcessedData, 'Light20', $null } | Should -Not -Throw } else { Set-ItResult -Skipped -Because "No mock resource of type '$script:ResType' / kind '$script:ResKind'" } } It 'Excel file is created' { if ($script:ProcessedData) { $script:XlsxFile | Should -Exist } else { Set-ItResult -Skipped -Because "No mock resource of type '$script:ResType' / kind '$script:ResKind'" } } } Describe 'AI Foundry Hub/Project Kind Detection' { It 'AIFoundryHubs only processes Kind=Hub workspaces' { $modFile = Join-Path $script:AIPath 'AIFoundryHubs.ps1' $content = Get-Content -Path $modFile -Raw $sb = [ScriptBlock]::Create($content) $result = Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $script:MockResources, $null, 'Processing', $null, $null, 'Light20', $null # Should only have the hub, not the project or generic workspace if ($result) { $result | Where-Object { $_ -is [System.Collections.Hashtable] } | ForEach-Object { # Hub results shouldn't contain the project name $_['Name'] | Should -Not -Be 'proj-chatapp' } } } It 'AIFoundryProjects only processes Kind=Project workspaces' { $modFile = Join-Path $script:AIPath 'AIFoundryProjects.ps1' $content = Get-Content -Path $modFile -Raw $sb = [ScriptBlock]::Create($content) $result = Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $script:MockResources, $null, 'Processing', $null, $null, 'Light20', $null $result | Should -Not -BeNullOrEmpty } } Describe 'OpenAI Kind Filtering' { It 'OpenAIAccounts only extracts Kind=OpenAI cognitive services accounts' { $modFile = Join-Path $script:AIPath 'OpenAIAccounts.ps1' $content = Get-Content -Path $modFile -Raw $sb = [ScriptBlock]::Create($content) $result = Invoke-Command -ScriptBlock $sb -ArgumentList $null, $null, $null, $script:MockResources, $null, 'Processing', $null, $null, 'Light20', $null $result | Should -Not -BeNullOrEmpty # Should produce exactly 1 row (only oai-prod has Kind=OpenAI) @($result).Count | Should -Be 1 } } |