Skip to content

Fixed Test-Modulemanifest to normalize paths correctly before validating - #3097

Merged
Jason Shirk (lzybkr) merged 8 commits into
PowerShell:masterfrom
SteveL-MSFT:modulemanifest
Mar 1, 2017
Merged

Fixed Test-Modulemanifest to normalize paths correctly before validating#3097
Jason Shirk (lzybkr) merged 8 commits into
PowerShell:masterfrom
SteveL-MSFT:modulemanifest

Conversation

@SteveL-MSFT

Copy link
Copy Markdown
Member

changed hard coded Windows directory separator and resolved path so the slashes are correct
added test
addresses #2610

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

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Member Author

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)

Copy link
Copy Markdown
Contributor

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?

@SteveL-MSFT Steve Lee (SteveL-MSFT) Feb 7, 2017

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jason Shirk (@lzybkr) Since wildcards are explicitly being checked and not allowed in the module manifest, is a Debug.Assert sufficient?

Copy link
Copy Markdown
Member Author

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

Copy link
Copy Markdown
Member Author

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

@SteveL-MSFT Steve Lee (SteveL-MSFT) left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jason Shirk (@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

Copy link
Copy Markdown
Collaborator

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Fixed.

Copy link
Copy Markdown
Collaborator

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

Copy link
Copy Markdown
Collaborator

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.

Copy link
Copy Markdown
Member Author

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.

Copy link
Copy Markdown
Collaborator

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

Copy link
Copy Markdown
Collaborator

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Copy Markdown
Collaborator

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) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo "parametersAndExecptions" <- "parametersAndErrors"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch

Copy link
Copy Markdown
Collaborator

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"
}

@iSazonov Ilya (iSazonov) Feb 15, 2017

Copy link
Copy Markdown
Collaborator

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

Copy link
Copy Markdown
Member Author

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

Copy link
Copy Markdown
Collaborator

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) {

Copy link
Copy Markdown
Collaborator

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closed.

@SteveL-MSFT

Copy link
Copy Markdown
Member Author

Ilya (@iSazonov) thanks for the feedback, I'll take care of these after I get back from vacation on 2/21

@lzybkr Jason Shirk (lzybkr) self-assigned this Feb 16, 2017
@iSazonov

Copy link
Copy Markdown
Collaborator

Steve Lee (@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
@SteveL-MSFT

Copy link
Copy Markdown
Member Author

Ilya (@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";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe remove it?

Copy link
Copy Markdown
Member Author

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.

}
foreach ($parameter in $parametersAndExecptions.Keys) {
foreach ($parameter in $parametersAndErrors.Keys) {
Write-Warning "Testing $parameter"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove?

Copy link
Copy Markdown
Member Author

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. James Truher (@JamesWTruher) suggestions?

Copy link
Copy Markdown
Collaborator

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

Copy link
Copy Markdown
Member Author

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

Copy link
Copy Markdown
Collaborator

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.

Copy link
Copy Markdown
Member Author

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

Copy link
Copy Markdown
Collaborator

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?

Copy link
Copy Markdown
Member Author

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 "")

Copy link
Copy Markdown
Collaborator

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.

Copy link
Copy Markdown
Member Author

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe remove too?

Copy link
Copy Markdown
Member Author

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")

Copy link
Copy Markdown
Collaborator

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.

Copy link
Copy Markdown
Member Author

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe remove too?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

@iSazonov

Copy link
Copy Markdown
Collaborator

I see multiple New-Item but I see no reason optimize them (BeforeAll).

So the tests LGTM.

}
}

//RootModule can be null, empty string or point to a valid .psm1, or .dll. Anything else is invalid.

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Contributor

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?

Copy link
Copy Markdown
Collaborator

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.

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Member Author

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created issue #3218

Copy link
Copy Markdown
Collaborator

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.

@SteveL-MSFT Steve Lee (SteveL-MSFT) Feb 27, 2017

Copy link
Copy Markdown
Member Author

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}

CC Hemant Mahawar (@HemantMahawar)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `

Copy link
Copy Markdown
Contributor

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)
}

Copy link
Copy Markdown
Member Author

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
@lzybkr

Copy link
Copy Markdown
Contributor

Closing and re-opening to retry blocked CI.

@SteveL-MSFT
Steve Lee (SteveL-MSFT) deleted the modulemanifest branch March 21, 2017 19:53
@iSazonov Ilya (iSazonov) removed the Review - Needed The PR is being reviewed label Mar 27, 2017
Thatgfsj (Thatgfsj) pushed a commit to Thatgfsj/PowerShell that referenced this pull request Aug 6, 2026
PowerShell#3097)

Changed hard coded Windows directory separator and resolved path so the slashes are correct.
Throw if resolving file path returns more than one result

Fixes PowerShell#2610
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants