Fixed Test-Modulemanifest to normalize paths correctly before validating#3097
Fixed Test-Modulemanifest to normalize paths correctly before validating#3097lzybkr merged 8 commits intoPowerShell:masterfrom
Conversation
changed hard coded Windows directory separator and resolved path so the slashes are correct added test
| "" > testdrive:/module/foo/bar.psm1 | ||
| "" > testdrive:/module/bar/foo.psm1 | ||
| New-ModuleManifest -NestedModules foo\bar.psm1,bar/foo.psm1 -RootModule foo\bar.psm1 -RequiredAssemblies foo/bar.psm1,bar\foo.psm1 -Path testdrive:/module/test.psd1 | ||
| Test-ModuleManifest -Path testdrive:/module/test.psd1 -ErrorAction Stop | Should BeOfType System.Management.Automation.PSModuleInfo |
There was a problem hiding this comment.
Do you want some additional validation on the paths, maybe a Test-Path on the NestedModules, RootModule, and RequiredAssemblies.
There are other module properties that specify files, maybe you should be testing those too - TypesToProcess, FormatsToProcess, ScriptsToProcess, maybe FileList and ModuleList?
I wonder if it's a bad idea to specify RequiredAssemblies without a valid assembly - if that's not already causing problems, I can see it causing problems in the future.
There was a problem hiding this comment.
The semantics of test-modulemanifest seems to only verify existence of files and not if they are valid. Rather than verify the files exist and being validated, I'm adding a negative test where test-modulemanifest should fail if any paths don't exist
| CmdletProviderContext cmdContext = new CmdletProviderContext(this); | ||
| Collection<PathInfo> pathInfos = SessionState.Path.GetResolvedPSPathFromPSPath(path, cmdContext); | ||
|
|
||
| foreach (PathInfo pathInfo in pathInfos) |
There was a problem hiding this comment.
If you resolve to multiple files, shouldn't that be an error instead of just ignoring it?
There was a problem hiding this comment.
@lzybkr Since wildcards are explicitly being checked and not allowed in the module manifest, is a Debug.Assert sufficient?
There was a problem hiding this comment.
looking at other code in this file, decided to throw
There was a problem hiding this comment.
Possible downside here is I'm adding blocks that can't be hit
added negative test cases that do file path checks
SteveL-MSFT
left a comment
There was a problem hiding this comment.
@lzybkr are you ok with the updated changes?
| New-Item -ItemType Directory -Path testdrive:/module/foo | ||
| New-Item -ItemType Directory -Path testdrive:/module/bar | ||
| "" > testdrive:/module/foo/bar.psm1 | ||
| "" > testdrive:/module/bar/foo.psm1 |
There was a problem hiding this comment.
Maybe better use Set-Content ? This is more clearly.
|
|
||
| Test-Path $testModulePath | Should Be $true | ||
|
|
||
| Test-ModuleManifest -Path $testModulePath -ErrorAction Stop | Should BeOfType System.Management.Automation.PSModuleInfo |
There was a problem hiding this comment.
Why we use -ErrorAction Stop ? It is not a "throw" test. Better -ErrorAction SilentlyContinue.
There was a problem hiding this comment.
I used ErrorAction Stop here since Test-ModuleManifest writes to the error stream on manifest errors and I thought this was an easy way to ensure no errors being returned. Otherwise I think I'd have to redirect the error stream and check it and I don't think that's providing additional value. I can add a comment to clarify my intent.
|
|
||
| New-Item -ItemType Directory -Path testdrive:/module | ||
| New-Item -ItemType Directory -Path testdrive:/module/foo | ||
| "" > testdrive:/module/foo/bar.psm1 |
There was a problem hiding this comment.
The same about Set-Content
| "RootModule"="Modules_InvalidManifest"; | ||
| "ScriptsToProcess"="Modules_InvalidManifest" | ||
| } | ||
| foreach ($parameter in $parametersAndExecptions.Keys) { |
There was a problem hiding this comment.
Typo "parametersAndExecptions" <- "parametersAndErrors"
| } | ||
| catch { | ||
| $_.FullQulaifiedErrorId | Should Match "$errorId" | ||
| } |
There was a problem hiding this comment.
Why Should BeOfType System.Management.Automation.PSModuleInfo ? If we expect that Test-ModuleManifest raise an exception in the tests the Should BeOfType will be never run.
I suggest using the excellent function ShouldBeErrorId
(I have already prepared new PR #3161 to move existing tests to this pattern)
The new look of this test:
{ Test-ModuleManifest -Path $testModulePath -ErrorAction Stop } | ShouldBeErrorId $errorIdOnly insert:
Import-Module $PSScriptRoot\..\..\Common\Test.Helpers.psm1There was a problem hiding this comment.
Cool! will make this change
| Describe "Test-ModuleManifest tests" -tags "CI" { | ||
|
|
||
| AfterEach { | ||
| if (Test-Path testdrive:/module) { |
There was a problem hiding this comment.
It looks as unneeded check: Remove-Item implicitly do the check.
|
@iSazonov thanks for the feedback, I'll take care of these after I get back from vacation on 2/21 |
|
@SteveL-MSFT I don't see new commit related with your last comments. |
… readable fixed typo in test that exposed issue in cmdlet for validating nestedmodules
|
@iSazonov took longer than I expected, after I fixed the typo, I found a issue with the cmdlet |
| "TypesToProcess"="Modules_InvalidManifest"; | ||
| "FormatsToProcess"="Modules_InvalidManifest"; | ||
| "RootModule"="Modules_InvalidManifest"; | ||
| #"RootModule"="Modules_InvalidManifest"; |
There was a problem hiding this comment.
Should be uncommented. Looks like the cmdlets doesn't do any validation of RootModule currently, will need to add that code.
| } | ||
| foreach ($parameter in $parametersAndExecptions.Keys) { | ||
| foreach ($parameter in $parametersAndErrors.Keys) { | ||
| Write-Warning "Testing $parameter" |
There was a problem hiding this comment.
Not sure what the best practice is here. When doing the test in a loop and something fails, the current error from Pester isn't sufficient to tell you where it failed. @JamesWTruher suggestions?
There was a problem hiding this comment.
I suppose we should use TestCases
| [string]$errorId = $parametersAndErrors[$parameter] + ",Microsoft.PowerShell.Commands.TestModuleManifestCommand" | ||
|
|
||
| { Test-ModuleManifest -Path $testModulePath -ErrorAction Stop } | ShouldBeErrorId $errorId | ||
| Remove-Item -Recurse -Force $testModulePath |
There was a problem hiding this comment.
Remove? It seems AfterEach does cleanups.
There was a problem hiding this comment.
This is needed as I'm generating a new invalid manifest each iteration of the loop
used TestCases feature of Pester for tests added tests for valid and invalid rootmodules
| "ScriptsToProcess"="Modules_InvalidManifest" | ||
| $args = @{$parameter = "doesnotexist.psm1"} | ||
| New-ModuleManifest -Path $testModulePath @args | ||
| Test-Path $testModulePath | Should Be $true |
There was a problem hiding this comment.
Below ShouldBeErrorId still catches this error. Maybe remove the line?
There was a problem hiding this comment.
Yeah, this isn't needed, originally I thought to check that the manifest was actually created, but it would fail later. Will remove.
| New-Item -ItemType Directory -Path testdrive:/module | ||
| $testModulePath = "testdrive:/module/test.psd1" | ||
|
|
||
| if ($rootModuleValue -ne $null -and $rootModuleValue -ne "") |
There was a problem hiding this comment.
It seems it is better to us to split the tests into two and remove the conditions.
There was a problem hiding this comment.
Was perhaps over optimizing on code reuse. I'll split it to make it more readable.
| { Test-ModuleManifest -Path $testModulePath -ErrorAction Stop } | ShouldBeErrorId $errorId | ||
| Remove-Item -Recurse -Force $testModulePath | ||
| New-ModuleManifest -Path $testModulePath -RootModule $rootModuleValue | ||
| Test-Path $testModulePath | Should Be $true |
| New-Item -ItemType Directory -Path testdrive:/module | ||
| $testModulePath = "testdrive:/module/test.psd1" | ||
|
|
||
| if ($rootModuleValue -ne "doesnotexist.psm1") |
There was a problem hiding this comment.
It seems it is better to us to split the tests into two and remove the conditions.
There was a problem hiding this comment.
I'm ok with splitting
| New-Item -ItemType File -Path testdrive:/module/$rootModuleValue | ||
| } | ||
| New-ModuleManifest -Path $testModulePath -RootModule $rootModuleValue | ||
| Test-Path $testModulePath | Should Be $true |
…r manifest creation
|
I see multiple So the tests LGTM. |
| } | ||
| } | ||
|
|
||
| //RootModule can be null, empty string or point to a valid .psm1, or .dll. Anything else is invalid. |
There was a problem hiding this comment.
cdxml and xaml modules are allowed in RootModule just as they are allowed in NestedModules.
There was a problem hiding this comment.
Also, when comparing extensions, is ignoring the case correct for non-Windows?
There was a problem hiding this comment.
This file contains OrdinalIgnoreCase 4 times. But I see lots of other files to ignore the case when dealing with paths.
There was a problem hiding this comment.
Yes, case insensitive comparisons on executable extensions could be a bigger issue than just this file.
There was a problem hiding this comment.
I think the extension comparison issue should probably be a separate issue so we can apply same fix everywhere
There was a problem hiding this comment.
I agree. We don't even have the desired method. Perhaps even better, make a request in .Net.
There was a problem hiding this comment.
In testing a fix for cdxml/XAML modules, I see that you get this error message for InvalidModuleManifest which just seems wrong:
<value>The module manifest '{0}' could not be processed because it is not a valid Windows PowerShell restricted language file. Remove the elements that are not permitted by the restricted language: {1}</value>I'd like to change it to something like:
The module manifest '{0}' could not be processed because it is not a valid PowerShell module manifest file. Remove the elements that are not permitted: {1}
added tests updated InvalidModuleManifest error message to be about module manifests
| Test-ModuleManifest -Path $testModulePath -ErrorAction Stop | Should BeOfType System.Management.Automation.PSModuleInfo | ||
| } | ||
|
|
||
| It "module manifest containing missing files returns error" -TestCases ` |
There was a problem hiding this comment.
Typical use of -TestCases is to introduce a variable - that is probably easier to read.
If there is a good reason to inline the argument - you should prefer parens instead of a backtick.
Extra indentation on the test cases might also make it more readable, so maybe format like:
It "should work" -TestCases (
@{rootModuleValue = "bar.psm1"},
@{rootModuleValue = "bar.dll"}
) {
param($rootModuleValue)
}added tests updated InvalidModuleManifest error message to be about module manifests changed -TestCases usage to parens than backtick for readability
…to modulemanifest
|
Closing and re-opening to retry blocked CI. |
changed hard coded Windows directory separator and resolved path so the slashes are correct
added test
addresses #2610