Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion eng/packages/http-client-csharp-mgmt/eng/scripts/Generate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ param(
)

Import-Module "$PSScriptRoot\Generation.psm1" -DisableNameChecking -Force;
Import-Module "$PSScriptRoot\Spector-Helper.psm1" -DisableNameChecking -Force;

$mgmtPackageRoot = Resolve-Path (Join-Path $PSScriptRoot '..' '..')
Write-Host "Mgmt Package root: $packageRoot" -ForegroundColor Cyan
Write-Host "Mgmt Package root: $mgmtPackageRoot" -ForegroundColor Cyan
$mgmtSolutionDir = Join-Path $mgmtPackageRoot 'generator'

if (-not $LaunchOnly) {
Expand Down Expand Up @@ -38,6 +39,43 @@ if (-not $LaunchOnly) {
}
}

$spectorRoot = Join-Path $mgmtPackageRoot 'generator' 'TestProjects' 'Spector'

$spectorLaunchProjects = @{}

foreach ($specFile in Get-Sorted-Specs) {
$subPath = Get-SubPath $specFile
$folders = $subPath.Split([System.IO.Path]::DirectorySeparatorChar)

if (-not (Compare-Paths $subPath $filter)) {
continue
}

$generationDir = $spectorRoot
foreach ($folder in $folders) {
$generationDir = Join-Path $generationDir $folder
}

# create the directory if it doesn't exist
if (-not (Test-Path $generationDir)) {
New-Item -ItemType Directory -Path $generationDir | Out-Null
}

Write-Host "Generating $subPath" -ForegroundColor Cyan

$spectorLaunchProjects.Add(($folders -join "-"), ("TestProjects/Spector/$($subPath.Replace([System.IO.Path]::DirectorySeparatorChar, '/'))"))
if ($LaunchOnly) {
continue
}

Invoke (Get-Mgmt-TspCommand $specFile $generationDir -debug:$Debug)

# exit if the generation failed
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
}

