-
-
Save gerron/835e0a082aa4bd630ae91b5eab383e1e to your computer and use it in GitHub Desktop.
#Function | |
#Get-Token and Get-PlainTextFromSecureString are private functions within the module | |
function Get-Projects | |
{ | |
[CmdletBinding()] | |
[OutputType([Object[]])] | |
param ( | |
[Parameter(Mandatory = $false)] | |
[PSCredential]$Credential | |
) | |
Begin | |
{ | |
$ErrorActionPreference = "Stop" | |
if(-not ($PSBoundParameters.ContainsKey("Credential"))) | |
{ | |
$Credential = Get-Credential | |
} | |
$token = Get-Token $Credential | |
} | |
Process | |
{ | |
$headers = @{ | |
'Authorization' = ("Bearer{0}" -f $token) | |
'Content-Type' = 'application/json;v=1.0' | |
} | |
$results = Invoke-RestMethod -uri 'https://internalEndpoint.domain.corp/internalsoftware/projects' -Method GET -Headers $headers | |
if(-not ($results.count -gt 0)) | |
{ | |
throw "There was an error retrieving a Projects. Projects returned are empty." | |
} | |
$results | |
} | |
End | |
{ | |
} | |
} | |
#Pester Test | |
#ModuleArtifact is the path to the IntermnModule file | |
Import-Module $ModuleArtifact -Verbose -Force | |
Describe "Get-Projects" { | |
InModuleScope InternalModule { | |
Mock Get-PlaintextFromSecureString {} | |
Context "when not passing in a credential" { | |
$password = ConvertTo-SecureString "Test1234!" -AsPlainText -Force | |
$credential = New-Object System.Management.Automation.PSCredential ('TestUser', $password) | |
Mock Get-Credential { $credential } | |
Mock Invoke-RestMethod {} | |
Mock Get-Token { "token" } | |
It "Get-Credential is called prompting for a password" { | |
GetProjects | |
Assert-MockCalled Get-Credential -Exactly 1 | |
Assert-MockCalled Get-PlaintextFromSecureString -Exactly 1 -ParameterFilter { $SecurePassword -eq $credential.password } | |
} | |
} | |
Context "when passing in a credential" { | |
$password = ConvertTo-SecureString "Test1234!" -AsPlainText -Force | |
$credential = New-Object System.Management.Automation.PSCredential ('TestUser', $password) | |
$nonEmptyArray = @(1,2,3,4) | |
Mock Invoke-RestMethod { $nonEmptyArray } | |
Mock Get-Token { "token" } | |
It "Get-Credential is not called prompting for a username and password" { | |
GetProjects -Credential $credential | |
Assert-MockCalled Get-Credential 0 | |
} | |
} | |
Context "when Invoke-RestMethod returns an empty empty array of projects" { | |
$password = ConvertTo-SecureString "Test1234!" -AsPlainText -Force | |
$credential = New-Object System.Management.Automation.PSCredential ('TestUser', $password) | |
Mock Get-Token { "token" } | |
It "GetProjects throws an exception" { | |
$emptyArray = @() | |
Mock Invoke-RestMethod { $emptyArray } | |
{ GetProjects -Credential $credential } | Should Throw "There was an error retrieving a Projects. Projects are empty." | |
Assert-MockCalled Invoke-RestMethod -Exactly 1 | |
} | |
} | |
} | |
} |
The one other thing I can think of. I notice you have a Import-Module "path to module".
Probably unrelated to your issue, but I had problems with this is the past. Had to tidy up my module definitions and packaging slightly so that I no longer had to import via a path to the psm1 file. So for example, all my deployments look like this:
$env:PSModulePath =
$env:PSModulePath + ";$ ($(Get-Location).Path)"
Import-Module Pivot.DockerAdmin
You probably know this stuff, but tripped me for a while. From my notes...
- Make sure your code is packaged properly^ (note: dir name same as module and manifest, then you import from level-up that includes this manifest parent directory)
- Include this folder in the PSModule path:
- Either by dropping it in one of the persistent paths.
- Or adding the path to it for the session**
- Now just use "Import-Module Hue.Script" rather than "Import-Module .\Hue.Script.psm1"
- If you don't do this, the manifest isn't considered at all.
- Make sure your manifest has the correct info - it's of critical importance now***
- E.g. include helper functions through NestedModules
- Include other files e.g. Const.psd1. Then can use within module like:
- $Const = Get-Content "$PSScriptRoot\Const.psd1" | Out-String | Invoke-Expression
- [or powershell 5+] >$Const = Import-PowerShellDataFile "$PSScriptRoot\Const.psd1"
^use this folder structure
root
--Hue.Script
----Hue.Script.psm1
----Hue.Script.psd1
----Nested.Module.psm1
You mention you tried the Mock verbatim with what's working my side. Also you're on a more recent version of pester. So only two things I can think of trying.
1. Move Get-Credential out of Begin { .. } and into Process { .. }
I know it's not what you want, but worth a try. If it makes the difference then could consider some kind of a wrapper to avoid many calls to Get-Credential.
1. If it's not Pester that's the problem, then how about the version of Powershell. Maybe Get-Credential implementation changed at some stage.
Tried moving into process block and same result. I'm using Powershell version 5.1 and may try experimenting with a different version. I'm even considering removing the get-credential call all together.
I'll keep experimenting and provide any updates here for future reference. I'll have to timebox this though for just today :/.
Thanks again!
The one other thing I can think of. I notice you have a Import-Module "path to module".
Probably unrelated to your issue, but I had problems with this is the past. Had to tidy up my module definitions and packaging slightly so that I no longer had to import via a path to the psm1 file. So for example, all my deployments look like this:$env:PSModulePath =
$env:PSModulePath + ";$ ($(Get-Location).Path)"
Import-Module Pivot.DockerAdminYou probably know this stuff, but tripped me for a while. From my notes...
1. Make sure your code is packaged properly^ (note: dir name same as module and manifest, then you import from level-up that includes this manifest parent directory) 2. Include this folder in the PSModule path: 1. Either by dropping it in one of the persistent paths. 2. Or adding the path to it for the session** 3. Now just use "Import-Module Hue.Script" rather than "Import-Module .\Hue.Script.psm1" 1. If you don't do this, the manifest isn't considered at all. 4. Make sure your manifest has the correct info - it's of critical importance now*** 1. E.g. include helper functions through NestedModules 2. Include other files e.g. Const.psd1. Then can use within module like: 1. $Const = Get-Content "$PSScriptRoot\Const.psd1" | Out-String | Invoke-Expression 2. [or powershell 5+] >$Const = Import-PowerShellDataFile "$PSScriptRoot\Const.psd1"
^use this folder structure
root
--Hue.Script----Hue.Script.psm1
----Hue.Script.psd1
----Nested.Module.psm1
Noted thanks!
@cathalmchale I ended up making the credential object a mandatory parameter which accomplishes the same goal. If I call my function without specifying a credential parameter, it prompts me using get-credential. I didn't need the logic around calling get-credential at all.
You mention you tried the Mock verbatim with what's working my side. Also you're on a more recent version of pester. So only two things I can think of trying.
I know it's not what you want, but worth a try. If it makes the difference then could consider some kind of a wrapper to avoid many calls to Get-Credential.