Skip to content

Commit 5a70cc8

Browse files
Merge pull request #118 from WarehouseFinds/fix/remove_labeler_from_CI
Add integration testing
2 parents 04553e7 + 2cecf24 commit 5a70cc8

File tree

7 files changed

+247
-29
lines changed

7 files changed

+247
-29
lines changed

.github/CODEOWNERS

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44

55
# Default owners for everything in the repo
66
# These owners will be requested for review when someone opens a pull request
7-
* @marko-stanojevic
7+
* @marko-stanojevic
88

99
# Source code
10-
/src/ @marko-stanojevic
10+
/src/ @marko-stanojevic
11+
/requirements.psd1 @marko-stanojevic
1112

1213
# Build and CI/CD
1314
*.build.ps1 @marko-stanojevic
1415
/.github/workflows/ @marko-stanojevic
15-
/requirements.psd1 @marko-stanojevic
1616
/gitversion.yml @marko-stanojevic
1717

1818
# Tests
19-
/tests/ @marko-stanojevic
19+
/tests/ @marko-stanojevic
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Run Integration Tests
2+
description: Execute integration tests on built module and publish results
3+
inputs:
4+
module-list:
5+
description: Comma-separated list of PowerShell modules to cache
6+
required: true
7+
runs:
8+
using: composite
9+
steps:
10+
- name: Run Integration Tests via Invoke-Build
11+
shell: pwsh
12+
run: |
13+
Set-StrictMode -Version Latest
14+
Invoke-Build -Task Invoke-IntegrationTests
15+
16+
- name: Publish Integration Test Results
17+
uses: EnricoMi/publish-unit-test-result-action@27d65e188ec43221b20d26de30f4892fad91df2f #v2.22.0
18+
if: (!cancelled())
19+
with:
20+
check_run: false
21+
check_name: ">> Report: Integration Tests"
22+
check_run_annotations: all tests, skipped tests
23+
job_summary: true
24+
comment_title: Integration Test Report
25+
comment_mode: off
26+
files: |
27+
test-results/integration-tests.xml

.github/workflows/bootstrap.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ jobs:
145145
MODULE_NAME=${{ github.event.repository.name }}
146146
sed -i "s/PSScriptModule/$MODULE_NAME/g" .devcontainer/devcontainer.json
147147
148+
- name: Update integration test file
149+
run: |
150+
MODULE_NAME=${{ github.event.repository.name }}
151+
sed -i "s/PSScriptModule/$MODULE_NAME/g" tests/Integration/Module.Integration.Tests.ps1
152+
148153
- name: Remove this workflow file
149154
run: |
150155
rm .github/workflows/bootstrap.yml

.github/workflows/ci.yml

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ on:
99
- main
1010
paths:
1111
- 'src/**'
12+
- 'tests/**'
13+
- '*.ps1'
14+
- '*.psd1'
1215

1316
pull_request:
1417
branches:
@@ -18,25 +21,13 @@ on:
1821
paths:
1922
- 'src/**'
2023
- 'tests/**'
21-
- 'docs/**'
2224
- '.github/**/*'
23-
- '*'
25+
- '*.ps1'
26+
- '*.psd1'
2427

2528
jobs:
26-
changes:
27-
name: Label Changes
28-
runs-on: [ubuntu-latest]
29-
if: github.event_name == 'pull_request'
30-
permissions:
31-
contents: read
32-
pull-requests: write
33-
steps:
34-
- name: Labeler
35-
id: labeler
36-
uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b #v6.0.1
37-
38-
setup:
39-
name: Setup
29+
dependencies:
30+
name: Dependencies
4031
runs-on: ubuntu-latest
4132
outputs:
4233
module-list: ${{ steps.resolve.outputs.module-list }}
@@ -51,7 +42,7 @@ jobs:
5142

5243
unit-tests:
5344
name: Unit Tests
54-
needs: [setup]
45+
needs: [dependencies]
5546
runs-on: ${{ matrix.os }}
5647
strategy:
5748
matrix:
@@ -66,11 +57,11 @@ jobs:
6657
- name: Run Pester Unit Tests
6758
uses: ./.github/actions/ps-unit-tests
6859
with:
69-
module-list: ${{ needs.setup.outputs.module-list }}
60+
module-list: ${{ needs.dependencies.outputs.module-list }}
7061

7162
static-code-analysis:
7263
name: Static Code Analysis
73-
needs: [setup]
64+
needs: [dependencies]
7465
runs-on: ubuntu-latest
7566
permissions:
7667
issues: write
@@ -82,11 +73,11 @@ jobs:
8273
- name: Run PSScriptAnalyzer
8374
uses: ./.github/actions/ps-static-code-analysis
8475
with:
85-
module-list: ${{ needs.setup.outputs.module-list }}
76+
module-list: ${{ needs.dependencies.outputs.module-list }}
8677

