diff --git a/.azure-pipelines/generate-beta-modules.yml b/.azure-pipelines/generate-beta-modules.yml
index e334fc50304..f41459c1093 100644
--- a/.azure-pipelines/generate-beta-modules.yml
+++ b/.azure-pipelines/generate-beta-modules.yml
@@ -133,7 +133,7 @@ jobs:
displayName: 'Generate and Build Graph Resource Modules'
inputs:
filePath: '$(System.DefaultWorkingDirectory)/tools/GenerateModules.ps1'
- arguments: '-ArtifactsLocation $(Build.ArtifactStagingDirectory)\ -Build -EnableSigning'
+ arguments: '-ArtifactsLocation $(Build.ArtifactStagingDirectory)\ -Build -Test -EnableSigning'
pwsh: true
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
diff --git a/.azure-pipelines/generate-modules-template.yml b/.azure-pipelines/generate-modules-template.yml
index 4476dc3ba12..d511c73b473 100644
--- a/.azure-pipelines/generate-modules-template.yml
+++ b/.azure-pipelines/generate-modules-template.yml
@@ -142,7 +142,7 @@ jobs:
pwsh: true
script: |
Write-Host $(BUILDNUMBER)
- pwsh $(System.DefaultWorkingDirectory)/tools/GenerateModules.ps1 -ArtifactsLocation $(Build.ArtifactStagingDirectory)\ -Build -EnableSigning -ModulePreviewNumber $(BUILDNUMBER) -UpdateAutoRest -RepositoryName "LocalNugetFeed"
+ pwsh $(System.DefaultWorkingDirectory)/tools/GenerateModules.ps1 -ArtifactsLocation $(Build.ArtifactStagingDirectory)\ -Build -Test -EnableSigning -ModulePreviewNumber $(BUILDNUMBER) -UpdateAutoRest -RepositoryName "LocalNugetFeed"
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
displayName: 'ESRP DLL Strong Name (Graph Resource Modules)'
diff --git a/.azure-pipelines/validate-pr-beta-modules.yml b/.azure-pipelines/validate-pr-beta-modules.yml
index abd45602bfc..c89258b16e5 100644
--- a/.azure-pipelines/validate-pr-beta-modules.yml
+++ b/.azure-pipelines/validate-pr-beta-modules.yml
@@ -48,7 +48,7 @@ jobs:
displayName: 'Generate and Build Graph Resource Modules'
inputs:
filePath: '$(System.DefaultWorkingDirectory)/tools/GenerateModules.ps1'
- arguments: '-RepositoryApiKey $(Api_Key) -Build'
+ arguments: '-RepositoryApiKey $(Api_Key) -Build -Test'
pwsh: true
- task: YodLabs.O365PostMessage.O365PostMessageBuild.O365PostMessageBuild@0
diff --git a/build.proj b/build.proj
index d489085c7dd..b236a72c755 100644
--- a/build.proj
+++ b/build.proj
@@ -31,7 +31,7 @@
$True
pwsh -NonInteractive -NoLogo -NoProfile -Command
- $(PowerShellCoreCommandPrefix) " $(RepoTools)/GenerateModules.ps1 -Build -SkipVersionCheck:$(SkipVersionCheck) -EnableSigning:$(EnableSigning) -UpdateAutoRest:$(UpdateAutoRest) "
+ $(PowerShellCoreCommandPrefix) " $(RepoTools)/GenerateModules.ps1 -Build -Test -SkipVersionCheck:$(SkipVersionCheck) -EnableSigning:$(EnableSigning) -UpdateAutoRest:$(UpdateAutoRest) "
$(PowerShellCoreCommandPrefix) " $(RepoTools)/GenerateRollUpModule.ps1 "
$(PowerShellCoreCommandPrefix) " $(RepoTools)/GenerateAuthenticationModule.ps1 -Build -BuildWhenEqual:$(BuildWhenEqual) -EnableSigning:$(EnableSigning) "
$(PowerShellCoreCommandPrefix) " $(RepoTools)/GenerateProfiles.ps1 "
diff --git a/src/Applications/Applications/test/Applications.Tests.ps1 b/src/Applications/Applications/test/Applications.Tests.ps1
new file mode 100644
index 00000000000..414cb8a9379
--- /dev/null
+++ b/src/Applications/Applications/test/Applications.Tests.ps1
@@ -0,0 +1,41 @@
+BeforeAll {
+ $ModuleName = "Microsoft.Graph.Applications"
+ $ModulePath = Join-Path $PSScriptRoot "..\$ModuleName.psd1"
+}
+
+Describe "Applications Module" {
+ It "Module should be available when imported" {
+ $LoadedModule = Get-Module -Name $ModuleName
+
+ $LoadedModule | Should -Not -Be $null
+ $LoadedModule.ExportedCommands.Count | Should -Not -Be 0
+ }
+
+ It "Module import should not write to streams when debug preference is not set" {
+ $ps = [powershell]::Create()
+ $ps.AddScript("Import-Module $ModulePath").Invoke()
+
+ $ps.Streams.Information.Count | Should -Be 0
+ $ps.Streams.Debug.Count | Should -Be 0
+ $ps.Streams.Error.Count | Should -Be 0
+ $ps.Streams.Verbose.Count | Should -Be 0
+ $ps.Streams.Warning.Count | Should -Be 0
+ $ps.Streams.Progress.Count | Should -Be 0
+
+ $ps.Dispose()
+ }
+
+ It "Module import should write to streams when debug preference is set" {
+ $ps = [powershell]::Create()
+ $ps.AddScript("`$DebugPreference = 'Inquire'; Import-Module $ModulePath").Invoke()
+
+ $ps.Streams.Information.Count | Should -Be 0
+ $ps.Streams.Debug.Count | Should -Be 2
+ $ps.Streams.Error.Count | Should -Be 0
+ $ps.Streams.Verbose.Count | Should -Be 0
+ $ps.Streams.Warning.Count | Should -Be 0
+ $ps.Streams.Progress.Count | Should -Be 0
+
+ $ps.Dispose()
+ }
+}
\ No newline at end of file
diff --git a/src/CloudCommunications/CloudCommunications/test/CloudCommunications.Tests.ps1 b/src/CloudCommunications/CloudCommunications/test/CloudCommunications.Tests.ps1
new file mode 100644
index 00000000000..e21b8b2ed09
--- /dev/null
+++ b/src/CloudCommunications/CloudCommunications/test/CloudCommunications.Tests.ps1
@@ -0,0 +1,41 @@
+BeforeAll {
+ $ModuleName = "Microsoft.Graph.CloudCommunications"
+ $ModulePath = Join-Path $PSScriptRoot "..\$ModuleName.psd1"
+}
+
+Describe "CloudCommunications Module" {
+ It "Module should be available when imported" {
+ $LoadedModule = Get-Module -Name $ModuleName
+
+ $LoadedModule | Should -Not -Be $null
+ $LoadedModule.ExportedCommands.Count | Should -Not -Be 0
+ }
+
+ It "Module import should not write to streams when debug preference is not set" {
+ $ps = [powershell]::Create()
+ $ps.AddScript("Import-Module $ModulePath").Invoke()
+
+ $ps.Streams.Information.Count | Should -Be 0
+ $ps.Streams.Debug.Count | Should -Be 0
+ $ps.Streams.Error.Count | Should -Be 0
+ $ps.Streams.Verbose.Count | Should -Be 0
+ $ps.Streams.Warning.Count | Should -Be 0
+ $ps.Streams.Progress.Count | Should -Be 0
+
+ $ps.Dispose()
+ }
+
+ It "Module import should write to streams when debug preference is set" {
+ $ps = [powershell]::Create()
+ $ps.AddScript("`$DebugPreference = 'Inquire'; Import-Module $ModulePath").Invoke()
+
+ $ps.Streams.Information.Count | Should -Be 0
+ $ps.Streams.Debug.Count | Should -Be 2
+ $ps.Streams.Error.Count | Should -Be 0
+ $ps.Streams.Verbose.Count | Should -Be 0
+ $ps.Streams.Warning.Count | Should -Be 0
+ $ps.Streams.Progress.Count | Should -Be 0
+
+ $ps.Dispose()
+ }
+}
\ No newline at end of file
diff --git a/src/Users/Users/test/Users.Tests.ps1 b/src/Users/Users/test/Users.Tests.ps1
new file mode 100644
index 00000000000..59cc9561920
--- /dev/null
+++ b/src/Users/Users/test/Users.Tests.ps1
@@ -0,0 +1,41 @@
+BeforeAll {
+ $ModuleName = "Microsoft.Graph.Users"
+ $ModulePath = Join-Path $PSScriptRoot "..\$ModuleName.psd1"
+}
+
+Describe "Users Module" {
+ It "Module should be available when imported" {
+ $LoadedModule = Get-Module -Name $ModuleName
+
+ $LoadedModule | Should -Not -Be $null
+ $LoadedModule.ExportedCommands.Count | Should -Not -Be 0
+ }
+
+ It "Module import should not write to streams when debug preference is not set" {
+ $ps = [powershell]::Create()
+ $ps.AddScript("Import-Module $ModulePath").Invoke()
+
+ $ps.Streams.Information.Count | Should -Be 0
+ $ps.Streams.Debug.Count | Should -Be 0
+ $ps.Streams.Error.Count | Should -Be 0
+ $ps.Streams.Verbose.Count | Should -Be 0
+ $ps.Streams.Warning.Count | Should -Be 0
+ $ps.Streams.Progress.Count | Should -Be 0
+
+ $ps.Dispose()
+ }
+
+ It "Module import should write to streams when debug preference is set" {
+ $ps = [powershell]::Create()
+ $ps.AddScript("`$DebugPreference = 'Inquire'; Import-Module $ModulePath").Invoke()
+
+ $ps.Streams.Information.Count | Should -Be 0
+ $ps.Streams.Debug.Count | Should -Be 2
+ $ps.Streams.Error.Count | Should -Be 0
+ $ps.Streams.Verbose.Count | Should -Be 0
+ $ps.Streams.Warning.Count | Should -Be 0
+ $ps.Streams.Progress.Count | Should -Be 0
+
+ $ps.Dispose()
+ }
+}
\ No newline at end of file
diff --git a/tools/GenerateModules.ps1 b/tools/GenerateModules.ps1
index 6f28026f013..28b45e1f096 100644
--- a/tools/GenerateModules.ps1
+++ b/tools/GenerateModules.ps1
@@ -7,6 +7,7 @@ Param(
[string] $ModuleMappingConfigPath = (Join-Path $PSScriptRoot "..\config\ModulesMapping.jsonc"),
[switch] $UpdateAutoRest,
[switch] $Build,
+ [switch] $Test,
[switch] $Pack,
[switch] $Publish,
[switch] $EnableSigning,
@@ -34,6 +35,7 @@ $RequiredGraphModules = @()
# PS Scripts
$ManageGeneratedModulePS1 = Join-Path $PSScriptRoot ".\ManageGeneratedModule.ps1" -Resolve
$BuildModulePS1 = Join-Path $PSScriptRoot ".\BuildModule.ps1" -Resolve
+$TestModulePS1 = Join-Path $PSScriptRoot ".\TestModule.ps1" -Resolve
$PackModulePS1 = Join-Path $PSScriptRoot ".\PackModule.ps1" -Resolve
$PublishModulePS1 = Join-Path $PSScriptRoot ".\PublishModule.ps1" -Resolve
$ReadModuleReadMePS1 = Join-Path $PSScriptRoot ".\ReadModuleReadMe.ps1" -Resolve
@@ -54,8 +56,7 @@ if($ModulePreviewNumber -eq -1) {
# Install module locally in order to specify it as a dependency for other modules down the generation pipeline.
# https://stackoverflow.com/questions/46216038/how-do-i-define-requiredmodules-in-a-powershell-module-manifest-psd1.
$ExistingAuthModule = Find-Module "Microsoft.Graph.Authentication" -Repository $RepositoryName -AllowPrerelease:$AllowPreRelease
-Write-Warning "Auth Module: $ExistingAuthModule.Name"
-Write-Warning "Auth Module: $ExistingAuthModule.Version"
+Write-Host -ForegroundColor Green "Auth Module: $($ExistingAuthModule.Name), $($ExistingAuthModule.Version)"
if (!(Get-Module -Name $ExistingAuthModule.Name -ListAvailable)) {
Install-Module $ExistingAuthModule.Name -Repository $RepositoryName -Force -AllowClobber -AllowPrerelease:$AllowPreRelease
}
@@ -83,7 +84,8 @@ $ModuleMapping.Keys | ForEach-Object -ThrottleLimit $ModuleMapping.Keys.Count -P
}
$ModuleName = $_
- Write-Warning "Generating $ModuleName"
+ $FullyQualifiedModuleName = "$using:ModulePrefix.$ModuleName"
+ Write-Host -ForegroundColor Green "Generating '$FullyQualifiedModuleName' module..."
$ModuleProjectDir = Join-Path $Using:ModulesOutputDir "$ModuleName\$ModuleName"
# Copy AutoRest readme.md config is none exists.
@@ -98,37 +100,36 @@ $ModuleMapping.Keys | ForEach-Object -ThrottleLimit $ModuleMapping.Keys.Count -P
$ModuleVersion = & $Using:ReadModuleReadMePS1 -ReadMePath $ModuleLevelReadMePath -FieldToRead "module-version"
if ($ModuleVersion -eq $null) {
# Module version not set in readme.md.
- Write-Error "Version number is not set on $Using:ModulePrefix.$ModuleName module. Please set 'module-version' in $ModuleLevelReadMePath."
+ Write-Error "Version number is not set on $FullyQualifiedModuleName module. Please set 'module-version' in $ModuleLevelReadMePath."
}
# Validate module version with the one on PSGallery.
- [VersionState] $VersionState = & $Using:ValidateUpdatedModuleVersionPS1 -ModuleName "$Using:ModulePrefix.$ModuleName" -NextVersion $ModuleVersion -PSRepository RepositoryName -ModulePreviewNumber $ModulePreviewNumber
+ [VersionState] $VersionState = & $Using:ValidateUpdatedModuleVersionPS1 -ModuleName "$FullyQualifiedModuleName" -NextVersion $ModuleVersion -PSRepository RepositoryName -ModulePreviewNumber $ModulePreviewNumber
if ($VersionState.Equals([VersionState]::Invalid) -and !$Using:SkipVersionCheck) {
- Write-Warning "The specified version in $Using:ModulePrefix.$ModuleName module is either higher or lower than what's on $Using:RepositoryName. Update the 'module-version' in $ModuleLevelReadMePath"
+ Write-Warning "The specified version in $FullyQualifiedModuleName module is either higher or lower than what's on $Using:RepositoryName. Update the 'module-version' in $ModuleLevelReadMePath"
}
elseif ($VersionState.Equals([VersionState]::EqualToFeed) -and !$SkipVersionCheck) {
- Write-Warning "$Using:ModulePrefix.$ModuleName module skipped. Version has not changed and is equal to what's on $Using:RepositoryName."
+ Write-Warning "$FullyQualifiedModuleName module skipped. Version has not changed and is equal to what's on $Using:RepositoryName."
}
elseif ($VersionState.Equals([VersionState]::Valid) -or $VersionState.Equals([VersionState]::NotOnFeed) -or $Using:SkipVersionCheck) {
# Read release notes from readme.
$ModuleReleaseNotes = & $Using:ReadModuleReadMePS1 -ReadMePath $ModuleLevelReadMePath -FieldToRead "release-notes"
if ($ModuleReleaseNotes -eq $null) {
# Release notes not set in readme.md.
- Write-Error "Release notes not set on $Using:ModulePrefix.$ModuleName module. Please set 'release-notes' in $ModuleLevelReadMePath."
+ Write-Error "Release notes not set on $FullyQualifiedModuleName module. Please set 'release-notes' in $ModuleLevelReadMePath."
}
try {
# Generate PowerShell modules.
- Write-Host -ForegroundColor Green "Generating '$Using:ModulePrefix.$ModuleName' module..."
& autorest --module-version:$ModuleVersion --service-name:$ModuleName $ModuleLevelReadMePath --verbose
if ($LASTEXITCODE) {
Write-Error "Failed to generate '$ModuleName' module."
}
- Write-Host -ForegroundColor Green "AutoRest generated '$Using:ModulePrefix.$ModuleName' successfully."
+ Write-Host -ForegroundColor Green "AutoRest generated '$FullyQualifiedModuleName' successfully."
# Manage generated module.
- Write-Host -ForegroundColor Green "Managing '$Using:ModulePrefix.$ModuleName' module..."
+ Write-Host -ForegroundColor Green "Managing '$FullyQualifiedModuleName' module..."
& $Using:ManageGeneratedModulePS1 -Module $ModuleName -ModulePrefix $Using:ModulePrefix
if ($Using:Build) {
@@ -146,12 +147,12 @@ $ModuleMapping.Keys | ForEach-Object -ThrottleLimit $ModuleMapping.Keys.Count -P
$Profiles = Get-ChildItem -Path $ModuleExportsPath -Directory | %{ $_.Name}
# Update module manifest wiht profiles.
- $ModuleManifestPath = Join-Path $ModuleProjectDir "$Using:ModulePrefix.$ModuleName.psd1"
+ $ModuleManifestPath = Join-Path $ModuleProjectDir "$FullyQualifiedModuleName.psd1"
[HashTable]$PrivateData = @{ Profiles = $Profiles }
Update-ModuleManifest -Path $ModuleManifestPath -PrivateData $PrivateData
# Update module psm1 with Graph session profile name.
- $ModulePsm1 = Join-Path $ModuleProjectDir "/$Using:ModulePrefix.$ModuleName.psm1"
+ $ModulePsm1 = Join-Path $ModuleProjectDir "/$FullyQualifiedModuleName.psm1"
(Get-Content -Path $ModulePsm1) | ForEach-Object{
if ($_ -match '\$instance = \[Microsoft.Graph.PowerShell.Module\]::Instance') {
# Update main psm1 with Graph session profile name and module name.
@@ -161,13 +162,15 @@ $ModuleMapping.Keys | ForEach-Object -ThrottleLimit $ModuleMapping.Keys.Count -P
# Rename all Azure instances in psm1 to `Microsoft Graph`.
$updatedLine = $_ -replace 'Azure', 'Microsoft Graph'
# Replace all 'instance.Name' declarations with fully qualified module name.
- $updatedLine = $updatedLine -replace '\$\(\$instance.Name\)', "$ModulePrefix.$ModuleName"
+ $updatedLine = $updatedLine -replace '\$\(\$instance.Name\)', "$FullyQualifiedModuleName"
+ # Replace Write-Information with Write-Debug
+ $updatedLine = $updatedLine -replace 'Write\-Information', 'Write-Debug'
$updatedLine
}
} | Set-Content $ModulePsm1
# Address AutoREST bug where it looks for exports in the wrong directory.
- $InternalModulePsm1 = Join-Path $ModuleProjectDir "/internal/$Using:ModulePrefix.$ModuleName.internal.psm1"
+ $InternalModulePsm1 = Join-Path $ModuleProjectDir "/internal/$FullyQualifiedModuleName.internal.psm1"
(Get-Content -Path $InternalModulePsm1) | ForEach-Object{
$updatedLine = $_
# Address AutoREST bug where it looks for exports in the wrong directory.
@@ -188,19 +191,22 @@ $ModuleMapping.Keys | ForEach-Object -ThrottleLimit $ModuleMapping.Keys.Count -P
}
}
+ if ($Using:Test) {
+ & $Using:TestModulePS1 -ModulePath $ModuleProjectDir -ModuleName $FullyQualifiedModuleName
+ }
+
if ($Using:Pack) {
# Pack generated module.
- & $Using:PackModulePS1 -Module $ModuleName -ArtifactsLocation $Using:ArtifactsLocation
+ . $Using:PackModulePS1 -Module $ModuleName -ArtifactsLocation $Using:ArtifactsLocation
}
}
catch {
- Write-Error $_.Exception
+ throw $_
}
- Write-Warning "Generating $ModuleName Completed"
+ Write-Host -ForeGroundColor Green "Generating $ModuleName Completed"
}
}
-Write-Host -ForeGroundColor Green "Requests: $RequestCount"
if ($Publish) {
# Publish generated modules.
& $PublishModulePS1 -Modules $ModuleMapping.Keys -ModulePrefix $ModulePrefix -ArtifactsLocation $ArtifactsLocation -RepositoryName $RepositoryName -RepositoryApiKey $RepositoryApiKey
diff --git a/tools/TestModule.ps1 b/tools/TestModule.ps1
new file mode 100644
index 00000000000..32ee8ee3b6a
--- /dev/null
+++ b/tools/TestModule.ps1
@@ -0,0 +1,36 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+param([string] $ModulePath, [string] $ModuleName, [switch]$Isolated)
+$ErrorActionPreference = 'Stop'
+
+# Install Pester
+if (!(Get-Module -Name Pester -ListAvailable)) {
+ Install-Module -Name Pester -Force -SkipPublisherCheck
+}
+
+if(-not $Isolated) {
+ Write-Host -ForegroundColor Green 'Creating isolated process...'
+ $pwsh = [System.Diagnostics.Process]::GetCurrentProcess().Path
+ & "$pwsh" -NonInteractive -NoLogo -NoProfile -File $MyInvocation.MyCommand.Path @PSBoundParameters -Isolated
+ return
+}
+
+$modulePsd1 = Get-Item -Path (Join-Path $ModulePath "./$ModuleName.psd1")
+
+Import-Module -Name Pester
+Import-Module -Name $modulePsd1.FullName
+
+$testFolder = Join-Path $ModulePath 'test'
+$PesterConfiguration = [PesterConfiguration]::Default
+$PesterConfiguration.Run.Path = $testFolder
+$PesterConfiguration.Run.Exit = $true
+$PesterConfiguration.TestResult.OutputPath = (Join-Path $testFolder "$moduleName-TestResults.xml")
+
+try {
+ Invoke-Pester -Configuration $PesterConfiguration
+}
+catch {
+ throw $_
+}
+
+Write-Host -ForegroundColor Green '-------------Done-------------'
\ No newline at end of file