-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Fixed Test-Modulemanifest to normalize paths correctly before validating #3097
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you resolve to multiple files, shouldn't that be an error instead of just ignoring it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking at other code in this file, decided to throw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible downside here is I'm adding blocks that can't be hit
added negative test cases that do file path checks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe better use Set-Content
? This is more clearly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closed.
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why we use -ErrorAction Stop
? It is not a "throw" test. Better -ErrorAction SilentlyContinue
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clear.
Closed.
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same about Set-Content
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closed.
"RootModule"="Modules_InvalidManifest"; | ||
"ScriptsToProcess"="Modules_InvalidManifest" | ||
} | ||
foreach ($parameter in $parametersAndExecptions.Keys) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo "parametersAndExecptions" <- "parametersAndErrors"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closed.
} | ||
catch { | ||
$_.FullQulaifiedErrorId | Should Match "$errorId" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 $errorId
Only insert:
Import-Module $PSScriptRoot\..\..\Common\Test.Helpers.psm1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! will make this change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closed.
Describe "Test-ModuleManifest tests" -tags "CI" { | ||
|
||
AfterEach { | ||
if (Test-Path testdrive:/module) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks as unneeded check: Remove-Item
implicitly do the check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closed.
@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 |
@@ -37,22 +38,17 @@ Describe "Test-ModuleManifest tests" -tags "CI" { | |||
"ModuleList"="Modules_InvalidModuleListinModuleManifest"; | |||
"TypesToProcess"="Modules_InvalidManifest"; | |||
"FormatsToProcess"="Modules_InvalidManifest"; | |||
"RootModule"="Modules_InvalidManifest"; | |||
#"RootModule"="Modules_InvalidManifest"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe remove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be uncommented. Looks like the cmdlets doesn't do any validation of RootModule currently, will need to add that code.
"ScriptsToProcess"="Modules_InvalidManifest" | ||
} | ||
foreach ($parameter in $parametersAndExecptions.Keys) { | ||
foreach ($parameter in $parametersAndErrors.Keys) { | ||
Write-Warning "Testing $parameter" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose we should use TestCases
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool!
} | ||
[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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove? It seems AfterEach
does cleanups.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Below ShouldBeErrorId
still catches this error. Maybe remove the line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems it is better to us to split the tests into two and remove the conditions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe remove too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree
New-Item -ItemType Directory -Path testdrive:/module | ||
$testModulePath = "testdrive:/module/test.psd1" | ||
|
||
if ($rootModuleValue -ne "doesnotexist.psm1") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems it is better to us to split the tests into two and remove the conditions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe remove too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree
…r manifest creation
I see multiple So the tests LGTM. |
@@ -131,6 +131,22 @@ protected override void ProcessRecord() | |||
} | |||
} | |||
|
|||
//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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cdxml
and xaml
modules are allowed in RootModule
just as they are allowed in NestedModules
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, when comparing extensions, is ignoring the case correct for non-Windows?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, case insensitive comparisons on executable extensions could be a bigger issue than just this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created issue #3218
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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: |
<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}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lzybkr addressed
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will change
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