8778
code-injection:
8879
name: Code Injection
89-
needs: [setup]
80+
needs: [dependencies]
9081
runs-on: ubuntu-latest
9182
permissions:
9283
issues: write
@@ -98,11 +89,11 @@ jobs:
9889
- name: Run InjectionHunter
9990
uses: ./.github/actions/ps-code-injection
10091
with:
101-
module-list: ${{ needs.setup.outputs.module-list }}
92+
module-list: ${{ needs.dependencies.outputs.module-list }}
10293

10394
semantic-code-analysis:
10495
name: Semantic Code Analysis
105-
needs: [setup]
96+
needs: [dependencies]
10697
runs-on: ubuntu-latest
10798
permissions:
10899
security-events: write
@@ -124,7 +115,7 @@ jobs:
124115

125116
build:
126117
name: Build
127-
needs: [setup, unit-tests, static-code-analysis, code-injection, semantic-code-analysis]
118+
needs: [dependencies, unit-tests, static-code-analysis, code-injection, semantic-code-analysis]
128119
runs-on: ubuntu-latest
129120
permissions:
130121
contents: write
@@ -141,4 +132,6 @@ jobs:
141132
uses: ./.github/actions/ps-build
142133
with:
143134
release-type: 'Debug'
144-
module-list: ${{ needs.setup.outputs.module-list }}
135+
module-list: ${{ needs.dependencies.outputs.module-list }}
136+
- name: Run Integration Tests
137+
uses: ./.github/actions/ps-integration-tests

PSScriptModule.build.ps1

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,40 @@ task Invoke-UnitTests {
101101
Invoke-Pester -Configuration $config -Verbose
102102
}
103103

104+
# Synopsis: Run integration tests on built module
105+
task Invoke-IntegrationTests {
106+
if (-not (Test-Path $testOutputPath)) {
107+
[void] (New-Item -Path $testOutputPath -ItemType Directory)
108+
}
109+
110+
$integrationTestPath = Join-Path -Path $testSourcePath -ChildPath 'Integration'
111+
if (-not (Test-Path $integrationTestPath)) {
112+
Write-Warning "No integration tests found at '$integrationTestPath'"
113+
return
114+
}
115+
116+
$config = New-PesterConfiguration @{
117+
Run = @{
118+
Path = $integrationTestPath
119+
PassThru = $true
120+
Exit = $true
121+
}
122+
TestResult = @{
123+
Enabled = $true
124+
OutputFormat = 'NUnitXml'
125+
OutputPath = "$testOutputPath\integration-tests.xml"
126+
}
127+
Filter = @{
128+
Tag = 'Integration'
129+
}
130+
Output = @{
131+
Verbosity = 'Detailed'
132+
}
133+
}
134+
135+
Invoke-Pester -Configuration $config
136+
}
137+
104138
# Synopsis: Run all tests
105139
task Test Invoke-UnitTests, Invoke-PSScriptAnalyzer, Invoke-InjectionHunter
106140

