Skip to content

Commit

Permalink
Merge pull request #14 from Fleid/release109
Browse files Browse the repository at this point in the history
Release109
  • Loading branch information
Fleid authored Jun 3, 2020
2 parents 0dfd159 + 0fe2a1a commit 22166bd
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 21 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ In this article:

### Context

At the time of writing, the major IDEs that support ASA ([VSCode](https://code.visualstudio.com/) and [Visual Studio](https://visualstudio.microsoft.com/vs/)) do not offer native unit testing capabilities.
At the time of writing, the major IDEs that support ASA ([VSCode](https://code.visualstudio.com/) and [Visual Studio](https://visualstudio.microsoft.com/vs/)) do not offer native **unit testing** capabilities.

This solution intends to fill that gap by enabling:
This tool intends to fill that gap by enabling:

- fully local, repeatable executions over multiple test cases
- automated evaluation of the resulting outputs against expected ones
Expand All @@ -39,7 +39,7 @@ For that it leverages the **local testing with sample data** capabilities of eit

Local runs are scripted thanks to the `sa.exe` tool from the [Microsoft.Azure.StreamAnalytics.CICD](https://www.nuget.org/packages/Microsoft.Azure.StreamAnalytics.CICD/) package.

The results are then evaluated against reference data sets thanks to the [jsondiffpatch](https://github.com/benjamine/JsonDiffPatch) library.
The results are then evaluated against reference data sets thanks to the [Compare-Object](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/compare-object?view=powershell-7) **PowerShell** cmdlet.

The whole thing is wired together in a **PowerShell** script based on a predefined test fixture (folder structure + naming convention):

Expand Down Expand Up @@ -69,10 +69,9 @@ Unit tests should not rely on external services, so all runs are done via local

### Requirements

This solution leverages [PowerShell](https://en.wikipedia.org/wiki/PowerShell), a [nuget](https://en.wikipedia.org/wiki/NuGet) package and a [npm](https://en.wikipedia.org/wiki/Npm_(software)) package to enable unit testing:
This solution leverages [PowerShell](https://en.wikipedia.org/wiki/PowerShell), and a [nuget](https://en.wikipedia.org/wiki/NuGet) package to enable ASA unit testing:

- For **PowerShell**, any [recent version](https://github.com/PowerShell/PowerShell/releases) should do (*assets* tab under a specific release)
- The **npm CLI** must also be installed manually (available with [Node.JS](https://nodejs.org/en/download/))
- The nuget CLI will be downloaded via the provided installation script, but it requires the [.NET Framework 4.7.2 or above](https://dotnet.microsoft.com/download/dotnet-framework) to run.

From there, the installation script will take care of the other dependencies (including the nuget CLI).
Expand Down Expand Up @@ -230,6 +229,9 @@ PowerShell [remoting for jobs](https://docs.microsoft.com/en-us/powershell/modul

### Change Log

- May 2020 :
- Update doc to reflect the removal of the jsondiffpatch dependency
- Fix open issues
- March 2020 :
- Full refactoring to allow publication in the PowerShell Gallery
- Complete unit test coverage (Pester) and linting
Expand All @@ -243,18 +245,16 @@ This solution uses the following components:

- the [Microsoft.Azure.StreamAnalytics.CICD](https://www.nuget.org/packages/Microsoft.Azure.StreamAnalytics.CICD/) nuget package, which provides `sa.exe`, a Windows-only executable that allows to run an ASA job [via command line](https://docs.microsoft.com/en-us/azure/stream-analytics/stream-analytics-tools-for-visual-studio-cicd)
- the [nuget CLI](https://docs.microsoft.com/en-us/nuget/reference/nuget-exe-cli-reference), to download and install the package above
- the **jsondiffpatch** npm package ([GitHub]((https://github.com/benjamine/JsonDiffPatch) ), [npm](https://www.npmjs.com/package/jsondiffpatch)) which allows to compare json files
- the [npm CLI](https://docs.npmjs.com/cli-documentation/) to install the package above, available with [Node.JS](https://nodejs.org/en/download/)
- [PowerShell](https://github.com/PowerShell/PowerShell/releases) as the shell to run intermediary tasks and execute the required commands

### Shortcomings

- Slow execution
- ~~Slow execution~~ Somewhat mitigated via the parallel execution of tests
- No integration to the usual IDEs
- No cross-platform options

### Thanks

- [Kevin Marquette](https://twitter.com/KevinMarquette) for his [invaluable](https://powershellexplained.com/2017-01-21-powershell-module-continious-delivery-pipeline/) blog on PowerShell
- [jsondiffpatch](https://github.com/benjamine/JsonDiffPatch) : Diff & patch JavaScript objects
- [jsondiffpatch](https://github.com/benjamine/JsonDiffPatch) : Diff & patch JavaScript objects (used actively up to release 1.0.7)
- [Tabler icons](https://github.com/tabler/tabler-icons) : A set of over 400 free MIT-licensed high-quality SVG icons for you to use in your web projects
2 changes: 1 addition & 1 deletion README_DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Import-Module -Name $moduleFile -verbose -force
$env:psmodulePath
```

Testing a run
### Testing a run (integration)

```PowerShell
$installFolder = "C:\users\fleide\Repos\asa.unittest\examples\ASAHelloWorld.Tests\"
Expand Down
10 changes: 10 additions & 0 deletions asa.unittest.tests/New-AutAsaprojXML.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ Describe "New-AutAsaprojXML Nominal" {
{
`"filePath`": `"JobConfig.json`",
`"subType`": `"JobConfig`"
},
{
`"filePath`": `"Functions\\jsFunction1.js.json`",
`"subType`": `"JSFunction`"
}
]
}"
Expand All @@ -34,6 +38,9 @@ Describe "New-AutAsaprojXML Nominal" {
$outputXMLstring ="<Project ToolsVersion=`"4.0`" DefaultTargets=`"Build`" xmlns=`"http://schemas.microsoft.com/developer/msbuild/2003`">
<ItemGroup>
<Script Include=`"asaproject.asaql`"/>
<ScriptCode Include=`"asaproject.asaql.cs`">
<DependentUpon>asaproject.asaql</DependentUpon>
</ScriptCode>
</ItemGroup>
<ItemGroup>
<Configure Include=`"Inputs\Local_input.json`">
Expand All @@ -45,6 +52,9 @@ Describe "New-AutAsaprojXML Nominal" {
<Configure Include=`"JobConfig.json`">
<SubType>JobConfig</SubType>
</Configure>
<Configure Include=`"Functions\jsFunction1.js.json`">
<SubType>JSFunction</SubType>
</Configure>
</ItemGroup>
</Project>
"
Expand Down
45 changes: 44 additions & 1 deletion asa.unittest.tests/New-AutRunFixture.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ Describe "New-AutRunFixture nominal" {
Assert-MockCalled New-Item -Times 3 -Exactly -Scope It -ParameterFilter {($ItemType -eq "Directory") -and ($Path -like "*\$t_testID\00?\$t_asaProjectName\Inputs\")}
}

It "creates function subfolder in each test case folder" {
New-AutRunFixture `
-solutionPath $t_solutionPath `
-asaProjectName $t_asaProjectName `
-unittestFolder $t_unittestFolder `
-testID $t_testID

Assert-MockCalled New-Item -Times 1 -Exactly -Scope It -ParameterFilter {($ItemType -eq "Directory") -and ($Path -like "*\$t_testID\001\$t_asaProjectName\Functions\")}
Assert-MockCalled New-Item -Times 1 -Exactly -Scope It -ParameterFilter {($ItemType -eq "Directory") -and ($Path -like "*\$t_testID\002\$t_asaProjectName\Functions\")}
Assert-MockCalled New-Item -Times 1 -Exactly -Scope It -ParameterFilter {($ItemType -eq "Directory") -and ($Path -like "*\$t_testID\003\$t_asaProjectName\Functions\")}
Assert-MockCalled New-Item -Times 3 -Exactly -Scope It -ParameterFilter {($ItemType -eq "Directory") -and ($Path -like "*\$t_testID\00?\$t_asaProjectName\Functions\")}
}

It "copies ASA config files in each test case folders" {
New-AutRunFixture `
-solutionPath $t_solutionPath `
Expand All @@ -99,6 +112,16 @@ Describe "New-AutRunFixture nominal" {
Assert-MockCalled Copy-Item -Times 3 -Exactly -Scope It -ParameterFilter {$Path -like "*.as*"}
}

It "copies ASA cs code behind files in each test case folders" {
New-AutRunFixture `
-solutionPath $t_solutionPath `
-asaProjectName $t_asaProjectName `
-unittestFolder $t_unittestFolder `
-testID $t_testID

Assert-MockCalled Copy-Item -Times 3 -Exactly -Scope It -ParameterFilter {$Path -like "*.cs"}
}

Mock Test-Path {return $false} -ParameterFilter {$Path -like "*.asaproj"}
It "calls New-AUTAsaprojXML if needed" {
New-AutRunFixture `
Expand Down Expand Up @@ -130,7 +153,27 @@ Describe "New-AutRunFixture nominal" {
-testID $t_testID

Assert-MockCalled Copy-Item -Times 3 -Exactly -Scope It -ParameterFilter {$Path -like "*Local*.json"}
}
}

It "copies ASA JS Function files in each test case folders" {
New-AutRunFixture `
-solutionPath $t_solutionPath `
-asaProjectName $t_asaProjectName `
-unittestFolder $t_unittestFolder `
-testID $t_testID

Assert-MockCalled Copy-Item -Times 3 -Exactly -Scope It -ParameterFilter {$Path -like "*.js"}
}

It "copies ASA JS Function definition (JSON) files in each test case folders" {
New-AutRunFixture `
-solutionPath $t_solutionPath `
-asaProjectName $t_asaProjectName `
-unittestFolder $t_unittestFolder `
-testID $t_testID

Assert-MockCalled Copy-Item -Times 3 -Exactly -Scope It -ParameterFilter {$Path -like "*.js.json"}
}

It "copies test files from 1_arrange in each test case folders" {
New-AutRunFixture `
Expand Down
18 changes: 16 additions & 2 deletions asa.unittest.tests/Start-AutRun.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ Describe "Start-AutRun parameter asaProjectName" {
Mock Get-ChildItem {}
Mock Get-Content {}

$t_solutionPath = "foo"
It "runs with a asaProjectName" {
Start-AutRun `
-asaNugetVersion $t_asaNugetVersion `
Expand All @@ -188,10 +187,22 @@ Describe "Start-AutRun parameter asaProjectName" {
Assert-MockCalled New-AutRunFixture -Times 1 -Exactly -Scope It
}

$t_asaProjectName = "X.X.X.ASA.ProjectName"
It "runs with dots in the asaProjectName" {
Start-AutRun `
-asaNugetVersion $t_asaNugetVersion `
-solutionPath $t_solutionPath `
-asaProjectName $t_asaProjectName `
-unittestFolder $t_unittestFolder |
Assert-MockCalled New-AutRunFixture -Times 1 -Exactly -Scope It
}
$t_asaProjectName = "bar"

It "fails without a asaProjectName" {
{Start-AutRun `
-asaNugetVersion $t_asaNugetVersion `
-solutionPath $t_solutionPath `
#-asaProjectName $t_asaProjectName `
-unittestFolder $t_unittestFolder} |
Should -throw "-asaProjectName is required"
}
Expand All @@ -203,9 +214,11 @@ Describe "Start-AutRun parameter asaProjectName" {
-solutionPath $t_solutionPath `
-asaProjectName $t_asaProjectName `
-unittestFolder $t_unittestFolder} |
Should -throw "Invalid -asaProjectName (3"
Should -throw "Invalid -asaProjectName ("
}

<#
# 1.0.9 - This is actually not necessary, the validation requirement are only applied on the Azure job, not the local project
$t_asaProjectName = " "
It "fails with an invalid asaProjectName (space)" {
{Start-AutRun `
Expand Down Expand Up @@ -245,6 +258,7 @@ Describe "Start-AutRun parameter asaProjectName" {
-unittestFolder $t_unittestFolder} |
Should -throw "Invalid -asaProjectName (3"
}
#>
}
}

Expand Down
5 changes: 4 additions & 1 deletion asa.unittest/Public/New-AutAsaprojXML.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function New-AutAsaprojXML{
$footer = "</Project>"
$itemGroupStart = "<ItemGroup>"
$itemGroupEnd = "</ItemGroup>"
$itemFilter = @("InputMock","JobConfig")
$itemFilter = @("InputMock","JobConfig","JSFunction")

################################################################################################################################
write-verbose "101 - Generating the XML asaproj"
Expand All @@ -67,6 +67,9 @@ function New-AutAsaprojXML{
# First ItemGroup for script file (asaql)
$targetAsaproj += $itemGroupStart + $newline
$targetAsaproj += "<Script Include=`"$($sourceAsaproj.startFile)`"/>" + $newline
$targetAsaproj += "<ScriptCode Include=`"$($sourceAsaproj.startFile).cs`">" + $newline
$targetAsaproj += "<DependentUpon>$($sourceAsaproj.startFile)</DependentUpon>" + $newline
$targetAsaproj += "</ScriptCode>" + $newline
$targetAsaproj += $itemGroupEnd + $newline

# Second ItemGroup for InputMock (local input config files) and JobConfig
Expand Down
10 changes: 5 additions & 5 deletions asa.unittest/Public/Start-AutRun.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ Function Start-AutRun{

if (-not (Test-Path $solutionPath)) {Throw "Invalid -solutionPath"}

if (-not (`
($asaProjectName -match '^[a-zA-Z0-9_-]+$') `
-and ($asaProjectName.Length -ge 3) `
-and ($asaProjectName.Length -le 63) `
)) {Throw "Invalid -asaProjectName (3-63 alp_ha-num)"}
if (-not (($asaProjectName.Length -ge 1)
# 1.0.9 - This is actually not necessary, the validation requirement are only applied on the Azure job, not the local project
#-and ($asaProjectName -match '^[a-zA-Z0-9_-]+$') `
#-and ($asaProjectName.Length -le 63) `
)) {Throw "Invalid -asaProjectName (empty string)"}

if (-not (Test-Path "$solutionPath\$unittestFolder\1_arrange")) {Throw "Can't find 1_arrange folder at $solutionPath\$unittestFolder\1_arrange"}

Expand Down
Binary file modified asa.unittest/asa.unittest.psd1
Binary file not shown.
22 changes: 20 additions & 2 deletions asa.unittest/private/New-AutRunFixture.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,16 @@ Function New-AutRunFixture{
New-Item -ItemType Directory |
Out-Null

## Copy .asaql, .asaproj (XML) and JobConfig, asaproj (JSON) required for run in each test case folder
## Create an ASA function folder in test case folder
$testFolders |
Select-Object @{Name = "Path"; Expression = {"$($_.Path)\$asaProjectName\Functions\"}} |
New-Item -ItemType Directory |
Out-Null

## Copy .asaql, .asaql.cs, .asaproj (XML) and JobConfig, asaproj (JSON) required for run in each test case folder
$testFolders |
Select-Object @{Name="Destination"; Expression = {"$($_.Path)\$asaProjectName\"}} |
Copy-Item -Path "$asaProjectPath\*.as*","$asaProjectPath\*.json" -recurse |
Copy-Item -Path "$asaProjectPath\*.as*","$asaProjectPath\*.cs","$asaProjectPath\*.json" -recurse |
Out-Null

## If there isn't a XML asaproj, generate it from the JSON one
Expand All @@ -98,6 +104,18 @@ Function New-AutRunFixture{
Copy-Item -Path "$asaProjectPath\Inputs\Local*.json" -recurse |
Out-Null

## Copy the local JS function files required for run in each test case folder
$testFolders |
Select-Object @{Name="Destination"; Expression = {"$($_.Path)\$asaProjectName\Functions\"}} |
Copy-Item -Path "$asaProjectPath\Functions\*.js" -recurse |
Out-Null

## Copy the local JS function definition files (JSON) required for run in each test case folder
$testFolders |
Select-Object @{Name="Destination"; Expression = {"$($_.Path)\$asaProjectName\Functions\"}} |
Copy-Item -Path "$asaProjectPath\Functions\*.js.json" -recurse |
Out-Null

## Copy test files from 1_arrange to each test case folder
$testDetails |
Select-Object `
Expand Down

0 comments on commit 22166bd

Please sign in to comment.