# only write new launch settings if no filter was passed in
if ($null -eq $filter) {
$mgmtSpec = "TestProjects/Local/Mgmt-TypeSpec"
Expand All @@ -50,6 +88,13 @@ if ($null -eq $filter) {
$mgmtLaunchSettings["profiles"]["Mgmt-TypeSpec"].Add("commandName", "Executable")
$mgmtLaunchSettings["profiles"]["Mgmt-TypeSpec"].Add("executablePath", "dotnet")

foreach ($kvp in $spectorLaunchProjects.GetEnumerator()) {
$mgmtLaunchSettings["profiles"].Add($kvp.Key, @{})
$mgmtLaunchSettings["profiles"][$kvp.Key].Add("commandLineArgs", "`$(SolutionDir)/../dist/generator/Microsoft.TypeSpec.Generator.dll `$(SolutionDir)/$($kvp.Value) -g MgmtStubGenerator")
$mgmtLaunchSettings["profiles"][$kvp.Key].Add("commandName", "Executable")
$mgmtLaunchSettings["profiles"][$kvp.Key].Add("executablePath", "dotnet")
}

$mgmtSortedLaunchSettings = @{}
$mgmtSortedLaunchSettings.Add("profiles", [ordered]@{})
$mgmtLaunchSettings["profiles"].Keys | Sort-Object | ForEach-Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ function Get-Mgmt-TspCommand {
}
$command += " --option @azure-typespec/http-client-csharp-mgmt.emitter-output-dir=$generationDir"
$command += " --option @azure-typespec/http-client-csharp-mgmt.save-inputs=true"
if ($generateStub) {
$command += " --option @azure-typespec/http-client-csharp-mgmt.plugin-name=AzureStubPlugin"
}

if ($apiVersion) {
$command += " --option @azure-typespec/http-client-csharp-mgmt.api-version=$apiVersion"
Expand Down
113 changes: 113 additions & 0 deletions eng/packages/http-client-csharp-mgmt/eng/scripts/Spector-Helper.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..')

# These are specs that are not yet building correctly with the management generator
# Add specs here as needed when they fail to build
$failingSpecs = @(
)

function Capitalize-FirstLetter {
param (
[string]$inputString
)

if ([string]::IsNullOrEmpty($inputString)) {
return $inputString
}

$firstChar = $inputString[0].ToString().ToUpper()
$restOfString = $inputString.Substring(1)

return $firstChar + $restOfString
}

function Get-Namespace {
param (
[string]$dir
)

$words = $dir.Split('-')
$namespace = ""
foreach ($word in $words) {
$namespace += Capitalize-FirstLetter $word
}
return $namespace
}

function IsValidSpecDir {
param (
[string]$fullPath
)
if (-not(Test-Path "$fullPath/main.tsp")){
return $false;
}

$subPath = Get-SubPath $fullPath

if ($failingSpecs.Contains($subPath)) {
Write-Host "Skipping $subPath" -ForegroundColor Yellow
return $false
}

return $true
}

function Get-Azure-Specs-Directory {
$packageRoot = Resolve-Path (Join-Path $PSScriptRoot '..' '..')
return Join-Path $packageRoot 'node_modules' '@azure-tools' 'azure-http-specs'
}

function Get-Sorted-Specs {
$azureSpecsDirectory = Get-Azure-Specs-Directory

# Only get azure resource-manager specs
$resourceManagerPath = Join-Path $azureSpecsDirectory "specs" "azure" "resource-manager"
$directories = @(Get-ChildItem -Path $resourceManagerPath -Directory -Recurse)

$sep = [System.IO.Path]::DirectorySeparatorChar
$pattern = "${sep}specs${sep}"

return $directories | Where-Object { IsValidSpecDir $_.FullName } | ForEach-Object {

# Pick client.tsp if it exists, otherwise main.tsp
$specFile = Join-Path $_.FullName "client.tsp"
if (-not (Test-Path $specFile)) {
$specFile = Join-Path $_.FullName "main.tsp"
}

# Extract the relative path after "specs/" and normalize slashes
$relativePath = ($specFile -replace '[\\\/]', '/').Substring($_.FullName.IndexOf($pattern) + $pattern.Length)

# Remove the filename to get just the directory path
$dirPath = $relativePath -replace '/[^/]+\.tsp$', ''

# Produce an object with the path for sorting
[PSCustomObject]@{
SpecFile = $specFile
DirPath = $dirPath
}
} | Sort-Object -Property @{Expression = { $_.DirPath -replace '/', '!' }; Ascending = $true} | ForEach-Object { $_.SpecFile }
}

function Get-SubPath {
param (
[string]$fullPath
)
$azureSpecsDirectory = Get-Azure-Specs-Directory

$subPath = $fullPath.Substring($azureSpecsDirectory.Length + 1)

# Keep consistent with the previous folder name because 'http' makes more sense then current 'specs'
$subPath = $subPath -replace '^specs', 'http'

# also strip off the spec file name if present
$leaf = Split-Path -Leaf $subPath
if ($leaf -like '*.tsp') {
return (Split-Path $subPath)
}

return $subPath
}

Export-ModuleMember -Function "Get-Namespace"
Export-ModuleMember -Function "Get-Sorted-Specs"
Export-ModuleMember -Function "Get-SubPath"
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#Requires -Version 7.0

param($filter)

Import-Module "$PSScriptRoot\Generation.psm1" -DisableNameChecking -Force;
Import-Module "$PSScriptRoot\Spector-Helper.psm1" -DisableNameChecking -Force;

$packageRoot = Resolve-Path (Join-Path $PSScriptRoot '..' '..')

Refresh-Mgmt-Build

$spectorRoot = Join-Path $packageRoot 'generator' 'TestProjects' 'Spector'
$spectorCsproj = Join-Path $packageRoot 'generator' 'TestProjects' 'Spector.Tests' 'TestProjects.Spector.Tests.csproj'

$coverageDir = Join-Path $packageRoot 'generator' 'artifacts' 'coverage'

if (-not (Test-Path $coverageDir)) {
New-Item -ItemType Directory -Path $coverageDir | Out-Null
}

foreach ($specFile in Get-Sorted-Specs) {
$subPath = Get-SubPath $specFile

# skip the HTTP root folder when computing the namespace filter
$folders = $subPath.Split([System.IO.Path]::DirectorySeparatorChar) | Select-Object -Skip 1

if (-not (Compare-Paths $subPath $filter)) {
continue
}

$testPath = Join-Path "$spectorRoot.Tests" "Http"
$testFilter = "TestProjects.Spector.Tests.Http"
foreach ($folder in $folders) {
$segment = "$(Get-Namespace $folder)"

# the test directory names match the test namespace names, but the source directory names will not have the leading underscore
# so check to see if the filter should contain a leading underscore by comparing with the test directory
if (-not (Test-Path (Join-Path $testPath $segment))) {
$testFilter += "._$segment"
$testPath = Join-Path $testPath "_$segment"
}
else{
$testFilter += ".$segment"
$testPath = Join-Path $testPath $segment
}
}

Write-Host "Regenerating $subPath" -ForegroundColor Cyan

$outputDir = Join-Path $spectorRoot $subPath

$command = Get-Mgmt-TspCommand $specFile $outputDir
Invoke $command

# exit if the generation failed
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}

Write-Host "Testing $subPath" -ForegroundColor Cyan
$command = "dotnet test $spectorCsproj --filter `"FullyQualifiedName~$testFilter`""
Invoke $command
# exit if the testing failed
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}

Write-Host "Restoring $subPath" -ForegroundColor Cyan

$command = "git clean -xfd $outputDir"
Invoke $command
# exit if the restore failed
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
$command = "git restore $outputDir"
Invoke $command
# exit if the restore failed
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using NUnit.Framework;

namespace TestProjects.Spector.Tests
{
[SetUpFixture]
public static class AssemblyCleanFixture
{
[OneTimeTearDown]
public static void RunOnAssemblyCleanUp()
{
SpectorServerSession.Start().Server?.Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using NUnit.Framework;

namespace TestProjects.Spector.Tests
{
public static class BinaryDataAssert
{
public static void AreEqual(BinaryData expected, BinaryData result)
{
CollectionAssert.AreEqual(expected?.ToArray(), result?.ToArray());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;

namespace TestProjects.Spector.Tests
{
[AttributeUsage(AttributeTargets.Assembly)]
internal sealed class BuildPropertiesAttribute : Attribute
{
public string RepoRoot { get; }
public string ArtifactsDirectory { get; }

public BuildPropertiesAttribute(string repoRoot, string artifactsDirectory)
{
RepoRoot = repoRoot;
ArtifactsDirectory = artifactsDirectory;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.ClientModel.Primitives;
using Azure.Generator.Management.Tests.Common;

namespace TestProjects.Spector.Tests.Infrastructure
{
public abstract class SpectorModelJsonTests<T> : SpectorModelTests<T> where T : IJsonModel<T>
{
[SpectorTest]
public void RoundTripWithJsonInterfaceOfTWire()
=> RoundTripTest("W", new JsonInterfaceStrategy<T>());

[SpectorTest]
public void RoundTripWithJsonInterfaceOfTJson()
=> RoundTripTest("J", new JsonInterfaceStrategy<T>());

[SpectorTest]
public void RoundTripWithJsonInterfaceNonGenericWire()
=> RoundTripTest("W", new JsonInterfaceAsObjectStrategy<T>());

[SpectorTest]
public void RoundTripWithJsonInterfaceNonGenericJson()
=> RoundTripTest("J", new JsonInterfaceAsObjectStrategy<T>());

[SpectorTest]
public void RoundTripWithJsonInterfaceUtf8ReaderWire()
=> RoundTripTest("W", new JsonInterfaceUtf8ReaderStrategy<T>());

[SpectorTest]
public void RoundTripWithJsonInterfaceUtf8ReaderJson()
=> RoundTripTest("J", new JsonInterfaceUtf8ReaderStrategy<T>());

[SpectorTest]
public void RoundTripWithJsonInterfaceUtf8ReaderNonGenericWire()
=> RoundTripTest("W", new JsonInterfaceUtf8ReaderAsObjectStrategy<T>());

[SpectorTest]
public void RoundTripWithJsonInterfaceUtf8ReaderNonGenericJson()
=> RoundTripTest("J", new JsonInterfaceUtf8ReaderAsObjectStrategy<T>());
}
}
Loading
Loading