src/PSScriptModule.psd1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
Copyright = '(c) Warehouse Finds'
77
Description = 'A production-ready PowerShell script module template designed to streamline the creation, testing, and delivery of PowerShell modules.'
88
RootModule = 'PSScriptModule.psm1'
9+
PowerShellVersion = '7.1'
910
FunctionsToExport = @()
1011
CmdletsToExport = @()
1112
VariablesToExport = @()
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Variables used in Pester test contexts')]
2+
param()
3+
4+
BeforeAll {
5+
# Determine the built module path dynamically
6+
$moduleName = 'PSScriptModule'
7+
$modulePath = Resolve-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath "../../build/out/$moduleName")
8+
$manifestPath = Join-Path -Path $modulePath -ChildPath "$moduleName.psd1"
9+
10+
# Import the built module
11+
if ($manifestPath -and (Test-Path $manifestPath)) {
12+
Import-Module $manifestPath -Force -ErrorAction Stop
13+
} else {
14+
throw "Built module not found at: $manifestPath. Run 'Invoke-Build' first."
15+
}
16+
}
17+
18+
AfterAll {
19+
# Clean up
20+
Remove-Module 'PSScriptModule' -ErrorAction SilentlyContinue
21+
}
22+
23+
Describe 'PSScriptModule Integration Tests' -Tag 'Integration' {
24+
25+
Context 'Module Loading' {
26+
It 'Should load the module successfully' {
27+
$module = Get-Module -Name 'PSScriptModule'
28+
$module | Should -Not -BeNullOrEmpty
29+
}
30+
31+
It 'Should have module manifest or psm1' {
32+
$module = Get-Module -Name 'PSScriptModule'
33+
$module.Path | Should -Match '\.(psd1|psm1)$'
34+
}
35+
36+
It 'Should have correct module name' {
37+
$module = Get-Module -Name 'PSScriptModule'
38+
$module.Name | Should -Be 'PSScriptModule'
39+
}
40+
41+
It 'Should have a valid version' {
42+
$module = Get-Module -Name 'PSScriptModule'
43+
$module.Version | Should -Not -BeNullOrEmpty
44+
$module.Version | Should -BeOfType [version]
45+
}
46+
}
47+
48+
Context 'Exported Functions' {
49+
BeforeAll {
50+
$module = Get-Module -Name 'PSScriptModule'
51+
$exportedCommands = $module.ExportedCommands.Keys
52+
53+
# Discover public functions from source
54+
$publicFunctionsPath = Resolve-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath '../../src/Public/')
55+
$publicFunctionFiles = @(Get-ChildItem -Path $publicFunctionsPath -Include '*.ps1' -Exclude '*.Tests.ps1' -Recurse |
56+
Select-Object -ExpandProperty BaseName)
57+
}
58+
59+
It 'Should export at least one function' {
60+
$exportedCommands.Count | Should -BeGreaterThan 0
61+
}
62+
63+
It 'Public function files' {
64+
$publicFunctionFiles | Should -HaveCount 1 -Because 'The template ships with a single public function'
65+
}
66+
67+
It 'Should discover public functions from src/Public' {
68+
$publicFunctionFiles.Count | Should -BeGreaterThan 0 -Because 'src/Public should contain at least one public function'
69+
}
70+
71+
It 'Should export all public functions from src/Public' {
72+
foreach ($functionName in $publicFunctionFiles) {
73+
$exportedCommands | Should -Contain $functionName -Because "Public function $functionName should be exported"
74+
}
75+
}
76+
77+
It 'Should not export private functions' {
78+
$privateFunctionsPath = Join-Path $PSScriptRoot '../../src/Private'
79+
if (Test-Path $privateFunctionsPath) {
80+
$privateFiles = Get-ChildItem -Path $privateFunctionsPath -Filter '*.ps1' -Exclude '*.Tests.ps1' |
81+
Select-Object -ExpandProperty BaseName
82+
83+
foreach ($functionName in $privateFiles) {
84+
$exportedCommands | Should -Not -Contain $functionName -Because "Private function $functionName should not be exported"
85+
}
86+
}
87+
}
88+
89+
It 'Should have help for all exported functions' {
90+
foreach ($command in $exportedCommands) {
91+
$help = Get-Help $command
92+
$help.Synopsis | Should -Not -BeNullOrEmpty -Because "Function $command should have synopsis"
93+
$help.Description | Should -Not -BeNullOrEmpty -Because "Function $command should have description"
94+
}
95+
}
96+
97+
It 'Should have help for each public function dynamically' {
98+
foreach ($functionName in $publicFunctionFiles) {
99+
$help = Get-Help $functionName
100+
$help.Synopsis | Should -Not -BeNullOrEmpty -Because "Public function $functionName should have synopsis"
101+
}
102+
}
103+
}
104+
105+
Context 'Module Metadata' {
106+
BeforeAll {
107+
$module = Get-Module -Name 'PSScriptModule'
108+
}
109+
110+
It 'Should have an author' {
111+
$module.Author | Should -Not -BeNullOrEmpty
112+
}
113+
114+
It 'Should have a description' {
115+
$module.Description | Should -Not -BeNullOrEmpty
116+
}
117+
118+
It 'Should have a company name' {
119+
$module.CompanyName | Should -Not -BeNullOrEmpty
120+
}
121+
122+
It 'Should have a copyright' {
123+
$module.Copyright | Should -Not -BeNullOrEmpty
124+
}
125+
126+
It 'Should specify PowerShell version' {
127+
$module = Get-Module -Name 'PSScriptModule'
128+
# PowerShellVersion may not be set for all modules
129+
if ($module.PowerShellVersion) {
130+
$module.PowerShellVersion | Should -BeOfType [version]
131+
} else {
132+
Set-ItResult -Skipped -Because 'PowerShellVersion not specified in manifest'
133+
}
134+
}
135+
136+
It 'Should have project URI' {
137+
$module.ProjectUri | Should -Not -BeNullOrEmpty
138+
$module.ProjectUri.AbsoluteUri | Should -Match '^https?://'
139+
}
140+
141+
It 'Should have license URI' {
142+
$module.LicenseUri | Should -Not -BeNullOrEmpty
143+
$module.LicenseUri.AbsoluteUri | Should -Match '^https?://'
144+
}
145+
}
146+
147+
Context 'Performance' {
148+
It 'Should load module in reasonable time' {
149+
$loadTime = Measure-Command {
150+
Remove-Module 'PSScriptModule' -ErrorAction SilentlyContinue
151+
# Use the same module path resolution as BeforeAll
152+
Import-Module $manifestPath -Force
153+
}
154+
155+
$loadTime.TotalSeconds | Should -BeLessThan 5 -Because 'Module should load within 5 seconds'
156+
}
157+
}
158+
}

0 commit comments

Comments
 (0)