diff --git a/eng/pipelines/libraries/deploy-networking-echo-test-servers.yml b/eng/pipelines/libraries/deploy-networking-echo-test-servers.yml new file mode 100644 index 00000000000000..c1bd5f5ffb4daa --- /dev/null +++ b/eng/pipelines/libraries/deploy-networking-echo-test-servers.yml @@ -0,0 +1,99 @@ +# This pipeline deploys the test servers we are using to run (outerloop) Functional tests for various functionality in System.Net namespace. +# The pipeline deploys to staging slots, which are available at +# - corefx-net-http11-staging.azurewebsites.net +# - corefx-net-http2-staging.azurewebsites.net +# +# Usage instructions: +# 1) Start pipeline at https://dev.azure.com/dnceng/internal/_build?definitionId=1419 ( +deploy-networking-echo-test-servers), pick the correct branch and start the build. +# 2) After pipeline succeeds, check your changes against the staging slots, two possible ways to do this are: +# - create a no-merge PR where you overwrite the default urls (e.g. https://github.com/dotnet/runtime/pull/111396) +# - test locally, either by same changes as in above PR, or by using the override environment variables +# +# DOTNET_TEST_HTTPHOST=http://corefx-net-http11-staging.azurewebsites.net +# DOTNET_TEST_SECUREHTTPHOST=https://corefx-net-http11-staging.azurewebsites.net +# DOTNET_TEST_WEBSOKETHOST=http://corefx-net-http11-staging.azurewebsites.net +# DOTNET_TEST_SECUREWEBSOKETHOST=http://corefx-net-http11-staging.azurewebsites.net +# +# DOTNET_TEST_HTTP2HOST=http://corefx-net-http2-staging.azurewebsites.net +# 3) If there are no issues, you can swap the staging slots with production slots via the Azure portal. +# Only the members of the .NET Networking team have access to the Azure Subscription which hosts the +# servers. Look for the "Deployment slots" section at corefx-net-http11 and corefx-net-http2 Web Apps + +trigger: none + +resources: + repositories: + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +variables: + - template: /eng/common/templates-official/variables/pool-providers.yml + - name: FrameworkVersion + value: 8.x + - name: TargetFramework + value: net8.0 + +extends: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates + parameters: + customBuildTags: + - 1ES.PT.ViaStartRight + pool: + name: $(DncEngInternalBuildPool) + image: 1es-windows-2022 + os: windows + + stages: + - stage: stage + displayName: Building in a VM + jobs: + - job: job + displayName: Build + steps: + - checkout: self + + - task: UseDotNet@2 + inputs: + packageType: "sdk" + version: $(FrameworkVersion) + + - script: echo {} > ./global.json + displayName: Bypass repository global.json + workingDirectory: ./src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer + + - script: dotnet publish -c Release /p:GenevaTelemetry=true /p:_TargetFrameworkForXHarness=$(TargetFramework) + workingDirectory: ./src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer + displayName: Run dotnet publish + + - task: zip@0 + displayName: Zip artifacts + inputs: + pathToZipFolder: 'artifacts\bin\NetCoreServer\Release\$(TargetFramework)\publish\' + pathToZipFile: 'artifacts\bin\NetCoreServer\Release\$(TargetFramework)\publish.zip' + + - task: AzureRmWebAppDeployment@4 + displayName: Deploy to corefx-net-http11-staging + inputs: + ConnectionType: "AzureRM" + azureSubscription: .NET Libraries Network Testing + appType: "webApp" + WebAppName: "corefx-net-http11" + deployToSlotOrASE: true + ResourceGroupName: "Production-WestUS" + SlotName: "staging" + package: 'artifacts\bin\NetCoreServer\Release\$(TargetFramework)\publish.zip' + + - task: AzureRmWebAppDeployment@4 + displayName: Deploy to corefx-net-http2-staging + inputs: + ConnectionType: "AzureRM" + azureSubscription: .NET Libraries Network Testing + appType: "webApp" + WebAppName: "corefx-net-http2" + deployToSlotOrASE: true + ResourceGroupName: "Production-WestUS" + SlotName: "staging" + package: 'artifacts\bin\NetCoreServer\Release\$(TargetFramework)\publish.zip' diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Directory.Build.props b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Directory.Build.props index 65a9a7c3bf4783..8b6a62bf6d7d27 100644 --- a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Directory.Build.props +++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Directory.Build.props @@ -4,4 +4,5 @@ + diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/GenericHandler.cs b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/GenericHandler.cs index c433a9edbcb76c..3731385df3bb27 100644 --- a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/GenericHandler.cs +++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/GenericHandler.cs @@ -19,6 +19,16 @@ public GenericHandler(RequestDelegate next) public async Task Invoke(HttpContext context) { PathString path = context.Request.Path; + if (path.Equals(new PathString("/swagger.json"))) + { + using (var stream = typeof(GenericHandler).Assembly.GetManifestResourceStream("NetCoreServer.swagger.json")) + { + context.Response.ContentType = "application/json"; + await stream.CopyToAsync(context.Response.Body); + } + return; + } + if (path.Equals(new PathString("/deflate.ashx"))) { await DeflateHandler.InvokeAsync(context); diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/NetCoreServer.csproj b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/NetCoreServer.csproj index a458eb3eeec5ed..d1c331b0aabcdb 100644 --- a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/NetCoreServer.csproj +++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/NetCoreServer.csproj @@ -16,11 +16,16 @@ - - - - - + + + + + + + + + + diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Startup.cs b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Startup.cs index 5eade747eb9d34..0dec43c28f5b82 100644 --- a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Startup.cs +++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Startup.cs @@ -10,10 +10,6 @@ using OpenTelemetry.Trace; using OpenTelemetry.Metrics; using OpenTelemetry.Exporter.Geneva; -using System.Diagnostics.Metrics; -using Microsoft.AspNetCore.Http; -using System.Threading.Tasks; -using System.Diagnostics; using System.Collections.Generic; #endif @@ -31,7 +27,8 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { #if GENEVA_TELEMETRY - services.AddOpenTelemetryMetrics((builder) => builder + services.AddOpenTelemetry() + .WithMetrics((builder) => builder .AddAspNetCoreInstrumentation() .AddGenevaMetricExporter(options => { diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/swagger.json b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/swagger.json new file mode 100644 index 00000000000000..8472a602b9bdc8 --- /dev/null +++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/swagger.json @@ -0,0 +1,294 @@ +{ + "openapi": "3.0.3", + "info": { + "title": ".NET Networking Echo Test Servers", + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://corefx-net-http11.azurewebsites.net/" + } + ], + "paths": { + "/deflate.ashx": { + "get": { + "summary": "Get DEFLATE compressed content", + "description": "Get DEFLATE compressed content", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "text/plain": { + "example": "Sending DEFLATE compressed" + } + } + } + } + } + }, + "/echo.ashx": { + "get": { + "summary": "Get request data echoed back", + "description": "Get request data echoed back", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestInformation" + } + } + } + } + } + } + }, + "/emptycontent.ashx": { + "get": { + "summary": "Get empty content back", + "description": "Get empty content back", + "responses": { + "200": { + "description": "Successful operation" + } + } + } + }, + "/gzip.ashx": { + "get": { + "summary": "Get gzip-compressed content", + "description": "Get gzip-compressed content", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "text/plain": { + "example": "Sending GZIP compressed" + } + } + } + } + } + }, + "/redirect.ashx": { + "get": { + "summary": "Get a redirect response", + "description": "get a redirect response", + "parameters": [ + { + "in": "query", + "name": "uri", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestInformation" + } + } + } + }, + "400": { + "description": "Failed operation" + } + } + } + }, + "/statuscode.ashx": { + "get": { + "summary": "Get a specific status code in response", + "description": "Get a specific status code in response", + "parameters": [ + { + "in": "query", + "name": "statuscode", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "in": "query", + "name": "statusdescription", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "delay", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Error parsing status code" + } + } + } + }, + "/version": { + "get": { + "summary": "Get version information", + "description": "Get version information", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "text/plain": { + "example": "Information for: NetCoreServer.dll\nLocation: C:\\home\\site\\wwwroot\nFramework: .NET 6.0.32\nFile Version: 1.0.0.0\nProduct Version: 1.0.0\nCreation Date: 4/11/2019 9:05:08 PM\nLast Modified: 2/28/2022 2:06:00 PM\n" + } + } + } + } + } + }, + "/test.ashx": { + "get": { + "summary": "Test endpoint", + "description": "Test endpoint", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "text/plain": { + "example": { + "Method": "GET", + "Url": "/test.ashx", + "Headers": { + "Accept": "text/plain", + "Accept-Encoding": "gzip, deflate, br, zstd", + "Accept-Language": "en-US,en;q=0.9,cs;q=0.8", + "Host": "corefx-net-http11.azurewebsites.net", + "Max-Forwards": "10", + "Referer": "https://editor-next.swagger.io/", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0", + "Origin": "https://editor-next.swagger.io", + "sec-ch-ua-platform": "\"Windows\"", + "sec-ch-ua": "\"Microsoft Edge\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"", + "sec-ch-ua-mobile": "?0", + "Sec-Fetch-Site": "cross-site", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Dest": "empty", + "X-ARR-LOG-ID": "46cb3aaa-9ad7-44b1-b284-a492ded947ed", + "CLIENT-IP": "167.220.196.35:19180", + "DISGUISED-HOST": "corefx-net-http11.azurewebsites.net", + "X-SITE-DEPLOYMENT-ID": "corefx-net-http11", + "WAS-DEFAULT-HOSTNAME": "corefx-net-http11.azurewebsites.net", + "X-Forwarded-Proto": "https", + "X-AppService-Proto": "https", + "X-ARR-SSL": "2048|256|CN=Microsoft Azure RSA TLS Issuing CA 08, O=Microsoft Corporation, C=US|CN=*.azurewebsites.net, O=Microsoft Corporation, L=Redmond, S=WA, C=US", + "X-Forwarded-TlsVersion": "1.3", + "X-Forwarded-For": "167.220.196.35:19180", + "X-Original-URL": "/test.ashx", + "X-WAWS-Unencoded-URL": "/test.ashx" + }, + "Cookies": {}, + "BodyContent": "", + "BodyLength": 0, + "SecureConnection": true, + "ClientCertificatePresent": false, + "ClientCertificate": null + } + } + }, + "headers": { + "Content-MD5": { + "schema": { + "type": "string" + }, + "description": "Base64-encoded MD5 hash of the response content" + } + } + } + } + } + }, + "/large.ashx": { + "get": { + "summary": "Get a large response", + "description": "Get a large response", + "parameters": [ + { + "in": "query", + "name": "size", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/octet-stream": { + "schema": { + "type": "array" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "RequestInformation": { + "type": "object", + "properties": { + "Method": { + "type": "string", + "example": "GET" + }, + "Url": { + "type": "string", + "format": "uri", + "example": "/echo.ashx" + }, + "Headers": { + "type": "object" + }, + "Cookies": { + "type": "object" + }, + "BodyContent": { + "type": "string" + }, + "BodyLength": { + "type": "integer" + }, + "SecureConnection": { + "type": "boolean" + }, + "ClientCertificatePresent": { + "type": "boolean" + }, + "ClientCertificate": { + "type": "object" + } + } + } + } + } +} \ No newline at end of file