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
2 changes: 1 addition & 1 deletion build/Build-MaesterModule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ $__MtSession = @{
ExoCache = @{}
OrcaCache = @{}
AIAgentInfo = $null
AzureDevOpsConnection = $null
AzureDevOpsConnectionCache = $null
DataverseApiBase = $null # Resolved Dataverse OData API base URL (e.g. https://org123.api.crm.dynamics.com/api/data/v9.2)
DataverseResourceUrl = $null # Dataverse resource URL for token acquisition (e.g. https://org123.crm.dynamics.com)
DataverseEnvironmentId = $null # Environment identifier for display (e.g. org123.crm.dynamics.com)
Expand Down
1 change: 1 addition & 0 deletions powershell/Maester.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ $__MtSession = @{
ExoCache = @{}
OrcaCache = @{}
AIAgentInfo = $null
AzureDevOpsConnectionCache = $null
DataverseApiBase = $null # Resolved Dataverse OData API base URL (e.g. https://org123.api.crm.dynamics.com/api/data/v9.2)
DataverseResourceUrl = $null # Dataverse resource URL for token acquisition (e.g. https://org123.crm.dynamics.com)
DataverseEnvironmentId = $null # Environment identifier for display (e.g. org123.crm.dynamics.com)
Expand Down
2 changes: 1 addition & 1 deletion powershell/internal/Clear-ModuleVariable.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
Clear-MtDnsCache
Clear-MtExoCache
$__MtSession.AIAgentInfo = $null
$__MtSession.AzureDevOpsConnection = $null
$__MtSession.AzureDevOpsConnectionCache = $null
# Invoke-Maester resets the per-run cache but preserves the existing GitHub session.
# Disconnect-MtGitHub, including through Disconnect-Maester, owns clearing GitHubConnection and GitHubAuthHeader.
$__MtSession.GitHubCache = @{}
Expand Down
10 changes: 5 additions & 5 deletions powershell/public/core/Test-MtConnection.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,12 @@
#region AzureDevOps
if ($Service -contains 'AzureDevOps' -or $Service -contains 'All') {
$IsConnected = $false
if ($null -ne $__MtSession.AzureDevOpsConnection) {
if ($null -ne $__MtSession.AzureDevOpsConnectionCache) {
# Use cached probe result to avoid re-running the connection check on every test.
if ($__MtSession.AzureDevOpsConnection -is [string] -and $__MtSession.AzureDevOpsConnection -eq 'NotConnected') {
if ($__MtSession.AzureDevOpsConnectionCache -is [string] -and $__MtSession.AzureDevOpsConnectionCache -eq 'NotConnected') {
$IsConnected = $false
} else {
$MtConnections.AzureDevOps = $__MtSession.AzureDevOpsConnection
$MtConnections.AzureDevOps = $__MtSession.AzureDevOpsConnectionCache
$IsConnected = $true
}
} else {
Expand All @@ -188,7 +188,7 @@
$connection = Get-ADOPSConnection
if ($null -ne $connection -and $null -ne $connection['Organization']) {
$MtConnections.AzureDevOps = $connection
$__MtSession.AzureDevOpsConnection = $connection
$__MtSession.AzureDevOpsConnectionCache = $connection
$IsConnected = $true
}
}
Expand All @@ -197,7 +197,7 @@
}
if (-not $IsConnected) {
# Cache negative result so subsequent calls skip the probe.
$__MtSession.AzureDevOpsConnection = 'NotConnected'
$__MtSession.AzureDevOpsConnectionCache = 'NotConnected'
}
Comment thread
SamErde marked this conversation as resolved.
}
Write-Verbose "AzureDevOps: $IsConnected"
Expand Down
79 changes: 74 additions & 5 deletions powershell/tests/functions/Test-MtConnection.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ Describe 'Test-MtConnection — GitHub service' {
BeforeEach {
InModuleScope Maester {
$__MtSession.GitHubConnection = $null
$__MtSession.AzureDevOpsConnection = $null
$__MtSession.AzureDevOpsConnectionCache = $null
}
}

AfterEach {
InModuleScope Maester {
$__MtSession.GitHubConnection = $null
$__MtSession.AzureDevOpsConnection = $null
$__MtSession.AzureDevOpsConnectionCache = $null
}
}

Expand Down Expand Up @@ -112,7 +112,7 @@ Describe 'Test-MtConnection — GitHub service' {
It 'Returns AllConnected $true when all included services are connected and GitHub session is absent' {
InModuleScope Maester {
$__MtSession.GitHubConnection = $null
$__MtSession.AzureDevOpsConnection = [PSCustomObject]@{ Organization = 'ado-org' }
$__MtSession.AzureDevOpsConnectionCache = [PSCustomObject]@{ Organization = 'ado-org' }
}
Mock Get-AzContext { [PSCustomObject]@{ Account = 'test@contoso.com' } } -ModuleName Maester
Mock Invoke-AzRestMethod { [PSCustomObject]@{} } -ModuleName Maester
Expand All @@ -138,7 +138,7 @@ Describe 'Test-MtConnection — GitHub service' {
It 'does not set the GitHub details property' {
InModuleScope Maester {
$__MtSession.GitHubConnection = [PSCustomObject]@{ Connected = $false; FailureReason = 'NotCalled' }
$__MtSession.AzureDevOpsConnection = 'NotConnected'
$__MtSession.AzureDevOpsConnectionCache = 'NotConnected'
}
Mock Get-AzContext { $null } -ModuleName Maester
Mock Get-MgContext { $null } -ModuleName Maester
Expand Down Expand Up @@ -183,7 +183,7 @@ Describe 'Test-MtConnection — GitHub service' {
It 'Does not populate the GitHub property' {
InModuleScope Maester {
$__MtSession.GitHubConnection = [PSCustomObject]@{ Connected = $true; Organization = 'myorg' }
$__MtSession.AzureDevOpsConnection = 'NotConnected'
$__MtSession.AzureDevOpsConnectionCache = 'NotConnected'
}
Mock Get-AzContext { $null } -ModuleName Maester
Mock Get-MgContext { $null } -ModuleName Maester
Expand All @@ -194,3 +194,72 @@ Describe 'Test-MtConnection — GitHub service' {
}
}
}

Describe 'Test-MtConnection AzureDevOps cache' {
BeforeEach {
InModuleScope Maester {
$__MtSession.AzureDevOpsConnectionCache = $null
$__MtSession.Remove('AzureDevOpsConnection')
}
}

AfterEach {
InModuleScope Maester {
Remove-Item -Path function:Get-ADOPSConnection -ErrorAction SilentlyContinue
$__MtSession.AzureDevOpsConnectionCache = $null
$__MtSession.Remove('AzureDevOpsConnection')
}
}

It 'caches a successful Azure DevOps probe under a cache-specific key' {
$result = InModuleScope Maester {
New-Item -Path function:Get-ADOPSConnection -Value { @{ Organization = 'ado-org' } } -Force | Out-Null
Test-MtConnection -Service AzureDevOps -Details
}

$result.AllConnected | Should -BeTrue
$result.AzureDevOps['Organization'] | Should -Be 'ado-org'
InModuleScope Maester {
$__MtSession.AzureDevOpsConnectionCache['Organization'] | Should -Be 'ado-org'
$__MtSession.ContainsKey('AzureDevOpsConnection') | Should -BeFalse
}
}

It 'caches a failed Azure DevOps probe as NotConnected' {
$result = InModuleScope Maester {
New-Item -Path function:Get-ADOPSConnection -Value { $null } -Force | Out-Null
Test-MtConnection -Service AzureDevOps -Details
}

$result.AllConnected | Should -BeFalse
$result.AzureDevOps | Should -BeNullOrEmpty
InModuleScope Maester {
$__MtSession.AzureDevOpsConnectionCache | Should -Be 'NotConnected'
$__MtSession.ContainsKey('AzureDevOpsConnection') | Should -BeFalse
}
}

It 'uses the cached Azure DevOps probe result without re-querying the external command' {
InModuleScope Maester {
$__MtSession.AzureDevOpsConnectionCache = @{ Organization = 'cached-org' }
}
$result = InModuleScope Maester {
New-Item -Path function:Get-ADOPSConnection -Value { throw 'Get-ADOPSConnection should not be called when cache exists.' } -Force | Out-Null
Test-MtConnection -Service AzureDevOps -Details
}

$result.AllConnected | Should -BeTrue
$result.AzureDevOps['Organization'] | Should -Be 'cached-org'
}

It 'clears the Azure DevOps probe cache during module-variable reset' {
InModuleScope Maester {
$__MtSession.AzureDevOpsConnectionCache = @{ Organization = 'cached-org' }

Clear-ModuleVariable

$__MtSession.AzureDevOpsConnectionCache | Should -BeNullOrEmpty
$__MtSession.ContainsKey('AzureDevOpsConnection') | Should -BeFalse
}
}
}
Loading