From a8a27c9cfe800aab5b47e843971f29588706ccb6 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Tue, 16 Jul 2024 20:13:44 +0000 Subject: [PATCH 01/32] feat(): onboard Azure.Developer.MicrosoftPlaywrightTesting sdk --- .github/CODEOWNERS | 2 +- eng/Packages.Data.props | 9 + eng/service.proj | 1 + ...loper.MicrosoftPlaywrightTesting.NUnit.sln | 22 + .../CHANGELOG.md | 0 .../Directory.Build.props | 6 + .../README.md | 0 ...tPlaywrightTesting.NUnit.netstandard2.0.cs | 13 + .../.runsettings | 15 + .../PlaywrightServiceSetup.cs | 6 + .../PlaywrightTests.csproj | 26 + .../customising-service-parameters/README.md | 0 .../UnitTest1.cs | 35 + .../.runsettings | 12 + .../PlaywrightServiceSetup.cs | 6 + .../PlaywrightTests.csproj | 26 + .../README.md | 0 .../UnitTest1.cs | 35 + .../samples/using-manual-launch/.runsettings | 9 + .../PlaywrightServiceSetup.cs | 6 + .../PlaywrightTests.csproj | 26 + .../samples/using-manual-launch/README.md | 0 .../samples/using-manual-launch/UnitTest1.cs | 49 + ...er.MicrosoftPlaywrightTesting.NUnit.csproj | 18 + .../src/PlaywrightServiceNUnit.cs | 57 + ...e.Developer.MicrosoftPlaywrightTesting.sln | 28 + .../CHANGELOG.md | 18 + .../Directory.Build.props | 6 + .../README.md | 0 ...wrightTesting.TestLogger.netstandard2.0.cs | 72 + .../src/AssemblyInfo.cs | 7 + ...eveloper.MicrosoftPlaywrightTesting.csproj | 26 + .../src/ConnectOptions.cs | 51 + .../src/Constants.cs | 195 ++ .../src/EntraLifecycle.cs | 78 + .../src/PlaywrightService.cs | 253 ++ .../src/PlaywrightServiceSettings.cs | 106 + .../TestLogger/Client/TestReportingClient.cs | 2553 +++++++++++++++++ .../src/TestLogger/Model/CIInfo.cs | 17 + .../src/TestLogger/Model/MPTResult.cs | 44 + .../src/TestLogger/PlaywrightReporter.cs | 689 +++++ .../src/TestLogger/Utility/CiInfoProvider.cs | 112 + .../src/TestLogger/Utility/Constants.cs | 46 + .../src/TestLogger/Utility/Logger.cs | 25 + ...er.MicrosoftPlaywrightTesting.Tests.csproj | 22 + .../tests/EntraLifecycleTests.cs | 201 ++ .../tests/PlaywrightServiceSettingsTest.cs | 87 + .../tests/PlaywrightServiceTests.cs | 660 +++++ 48 files changed, 5674 insertions(+), 1 deletion(-) create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.sln create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Directory.Build.props create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/.runsettings create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightServiceSetup.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightTests.csproj create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/.runsettings create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightServiceSetup.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightTests.csproj create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/.runsettings create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightServiceSetup.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightTests.csproj create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/README.md create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Azure.Developer.MicrosoftPlaywrightTesting.sln create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Directory.Build.props create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/AssemblyInfo.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClient.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/CIInfo.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/CiInfoProvider.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Logger.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 349974ecafcf..5527508b4ad9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -733,7 +733,7 @@ # ServiceOwners: @rhurey @dargilco # PRLabel: %Playwright -/sdk/playwrighttesting/ @shreyaanand @mjmadhu +/sdk/playwrighttesting/ @Sid200026 @puagarwa @vvs11 @ShreyaAnand # ServiceLabel: %Playwright # ServiceOwners: @shreyaanand @mjmadhu diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index be343287cbc9..d4b846b64df5 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -384,6 +384,15 @@ + + + + + + + + + 1.0.0-dev.20240619.2 diff --git a/eng/service.proj b/eng/service.proj index bc473731f3f1..6a7ee156d116 100644 --- a/eng/service.proj +++ b/eng/service.proj @@ -43,6 +43,7 @@ + diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.sln b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.sln new file mode 100644 index 000000000000..9cc262f01b3b --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Developer.MicrosoftPlaywrightTesting.NUnit", "src\Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj", "{CF3C8F52-D3FD-4338-9432-58FF4BF4475E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF3C8F52-D3FD-4338-9432-58FF4BF4475E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF3C8F52-D3FD-4338-9432-58FF4BF4475E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF3C8F52-D3FD-4338-9432-58FF4BF4475E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF3C8F52-D3FD-4338-9432-58FF4BF4475E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Directory.Build.props b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Directory.Build.props new file mode 100644 index 000000000000..63bd836ad44b --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Directory.Build.props @@ -0,0 +1,6 @@ + + + + diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs new file mode 100644 index 000000000000..abc3972b899c --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs @@ -0,0 +1,13 @@ +namespace Azure.Developer.MicrosoftPlaywrightTesting.NUnit +{ + [NUnit.Framework.SetUpFixtureAttribute] + public partial class PlaywrightServiceNUnit : Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightService + { + public static Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceSettings playwrightServiceSettings; + public PlaywrightServiceNUnit(Azure.Core.TokenCredential? tokenCredential = null) : base (default(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceSettings), default(Azure.Core.TokenCredential)) { } + [NUnit.Framework.OneTimeSetUpAttribute] + public System.Threading.Tasks.Task SetupAsync() { throw null; } + [NUnit.Framework.OneTimeTearDownAttribute] + public void Teardown() { } + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/.runsettings b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/.runsettings new file mode 100644 index 000000000000..0b1d6bb95e58 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/.runsettings @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightServiceSetup.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightServiceSetup.cs new file mode 100644 index 000000000000..d800c8ace326 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightServiceSetup.cs @@ -0,0 +1,6 @@ +using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; + +namespace PlaywrightTests; + +[SetUpFixture] +public class PlaywrightServiceSetup : PlaywrightServiceNUnit; \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightTests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightTests.csproj new file mode 100644 index 000000000000..dd3f8b888457 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightTests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + enable + enable + false + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs new file mode 100644 index 000000000000..f37d1f2ae33d --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs @@ -0,0 +1,35 @@ +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.Playwright; +using Microsoft.Playwright.NUnit; +using NUnit.Framework; + +namespace PlaywrightTests; + +[Parallelizable(ParallelScope.Self)] +[TestFixture] +public class ExampleTest : PageTest +{ + [Test] + [Category("Live")] + public async Task HasTitle() + { + await Page.GotoAsync("https://playwright.dev"); + + // Expect a title "to contain" a substring. + await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); + } + + [Test] + [Category("Live")] + public async Task GetStartedLink() + { + await Page.GotoAsync("https://playwright.dev"); + + // Click the get started link. + await Page.GetByRole(AriaRole.Link, new() { Name = "Get started" }).ClickAsync(); + + // Expects page to have a heading with the name of Installation. + await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Installation" })).ToBeVisibleAsync(); + } +} \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/.runsettings b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/.runsettings new file mode 100644 index 000000000000..5a52509978ff --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/.runsettings @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightServiceSetup.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightServiceSetup.cs new file mode 100644 index 000000000000..d800c8ace326 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightServiceSetup.cs @@ -0,0 +1,6 @@ +using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; + +namespace PlaywrightTests; + +[SetUpFixture] +public class PlaywrightServiceSetup : PlaywrightServiceNUnit; \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightTests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightTests.csproj new file mode 100644 index 000000000000..dd3f8b888457 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightTests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + enable + enable + false + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs new file mode 100644 index 000000000000..f37d1f2ae33d --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs @@ -0,0 +1,35 @@ +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.Playwright; +using Microsoft.Playwright.NUnit; +using NUnit.Framework; + +namespace PlaywrightTests; + +[Parallelizable(ParallelScope.Self)] +[TestFixture] +public class ExampleTest : PageTest +{ + [Test] + [Category("Live")] + public async Task HasTitle() + { + await Page.GotoAsync("https://playwright.dev"); + + // Expect a title "to contain" a substring. + await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); + } + + [Test] + [Category("Live")] + public async Task GetStartedLink() + { + await Page.GotoAsync("https://playwright.dev"); + + // Click the get started link. + await Page.GetByRole(AriaRole.Link, new() { Name = "Get started" }).ClickAsync(); + + // Expects page to have a heading with the name of Installation. + await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Installation" })).ToBeVisibleAsync(); + } +} \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/.runsettings b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/.runsettings new file mode 100644 index 000000000000..b2b09c4ebf83 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/.runsettings @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightServiceSetup.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightServiceSetup.cs new file mode 100644 index 000000000000..d800c8ace326 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightServiceSetup.cs @@ -0,0 +1,6 @@ +using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; + +namespace PlaywrightTests; + +[SetUpFixture] +public class PlaywrightServiceSetup : PlaywrightServiceNUnit; \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightTests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightTests.csproj new file mode 100644 index 000000000000..dd3f8b888457 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightTests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + enable + enable + false + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs new file mode 100644 index 000000000000..173f459a32ec --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs @@ -0,0 +1,49 @@ +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.Playwright; +using Microsoft.Playwright.NUnit; +using NUnit.Framework; +using Azure.Developer.MicrosoftPlaywrightTesting; + +namespace PlaywrightTests; + +[Parallelizable(ParallelScope.Self)] +[TestFixture] +public class Tests +{ + private IPlaywright _playwright; + private IBrowser _browser; + public IPage _page; + + [SetUp] + public async Task PageSetup() + { + _playwright = await Playwright.CreateAsync(); + + // Old code + //Browser = await _playwright.Chromium.LaunchAsync(); + + // New code + var playwrightService = new PlaywrightService(); + var connectOptions = await playwrightService.GetConnectOptionsAsync(os: ServiceOs.LINUX, runId: $"Manual Launch - {DateTime.UtcNow}"); + _browser = await _playwright.Chromium.ConnectAsync(connectOptions.WsEndpoint!, connectOptions.Options!); + // End new code + + _page = await _browser.NewPageAsync(); + } + + [TearDown] + public async Task PageTeardown() + { + await _page.CloseAsync(); + await _browser.CloseAsync(); + _playwright.Dispose(); + } + + [Test] + [Category("Live")] + public async Task HasTitle() + { + await _page.GotoAsync("https://playwright.dev"); + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj new file mode 100644 index 000000000000..a8145ca5fbd6 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj @@ -0,0 +1,18 @@ + + + Azure, Cloud, Playwright, Playwright Service, Reporting, Playwright Testing + + Package to integrate your Playwright test suite with Microsoft Playwright Testing + service + + 1.0.0-beta.1 + true + $(RequiredTargetFrameworks) + enable + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs new file mode 100644 index 000000000000..48718edd616a --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core; +using NUnit.Framework; +using System.Threading.Tasks; +using Azure.Developer.MicrosoftPlaywrightTesting; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.NUnit; + +/// +/// NUnit setup fixture to initialize Playwright Service. +/// +[SetUpFixture] +public class PlaywrightServiceNUnit : PlaywrightService +{ + /// + /// Initializes a new instance of the class. + /// + /// The azure token credential to use for authentication. + public PlaywrightServiceNUnit(TokenCredential? tokenCredential = null) + : base(playwrightServiceSettings, tokenCredential: tokenCredential) + { + } + + /// + /// Creates a new instance of based on the runsettings file. + /// + public static PlaywrightServiceSettings playwrightServiceSettings = new( + os: TestContext.Parameters.Get(RunSettingKey.OS), + runId: TestContext.Parameters.Get(RunSettingKey.RUN_ID), + exposeNetwork: TestContext.Parameters.Get(RunSettingKey.EXPOSE_NETWORK), + defaultAuth: TestContext.Parameters.Get(RunSettingKey.DEFAULT_AUTH), + useCloudHostedBrowsers: TestContext.Parameters.Get(RunSettingKey.USE_CLOUD_HOSTED_BROWSERS), + azureTokenCredentialType: TestContext.Parameters.Get(RunSettingKey.AZURE_TOKEN_CREDENTIAL_TYPE), + managedIdentityClientId: TestContext.Parameters.Get(RunSettingKey.MANAGED_IDENTITY_CLIENT_ID) + ); + + /// + /// Setup the resources utilized by Playwright service. + /// + /// + [OneTimeSetUp] + public async Task SetupAsync() + { + await InitializeAsync().ConfigureAwait(false); + } + + /// + /// Tear down resources utilized by Playwright service. + /// + [OneTimeTearDown] + public void Teardown() + { + Cleanup(); + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Azure.Developer.MicrosoftPlaywrightTesting.sln b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Azure.Developer.MicrosoftPlaywrightTesting.sln new file mode 100644 index 000000000000..fdf740cc6ede --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Azure.Developer.MicrosoftPlaywrightTesting.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Developer.MicrosoftPlaywrightTesting", "src\Azure.Developer.MicrosoftPlaywrightTesting.csproj", "{2C1F9880-AD7D-433E-A73E-43F503772CD8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Developer.MicrosoftPlaywrightTesting.Tests", "tests\Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj", "{6C78D318-9B96-43B4-97A7-7B3C8088983C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2C1F9880-AD7D-433E-A73E-43F503772CD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C1F9880-AD7D-433E-A73E-43F503772CD8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C1F9880-AD7D-433E-A73E-43F503772CD8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C1F9880-AD7D-433E-A73E-43F503772CD8}.Release|Any CPU.Build.0 = Release|Any CPU + {6C78D318-9B96-43B4-97A7-7B3C8088983C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C78D318-9B96-43B4-97A7-7B3C8088983C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C78D318-9B96-43B4-97A7-7B3C8088983C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C78D318-9B96-43B4-97A7-7B3C8088983C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md new file mode 100644 index 000000000000..736ac995d2b7 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md @@ -0,0 +1,18 @@ +# 1.0.0-beta.1 (2024-07-31) + +## Added + +- **Initial release of the package**: This is the first version of the Microsoft Playwright Testing service package. It enables you to integrate your Playwright test suite with the Microsoft Playwright Testing service. +- The service package enables you to: + - Expedite your Playwright test suite by running more tests in parallel on cloud-hosted browsers. + - Improve test coverage by enabling you to test on multiple OS-browser combinations. + - Troubleshoot easily and faster by publishing test results and artifacts generated by Playwright to the service and viewing them in the service portal. + +## Useful Links +- [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart) +- [Quickstart: Set up continuous end-to-end testing across different browsers and operating systems](https://aka.ms/mpt/ci) +- [Explore features and benefits](https://aka.ms/mpt/about) +- [View Microsoft Playwright Testing service demo](https://youtu.be/GenC1jAeTZE) +- [Documentation](https://aka.ms/mpt/docs) +- [Pricing](https://aka.ms/mpt/pricing) +- [Share feedback](https://aka.ms/mpt/feedback) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Directory.Build.props b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Directory.Build.props new file mode 100644 index 000000000000..63bd836ad44b --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Directory.Build.props @@ -0,0 +1,6 @@ + + + + diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs new file mode 100644 index 000000000000..79047844ccc8 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs @@ -0,0 +1,72 @@ +namespace Azure.Developer.MicrosoftPlaywrightTesting +{ + public partial class AzureTokenCredentialType + { + public static readonly string AzureCliCredential; + public static readonly string AzureDeveloperCliCredential; + public static readonly string AzurePowerShellCredential; + public static readonly string DefaultAzureCredential; + public static readonly string EnvironmentCredential; + public static readonly string InteractiveBrowserCredential; + public static readonly string ManagedIdentityCredential; + public static readonly string SharedTokenCacheCredential; + public static readonly string VisualStudioCodeCredential; + public static readonly string VisualStudioCredential; + public static readonly string WorkloadIdentityCredential; + public AzureTokenCredentialType() { } + } + public partial class ConnectOptions where T : class, new() + { + public T? Options; + public string? WsEndpoint; + public ConnectOptions() { } + } + public partial class PlaywrightService + { + public PlaywrightService(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceSettings playwrightServiceSettings, Azure.Core.TokenCredential? tokenCredential = null) { } + public PlaywrightService(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = default(bool?), Azure.Core.TokenCredential? tokenCredential = null) { } + public string DefaultAuth { get { throw null; } set { } } + public System.Threading.Timer? RotationTimer { get { throw null; } set { } } + public static string? ServiceEndpoint { get { throw null; } } + public bool UseCloudHostedBrowsers { get { throw null; } set { } } + public void Cleanup() { } + public System.Threading.Tasks.Task> GetConnectOptionsAsync(string? os = null, string? runId = null, string? exposeNetwork = null) where T : class, new() { throw null; } + public System.Threading.Tasks.Task InitializeAsync() { throw null; } + } + public partial class PlaywrightServiceSettings + { + public PlaywrightServiceSettings(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) { } + } + public partial class RunSettingKey + { + public static readonly string AZURE_TOKEN_CREDENTIAL_TYPE; + public static readonly string DEFAULT_AUTH; + public static readonly string EXPOSE_NETWORK; + public static readonly string MANAGED_IDENTITY_CLIENT_ID; + public static readonly string OS; + public static readonly string RUN_ID; + public static readonly string USE_CLOUD_HOSTED_BROWSERS; + public RunSettingKey() { } + } + public partial class ServiceAuth + { + public static readonly string ENTRA; + public static readonly string TOKEN; + public ServiceAuth() { } + } + public partial class ServiceEnvironmentVariable + { + public static readonly string PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE; + public static readonly string PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE; + public static readonly string PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE; + public static readonly string PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE; + public static readonly string PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE; + public ServiceEnvironmentVariable() { } + } + public partial class ServiceOs + { + public static readonly string LINUX; + public static readonly string WINDOWS; + public ServiceOs() { } + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/AssemblyInfo.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/AssemblyInfo.cs new file mode 100644 index 000000000000..a3e47e75d0c2 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/AssemblyInfo.cs @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Azure.Developer.MicrosoftPlaywrightTesting.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj new file mode 100644 index 000000000000..255126708467 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj @@ -0,0 +1,26 @@ + + + Azure.Developer.MicrosoftPlaywrightTesting + Azure.Developer.MicrosoftPlaywrightTesting + Azure.Developer.MicrosoftPlaywrightTesting + + Azure.Developer.MicrosoftPlaywrightTesting.TestLogger + Azure, Cloud, Playwright, Playwright Service, Reporting, Playwright Testing + + Package to integrate your Playwright test suite with Microsoft Playwright Testing + service + + 1.0.0-beta.1 + true + $(RequiredTargetFrameworks) + enable + + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs new file mode 100644 index 000000000000..609f8143a185 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; + +namespace Azure.Developer.MicrosoftPlaywrightTesting; + +/// +/// Represents the connect options for a generic type. +/// +/// The type parameter. +public class ConnectOptions where T : class, new() +{ + /// + /// A browser websocket endpoint to connect to. + /// + public string? WsEndpoint; + /// + /// Connect options for the service. + /// + public T? Options; +} + +internal class BrowserConnectOptions +{ + public string? ExposeNetwork { get; set; } + public IEnumerable>? Headers { get; set; } + public float? SlowMo { get; set; } + public float? Timeout { get; set; } +} + +internal static class BrowserConnectOptionsConverter +{ + public static T Convert(object source) where T : class, new() + { + var target = new T(); + System.Type sourceType = source.GetType(); + System.Type targetType = typeof(T); + + foreach (System.Reflection.PropertyInfo? sourceProperty in sourceType.GetProperties()) + { + System.Reflection.PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name); + if (targetProperty != null && targetProperty.CanWrite) + { + targetProperty.SetValue(target, sourceProperty.GetValue(source)); + } + } + + return target; + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs new file mode 100644 index 000000000000..f41be08719cd --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Developer.MicrosoftPlaywrightTesting; + +/// +/// Contains environment variable names used by the Playwright service. +/// +public class ServiceEnvironmentVariable +{ + /// + /// The environment variable for the Playwright service access token. + /// + public static readonly string PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_ACCESS_TOKEN"; + + /// + /// The environment variable for the Playwright service URL. + /// + public static readonly string PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_URL"; + + /// + /// The environment variable for exposing the Playwright service network. + /// + public static readonly string PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_EXPOSE_NETWORK"; + + /// + /// The environment variable for the Playwright service operating system. + /// + public static readonly string PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_OS"; + + /// + /// The environment variable for the Playwright service run ID. + /// + public static readonly string PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_RUN_ID"; +}; + +/// +/// Contains constants for supported operating systems on Microsoft Playwright Testing. +/// +public class ServiceOs +{ + /// + /// Linux operating system. + /// + public static readonly string LINUX = "linux"; + + /// + /// Windows operating system. + /// + public static readonly string WINDOWS = "windows"; +}; + +/// +/// Contains constants for authentication methods. +/// +public class ServiceAuth +{ + /// + /// Entra ID authentication method. + /// + public static readonly string ENTRA = "ENTRA"; + + /// + /// Service token authentication method. + /// + public static readonly string TOKEN = "TOKEN"; +}; + +/// +/// Contains constants for Azure token credential types. +/// +public class AzureTokenCredentialType +{ + /// + /// Environment Credential. + /// + public static readonly string EnvironmentCredential = "EnvironmentCredential"; + + /// + /// Workload Identity Credential. + /// + public static readonly string WorkloadIdentityCredential = "WorkloadIdentityCredential"; + + /// + /// Managed Identity Credential. + /// + public static readonly string ManagedIdentityCredential = "ManagedIdentityCredential"; + + /// + /// Shared Token Cache Credential. + /// + public static readonly string SharedTokenCacheCredential = "SharedTokenCacheCredential"; + + /// + /// Visual Studio Credential. + /// + public static readonly string VisualStudioCredential = "VisualStudioCredential"; + + /// + /// Visual Studio Code Credential. + /// + public static readonly string VisualStudioCodeCredential = "VisualStudioCodeCredential"; + + /// + /// Azure CLI Credential. + /// + public static readonly string AzureCliCredential = "AzureCliCredential"; + + /// + /// Azure PowerShell Credential. + /// + public static readonly string AzurePowerShellCredential = "AzurePowerShellCredential"; + + /// + /// Azure Developer CLI Credential. + /// + public static readonly string AzureDeveloperCliCredential = "AzureDeveloperCliCredential"; + + /// + /// Interactive Browser Credential. + /// + public static readonly string InteractiveBrowserCredential = "InteractiveBrowserCredential"; + + /// + /// Default Azure Credential. + /// + public static readonly string DefaultAzureCredential = "DefaultAzureCredential"; +} + +/// +/// Contains constants for run setting keys. +/// +public class RunSettingKey +{ + /// + /// The operating system setting key. + /// + public static readonly string OS = "Os"; + + /// + /// The run ID setting key. + /// + public static readonly string RUN_ID = "RunId"; + + /// + /// The expose network setting key. + /// + public static readonly string EXPOSE_NETWORK = "ExposeNetwork"; + + /// + /// The default authentication setting key. + /// + public static readonly string DEFAULT_AUTH = "DefaultAuth"; + + /// + /// The use cloud-hosted browsers setting key. + /// + public static readonly string USE_CLOUD_HOSTED_BROWSERS = "UseCloudHostedBrowsers"; + + /// + /// The Azure token credential type setting key. + /// + public static readonly string AZURE_TOKEN_CREDENTIAL_TYPE = "AzureTokenCredentialType"; + + /// + /// The managed identity client ID setting key. + /// + public static readonly string MANAGED_IDENTITY_CLIENT_ID = "ManagedIdentityClientId"; +} + +internal class Constants +{ + // Default constants + internal static readonly string s_default_os = ServiceOs.LINUX; + internal static readonly string s_default_expose_network = ""; + + // Entra id access token constants + internal static readonly int s_entra_access_token_lifetime_left_threshold_in_minutes_for_rotation = 15; + internal static readonly string[] s_entra_access_token_scopes = new string[] { "https://management.core.windows.net/.default" }; + internal static readonly int s_entra_access_token_rotation_interval_period_in_minutes = 4; + + // Service constants + internal static readonly string s_api_version = "2023-10-01-preview"; + + // Error messages + internal static readonly string s_no_service_endpoint_error_message = "Please set PLAYWRIGHT_SERVICE_URL in your environment variables."; + internal static readonly string s_service_endpoint_removed_since_scalable_execution_disabled_error_message = "GetConnectOptionsAsync() method cannot be used when disableScalableExecution is set to true in the setup file."; + internal static readonly string s_no_auth_error = "Could not authenticate with the service. Please refer to https://aka.ms/mpt/authentication for more information."; + internal static readonly string s_invalid_mpt_pat_error = "The service PAT set in the environment variable is invalid."; + internal static readonly string s_expired_mpt_pat_error = "The service PAT has expired. Please create a new PAT."; + + internal static readonly string s_playwright_service_disable_scalable_execution_environment_variable = "PLAYWRIGHT_SERVICE_DISABLE_SCALABLE_EXECUTION"; + internal static readonly string s_playwright_service_reporting_url_environment_variable = "PLAYWRIGHT_SERVICE_REPORTING_URL"; + internal static readonly string s_playwright_service_workspace_id_environment_variable = "PLAYWRIGHT_SERVICE_WORKSPACE_ID"; +} \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs new file mode 100644 index 000000000000..f3a55e468098 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Identity; +using Microsoft.IdentityModel.JsonWebTokens; + +namespace Azure.Developer.MicrosoftPlaywrightTesting; + +internal class EntraLifecycle +{ + internal string? _entraIdAccessToken; + internal long? _entraIdAccessTokenExpiry; + private readonly TokenCredential _tokenCredential; + private readonly JsonWebTokenHandler _jsonWebTokenHandler; + + public EntraLifecycle(TokenCredential? tokenCredential = null, JsonWebTokenHandler? jsonWebTokenHandler = null) + { + _tokenCredential = tokenCredential ?? new DefaultAzureCredential(); + _jsonWebTokenHandler = jsonWebTokenHandler ?? new JsonWebTokenHandler(); + SetEntraIdAccessTokenFromEnvironment(); + } + + internal async Task FetchEntraIdAccessTokenAsync() + { + try + { + var tokenRequestContext = new TokenRequestContext(Constants.s_entra_access_token_scopes); + AccessToken accessToken = await _tokenCredential.GetTokenAsync(tokenRequestContext, default).ConfigureAwait(false); + _entraIdAccessToken = accessToken.Token; + _entraIdAccessTokenExpiry = accessToken.ExpiresOn.ToUnixTimeSeconds(); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, _entraIdAccessToken); + return true; + } + catch (Exception ex) + { + Console.Error.WriteLine(ex); + return false; + } + } + + internal bool DoesEntraIdAccessTokenRequireRotation() + { + if (string.IsNullOrEmpty(_entraIdAccessToken)) + { + return true; + } + var lifetimeLeft = _entraIdAccessTokenExpiry - DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + return lifetimeLeft < Constants.s_entra_access_token_lifetime_left_threshold_in_minutes_for_rotation * 60; + } + + private void SetEntraIdAccessTokenFromEnvironment() + { + try + { + var token = Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE); + JsonWebToken jsonWebToken = _jsonWebTokenHandler.ReadJsonWebToken(token); + jsonWebToken.TryGetClaim( + "aid", + out System.Security.Claims.Claim? aidClaim + ); + jsonWebToken.TryGetClaim( + "accountId", + out System.Security.Claims.Claim? accountIdClaim + ); + if (aidClaim != null || accountIdClaim != null) + return; // MPT Token + var expiry = (long)(jsonWebToken.ValidTo - new DateTime(1970, 1, 1)).TotalSeconds; + _entraIdAccessToken = token; + _entraIdAccessTokenExpiry = expiry; + } + catch (Exception) + { + } + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs new file mode 100644 index 000000000000..64daf6f14b30 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -0,0 +1,253 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core; +using Microsoft.IdentityModel.JsonWebTokens; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace Azure.Developer.MicrosoftPlaywrightTesting; + +/// +/// Sets up and manages the Playwright service. +/// +public class PlaywrightService +{ + /// + /// Gets or sets the default authentication mechanism. + /// + public string DefaultAuth { get; set; } = ServiceAuth.ENTRA; + /// + /// Gets or sets a flag indicating whether to use cloud-hosted browsers. + /// + public bool UseCloudHostedBrowsers { get; set; } = true; + /// + /// Gets or sets the rotation timer for the Playwright service. + /// + public Timer? RotationTimer { get; set; } + /// + /// Gets the service endpoint for the Playwright service. + /// + public static string? ServiceEndpoint => Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE); + + private readonly EntraLifecycle? _entraLifecycle; + private readonly JsonWebTokenHandler? _jsonWebTokenHandler; + + /// + /// Initializes a new instance of the class. + /// + /// + /// + public PlaywrightService(PlaywrightServiceSettings playwrightServiceSettings, TokenCredential? tokenCredential = null) : this( + os: playwrightServiceSettings.Os, + runId: playwrightServiceSettings.RunId, + exposeNetwork: playwrightServiceSettings.ExposeNetwork, + defaultAuth: playwrightServiceSettings.DefaultAuth, + useCloudHostedBrowsers: playwrightServiceSettings.UseCloudHostedBrowsers, + tokenCredential: tokenCredential ?? playwrightServiceSettings.AzureTokenCredential + ) + { + // No-op + } + + /// + /// Initializes a new instance of the class. + /// + /// The operating system. + /// The run ID. + /// The network exposure. + /// The default authentication mechanism. + /// Whether to use cloud-hosted browsers. + /// The token credential. + public PlaywrightService(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, TokenCredential? tokenCredential = null) + { + if (string.IsNullOrEmpty(ServiceEndpoint)) + return; + _entraLifecycle = new EntraLifecycle(tokenCredential: tokenCredential); + _jsonWebTokenHandler = new JsonWebTokenHandler(); + InitializePlaywrightServiceEnvironmentVariables(os, runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); + } + + internal PlaywrightService(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, EntraLifecycle? entraLifecycle = null, JsonWebTokenHandler? jsonWebTokenHandler = null, TokenCredential? tokenCredential = null) + { + if (string.IsNullOrEmpty(ServiceEndpoint)) + return; + _entraLifecycle = entraLifecycle ?? new EntraLifecycle(tokenCredential); + _jsonWebTokenHandler = jsonWebTokenHandler ?? new JsonWebTokenHandler(); + InitializePlaywrightServiceEnvironmentVariables(os, runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); + } + + /// + /// Gets the connect options for connecting to Playwright Service's cloud hosted browsers. + /// + /// The type of the connect options. + /// The operating system. + /// The run ID. + /// The network exposure. + /// The connect options. + public async Task> GetConnectOptionsAsync(string? os = null, string? runId = null, string? exposeNetwork = null) where T : class, new() + { + if (Environment.GetEnvironmentVariable(Constants.s_playwright_service_disable_scalable_execution_environment_variable) == "true") + throw new Exception(Constants.s_service_endpoint_removed_since_scalable_execution_disabled_error_message); + if (string.IsNullOrEmpty(ServiceEndpoint)) + throw new Exception(Constants.s_no_service_endpoint_error_message); + string _serviceOs = Uri.EscapeDataString(os ?? Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE) ?? Constants.s_default_os); + string _runId = Uri.EscapeDataString(runId ?? Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE) ?? GetDefaultRunId()); + string _exposeNetwork = exposeNetwork ?? Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE) ?? Constants.s_default_expose_network; + + string wsEndpoint = $"{ServiceEndpoint}?os={_serviceOs}&runId={_runId}&api-version={Constants.s_api_version}"; + + // fetch Entra id access token if required + // 1. Entra id access token has been fetched once via global functions + // 2. Not close to expiry + if (!string.IsNullOrEmpty(_entraLifecycle!._entraIdAccessToken) && _entraLifecycle!.DoesEntraIdAccessTokenRequireRotation()) + { + _ = await _entraLifecycle.FetchEntraIdAccessTokenAsync().ConfigureAwait(false); + } + if (string.IsNullOrEmpty(GetAuthToken())) + { + throw new Exception(Constants.s_no_auth_error); + } + + var browserConnectOptions = new BrowserConnectOptions + { + Timeout = 3 * 60 * 1000, + ExposeNetwork = _exposeNetwork, + Headers = new Dictionary + { + ["Authorization"] = $"Bearer {GetAuthToken()}" + } + }; + return new ConnectOptions + { + WsEndpoint = wsEndpoint, + Options = BrowserConnectOptionsConverter.Convert(browserConnectOptions) + }; + } + + /// + /// Initialises the resources used to setup entra id authentication. + /// + public async Task InitializeAsync() + { + if (string.IsNullOrEmpty(ServiceEndpoint)) + return; + if (!UseCloudHostedBrowsers) + { + // Since playwright-dotnet checks PLAYWRIGHT_SERVICE_ACCESS_TOKEN and PLAYWRIGHT_SERVICE_URL to be set, remove PLAYWRIGHT_SERVICE_URL so that tests are run locally. + // If customers use GetConnectOptionsAsync, after setting disableScalableExecution, an error will be thrown. + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); + } + // If default auth mechanism is Access token and token is available in the environment variable, no need to setup rotation handler + if (DefaultAuth == ServiceAuth.TOKEN && !string.IsNullOrEmpty(GetAuthToken())) + return; + var operationStatus = await _entraLifecycle!.FetchEntraIdAccessTokenAsync().ConfigureAwait(false); + if (!operationStatus) + { + if (!string.IsNullOrEmpty(GetAuthToken())) + { + ValidateMptPAT(); // throws exception if token is invalid + } + return; // no need to setup rotation handler. If token is not available, it will fallback to local browser launch + } + + RotationTimer = new Timer(RotationHandlerAsync, null, TimeSpan.FromMinutes(Constants.s_entra_access_token_rotation_interval_period_in_minutes), TimeSpan.FromMinutes(Constants.s_entra_access_token_rotation_interval_period_in_minutes)); + } + + /// + /// Cleans up the resources used to setup entra id authentication. + /// + public void Cleanup() + { + RotationTimer?.Dispose(); + } + + internal async void RotationHandlerAsync(object? _) + { + if (_entraLifecycle!.DoesEntraIdAccessTokenRequireRotation()) + { + await _entraLifecycle.FetchEntraIdAccessTokenAsync().ConfigureAwait(false); + } + } + + private void InitializePlaywrightServiceEnvironmentVariables(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null) + { + if (!string.IsNullOrEmpty(defaultAuth)) + { + DefaultAuth = defaultAuth!; + } + if (useCloudHostedBrowsers != null) + { + UseCloudHostedBrowsers = (bool)useCloudHostedBrowsers; + if (!UseCloudHostedBrowsers) + Environment.SetEnvironmentVariable(Constants.s_playwright_service_disable_scalable_execution_environment_variable, "true"); + } + if (!string.IsNullOrEmpty(os)) + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE, os); + } + else + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE, Constants.s_default_os); + } + if (!string.IsNullOrEmpty(runId)) + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); + } + else + { + GetDefaultRunId(); + } + if (!string.IsNullOrEmpty(exposeNetwork)) + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE, exposeNetwork); + } + else + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE, Constants.s_default_expose_network); + } + SetReportingUrlAndWorkspaceId(); + } + + internal static string GetDefaultRunId() + { + var runIdFromEnvironmentVariable = Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE); + if (!string.IsNullOrEmpty(runIdFromEnvironmentVariable)) + return runIdFromEnvironmentVariable!; + var runId = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fff'Z'", CultureInfo.InvariantCulture); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); + return runId; + } + + internal static void SetReportingUrlAndWorkspaceId() + { + Match match = Regex.Match(ServiceEndpoint, @"wss://(?[\w-]+)\.api\.(?playwright(?:-test|-int)?\.io|playwright\.microsoft\.com)/accounts/(?[\w-]+)/"); + if (!match.Success) + return; + var region = match.Groups["region"].Value; + var domain = match.Groups["domain"].Value; + var workspaceId = match.Groups["workspaceId"].Value; + if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable))) + Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, $"https://{region}.reporting.api.{domain}"); + if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable))) + Environment.SetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable, $"{workspaceId}"); + } + + private static string? GetAuthToken() + { + return Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE); + } + + private void ValidateMptPAT() + { + string authToken = GetAuthToken()!; + JsonWebToken jsonWebToken = _jsonWebTokenHandler!.ReadJsonWebToken(authToken) ?? throw new Exception(Constants.s_invalid_mpt_pat_error); + var expiry = (long)(jsonWebToken.ValidTo - new DateTime(1970, 1, 1)).TotalSeconds; + if (expiry <= DateTimeOffset.UtcNow.ToUnixTimeSeconds()) + throw new Exception(Constants.s_expired_mpt_pat_error); + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs new file mode 100644 index 000000000000..14094d353f4f --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core; +using Azure.Identity; + +namespace Azure.Developer.MicrosoftPlaywrightTesting; + +/// +/// Settings for the Playwright service. +/// +public class PlaywrightServiceSettings +{ + internal string? Os { get; set; } + internal string? RunId { get; set; } + internal string? ExposeNetwork { get; set; } + internal string DefaultAuth { get; set; } + internal bool UseCloudHostedBrowsers { get; set; } + internal TokenCredential AzureTokenCredential { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The operating system. + /// The run ID. + /// The network exposure. + /// The default authentication mechanism. + /// Whether to use cloud-hosted browsers. + /// The Azure token credential type. + /// The managed identity client ID. + public PlaywrightServiceSettings(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) + { + Os = os; + RunId = runId; + ExposeNetwork = exposeNetwork; + DefaultAuth = defaultAuth ?? ServiceAuth.ENTRA; + UseCloudHostedBrowsers = string.IsNullOrEmpty(useCloudHostedBrowsers) || bool.Parse(useCloudHostedBrowsers!); + AzureTokenCredential = GetTokenCredential(azureTokenCredentialType, managedIdentityClientId); + Validate(); + } + + private void Validate() + { + if (!string.IsNullOrEmpty(Os) && Os != ServiceOs.LINUX && Os != ServiceOs.WINDOWS) + { + throw new System.Exception($"Invalid value for {nameof(Os)}: {Os}. Supported values are {ServiceOs.LINUX} and {ServiceOs.WINDOWS}"); + } + if (!string.IsNullOrEmpty(DefaultAuth) && DefaultAuth != ServiceAuth.ENTRA && DefaultAuth != ServiceAuth.TOKEN) + { + throw new System.Exception($"Invalid value for {nameof(DefaultAuth)}: {DefaultAuth}. Supported values are {ServiceAuth.ENTRA} and {ServiceAuth.TOKEN}"); + } + } + + private static TokenCredential GetTokenCredential(string? azureTokenCredentialType, string? managedIdentityClientId) + { + if (string.IsNullOrEmpty(azureTokenCredentialType) && string.IsNullOrEmpty(managedIdentityClientId)) + return new DefaultAzureCredential(); + if (azureTokenCredentialType == AzureTokenCredentialType.ManagedIdentityCredential) + { + return new ManagedIdentityCredential(managedIdentityClientId); + } + else if (azureTokenCredentialType == AzureTokenCredentialType.WorkloadIdentityCredential) + { + return new WorkloadIdentityCredential(); + } + else if (azureTokenCredentialType == AzureTokenCredentialType.EnvironmentCredential) + { + return new EnvironmentCredential(); + } + else if (azureTokenCredentialType == AzureTokenCredentialType.AzureCliCredential) + { + return new AzureCliCredential(); + } + else if (azureTokenCredentialType == AzureTokenCredentialType.AzurePowerShellCredential) + { + return new AzurePowerShellCredential(); + } + else if (azureTokenCredentialType == AzureTokenCredentialType.AzureDeveloperCliCredential) + { + return new AzureDeveloperCliCredential(); + } + else if (azureTokenCredentialType == AzureTokenCredentialType.SharedTokenCacheCredential) + { + return new SharedTokenCacheCredential(); + } + else if (azureTokenCredentialType == AzureTokenCredentialType.VisualStudioCredential) + { + return new VisualStudioCredential(); + } + else if (azureTokenCredentialType == AzureTokenCredentialType.VisualStudioCodeCredential) + { + return new VisualStudioCodeCredential(); + } + else if (azureTokenCredentialType == AzureTokenCredentialType.InteractiveBrowserCredential) + { + return new InteractiveBrowserCredential(); + } + else + { + return new DefaultAzureCredential(new DefaultAzureCredentialOptions + { + ManagedIdentityClientId = managedIdentityClientId + }); + } + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClient.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClient.cs new file mode 100644 index 000000000000..cdb4648d4adc --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClient.cs @@ -0,0 +1,2553 @@ +//---------------------- +// +// Generated using the NSwag toolchain v14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" +#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" +#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Clients +{ + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial interface ITestReportingClient + { + /// + /// Get summary of test results + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestResultsSummaryAsync(string workspaceId, string filter, string orderby, string authorization, string x_correlation_id, string api_version); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get summary of test results + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestResultsSummaryAsync(string workspaceId, string filter, string orderby, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); + + /// + /// Get the test results for a given test run ID + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the test run + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestResultsAsync(string workspaceId, string filter, string orderby, int? top, int? skip, string authorization, string x_correlation_id, string api_version); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the test results for a given test run ID + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the test run + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestResultsAsync(string workspaceId, string filter, string orderby, int? top, int? skip, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); + + /// + /// Uploads a batch of test results to the test run + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestResultsUploadBatchAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, UploadTestResultsRequest body); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Uploads a batch of test results to the test run + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestResultsUploadBatchAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, UploadTestResultsRequest body, System.Threading.CancellationToken cancellationToken); + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsPatchAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, TestRunDtoV2 body); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsPatchAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, TestRunDtoV2 body, System.Threading.CancellationToken cancellationToken); + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, int? top, int? skip, string authorization, string x_correlation_id, string api_version); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, int? top, int? skip, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); + + /// + /// Delete all the test runs for a given workspaceId + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsDeleteAsync(string workspaceId, string authorization, string x_correlation_id, string api_version); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Delete all the test runs for a given workspaceId + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsDeleteAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsResulturiAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsResulturiAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsShardsAsync(string workspaceId, string testRunId, string shardId, string authorization, string x_correlation_id, string api_version, TestRunShardDto body); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesTestRunsShardsAsync(string workspaceId, string testRunId, string shardId, string authorization, string x_correlation_id, string api_version, TestRunShardDto body, System.Threading.CancellationToken cancellationToken); + + /// + /// Get the storage account and link with the given workspace id. + /// + /// The workspace id. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the storage account details. + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesStoragePutAsync(string workspaceId, string authorization, string x_correlation_id, string api_version); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the storage account and link with the given workspace id. + /// + /// The workspace id. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the storage account details. + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesStoragePutAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); + + /// + /// Get the storage account details for the given workspaceId. + /// + /// The workspaceId. + /// The storage id. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the storage account details. + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesStorageGetAsync(string workspaceId, string storageAccountId, string authorization, string x_correlation_id, string api_version); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the storage account details for the given workspaceId. + /// + /// The workspaceId. + /// The storage id. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the storage account details. + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesStorageGetAsync(string workspaceId, string storageAccountId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); + + /// + /// Delete or unlink the storage account for the given workspaceId. + /// + /// The workspaceId. + /// The storage id. + /// The flag to indicate if it is a soft delete. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns no content. + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesStorageDeleteAsync(string workspaceId, string storageAccountId, bool? isSoftDelete, string authorization, string x_correlation_id, string api_version); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Delete or unlink the storage account for the given workspaceId. + /// + /// The workspaceId. + /// The storage id. + /// The flag to indicate if it is a soft delete. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns no content. + /// A server side error occurred. + System.Threading.Tasks.Task WorkspacesStorageDeleteAsync(string workspaceId, string storageAccountId, bool? isSoftDelete, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestReportingClient : ITestReportingClient + { +#pragma warning disable 8618 + private string _baseUrl; +#pragma warning restore 8618 + + private System.Net.Http.HttpClient _httpClient; + private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public TestReportingClient(string baseUrl, System.Net.Http.HttpClient httpClient) +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + { + BaseUrl = baseUrl; + _httpClient = httpClient; + } + + private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set + { + _baseUrl = value; + if (!string.IsNullOrEmpty(_baseUrl) && !_baseUrl.EndsWith("/")) + _baseUrl += '/'; + } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } + + static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + + /// + /// Get summary of test results + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesTestResultsSummaryAsync(string workspaceId, string filter, string orderby, string authorization, string x_correlation_id, string api_version) + { + return WorkspacesTestResultsSummaryAsync(workspaceId, filter, orderby, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get summary of test results + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesTestResultsSummaryAsync(string workspaceId, string filter, string orderby, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/test-results/summary" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/test-results/summary"); + urlBuilder_.Append('?'); + if (filter != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filter")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filter, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (orderby != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("orderby")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(orderby, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad Request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Server Error", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get the test results for a given test run ID + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the test run + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesTestResultsAsync(string workspaceId, string filter, string orderby, int? top, int? skip, string authorization, string x_correlation_id, string api_version) + { + return WorkspacesTestResultsAsync(workspaceId, filter, orderby, top, skip, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the test results for a given test run ID + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the test run + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesTestResultsAsync(string workspaceId, string filter, string orderby, int? top, int? skip, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/test-results" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/test-results"); + urlBuilder_.Append('?'); + if (filter != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filter")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filter, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (orderby != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("orderby")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(orderby, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (top != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("top")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(top, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (skip != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("skip")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(skip, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If the runId is empty", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("In case of internal server error/exception", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Uploads a batch of test results to the test run + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesTestResultsUploadBatchAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, UploadTestResultsRequest body) + { + return WorkspacesTestResultsUploadBatchAsync(workspaceId, authorization, x_correlation_id, api_version, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Uploads a batch of test results to the test run + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesTestResultsUploadBatchAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, UploadTestResultsRequest body, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/test-results/upload-batch" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/test-results/upload-batch"); + urlBuilder_.Append('?'); + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad Request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Server Error", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version) + { + return WorkspacesTestRunsGetAsync(workspaceId, testRunId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + if (testRunId == null) + throw new System.ArgumentNullException("testRunId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/test-runs/{testRunId}" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/test-runs/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(testRunId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesTestRunsPatchAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, TestRunDtoV2 body) + { + return WorkspacesTestRunsPatchAsync(workspaceId, testRunId, authorization, x_correlation_id, api_version, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesTestRunsPatchAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, TestRunDtoV2 body, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + if (testRunId == null) + throw new System.ArgumentNullException("testRunId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json-patch+json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PATCH"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/test-runs/{testRunId}" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/test-runs/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(testRunId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, int? top, int? skip, string authorization, string x_correlation_id, string api_version) + { + return WorkspacesTestRunsGetAsync(workspaceId, top, skip, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, int? top, int? skip, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/test-runs" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/test-runs"); + urlBuilder_.Append('?'); + if (top != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("top")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(top, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (skip != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("skip")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(skip, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Delete all the test runs for a given workspaceId + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesTestRunsDeleteAsync(string workspaceId, string authorization, string x_correlation_id, string api_version) + { + return WorkspacesTestRunsDeleteAsync(workspaceId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Delete all the test runs for a given workspaceId + /// + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesTestRunsDeleteAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/test-runs" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/test-runs"); + urlBuilder_.Append('?'); + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 204) + { + return; + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If no resource found with the input workspaceId", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If the workspaceId is null", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("In case of internal server error/exception", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesTestRunsResulturiAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version) + { + return WorkspacesTestRunsResulturiAsync(workspaceId, testRunId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesTestRunsResulturiAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + if (testRunId == null) + throw new System.ArgumentNullException("testRunId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/test-runs/{testRunId}/resulturi" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/test-runs/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(testRunId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/resulturi"); + urlBuilder_.Append('?'); + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesTestRunsShardsAsync(string workspaceId, string testRunId, string shardId, string authorization, string x_correlation_id, string api_version, TestRunShardDto body) + { + return WorkspacesTestRunsShardsAsync(workspaceId, testRunId, shardId, authorization, x_correlation_id, api_version, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesTestRunsShardsAsync(string workspaceId, string testRunId, string shardId, string authorization, string x_correlation_id, string api_version, TestRunShardDto body, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + if (testRunId == null) + throw new System.ArgumentNullException("testRunId"); + + if (shardId == null) + throw new System.ArgumentNullException("shardId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json-patch+json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PATCH"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/test-runs/{testRunId}/shards/{shardId}" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/test-runs/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(testRunId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/shards/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(shardId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get the storage account and link with the given workspace id. + /// + /// The workspace id. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the storage account details. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesStoragePutAsync(string workspaceId, string authorization, string x_correlation_id, string api_version) + { + return WorkspacesStoragePutAsync(workspaceId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the storage account and link with the given workspace id. + /// + /// The workspace id. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the storage account details. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesStoragePutAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("PUT"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/storage" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/storage"); + urlBuilder_.Append('?'); + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If the workspace id is invalid.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Not Found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If there is an internal server error.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get the storage account details for the given workspaceId. + /// + /// The workspaceId. + /// The storage id. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the storage account details. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesStorageGetAsync(string workspaceId, string storageAccountId, string authorization, string x_correlation_id, string api_version) + { + return WorkspacesStorageGetAsync(workspaceId, storageAccountId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the storage account details for the given workspaceId. + /// + /// The workspaceId. + /// The storage id. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns the storage account details. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesStorageGetAsync(string workspaceId, string storageAccountId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + if (storageAccountId == null) + throw new System.ArgumentNullException("storageAccountId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/storage/{storageAccountId}" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/storage/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(storageAccountId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If the workspaceId or storage id is invalid.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If the workspaceId is not found.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If there is an internal server error.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Delete or unlink the storage account for the given workspaceId. + /// + /// The workspaceId. + /// The storage id. + /// The flag to indicate if it is a soft delete. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns no content. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WorkspacesStorageDeleteAsync(string workspaceId, string storageAccountId, bool? isSoftDelete, string authorization, string x_correlation_id, string api_version) + { + return WorkspacesStorageDeleteAsync(workspaceId, storageAccountId, isSoftDelete, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Delete or unlink the storage account for the given workspaceId. + /// + /// The workspaceId. + /// The storage id. + /// The flag to indicate if it is a soft delete. + /// access token + /// Correlation-id used for tracing and debugging. + /// api version + /// Returns no content. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WorkspacesStorageDeleteAsync(string workspaceId, string storageAccountId, bool? isSoftDelete, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) + { + if (workspaceId == null) + throw new System.ArgumentNullException("workspaceId"); + + if (storageAccountId == null) + throw new System.ArgumentNullException("storageAccountId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (authorization != null) + request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_correlation_id != null) + request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "workspaces/{workspaceId}/storage/{storageAccountId}" + urlBuilder_.Append("workspaces/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/storage/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(storageAccountId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (isSoftDelete != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("isSoftDelete")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(isSoftDelete, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (api_version != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 204) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If the workspace id or storage id is invalid.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If the workspace id is not found.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("If there is an internal server error.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[])value); + } + else if (value is string[]) + { + return string.Join(",", (string[])value); + } + else if (value.GetType().IsArray) + { + var valueArray = (System.Array)value; + var valueTextArray = new string[valueArray.Length]; + for (var i = 0; i < valueArray.Length; i++) + { + valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); + } + return string.Join(",", valueTextArray); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal enum AccessLevel + { + + [System.Runtime.Serialization.EnumMember(Value = @"Read")] + Read = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Write")] + Write = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"ReadWrite")] + ReadWrite = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"ReadAddCreateWrite")] + ReadAddCreateWrite = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class CIConfig + { + [Newtonsoft.Json.JsonProperty("ciProviderName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CiProviderName { get; set; } + + [Newtonsoft.Json.JsonProperty("branch", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Branch { get; set; } + + [Newtonsoft.Json.JsonProperty("author", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Author { get; set; } + + [Newtonsoft.Json.JsonProperty("commitId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CommitId { get; set; } + + [Newtonsoft.Json.JsonProperty("revisionUrl", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string RevisionUrl { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class ClientConfig + { + [Newtonsoft.Json.JsonProperty("retries", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Retries { get; set; } + + [Newtonsoft.Json.JsonProperty("repeatEach", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? RepeatEach { get; set; } + + [Newtonsoft.Json.JsonProperty("workers", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Workers { get; set; } + + [Newtonsoft.Json.JsonProperty("pwVersion", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PwVersion { get; set; } + + [Newtonsoft.Json.JsonProperty("testFramework", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestFramework TestFramework { get; set; } + + [Newtonsoft.Json.JsonProperty("shards", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Shard Shards { get; set; } + + [Newtonsoft.Json.JsonProperty("timeout", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Timeout { get; set; } + + [Newtonsoft.Json.JsonProperty("testType", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TestType { get; set; } + + [Newtonsoft.Json.JsonProperty("testSdkLanguage", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TestSdkLanguage { get; set; } + + [Newtonsoft.Json.JsonProperty("reporterPackageVersion", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ReporterPackageVersion { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class Error + { + [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Code { get; set; } + + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Message { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class ErrorResponse + { + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Status { get; set; } + + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Error Error { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class ListTestRunResponse + { + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Value { get; set; } + + [Newtonsoft.Json.JsonProperty("nextLink", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string NextLink { get; set; } + + [Newtonsoft.Json.JsonProperty("size", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Size { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class PreviousRetrySummary + { + [Newtonsoft.Json.JsonProperty("testExecutionId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TestExecutionId { get; set; } + + [Newtonsoft.Json.JsonProperty("retry", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Retry { get; set; } + + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Status { get; set; } + + [Newtonsoft.Json.JsonProperty("duration", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? Duration { get; set; } + + [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string StartTime { get; set; } + + [Newtonsoft.Json.JsonProperty("attachmentsMetadata", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string AttachmentsMetadata { get; set; } + + [Newtonsoft.Json.JsonProperty("artifactsPath", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection ArtifactsPath { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class Shard + { + [Newtonsoft.Json.JsonProperty("total", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Total { get; set; } + + [Newtonsoft.Json.JsonProperty("current", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Current { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class StorageAccountDTO + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + [Newtonsoft.Json.JsonProperty("subscriptionId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SubscriptionId { get; set; } + + [Newtonsoft.Json.JsonProperty("linkedAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string LinkedAt { get; set; } + + [Newtonsoft.Json.JsonProperty("accountId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string AccountId { get; set; } + + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public StorageAccountStatus? Status { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal enum StorageAccountStatus + { + + [System.Runtime.Serialization.EnumMember(Value = @"Linked")] + Linked = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Deleted")] + Deleted = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"LinkingInProgress")] + LinkingInProgress = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"DeletionInProgress")] + DeletionInProgress = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestFramework + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Version { get; set; } + + [Newtonsoft.Json.JsonProperty("runnerName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string RunnerName { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestResults + { + [Newtonsoft.Json.JsonProperty("testExecutionId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TestExecutionId { get; set; } + + [Newtonsoft.Json.JsonProperty("testId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TestId { get; set; } + + [Newtonsoft.Json.JsonProperty("testCombinationId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TestCombinationId { get; set; } + + [Newtonsoft.Json.JsonProperty("runId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string RunId { get; set; } + + [Newtonsoft.Json.JsonProperty("accountId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string AccountId { get; set; } + + [Newtonsoft.Json.JsonProperty("suiteId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SuiteId { get; set; } + + [Newtonsoft.Json.JsonProperty("testTitle", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TestTitle { get; set; } + + [Newtonsoft.Json.JsonProperty("suiteTitle", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SuiteTitle { get; set; } + + [Newtonsoft.Json.JsonProperty("fileName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string FileName { get; set; } + + [Newtonsoft.Json.JsonProperty("lineNumber", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? LineNumber { get; set; } + + [Newtonsoft.Json.JsonProperty("retry", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Retry { get; set; } + + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Status { get; set; } + + [Newtonsoft.Json.JsonProperty("webTestConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public WebTestConfig WebTestConfig { get; set; } + + [Newtonsoft.Json.JsonProperty("ciConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public CIConfig CiConfig { get; set; } + + [Newtonsoft.Json.JsonProperty("resultsSummary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestResultsSummary ResultsSummary { get; set; } + + [Newtonsoft.Json.JsonProperty("previousRetries", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection PreviousRetries { get; set; } + + [Newtonsoft.Json.JsonProperty("tags", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Tags { get; set; } + + [Newtonsoft.Json.JsonProperty("annotations", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Annotations { get; set; } + + [Newtonsoft.Json.JsonProperty("artifactsPath", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection ArtifactsPath { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestResultsSummary + { + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Status { get; set; } + + [Newtonsoft.Json.JsonProperty("duration", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? Duration { get; set; } + + [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string StartTime { get; set; } + + [Newtonsoft.Json.JsonProperty("attachmentsMetadata", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string AttachmentsMetadata { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestResultsUri + { + [Newtonsoft.Json.JsonProperty("uri", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Uri { get; set; } + + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + [Newtonsoft.Json.JsonProperty("expiresAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ExpiresAt { get; set; } + + [Newtonsoft.Json.JsonProperty("accessLevel", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public AccessLevel? AccessLevel { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestRunDto + { + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Id { get; set; } + + [Newtonsoft.Json.JsonProperty("title", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Title { get; set; } + + [Newtonsoft.Json.JsonProperty("accountId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string AccountId { get; set; } + + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + + [Newtonsoft.Json.JsonProperty("userName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserName { get; set; } + + [Newtonsoft.Json.JsonProperty("summary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestRunSummary Summary { get; set; } + + [Newtonsoft.Json.JsonProperty("resultsSummary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestRunResultsSummary ResultsSummary { get; set; } + + [Newtonsoft.Json.JsonProperty("ciConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public CIConfig CiConfig { get; set; } + + [Newtonsoft.Json.JsonProperty("clientConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public ClientConfig ClientConfig { get; set; } + + [Newtonsoft.Json.JsonProperty("testResultsUri", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestResultsUri TestResultsUri { get; set; } + + [Newtonsoft.Json.JsonProperty("isScalablyExecuted", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IsScalablyExecuted { get; set; } + + [Newtonsoft.Json.JsonProperty("isReportingEnabled", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IsReportingEnabled { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestRunDtoV2 + { + [Newtonsoft.Json.JsonProperty("testRunId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TestRunId { get; set; } + + [Newtonsoft.Json.JsonProperty("displayName", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.StringLength(200)] + public string DisplayName { get; set; } + + [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$")] + public string StartTime { get; set; } + + [Newtonsoft.Json.JsonProperty("creatorId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatorId { get; set; } + + [Newtonsoft.Json.JsonProperty("creatorName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatorName { get; set; } + + [Newtonsoft.Json.JsonProperty("summary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestRunSummary Summary { get; set; } + + [Newtonsoft.Json.JsonProperty("resultsSummary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestRunResultsSummary ResultsSummary { get; set; } + + [Newtonsoft.Json.JsonProperty("ciConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public CIConfig CiConfig { get; set; } + + [Newtonsoft.Json.JsonProperty("testRunConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public ClientConfig TestRunConfig { get; set; } + + [Newtonsoft.Json.JsonProperty("testResultsUri", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestResultsUri TestResultsUri { get; set; } + + [Newtonsoft.Json.JsonProperty("cloudRunEnabled", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"true|false")] + public string CloudRunEnabled { get; set; } + + [Newtonsoft.Json.JsonProperty("cloudReportingEnabled", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"true|false")] + public string CloudReportingEnabled { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestRunResultsSummary + { + [Newtonsoft.Json.JsonProperty("numTotalTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? NumTotalTests { get; set; } + + [Newtonsoft.Json.JsonProperty("numPassedTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? NumPassedTests { get; set; } + + [Newtonsoft.Json.JsonProperty("numFailedTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? NumFailedTests { get; set; } + + [Newtonsoft.Json.JsonProperty("numSkippedTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? NumSkippedTests { get; set; } + + [Newtonsoft.Json.JsonProperty("numFlakyTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? NumFlakyTests { get; set; } + + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Status { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestRunShardDto + { + [Newtonsoft.Json.JsonProperty("uploadCompleted", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.RegularExpression(@"true|false")] + public string UploadCompleted { get; set; } + + [Newtonsoft.Json.JsonProperty("summary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestRunShardSummary Summary { get; set; } + + [Newtonsoft.Json.JsonProperty("testRunConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public ClientConfig TestRunConfig { get; set; } + + [Newtonsoft.Json.JsonProperty("resultsSummary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public TestRunResultsSummary ResultsSummary { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestRunShardSummary + { + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"RUNNING|CLIENT_COMPLETE|SERVER_COMPLETE")] + public string Status { get; set; } + + [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$")] + public string StartTime { get; set; } + + [Newtonsoft.Json.JsonProperty("endTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$")] + public string EndTime { get; set; } + + [Newtonsoft.Json.JsonProperty("errorMessages", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection ErrorMessages { get; set; } + + [Newtonsoft.Json.JsonProperty("uploadMetadata", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public UploadMetadata UploadMetadata { get; set; } + + [Newtonsoft.Json.JsonProperty("totalTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? TotalTime { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestRunSummary + { + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"RUNNING|CLIENT_COMPLETE|SERVER_COMPLETE")] + public string Status { get; set; } + + [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string StartTime { get; set; } + + [Newtonsoft.Json.JsonProperty("endTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EndTime { get; set; } + + [Newtonsoft.Json.JsonProperty("billableTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? BillableTime { get; set; } + + [Newtonsoft.Json.JsonProperty("totalTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? TotalTime { get; set; } + + [Newtonsoft.Json.JsonProperty("numBrowserSessions", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? NumBrowserSessions { get; set; } + + [Newtonsoft.Json.JsonProperty("jobs", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Jobs { get; set; } + + [Newtonsoft.Json.JsonProperty("projects", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Projects { get; set; } + + [Newtonsoft.Json.JsonProperty("tags", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Tags { get; set; } + + [Newtonsoft.Json.JsonProperty("errorMessages", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection ErrorMessages { get; set; } + + [Newtonsoft.Json.JsonProperty("uploadMetadata", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public UploadMetadata UploadMetadata { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class TestSummary + { + [Newtonsoft.Json.JsonProperty("total", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Total { get; set; } + + [Newtonsoft.Json.JsonProperty("passed", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Passed { get; set; } + + [Newtonsoft.Json.JsonProperty("failed", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Failed { get; set; } + + [Newtonsoft.Json.JsonProperty("skipped", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Skipped { get; set; } + + [Newtonsoft.Json.JsonProperty("flaky", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? Flaky { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class UploadMetadata + { + [Newtonsoft.Json.JsonProperty("numTestResults", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? NumTestResults { get; set; } + + [Newtonsoft.Json.JsonProperty("numTotalAttachments", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? NumTotalAttachments { get; set; } + + [Newtonsoft.Json.JsonProperty("sizeTotalAttachments", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long? SizeTotalAttachments { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class UploadTestResultsRequest + { + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Value { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class WebTestConfig + { + [Newtonsoft.Json.JsonProperty("jobName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string JobName { get; set; } + + [Newtonsoft.Json.JsonProperty("projectName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ProjectName { get; set; } + + [Newtonsoft.Json.JsonProperty("browserName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BrowserName { get; set; } + + [Newtonsoft.Json.JsonProperty("os", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Os { get; set; } + + } + + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class ApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class ApiException : ApiException + { + public TResult Result { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8603 +#pragma warning restore 8604 +#pragma warning restore 8625 \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/CIInfo.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/CIInfo.cs new file mode 100644 index 000000000000..e44bdae81baf --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/CIInfo.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; + +internal class CIInfo +{ + internal string? Provider { get; set; } + internal string? Repo { get; set; } + internal string? Branch { get; set; } + internal string? Author { get; set; } + internal string? CommitId { get; set; } + internal string? RevisionUrl { get; set; } + internal string? RunId { get; set; } + internal int? RunAttempt { get; set; } + internal string? JobId { get; set; } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs new file mode 100644 index 000000000000..8a2deee0d5a0 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; + +internal class RawTestStep +{ + internal string? Title { get; set; } + internal string? Category { get; set; } + internal string? StartTime { get; set; } + internal int Duration { get; set; } + internal string? Error { get; set; } + internal List Steps { get; set; } = new List(); + internal Location? Location { get; set; } + internal string? Snippet { get; set; } + internal int Count { get; set; } +} + +internal class Location +{ + internal int LineNumber { get; set; } +} + +internal class MPTError +{ + internal string? message { get; set; } +} +internal class RawTestResult +{ + internal List Steps { get; set; } = new List(); + internal string? errors { get; set; } + internal string? stdErr { get; set; } + internal string? stdOut { get; set; } +} + +internal class TokenDetails +{ + internal string? aid { get; set; } + internal string? oid { get; set; } + internal string? id { get; set; } + internal string? userName { get; set; } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs new file mode 100644 index 000000000000..0ecceb0760b4 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -0,0 +1,689 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; +using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility; +using Azure.Storage.Blobs; +using Microsoft.IdentityModel.JsonWebTokens; +using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Clients; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; +using Newtonsoft.Json; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using PlaywrightConstants = Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility.Constants; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; + +[FriendlyName("ms-playwright-service")] +[ExtensionUri("logger://Microsoft/Playwright/ServiceLogger/v1")] +internal class PlaywrightReporter : ITestLoggerWithParameters +{ + private Dictionary? _parametersDictionary; + + private bool IsInitialized { get; set; } + + private HttpClient? _httpClient; + + private TestReportingClient? _testReportingClient; + + private static readonly JsonWebTokenHandler s_tokenHandler = new(); + + private readonly LogLevel _logLevel = LogLevel.Debug; + + private readonly string _apiVersion = PlaywrightConstants.ReportingAPIVersion_2024_05_20_preview; + + internal static string EnableConsoleLog { get => Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_DEBUG) ?? "false"; set { } } + + internal string? PortalUrl { get; set; } + + internal static string? BaseUrl { get => Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_REPORTING_URL); private set { } } + + internal static string AccessToken { get => Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_ACCESS_TOKEN) ?? ""; set { } } + + internal string? WorkspaceId { get; set; } + + internal TokenDetails? TokenDetails { get; set; } + + internal CIInfo? CIInfo { get; set; } + + internal string? RunId { get; set; } + + internal DateTime TestRunStartTime { get; private set; } + + internal int TotalTestCount { get; private set; } + + internal int PassedTestCount { get; private set; } + + internal int FailedTestCount { get; private set; } + + internal int SkippedTestCount { get; private set; } + + internal TestRunDtoV2? TestRun { get; set; } + + internal TestRunShardDto? TestRunShard { get; set; } + + internal List TestResults = new(); + + internal ConcurrentDictionary RawTestResultsMap = new(); + + internal PlaywrightService? playwrightService; + + public void Initialize(TestLoggerEvents events, Dictionary parameters) + { + ValidateArg.NotNull(events, nameof(events)); + _parametersDictionary = parameters; + Initialize(events, _parametersDictionary[DefaultLoggerParameterNames.TestRunDirectory]!); + } + + public void Initialize(TestLoggerEvents events, string testResultsDirPath) + { + ValidateArg.NotNull(events, nameof(events)); + ValidateArg.NotNullOrEmpty(testResultsDirPath, nameof(testResultsDirPath)); + + // Register for the events. + events.TestRunMessage += TestMessageHandler; + events.TestResult += TestResultHandler; + events.TestRunComplete += TestRunCompleteHandler; + events.TestRunStart += TestRunStartHandler; + } + + #region Event Handlers + + internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) + { + InitializePlaywrightReporter(e.TestRunCriteria.TestRunSettings); + LogMessage("Test Run start Handler"); + if (!IsInitialized || _testReportingClient == null) + { + LogErrorMessage("Test Run setup issue exiting handler"); + return; + } + var testResultsJson = JsonConvert.SerializeObject(e); + LogMessage(testResultsJson); + + var startTime = TestRunStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"); + LogMessage("Test Run start time: " + startTime); + var corelationId = Guid.NewGuid().ToString(); + var runName = "TestRun#" + startTime; // TODO discuss approach + var run = new TestRunDtoV2 + { + TestRunId = RunId, + DisplayName = runName, + StartTime = startTime, + CreatorId = TokenDetails!.oid, + CreatorName = TokenDetails.userName, + //CloudRunEnabled = "false", + CloudReportingEnabled = "true", + Summary = new TestRunSummary + { + Status = "RUNNING", + StartTime = startTime, + //Projects = ["playwright-dotnet"], + //Tags = ["Nunit", "dotnet"], + //Jobs = ["playwright-dotnet"], + }, + CiConfig = new CIConfig // TODO fetch dynamically + { + Branch = CIInfo!.Branch, + Author = CIInfo.Author, + CommitId = CIInfo.CommitId, + RevisionUrl = CIInfo.RevisionUrl + }, + TestRunConfig = new ClientConfig // TODO fetch some of these dynamically + { + Workers = 1, + PwVersion = "1.40", + Timeout = 60000, + TestType = "WebTest", + TestSdkLanguage = "Dotnet", + TestFramework = new TestFramework() { Name = "VSTest", RunnerName = "Nunit/MSTest", Version = "3.1" }, // TODO fetch runner name MSTest/Nunit + ReporterPackageVersion = "0.0.1-dotnet", + Shards = new Shard() { Current = 0, Total = 1 } + } + }; + var shard = new TestRunShardDto + { + UploadCompleted = "false", + Summary = new TestRunShardSummary + { + Status = "RUNNING", + StartTime = startTime, + }, + TestRunConfig = new ClientConfig // TODO fetch some of these dynamically + { + Workers = 1, + PwVersion = "1.40", + Timeout = 60000, + TestType = "Functional", + TestSdkLanguage = "dotnet", + TestFramework = new TestFramework() { Name = "VSTest", RunnerName = "Nunit", Version = "3.1" }, + ReporterPackageVersion = "0.0.1-dotnet", + Shards = new Shard() { Current = 0, Total = 1 }, + } + }; + var token = "Bearer " + AccessToken; + TestRunDtoV2 response; + try + { + var testRunBodyJson = JsonConvert.SerializeObject(run); + LogMessage("TestRunInput" + testRunBodyJson); +#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + response = _testReportingClient.WorkspacesTestRunsPatchAsync( // Add retry + WorkspaceId, + RunId, + token, + corelationId, + _apiVersion, + run).GetAwaiter().GetResult(); +#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + } + catch (Exception ex) + { + Logger.Log(true, LogLevel.Error, ex.ToString()); + throw; + } + if (response != null) + { + var testRunJson = JsonConvert.SerializeObject(response); + LogMessage("TestRunResponse" + testRunJson); + this.TestRun = response; + + // Start shard + corelationId = Guid.NewGuid().ToString(); + TestRunShardDto response1; + try + { +#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + response1 = _testReportingClient.WorkspacesTestRunsShardsAsync( + WorkspaceId, + RunId, + "1", + token, + corelationId, + _apiVersion, + shard).GetAwaiter().GetResult(); +#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + } + catch (Exception ex) + { + Logger.Log(true, LogLevel.Error, ex.ToString()); + throw; + } + if (response1 != null) + { + var testRunShardJson = JsonConvert.SerializeObject(response); + LogMessage("TestRunShardResponse" + testRunShardJson); + TestRunShard = shard; // due to wrong response type TODO + } + else + { + Logger.Log(true, LogLevel.Error, "Run shard creation Failed"); + } + } + else + { + Logger.Log(true, LogLevel.Error, "Run creation Failed"); + } + LogMessage("Test Run start Handler completed"); + } + + internal void TestMessageHandler(object? sender, TestRunMessageEventArgs e) + { + LogMessage("Test Message Handler"); + ValidateArg.NotNull(sender, nameof(sender)); + ValidateArg.NotNull(e, nameof(e)); + LogMessage(e.Message); + } + + internal void TestResultHandler(object? sender, TestResultEventArgs e) + { + LogMessage("Test Result Handler"); + if (!IsInitialized || _testReportingClient == null) + { + LogErrorMessage("Test Run setup issue exiting handler"); + return; + } + var testResultsJson = JsonConvert.SerializeObject(e); + LogMessage(testResultsJson); + + TestResults? testResult = GetTestCaseResultData(e.Result); + // Set various counts (passed tests, failed tests, total tests) + if (testResult != null) + { + TotalTestCount++; + if (testResult.Status == "failed") + { + FailedTestCount++; + } + else if (testResult.Status == "passed") + { + PassedTestCount++; + } + else if (testResult.Status == "skipped") + { + SkippedTestCount++; + } + } + if (testResult != null) + { + TestResults.Add(testResult); + } + } + + internal void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e) + { + LogMessage("Test Run End Handler"); + if (!IsInitialized || _testReportingClient == null || TestRun == null) + { + LogErrorMessage("Test Run setup issue exiting handler"); + return; + } + var testResultsJson = JsonConvert.SerializeObject(e); + LogMessage(testResultsJson); + LogMessage(JsonConvert.SerializeObject(TestResults)); + // Upload TestResults + var corelationId = Guid.NewGuid().ToString(); + var token = "Bearer " + AccessToken; + + var body = new UploadTestResultsRequest() { Value = TestResults }; + try + { +#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + _testReportingClient.WorkspacesTestResultsUploadBatchAsync( + WorkspaceId, + token, + corelationId, + _apiVersion, + body).GetAwaiter().GetResult(); +#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + LogMessage("Test Result Uploaded"); + } + catch (Exception ex) + { + LogErrorMessage(ex.Message); + } + + corelationId = Guid.NewGuid().ToString(); +#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + TestResultsUri sasUri = _testReportingClient.WorkspacesTestRunsResulturiAsync( + WorkspaceId, + RunId, + token, + corelationId, + _apiVersion).GetAwaiter().GetResult(); +#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + if (sasUri != null && !string.IsNullOrEmpty(sasUri.Uri)) + { + LogMessage("Test Run Uri: " + sasUri.ToString()); + foreach (TestResults testResult in TestResults) + { + if (RawTestResultsMap.TryGetValue(testResult.TestExecutionId, out RawTestResult? rawResult) && rawResult != null) + { + // Upload rawResult to blob storage using sasUri + var rawTestResultJson = JsonConvert.SerializeObject(rawResult); + var filePath = $"{testResult.TestExecutionId}/rawTestResult.json"; + UploadBuffer(sasUri.Uri, rawTestResultJson, filePath); + } + else + { + LogMessage("Couldnt find rawResult for Id: " + testResult.TestExecutionId); + } + } + } + else + { + Logger.Log(true, LogLevel.Error, "MPT API error: failed to upload artifacts"); + } + LogMessage("Test Results uploaded"); + // Update TestRun with CLIENT_COMPLETE + if (UpdateTestRun(e) == false) + { + LogErrorMessage("Test Run setup issue, Failed to update TestRun"); + } + } + #endregion + + private bool UpdateTestRun(TestRunCompleteEventArgs e) + { + if (!IsInitialized || _testReportingClient == null || TestRun == null || TestRunShard == null) + return false; + DateTime testRunStartedOn = DateTime.MinValue; + DateTime testRunEndedOn = DateTime.UtcNow; + long durationInMs = 0; + + var result = FailedTestCount > 0 ? "failed" : "passed"; + + if (e.ElapsedTimeInRunningTests != null) + { + testRunEndedOn = TestRunStartTime.Add(e.ElapsedTimeInRunningTests); + durationInMs = (long)e.ElapsedTimeInRunningTests.TotalMilliseconds; + } + + // Update Shard End + if (TestRunShard.Summary == null) + TestRunShard.Summary = new TestRunShardSummary(); + TestRunShard.Summary.Status = "CLIENT_COMPLETE"; + TestRunShard.Summary.StartTime = TestRunStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"); + TestRunShard.Summary.EndTime = testRunEndedOn.ToString("yyyy-MM-ddTHH:mm:ssZ"); + TestRunShard.Summary.TotalTime = durationInMs; + TestRunShard.Summary.UploadMetadata = new UploadMetadata() { NumTestResults = TotalTestCount, NumTotalAttachments = 0, SizeTotalAttachments = 0 }; + LogMessage("duration:" + durationInMs); + LogMessage("StartTime:" + TestRunShard.Summary.StartTime); + LogMessage("EndTime:" + TestRunShard.Summary.EndTime); + TestRunShard.ResultsSummary = new TestRunResultsSummary + { + NumTotalTests = TotalTestCount, + NumPassedTests = PassedTestCount, + NumFailedTests = FailedTestCount, + NumSkippedTests = SkippedTestCount, + NumFlakyTests = 0, // TODO: Implement flaky tests + Status = result + }; + TestRunShard.UploadCompleted = "true"; + var testRunShardJson = JsonConvert.SerializeObject(TestRunShard); + LogMessage(testRunShardJson); + var token = "Bearer " + AccessToken; + var corelationId = Guid.NewGuid().ToString(); + try + { +#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + _testReportingClient.WorkspacesTestRunsShardsAsync( + WorkspaceId, + RunId, + "1", + token, + corelationId, + _apiVersion, + TestRunShard).GetAwaiter().GetResult(); +#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + } + catch (Exception ex) + { + LogErrorMessage("Test Run shard failed: " + ex.ToString()); + throw; + } + + LogMessage("TestRun Shard updated"); + playwrightService?.Cleanup(); + Console.WriteLine("Visit MPT Portal for Debugging: " + Uri.EscapeUriString(PortalUrl!)); + return true; + } + + private TestResults GetTestCaseResultData(TestResult testResultSource) + { + if (testResultSource == null) + return new TestResults(); + + LogMessage(testResultSource.TestCase.DisplayName); + TestResults testCaseResultData = new() + { + ArtifactsPath = new List(), + + AccountId = WorkspaceId, + RunId = RunId, + TestExecutionId = GetExecutionId(testResultSource).ToString() + }; + testCaseResultData.TestCombinationId = testCaseResultData.TestExecutionId; // TODO check + testCaseResultData.TestId = testResultSource.TestCase.Id.ToString(); + testCaseResultData.TestTitle = testResultSource.TestCase.DisplayName; + var className = FetchTestClassName(testResultSource.TestCase.FullyQualifiedName); + testCaseResultData.SuiteTitle = className; + testCaseResultData.SuiteId = className; + testCaseResultData.FileName = FetchFileName(testResultSource.TestCase.Source); + testCaseResultData.LineNumber = testResultSource.TestCase.LineNumber; + testCaseResultData.Retry = 0; // TODO Retry and PreviousRetries + testCaseResultData.WebTestConfig = new WebTestConfig + { + JobName = CIInfo!.JobId, + //ProjectName = "playwright-dotnet", // TODO no project concept NA?? + //BrowserName = "chromium", // TODO check if possible to get from test + Os = GetCurrentOS(), + }; + //testCaseResultData.Annotations = ["windows"]; // TODO MSTest/Nunit annotation ?? + //testCaseResultData.Tags = ["windows"]; // TODO NA ?? + + TimeSpan duration = testResultSource.Duration; + testCaseResultData.ResultsSummary = new TestResultsSummary + { + Duration = (long)duration.TotalMilliseconds, // TODO fallback get from End-Start + StartTime = testResultSource.StartTime.UtcDateTime.ToString(), + Status = "inconclusive" + }; + TestOutcome outcome = testResultSource.Outcome; + switch (outcome) + { + case TestOutcome.Passed: + testCaseResultData.ResultsSummary.Status = "passed"; + testCaseResultData.Status = "passed"; + break; + case TestOutcome.Failed: + testCaseResultData.ResultsSummary.Status = "failed"; + testCaseResultData.Status = "failed"; + break; + case TestOutcome.Skipped: + testCaseResultData.ResultsSummary.Status = "skipped"; + testCaseResultData.Status = "skipped"; + break; + default: + testCaseResultData.ResultsSummary.Status = "inconclusive"; + testCaseResultData.Status = "inconclusive"; + break; + } + // errorMessage, Stacktrace + RawTestResult rawResult = GetRawResultObject(testResultSource); + RawTestResultsMap.TryAdd(testCaseResultData.TestExecutionId, rawResult); + + if (!string.IsNullOrEmpty(testResultSource.ErrorMessage)) + { + // TODO send it in blob + } + if (!string.IsNullOrEmpty(testResultSource.ErrorStackTrace)) + { + // TODO send it in blob + } + + // TODO ArtifactsPaths + return testCaseResultData; + } + + private TokenDetails ParseWorkspaceIdFromAccessToken(string accessToken) + { + TokenDetails tokenDetails = new(); + if (accessToken == null) + { + if (string.IsNullOrEmpty(accessToken)) + { + throw new ArgumentNullException("AccessToken is null or empty"); + } + } + try + { + JsonWebToken inputToken = (JsonWebToken)s_tokenHandler.ReadToken(accessToken); + var aid = inputToken.Claims.FirstOrDefault(c => c.Type == "aid")?.Value ?? string.Empty; + + if (!string.IsNullOrEmpty(aid)) // Custom Token + { + LogMessage("Custom Token parsing"); + tokenDetails.aid = aid; + tokenDetails.oid = inputToken.Claims.FirstOrDefault(c => c.Type == "oid")?.Value ?? string.Empty; + tokenDetails.id = inputToken.Claims.FirstOrDefault(c => c.Type == "id")?.Value ?? string.Empty; + tokenDetails.userName = inputToken.Claims.FirstOrDefault(c => c.Type == "name")?.Value ?? string.Empty; + } + else // Entra Token + { + LogMessage("Entra Token parsing"); + tokenDetails.aid = Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_WORKSPACE_ID) ?? string.Empty; + tokenDetails.oid = inputToken.Claims.FirstOrDefault(c => c.Type == "oid")?.Value ?? string.Empty; + tokenDetails.id = string.Empty; + tokenDetails.userName = inputToken.Claims.FirstOrDefault(c => c.Type == "name")?.Value ?? string.Empty; + // TODO add back suport for old claims https://devdiv.visualstudio.com/OnlineServices/_git/PlaywrightService?path=/src/Common/Authorization/JwtSecurityTokenValidator.cs&version=GBmain&line=200&lineEnd=200&lineStartColumn=30&lineEndColumn=52&lineStyle=plain&_a=contents + } + + return tokenDetails; + } + catch (Exception ex) + { + LogErrorMessage(ex.Message); + throw; + } + } + + private static Guid GetExecutionId(TestResult testResult) + { + TestProperty? executionIdProperty = testResult.Properties.FirstOrDefault( + property => property.Id.Equals(PlaywrightConstants.ExecutionIdPropertyIdentifier)); + + Guid executionId = Guid.Empty; + if (executionIdProperty != null) + executionId = testResult.GetPropertyValue(executionIdProperty, Guid.Empty); + + return executionId.Equals(Guid.Empty) ? Guid.NewGuid() : executionId; + } + + private static RawTestResult GetRawResultObject(TestResult testResultSource) + { + List errors = new();//[testResultSource.ErrorMessage]; + if (testResultSource.ErrorMessage != null) + errors.Add(new MPTError() { message = testResultSource.ErrorMessage }); + var rawTestResult = new RawTestResult + { + errors = JsonConvert.SerializeObject(errors), + stdErr = testResultSource?.ErrorStackTrace ?? string.Empty + }; + return rawTestResult; + } + + private static string GetCloudFilePath(string uri, string fileRelativePath) + { + // Assuming Constants.SAS_URI_SEPARATOR is a static property or field in a class named Constants + // that holds the character used to split the URI and the SAS token. + string[] parts = uri.Split(new string[] { PlaywrightConstants.SASUriSeparator }, StringSplitOptions.None); + string containerUri = parts[0]; + string sasToken = parts.Length > 1 ? parts[1] : string.Empty; + + return $"{containerUri}/{fileRelativePath}?{sasToken}"; + } + + private void UploadBuffer(string uri, string buffer, string fileRelativePath) + { + string cloudFilePath = GetCloudFilePath(uri, fileRelativePath); + LogMessage(cloudFilePath); + LogMessage(buffer); + BlobClient blobClient = new(new Uri(cloudFilePath)); + byte[] bufferBytes = Encoding.UTF8.GetBytes(buffer); + blobClient.Upload(new BinaryData(bufferBytes), overwrite: true); + LogMessage($"Uploaded buffer to {fileRelativePath}"); + } + + private static string FetchTestClassName(string fullyQualifiedName) + { + string[] parts = fullyQualifiedName.Split('.'); + return string.Join(".", parts.Take(parts.Length - 1)); + } + + private static string FetchFileName(string fullFilePath) + { + char[] delimiters = { '\\', '/' }; + string[] parts = fullFilePath.Split(delimiters); + return parts.Last(); + } + + private static string GetCurrentOS() + { + // we could return simplified name like "windows", "linux", "macos" + return Environment.OSVersion.Platform.ToString(); + } + + private void LogMessage(string message) + { + bool enable = bool.TryParse(EnableConsoleLog, out enable) == true && enable; + Logger.Log(enable, _logLevel, message); + } + + private static void LogErrorMessage(string message) + { + Logger.Log(true, LogLevel.Error, message); + } + + private void InitializePlaywrightReporter(string xmlSettings) + { + if (IsInitialized) + { + return; + } + + Dictionary runParameters = XmlRunSettingsUtilities.GetTestRunParameters(xmlSettings); + runParameters.TryGetValue(RunSettingKey.RUN_ID, out var runId); + runParameters.TryGetValue(RunSettingKey.DEFAULT_AUTH, out var defaultAuth); + runParameters.TryGetValue(RunSettingKey.AZURE_TOKEN_CREDENTIAL_TYPE, out var azureTokenCredential); + runParameters.TryGetValue(RunSettingKey.MANAGED_IDENTITY_CLIENT_ID, out var managedIdentityClientId); + PlaywrightServiceSettings? playwrightServiceSettings = null; + try + { + playwrightServiceSettings = new(runId: runId?.ToString(), defaultAuth: defaultAuth?.ToString(), azureTokenCredentialType: azureTokenCredential?.ToString(), managedIdentityClientId: managedIdentityClientId?.ToString()); + } + catch (Exception ex) + { + Console.Error.WriteLine("Failed to initialize PlaywrightServiceSettings: " + ex.Message); + Environment.Exit(1); + } + + // If run id is not provided and not set via env, try fetching it from CI info. + CIInfo = CiInfoProvider.GetCIInfo(); + if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID)) && !string.IsNullOrEmpty(CIInfo.RunId) && string.IsNullOrEmpty(runId?.ToString())) + { + Environment.SetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID, CIInfo.RunId); + } + else + { + PlaywrightService.GetDefaultRunId(); // will not set run id if already present in the environment variable + } + + // setup entra rotation handlers + playwrightService = new PlaywrightService(null, playwrightServiceSettings!.RunId, null, playwrightServiceSettings.DefaultAuth, null, playwrightServiceSettings.AzureTokenCredential); +#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + playwrightService.InitializeAsync().GetAwaiter().GetResult(); +#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + + RunId = Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID); + + try + { + ValidateArg.NotNullOrEmpty(BaseUrl, "Playwright Service URL"); + ValidateArg.NotNullOrEmpty(AccessToken, "Playwright Service Access Token"); + } + catch (Exception ex) + { + Console.Error.WriteLine("Missing values : " + ex.Message); + Environment.Exit(1); + } + + TotalTestCount = 0; + PassedTestCount = 0; + FailedTestCount = 0; + SkippedTestCount = 0; + + TestRunStartTime = DateTime.UtcNow; + TokenDetails = ParseWorkspaceIdFromAccessToken(AccessToken); + WorkspaceId = TokenDetails.aid; + LogMessage("RunId: " + RunId); + LogMessage("BaseUrl: " + BaseUrl); + LogMessage("Workspace Id: " + WorkspaceId); + + PortalUrl = PlaywrightConstants.PortalBaseUrl + WorkspaceId + PlaywrightConstants.ReportingRoute + RunId; + + _httpClient = new HttpClient(); + _testReportingClient = new TestReportingClient(BaseUrl, _httpClient); + + IsInitialized = true; + + LogMessage("Playwright Service Reporter Intialized"); + } +} \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/CiInfoProvider.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/CiInfoProvider.cs new file mode 100644 index 000000000000..97e332b62505 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/CiInfoProvider.cs @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; +using System; +using PlaywrightConstants = Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility.Constants; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility; + +internal class CiInfoProvider +{ + private static bool IsGitHubActions() + { + return Environment.GetEnvironmentVariable("GITHUB_ACTIONS") == "true"; + } + + private static bool IsAzureDevOps() + { + return Environment.GetEnvironmentVariable("AZURE_HTTP_USER_AGENT") != null && + Environment.GetEnvironmentVariable("TF_BUILD") != null; + } + + internal static string GetCIProvider() + { + if (IsGitHubActions()) + return PlaywrightConstants.GITHUB_ACTIONS; + else if (IsAzureDevOps()) + return PlaywrightConstants.AZURE_DEVOPS; + else + return PlaywrightConstants.DEFAULT; + } + + internal static CIInfo GetCIInfo() + { + string ciProvider = GetCIProvider(); + if (ciProvider == PlaywrightConstants.GITHUB_ACTIONS) + { + // Logic to get GitHub Actions CIInfo + return new CIInfo + { + Provider = PlaywrightConstants.GITHUB_ACTIONS, + Repo = Environment.GetEnvironmentVariable("GITHUB_REPOSITORY_ID"), + Branch = GetGHBranchName(), + Author = Environment.GetEnvironmentVariable("GITHUB_ACTOR"), + CommitId = Environment.GetEnvironmentVariable("GITHUB_SHA"), + RevisionUrl = Environment.GetEnvironmentVariable("GITHUB_SERVER_URL") != null + ? $"{Environment.GetEnvironmentVariable("GITHUB_SERVER_URL")}/{Environment.GetEnvironmentVariable("GITHUB_REPOSITORY")}/commit/{Environment.GetEnvironmentVariable("GITHUB_SHA")}" + : null, + RunId = Environment.GetEnvironmentVariable("GITHUB_RUN_ID"), + RunAttempt = Environment.GetEnvironmentVariable("GITHUB_RUN_ATTEMPT") != null + ? int.Parse(Environment.GetEnvironmentVariable("GITHUB_RUN_ATTEMPT")!) + : null, + JobId = Environment.GetEnvironmentVariable("GITHUB_JOB") + }; + } + else if (ciProvider == PlaywrightConstants.AZURE_DEVOPS) + { + // Logic to get Azure DevOps CIInfo + return new CIInfo + { + Provider = PlaywrightConstants.AZURE_DEVOPS, + Repo = Environment.GetEnvironmentVariable("BUILD_REPOSITORY_ID"), + Branch = Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH"), + Author = Environment.GetEnvironmentVariable("BUILD_REQUESTEDFOR"), + CommitId = Environment.GetEnvironmentVariable("BUILD_SOURCEVERSION"), + RevisionUrl = Environment.GetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI") != null + ? $"{Environment.GetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI")}{Environment.GetEnvironmentVariable("SYSTEM_TEAMPROJECT")}/_git/{Environment.GetEnvironmentVariable("BUILD_REPOSITORY_NAME")}/commit/{Environment.GetEnvironmentVariable("BUILD_SOURCEVERSION")}" + : null, + RunId = GetADORunId(), + RunAttempt = Environment.GetEnvironmentVariable("RELEASE_ATTEMPTNUMBER") != null + ? int.Parse(Environment.GetEnvironmentVariable("RELEASE_ATTEMPTNUMBER")!) + : int.Parse(Environment.GetEnvironmentVariable("SYSTEM_JOBATTEMPT")!), + JobId = Environment.GetEnvironmentVariable("RELEASE_DEPLOYMENTID") ?? Environment.GetEnvironmentVariable("SYSTEM_JOBID") + }; + } + else + { + // Handle unsupported CI provider + return new CIInfo + { + Provider = PlaywrightConstants.DEFAULT, + Repo = Environment.GetEnvironmentVariable("REPO"), + Branch = Environment.GetEnvironmentVariable("BRANCH"), + Author = Environment.GetEnvironmentVariable("AUTHOR"), + CommitId = Environment.GetEnvironmentVariable("COMMIT_ID"), + RevisionUrl = Environment.GetEnvironmentVariable("REVISION_URL"), + RunId = Environment.GetEnvironmentVariable("RUN_ID"), + RunAttempt = Environment.GetEnvironmentVariable("RUN_ATTEMPT") != null + ? int.Parse(Environment.GetEnvironmentVariable("RUN_ATTEMPT")!) + : null, + JobId = Environment.GetEnvironmentVariable("JOB_ID") + }; + } + } + + private static string GetADORunId() + { + if (Environment.GetEnvironmentVariable("RELEASE_DEFINITIONID") != null && Environment.GetEnvironmentVariable("RELEASE_DEPLOYMENTID") != null) + return $"{Environment.GetEnvironmentVariable("RELEASE_DEFINITIONID")}-{Environment.GetEnvironmentVariable("RELEASE_DEPLOYMENTID")}"; + else + return $"{Environment.GetEnvironmentVariable("SYSTEM_DEFINITIONID")}-{Environment.GetEnvironmentVariable("SYSTEM_JOBID")}"; + } + + private static string GetGHBranchName() + { + if (Environment.GetEnvironmentVariable("GITHUB_EVENT_NAME") == "pull_request" || + Environment.GetEnvironmentVariable("GITHUB_EVENT_NAME") == "pull_request_target") + return Environment.GetEnvironmentVariable("GITHUB_HEAD_REF")!; + else + return Environment.GetEnvironmentVariable("GITHUB_REF_NAME")!; + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs new file mode 100644 index 000000000000..ffc035c68b93 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility; + +internal static class Constants +{ + /// + /// Property Id storing the ExecutionId. + /// + internal const string ExecutionIdPropertyIdentifier = "ExecutionId"; + + /// + /// Property Id storing the ParentExecutionId. + /// + internal const string ParentExecutionIdPropertyIdentifier = "ParentExecId"; + + /// + /// Property If storing the TestType. + /// + internal const string TestTypePropertyIdentifier = "TestType"; + + internal const string SASUriSeparator = "?"; + + internal const string PortalBaseUrl = "https://playwright.microsoft.com/workspaces/"; + + internal const string ReportingRoute = "/runs/"; + + internal const string ReportingAPIVersion_2024_04_30_preview = "2024-04-30-preview"; + + internal const string ReportingAPIVersion_2024_05_20_preview = "2024-05-20-preview"; + + internal const string PLAYWRIGHT_SERVICE_REPORTING_URL = "PLAYWRIGHT_SERVICE_REPORTING_URL"; + + internal const string PLAYWRIGHT_SERVICE_WORKSPACE_ID = "PLAYWRIGHT_SERVICE_WORKSPACE_ID"; + + internal const string PLAYWRIGHT_SERVICE_ACCESS_TOKEN = "PLAYWRIGHT_SERVICE_ACCESS_TOKEN"; + + internal const string PLAYWRIGHT_SERVICE_DEBUG = "PLAYWRIGHT_SERVICE_DEBUG"; + + internal const string PLAYWRIGHT_SERVICE_RUN_ID = "PLAYWRIGHT_SERVICE_RUN_ID"; + + internal const string GITHUB_ACTIONS = "GitHub Actions"; + internal const string AZURE_DEVOPS = "Azure DevOps"; + internal const string DEFAULT = "Default"; +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Logger.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Logger.cs new file mode 100644 index 000000000000..e01a38ca0396 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Logger.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility; + +internal enum LogLevel +{ + Debug, + Info, + Warning, + Error +} + +internal static class Logger +{ + public static void Log(bool enableConsoleLog, LogLevel level, string message) + { + if (enableConsoleLog) + { + Console.WriteLine($"{DateTime.Now} [{level}]: {message}"); + } + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj new file mode 100644 index 000000000000..4b667d1db98b --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj @@ -0,0 +1,22 @@ + + + + enable + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs new file mode 100644 index 000000000000..64fedd3a4dca --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs @@ -0,0 +1,201 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Identity; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; +using Moq; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; + +[TestFixture] +public class EntraLifecycleTests +{ + private static string GetToken(Dictionary claims, DateTime? expires = null) + { + var tokenHandler = new JsonWebTokenHandler(); + var token = tokenHandler.CreateToken(new SecurityTokenDescriptor + { + Claims = claims, + Expires = expires ?? DateTime.UtcNow.AddMinutes(10), + }); + return token!; + } + + [TearDown] + public void TearDown() + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + } + + [Test] + public void Constructor_WhenAccessTokenEnvironmentIsNotSet_DoesNotInitializeEntraToken() + { + EntraLifecycle entraLifecycle = new(); + Assert.That(entraLifecycle._entraIdAccessToken, Is.Null); + } + + [Test] + public void Constructor_WhenAccessTokenEnvironmentIsSetButTokenIsNotValid_DoesNotInitializeEntraToken() + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + EntraLifecycle entraLifecycle = new(); + Assert.That(entraLifecycle._entraIdAccessToken, Is.Null); + } + + [Test] + public void Constructor_WhenAccessTokenEnvironmentIsSetAndTokenIsMPTCustomToken_DoesNotInitializeEntraToken() + { + var token = GetToken(new Dictionary + { + {"aid", "account-id-guid"}, + }); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + EntraLifecycle entraLifecycle = new(); + Assert.That(entraLifecycle._entraIdAccessToken, Is.Null); + } + + [Test] + public void Constructor_WhenAccessTokenEnvironmentIsSetAndTokenIsMPTCustomTokenWithAccountIdClaim_DoesNotInitializeEntraToken() + { + var token = GetToken(new Dictionary + { + {"accountId", "account-id-guid"}, + }); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + EntraLifecycle entraLifecycle = new(); + Assert.That(entraLifecycle._entraIdAccessToken, Is.Null); + } + + [Test] + public void Constructor_WhenJWTValidationThrowsException_DoesNotInitializeEntraToken() + { + var token = GetToken(new Dictionary()); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + var jsonWebTokenHandlerMock = new Mock(); + jsonWebTokenHandlerMock + .Setup(x => x.ReadJsonWebToken(token)) + .Throws(new Exception()); + EntraLifecycle entraLifecycle = new(jsonWebTokenHandler: jsonWebTokenHandlerMock.Object); + Assert.That(entraLifecycle._entraIdAccessToken, Is.Null); + } + + [Test] + public void Constructor_WhenAccessTokenEnvironmentIsSetAndValid_InitializeEntraToken() + { + var expiry = DateTime.UtcNow.AddMinutes(10); + var token = GetToken(new Dictionary(), expiry); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + EntraLifecycle entraLifecycle = new(); + Assert.Multiple(() => + { + Assert.That(entraLifecycle._entraIdAccessToken, Is.EqualTo(token)); + Assert.That(entraLifecycle._entraIdAccessTokenExpiry, Is.EqualTo((long)(expiry - new DateTime(1970, 1, 1)).TotalSeconds)); + }); + } + + [Test] + public async Task FetchEntraIdAccessTokenAsync_WhenTokenIsFetched_SetsEnvironmentVariable() + { + var defaultAzureCredentialMock = new Mock(); + var token = "valid_token"; + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); + EntraLifecycle entraLifecycle = new(defaultAzureCredentialMock.Object); + await entraLifecycle.FetchEntraIdAccessTokenAsync(); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE), Is.EqualTo(token)); + + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + } + + [Test] + public async Task FetchEntraIdAccessTokenAsync_WhenTokenIsFetched_SetsTokenAndExpiry() + { + var defaultAzureCredentialMock = new Mock(); + var token = "valid_token"; + var expiry = DateTimeOffset.UtcNow.AddMinutes(10); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken(token, expiry)); + EntraLifecycle entraLifecycle = new(defaultAzureCredentialMock.Object); + await entraLifecycle.FetchEntraIdAccessTokenAsync(); + Assert.That(entraLifecycle._entraIdAccessToken, Is.EqualTo(token)); + Assert.That(entraLifecycle._entraIdAccessTokenExpiry, Is.EqualTo((int)expiry.ToUnixTimeSeconds())); + + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + } + + [Test] + public async Task FetchEntraIdAccessTokenAsync_WhenTokenIsFetched_ReturnsTrue() + { + var defaultAzureCredentialMock = new Mock(); + var token = "valid_token"; + var expiry = DateTimeOffset.UtcNow.AddMinutes(10); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken(token, expiry)); + EntraLifecycle entraLifecycle = new(defaultAzureCredentialMock.Object); + Assert.That(await entraLifecycle.FetchEntraIdAccessTokenAsync(), Is.True); + + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + } + + [Test] + public async Task FetchEntraIdAccessTokenAsync_WhenThrowsError_ReturnsFalse() + { + var defaultAzureCredentialMock = new Mock(); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception("sample exception")); + EntraLifecycle entraLifecycle = new(defaultAzureCredentialMock.Object); + Assert.That(await entraLifecycle.FetchEntraIdAccessTokenAsync(), Is.False); + } + + [Test] + public void DoesEntraIdAccessTokenRequireRotation_WhenEntraIdAccessTokenIsEmpty_ReturnsTrue() + { + EntraLifecycle entraLifecycle = new() + { + _entraIdAccessToken = "" + }; + Assert.That(entraLifecycle.DoesEntraIdAccessTokenRequireRotation(), Is.True); + } + + [Test] + public void DoesEntraIdAccessTokenRequireRotation_WhenEntraIdAccessTokenIsNull_ReturnsTrue() + { + EntraLifecycle entraLifecycle = new() + { + _entraIdAccessToken = null + }; + Assert.That(entraLifecycle.DoesEntraIdAccessTokenRequireRotation(), Is.True); + } + + [Test] + public void DoesEntraIdAccessTokenRequireRotation_WhenTokenIsNotAboutToExpire_ReturnsFalse() + { + EntraLifecycle entraLifecycle = new() + { + _entraIdAccessToken = "valid_token", + _entraIdAccessTokenExpiry = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 1000 // more than threshold of 10 mins + }; + Assert.That(entraLifecycle.DoesEntraIdAccessTokenRequireRotation(), Is.False); + } + + [Test] + public void DoesEntraIdAccessTokenRequireRotation_WhenTokenIsAboutToExpire_ReturnsTrue() + { + EntraLifecycle entraLifecycle = new() + { + _entraIdAccessToken = "valid_token", + _entraIdAccessTokenExpiry = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 400 // less than threshold of 10 mins + }; + Assert.That(entraLifecycle.DoesEntraIdAccessTokenRequireRotation(), Is.True); + } +} \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs new file mode 100644 index 000000000000..0f1b2af6f278 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Identity; +using Azure.Developer.MicrosoftPlaywrightTesting; +using System; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; + +[TestFixture] +public class PlaywrightServiceSettingsTest +{ + [Test] + public void Constructor_ShouldInitializeProperties() + { + var os = ServiceOs.LINUX; + var runId = "test-run-id"; + var exposeNetwork = "true"; + var defaultAuth = ServiceAuth.ENTRA; + var useCloudHostedBrowsers = "true"; + var azureTokenCredentialType = AzureTokenCredentialType.ManagedIdentityCredential; + var managedIdentityClientId = "test-client-id"; + + var settings = new PlaywrightServiceSettings( + os, runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers, azureTokenCredentialType, managedIdentityClientId); + + Assert.Multiple(() => + { + Assert.That(settings.Os, Is.EqualTo(os)); + Assert.That(settings.RunId, Is.EqualTo(runId)); + Assert.That(settings.ExposeNetwork, Is.EqualTo(exposeNetwork)); + Assert.That(settings.DefaultAuth, Is.EqualTo(defaultAuth)); + Assert.That(settings.UseCloudHostedBrowsers, Is.True); + Assert.That(settings.AzureTokenCredential, Is.InstanceOf()); + }); + } + + [Test] + public void Constructor_ShouldUseDefaultValues() + { + var settings = new PlaywrightServiceSettings(); + Assert.Multiple(() => + { + Assert.That(settings.Os, Is.Null); + Assert.That(settings.RunId, Is.Null); + Assert.That(settings.ExposeNetwork, Is.Null); + Assert.That(settings.DefaultAuth, Is.EqualTo(ServiceAuth.ENTRA)); + Assert.That(settings.UseCloudHostedBrowsers, Is.True); + Assert.That(settings.AzureTokenCredential, Is.InstanceOf()); + }); + } + + [Test] + public void Validate_ShouldThrowExceptionForInvalidOs() + { + var invalidOs = "InvalidOS"; + var ex = Assert.Throws(() => new PlaywrightServiceSettings(os: invalidOs)); + Assert.That(ex!.Message, Does.Contain("Invalid value for Os")); + } + + [Test] + public void Validate_ShouldThrowExceptionForInvalidDefaultAuth() + { + var invalidAuth = "InvalidAuth"; + var ex = Assert.Throws(() => new PlaywrightServiceSettings(defaultAuth: invalidAuth)); + Assert.That(ex!.Message, Does.Contain("Invalid value for DefaultAuth")); + } + + [TestCase("ManagedIdentityCredential", typeof(ManagedIdentityCredential))] + [TestCase("WorkloadIdentityCredential", typeof(WorkloadIdentityCredential))] + [TestCase("EnvironmentCredential", typeof(EnvironmentCredential))] + [TestCase("AzureCliCredential", typeof(AzureCliCredential))] + [TestCase("AzurePowerShellCredential", typeof(AzurePowerShellCredential))] + [TestCase("AzureDeveloperCliCredential", typeof(AzureDeveloperCliCredential))] + [TestCase("InteractiveBrowserCredential", typeof(InteractiveBrowserCredential))] + [TestCase("SharedTokenCacheCredential", typeof(SharedTokenCacheCredential))] + [TestCase("VisualStudioCredential", typeof(VisualStudioCredential))] + [TestCase("VisualStudioCodeCredential", typeof(VisualStudioCodeCredential))] + [TestCase("DefaultAzureCredential", typeof(DefaultAzureCredential))] + [TestCase("", typeof(DefaultAzureCredential))] + [TestCase(null, typeof(DefaultAzureCredential))] + public void GetTokenCredential_ShouldReturnCorrectCredential(string? credentialType, Type expectedType) + { + var settings = new PlaywrightServiceSettings(azureTokenCredentialType: credentialType); + Assert.That(settings.AzureTokenCredential, Is.InstanceOf(expectedType)); + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs new file mode 100644 index 000000000000..e966ce147633 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs @@ -0,0 +1,660 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Identity; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; +using Moq; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; + +[TestFixture] +public class PlaywrightServiceTests +{ + private static string GetToken(Dictionary claims, DateTime? expires = null) + { + var tokenHandler = new JsonWebTokenHandler(); + var token = tokenHandler.CreateToken(new SecurityTokenDescriptor + { + Claims = claims, + Expires = expires ?? DateTime.UtcNow.AddMinutes(10), + }); + return token!; + } + + [SetUp] + public void Setup() + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, "https://playwright.microsoft.com"); + } + [TearDown] + public void TearDown() + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(Constants.s_playwright_service_disable_scalable_execution_environment_variable, null); + Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, null); + Environment.SetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable, null); + } + + [Test] + public void Constructor_NoConstructorParams_SetsEntraAuthMechanismAsDefault() + { + PlaywrightService service = new(entraLifecycle: null); + Assert.That(service.DefaultAuth, Is.EqualTo(ServiceAuth.ENTRA)); + } + + [Test] + public void Constructor_NoServiceParams_SetsDefaultValues() + { + var playwrightService = new PlaywrightService(entraLifecycle: null); + Assert.Multiple(() => + { + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE), Is.EqualTo(Constants.s_default_os)); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE), Is.EqualTo(Constants.s_default_expose_network)); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE), Is.Not.Null); + Assert.That(playwrightService.DefaultAuth, Is.EqualTo(ServiceAuth.ENTRA)); + Assert.That(playwrightService.UseCloudHostedBrowsers, Is.True); + }); + } + + [Test] + public void Constructor_PassServiceOS_SetsServiceOS() + { + _ = new PlaywrightService(os: ServiceOs.WINDOWS, entraLifecycle: null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE), Is.EqualTo(ServiceOs.WINDOWS)); + } + + [Test] + public void Constructor_PassExposeNetwork_SetsExposeNetwork() + { + _ = new PlaywrightService(exposeNetwork: "new-expose", entraLifecycle: null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE), Is.EqualTo("new-expose")); + } + + [Test] + public void Constructor_PassRunId_SetsRunId() + { + _ = new PlaywrightService(runId: "new-run-id", entraLifecycle: null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE), Is.EqualTo("new-run-id")); + } + + [Test] + public void Constructor_PassDefaultAuthMechanism_SetsDefaultAuthMechanism() + { + var playwrightService = new PlaywrightService(entraLifecycle: null, defaultAuth: ServiceAuth.TOKEN); + Assert.That(playwrightService.DefaultAuth, Is.EqualTo(ServiceAuth.TOKEN)); + } + + [Test] + public void Constructor_PassUseCloudHostedBrowsersAsFalse_SetsDisableScalableExecutionAndEnvVariable() + { + var playwrightService = new PlaywrightService(entraLifecycle: null, useCloudHostedBrowsers: false); + Assert.Multiple(() => + { + Assert.That(playwrightService.UseCloudHostedBrowsers, Is.False); + Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_disable_scalable_execution_environment_variable), Is.EqualTo("true")); + }); + } + + [Test] + public void Constructor_PassUseCloudHostedBrowsersAsTrue_SetsDisableScalableExecutionButNotEnvVariable() + { + var playwrightService = new PlaywrightService(entraLifecycle: null, useCloudHostedBrowsers: true); + Assert.Multiple(() => + { + Assert.That(playwrightService.UseCloudHostedBrowsers, Is.True); + Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_disable_scalable_execution_environment_variable), Is.Null); + }); + } + + [Test] + public void Initialize_WhenServiceEnpointIsNotSet_NoOP() + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + service.InitializeAsync().Wait(); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Never); + } + + [Test] + public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironmentVariableIsSet_FetchesEntraIdAccessToken() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + var token = "valid_token"; + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "access_token"); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + service.InitializeAsync().Wait(); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); + + service.RotationTimer!.Dispose(); + + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE), Is.Not.Null); + } + + [Test] + public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironmentVariableIsSetAndCredentialsArePassed_FetchesEntraIdAccessTokenUsedPassedCredentials() + { + var tokenCredential = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + var token = "valid_token"; + tokenCredential + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "access_token"); + PlaywrightService service = new(new PlaywrightServiceSettings(), tokenCredential: tokenCredential.Object); + service.InitializeAsync().Wait(); + tokenCredential.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); + + service.RotationTimer!.Dispose(); + + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE), Is.Not.Null); + } + + [Test] + public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironmentVariableIsSetButScalableExecutionIsDisabled_DeletesServiceUrlEnvVariable() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + var token = "valid_token"; + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "access_token"); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, useCloudHostedBrowsers: false); + + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE), Is.Not.Null); + + service.InitializeAsync().Wait(); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); + + service.RotationTimer!.Dispose(); + + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE), Is.Null); + } + + [Test] + public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironmentVariableIsNotSet_FetchesEntraIdAccessToken() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + var token = "valid_token"; + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + service.InitializeAsync().Wait(); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); + + service.RotationTimer!.Dispose(); + } + + [Test] + public void Initialize_WhenFetchesEntraIdAccessToken_SetsUpRotationHandler() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + var token = "valid_token"; + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + service.InitializeAsync().Wait(); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); + Assert.That(service.RotationTimer, Is.Not.Null); + + service.RotationTimer!.Dispose(); + } + + [Test] + public void Initialize_WhenFailsToFetchEntraIdAccessToken_DoesNotSetUpRotationHandler() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + service.InitializeAsync().Wait(); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); + Assert.That(service.RotationTimer, Is.Null); + } + + [Test] + public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatIsSet_DoesNotSetUpRotationHandler() + { + var token = GetToken(new Dictionary + { + {"aid", "account-id-guid"}, + }); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + var defaultAzureCredentialMock = new Mock(); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, new JsonWebTokenHandler()); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: new JsonWebTokenHandler()); + service.InitializeAsync().Wait(); + Assert.That(service.RotationTimer, Is.Null); + } + + [Test] + public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatIsNotSet_DoesNotSetUpRotationHandler() + { + var token = GetToken(new Dictionary + { + {"aid", "account-id-guid"}, + }); + var defaultAzureCredentialMock = new Mock(); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, new JsonWebTokenHandler()); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: new JsonWebTokenHandler()); + service.InitializeAsync().Wait(); + Assert.That(service.RotationTimer, Is.Null); + } + + [Test] + public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatIsNotValid_ThrowsError() + { + var token = "sample token"; + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + var defaultAzureCredentialMock = new Mock(); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, new JsonWebTokenHandler()); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: new JsonWebTokenHandler()); + Assert.That(() => service.InitializeAsync().Wait(), Throws.Exception); + } + + [Test] + public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatTokenParsingReturnsNull_ThrowsError() + { + var token = "sample token"; + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + var jsonWebTokenHandlerMock = new Mock(); +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + jsonWebTokenHandlerMock + .Setup(x => x.ReadJsonWebToken(It.IsAny())) + .Returns(value: null); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. + var defaultAzureCredentialMock = new Mock(); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, new JsonWebTokenHandler()); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: jsonWebTokenHandlerMock.Object); + Assert.That(() => service.InitializeAsync().Wait(), Throws.Exception); + } + + [Test] + public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatIsExpired_ThrowsError() + { + var token = GetToken(new Dictionary + { + {"aid", "account-id-guid"}, + }, DateTime.UtcNow.AddMinutes(-1)); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + var defaultAzureCredentialMock = new Mock(); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, new JsonWebTokenHandler()); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: new JsonWebTokenHandler()); + + Assert.That(() => service.InitializeAsync().Wait(), Throws.Exception); + } + + [Test] + public void Initialize_WhenDefaultAuthIsMptPATAndPATIsSet_DoesNotSetUpRotationHandler() + { + var token = GetToken(new Dictionary + { + {"aid", "account-id-guid"}, + }); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + var defaultAzureCredentialMock = new Mock(); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, new JsonWebTokenHandler()); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: new JsonWebTokenHandler(), defaultAuth: ServiceAuth.TOKEN); + service.InitializeAsync().Wait(); + Assert.That(service.RotationTimer, Is.Null); + } + + [Test] + public void RotationHandler_WhenEntraIdAccessTokenRequiresRotation_FetchesEntraIdAccessToken() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + var token = "valid_token"; + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(5))); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + + service.RotationHandlerAsync(null); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public void RotationHandler_WhenEntraIdAccessTokenDoesNotRequireRotation_NoOp() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + entraLifecycleMock.Object._entraIdAccessToken = "valid_token"; + entraLifecycleMock.Object._entraIdAccessTokenExpiry = (int)DateTimeOffset.UtcNow.AddMinutes(22).ToUnixTimeSeconds(); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + + service.RotationHandlerAsync(null); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Never); + } + + [Test] + public void GetConnectOptionsAsync_WhenServiceEndpointIsNotSet_ThrowsException() + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); + PlaywrightService service = new(entraLifecycle: null); + var ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); + Assert.That(ex!.Message, Is.EqualTo(Constants.s_no_service_endpoint_error_message)); + } + + [Test] + public void GetConnectOptionsAsync_WhenUseCloudHostedBrowsersEnvironmentIsFalse_ThrowsException() + { + PlaywrightService service = new(entraLifecycle: null, useCloudHostedBrowsers: false); + var ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); + Assert.Multiple(() => + { + Assert.That(service.UseCloudHostedBrowsers, Is.False); + Assert.That(ex!.Message, Is.EqualTo(Constants.s_service_endpoint_removed_since_scalable_execution_disabled_error_message)); + }); + } + + [Test] + public async Task GetConnectOptionsAsync_WhenServiceEndpointIsSet_ReturnsConnectOptions() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + entraLifecycleMock.Object._entraIdAccessToken = "valid_token"; + entraLifecycleMock.Object._entraIdAccessTokenExpiry = (int)DateTimeOffset.UtcNow.AddMinutes(22).ToUnixTimeSeconds(); + var runId = "run-id"; + + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + var connectOptions = await service.GetConnectOptionsAsync(runId: runId); + var authorizationHeader = connectOptions.Options!.Headers!.Where(x => x.Key == "Authorization").FirstOrDefault().Value!; + Assert.Multiple(() => + { + Assert.That(connectOptions.WsEndpoint, Is.EqualTo($"https://playwright.microsoft.com?os={Constants.s_default_os}&runId={runId}&api-version={Constants.s_api_version}")); + Assert.That(connectOptions.Options!.Timeout, Is.EqualTo(3 * 60 * 1000)); + Assert.That(connectOptions.Options!.ExposeNetwork, Is.EqualTo(Constants.s_default_expose_network)); + Assert.That(authorizationHeader, Is.EqualTo("Bearer valid_token")); + }); + } + + [Test] + public async Task GetConnectOptionsAsync_WhenTokenRequiresRotation_RotatesEntraToken() + { + var defaultAzureCredentialMock = new Mock(); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken("valid_token", DateTimeOffset.UtcNow.AddMinutes(5))); + var jsonWebTokenHandlerMock = new Mock(); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + entraLifecycleMock.Object._entraIdAccessToken = "valid_token"; + entraLifecycleMock.Object._entraIdAccessTokenExpiry = (int)DateTimeOffset.UtcNow.AddMinutes(-1).ToUnixTimeSeconds(); + + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + _ = await service.GetConnectOptionsAsync(); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); + } + + [Test] + public async Task GetConnectOptionsAsync_WhenTokenDoesNotRequireRotation_DoesNotRotateEntraToken() + { + var defaultAzureCredentialMock = new Mock(); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + defaultAzureCredentialMock + .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new AccessToken("valid_token", DateTimeOffset.UtcNow.AddMinutes(5))); + var jsonWebTokenHandlerMock = new Mock(); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + entraLifecycleMock.Object._entraIdAccessToken = "valid_token"; + entraLifecycleMock.Object._entraIdAccessTokenExpiry = (int)DateTimeOffset.UtcNow.AddMinutes(22).ToUnixTimeSeconds(); + + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); + _ = await service.GetConnectOptionsAsync(); + defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Never); + } + + [Test] + public async Task GetConnectOptionsAsync_WhenDefaultParametersAreProvided_SetsServiceParameters() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + entraLifecycleMock.Object + ._entraIdAccessToken = "valid_token"; + entraLifecycleMock.Object + ._entraIdAccessTokenExpiry = (int)DateTimeOffset.UtcNow.AddMinutes(22).ToUnixTimeSeconds(); + var runId = "run-id"; + + var service = new PlaywrightService(entraLifecycle: entraLifecycleMock.Object); + var connectOptions = await service.GetConnectOptionsAsync(runId: runId, os: ServiceOs.WINDOWS, exposeNetwork: "localhost"); + + Assert.Multiple(() => + { + Assert.That(connectOptions.WsEndpoint, Is.EqualTo($"https://playwright.microsoft.com?os={ServiceOs.WINDOWS}&runId={runId}&api-version={Constants.s_api_version}")); + Assert.That(connectOptions.Options!.ExposeNetwork, Is.EqualTo("localhost")); + }); + } + + [Test] + public async Task GetConnectOptionsAsync_WhenDefaultParametersAreNotProvided_SetsDefaultServiceParameters() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + entraLifecycleMock.Object + ._entraIdAccessToken = "valid_token"; + entraLifecycleMock.Object + ._entraIdAccessTokenExpiry = (int)DateTimeOffset.UtcNow.AddMinutes(22).ToUnixTimeSeconds(); + var runId = "run-id"; + + var service = new PlaywrightService(entraLifecycle: entraLifecycleMock.Object); + var connectOptions = await service.GetConnectOptionsAsync(runId: runId); + + Assert.Multiple(() => + { + Assert.That(connectOptions.WsEndpoint, Is.EqualTo($"https://playwright.microsoft.com?os={Constants.s_default_os}&runId={runId}&api-version={Constants.s_api_version}")); + Assert.That(connectOptions.Options!.ExposeNetwork, Is.EqualTo(Constants.s_default_expose_network)); + }); + } + + [Test] + public async Task GetConnectOptionsAsync_WhenServiceParametersAreSetViaEnvironment_SetsServiceParameters() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + entraLifecycleMock.Object + ._entraIdAccessToken = "valid_token"; + entraLifecycleMock.Object + ._entraIdAccessTokenExpiry = (int)DateTimeOffset.UtcNow.AddMinutes(22).ToUnixTimeSeconds(); + var runId = "run-id"; + var service = new PlaywrightService(entraLifecycle: entraLifecycleMock.Object); + + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE, ServiceOs.WINDOWS); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE, "localhost"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); + + var connectOptions = await service.GetConnectOptionsAsync(); + Assert.Multiple(() => + { + Assert.That(connectOptions.WsEndpoint, Is.EqualTo($"https://playwright.microsoft.com?os={ServiceOs.WINDOWS}&runId={runId}&api-version={Constants.s_api_version}")); + Assert.That(connectOptions.Options!.ExposeNetwork, Is.EqualTo("localhost")); + }); + } + + [Test] + public void GetConnectOptionsAsync_WhenNoAuthTokenIsSet_ThrowsException() + { + var defaultAzureCredentialMock = new Mock(); + var jsonWebTokenHandlerMock = new Mock(); + var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); + var service = new PlaywrightService(entraLifecycle: entraLifecycleMock.Object); + + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + + var ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); + Assert.That(ex!.Message, Is.EqualTo(Constants.s_no_auth_error)); + } + + [Test] + public void GetDefaultRunId_RunIdSetViaEnvironmentVariable_ReturnsRunId() + { + var runId = "run-id"; + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); + Assert.Multiple(() => + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, null); + Assert.That(PlaywrightService.GetDefaultRunId(), Is.Not.Null); + }); + } + + [Test] + public void GetDefaultRunId_RunIdNotSetViaEnvironmentVariable_ReturnsRandomRunId() + { + Assert.Multiple(() => + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, null); + Assert.That(PlaywrightService.GetDefaultRunId(), Is.Not.Null); + }); + } + + [Test] + public void SetReportingUrlAndWorkspaceId_WhenServiceEndpointIsSet_SetsReportingUrlAndWorkspaceId() + { + var testRubricCombinations = new List>() + { + new() + { + { "url", "wss://eastus.api.playwright.microsoft.com/accounts/eastus_bd830e63-6120-40cb-8cd7-f0739502d888/browsers" }, + { "workspaceId", "eastus_bd830e63-6120-40cb-8cd7-f0739502d888" }, + { "region", "eastus" }, + { "domain", "playwright.microsoft.com" } + }, + new() + { + { "url", "wss://eastus.api.playwright.microsoft.com/accounts/77a38aac-4577-43a9-ac72-5720e5459c5a/browsers" }, + { "workspaceId", "77a38aac-4577-43a9-ac72-5720e5459c5a" }, + { "region", "eastus" }, + { "domain", "playwright.microsoft.com" } + }, + new() + { + { "url", "wss://westus3.api.playwright.microsoft.com/accounts/ad3cf59a-43e1-4dbe-af22-49bfe72b4178/browsers" }, + { "workspaceId", "ad3cf59a-43e1-4dbe-af22-49bfe72b4178" }, + { "region", "westus3" }, + { "domain", "playwright.microsoft.com" } + }, + new() + { + { "url", "wss://westus3.api.playwright-int.io/accounts/3c9ae1d4-e856-4ce0-8b56-1f4488676dff/browsers" }, + { "workspaceId", "3c9ae1d4-e856-4ce0-8b56-1f4488676dff" }, + { "region", "westus3" }, + { "domain", "playwright-int.io" } + }, + new() + { + { "url", "wss://eastasia.api.playwright-test.io/accounts/29abee44-a5f4-477e-9ff1-6c6786d09c7c/browsers" }, + { "workspaceId", "29abee44-a5f4-477e-9ff1-6c6786d09c7c" }, + { "region", "eastasia" }, + { "domain", "playwright-test.io" } + } + }; + + foreach (var testRubric in testRubricCombinations) + { + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, $"{testRubric["url"]}"); + var service = new PlaywrightService(entraLifecycle: null); + Assert.Multiple(() => + { + Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable), Is.EqualTo($"https://{testRubric["region"]}.reporting.api.{testRubric["domain"]}")); + Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable), Is.EqualTo(testRubric["workspaceId"])); + }); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, null); + Environment.SetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable, null); + } + } + + [Test] + public void SetReportingUrlAndWorkspaceId_WhenReportingServiceEndpointIsSet_OnlySetsWorkspaceId() + { + var testRubric = new Dictionary + { + { "url", "wss://eastus.api.playwright.microsoft.com/accounts/eastus_bd830e63-6120-40cb-8cd7-f0739502d888/browsers" }, + { "workspaceId", "eastus_bd830e63-6120-40cb-8cd7-f0739502d888" }, + { "region", "eastus" }, + { "domain", "playwright.microsoft.com" } + }; + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, $"{testRubric["url"]}"); + Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, "https://playwright.microsoft.com"); + var service = new PlaywrightService(entraLifecycle: null); + Assert.Multiple(() => + { + Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable), Is.EqualTo("https://playwright.microsoft.com")); + Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable), Is.EqualTo(testRubric["workspaceId"])); + }); + } + + [Test] + public void SetReportingUrlAndWorkspaceId_WhenReportingServiceEndpointAndWorkspaceIdIsSet_NoOp() + { + var testRubric = new Dictionary + { + { "url", "wss://eastus.api.playwright.microsoft.com/accounts/eastus_bd830e63-6120-40cb-8cd7-f0739502d888/browsers" }, + { "workspaceId", "eastus_bd830e63-6120-40cb-8cd7-f0739502d888" }, + { "region", "eastus" }, + { "domain", "playwright.microsoft.com" } + }; + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, $"{testRubric["url"]}"); + Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, "https://playwright.microsoft.com"); + Environment.SetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable, "sample-id"); + var service = new PlaywrightService(entraLifecycle: null); + Assert.Multiple(() => + { + Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable), Is.EqualTo("https://playwright.microsoft.com")); + Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable), Is.EqualTo("sample-id")); + }); + } +} From cb8de63f9b0be0b0aff7b11d385642a94b92893e Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Tue, 16 Jul 2024 20:28:33 +0000 Subject: [PATCH 02/32] chore(): add support for github summary --- .../UnitTest1.cs | 2 - .../UnitTest1.cs | 2 - .../samples/using-manual-launch/UnitTest1.cs | 1 - .../src/Constants.cs | 5 +++ .../src/TestLogger/PlaywrightReporter.cs | 38 +++++++++++++++++++ 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs index f37d1f2ae33d..8796cf2565ce 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs @@ -11,7 +11,6 @@ namespace PlaywrightTests; public class ExampleTest : PageTest { [Test] - [Category("Live")] public async Task HasTitle() { await Page.GotoAsync("https://playwright.dev"); @@ -21,7 +20,6 @@ public async Task HasTitle() } [Test] - [Category("Live")] public async Task GetStartedLink() { await Page.GotoAsync("https://playwright.dev"); diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs index f37d1f2ae33d..8796cf2565ce 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs @@ -11,7 +11,6 @@ namespace PlaywrightTests; public class ExampleTest : PageTest { [Test] - [Category("Live")] public async Task HasTitle() { await Page.GotoAsync("https://playwright.dev"); @@ -21,7 +20,6 @@ public async Task HasTitle() } [Test] - [Category("Live")] public async Task GetStartedLink() { await Page.GotoAsync("https://playwright.dev"); diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs index 173f459a32ec..583f5050b9d8 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs @@ -41,7 +41,6 @@ public async Task PageTeardown() } [Test] - [Category("Live")] public async Task HasTitle() { await _page.GotoAsync("https://playwright.dev"); diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs index f41be08719cd..77509b258755 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs @@ -166,6 +166,11 @@ public class RunSettingKey /// The managed identity client ID setting key. /// public static readonly string MANAGED_IDENTITY_CLIENT_ID = "ManagedIdentityClientId"; + + /// + /// Enable GitHub summary setting key. + /// + public static readonly string ENABLE_GITHUB_SUMMARY = "EnableGitHubSummary"; } internal class Constants diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index 0ecceb0760b4..b111d1062587 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -18,6 +18,7 @@ using System.Text; using PlaywrightConstants = Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility.Constants; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; +using System.IO; namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; @@ -69,6 +70,8 @@ internal class PlaywrightReporter : ITestLoggerWithParameters internal TestRunShardDto? TestRunShard { get; set; } + internal bool EnableGithubSummary { get; set; } = true; + internal List TestResults = new(); internal ConcurrentDictionary RawTestResultsMap = new(); @@ -413,6 +416,7 @@ private bool UpdateTestRun(TestRunCompleteEventArgs e) LogMessage("TestRun Shard updated"); playwrightService?.Cleanup(); Console.WriteLine("Visit MPT Portal for Debugging: " + Uri.EscapeUriString(PortalUrl!)); + if (EnableGithubSummary) GenerateMarkdownSummary(); return true; } @@ -624,6 +628,10 @@ private void InitializePlaywrightReporter(string xmlSettings) runParameters.TryGetValue(RunSettingKey.DEFAULT_AUTH, out var defaultAuth); runParameters.TryGetValue(RunSettingKey.AZURE_TOKEN_CREDENTIAL_TYPE, out var azureTokenCredential); runParameters.TryGetValue(RunSettingKey.MANAGED_IDENTITY_CLIENT_ID, out var managedIdentityClientId); + runParameters.TryGetValue(RunSettingKey.ENABLE_GITHUB_SUMMARY, out var enableGithubSummary); + string? enableGithubSummaryString = enableGithubSummary?.ToString(); + EnableGithubSummary = string.IsNullOrEmpty(enableGithubSummaryString) || bool.Parse(enableGithubSummaryString!); + PlaywrightServiceSettings? playwrightServiceSettings = null; try { @@ -686,4 +694,34 @@ private void InitializePlaywrightReporter(string xmlSettings) LogMessage("Playwright Service Reporter Intialized"); } + + public void GenerateMarkdownSummary() + { + if (CiInfoProvider.GetCIProvider() == PlaywrightConstants.GITHUB_ACTIONS) + { + string markdownContent = @$" +#### Results: + +![pass](https://img.shields.io/badge/status-passed-brightgreen) **Passed:** {TestRunShard!.ResultsSummary.NumPassedTests} + +![fail](https://img.shields.io/badge/status-failed-red) **Failed:** {TestRunShard!.ResultsSummary.NumFailedTests} + +![flaky](https://img.shields.io/badge/status-flaky-yellow) **Flaky:** {"0"} + +![skipped](https://img.shields.io/badge/status-skipped-lightgrey) **Skipped:** {TestRunShard!.ResultsSummary.NumSkippedTests} + +#### For more details, visit the [service dashboard]({Uri.EscapeUriString(PortalUrl!)}). +"; + + string filePath = Environment.GetEnvironmentVariable("GITHUB_STEP_SUMMARY"); + try + { + File.WriteAllText(filePath, markdownContent); + } + catch (Exception ex) + { + LogErrorMessage($"Error writing Markdown summary: {ex}"); + } + } + } } \ No newline at end of file From 8b57e8e9e50c2ef442fccfa242b0e14a70ad9d3c Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Tue, 16 Jul 2024 22:47:38 +0000 Subject: [PATCH 03/32] docs(): sample, CHANGELOG and README --- .../CHANGELOG.md | 18 +++ .../README.md | 125 +++++++++++++++++ .../samples/README.md | 16 +++ .../customising-service-parameters/README.md | 128 ++++++++++++++++++ .../.runsettings | 0 .../PlaywrightServiceSetup.cs | 0 .../PlaywrightTests.csproj | 0 .../manually-connecting-to-browsers/README.md | 94 +++++++++++++ .../UnitTest1.cs | 0 .../README.md | 92 +++++++++++++ .../samples/using-manual-launch/README.md | 0 .../README.md | 52 +++++++ sdk/playwrighttesting/ci.yml | 41 ++++++ 13 files changed, 566 insertions(+) create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md rename sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/{using-manual-launch => manually-connecting-to-browsers}/.runsettings (100%) rename sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/{using-manual-launch => manually-connecting-to-browsers}/PlaywrightServiceSetup.cs (100%) rename sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/{using-manual-launch => manually-connecting-to-browsers}/PlaywrightTests.csproj (100%) create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md rename sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/{using-manual-launch => manually-connecting-to-browsers}/UnitTest1.cs (100%) delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/README.md create mode 100644 sdk/playwrighttesting/ci.yml diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md index e69de29bb2d1..376422decdbb 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md @@ -0,0 +1,18 @@ +# 1.0.0-beta.1 (2024-07-31) + +## Added + +- **Initial release of the package**: This is the first version of the Microsoft Playwright Testing service package for NUnit. It enables you to integrate your NUnit Playwright test suite with the Microsoft Playwright Testing service. +- The service package enables you to: + - Expedite your Playwright test suite by running more tests in parallel on cloud-hosted browsers. + - Improve test coverage by enabling you to test on multiple OS-browser combinations. + - Troubleshoot easily and faster by publishing test results and artifacts generated by Playwright to the service and viewing them in the service portal. + +## Useful Links +- [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart) +- [Quickstart: Set up continuous end-to-end testing across different browsers and operating systems](https://aka.ms/mpt/ci) +- [Explore features and benefits](https://aka.ms/mpt/about) +- [View Microsoft Playwright Testing service demo](https://youtu.be/GenC1jAeTZE) +- [Documentation](https://aka.ms/mpt/docs) +- [Pricing](https://aka.ms/mpt/pricing) +- [Share feedback](https://aka.ms/mpt/feedback) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md index e69de29bb2d1..1a87a3369ad8 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md @@ -0,0 +1,125 @@ +# Microsoft Playwright Testing preview + +Microsoft Playwright Testing is a fully managed service that uses the cloud to enable you to run Playwright tests with much higher parallelization across different operating system-browser combinations simultaneously. This means faster test runs with broader scenario coverage, which helps speed up delivery of features without sacrificing quality. The service also enables you to publish test results and related artifacts to the service and view them in the service portal enabling faster and easier troubleshooting. With Microsoft Playwright Testing service, you can release features faster and more confidently. + +Ready to get started? Jump into our [quickstart guide](#get-started)! + + +## Useful Links +- [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart) +- [Quickstart: Set up continuous end-to-end testing across different browsers and operating systems](https://aka.ms/mpt/ci) +- [Explore features and benefits](https://aka.ms/mpt/about) +- [View Microsoft Playwright Testing service demo](https://youtu.be/GenC1jAeTZE) +- [Documentation](https://aka.ms/mpt/docs) +- [Pricing](https://aka.ms/mpt/pricing) +- [Share feedback](https://aka.ms/mpt/feedback) + +## Get Started +Follow these steps to run your existing Playwright test suite with the service. + +### Prerequisites + +- An Azure account with an active subscription. If you don't have an Azure subscription, [create a free account](https://aka.ms/mpt/create-azure-subscription) before you begin. +- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). +- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) must be installed in the machine from where you are running Playwright tests. + +### Create a Workspace + +1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account. + +2. Create the Workspace. + + ![Create new workspace](https://github.com/microsoft/playwright-testing-service/assets/12104064/d571e86b-9d43-48ac-a2b7-63afb9bb86a8) + + |Field |Description | + |---------|---------| + |**Workspace Name** | A unique name to identify your workspace.
The name can't contain special characters or whitespace. | + |**Azure Subscription** | Select an Azure subscription where you want to create the workspace. | + |**Region** | This is where test run data will be stored for your workspace. | + + > [!NOTE] + > If you don't see this screen, select an existing workspace and go to the next section. + +### Install Microsoft Playwright Testing package + +1. Run this command to install the service package + + ```dotnetcli + dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit + ``` + +### Setup Microsoft Playwright Testing + +1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the below content + + ```c# + using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; + + namespace PlaywrightTests; // Remember to change this as per your project namespace + + [SetUpFixture] + public class PlaywrightServiceSetup : PlaywrightServiceNUnit; + ``` + +> [!NOTE] +> Make sure your project uses Microsoft.Playwright.NUnit version 1.37 or above. + +### Obtain region endpoint + +1. In the [Playwright portal](https://aka.ms/mpt/portal), copy the command under **Add region endpoint in your set up**. + + ![Set workspace endpoint](https://github.com/microsoft/playwright-testing-service/assets/12104064/d81ca629-2b23-4d34-8b70-67b6f7061a83) + + The endpoint URL corresponds to the workspace region. You might see a different endpoint URL in the Playwright portal, depending on the region you selected when creating the workspace. + +### Set up environment + +Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is available in your environment. + +### Sign in to Azure + +You need to sign in to Azure using Azure CLI to enable authentication via Entra ID. Run the command to sign-in + +```azurecli +az login +``` + +**NOTE**: If you are a part of multiple tenants, you will have to login to a particular tenant. Run `az login --tenant=' to sign in to the tenant where the workspace is created. You can find the tenant id through these [steps.](https://learn.microsoft.com/en-us/entra/fundamentals/how-to-find-tenant) + +### Run the tests + +Run Playwright tests against browsers managed by the service using the configuration you created above. + +```dotnetcli +dotnet test --logger "ms-playwright-service" +``` + +## Next steps + +- Run tests in a [CI/CD pipeline.](https://aka.ms/mpt/configure-pipeline) + +- Learn how to [manage access](https://aka.ms/mpt/manage-access) to the created workspace. + +- Experiment with different number of workers to [determine the optimal configuration of your test suite](https://aka.ms/mpt/parallelism). + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## Trademarks + +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft +trademarks or logos is subject to and must follow +[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). +Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. +Any use of third-party trademarks or logos is subject to those third-party's policies. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md new file mode 100644 index 000000000000..e46a6f61296c --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md @@ -0,0 +1,16 @@ +--- +page_type: sample +languages: +- csharp +products: +- azure +- microsoft-playwright-testing +name: Azure.Developer.MicrosoftPlaywrightTesting.NUnit samples for .NET +description: Samples for the Azure.Developer.MicrosoftPlaywrightTesting.NUnit client library +--- + +# Azure.Developer.MicrosoftPlaywrightTesting.NUnit samples for .NET + +- [Manually connecting to browsers](./manually-connecting-to-browsers/README.md) +- [Customising service parameters](./customising-service-parameters/README.md) +- [Set default authentication mechanism](./set-default-authentication-mechanism/README.md) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md index e69de29bb2d1..ac32901b04b8 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md @@ -0,0 +1,128 @@ +## Learn about different available service parameters and how to use them + +Follow the steps listed in this [README](../../README.md) to integrate your existing Playwright test suite with the Microsoft Playwright Testing service. + +This guide explains the different options available to you in the Azure.Developer.MicrosoftPlaywrightTesting.NUnit package and how to use them. + +### Using runsettings file + +1. Create a `.runsettings` file in the root directory + + ```xml + + + + + + + + + + + + + + + + + + + + + ``` + + > [!NOTE] + > You can also modify the runid by setting the environment variable `PLAYWRIGHT_SERVICE_RUN_ID`. + +2. Run tests using the above runsettings file + + ```dotnetcli + dotnet test --settings .runsettings + ``` + +#### Known Issue - Minimal support for Azure Credentials + +This issue only impacts the reporting feature. Currently, the service provides a minimal support for the below [Azure Credential types](https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme?view=azure-dotnet) + +- EnvironmentCredential +- WorkloadIdentityCredential +- ManagedIdentityCredential +- SharedTokenCacheCredential +- VisualStudioCredential +- VisualStudioCodeCredential +- AzureCliCredential +- AzurePowerShellCredential +- AzureDeveloperCliCredential +- InteractiveBrowserCredential +- DefaultAzureCredential (Default) + +Along with this, we also support passing a Managed Identity ClientId to be used along with `DefaultAzureCredential` and `ManagedIdentityCredential`. + +If you only want to use cloud hosted browsers along with your tests, you can disable the reporting feature by removing the logger from the runsettings file and then modify the `PlaywrightServiceSetup.cs` file as per below. + +```c# +using Azure.Core; +using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; +using Azure.Identity; + +namespace PlaywrightTests; + +[SetUpFixture] +public class PlaywrightServiceSetup : PlaywrightServiceNUnit +{ + public static readonly TokenCredential managedIdentityCredential = new ManagedIdentityCredential(); + + public PlaywrightServiceSetup() : base(managedIdentityCredential) + { } +}; +``` + +## Settings + +1. **`Os`**: + - **Description**: This setting allows you to choose the operating system where the browsers running Playwright tests will be hosted. + - **Available Options**: + - `ServiceOS.WINDOWS` for Windows OS. + - `ServiceOS.LINUX` for Linux OS. + - **Default Value**: `ServiceOS.LINUX` + +2. **`RunId`**: + - **Description**: This setting allows you to set a unique ID for every test run to distinguish them in the service portal. + +3. **`ExposeNetwork`**: + - **Description**: This settings exposes network available on the connecting client to the browser being connected to. + +4. **`DefaultAuth`** + - **Description**: This setting sllows you to specify the default authentication mechanism to be used for sending requests to the service. + - **Available Options**: + - `ServiceAuth.ENTRA` for Entra ID authentication. + - `ServiceAuth.TOKEN` for MPT Access Token authenticaton. + - **Default Value**: `ServiceAuth.ENTRA` + +5. **`UseCloudHostedBrowsers`** + - **Description**: This setting allows you to select whether to use cloud-hosted browsers to run your Playwright tests. Reporting features remain available even if you disable this setting. + - **Default Value**: `true` + +6. **`AzureTokenCredentialType`**: + - **Description**: This setting allows you to select the authentication method you want to use with Entra. + - **Available Options**: + - `AzureTokenCredentialType.EnvironmentCredential` + - `AzureTokenCredentialType.WorkloadIdentityCredential` + - `AzureTokenCredentialType.ManagedIdentityCredential` + - `AzureTokenCredentialType.SharedTokenCacheCredential` + - `AzureTokenCredentialType.VisualStudioCredential` + - `AzureTokenCredentialType.VisualStudioCodeCredential` + - `AzureTokenCredentialType.AzureCliCredential` + - `AzureTokenCredentialType.AzurePowerShellCredential` + - `AzureTokenCredentialType.AzureDeveloperCliCredential` + - `AzureTokenCredentialType.InteractiveBrowserCredential` + - `AzureTokenCredentialType.DefaultAzureCredential` + - **Default Value**: `AzureTokenCredentialType.DefaultAzureCredential` + +7. **`ManagedIdentityClientId`** + - **Description**: This setting allows you to specify the managed identity client id to be used for entra id authentication. + +8. **`EnableGitHubSummary`**: + - **Description**: This setting allows you to configure the Microsoft Playwright Testing service reporter. You can choose whether to include the test run summary in the GitHub summary when running in GitHub Actions. + - **Default Value**: `true` + diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/.runsettings b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/.runsettings similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/.runsettings rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/.runsettings diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightServiceSetup.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightServiceSetup.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightServiceSetup.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightServiceSetup.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightTests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightTests.csproj similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/PlaywrightTests.csproj rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightTests.csproj diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md new file mode 100644 index 000000000000..17ddbc63c709 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md @@ -0,0 +1,94 @@ +# How to integrate your test suite with Microsoft Playwright Testing service if you are manually launching browsers in tests + +This guide will walk you through the steps to integrate your Playwright project, where you are launching browsers from within the tests, with the service. + +### Prerequisites + +- An Azure account with an active subscription. If you don't have an Azure subscription, [create a free account](https://aka.ms/mpt/create-azure-subscription) before you begin. +- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). +- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) must be installed in the machine from where you are running Playwright tests. + +### Create a Workspace + +1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account. + +2. Create the Workspace. + + ![Create new workspace](https://github.com/microsoft/playwright-testing-service/assets/12104064/d571e86b-9d43-48ac-a2b7-63afb9bb86a8) + + |Field |Description | + |---------|---------| + |**Workspace Name** | A unique name to identify your workspace.
The name can't contain special characters or whitespace. | + |**Azure Subscription** | Select an Azure subscription where you want to create the workspace. | + |**Region** | This is where test run data will be stored for your workspace. | + + > [!NOTE] + > If you don't see this screen, select an existing workspace and go to the next section. + +### Install Microsoft Playwright Testing package + +1. Run this command to install the service package + + ```dotnetcli + dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit + ``` + +### Setup Microsoft Playwright Testing + +1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the below content + + ```c# + using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; + + namespace PlaywrightTests; // Remember to change this as per your project namespace + + [SetUpFixture] + public class PlaywrightServiceSetup : PlaywrightServiceNUnit; + ``` + +> [!NOTE] +> Make sure your project uses Microsoft.Playwright.NUnit version 1.37 or above. + +### Configure browsers to be launched on the service + +In the test project, wherever there is a manual browser launch or manual connect to a remote browser, replace it with the below code snippet + +```c# +// Old code +//Browser = await _playwright.Chromium.LaunchAsync(); + +// New code +var playwrightService = new PlaywrightService(); +var connectOptions = await playwrightService.GetConnectOptionsAsync(os: ServiceOs.LINUX, runId: $"Manual Launch - {DateTime.UtcNow}"); +_browser = await _playwright.Chromium.ConnectAsync(connectOptions.WsEndpoint!, connectOptions.Options!); +``` + +### Obtain region endpoint + +1. In the [Playwright portal](https://aka.ms/mpt/portal), copy the command under **Add region endpoint in your set up**. + + ![Set workspace endpoint](https://github.com/microsoft/playwright-testing-service/assets/12104064/d81ca629-2b23-4d34-8b70-67b6f7061a83) + + The endpoint URL corresponds to the workspace region. You might see a different endpoint URL in the Playwright portal, depending on the region you selected when creating the workspace. + +### Set up environment + +Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is available in your environment. + +### Sign in to Azure + +You need to sign in to Azure using Azure CLI to enable authentication via Entra ID. Run the command to sign-in + +```azurecli +az login +``` + +**NOTE**: If you are a part of multiple tenants, you will have to login to a particular tenant. Run `az login --tenant=' to sign in to the tenant where the workspace is created. You can find the tenant id through these [steps.](https://learn.microsoft.com/en-us/entra/fundamentals/how-to-find-tenant) + +### Run the tests + +Run Playwright tests against browsers managed by the service using the configuration you created above. + +```dotnetcli +dotnet test --logger "ms-playwright-service" +``` \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/UnitTest1.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/UnitTest1.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/UnitTest1.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md index e69de29bb2d1..f80058739277 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md @@ -0,0 +1,92 @@ +# How to authenticate to Microsoft Playwright Testing service using service access token. + +This guide will walk you through the steps to integrate your Playwright project where you are launching browsers from within the tests with the service. + +### Prerequisites + +- An Azure account with an active subscription. If you don't have an Azure subscription, [create a free account](https://aka.ms/mpt/create-azure-subscription) before you begin. +- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). +- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) must be installed in the machine from where you are running Playwright tests. + +### Create a Workspace + +1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account. + +2. Create the Workspace. + + ![Create new workspace](https://github.com/microsoft/playwright-testing-service/assets/12104064/d571e86b-9d43-48ac-a2b7-63afb9bb86a8) + + |Field |Description | + |---------|---------| + |**Workspace Name** | A unique name to identify your workspace.
The name can't contain special characters or whitespace. | + |**Azure Subscription** | Select an Azure subscription where you want to create the workspace. | + |**Region** | This is where test run data will be stored for your workspace. | + + > [!NOTE] + > If you don't see this screen, select an existing workspace and go to the next section. + +### Install Microsoft Playwright Testing package + +1. Run this command to install the service package + + ```dotnetcli + dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit + ``` + +### Setup Microsoft Playwright Testing + +1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the below content + + ```c# + using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; + + namespace PlaywrightTests; // Remember to change this as per your project namespace + + [SetUpFixture] + public class PlaywrightServiceSetup : PlaywrightServiceNUnit; + ``` + +2. Create a .runsettings file to modify default authentication mechanism. + + ```xml + + + + + + + + ``` + +> [!NOTE] +> Make sure your project uses Microsoft.Playwright.NUnit version 1.37 or above. + +### Obtain region endpoint + +1. In the [Playwright portal](https://aka.ms/mpt/portal), copy the command under **Add region endpoint in your set up**. + + ![Set workspace endpoint](https://github.com/microsoft/playwright-testing-service/assets/12104064/d81ca629-2b23-4d34-8b70-67b6f7061a83) + + The endpoint URL corresponds to the workspace region. You might see a different endpoint URL in the Playwright portal, depending on the region you selected when creating the workspace. + +### Set up environment + +Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is available in your environment. + +### Sign in to Azure + +You need to sign in to Azure using Azure CLI to enable authentication via Entra ID. Run the command to sign-in + +```azurecli +az login +``` + +**NOTE**: If you are a part of multiple tenants, you will have to login to a particular tenant. Run `az login --tenant=' to sign in to the tenant where the workspace is created. You can find the tenant id through these [steps.](https://learn.microsoft.com/en-us/entra/fundamentals/how-to-find-tenant) + +### Run the tests + +Run Playwright tests against browsers managed by the service using the configuration you created above. + +```dotnetcli +dotnet test --settings .runsettings +``` \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/using-manual-launch/README.md deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md index e69de29bb2d1..3b579c71f94b 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md @@ -0,0 +1,52 @@ +# Microsoft Playwright Testing preview + +Microsoft Playwright Testing is a fully managed service that uses the cloud to enable you to run Playwright tests with much higher parallelization across different operating system-browser combinations simultaneously. This means faster test runs with broader scenario coverage, which helps speed up delivery of features without sacrificing quality. The service also enables you to publish test results and related artifacts to the service and view them in the service portal enabling faster and easier troubleshooting. With Microsoft Playwright Testing service, you can release features faster and more confidently. + +## Getting started + +### Install the package + +Install the client library from [NuGet](https://www.nuget.org/): + +```dotnetcli +dotnet add package Azure.Developer.MicrosoftPlaywrightTesting +``` + +## Useful Links +- [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart) +- [Quickstart: Set up continuous end-to-end testing across different browsers and operating systems](https://aka.ms/mpt/ci) +- [Explore features and benefits](https://aka.ms/mpt/about) +- [View Microsoft Playwright Testing service demo](https://youtu.be/GenC1jAeTZE) +- [Documentation](https://aka.ms/mpt/docs) +- [Pricing](https://aka.ms/mpt/pricing) +- [Share feedback](https://aka.ms/mpt/feedback) + +## Next steps + +- Run tests in a [CI/CD pipeline.](https://aka.ms/mpt/configure-pipeline) + +- Learn how to [manage access](https://aka.ms/mpt/manage-access) to the created workspace. + +- Experiment with different number of workers to [determine the optimal configuration of your test suite](https://aka.ms/mpt/parallelism). + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## Trademarks + +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft +trademarks or logos is subject to and must follow +[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). +Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. +Any use of third-party trademarks or logos is subject to those third-party's policies. diff --git a/sdk/playwrighttesting/ci.yml b/sdk/playwrighttesting/ci.yml new file mode 100644 index 000000000000..3ec09b524cef --- /dev/null +++ b/sdk/playwrighttesting/ci.yml @@ -0,0 +1,41 @@ +# NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file. + +trigger: + branches: + include: + - main + - hotfix/* + - release/* + paths: + include: + - sdk/playwrighttesting/ + exclude: + - sdk/playwrighttesting/Azure.ResourceManager.PlaywrightTesting/ + +pr: + branches: + include: + - main + - feature/* + - hotfix/* + - release/* + paths: + include: + - sdk/playwrighttesting/ + exclude: + - sdk/playwrighttesting/Azure.ResourceManager.PlaywrightTesting/ + +extends: + template: /eng/pipelines/templates/stages/archetype-sdk-client.yml + parameters: + ServiceDirectory: playwrighttesting + BuildSnippets: false + ArtifactName: packages + Artifacts: + - name: Azure.Developer.MicrosoftPlaywrightTesting.NUnit + safeName: AzureDeveloperMicrosoftPlaywrightTestingNUnit + - name: Azure.Developer.MicrosoftPlaywrightTesting + safeName: AzureDeveloperMicrosoftPlaywrightTesting + + + From ad7d11ac9429c9215cddb65c52a5b3d0b24425b7 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Tue, 16 Jul 2024 22:56:23 +0000 Subject: [PATCH 04/32] docs(): content of samples --- .../samples/customising-service-parameters/README.md | 8 ++++---- .../samples/manually-connecting-to-browsers/README.md | 2 +- .../set-default-authentication-mechanism/README.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md index ac32901b04b8..165134a51269 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md @@ -42,7 +42,7 @@ This guide explains the different options available to you in the Azure.Develope #### Known Issue - Minimal support for Azure Credentials -This issue only impacts the reporting feature. Currently, the service provides a minimal support for the below [Azure Credential types](https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme?view=azure-dotnet) +This issue only impacts the reporting feature. Currently, the service provides minimal support for the following [Azure Credential types](https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme?view=azure-dotnet) - EnvironmentCredential - WorkloadIdentityCredential @@ -58,7 +58,7 @@ This issue only impacts the reporting feature. Currently, the service provides a Along with this, we also support passing a Managed Identity ClientId to be used along with `DefaultAzureCredential` and `ManagedIdentityCredential`. -If you only want to use cloud hosted browsers along with your tests, you can disable the reporting feature by removing the logger from the runsettings file and then modify the `PlaywrightServiceSetup.cs` file as per below. +If you only want to use cloud hosted browsers along with your tests, you can disable the reporting feature by removing the logger from the runsettings file and then modify the `PlaywrightServiceSetup.cs` file as per the following. ```c# using Azure.Core; @@ -93,10 +93,10 @@ public class PlaywrightServiceSetup : PlaywrightServiceNUnit - **Description**: This settings exposes network available on the connecting client to the browser being connected to. 4. **`DefaultAuth`** - - **Description**: This setting sllows you to specify the default authentication mechanism to be used for sending requests to the service. + - **Description**: This setting allows you to specify the default authentication mechanism to be used for sending requests to the service. - **Available Options**: - `ServiceAuth.ENTRA` for Entra ID authentication. - - `ServiceAuth.TOKEN` for MPT Access Token authenticaton. + - `ServiceAuth.TOKEN` for MPT Access Token authentication. - **Default Value**: `ServiceAuth.ENTRA` 5. **`UseCloudHostedBrowsers`** diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md index 17ddbc63c709..38f580247d4a 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md @@ -35,7 +35,7 @@ This guide will walk you through the steps to integrate your Playwright project, ### Setup Microsoft Playwright Testing -1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the below content +1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the following ```c# using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md index f80058739277..9c029b85392b 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md @@ -35,7 +35,7 @@ This guide will walk you through the steps to integrate your Playwright project ### Setup Microsoft Playwright Testing -1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the below content +1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the following ```c# using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; From 14044239489a6a4b7c69428b2731f5eee67d25f8 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Wed, 31 Jul 2024 07:59:20 +0000 Subject: [PATCH 05/32] chore():: modify samples as per azure sdk guidelines --- eng/service.proj | 1 - .../samples/README.md | 6 +-- ...> Sample1_CustomisingServiceParameters.md} | 0 ...ple2_SetDefaultAuthenticationMechanism.md} | 0 ...> Sample3_ManuallyConnectingToBrowsers.md} | 0 .../.runsettings | 15 ------ .../PlaywrightServiceSetup.cs | 6 --- .../PlaywrightTests.csproj | 26 ---------- .../UnitTest1.cs | 33 ------------- .../.runsettings | 9 ---- .../PlaywrightServiceSetup.cs | 6 --- .../PlaywrightTests.csproj | 26 ---------- .../UnitTest1.cs | 48 ------------------- .../.runsettings | 12 ----- .../PlaywrightServiceSetup.cs | 6 --- .../PlaywrightTests.csproj | 26 ---------- .../UnitTest1.cs | 33 ------------- 17 files changed, 3 insertions(+), 250 deletions(-) rename sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/{customising-service-parameters/README.md => Sample1_CustomisingServiceParameters.md} (100%) rename sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/{set-default-authentication-mechanism/README.md => Sample2_SetDefaultAuthenticationMechanism.md} (100%) rename sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/{manually-connecting-to-browsers/README.md => Sample3_ManuallyConnectingToBrowsers.md} (100%) delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/.runsettings delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightServiceSetup.cs delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightTests.csproj delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/.runsettings delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightServiceSetup.cs delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightTests.csproj delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/UnitTest1.cs delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/.runsettings delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightServiceSetup.cs delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightTests.csproj delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs diff --git a/eng/service.proj b/eng/service.proj index 6a7ee156d116..bc473731f3f1 100644 --- a/eng/service.proj +++ b/eng/service.proj @@ -43,7 +43,6 @@ - diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md index e46a6f61296c..9499d8d9e738 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md @@ -11,6 +11,6 @@ description: Samples for the Azure.Developer.MicrosoftPlaywrightTesting.NUnit cl # Azure.Developer.MicrosoftPlaywrightTesting.NUnit samples for .NET -- [Manually connecting to browsers](./manually-connecting-to-browsers/README.md) -- [Customising service parameters](./customising-service-parameters/README.md) -- [Set default authentication mechanism](./set-default-authentication-mechanism/README.md) +- [Customising service parameters](./Sample1_CustomisingServiceParameters.md) +- [Set default authentication mechanism](./Sample2_SetDefaultAuthenticationMechanism.md) +- [Manually connecting to browsers](./Sample3_ManuallyConnectingToBrowsers.md) \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/README.md rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/README.md rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/README.md rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/.runsettings b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/.runsettings deleted file mode 100644 index 0b1d6bb95e58..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/.runsettings +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightServiceSetup.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightServiceSetup.cs deleted file mode 100644 index d800c8ace326..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightServiceSetup.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; - -namespace PlaywrightTests; - -[SetUpFixture] -public class PlaywrightServiceSetup : PlaywrightServiceNUnit; \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightTests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightTests.csproj deleted file mode 100644 index dd3f8b888457..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/PlaywrightTests.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - net8.0 - enable - enable - false - true - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs deleted file mode 100644 index 8796cf2565ce..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/customising-service-parameters/UnitTest1.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.Playwright; -using Microsoft.Playwright.NUnit; -using NUnit.Framework; - -namespace PlaywrightTests; - -[Parallelizable(ParallelScope.Self)] -[TestFixture] -public class ExampleTest : PageTest -{ - [Test] - public async Task HasTitle() - { - await Page.GotoAsync("https://playwright.dev"); - - // Expect a title "to contain" a substring. - await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); - } - - [Test] - public async Task GetStartedLink() - { - await Page.GotoAsync("https://playwright.dev"); - - // Click the get started link. - await Page.GetByRole(AriaRole.Link, new() { Name = "Get started" }).ClickAsync(); - - // Expects page to have a heading with the name of Installation. - await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Installation" })).ToBeVisibleAsync(); - } -} \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/.runsettings b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/.runsettings deleted file mode 100644 index b2b09c4ebf83..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/.runsettings +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightServiceSetup.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightServiceSetup.cs deleted file mode 100644 index d800c8ace326..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightServiceSetup.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; - -namespace PlaywrightTests; - -[SetUpFixture] -public class PlaywrightServiceSetup : PlaywrightServiceNUnit; \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightTests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightTests.csproj deleted file mode 100644 index dd3f8b888457..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/PlaywrightTests.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - net8.0 - enable - enable - false - true - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/UnitTest1.cs deleted file mode 100644 index 583f5050b9d8..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/manually-connecting-to-browsers/UnitTest1.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.Playwright; -using Microsoft.Playwright.NUnit; -using NUnit.Framework; -using Azure.Developer.MicrosoftPlaywrightTesting; - -namespace PlaywrightTests; - -[Parallelizable(ParallelScope.Self)] -[TestFixture] -public class Tests -{ - private IPlaywright _playwright; - private IBrowser _browser; - public IPage _page; - - [SetUp] - public async Task PageSetup() - { - _playwright = await Playwright.CreateAsync(); - - // Old code - //Browser = await _playwright.Chromium.LaunchAsync(); - - // New code - var playwrightService = new PlaywrightService(); - var connectOptions = await playwrightService.GetConnectOptionsAsync(os: ServiceOs.LINUX, runId: $"Manual Launch - {DateTime.UtcNow}"); - _browser = await _playwright.Chromium.ConnectAsync(connectOptions.WsEndpoint!, connectOptions.Options!); - // End new code - - _page = await _browser.NewPageAsync(); - } - - [TearDown] - public async Task PageTeardown() - { - await _page.CloseAsync(); - await _browser.CloseAsync(); - _playwright.Dispose(); - } - - [Test] - public async Task HasTitle() - { - await _page.GotoAsync("https://playwright.dev"); - } -} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/.runsettings b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/.runsettings deleted file mode 100644 index 5a52509978ff..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/.runsettings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightServiceSetup.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightServiceSetup.cs deleted file mode 100644 index d800c8ace326..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightServiceSetup.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; - -namespace PlaywrightTests; - -[SetUpFixture] -public class PlaywrightServiceSetup : PlaywrightServiceNUnit; \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightTests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightTests.csproj deleted file mode 100644 index dd3f8b888457..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/PlaywrightTests.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - net8.0 - enable - enable - false - true - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs deleted file mode 100644 index 8796cf2565ce..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/set-default-authentication-mechanism/UnitTest1.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.Playwright; -using Microsoft.Playwright.NUnit; -using NUnit.Framework; - -namespace PlaywrightTests; - -[Parallelizable(ParallelScope.Self)] -[TestFixture] -public class ExampleTest : PageTest -{ - [Test] - public async Task HasTitle() - { - await Page.GotoAsync("https://playwright.dev"); - - // Expect a title "to contain" a substring. - await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); - } - - [Test] - public async Task GetStartedLink() - { - await Page.GotoAsync("https://playwright.dev"); - - // Click the get started link. - await Page.GetByRole(AriaRole.Link, new() { Name = "Get started" }).ClickAsync(); - - // Expects page to have a heading with the name of Installation. - await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Installation" })).ToBeVisibleAsync(); - } -} \ No newline at end of file From dde5490bf167802d61acd7289627b0629de8a667 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Wed, 31 Jul 2024 08:58:28 +0000 Subject: [PATCH 06/32] refactor(): unit tests as per azure sdk guidelines --- .../Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj | 1 + .../tests/PlaywrightServiceSettingsTest.cs | 1 + .../tests/PlaywrightServiceTests.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj index 4b667d1db98b..d339be265b32 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj @@ -12,6 +12,7 @@ + diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs index 0f1b2af6f278..ba7dfb5989ef 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs @@ -8,6 +8,7 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; [TestFixture] +[Parallelizable(ParallelScope.Self)] public class PlaywrightServiceSettingsTest { [Test] diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs index e966ce147633..c27c1faa5447 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs @@ -15,6 +15,7 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; [TestFixture] +[Parallelizable(ParallelScope.Self)] public class PlaywrightServiceTests { private static string GetToken(Dictionary claims, DateTime? expires = null) From 21eca6d0a51b2dbc00997c07fe183437939ef40e Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 12 Aug 2024 15:00:30 +0530 Subject: [PATCH 07/32] chore(): use autorest to generate api clients --- eng/Packages.Data.props | 4 +- ...eveloper.MicrosoftPlaywrightTesting.csproj | 7 +- .../TestLogger/Client/Internal/Argument.cs | 129 + .../Client/ReportingTestResultsClient.cs | 159 + .../Client/ReportingTestRunsClient.cs | 482 ++++ .../TestLogger/Client/TestReportingClient.cs | 2553 ----------------- .../Client/TestReportingClientOptions.cs | 37 + .../src/TestLogger/Model/MPTResult.cs | 13 +- .../src/TestLogger/Model/TestReporting.cs | 313 ++ .../src/TestLogger/PlaywrightReporter.cs | 175 +- 10 files changed, 1201 insertions(+), 2671 deletions(-) create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/Internal/Argument.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClient.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClientOptions.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/TestReporting.cs diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index d4b846b64df5..064af824c8d9 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -385,9 +385,7 @@ - - - + diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj index 255126708467..4a08d1ec4c8a 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj @@ -16,11 +16,10 @@ enable + - + - - - + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/Internal/Argument.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/Internal/Argument.cs new file mode 100644 index 000000000000..825022ea323c --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/Internal/Argument.cs @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client +{ + internal static class Argument + { + public static void AssertNotNull(T value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + } + + public static void AssertNotNull(T? value, string name) + where T : struct + { + if (!value.HasValue) + { + throw new ArgumentNullException(name); + } + } + + public static void AssertNotNullOrEmpty(IEnumerable value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (value is ICollection collectionOfT && collectionOfT.Count == 0) + { + throw new ArgumentException("Value cannot be an empty collection.", name); + } + if (value is ICollection collection && collection.Count == 0) + { + throw new ArgumentException("Value cannot be an empty collection.", name); + } + using IEnumerator e = value.GetEnumerator(); + if (!e.MoveNext()) + { + throw new ArgumentException("Value cannot be an empty collection.", name); + } + } + + public static void AssertNotNullOrEmpty(string value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (value.Length == 0) + { + throw new ArgumentException("Value cannot be an empty string.", name); + } + } + + public static void AssertNotNullOrWhiteSpace(string value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("Value cannot be empty or contain only white-space characters.", name); + } + } + + public static void AssertNotDefault(ref T value, string name) + where T : struct, IEquatable + { + if (value.Equals(default)) + { + throw new ArgumentException("Value cannot be empty.", name); + } + } + + public static void AssertInRange(T value, T minimum, T maximum, string name) + where T : notnull, IComparable + { + if (minimum.CompareTo(value) > 0) + { + throw new ArgumentOutOfRangeException(name, "Value is less than the minimum allowed."); + } + if (maximum.CompareTo(value) < 0) + { + throw new ArgumentOutOfRangeException(name, "Value is greater than the maximum allowed."); + } + } + + public static void AssertEnumDefined(Type enumType, object value, string name) + { + if (!Enum.IsDefined(enumType, value)) + { + throw new ArgumentException($"Value not defined for {enumType.FullName}.", name); + } + } + + public static T CheckNotNull(T value, string name) + where T : class + { + AssertNotNull(value, name); + return value; + } + + public static string CheckNotNullOrEmpty(string value, string name) + { + AssertNotNullOrEmpty(value, name); + return value; + } + + public static void AssertNull(T value, string name, string message = null) + { + if (value != null) + { + throw new ArgumentException(message ?? "Value must be null.", name); + } + } + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs new file mode 100644 index 000000000000..9e4141d63ce9 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client +{ + // Data plane generated client. + /// The TestResults service client. + public partial class ReportingTestResultsClient + { + private readonly HttpPipeline _pipeline; + private readonly Uri _endpoint; + private readonly string _apiVersion; + + /// The ClientDiagnostics is used to provide tracing support for the client library. + internal ClientDiagnostics ClientDiagnostics { get; } + + /// The HTTP pipeline for sending and receiving REST requests and responses. + public virtual HttpPipeline Pipeline => _pipeline; + + /// Initializes a new instance of ReportingTestResultsClient for mocking. + protected ReportingTestResultsClient() + { + } + + /// Initializes a new instance of ReportingTestResultsClient. + /// server parameter. + /// is null. + public ReportingTestResultsClient(Uri endpoint) : this(endpoint, new TestReportingClientOptions()) + { + } + + /// Initializes a new instance of ReportingTestResultsClient. + /// server parameter. + /// The options for configuring the client. + /// is null. + public ReportingTestResultsClient(Uri endpoint, TestReportingClientOptions options) + { + Argument.AssertNotNull(endpoint, nameof(endpoint)); + options ??= new TestReportingClientOptions(); + + ClientDiagnostics = new ClientDiagnostics(options, true); + _pipeline = HttpPipelineBuilder.Build(options, Array.Empty(), Array.Empty(), new ResponseClassifier()); + _endpoint = endpoint; + _apiVersion = options.Version; + } + + /// + /// [Protocol Method] Uploads a batch of test results to the test run + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The content to send as the body of the request. + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task UploadBatchTestResultsAsync(string workspaceId, RequestContent content, string authorization = null, string xCorrelationId = null, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestResultsClient.UploadBatchTestResults"); + scope.Start(); + try + { + using HttpMessage message = CreateUploadBatchTestResultsRequest(workspaceId, content, authorization, xCorrelationId, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Uploads a batch of test results to the test run + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The content to send as the body of the request. + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual Response UploadBatchTestResults(string workspaceId, RequestContent content, string authorization = null, string xCorrelationId = null, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestResultsClient.UploadBatchTestResults"); + scope.Start(); + try + { + using HttpMessage message = CreateUploadBatchTestResultsRequest(workspaceId, content, authorization, xCorrelationId, context); + return _pipeline.ProcessMessage(message, context); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal HttpMessage CreateUploadBatchTestResultsRequest(string workspaceId, RequestContent content, string authorization, string xCorrelationId, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200400500); + var request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/workspaces/", false); + uri.AppendPath(workspaceId, true); + uri.AppendPath("/test-results/upload-batch", false); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + if (authorization != null) + { + request.Headers.Add("Authorization", authorization); + } + if (xCorrelationId != null) + { + request.Headers.Add("x-correlation-id", xCorrelationId); + } + request.Headers.Add("Content-Type", "application/json"); + request.Content = content; + return message; + } + + private static ResponseClassifier _responseClassifier200400500; + private static ResponseClassifier ResponseClassifier200400500 => _responseClassifier200400500 ??= new StatusCodeClassifier(stackalloc ushort[] { 200, 400, 500 }); + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs new file mode 100644 index 000000000000..d1e4434ec21d --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs @@ -0,0 +1,482 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client +{ + // Data plane generated client. + /// The TestRuns service client. + public partial class ReportingTestRunsClient + { + private readonly HttpPipeline _pipeline; + private readonly Uri _endpoint; + private readonly string _apiVersion; + + /// The ClientDiagnostics is used to provide tracing support for the client library. + internal ClientDiagnostics ClientDiagnostics { get; } + + /// The HTTP pipeline for sending and receiving REST requests and responses. + public virtual HttpPipeline Pipeline => _pipeline; + + /// Initializes a new instance of ReportingTestRunsClient for mocking. + protected ReportingTestRunsClient() + { + } + + /// Initializes a new instance of ReportingTestRunsClient. + /// server parameter. + /// is null. + public ReportingTestRunsClient(Uri endpoint) : this(endpoint, new TestReportingClientOptions()) + { + } + + /// Initializes a new instance of ReportingTestRunsClient. + /// server parameter. + /// The options for configuring the client. + /// is null. + public ReportingTestRunsClient(Uri endpoint, TestReportingClientOptions options) + { + Argument.AssertNotNull(endpoint, nameof(endpoint)); + options ??= new TestReportingClientOptions(); + + ClientDiagnostics = new ClientDiagnostics(options, true); + _pipeline = HttpPipelineBuilder.Build(options, Array.Empty(), Array.Empty(), new ResponseClassifier()); + _endpoint = endpoint; + _apiVersion = options.Version; + } + + /// + /// [Protocol Method] Patch Test Run Info + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The to use. + /// The content to send as the body of the request. + /// Body Parameter content-type. Allowed values: "application/*+json" | "application/json" | "application/json-patch+json" | "text/json". + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task PatchTestRunInfoAsync(string workspaceId, string testRunId, RequestContent content, ContentType contentType, string authorization = null, string xCorrelationId = null, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + Argument.AssertNotNullOrEmpty(testRunId, nameof(testRunId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestRunsClient.PatchTestRunInfoAsync"); + scope.Start(); + try + { + using HttpMessage message = CreatePatchTestRunInfoAsyncRequest(workspaceId, testRunId, content, contentType, authorization, xCorrelationId, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Patch Test Run Info + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The to use. + /// The content to send as the body of the request. + /// Body Parameter content-type. Allowed values: "application/*+json" | "application/json" | "application/json-patch+json" | "text/json". + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual Response PatchTestRunInfo(string workspaceId, string testRunId, RequestContent content, ContentType contentType, string authorization = null, string xCorrelationId = null, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + Argument.AssertNotNullOrEmpty(testRunId, nameof(testRunId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestRunsClient.PatchTestRunInfoAsync"); + scope.Start(); + try + { + using HttpMessage message = CreatePatchTestRunInfoAsyncRequest(workspaceId, testRunId, content, contentType, authorization, xCorrelationId, context); + return _pipeline.ProcessMessage(message, context); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Get Test Run Info + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The to use. + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetTestRunAsync(string workspaceId, string testRunId, string authorization, string xCorrelationId, RequestContext context) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + Argument.AssertNotNullOrEmpty(testRunId, nameof(testRunId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestRunsClient.GetTestRunAsync"); + scope.Start(); + try + { + using HttpMessage message = CreateGetTestRunAsyncRequest(workspaceId, testRunId, authorization, xCorrelationId, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Get Test Run Info + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The to use. + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual Response GetTestRun(string workspaceId, string testRunId, string authorization, string xCorrelationId, RequestContext context) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + Argument.AssertNotNullOrEmpty(testRunId, nameof(testRunId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestRunsClient.GetTestRunAsync"); + scope.Start(); + try + { + using HttpMessage message = CreateGetTestRunAsyncRequest(workspaceId, testRunId, authorization, xCorrelationId, context); + return _pipeline.ProcessMessage(message, context); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Patch Test Run Shard Info + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The to use. + /// The to use. + /// The content to send as the body of the request. + /// Body Parameter content-type. Allowed values: "application/*+json" | "application/json" | "application/json-patch+json" | "text/json". + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// , or is null. + /// , or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task PatchTestRunShardInfoAsync(string workspaceId, string testRunId, string shardId, RequestContent content, ContentType contentType, string authorization = null, string xCorrelationId = null, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + Argument.AssertNotNullOrEmpty(testRunId, nameof(testRunId)); + Argument.AssertNotNullOrEmpty(shardId, nameof(shardId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestRunsClient.PatchTestRunShardInfoAsync"); + scope.Start(); + try + { + using HttpMessage message = CreatePatchTestRunShardInfoAsyncRequest(workspaceId, testRunId, shardId, content, contentType, authorization, xCorrelationId, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Patch Test Run Shard Info + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The to use. + /// The to use. + /// The content to send as the body of the request. + /// Body Parameter content-type. Allowed values: "application/*+json" | "application/json" | "application/json-patch+json" | "text/json". + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// , or is null. + /// , or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual Response PatchTestRunShardInfo(string workspaceId, string testRunId, string shardId, RequestContent content, ContentType contentType, string authorization = null, string xCorrelationId = null, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + Argument.AssertNotNullOrEmpty(testRunId, nameof(testRunId)); + Argument.AssertNotNullOrEmpty(shardId, nameof(shardId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestRunsClient.PatchTestRunShardInfoAsync"); + scope.Start(); + try + { + using HttpMessage message = CreatePatchTestRunShardInfoAsyncRequest(workspaceId, testRunId, shardId, content, contentType, authorization, xCorrelationId, context); + return _pipeline.ProcessMessage(message, context); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Get Test Run Results Uri + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The to use. + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetTestRunResultsUriAsync(string workspaceId, string testRunId, string authorization, string xCorrelationId, RequestContext context) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + Argument.AssertNotNullOrEmpty(testRunId, nameof(testRunId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestRunsClient.GetTestRunResultsUriAsync"); + scope.Start(); + try + { + using HttpMessage message = CreateGetTestRunResultsUriAsyncRequest(workspaceId, testRunId, authorization, xCorrelationId, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Get Test Run Results Uri + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The to use. + /// The to use. + /// access token. + /// Correlation-id used for tracing and debugging. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual Response GetTestRunResultsUri(string workspaceId, string testRunId, string authorization, string xCorrelationId, RequestContext context) + { + Argument.AssertNotNullOrEmpty(workspaceId, nameof(workspaceId)); + Argument.AssertNotNullOrEmpty(testRunId, nameof(testRunId)); + + using var scope = ClientDiagnostics.CreateScope("ReportingTestRunsClient.GetTestRunResultsUriAsync"); + scope.Start(); + try + { + using HttpMessage message = CreateGetTestRunResultsUriAsyncRequest(workspaceId, testRunId, authorization, xCorrelationId, context); + return _pipeline.ProcessMessage(message, context); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal HttpMessage CreatePatchTestRunInfoAsyncRequest(string workspaceId, string testRunId, RequestContent content, ContentType contentType, string authorization, string xCorrelationId, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200400401500); + var request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/workspaces/", false); + uri.AppendPath(workspaceId, true); + uri.AppendPath("/test-runs/", false); + uri.AppendPath(testRunId, true); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + if (authorization != null) + { + request.Headers.Add("Authorization", authorization); + } + if (xCorrelationId != null) + { + request.Headers.Add("x-correlation-id", xCorrelationId); + } + request.Headers.Add("Content-Type", contentType.ToString()); + request.Content = content; + return message; + } + + internal HttpMessage CreateGetTestRunAsyncRequest(string workspaceId, string testRunId, string authorization, string xCorrelationId, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200400401500); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/workspaces/", false); + uri.AppendPath(workspaceId, true); + uri.AppendPath("/test-runs/", false); + uri.AppendPath(testRunId, true); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + if (authorization != null) + { + request.Headers.Add("Authorization", authorization); + } + if (xCorrelationId != null) + { + request.Headers.Add("x-correlation-id", xCorrelationId); + } + return message; + } + + internal HttpMessage CreatePatchTestRunShardInfoAsyncRequest(string workspaceId, string testRunId, string shardId, RequestContent content, ContentType contentType, string authorization, string xCorrelationId, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200400401500); + var request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/workspaces/", false); + uri.AppendPath(workspaceId, true); + uri.AppendPath("/test-runs/", false); + uri.AppendPath(testRunId, true); + uri.AppendPath("/shards/", false); + uri.AppendPath(shardId, true); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + if (authorization != null) + { + request.Headers.Add("Authorization", authorization); + } + if (xCorrelationId != null) + { + request.Headers.Add("x-correlation-id", xCorrelationId); + } + request.Headers.Add("Content-Type", contentType.ToString()); + request.Content = content; + return message; + } + + internal HttpMessage CreateGetTestRunResultsUriAsyncRequest(string workspaceId, string testRunId, string authorization, string xCorrelationId, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200400401500); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/workspaces/", false); + uri.AppendPath(workspaceId, true); + uri.AppendPath("/test-runs/", false); + uri.AppendPath(testRunId, true); + uri.AppendPath("/resulturi", false); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + if (authorization != null) + { + request.Headers.Add("Authorization", authorization); + } + if (xCorrelationId != null) + { + request.Headers.Add("x-correlation-id", xCorrelationId); + } + return message; + } + + private static ResponseClassifier _responseClassifier200400401500; + private static ResponseClassifier ResponseClassifier200400401500 => _responseClassifier200400401500 ??= new StatusCodeClassifier(stackalloc ushort[] { 200, 400, 401, 500 }); + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClient.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClient.cs deleted file mode 100644 index cdb4648d4adc..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClient.cs +++ /dev/null @@ -1,2553 +0,0 @@ -//---------------------- -// -// Generated using the NSwag toolchain v14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) -// -//---------------------- - -#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." -#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." -#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' -#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" -#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... -#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." -#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" -#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" -#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" -#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" -#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" -#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). - -namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Clients -{ - using System = global::System; - - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial interface ITestReportingClient - { - /// - /// Get summary of test results - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestResultsSummaryAsync(string workspaceId, string filter, string orderby, string authorization, string x_correlation_id, string api_version); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get summary of test results - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestResultsSummaryAsync(string workspaceId, string filter, string orderby, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); - - /// - /// Get the test results for a given test run ID - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the test run - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestResultsAsync(string workspaceId, string filter, string orderby, int? top, int? skip, string authorization, string x_correlation_id, string api_version); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get the test results for a given test run ID - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the test run - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestResultsAsync(string workspaceId, string filter, string orderby, int? top, int? skip, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); - - /// - /// Uploads a batch of test results to the test run - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestResultsUploadBatchAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, UploadTestResultsRequest body); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Uploads a batch of test results to the test run - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestResultsUploadBatchAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, UploadTestResultsRequest body, System.Threading.CancellationToken cancellationToken); - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsPatchAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, TestRunDtoV2 body); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsPatchAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, TestRunDtoV2 body, System.Threading.CancellationToken cancellationToken); - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, int? top, int? skip, string authorization, string x_correlation_id, string api_version); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, int? top, int? skip, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); - - /// - /// Delete all the test runs for a given workspaceId - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsDeleteAsync(string workspaceId, string authorization, string x_correlation_id, string api_version); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Delete all the test runs for a given workspaceId - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsDeleteAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsResulturiAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsResulturiAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsShardsAsync(string workspaceId, string testRunId, string shardId, string authorization, string x_correlation_id, string api_version, TestRunShardDto body); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesTestRunsShardsAsync(string workspaceId, string testRunId, string shardId, string authorization, string x_correlation_id, string api_version, TestRunShardDto body, System.Threading.CancellationToken cancellationToken); - - /// - /// Get the storage account and link with the given workspace id. - /// - /// The workspace id. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the storage account details. - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesStoragePutAsync(string workspaceId, string authorization, string x_correlation_id, string api_version); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get the storage account and link with the given workspace id. - /// - /// The workspace id. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the storage account details. - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesStoragePutAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); - - /// - /// Get the storage account details for the given workspaceId. - /// - /// The workspaceId. - /// The storage id. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the storage account details. - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesStorageGetAsync(string workspaceId, string storageAccountId, string authorization, string x_correlation_id, string api_version); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get the storage account details for the given workspaceId. - /// - /// The workspaceId. - /// The storage id. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the storage account details. - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesStorageGetAsync(string workspaceId, string storageAccountId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); - - /// - /// Delete or unlink the storage account for the given workspaceId. - /// - /// The workspaceId. - /// The storage id. - /// The flag to indicate if it is a soft delete. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns no content. - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesStorageDeleteAsync(string workspaceId, string storageAccountId, bool? isSoftDelete, string authorization, string x_correlation_id, string api_version); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Delete or unlink the storage account for the given workspaceId. - /// - /// The workspaceId. - /// The storage id. - /// The flag to indicate if it is a soft delete. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns no content. - /// A server side error occurred. - System.Threading.Tasks.Task WorkspacesStorageDeleteAsync(string workspaceId, string storageAccountId, bool? isSoftDelete, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken); - - } - - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestReportingClient : ITestReportingClient - { -#pragma warning disable 8618 - private string _baseUrl; -#pragma warning restore 8618 - - private System.Net.Http.HttpClient _httpClient; - private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); - -#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - public TestReportingClient(string baseUrl, System.Net.Http.HttpClient httpClient) -#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - { - BaseUrl = baseUrl; - _httpClient = httpClient; - } - - private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() - { - var settings = new Newtonsoft.Json.JsonSerializerSettings(); - UpdateJsonSerializerSettings(settings); - return settings; - } - - public string BaseUrl - { - get { return _baseUrl; } - set - { - _baseUrl = value; - if (!string.IsNullOrEmpty(_baseUrl) && !_baseUrl.EndsWith("/")) - _baseUrl += '/'; - } - } - - protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } - - static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); - - partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); - partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); - partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); - - /// - /// Get summary of test results - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesTestResultsSummaryAsync(string workspaceId, string filter, string orderby, string authorization, string x_correlation_id, string api_version) - { - return WorkspacesTestResultsSummaryAsync(workspaceId, filter, orderby, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get summary of test results - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesTestResultsSummaryAsync(string workspaceId, string filter, string orderby, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/test-results/summary" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/test-results/summary"); - urlBuilder_.Append('?'); - if (filter != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("filter")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filter, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (orderby != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("orderby")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(orderby, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - if (status_ == 400) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Bad Request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 401) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 500) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Server Error", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Get the test results for a given test run ID - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the test run - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesTestResultsAsync(string workspaceId, string filter, string orderby, int? top, int? skip, string authorization, string x_correlation_id, string api_version) - { - return WorkspacesTestResultsAsync(workspaceId, filter, orderby, top, skip, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get the test results for a given test run ID - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the test run - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesTestResultsAsync(string workspaceId, string filter, string orderby, int? top, int? skip, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/test-results" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/test-results"); - urlBuilder_.Append('?'); - if (filter != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("filter")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filter, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (orderby != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("orderby")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(orderby, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (top != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("top")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(top, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (skip != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("skip")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(skip, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - if (status_ == 400) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If the runId is empty", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 401) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 500) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("In case of internal server error/exception", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Uploads a batch of test results to the test run - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesTestResultsUploadBatchAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, UploadTestResultsRequest body) - { - return WorkspacesTestResultsUploadBatchAsync(workspaceId, authorization, x_correlation_id, api_version, body, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Uploads a batch of test results to the test run - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesTestResultsUploadBatchAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, UploadTestResultsRequest body, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); - var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("POST"); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/test-results/upload-batch" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/test-results/upload-batch"); - urlBuilder_.Append('?'); - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - return; - } - else - if (status_ == 400) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Bad Request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 500) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Server Error", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version) - { - return WorkspacesTestRunsGetAsync(workspaceId, testRunId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - if (testRunId == null) - throw new System.ArgumentNullException("testRunId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/test-runs/{testRunId}" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/test-runs/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(testRunId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append('?'); - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesTestRunsPatchAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, TestRunDtoV2 body) - { - return WorkspacesTestRunsPatchAsync(workspaceId, testRunId, authorization, x_correlation_id, api_version, body, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesTestRunsPatchAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, TestRunDtoV2 body, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - if (testRunId == null) - throw new System.ArgumentNullException("testRunId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); - var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json-patch+json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("PATCH"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/test-runs/{testRunId}" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/test-runs/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(testRunId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append('?'); - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, int? top, int? skip, string authorization, string x_correlation_id, string api_version) - { - return WorkspacesTestRunsGetAsync(workspaceId, top, skip, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesTestRunsGetAsync(string workspaceId, int? top, int? skip, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/test-runs" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/test-runs"); - urlBuilder_.Append('?'); - if (top != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("top")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(top, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (skip != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("skip")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(skip, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Delete all the test runs for a given workspaceId - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesTestRunsDeleteAsync(string workspaceId, string authorization, string x_correlation_id, string api_version) - { - return WorkspacesTestRunsDeleteAsync(workspaceId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Delete all the test runs for a given workspaceId - /// - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesTestRunsDeleteAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - request_.Method = new System.Net.Http.HttpMethod("DELETE"); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/test-runs" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/test-runs"); - urlBuilder_.Append('?'); - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 204) - { - return; - } - else - if (status_ == 404) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If no resource found with the input workspaceId", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 400) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If the workspaceId is null", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 401) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 500) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("In case of internal server error/exception", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesTestRunsResulturiAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version) - { - return WorkspacesTestRunsResulturiAsync(workspaceId, testRunId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesTestRunsResulturiAsync(string workspaceId, string testRunId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - if (testRunId == null) - throw new System.ArgumentNullException("testRunId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/test-runs/{testRunId}/resulturi" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/test-runs/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(testRunId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/resulturi"); - urlBuilder_.Append('?'); - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesTestRunsShardsAsync(string workspaceId, string testRunId, string shardId, string authorization, string x_correlation_id, string api_version, TestRunShardDto body) - { - return WorkspacesTestRunsShardsAsync(workspaceId, testRunId, shardId, authorization, x_correlation_id, api_version, body, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Success - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesTestRunsShardsAsync(string workspaceId, string testRunId, string shardId, string authorization, string x_correlation_id, string api_version, TestRunShardDto body, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - if (testRunId == null) - throw new System.ArgumentNullException("testRunId"); - - if (shardId == null) - throw new System.ArgumentNullException("shardId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value); - var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json-patch+json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("PATCH"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/test-runs/{testRunId}/shards/{shardId}" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/test-runs/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(testRunId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/shards/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(shardId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append('?'); - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Get the storage account and link with the given workspace id. - /// - /// The workspace id. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the storage account details. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesStoragePutAsync(string workspaceId, string authorization, string x_correlation_id, string api_version) - { - return WorkspacesStoragePutAsync(workspaceId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get the storage account and link with the given workspace id. - /// - /// The workspace id. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the storage account details. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesStoragePutAsync(string workspaceId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); - request_.Method = new System.Net.Http.HttpMethod("PUT"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/storage" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/storage"); - urlBuilder_.Append('?'); - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - if (status_ == 400) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If the workspace id is invalid.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 404) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Not Found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 500) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If there is an internal server error.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Get the storage account details for the given workspaceId. - /// - /// The workspaceId. - /// The storage id. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the storage account details. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesStorageGetAsync(string workspaceId, string storageAccountId, string authorization, string x_correlation_id, string api_version) - { - return WorkspacesStorageGetAsync(workspaceId, storageAccountId, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get the storage account details for the given workspaceId. - /// - /// The workspaceId. - /// The storage id. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns the storage account details. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesStorageGetAsync(string workspaceId, string storageAccountId, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - if (storageAccountId == null) - throw new System.ArgumentNullException("storageAccountId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/storage/{storageAccountId}" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/storage/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(storageAccountId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append('?'); - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - if (status_ == 400) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If the workspaceId or storage id is invalid.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 404) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If the workspaceId is not found.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 500) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If there is an internal server error.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Delete or unlink the storage account for the given workspaceId. - /// - /// The workspaceId. - /// The storage id. - /// The flag to indicate if it is a soft delete. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns no content. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task WorkspacesStorageDeleteAsync(string workspaceId, string storageAccountId, bool? isSoftDelete, string authorization, string x_correlation_id, string api_version) - { - return WorkspacesStorageDeleteAsync(workspaceId, storageAccountId, isSoftDelete, authorization, x_correlation_id, api_version, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Delete or unlink the storage account for the given workspaceId. - /// - /// The workspaceId. - /// The storage id. - /// The flag to indicate if it is a soft delete. - /// access token - /// Correlation-id used for tracing and debugging. - /// api version - /// Returns no content. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WorkspacesStorageDeleteAsync(string workspaceId, string storageAccountId, bool? isSoftDelete, string authorization, string x_correlation_id, string api_version, System.Threading.CancellationToken cancellationToken) - { - if (workspaceId == null) - throw new System.ArgumentNullException("workspaceId"); - - if (storageAccountId == null) - throw new System.ArgumentNullException("storageAccountId"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (authorization != null) - request_.Headers.TryAddWithoutValidation("Authorization", ConvertToString(authorization, System.Globalization.CultureInfo.InvariantCulture)); - - if (x_correlation_id != null) - request_.Headers.TryAddWithoutValidation("x-correlation-id", ConvertToString(x_correlation_id, System.Globalization.CultureInfo.InvariantCulture)); - request_.Method = new System.Net.Http.HttpMethod("DELETE"); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "workspaces/{workspaceId}/storage/{storageAccountId}" - urlBuilder_.Append("workspaces/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(workspaceId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/storage/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(storageAccountId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append('?'); - if (isSoftDelete != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("isSoftDelete")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(isSoftDelete, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (api_version != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("api-version")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(api_version, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 204) - { - return; - } - else - if (status_ == 400) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If the workspace id or storage id is invalid.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 404) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If the workspace id is not found.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 500) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("If there is an internal server error.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - protected struct ObjectResponseResult - { - public ObjectResponseResult(T responseObject, string responseText) - { - this.Object = responseObject; - this.Text = responseText; - } - - public T Object { get; } - - public string Text { get; } - } - - public bool ReadResponseAsString { get; set; } - - protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) - { - if (response == null || response.Content == null) - { - return new ObjectResponseResult(default(T), string.Empty); - } - - if (ReadResponseAsString) - { - var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - try - { - var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); - return new ObjectResponseResult(typedBody, responseText); - } - catch (Newtonsoft.Json.JsonException exception) - { - var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; - throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); - } - } - else - { - try - { - using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) - using (var streamReader = new System.IO.StreamReader(responseStream)) - using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) - { - var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); - var typedBody = serializer.Deserialize(jsonTextReader); - return new ObjectResponseResult(typedBody, string.Empty); - } - } - catch (Newtonsoft.Json.JsonException exception) - { - var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; - throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); - } - } - } - - private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) - { - if (value == null) - { - return ""; - } - - if (value is System.Enum) - { - var name = System.Enum.GetName(value.GetType(), value); - if (name != null) - { - var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); - if (field != null) - { - var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) - as System.Runtime.Serialization.EnumMemberAttribute; - if (attribute != null) - { - return attribute.Value != null ? attribute.Value : name; - } - } - - var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); - return converted == null ? string.Empty : converted; - } - } - else if (value is bool) - { - return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); - } - else if (value is byte[]) - { - return System.Convert.ToBase64String((byte[])value); - } - else if (value is string[]) - { - return string.Join(",", (string[])value); - } - else if (value.GetType().IsArray) - { - var valueArray = (System.Array)value; - var valueTextArray = new string[valueArray.Length]; - for (var i = 0; i < valueArray.Length; i++) - { - valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); - } - return string.Join(",", valueTextArray); - } - - var result = System.Convert.ToString(value, cultureInfo); - return result == null ? "" : result; - } - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal enum AccessLevel - { - - [System.Runtime.Serialization.EnumMember(Value = @"Read")] - Read = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"Write")] - Write = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"ReadWrite")] - ReadWrite = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"ReadAddCreateWrite")] - ReadAddCreateWrite = 3, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class CIConfig - { - [Newtonsoft.Json.JsonProperty("ciProviderName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string CiProviderName { get; set; } - - [Newtonsoft.Json.JsonProperty("branch", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Branch { get; set; } - - [Newtonsoft.Json.JsonProperty("author", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Author { get; set; } - - [Newtonsoft.Json.JsonProperty("commitId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string CommitId { get; set; } - - [Newtonsoft.Json.JsonProperty("revisionUrl", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string RevisionUrl { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class ClientConfig - { - [Newtonsoft.Json.JsonProperty("retries", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Retries { get; set; } - - [Newtonsoft.Json.JsonProperty("repeatEach", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? RepeatEach { get; set; } - - [Newtonsoft.Json.JsonProperty("workers", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Workers { get; set; } - - [Newtonsoft.Json.JsonProperty("pwVersion", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string PwVersion { get; set; } - - [Newtonsoft.Json.JsonProperty("testFramework", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestFramework TestFramework { get; set; } - - [Newtonsoft.Json.JsonProperty("shards", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Shard Shards { get; set; } - - [Newtonsoft.Json.JsonProperty("timeout", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Timeout { get; set; } - - [Newtonsoft.Json.JsonProperty("testType", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TestType { get; set; } - - [Newtonsoft.Json.JsonProperty("testSdkLanguage", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TestSdkLanguage { get; set; } - - [Newtonsoft.Json.JsonProperty("reporterPackageVersion", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string ReporterPackageVersion { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class Error - { - [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Code { get; set; } - - [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Message { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class ErrorResponse - { - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Status { get; set; } - - [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Error Error { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class ListTestRunResponse - { - [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Value { get; set; } - - [Newtonsoft.Json.JsonProperty("nextLink", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string NextLink { get; set; } - - [Newtonsoft.Json.JsonProperty("size", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Size { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class PreviousRetrySummary - { - [Newtonsoft.Json.JsonProperty("testExecutionId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TestExecutionId { get; set; } - - [Newtonsoft.Json.JsonProperty("retry", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Retry { get; set; } - - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Status { get; set; } - - [Newtonsoft.Json.JsonProperty("duration", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? Duration { get; set; } - - [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string StartTime { get; set; } - - [Newtonsoft.Json.JsonProperty("attachmentsMetadata", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string AttachmentsMetadata { get; set; } - - [Newtonsoft.Json.JsonProperty("artifactsPath", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection ArtifactsPath { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class Shard - { - [Newtonsoft.Json.JsonProperty("total", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Total { get; set; } - - [Newtonsoft.Json.JsonProperty("current", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Current { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class StorageAccountDTO - { - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Name { get; set; } - - [Newtonsoft.Json.JsonProperty("subscriptionId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string SubscriptionId { get; set; } - - [Newtonsoft.Json.JsonProperty("linkedAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string LinkedAt { get; set; } - - [Newtonsoft.Json.JsonProperty("accountId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string AccountId { get; set; } - - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public StorageAccountStatus? Status { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal enum StorageAccountStatus - { - - [System.Runtime.Serialization.EnumMember(Value = @"Linked")] - Linked = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"Deleted")] - Deleted = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"LinkingInProgress")] - LinkingInProgress = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"DeletionInProgress")] - DeletionInProgress = 3, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestFramework - { - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Name { get; set; } - - [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Version { get; set; } - - [Newtonsoft.Json.JsonProperty("runnerName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string RunnerName { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestResults - { - [Newtonsoft.Json.JsonProperty("testExecutionId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TestExecutionId { get; set; } - - [Newtonsoft.Json.JsonProperty("testId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TestId { get; set; } - - [Newtonsoft.Json.JsonProperty("testCombinationId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TestCombinationId { get; set; } - - [Newtonsoft.Json.JsonProperty("runId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string RunId { get; set; } - - [Newtonsoft.Json.JsonProperty("accountId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string AccountId { get; set; } - - [Newtonsoft.Json.JsonProperty("suiteId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string SuiteId { get; set; } - - [Newtonsoft.Json.JsonProperty("testTitle", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TestTitle { get; set; } - - [Newtonsoft.Json.JsonProperty("suiteTitle", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string SuiteTitle { get; set; } - - [Newtonsoft.Json.JsonProperty("fileName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string FileName { get; set; } - - [Newtonsoft.Json.JsonProperty("lineNumber", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? LineNumber { get; set; } - - [Newtonsoft.Json.JsonProperty("retry", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Retry { get; set; } - - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Status { get; set; } - - [Newtonsoft.Json.JsonProperty("webTestConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public WebTestConfig WebTestConfig { get; set; } - - [Newtonsoft.Json.JsonProperty("ciConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public CIConfig CiConfig { get; set; } - - [Newtonsoft.Json.JsonProperty("resultsSummary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestResultsSummary ResultsSummary { get; set; } - - [Newtonsoft.Json.JsonProperty("previousRetries", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection PreviousRetries { get; set; } - - [Newtonsoft.Json.JsonProperty("tags", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Tags { get; set; } - - [Newtonsoft.Json.JsonProperty("annotations", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Annotations { get; set; } - - [Newtonsoft.Json.JsonProperty("artifactsPath", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection ArtifactsPath { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestResultsSummary - { - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Status { get; set; } - - [Newtonsoft.Json.JsonProperty("duration", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? Duration { get; set; } - - [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string StartTime { get; set; } - - [Newtonsoft.Json.JsonProperty("attachmentsMetadata", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string AttachmentsMetadata { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestResultsUri - { - [Newtonsoft.Json.JsonProperty("uri", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Uri { get; set; } - - [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string CreatedAt { get; set; } - - [Newtonsoft.Json.JsonProperty("expiresAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string ExpiresAt { get; set; } - - [Newtonsoft.Json.JsonProperty("accessLevel", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public AccessLevel? AccessLevel { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestRunDto - { - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public string Id { get; set; } - - [Newtonsoft.Json.JsonProperty("title", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public string Title { get; set; } - - [Newtonsoft.Json.JsonProperty("accountId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string AccountId { get; set; } - - [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string UserId { get; set; } - - [Newtonsoft.Json.JsonProperty("userName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string UserName { get; set; } - - [Newtonsoft.Json.JsonProperty("summary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestRunSummary Summary { get; set; } - - [Newtonsoft.Json.JsonProperty("resultsSummary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestRunResultsSummary ResultsSummary { get; set; } - - [Newtonsoft.Json.JsonProperty("ciConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public CIConfig CiConfig { get; set; } - - [Newtonsoft.Json.JsonProperty("clientConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public ClientConfig ClientConfig { get; set; } - - [Newtonsoft.Json.JsonProperty("testResultsUri", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestResultsUri TestResultsUri { get; set; } - - [Newtonsoft.Json.JsonProperty("isScalablyExecuted", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string IsScalablyExecuted { get; set; } - - [Newtonsoft.Json.JsonProperty("isReportingEnabled", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string IsReportingEnabled { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestRunDtoV2 - { - [Newtonsoft.Json.JsonProperty("testRunId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TestRunId { get; set; } - - [Newtonsoft.Json.JsonProperty("displayName", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [System.ComponentModel.DataAnnotations.StringLength(200)] - public string DisplayName { get; set; } - - [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$")] - public string StartTime { get; set; } - - [Newtonsoft.Json.JsonProperty("creatorId", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string CreatorId { get; set; } - - [Newtonsoft.Json.JsonProperty("creatorName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string CreatorName { get; set; } - - [Newtonsoft.Json.JsonProperty("summary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestRunSummary Summary { get; set; } - - [Newtonsoft.Json.JsonProperty("resultsSummary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestRunResultsSummary ResultsSummary { get; set; } - - [Newtonsoft.Json.JsonProperty("ciConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public CIConfig CiConfig { get; set; } - - [Newtonsoft.Json.JsonProperty("testRunConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public ClientConfig TestRunConfig { get; set; } - - [Newtonsoft.Json.JsonProperty("testResultsUri", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestResultsUri TestResultsUri { get; set; } - - [Newtonsoft.Json.JsonProperty("cloudRunEnabled", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"true|false")] - public string CloudRunEnabled { get; set; } - - [Newtonsoft.Json.JsonProperty("cloudReportingEnabled", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"true|false")] - public string CloudReportingEnabled { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestRunResultsSummary - { - [Newtonsoft.Json.JsonProperty("numTotalTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? NumTotalTests { get; set; } - - [Newtonsoft.Json.JsonProperty("numPassedTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? NumPassedTests { get; set; } - - [Newtonsoft.Json.JsonProperty("numFailedTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? NumFailedTests { get; set; } - - [Newtonsoft.Json.JsonProperty("numSkippedTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? NumSkippedTests { get; set; } - - [Newtonsoft.Json.JsonProperty("numFlakyTests", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? NumFlakyTests { get; set; } - - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Status { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestRunShardDto - { - [Newtonsoft.Json.JsonProperty("uploadCompleted", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.RegularExpression(@"true|false")] - public string UploadCompleted { get; set; } - - [Newtonsoft.Json.JsonProperty("summary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestRunShardSummary Summary { get; set; } - - [Newtonsoft.Json.JsonProperty("testRunConfig", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public ClientConfig TestRunConfig { get; set; } - - [Newtonsoft.Json.JsonProperty("resultsSummary", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public TestRunResultsSummary ResultsSummary { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestRunShardSummary - { - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"RUNNING|CLIENT_COMPLETE|SERVER_COMPLETE")] - public string Status { get; set; } - - [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$")] - public string StartTime { get; set; } - - [Newtonsoft.Json.JsonProperty("endTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$")] - public string EndTime { get; set; } - - [Newtonsoft.Json.JsonProperty("errorMessages", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection ErrorMessages { get; set; } - - [Newtonsoft.Json.JsonProperty("uploadMetadata", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public UploadMetadata UploadMetadata { get; set; } - - [Newtonsoft.Json.JsonProperty("totalTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? TotalTime { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestRunSummary - { - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"RUNNING|CLIENT_COMPLETE|SERVER_COMPLETE")] - public string Status { get; set; } - - [Newtonsoft.Json.JsonProperty("startTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string StartTime { get; set; } - - [Newtonsoft.Json.JsonProperty("endTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string EndTime { get; set; } - - [Newtonsoft.Json.JsonProperty("billableTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? BillableTime { get; set; } - - [Newtonsoft.Json.JsonProperty("totalTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? TotalTime { get; set; } - - [Newtonsoft.Json.JsonProperty("numBrowserSessions", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? NumBrowserSessions { get; set; } - - [Newtonsoft.Json.JsonProperty("jobs", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Jobs { get; set; } - - [Newtonsoft.Json.JsonProperty("projects", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Projects { get; set; } - - [Newtonsoft.Json.JsonProperty("tags", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Tags { get; set; } - - [Newtonsoft.Json.JsonProperty("errorMessages", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection ErrorMessages { get; set; } - - [Newtonsoft.Json.JsonProperty("uploadMetadata", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public UploadMetadata UploadMetadata { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class TestSummary - { - [Newtonsoft.Json.JsonProperty("total", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Total { get; set; } - - [Newtonsoft.Json.JsonProperty("passed", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Passed { get; set; } - - [Newtonsoft.Json.JsonProperty("failed", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Failed { get; set; } - - [Newtonsoft.Json.JsonProperty("skipped", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Skipped { get; set; } - - [Newtonsoft.Json.JsonProperty("flaky", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public int? Flaky { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class UploadMetadata - { - [Newtonsoft.Json.JsonProperty("numTestResults", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? NumTestResults { get; set; } - - [Newtonsoft.Json.JsonProperty("numTotalAttachments", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? NumTotalAttachments { get; set; } - - [Newtonsoft.Json.JsonProperty("sizeTotalAttachments", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public long? SizeTotalAttachments { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class UploadTestResultsRequest - { - [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection Value { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class WebTestConfig - { - [Newtonsoft.Json.JsonProperty("jobName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string JobName { get; set; } - - [Newtonsoft.Json.JsonProperty("projectName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string ProjectName { get; set; } - - [Newtonsoft.Json.JsonProperty("browserName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string BrowserName { get; set; } - - [Newtonsoft.Json.JsonProperty("os", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Os { get; set; } - - } - - - - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class ApiException : System.Exception - { - public int StatusCode { get; private set; } - - public string Response { get; private set; } - - public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } - - public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) - : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) - { - StatusCode = statusCode; - Response = response; - Headers = headers; - } - - public override string ToString() - { - return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); - } - } - - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class ApiException : ApiException - { - public TResult Result { get; private set; } - - public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) - : base(message, statusCode, response, headers, innerException) - { - Result = result; - } - } - -} - -#pragma warning restore 108 -#pragma warning restore 114 -#pragma warning restore 472 -#pragma warning restore 612 -#pragma warning restore 1573 -#pragma warning restore 1591 -#pragma warning restore 8073 -#pragma warning restore 3016 -#pragma warning restore 8603 -#pragma warning restore 8604 -#pragma warning restore 8625 \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClientOptions.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClientOptions.cs new file mode 100644 index 000000000000..cf4492767fe7 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClientOptions.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using Azure.Core; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client +{ + /// Client options for TestReporting library clients. + public partial class TestReportingClientOptions : ClientOptions + { + private const ServiceVersion LatestVersion = ServiceVersion.V2024_05_20_Preview; + + /// The version of the service to use. + public enum ServiceVersion + { + /// Service version "2024-05-20-preview". + V2024_05_20_Preview = 1, + } + + internal string Version { get; } + + /// Initializes new instance of TestReportingClientOptions. + public TestReportingClientOptions(ServiceVersion version = LatestVersion) + { + Version = version switch + { + ServiceVersion.V2024_05_20_Preview => "2024-05-20-preview", + _ => throw new NotSupportedException() + }; + } + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs index 8a2deee0d5a0..c42f08d89df9 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; +using System.Text.Json.Serialization; namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; @@ -29,10 +30,14 @@ internal class MPTError } internal class RawTestResult { - internal List Steps { get; set; } = new List(); - internal string? errors { get; set; } - internal string? stdErr { get; set; } - internal string? stdOut { get; set; } + [JsonPropertyName("steps")] + public List Steps { get; set; } = new List(); + [JsonPropertyName("errors")] + public string? errors { get; set; } + [JsonPropertyName("stdErr")] + public string? stdErr { get; set; } + [JsonPropertyName("stdOut")] + public string? stdOut { get; set; } } internal class TokenDetails diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/TestReporting.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/TestReporting.cs new file mode 100644 index 000000000000..08cff08b222f --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/TestReporting.cs @@ -0,0 +1,313 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; + +internal enum AccessLevel +{ + Read = 0, + Write = 1, + ReadWrite = 2, + ReadAddCreateWrite = 3, +} + +internal partial class CIConfig +{ + [JsonPropertyName("ciProviderName")] public string CiProviderName { get; set; } = ""; + + [JsonPropertyName("branch")] public string Branch { get; set; } = ""; + + [JsonPropertyName("author")] public string Author { get; set; } = ""; + + [JsonPropertyName("commitId")] public string CommitId { get; set; } = ""; + + [JsonPropertyName("revisionUrl")] public string RevisionUrl { get; set; } = ""; +} + +internal partial class ClientConfig +{ + [JsonPropertyName("retries")] + public int Retries { get; set; } + + [JsonPropertyName("repeatEach")] + public int RepeatEach { get; set; } + + [JsonPropertyName("workers")] + public int Workers { get; set; } + + [JsonPropertyName("pwVersion")] public string PwVersion { get; set; } = ""; + + [JsonPropertyName("testFramework")] + public TestFramework? TestFramework { get; set; } + + [JsonPropertyName("shards")] + public Shard? Shards { get; set; } + + [JsonPropertyName("timeout")] + public int Timeout { get; set; } + + [JsonPropertyName("testType")] public string TestType { get; set; } = ""; + + [JsonPropertyName("testSdkLanguage")] public string TestSdkLanguage { get; set; } = ""; + + [JsonPropertyName("reporterPackageVersion")] public string ReporterPackageVersion { get; set; } = ""; +} + +internal partial class PreviousRetrySummary +{ + [JsonPropertyName("testExecutionId")] public string TestExecutionId { get; set; } = ""; + + [JsonPropertyName("retry")] + public int Retry { get; set; } + + [JsonPropertyName("status")] public string Status { get; set; } = ""; + + [JsonPropertyName("duration")] public long Duration { get; set; } + + [JsonPropertyName("startTime")] public string StartTime { get; set; } = ""; + + [JsonPropertyName("attachmentsMetadata")] public string AttachmentsMetadata { get; set; } = ""; + + [JsonPropertyName("artifactsPath")] + public ICollection ArtifactsPath { get; set; } = new List(); +} + +internal partial class Shard +{ + [JsonPropertyName("total")] + public int Total { get; set; } + + [JsonPropertyName("current")] + public int Current { get; set; } +} + +internal partial class TestFramework +{ + [JsonPropertyName("name")] public string Name { get; set; } = ""; + + [JsonPropertyName("version")] public string Version { get; set; } = ""; + + [JsonPropertyName("runnerName")] public string RunnerName { get; set; } = ""; +} + +internal partial class TestResults +{ + [JsonPropertyName("testExecutionId")] public string TestExecutionId { get; set; } = ""; + + [JsonPropertyName("testId")] public string TestId { get; set; } = ""; + + [JsonPropertyName("testCombinationId")] public string TestCombinationId { get; set; } = ""; + + [JsonPropertyName("runId")] public string RunId { get; set; } = ""; + + [JsonPropertyName("accountId")] public string AccountId { get; set; } = ""; + + [JsonPropertyName("suiteId")] public string SuiteId { get; set; } = ""; + + [JsonPropertyName("testTitle")] public string TestTitle { get; set; } = ""; + + [JsonPropertyName("suiteTitle")] public string SuiteTitle { get; set; } = ""; + + [JsonPropertyName("fileName")] public string FileName { get; set; } = ""; + + [JsonPropertyName("lineNumber")] + public int LineNumber { get; set; } + + [JsonPropertyName("retry")] + public int Retry { get; set; } + + [JsonPropertyName("status")] public string Status { get; set; } = ""; + + [JsonPropertyName("webTestConfig")] + public WebTestConfig? WebTestConfig { get; set; } + + [JsonPropertyName("ciConfig")] + public CIConfig? CiConfig { get; set; } + + [JsonPropertyName("resultsSummary")] + public TestResultsSummary? ResultsSummary { get; set; } + + [JsonPropertyName("previousRetries")] + public ICollection PreviousRetries { get; set; } = new List(); + + [JsonPropertyName("tags")] + public ICollection Tags { get; set; } = new List(); + + [JsonPropertyName("annotations")] + public ICollection Annotations { get; set; } = new List(); + + [JsonPropertyName("artifactsPath")] + public ICollection ArtifactsPath { get; set; } = new List(); +} + +internal partial class TestResultsSummary +{ + [JsonPropertyName("status")] public string Status { get; set; } = ""; + + [JsonPropertyName("duration")] public long Duration { get; set; } + + [JsonPropertyName("startTime")] public string StartTime { get; set; } = ""; + + [JsonPropertyName("attachmentsMetadata")] public string AttachmentsMetadata { get; set; } = ""; +} + +internal partial class TestResultsUri +{ + [JsonPropertyName("uri")] public string Uri { get; set; } = ""; + + [JsonPropertyName("createdAt")] public string CreatedAt { get; set; } = ""; + + [JsonPropertyName("expiresAt")] public string ExpiresAt { get; set; } = ""; + + [JsonPropertyName("accessLevel")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public AccessLevel? AccessLevel { get; set; } +} + +internal partial class TestRunDtoV2 +{ + [JsonPropertyName("testRunId")] + public string TestRunId { get; set; } = ""; + + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = ""; + + [JsonPropertyName("startTime")] + public string StartTime { get; set; } = ""; + + [JsonPropertyName("creatorId")] + public string CreatorId { get; set; } = ""; + + [JsonPropertyName("creatorName")] + public string CreatorName { get; set; } = ""; + + [JsonPropertyName("summary")] + public TestRunSummary? Summary { get; set; } + + [JsonPropertyName("resultsSummary")] + public TestRunResultsSummary? ResultsSummary { get; set; } + + [JsonPropertyName("ciConfig")] + public CIConfig? CiConfig { get; set; } + + [JsonPropertyName("testRunConfig")] + public ClientConfig? TestRunConfig { get; set; } + + [JsonPropertyName("testResultsUri")] + public TestResultsUri? TestResultsUri { get; set; } + + [JsonPropertyName("cloudRunEnabled")] public string CloudRunEnabled { get; set; } = ""; + + [JsonPropertyName("cloudReportingEnabled")] public string CloudReportingEnabled { get; set; } = ""; +} + +internal partial class TestRunResultsSummary +{ + [JsonPropertyName("numTotalTests")] + public long NumTotalTests { get; set; } + + [JsonPropertyName("numPassedTests")] + public long NumPassedTests { get; set; } + + [JsonPropertyName("numFailedTests")] + public long NumFailedTests { get; set; } + + [JsonPropertyName("numSkippedTests")] + public long NumSkippedTests { get; set; } + + [JsonPropertyName("numFlakyTests")] + public long NumFlakyTests { get; set; } + + [JsonPropertyName("status")] + public string Status { get; set; } = ""; +} + +internal partial class TestRunShardDto +{ + [JsonPropertyName("uploadCompleted")] public string UploadCompleted { get; set; } = ""; + + [JsonPropertyName("summary")] + public TestRunShardSummary? Summary { get; set; } + + [JsonPropertyName("testRunConfig")] + public ClientConfig? TestRunConfig { get; set; } + + [JsonPropertyName("resultsSummary")] + public TestRunResultsSummary? ResultsSummary { get; set; } +} + +internal partial class TestRunShardSummary +{ + [JsonPropertyName("status")] public string Status { get; set; } = ""; + + [JsonPropertyName("startTime")] public string StartTime { get; set; } = ""; + + [JsonPropertyName("endTime")] public string EndTime { get; set; } = ""; + + [JsonPropertyName("errorMessages")] + public ICollection ErrorMessages { get; set; } = new List(); + + [JsonPropertyName("uploadMetadata")] + public UploadMetadata? UploadMetadata { get; set; } + + [JsonPropertyName("totalTime")] public long TotalTime { get; set; } +} + +internal partial class TestRunSummary +{ + [JsonPropertyName("status")] public string Status { get; set; } = ""; + + [JsonPropertyName("startTime")] public string StartTime { get; set; } = ""; + + [JsonPropertyName("endTime")] public string EndTime { get; set; } = ""; + + [JsonPropertyName("billableTime")] public long BillableTime { get; set; } + + [JsonPropertyName("totalTime")] public long TotalTime { get; set; } + + [JsonPropertyName("numBrowserSessions")] public long NumBrowserSessions { get; set; } + + [JsonPropertyName("jobs")] + public ICollection Jobs { get; set; } = new List(); + + [JsonPropertyName("projects")] + public ICollection Projects { get; set; } = new List(); + + [JsonPropertyName("tags")] + public ICollection Tags { get; set; } = new List(); + + [JsonPropertyName("errorMessages")] + public ICollection ErrorMessages { get; set; } = new List(); + + [JsonPropertyName("uploadMetadata")] + public UploadMetadata? UploadMetadata { get; set; } +} + +internal partial class UploadMetadata +{ + [JsonPropertyName("numTestResults")] public long NumTestResults { get; set; } + + [JsonPropertyName("numTotalAttachments")] public long NumTotalAttachments { get; set; } + + [JsonPropertyName("sizeTotalAttachments")] public long SizeTotalAttachments { get; set; } +} + +internal partial class UploadTestResultsRequest +{ + [JsonPropertyName("value")] + public ICollection Value { get; set; } = new List(); +} + +internal partial class WebTestConfig +{ + [JsonPropertyName("jobName")] public string JobName { get; set; } = ""; + + [JsonPropertyName("projectName")] public string ProjectName { get; set; } = ""; + + [JsonPropertyName("browserName")] public string BrowserName { get; set; } = ""; + + [JsonPropertyName("os")] public string Os { get; set; } = ""; +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index b111d1062587..68c2bc07b7fc 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -1,24 +1,26 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Azure.Storage.Blobs; using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility; -using Azure.Storage.Blobs; +using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client; using Microsoft.IdentityModel.JsonWebTokens; -using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Clients; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging; -using Newtonsoft.Json; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; -using PlaywrightConstants = Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility.Constants; -using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; using System.IO; +using System.Text.Json; +using PlaywrightConstants = Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility.Constants; +using Azure.Core; +using Azure.Core.Serialization; namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; @@ -32,14 +34,13 @@ internal class PlaywrightReporter : ITestLoggerWithParameters private HttpClient? _httpClient; - private TestReportingClient? _testReportingClient; + private ReportingTestResultsClient? _reportingTestResultsClient; + private ReportingTestRunsClient? _reportingTestRunsClient; private static readonly JsonWebTokenHandler s_tokenHandler = new(); private readonly LogLevel _logLevel = LogLevel.Debug; - private readonly string _apiVersion = PlaywrightConstants.ReportingAPIVersion_2024_05_20_preview; - internal static string EnableConsoleLog { get => Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_DEBUG) ?? "false"; set { } } internal string? PortalUrl { get; set; } @@ -103,13 +104,11 @@ internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) { InitializePlaywrightReporter(e.TestRunCriteria.TestRunSettings); LogMessage("Test Run start Handler"); - if (!IsInitialized || _testReportingClient == null) + if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null) { LogErrorMessage("Test Run setup issue exiting handler"); return; } - var testResultsJson = JsonConvert.SerializeObject(e); - LogMessage(testResultsJson); var startTime = TestRunStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"); LogMessage("Test Run start time: " + startTime); @@ -117,11 +116,11 @@ internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) var runName = "TestRun#" + startTime; // TODO discuss approach var run = new TestRunDtoV2 { - TestRunId = RunId, + TestRunId = RunId!, DisplayName = runName, StartTime = startTime, - CreatorId = TokenDetails!.oid, - CreatorName = TokenDetails.userName, + CreatorId = TokenDetails!.oid ?? "", + CreatorName = TokenDetails.userName ?? "", //CloudRunEnabled = "false", CloudReportingEnabled = "true", Summary = new TestRunSummary @@ -134,10 +133,10 @@ internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) }, CiConfig = new CIConfig // TODO fetch dynamically { - Branch = CIInfo!.Branch, - Author = CIInfo.Author, - CommitId = CIInfo.CommitId, - RevisionUrl = CIInfo.RevisionUrl + Branch = CIInfo!.Branch ?? "", + Author = CIInfo.Author ?? "", + CommitId = CIInfo.CommitId ?? "", + RevisionUrl = CIInfo.RevisionUrl ?? "" }, TestRunConfig = new ClientConfig // TODO fetch some of these dynamically { @@ -172,20 +171,14 @@ internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) } }; var token = "Bearer " + AccessToken; - TestRunDtoV2 response; + TestRunDtoV2? response = null; try { - var testRunBodyJson = JsonConvert.SerializeObject(run); - LogMessage("TestRunInput" + testRunBodyJson); -#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. - response = _testReportingClient.WorkspacesTestRunsPatchAsync( // Add retry - WorkspaceId, - RunId, - token, - corelationId, - _apiVersion, - run).GetAwaiter().GetResult(); -#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + Response apiResponse = _reportingTestRunsClient.PatchTestRunInfo(WorkspaceId, RunId, RequestContent.Create(run), "application/json", token, corelationId); + if (apiResponse.Content != null) + { + response = apiResponse.Content!.ToObject(new JsonObjectSerializer()); + } } catch (Exception ex) { @@ -194,25 +187,18 @@ internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) } if (response != null) { - var testRunJson = JsonConvert.SerializeObject(response); - LogMessage("TestRunResponse" + testRunJson); - this.TestRun = response; + TestRun = response; // Start shard corelationId = Guid.NewGuid().ToString(); - TestRunShardDto response1; + TestRunShardDto? response1 = null; try { -#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. - response1 = _testReportingClient.WorkspacesTestRunsShardsAsync( - WorkspaceId, - RunId, - "1", - token, - corelationId, - _apiVersion, - shard).GetAwaiter().GetResult(); -#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + Response apiResponse = _reportingTestRunsClient.PatchTestRunShardInfo(WorkspaceId, RunId, "1", RequestContent.Create(shard), "application/json", token, corelationId); + if (apiResponse.Content != null) + { + response1 = apiResponse.Content!.ToObject(new JsonObjectSerializer()); + } } catch (Exception ex) { @@ -221,8 +207,6 @@ internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) } if (response1 != null) { - var testRunShardJson = JsonConvert.SerializeObject(response); - LogMessage("TestRunShardResponse" + testRunShardJson); TestRunShard = shard; // due to wrong response type TODO } else @@ -248,14 +232,11 @@ internal void TestMessageHandler(object? sender, TestRunMessageEventArgs e) internal void TestResultHandler(object? sender, TestResultEventArgs e) { LogMessage("Test Result Handler"); - if (!IsInitialized || _testReportingClient == null) + if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null) { LogErrorMessage("Test Run setup issue exiting handler"); return; } - var testResultsJson = JsonConvert.SerializeObject(e); - LogMessage(testResultsJson); - TestResults? testResult = GetTestCaseResultData(e.Result); // Set various counts (passed tests, failed tests, total tests) if (testResult != null) @@ -283,14 +264,11 @@ internal void TestResultHandler(object? sender, TestResultEventArgs e) internal void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e) { LogMessage("Test Run End Handler"); - if (!IsInitialized || _testReportingClient == null || TestRun == null) + if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null || TestRun == null) { LogErrorMessage("Test Run setup issue exiting handler"); return; } - var testResultsJson = JsonConvert.SerializeObject(e); - LogMessage(testResultsJson); - LogMessage(JsonConvert.SerializeObject(TestResults)); // Upload TestResults var corelationId = Guid.NewGuid().ToString(); var token = "Bearer " + AccessToken; @@ -298,14 +276,7 @@ internal void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e) var body = new UploadTestResultsRequest() { Value = TestResults }; try { -#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. - _testReportingClient.WorkspacesTestResultsUploadBatchAsync( - WorkspaceId, - token, - corelationId, - _apiVersion, - body).GetAwaiter().GetResult(); -#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + _reportingTestResultsClient.UploadBatchTestResults(WorkspaceId, RequestContent.Create(JsonSerializer.Serialize(body)), token, corelationId, null); LogMessage("Test Result Uploaded"); } catch (Exception ex) @@ -314,25 +285,24 @@ internal void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e) } corelationId = Guid.NewGuid().ToString(); -#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. - TestResultsUri sasUri = _testReportingClient.WorkspacesTestRunsResulturiAsync( - WorkspaceId, - RunId, - token, - corelationId, - _apiVersion).GetAwaiter().GetResult(); -#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + TestResultsUri? sasUri = null; + Response response = _reportingTestRunsClient.GetTestRunResultsUri(WorkspaceId, RunId, token, corelationId, null); + var serializer = new JsonObjectSerializer(); + if (response.Content != null) + { + sasUri = response.Content.ToObject(serializer); + } if (sasUri != null && !string.IsNullOrEmpty(sasUri.Uri)) { LogMessage("Test Run Uri: " + sasUri.ToString()); foreach (TestResults testResult in TestResults) { - if (RawTestResultsMap.TryGetValue(testResult.TestExecutionId, out RawTestResult? rawResult) && rawResult != null) + if (RawTestResultsMap.TryGetValue(testResult.TestExecutionId!, out RawTestResult? rawResult) && rawResult != null) { // Upload rawResult to blob storage using sasUri - var rawTestResultJson = JsonConvert.SerializeObject(rawResult); + var rawTestResultJson = JsonSerializer.Serialize(rawResult); var filePath = $"{testResult.TestExecutionId}/rawTestResult.json"; - UploadBuffer(sasUri.Uri, rawTestResultJson, filePath); + UploadBuffer(sasUri.Uri!, rawTestResultJson, filePath); } else { @@ -342,7 +312,7 @@ internal void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e) } else { - Logger.Log(true, LogLevel.Error, "MPT API error: failed to upload artifacts"); + LogMessage("MPT API error: failed to upload artifacts"); } LogMessage("Test Results uploaded"); // Update TestRun with CLIENT_COMPLETE @@ -355,7 +325,7 @@ internal void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e) private bool UpdateTestRun(TestRunCompleteEventArgs e) { - if (!IsInitialized || _testReportingClient == null || TestRun == null || TestRunShard == null) + if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null || TestRun == null || TestRunShard == null) return false; DateTime testRunStartedOn = DateTime.MinValue; DateTime testRunEndedOn = DateTime.UtcNow; @@ -390,22 +360,11 @@ private bool UpdateTestRun(TestRunCompleteEventArgs e) Status = result }; TestRunShard.UploadCompleted = "true"; - var testRunShardJson = JsonConvert.SerializeObject(TestRunShard); - LogMessage(testRunShardJson); var token = "Bearer " + AccessToken; var corelationId = Guid.NewGuid().ToString(); try { -#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. - _testReportingClient.WorkspacesTestRunsShardsAsync( - WorkspaceId, - RunId, - "1", - token, - corelationId, - _apiVersion, - TestRunShard).GetAwaiter().GetResult(); -#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. + _reportingTestRunsClient.PatchTestRunShardInfo(WorkspaceId, RunId, "1", RequestContent.Create(TestRunShard), "application/json", token, corelationId); } catch (Exception ex) { @@ -430,8 +389,8 @@ private TestResults GetTestCaseResultData(TestResult testResultSource) { ArtifactsPath = new List(), - AccountId = WorkspaceId, - RunId = RunId, + AccountId = WorkspaceId!, + RunId = RunId!, TestExecutionId = GetExecutionId(testResultSource).ToString() }; testCaseResultData.TestCombinationId = testCaseResultData.TestExecutionId; // TODO check @@ -445,7 +404,7 @@ private TestResults GetTestCaseResultData(TestResult testResultSource) testCaseResultData.Retry = 0; // TODO Retry and PreviousRetries testCaseResultData.WebTestConfig = new WebTestConfig { - JobName = CIInfo!.JobId, + JobName = CIInfo!.JobId ?? "", //ProjectName = "playwright-dotnet", // TODO no project concept NA?? //BrowserName = "chromium", // TODO check if possible to get from test Os = GetCurrentOS(), @@ -558,7 +517,7 @@ private static RawTestResult GetRawResultObject(TestResult testResultSource) errors.Add(new MPTError() { message = testResultSource.ErrorMessage }); var rawTestResult = new RawTestResult { - errors = JsonConvert.SerializeObject(errors), + errors = JsonSerializer.Serialize(errors), stdErr = testResultSource?.ErrorStackTrace ?? string.Empty }; return rawTestResult; @@ -625,13 +584,24 @@ private void InitializePlaywrightReporter(string xmlSettings) Dictionary runParameters = XmlRunSettingsUtilities.GetTestRunParameters(xmlSettings); runParameters.TryGetValue(RunSettingKey.RUN_ID, out var runId); + // If run id is not provided and not set via env, try fetching it from CI info. + CIInfo = CiInfoProvider.GetCIInfo(); + if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID)) && !string.IsNullOrEmpty(CIInfo.RunId) && string.IsNullOrEmpty(runId?.ToString())) + { + Environment.SetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID, CIInfo.RunId); + } + else + { + PlaywrightService.GetDefaultRunId(); // will not set run id if already present in the environment variable + } + runParameters.TryGetValue(RunSettingKey.DEFAULT_AUTH, out var defaultAuth); runParameters.TryGetValue(RunSettingKey.AZURE_TOKEN_CREDENTIAL_TYPE, out var azureTokenCredential); runParameters.TryGetValue(RunSettingKey.MANAGED_IDENTITY_CLIENT_ID, out var managedIdentityClientId); runParameters.TryGetValue(RunSettingKey.ENABLE_GITHUB_SUMMARY, out var enableGithubSummary); string? enableGithubSummaryString = enableGithubSummary?.ToString(); - EnableGithubSummary = string.IsNullOrEmpty(enableGithubSummaryString) || bool.Parse(enableGithubSummaryString!); + EnableGithubSummary = string.IsNullOrEmpty(enableGithubSummaryString) || bool.Parse(enableGithubSummaryString!); PlaywrightServiceSettings? playwrightServiceSettings = null; try { @@ -643,17 +613,6 @@ private void InitializePlaywrightReporter(string xmlSettings) Environment.Exit(1); } - // If run id is not provided and not set via env, try fetching it from CI info. - CIInfo = CiInfoProvider.GetCIInfo(); - if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID)) && !string.IsNullOrEmpty(CIInfo.RunId) && string.IsNullOrEmpty(runId?.ToString())) - { - Environment.SetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID, CIInfo.RunId); - } - else - { - PlaywrightService.GetDefaultRunId(); // will not set run id if already present in the environment variable - } - // setup entra rotation handlers playwrightService = new PlaywrightService(null, playwrightServiceSettings!.RunId, null, playwrightServiceSettings.DefaultAuth, null, playwrightServiceSettings.AzureTokenCredential); #pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. @@ -688,7 +647,9 @@ private void InitializePlaywrightReporter(string xmlSettings) PortalUrl = PlaywrightConstants.PortalBaseUrl + WorkspaceId + PlaywrightConstants.ReportingRoute + RunId; _httpClient = new HttpClient(); - _testReportingClient = new TestReportingClient(BaseUrl, _httpClient); + var baseUri = new Uri(BaseUrl!); + _reportingTestRunsClient = new ReportingTestRunsClient(baseUri); + _reportingTestResultsClient = new ReportingTestResultsClient(baseUri); IsInitialized = true; @@ -702,13 +663,13 @@ public void GenerateMarkdownSummary() string markdownContent = @$" #### Results: -![pass](https://img.shields.io/badge/status-passed-brightgreen) **Passed:** {TestRunShard!.ResultsSummary.NumPassedTests} +![pass](https://img.shields.io/badge/status-passed-brightgreen) **Passed:** {TestRunShard!.ResultsSummary!.NumPassedTests} -![fail](https://img.shields.io/badge/status-failed-red) **Failed:** {TestRunShard!.ResultsSummary.NumFailedTests} +![fail](https://img.shields.io/badge/status-failed-red) **Failed:** {TestRunShard.ResultsSummary.NumFailedTests} ![flaky](https://img.shields.io/badge/status-flaky-yellow) **Flaky:** {"0"} -![skipped](https://img.shields.io/badge/status-skipped-lightgrey) **Skipped:** {TestRunShard!.ResultsSummary.NumSkippedTests} +![skipped](https://img.shields.io/badge/status-skipped-lightgrey) **Skipped:** {TestRunShard.ResultsSummary.NumSkippedTests} #### For more details, visit the [service dashboard]({Uri.EscapeUriString(PortalUrl!)}). "; From 868c50cefeb3628e945d10c8c78915e3e38befdb Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 12 Aug 2024 17:12:25 +0530 Subject: [PATCH 08/32] fix(): json parsing of error messages --- .../src/Azure.Developer.MicrosoftPlaywrightTesting.csproj | 3 ++- .../src/TestLogger/Model/MPTResult.cs | 8 ++++---- .../src/TestLogger/PlaywrightReporter.cs | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj index 4a08d1ec4c8a..d5d956625bf2 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj @@ -14,7 +14,8 @@ true $(RequiredTargetFrameworks) enable - + true + diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs index c42f08d89df9..50006b0d55dc 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs @@ -26,18 +26,18 @@ internal class Location internal class MPTError { - internal string? message { get; set; } + public string? message { get; set; } } internal class RawTestResult { [JsonPropertyName("steps")] public List Steps { get; set; } = new List(); [JsonPropertyName("errors")] - public string? errors { get; set; } + public string errors { get; set; } = "[]"; [JsonPropertyName("stdErr")] - public string? stdErr { get; set; } + public string stdErr { get; set; } = "[]"; [JsonPropertyName("stdOut")] - public string? stdOut { get; set; } + public string stdOut { get; set; } = "[]"; } internal class TokenDetails diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index 68c2bc07b7fc..221880fd0f32 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -685,4 +685,4 @@ public void GenerateMarkdownSummary() } } } -} \ No newline at end of file +} From 8cc4441d58b3672d7644fa297f7dbe5b0687f83e Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Wed, 14 Aug 2024 11:47:33 +0530 Subject: [PATCH 09/32] chore(): add live tests --- .../src/TestLogger/PlaywrightReporter.cs | 2 +- .../tests/EntraLifecycleTests.cs | 6 +- .../tests/PlaywrightServiceClientTests.cs | 55 +++++++++++++++++++ .../tests/PlaywrightServiceSettingsTest.cs | 4 +- .../tests/PlaywrightServiceTestEnvironment.cs | 12 ++++ .../tests/PlaywrightServiceTests.cs | 16 +++--- .../tests/TestUtils.cs | 20 +++++++ sdk/playwrighttesting/test-resources.json | 32 +++++++++++ sdk/playwrighttesting/tests.yml | 8 +++ 9 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTestEnvironment.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/TestUtils.cs create mode 100644 sdk/playwrighttesting/test-resources.json create mode 100644 sdk/playwrighttesting/tests.yml diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index 221880fd0f32..047c84c63e76 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -102,7 +102,7 @@ public void Initialize(TestLoggerEvents events, string testResultsDirPath) internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) { - InitializePlaywrightReporter(e.TestRunCriteria.TestRunSettings); + InitializePlaywrightReporter(e.TestRunCriteria.TestRunSettings!); LogMessage("Test Run start Handler"); if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null) { diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs index 64fedd3a4dca..250873adabe5 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs @@ -88,7 +88,7 @@ public void Constructor_WhenJWTValidationThrowsException_DoesNotInitializeEntraT [Test] public void Constructor_WhenAccessTokenEnvironmentIsSetAndValid_InitializeEntraToken() { - var expiry = DateTime.UtcNow.AddMinutes(10); + DateTime expiry = DateTime.UtcNow.AddMinutes(10); var token = GetToken(new Dictionary(), expiry); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); EntraLifecycle entraLifecycle = new(); @@ -119,7 +119,7 @@ public async Task FetchEntraIdAccessTokenAsync_WhenTokenIsFetched_SetsTokenAndEx { var defaultAzureCredentialMock = new Mock(); var token = "valid_token"; - var expiry = DateTimeOffset.UtcNow.AddMinutes(10); + DateTimeOffset expiry = DateTimeOffset.UtcNow.AddMinutes(10); defaultAzureCredentialMock .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new AccessToken(token, expiry)); @@ -136,7 +136,7 @@ public async Task FetchEntraIdAccessTokenAsync_WhenTokenIsFetched_ReturnsTrue() { var defaultAzureCredentialMock = new Mock(); var token = "valid_token"; - var expiry = DateTimeOffset.UtcNow.AddMinutes(10); + DateTimeOffset expiry = DateTimeOffset.UtcNow.AddMinutes(10); defaultAzureCredentialMock .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new AccessToken(token, expiry)); diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs new file mode 100644 index 000000000000..37ef26196817 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Azure.Core.TestFramework; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; + +public class PlaywrightServiceClientTests : RecordedTestBase +{ + private PlaywrightService? _playwrightService; + private static string Access_Token => Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE)!; + + public PlaywrightServiceClientTests(bool isAsync) : base(isAsync, RecordedTestMode.Live) { } + + [SetUp] + public async Task Setup() + { + var workspaceId = TestUtils.GetWorkspaceIdFromDashboardEndpoint(TestEnvironment.DashboardEndpoint); + var region = TestEnvironment.Region; + var serviceApiEndpoint = TestUtils.GetPlaywrightServiceAPIEndpoint(workspaceId, region); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, serviceApiEndpoint); + _playwrightService = new PlaywrightService(new PlaywrightServiceSettings(), tokenCredential: TestEnvironment.Credential); + await _playwrightService.InitializeAsync(); + } + + [TearDown] + public void Teardown() + { + _playwrightService?.Cleanup(); + } + + [Test] + [Category("Live")] + public async Task TestPlaywrightServiceConnection() + { + var workspaceId = TestUtils.GetWorkspaceIdFromDashboardEndpoint(TestEnvironment.DashboardEndpoint); + var region = TestEnvironment.Region; + var serviceApiEndpoint = TestUtils.GetPlaywrightServiceAPIEndpoint(workspaceId, region); + var client = new HttpClient(new HttpClientHandler + { + AllowAutoRedirect = false + }); + var request = new HttpRequestMessage(HttpMethod.Get, serviceApiEndpoint); + request.Headers.Add("Authorization", $"Bearer {Access_Token}"); + request.RequestUri = new Uri($"{request.RequestUri}?cap={{}}"); + HttpResponseMessage response = await client.SendAsync(request); + response.Headers.TryGetValues("Location", out System.Collections.Generic.IEnumerable? location); + Assert.AreEqual(302, (int)response.StatusCode); + Assert.IsTrue(location!.Any(url => url.Contains("browser.playwright.microsoft.com"))); + } +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs index ba7dfb5989ef..1b0831e93f55 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs @@ -55,7 +55,7 @@ public void Constructor_ShouldUseDefaultValues() public void Validate_ShouldThrowExceptionForInvalidOs() { var invalidOs = "InvalidOS"; - var ex = Assert.Throws(() => new PlaywrightServiceSettings(os: invalidOs)); + Exception? ex = Assert.Throws(() => new PlaywrightServiceSettings(os: invalidOs)); Assert.That(ex!.Message, Does.Contain("Invalid value for Os")); } @@ -63,7 +63,7 @@ public void Validate_ShouldThrowExceptionForInvalidOs() public void Validate_ShouldThrowExceptionForInvalidDefaultAuth() { var invalidAuth = "InvalidAuth"; - var ex = Assert.Throws(() => new PlaywrightServiceSettings(defaultAuth: invalidAuth)); + Exception? ex = Assert.Throws(() => new PlaywrightServiceSettings(defaultAuth: invalidAuth)); Assert.That(ex!.Message, Does.Contain("Invalid value for DefaultAuth")); } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTestEnvironment.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTestEnvironment.cs new file mode 100644 index 000000000000..6fc1a455403a --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTestEnvironment.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core.TestFramework; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; + +public class PlaywrightServiceTestEnvironment : TestEnvironment +{ + public string Region => GetRecordedVariable("PLAYWRIGHTTESTING_LOCATION"); + public string DashboardEndpoint => GetRecordedVariable("DASHBOARD_ENDPOINT"); +}; diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs index c27c1faa5447..0a633d304de5 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs @@ -379,7 +379,7 @@ public void GetConnectOptionsAsync_WhenServiceEndpointIsNotSet_ThrowsException() { Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); PlaywrightService service = new(entraLifecycle: null); - var ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); + Exception? ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); Assert.That(ex!.Message, Is.EqualTo(Constants.s_no_service_endpoint_error_message)); } @@ -387,7 +387,7 @@ public void GetConnectOptionsAsync_WhenServiceEndpointIsNotSet_ThrowsException() public void GetConnectOptionsAsync_WhenUseCloudHostedBrowsersEnvironmentIsFalse_ThrowsException() { PlaywrightService service = new(entraLifecycle: null, useCloudHostedBrowsers: false); - var ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); + Exception? ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); Assert.Multiple(() => { Assert.That(service.UseCloudHostedBrowsers, Is.False); @@ -407,7 +407,7 @@ public async Task GetConnectOptionsAsync_WhenServiceEndpointIsSet_ReturnsConnect var runId = "run-id"; PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); - var connectOptions = await service.GetConnectOptionsAsync(runId: runId); + ConnectOptions connectOptions = await service.GetConnectOptionsAsync(runId: runId); var authorizationHeader = connectOptions.Options!.Headers!.Where(x => x.Key == "Authorization").FirstOrDefault().Value!; Assert.Multiple(() => { @@ -467,7 +467,7 @@ public async Task GetConnectOptionsAsync_WhenDefaultParametersAreProvided_SetsSe var runId = "run-id"; var service = new PlaywrightService(entraLifecycle: entraLifecycleMock.Object); - var connectOptions = await service.GetConnectOptionsAsync(runId: runId, os: ServiceOs.WINDOWS, exposeNetwork: "localhost"); + ConnectOptions connectOptions = await service.GetConnectOptionsAsync(runId: runId, os: ServiceOs.WINDOWS, exposeNetwork: "localhost"); Assert.Multiple(() => { @@ -490,7 +490,7 @@ public async Task GetConnectOptionsAsync_WhenDefaultParametersAreNotProvided_Set var runId = "run-id"; var service = new PlaywrightService(entraLifecycle: entraLifecycleMock.Object); - var connectOptions = await service.GetConnectOptionsAsync(runId: runId); + ConnectOptions connectOptions = await service.GetConnectOptionsAsync(runId: runId); Assert.Multiple(() => { @@ -517,7 +517,7 @@ public async Task GetConnectOptionsAsync_WhenServiceParametersAreSetViaEnvironme Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE, "localhost"); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); - var connectOptions = await service.GetConnectOptionsAsync(); + ConnectOptions connectOptions = await service.GetConnectOptionsAsync(); Assert.Multiple(() => { Assert.That(connectOptions.WsEndpoint, Is.EqualTo($"https://playwright.microsoft.com?os={ServiceOs.WINDOWS}&runId={runId}&api-version={Constants.s_api_version}")); @@ -535,7 +535,7 @@ public void GetConnectOptionsAsync_WhenNoAuthTokenIsSet_ThrowsException() Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); - var ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); + Exception? ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); Assert.That(ex!.Message, Is.EqualTo(Constants.s_no_auth_error)); } @@ -603,7 +603,7 @@ public void SetReportingUrlAndWorkspaceId_WhenServiceEndpointIsSet_SetsReporting } }; - foreach (var testRubric in testRubricCombinations) + foreach (Dictionary testRubric in testRubricCombinations) { Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, $"{testRubric["url"]}"); var service = new PlaywrightService(entraLifecycle: null); diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/TestUtils.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/TestUtils.cs new file mode 100644 index 000000000000..0d884ef39cad --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/TestUtils.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Linq; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; + +public class TestUtils +{ + public static string GetPlaywrightServiceAPIEndpoint(string workspaceId, string region) + { + return $"https://{region}.api.playwright.microsoft.com/accounts/{workspaceId}/browsers"; + } + + public static string GetWorkspaceIdFromDashboardEndpoint(string dashboardEndpoint) + { + var parts = dashboardEndpoint.Split('/'); + return parts.Last(); + } +} diff --git a/sdk/playwrighttesting/test-resources.json b/sdk/playwrighttesting/test-resources.json new file mode 100644 index 000000000000..96dd2c7ae97a --- /dev/null +++ b/sdk/playwrighttesting/test-resources.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://schema.management.azure.com/schemas/2019-08-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "baseName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": {} + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location of the resource. By default, this is the same as the resource group." + } + } + }, + "resources": [ + { + "apiVersion": "2024-02-01-preview", + "name": "[parameters('baseName')]", + "location": "[parameters('location')]", + "type": "Microsoft.AzurePlaywrightService/accounts" + } + ], + "outputs": { + "DASHBOARD_ENDPOINT": { + "type": "string", + "value": "[reference(resourceId('Microsoft.AzurePlaywrightService/accounts', parameters('baseName'))).dashboardUri]" + } + } +} \ No newline at end of file diff --git a/sdk/playwrighttesting/tests.yml b/sdk/playwrighttesting/tests.yml new file mode 100644 index 000000000000..f5ec49ac34e2 --- /dev/null +++ b/sdk/playwrighttesting/tests.yml @@ -0,0 +1,8 @@ +trigger: none + +extends: + template: ../../eng/pipelines/templates/stages/archetype-sdk-tests.yml + parameters: + ServiceDirectory: playwrighttesting + SupportedClouds: 'Public' + Location: 'eastus' \ No newline at end of file From 817e12062b87d4625e976033035e117b75933b41 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Fri, 23 Aug 2024 16:03:36 +0530 Subject: [PATCH 10/32] fix(): run id handling across scalable and reporting --- .../src/Constants.cs | 4 +-- .../src/PlaywrightService.cs | 25 +++++++++++---- .../src/TestLogger/PlaywrightReporter.cs | 9 ++++-- .../src/TestLogger/Utility/ReporterUtils.cs | 31 +++++++++++++++++++ 4 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs index 77509b258755..131b91add6a7 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs @@ -191,8 +191,8 @@ internal class Constants internal static readonly string s_no_service_endpoint_error_message = "Please set PLAYWRIGHT_SERVICE_URL in your environment variables."; internal static readonly string s_service_endpoint_removed_since_scalable_execution_disabled_error_message = "GetConnectOptionsAsync() method cannot be used when disableScalableExecution is set to true in the setup file."; internal static readonly string s_no_auth_error = "Could not authenticate with the service. Please refer to https://aka.ms/mpt/authentication for more information."; - internal static readonly string s_invalid_mpt_pat_error = "The service PAT set in the environment variable is invalid."; - internal static readonly string s_expired_mpt_pat_error = "The service PAT has expired. Please create a new PAT."; + internal static readonly string s_invalid_mpt_pat_error = "The Access Token provided in the environment variable is invalid."; + internal static readonly string s_expired_mpt_pat_error = "The Access Token you are using is expired. Create a new token."; internal static readonly string s_playwright_service_disable_scalable_execution_environment_variable = "PLAYWRIGHT_SERVICE_DISABLE_SCALABLE_EXECUTION"; internal static readonly string s_playwright_service_reporting_url_environment_variable = "PLAYWRIGHT_SERVICE_REPORTING_URL"; diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs index 64daf6f14b30..fbb31e90b3cc 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. using Azure.Core; +using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; +using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility; using Microsoft.IdentityModel.JsonWebTokens; using System; using System.Collections.Generic; @@ -144,7 +146,10 @@ public async Task InitializeAsync() } // If default auth mechanism is Access token and token is available in the environment variable, no need to setup rotation handler if (DefaultAuth == ServiceAuth.TOKEN && !string.IsNullOrEmpty(GetAuthToken())) + { + ValidateMptPAT(); return; + } var operationStatus = await _entraLifecycle!.FetchEntraIdAccessTokenAsync().ConfigureAwait(false); if (!operationStatus) { @@ -218,7 +223,8 @@ internal static string GetDefaultRunId() var runIdFromEnvironmentVariable = Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE); if (!string.IsNullOrEmpty(runIdFromEnvironmentVariable)) return runIdFromEnvironmentVariable!; - var runId = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fff'Z'", CultureInfo.InvariantCulture); + CIInfo ciInfo = CiInfoProvider.GetCIInfo(); + var runId = ReporterUtils.GetRunId(ciInfo); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); return runId; } @@ -244,10 +250,17 @@ internal static void SetReportingUrlAndWorkspaceId() private void ValidateMptPAT() { - string authToken = GetAuthToken()!; - JsonWebToken jsonWebToken = _jsonWebTokenHandler!.ReadJsonWebToken(authToken) ?? throw new Exception(Constants.s_invalid_mpt_pat_error); - var expiry = (long)(jsonWebToken.ValidTo - new DateTime(1970, 1, 1)).TotalSeconds; - if (expiry <= DateTimeOffset.UtcNow.ToUnixTimeSeconds()) - throw new Exception(Constants.s_expired_mpt_pat_error); + try + { + string authToken = GetAuthToken()!; + JsonWebToken jsonWebToken = _jsonWebTokenHandler!.ReadJsonWebToken(authToken) ?? throw new Exception(Constants.s_invalid_mpt_pat_error); + var expiry = (long)(jsonWebToken.ValidTo - new DateTime(1970, 1, 1)).TotalSeconds; + if (expiry <= DateTimeOffset.UtcNow.ToUnixTimeSeconds()) + throw new Exception(Constants.s_expired_mpt_pat_error); + } + catch (Exception) + { + throw new Exception(Constants.s_invalid_mpt_pat_error); + } } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index 047c84c63e76..9e254a699a6c 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -113,7 +113,7 @@ internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) var startTime = TestRunStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"); LogMessage("Test Run start time: " + startTime); var corelationId = Guid.NewGuid().ToString(); - var runName = "TestRun#" + startTime; // TODO discuss approach + var runName = Guid.NewGuid().ToString(); // TODO discuss approach var run = new TestRunDtoV2 { TestRunId = RunId!, @@ -586,9 +586,12 @@ private void InitializePlaywrightReporter(string xmlSettings) runParameters.TryGetValue(RunSettingKey.RUN_ID, out var runId); // If run id is not provided and not set via env, try fetching it from CI info. CIInfo = CiInfoProvider.GetCIInfo(); - if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID)) && !string.IsNullOrEmpty(CIInfo.RunId) && string.IsNullOrEmpty(runId?.ToString())) + if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID))) { - Environment.SetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID, CIInfo.RunId); + if (string.IsNullOrEmpty(runId?.ToString())) + Environment.SetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID, ReporterUtils.GetRunId(CIInfo)); + else + Environment.SetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID, runId!.ToString()); } else { diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs new file mode 100644 index 000000000000..b1347b2f79f0 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Security.Cryptography; +using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; + +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility +{ + internal class ReporterUtils + { + internal static string GetRunId(CIInfo cIInfo) + { + if (cIInfo.Provider == Constants.DEFAULT) + { + return Guid.NewGuid().ToString(); + } + var concatString = $"{cIInfo.Provider}-{cIInfo.Repo}-{cIInfo.RunId}-{cIInfo.RunAttempt}"; + return CalculateSha1Hash(concatString); + } + + internal static string CalculateSha1Hash(string input) + { + using (var sha1 = SHA1.Create()) + { + var hash = sha1.ComputeHash(System.Text.Encoding.UTF8.GetBytes(input)); + return BitConverter.ToString(hash).Replace("-", string.Empty).ToLower(); + } + } + } +} From dc9a98fb4c2ba8f230e602d88746719f626d8b26 Mon Sep 17 00:00:00 2001 From: Vansh Vardhan Singh Date: Mon, 26 Aug 2024 08:53:57 +0000 Subject: [PATCH 11/32] Adressing comments --- .../README.md | 62 +++++++------------ 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md index 1a87a3369ad8..2cb6518466be 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md @@ -1,14 +1,10 @@ -# Microsoft Playwright Testing preview - +# Microsoft Playwright Testing client library for .NET Microsoft Playwright Testing is a fully managed service that uses the cloud to enable you to run Playwright tests with much higher parallelization across different operating system-browser combinations simultaneously. This means faster test runs with broader scenario coverage, which helps speed up delivery of features without sacrificing quality. The service also enables you to publish test results and related artifacts to the service and view them in the service portal enabling faster and easier troubleshooting. With Microsoft Playwright Testing service, you can release features faster and more confidently. Ready to get started? Jump into our [quickstart guide](#get-started)! - -## Useful Links +## Useful links - [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart) -- [Quickstart: Set up continuous end-to-end testing across different browsers and operating systems](https://aka.ms/mpt/ci) -- [Explore features and benefits](https://aka.ms/mpt/about) - [View Microsoft Playwright Testing service demo](https://youtu.be/GenC1jAeTZE) - [Documentation](https://aka.ms/mpt/docs) - [Pricing](https://aka.ms/mpt/pricing) @@ -17,13 +13,20 @@ Ready to get started? Jump into our [quickstart guide](#get-started)! ## Get Started Follow these steps to run your existing Playwright test suite with the service. +### Install Microsoft Playwright Testing package + +1. Run this command to install the service package + + ```dotnetcli +- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). + ### Prerequisites - An Azure account with an active subscription. If you don't have an Azure subscription, [create a free account](https://aka.ms/mpt/create-azure-subscription) before you begin. - Your Azure account must be assigned the [Owner](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) must be installed in the machine from where you are running Playwright tests. - -### Create a Workspace +- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). +#### Create a Workspace 1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account. @@ -39,16 +42,9 @@ Follow these steps to run your existing Playwright test suite with the service. > [!NOTE] > If you don't see this screen, select an existing workspace and go to the next section. - -### Install Microsoft Playwright Testing package - -1. Run this command to install the service package - - ```dotnetcli - dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit ``` -### Setup Microsoft Playwright Testing +### Set up Microsoft Playwright Testing 1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the below content @@ -62,7 +58,7 @@ Follow these steps to run your existing Playwright test suite with the service. ``` > [!NOTE] -> Make sure your project uses Microsoft.Playwright.NUnit version 1.37 or above. +> Make sure your project uses `Microsoft.Playwright.NUnit` version 1.37 or above. ### Obtain region endpoint @@ -78,13 +74,13 @@ Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is a ### Sign in to Azure -You need to sign in to Azure using Azure CLI to enable authentication via Entra ID. Run the command to sign-in +You need to sign in to Azure using Azure CLI to enable authentication via Microsoft Entra ID. Run the command to sign-in ```azurecli az login ``` -**NOTE**: If you are a part of multiple tenants, you will have to login to a particular tenant. Run `az login --tenant=' to sign in to the tenant where the workspace is created. You can find the tenant id through these [steps.](https://learn.microsoft.com/en-us/entra/fundamentals/how-to-find-tenant) +**NOTE**: If you are a part of multiple tenants, you will have to login to a particular tenant. Run `az login --tenant=' to sign in to the tenant where the workspace is created. You can find the tenant id through these [steps.](https://learn.microsoft.com/entra/fundamentals/how-to-find-tenant) ### Run the tests @@ -103,23 +99,11 @@ dotnet test --logger "ms-playwright-service" - Experiment with different number of workers to [determine the optimal configuration of your test suite](https://aka.ms/mpt/parallelism). ## Contributing - -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. - -When you submit a pull request, a CLA bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - -## Trademarks - -This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft -trademarks or logos is subject to and must follow -[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). -Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. -Any use of third-party trademarks or logos is subject to those third-party's policies. +This project welcomes contributions and suggestions. Most contributions require +you to agree to a Contributor License Agreement (CLA) declaring that you have +the right to, and actually do, grant us the rights to use your contribution. For +details, visit [cla.microsoft.com][cla]. + +This project has adopted the [Microsoft Open Source Code of Conduct][coc]. +For more information see the [Code of Conduct FAQ][coc_faq] or contact +[opencode@microsoft.com][coc_contact] with any additional questions or comments. From 733a700db22a00c8c3c864ed808a7a756a839748 Mon Sep 17 00:00:00 2001 From: Vansh Vardhan Singh Date: Mon, 26 Aug 2024 08:58:01 +0000 Subject: [PATCH 12/32] comment --- .../Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md index 2cb6518466be..588507fb1035 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md @@ -30,7 +30,7 @@ Follow these steps to run your existing Playwright test suite with the service. 1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account. -2. Create the Workspace. +2. Create the Workspace ![Create new workspace](https://github.com/microsoft/playwright-testing-service/assets/12104064/d571e86b-9d43-48ac-a2b7-63afb9bb86a8) From cc953aa50d5887ef6f552a05498a6ffbcb81ac24 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Wed, 28 Aug 2024 18:33:19 +0000 Subject: [PATCH 13/32] chore(): resolve documentation comments --- .github/CODEOWNERS | 2 +- ...loper.MicrosoftPlaywrightTesting.NUnit.sln | 6 ++++ .../CHANGELOG.md | 20 +++-------- .../README.md | 30 +++++++--------- .../samples/README.md | 8 ++--- .../Sample1_CustomisingServiceParameters.md | 28 +++++---------- ...mple2_SetDefaultAuthenticationMechanism.md | 2 +- .../Sample3_ManuallyConnectingToBrowsers.md | 2 +- ...rosoftPlaywrightTesting.NUnit.Tests.csproj | 23 ++++++++++++ .../CHANGELOG.md | 20 +++-------- .../README.md | 36 +++++++++---------- 11 files changed, 83 insertions(+), 94 deletions(-) create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.Tests.csproj diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5527508b4ad9..db0644aac916 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -733,7 +733,7 @@ # ServiceOwners: @rhurey @dargilco # PRLabel: %Playwright -/sdk/playwrighttesting/ @Sid200026 @puagarwa @vvs11 @ShreyaAnand +/sdk/playwrighttesting/ @Sid200026 @puagarwa @ShreyaAnand # ServiceLabel: %Playwright # ServiceOwners: @shreyaanand @mjmadhu diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.sln b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.sln index 9cc262f01b3b..840be72bea43 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.sln +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Developer.MicrosoftPlaywrightTesting.NUnit", "src\Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj", "{CF3C8F52-D3FD-4338-9432-58FF4BF4475E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Developer.MicrosoftPlaywrightTesting.NUnit.Tests", "tests\Azure.Developer.MicrosoftPlaywrightTesting.NUnit.Tests.csproj", "{081210F2-A9F8-4137-97F4-5D5EF238B553}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,5 +20,9 @@ Global {CF3C8F52-D3FD-4338-9432-58FF4BF4475E}.Debug|Any CPU.Build.0 = Debug|Any CPU {CF3C8F52-D3FD-4338-9432-58FF4BF4475E}.Release|Any CPU.ActiveCfg = Release|Any CPU {CF3C8F52-D3FD-4338-9432-58FF4BF4475E}.Release|Any CPU.Build.0 = Release|Any CPU + {081210F2-A9F8-4137-97F4-5D5EF238B553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {081210F2-A9F8-4137-97F4-5D5EF238B553}.Debug|Any CPU.Build.0 = Debug|Any CPU + {081210F2-A9F8-4137-97F4-5D5EF238B553}.Release|Any CPU.ActiveCfg = Release|Any CPU + {081210F2-A9F8-4137-97F4-5D5EF238B553}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md index 376422decdbb..1576c72198be 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/CHANGELOG.md @@ -1,18 +1,8 @@ -# 1.0.0-beta.1 (2024-07-31) +# Release History -## Added +## 1.0.0-beta.1 (2024-09-11) -- **Initial release of the package**: This is the first version of the Microsoft Playwright Testing service package for NUnit. It enables you to integrate your NUnit Playwright test suite with the Microsoft Playwright Testing service. -- The service package enables you to: - - Expedite your Playwright test suite by running more tests in parallel on cloud-hosted browsers. - - Improve test coverage by enabling you to test on multiple OS-browser combinations. - - Troubleshoot easily and faster by publishing test results and artifacts generated by Playwright to the service and viewing them in the service portal. +### Features Added -## Useful Links -- [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart) -- [Quickstart: Set up continuous end-to-end testing across different browsers and operating systems](https://aka.ms/mpt/ci) -- [Explore features and benefits](https://aka.ms/mpt/about) -- [View Microsoft Playwright Testing service demo](https://youtu.be/GenC1jAeTZE) -- [Documentation](https://aka.ms/mpt/docs) -- [Pricing](https://aka.ms/mpt/pricing) -- [Share feedback](https://aka.ms/mpt/feedback) +- Added authentication using Microsoft Entra ID for the service. +- Added reporting capabilities for the service. You can now publish the reports and artifacts generated by Playwright OSS to the service. \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md index 588507fb1035..31d4341a2bf7 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md @@ -1,4 +1,5 @@ # Microsoft Playwright Testing client library for .NET + Microsoft Playwright Testing is a fully managed service that uses the cloud to enable you to run Playwright tests with much higher parallelization across different operating system-browser combinations simultaneously. This means faster test runs with broader scenario coverage, which helps speed up delivery of features without sacrificing quality. The service also enables you to publish test results and related artifacts to the service and view them in the service portal enabling faster and easier troubleshooting. With Microsoft Playwright Testing service, you can release features faster and more confidently. Ready to get started? Jump into our [quickstart guide](#get-started)! @@ -10,22 +11,21 @@ Ready to get started? Jump into our [quickstart guide](#get-started)! - [Pricing](https://aka.ms/mpt/pricing) - [Share feedback](https://aka.ms/mpt/feedback) -## Get Started -Follow these steps to run your existing Playwright test suite with the service. +## Getting started -### Install Microsoft Playwright Testing package +### Install the package -1. Run this command to install the service package +Install the client library for .NET with [NuGet](https://www.nuget.org/): - ```dotnetcli -- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). +```dotnetcli +dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit --prerelease +``` ### Prerequisites -- An Azure account with an active subscription. If you don't have an Azure subscription, [create a free account](https://aka.ms/mpt/create-azure-subscription) before you begin. -- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). -- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) must be installed in the machine from where you are running Playwright tests. +- An [Azure subscription](https://azure.microsoft.com/free/dotnet/) - Your Azure account must be assigned the [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). + #### Create a Workspace 1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account. @@ -72,15 +72,9 @@ Follow these steps to run your existing Playwright test suite with the service. Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is available in your environment. -### Sign in to Azure +### Authenticate the client -You need to sign in to Azure using Azure CLI to enable authentication via Microsoft Entra ID. Run the command to sign-in - -```azurecli -az login -``` - -**NOTE**: If you are a part of multiple tenants, you will have to login to a particular tenant. Run `az login --tenant=' to sign in to the tenant where the workspace is created. You can find the tenant id through these [steps.](https://learn.microsoft.com/entra/fundamentals/how-to-find-tenant) +To learn more about options for Microsoft Entra Id authentication, refer to [Azure.Identity credentials](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/identity/Azure.Identity#credentials). You can also refer to [our samples] on how to configurate different Azure Identity credentials. ### Run the tests @@ -107,3 +101,5 @@ details, visit [cla.microsoft.com][cla]. This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For more information see the [Code of Conduct FAQ][coc_faq] or contact [opencode@microsoft.com][coc_contact] with any additional questions or comments. + +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.png) \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md index 9499d8d9e738..2ceca6fb7d7e 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md @@ -4,13 +4,13 @@ languages: - csharp products: - azure -- microsoft-playwright-testing +- playwright-testing name: Azure.Developer.MicrosoftPlaywrightTesting.NUnit samples for .NET description: Samples for the Azure.Developer.MicrosoftPlaywrightTesting.NUnit client library --- # Azure.Developer.MicrosoftPlaywrightTesting.NUnit samples for .NET -- [Customising service parameters](./Sample1_CustomisingServiceParameters.md) -- [Set default authentication mechanism](./Sample2_SetDefaultAuthenticationMechanism.md) -- [Manually connecting to browsers](./Sample3_ManuallyConnectingToBrowsers.md) \ No newline at end of file +- [Customising service parameters] +- [Set default authentication mechanism] +- [Manually connecting to browsers] \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md index 165134a51269..45ff0e2fde9e 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md @@ -4,9 +4,9 @@ Follow the steps listed in this [README](../../README.md) to integrate your exis This guide explains the different options available to you in the Azure.Developer.MicrosoftPlaywrightTesting.NUnit package and how to use them. -### Using runsettings file +### Using .runsettings file -1. Create a `.runsettings` file in the root directory +1. Create a `.runsettings` file in the root directory: ```xml @@ -34,31 +34,19 @@ This guide explains the different options available to you in the Azure.Develope > [!NOTE] > You can also modify the runid by setting the environment variable `PLAYWRIGHT_SERVICE_RUN_ID`. -2. Run tests using the above runsettings file +2. Run tests using the above `.runsettings` file: ```dotnetcli dotnet test --settings .runsettings ``` -#### Known Issue - Minimal support for Azure Credentials +#### Known issue: Minimal support for Azure Identity library credentials -This issue only impacts the reporting feature. Currently, the service provides minimal support for the following [Azure Credential types](https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme?view=azure-dotnet) - -- EnvironmentCredential -- WorkloadIdentityCredential -- ManagedIdentityCredential -- SharedTokenCacheCredential -- VisualStudioCredential -- VisualStudioCodeCredential -- AzureCliCredential -- AzurePowerShellCredential -- AzureDeveloperCliCredential -- InteractiveBrowserCredential -- DefaultAzureCredential (Default) +This issue only impacts the reporting feature. Currently, the service provides minimal support for the following [Azure Credential types.](https://learn.microsoft.com/dotnet/api/overview/azure/identity-readme?view=azure-dotnet#credential-classes) Along with this, we also support passing a Managed Identity ClientId to be used along with `DefaultAzureCredential` and `ManagedIdentityCredential`. -If you only want to use cloud hosted browsers along with your tests, you can disable the reporting feature by removing the logger from the runsettings file and then modify the `PlaywrightServiceSetup.cs` file as per the following. +If you only want to use cloud-hosted browsers along with your tests, you can disable the reporting feature by removing the logger from the runsettings file and then modify the `PlaywrightServiceSetup.cs` file as per the following. ```c# using Azure.Core; @@ -95,7 +83,7 @@ public class PlaywrightServiceSetup : PlaywrightServiceNUnit 4. **`DefaultAuth`** - **Description**: This setting allows you to specify the default authentication mechanism to be used for sending requests to the service. - **Available Options**: - - `ServiceAuth.ENTRA` for Entra ID authentication. + - `ServiceAuth.ENTRA` for Microsoft Entra ID authentication. - `ServiceAuth.TOKEN` for MPT Access Token authentication. - **Default Value**: `ServiceAuth.ENTRA` @@ -120,7 +108,7 @@ public class PlaywrightServiceSetup : PlaywrightServiceNUnit - **Default Value**: `AzureTokenCredentialType.DefaultAzureCredential` 7. **`ManagedIdentityClientId`** - - **Description**: This setting allows you to specify the managed identity client id to be used for entra id authentication. + - **Description**: This setting allows you to specify the managed identity client id to be used for Microsoft Entra Id authentication. 8. **`EnableGitHubSummary`**: - **Description**: This setting allows you to configure the Microsoft Playwright Testing service reporter. You can choose whether to include the test run summary in the GitHub summary when running in GitHub Actions. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md index 9c029b85392b..fceb37b6a562 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md @@ -75,7 +75,7 @@ Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is a ### Sign in to Azure -You need to sign in to Azure using Azure CLI to enable authentication via Entra ID. Run the command to sign-in +You need to sign in to Azure using Azure CLI to enable authentication via Microsoft Entra ID. Run the command to sign-in ```azurecli az login diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md index 38f580247d4a..ef7c3e43dfe9 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md @@ -77,7 +77,7 @@ Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is a ### Sign in to Azure -You need to sign in to Azure using Azure CLI to enable authentication via Entra ID. Run the command to sign-in +You need to sign in to Azure using Azure CLI to enable authentication via Microsoft Entra ID. Run the command to sign-in ```azurecli az login diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.Tests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.Tests.csproj new file mode 100644 index 000000000000..876d71881eb3 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.Tests.csproj @@ -0,0 +1,23 @@ + + + + enable + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md index 736ac995d2b7..1576c72198be 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md @@ -1,18 +1,8 @@ -# 1.0.0-beta.1 (2024-07-31) +# Release History -## Added +## 1.0.0-beta.1 (2024-09-11) -- **Initial release of the package**: This is the first version of the Microsoft Playwright Testing service package. It enables you to integrate your Playwright test suite with the Microsoft Playwright Testing service. -- The service package enables you to: - - Expedite your Playwright test suite by running more tests in parallel on cloud-hosted browsers. - - Improve test coverage by enabling you to test on multiple OS-browser combinations. - - Troubleshoot easily and faster by publishing test results and artifacts generated by Playwright to the service and viewing them in the service portal. +### Features Added -## Useful Links -- [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart) -- [Quickstart: Set up continuous end-to-end testing across different browsers and operating systems](https://aka.ms/mpt/ci) -- [Explore features and benefits](https://aka.ms/mpt/about) -- [View Microsoft Playwright Testing service demo](https://youtu.be/GenC1jAeTZE) -- [Documentation](https://aka.ms/mpt/docs) -- [Pricing](https://aka.ms/mpt/pricing) -- [Share feedback](https://aka.ms/mpt/feedback) +- Added authentication using Microsoft Entra ID for the service. +- Added reporting capabilities for the service. You can now publish the reports and artifacts generated by Playwright OSS to the service. \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md index 3b579c71f94b..ebf675a33a1e 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md @@ -6,13 +6,18 @@ Microsoft Playwright Testing is a fully managed service that uses the cloud to e ### Install the package -Install the client library from [NuGet](https://www.nuget.org/): +Install the client library for .NET with [NuGet](https://www.nuget.org/): ```dotnetcli -dotnet add package Azure.Developer.MicrosoftPlaywrightTesting +dotnet add package Azure.Developer.MicrosoftPlaywrightTesting --prerelease ``` -## Useful Links +### Prerequisites + +- An [Azure subscription](https://azure.microsoft.com/free/dotnet/) +- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). + +## Useful links - [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart) - [Quickstart: Set up continuous end-to-end testing across different browsers and operating systems](https://aka.ms/mpt/ci) - [Explore features and benefits](https://aka.ms/mpt/about) @@ -31,22 +36,13 @@ dotnet add package Azure.Developer.MicrosoftPlaywrightTesting ## Contributing -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. - -When you submit a pull request, a CLA bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +This project welcomes contributions and suggestions. Most contributions require +you to agree to a Contributor License Agreement (CLA) declaring that you have +the right to, and actually do, grant us the rights to use your contribution. For +details, visit [cla.microsoft.com][cla]. -## Trademarks +This project has adopted the [Microsoft Open Source Code of Conduct][coc]. +For more information see the [Code of Conduct FAQ][coc_faq] or contact +[opencode@microsoft.com][coc_contact] with any additional questions or comments. -This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft -trademarks or logos is subject to and must follow -[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). -Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. -Any use of third-party trademarks or logos is subject to those third-party's policies. +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.png) \ No newline at end of file From 4123d019626e1d80b892dc0d545c12ccf09c3412 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Wed, 28 Aug 2024 19:14:08 +0000 Subject: [PATCH 14/32] docs(): import c# code snippets from .cs files --- .../README.md | 16 ++-- .../samples/README.md | 3 +- .../Sample1_CustomisingServiceParameters.md | 59 ++++++------ ...mple2_SetDefaultAuthenticationMechanism.md | 73 ++++---------- .../Sample3_ManuallyConnectingToBrowsers.md | 94 ------------------- .../tests/samples/README.md | 3 + .../Sample1_CustomisingServiceParameters.cs | 26 +++++ ...mple2_SetDefaultAuthenticationMechanism.cs | 15 +++ 8 files changed, 101 insertions(+), 188 deletions(-) delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/README.md create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/Sample1_CustomisingServiceParameters.cs create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/Sample2_SetDefaultAuthenticationMechanism.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md index 31d4341a2bf7..40983e42a3a5 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md @@ -2,7 +2,7 @@ Microsoft Playwright Testing is a fully managed service that uses the cloud to enable you to run Playwright tests with much higher parallelization across different operating system-browser combinations simultaneously. This means faster test runs with broader scenario coverage, which helps speed up delivery of features without sacrificing quality. The service also enables you to publish test results and related artifacts to the service and view them in the service portal enabling faster and easier troubleshooting. With Microsoft Playwright Testing service, you can release features faster and more confidently. -Ready to get started? Jump into our [quickstart guide](#get-started)! +Ready to get started? Jump into our [quickstart guide]! ## Useful links - [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart) @@ -46,16 +46,16 @@ dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit --prerelease ### Set up Microsoft Playwright Testing -1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the below content +Create a file `PlaywrightServiceSetup.cs` in the root directory with the below content - ```c# - using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; +```C# Snippet:Sample2_SetDefaultAuthenticationMechanism +using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; - namespace PlaywrightTests; // Remember to change this as per your project namespace +namespace PlaywrightATests; // Remember to change this as per your project namespace - [SetUpFixture] - public class PlaywrightServiceSetup : PlaywrightServiceNUnit; - ``` +[SetUpFixture] +public class PlaywrightServiceSetup : PlaywrightServiceNUnit {}; +``` > [!NOTE] > Make sure your project uses `Microsoft.Playwright.NUnit` version 1.37 or above. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md index 2ceca6fb7d7e..218796676686 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/README.md @@ -12,5 +12,4 @@ description: Samples for the Azure.Developer.MicrosoftPlaywrightTesting.NUnit cl # Azure.Developer.MicrosoftPlaywrightTesting.NUnit samples for .NET - [Customising service parameters] -- [Set default authentication mechanism] -- [Manually connecting to browsers] \ No newline at end of file +- [Set default authentication mechanism] \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md index 45ff0e2fde9e..0d5d090fd0a9 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md @@ -1,6 +1,6 @@ ## Learn about different available service parameters and how to use them -Follow the steps listed in this [README](../../README.md) to integrate your existing Playwright test suite with the Microsoft Playwright Testing service. +Follow the steps listed in this [README] to integrate your existing Playwright test suite with the Microsoft Playwright Testing service. This guide explains the different options available to you in the Azure.Developer.MicrosoftPlaywrightTesting.NUnit package and how to use them. @@ -8,37 +8,37 @@ This guide explains the different options available to you in the Azure.Develope 1. Create a `.runsettings` file in the root directory: - ```xml - - - - - - - - - - - - - - - - - - - - - ``` +```xml + + + + + + + + + + + + + + + + + + + + +``` > [!NOTE] > You can also modify the runid by setting the environment variable `PLAYWRIGHT_SERVICE_RUN_ID`. 2. Run tests using the above `.runsettings` file: - ```dotnetcli - dotnet test --settings .runsettings - ``` +```dotnetcli +dotnet test --settings .runsettings +``` #### Known issue: Minimal support for Azure Identity library credentials @@ -48,7 +48,7 @@ Along with this, we also support passing a Managed Identity ClientId to be used If you only want to use cloud-hosted browsers along with your tests, you can disable the reporting feature by removing the logger from the runsettings file and then modify the `PlaywrightServiceSetup.cs` file as per the following. -```c# +```C# Snippet:Sample1_CustomisingServiceParameters using Azure.Core; using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; using Azure.Identity; @@ -60,9 +60,8 @@ public class PlaywrightServiceSetup : PlaywrightServiceNUnit { public static readonly TokenCredential managedIdentityCredential = new ManagedIdentityCredential(); - public PlaywrightServiceSetup() : base(managedIdentityCredential) - { } -}; + public PlaywrightServiceSetup() : base(managedIdentityCredential) {} +} ``` ## Settings diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md index fceb37b6a562..85cc028890de 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md @@ -1,62 +1,33 @@ # How to authenticate to Microsoft Playwright Testing service using service access token. -This guide will walk you through the steps to integrate your Playwright project where you are launching browsers from within the tests with the service. - -### Prerequisites - -- An Azure account with an active subscription. If you don't have an Azure subscription, [create a free account](https://aka.ms/mpt/create-azure-subscription) before you begin. -- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). -- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) must be installed in the machine from where you are running Playwright tests. - -### Create a Workspace - -1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account. - -2. Create the Workspace. - - ![Create new workspace](https://github.com/microsoft/playwright-testing-service/assets/12104064/d571e86b-9d43-48ac-a2b7-63afb9bb86a8) - - |Field |Description | - |---------|---------| - |**Workspace Name** | A unique name to identify your workspace.
The name can't contain special characters or whitespace. | - |**Azure Subscription** | Select an Azure subscription where you want to create the workspace. | - |**Region** | This is where test run data will be stored for your workspace. | - - > [!NOTE] - > If you don't see this screen, select an existing workspace and go to the next section. +Follow the steps listed in this [README] to integrate your existing Playwright test suite with the Microsoft Playwright Testing service. -### Install Microsoft Playwright Testing package - -1. Run this command to install the service package - - ```dotnetcli - dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit - ``` +This guide will walk you through the steps to integrate your Playwright project where you are launching browsers from within the tests with the service. ### Setup Microsoft Playwright Testing 1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the following - ```c# - using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; +```C# Snippet:Sample2_SetDefaultAuthenticationMechanism +using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; - namespace PlaywrightTests; // Remember to change this as per your project namespace +namespace PlaywrightATests; // Remember to change this as per your project namespace - [SetUpFixture] - public class PlaywrightServiceSetup : PlaywrightServiceNUnit; - ``` +[SetUpFixture] +public class PlaywrightServiceSetup : PlaywrightServiceNUnit {}; +``` 2. Create a .runsettings file to modify default authentication mechanism. - ```xml - - - - - - - - ``` +```xml + + + + + + + +``` > [!NOTE] > Make sure your project uses Microsoft.Playwright.NUnit version 1.37 or above. @@ -73,15 +44,9 @@ This guide will walk you through the steps to integrate your Playwright project Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is available in your environment. -### Sign in to Azure - -You need to sign in to Azure using Azure CLI to enable authentication via Microsoft Entra ID. Run the command to sign-in - -```azurecli -az login -``` +### Authenticate the client -**NOTE**: If you are a part of multiple tenants, you will have to login to a particular tenant. Run `az login --tenant=' to sign in to the tenant where the workspace is created. You can find the tenant id through these [steps.](https://learn.microsoft.com/en-us/entra/fundamentals/how-to-find-tenant) +To learn more about options for Microsoft Entra Id authentication, refer to [Azure.Identity credentials](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/identity/Azure.Identity#credentials). You can also refer to [our samples] on how to configurate different Azure Identity credentials. ### Run the tests diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md deleted file mode 100644 index ef7c3e43dfe9..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample3_ManuallyConnectingToBrowsers.md +++ /dev/null @@ -1,94 +0,0 @@ -# How to integrate your test suite with Microsoft Playwright Testing service if you are manually launching browsers in tests - -This guide will walk you through the steps to integrate your Playwright project, where you are launching browsers from within the tests, with the service. - -### Prerequisites - -- An Azure account with an active subscription. If you don't have an Azure subscription, [create a free account](https://aka.ms/mpt/create-azure-subscription) before you begin. -- Your Azure account must be assigned the [Owner](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). -- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) must be installed in the machine from where you are running Playwright tests. - -### Create a Workspace - -1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account. - -2. Create the Workspace. - - ![Create new workspace](https://github.com/microsoft/playwright-testing-service/assets/12104064/d571e86b-9d43-48ac-a2b7-63afb9bb86a8) - - |Field |Description | - |---------|---------| - |**Workspace Name** | A unique name to identify your workspace.
The name can't contain special characters or whitespace. | - |**Azure Subscription** | Select an Azure subscription where you want to create the workspace. | - |**Region** | This is where test run data will be stored for your workspace. | - - > [!NOTE] - > If you don't see this screen, select an existing workspace and go to the next section. - -### Install Microsoft Playwright Testing package - -1. Run this command to install the service package - - ```dotnetcli - dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit - ``` - -### Setup Microsoft Playwright Testing - -1. Create a file `PlaywrightServiceSetup.cs` in the root directory with the following - - ```c# - using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; - - namespace PlaywrightTests; // Remember to change this as per your project namespace - - [SetUpFixture] - public class PlaywrightServiceSetup : PlaywrightServiceNUnit; - ``` - -> [!NOTE] -> Make sure your project uses Microsoft.Playwright.NUnit version 1.37 or above. - -### Configure browsers to be launched on the service - -In the test project, wherever there is a manual browser launch or manual connect to a remote browser, replace it with the below code snippet - -```c# -// Old code -//Browser = await _playwright.Chromium.LaunchAsync(); - -// New code -var playwrightService = new PlaywrightService(); -var connectOptions = await playwrightService.GetConnectOptionsAsync(os: ServiceOs.LINUX, runId: $"Manual Launch - {DateTime.UtcNow}"); -_browser = await _playwright.Chromium.ConnectAsync(connectOptions.WsEndpoint!, connectOptions.Options!); -``` - -### Obtain region endpoint - -1. In the [Playwright portal](https://aka.ms/mpt/portal), copy the command under **Add region endpoint in your set up**. - - ![Set workspace endpoint](https://github.com/microsoft/playwright-testing-service/assets/12104064/d81ca629-2b23-4d34-8b70-67b6f7061a83) - - The endpoint URL corresponds to the workspace region. You might see a different endpoint URL in the Playwright portal, depending on the region you selected when creating the workspace. - -### Set up environment - -Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is available in your environment. - -### Sign in to Azure - -You need to sign in to Azure using Azure CLI to enable authentication via Microsoft Entra ID. Run the command to sign-in - -```azurecli -az login -``` - -**NOTE**: If you are a part of multiple tenants, you will have to login to a particular tenant. Run `az login --tenant=' to sign in to the tenant where the workspace is created. You can find the tenant id through these [steps.](https://learn.microsoft.com/en-us/entra/fundamentals/how-to-find-tenant) - -### Run the tests - -Run Playwright tests against browsers managed by the service using the configuration you created above. - -```dotnetcli -dotnet test --logger "ms-playwright-service" -``` \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/README.md new file mode 100644 index 000000000000..ecd5c103e8fe --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/README.md @@ -0,0 +1,3 @@ +Source files in this directory are written as tests from which samples are extracted. +They are not intended to be viewed directly and help ensure our samples compile and work correctly. +See our [list of samples](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples) for more explanation about how to use this client library. \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/Sample1_CustomisingServiceParameters.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/Sample1_CustomisingServiceParameters.cs new file mode 100644 index 000000000000..aaaf15ee8fe4 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/Sample1_CustomisingServiceParameters.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#region Snippet:Sample1_CustomisingServiceParameters +using Azure.Core; +using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; +using Azure.Identity; + +namespace PlaywrightTests; + +[SetUpFixture] +#if SNIPPET +public class PlaywrightServiceSetup : PlaywrightServiceNUnit +#else +public class Sample2ServiceSetup : PlaywrightServiceNUnit +#endif +{ + public static readonly TokenCredential managedIdentityCredential = new ManagedIdentityCredential(); + +#if SNIPPET + public PlaywrightServiceSetup() : base(managedIdentityCredential) {} +#else + public Sample2ServiceSetup() : base(managedIdentityCredential) {} +#endif +} +#endregion \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/Sample2_SetDefaultAuthenticationMechanism.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/Sample2_SetDefaultAuthenticationMechanism.cs new file mode 100644 index 000000000000..6cf327b7d468 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/tests/samples/Sample2_SetDefaultAuthenticationMechanism.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#region Snippet:Sample2_SetDefaultAuthenticationMechanism +using Azure.Developer.MicrosoftPlaywrightTesting.NUnit; + +namespace PlaywrightATests; // Remember to change this as per your project namespace + +[SetUpFixture] +#if SNIPPET +public class PlaywrightServiceSetup : PlaywrightServiceNUnit {}; +#else +public class Sample2ServiceSetup : PlaywrightServiceNUnit { }; +#endif +#endregion \ No newline at end of file From d7fe0419b4e654aa5d9386e8904f65351a086b7e Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Sun, 1 Sep 2024 18:21:46 +0000 Subject: [PATCH 15/32] refactor(): update CODEOWNERS with latest labels --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index db0644aac916..c37fc65b5c5e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -732,10 +732,10 @@ # ServiceLabel: %Image Analysis # ServiceOwners: @rhurey @dargilco -# PRLabel: %Playwright +# PRLabel: %Microsoft Playwright Testing /sdk/playwrighttesting/ @Sid200026 @puagarwa @ShreyaAnand -# ServiceLabel: %Playwright +# ServiceLabel: %Microsoft Playwright Testing # ServiceOwners: @shreyaanand @mjmadhu # ServiceLabel: %Policy From f2ce9a6b6dc57ab815ccb87a61c12e96ea06568d Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 2 Sep 2024 00:46:25 +0530 Subject: [PATCH 16/32] chore(): add git commit based display name --- ...er.MicrosoftPlaywrightTesting.NUnit.csproj | 2 +- ...eveloper.MicrosoftPlaywrightTesting.csproj | 2 +- .../src/PlaywrightService.cs | 1 - .../src/TestLogger/PlaywrightReporter.cs | 13 +++- .../src/TestLogger/Utility/ReporterUtils.cs | 67 +++++++++++++++++++ 5 files changed, 79 insertions(+), 6 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj index a8145ca5fbd6..3e8c4a1b7523 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj @@ -5,7 +5,7 @@ Package to integrate your Playwright test suite with Microsoft Playwright Testing service - 1.0.0-beta.1 + 1.0.0-beta.1 true $(RequiredTargetFrameworks) enable diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj index d5d956625bf2..2abb6384997f 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj @@ -10,7 +10,7 @@ Package to integrate your Playwright test suite with Microsoft Playwright Testing service - 1.0.0-beta.1 + 1.0.0-beta.1 true $(RequiredTargetFrameworks) enable diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs index fbb31e90b3cc..5e4ce0b28f71 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -7,7 +7,6 @@ using Microsoft.IdentityModel.JsonWebTokens; using System; using System.Collections.Generic; -using System.Globalization; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index 9e254a699a6c..73b43037be0d 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -21,6 +21,7 @@ using PlaywrightConstants = Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility.Constants; using Azure.Core; using Azure.Core.Serialization; +using Azure.Core.Pipeline; namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; @@ -113,7 +114,8 @@ internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) var startTime = TestRunStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"); LogMessage("Test Run start time: " + startTime); var corelationId = Guid.NewGuid().ToString(); - var runName = Guid.NewGuid().ToString(); // TODO discuss approach + var gitBasedRunName = ReporterUtils.GetRunName(CiInfoProvider.GetCIInfo()); + var runName = string.IsNullOrEmpty(gitBasedRunName) ? Guid.NewGuid().ToString() : gitBasedRunName; var run = new TestRunDtoV2 { TestRunId = RunId!, @@ -560,8 +562,13 @@ private static string FetchFileName(string fullFilePath) private static string GetCurrentOS() { - // we could return simplified name like "windows", "linux", "macos" - return Environment.OSVersion.Platform.ToString(); + PlatformID platform = Environment.OSVersion.Platform; + if (platform == PlatformID.Unix) + return "Linux"; + else if (platform == PlatformID.MacOSX) + return "MacOS"; + else + return "Windows"; } private void LogMessage(string message) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs index b1347b2f79f0..c25c8d466eb9 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs @@ -2,7 +2,10 @@ // Licensed under the MIT License. using System; +using System.Diagnostics; using System.Security.Cryptography; +using System.Threading.Tasks; +using Azure.Core.Pipeline; using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Model; namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility @@ -27,5 +30,69 @@ internal static string CalculateSha1Hash(string input) return BitConverter.ToString(hash).Replace("-", string.Empty).ToLower(); } } + + internal static string GetRunName(CIInfo ciInfo) + { + string GIT_VERSION_COMMAND = "git --version"; + string GIT_REV_PARSE = "git rev-parse --is-inside-work-tree"; + string GIT_COMMIT_MESSAGE_COMMAND = "git log -1 --pretty=%B"; + + if (ciInfo.Provider == Constants.GITHUB_ACTIONS && + Environment.GetEnvironmentVariable("GITHUB_EVENT_NAME") == "pull_request") + { + var prNumber = Environment.GetEnvironmentVariable("GITHUB_REF_NAME")?.Split('/')[0]; + var repo = Environment.GetEnvironmentVariable("GITHUB_REPOSITORY"); + var prLink = $"{repo}/pull/{prNumber}"; + return $"PR# {prNumber} on Repo: {repo} ({prLink})"; + } + + try + { + string gitVersion = RunCommandAsync(GIT_VERSION_COMMAND).EnsureCompleted(); + if (string.IsNullOrEmpty(gitVersion)) + { + throw new Exception("Git is not installed on the machine"); + } + + string isInsideWorkTree = RunCommandAsync(GIT_REV_PARSE).EnsureCompleted(); + if (isInsideWorkTree.Trim() != "true") + { + throw new Exception("Not inside a git repository"); + } + + string gitCommitMessage = RunCommandAsync(GIT_COMMIT_MESSAGE_COMMAND).EnsureCompleted(); + return gitCommitMessage; + } + catch (Exception) + { + return string.Empty; + } + } + + internal static async Task RunCommandAsync(string command, bool async = false) + { + var processInfo = new ProcessStartInfo("cmd", $"/c {command}") + { + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + using (var process = new Process { StartInfo = processInfo }) + { + process.Start(); + string result; + if (async) + { + result = await process.StandardOutput.ReadToEndAsync().ConfigureAwait(false); + } + else + { + result = process.StandardOutput.ReadToEnd(); + } + process.WaitForExit(); + return result; + } + } } } From d90831010ef0d568d0055fc0cd3e71f39f87c2aa Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 2 Sep 2024 02:43:47 +0530 Subject: [PATCH 17/32] feat(): scalable run error handling --- ...er.MicrosoftPlaywrightTesting.NUnit.csproj | 1 + ...eveloper.MicrosoftPlaywrightTesting.csproj | 1 + .../src/Constants.cs | 5 + .../src/TestLogger/PlaywrightReporter.cs | 162 ++++++++++++------ .../src/TestLogger/Utility/Constants.cs | 82 +++++++++ 5 files changed, 201 insertions(+), 50 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj index 3e8c4a1b7523..f6d2849191fc 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj @@ -6,6 +6,7 @@ service 1.0.0-beta.1 + 1.0.0-beta.1 true $(RequiredTargetFrameworks) enable diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj index 2abb6384997f..81ff3d628bfb 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj @@ -11,6 +11,7 @@ service 1.0.0-beta.1 + 1.0.0-beta.1 true $(RequiredTargetFrameworks) enable diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs index 131b91add6a7..6baddbab464a 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs @@ -171,6 +171,11 @@ public class RunSettingKey /// Enable GitHub summary setting key. /// public static readonly string ENABLE_GITHUB_SUMMARY = "EnableGitHubSummary"; + + /// + /// Enable Result publish. + /// + public static readonly string ENABLE_RESULT_PUBLISH = "EnableResultPublish"; } internal class Constants diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index 73b43037be0d..2114328f4992 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -21,7 +21,6 @@ using PlaywrightConstants = Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility.Constants; using Azure.Core; using Azure.Core.Serialization; -using Azure.Core.Pipeline; namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; @@ -73,12 +72,15 @@ internal class PlaywrightReporter : ITestLoggerWithParameters internal TestRunShardDto? TestRunShard { get; set; } internal bool EnableGithubSummary { get; set; } = true; + internal bool EnableResultPublish { get; set; } = true; internal List TestResults = new(); internal ConcurrentDictionary RawTestResultsMap = new(); internal PlaywrightService? playwrightService; + private List informationalMessages = new(); + private List processedErrorMessageKeys = new(); public void Initialize(TestLoggerEvents events, Dictionary parameters) { @@ -105,6 +107,10 @@ internal void TestRunStartHandler(object? sender, TestRunStartEventArgs e) { InitializePlaywrightReporter(e.TestRunCriteria.TestRunSettings!); LogMessage("Test Run start Handler"); + if (!EnableResultPublish) + { + return; + } if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null) { LogErrorMessage("Test Run setup issue exiting handler"); @@ -234,12 +240,16 @@ internal void TestMessageHandler(object? sender, TestRunMessageEventArgs e) internal void TestResultHandler(object? sender, TestResultEventArgs e) { LogMessage("Test Result Handler"); + TestResults? testResult = GetTestCaseResultData(e.Result); + if (!EnableResultPublish) + { + return; + } if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null) { LogErrorMessage("Test Run setup issue exiting handler"); return; } - TestResults? testResult = GetTestCaseResultData(e.Result); // Set various counts (passed tests, failed tests, total tests) if (testResult != null) { @@ -266,9 +276,16 @@ internal void TestResultHandler(object? sender, TestResultEventArgs e) internal void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e) { LogMessage("Test Run End Handler"); + if (!EnableResultPublish) + { + UpdateTestRun(e); // will not publish results, but will print informational messages + return; + } if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null || TestRun == null) { LogErrorMessage("Test Run setup issue exiting handler"); + EnableResultPublish = false; + UpdateTestRun(e); // will not publish results, but will print informational messages return; } // Upload TestResults @@ -327,57 +344,73 @@ internal void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e) private bool UpdateTestRun(TestRunCompleteEventArgs e) { - if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null || TestRun == null || TestRunShard == null) - return false; - DateTime testRunStartedOn = DateTime.MinValue; - DateTime testRunEndedOn = DateTime.UtcNow; - long durationInMs = 0; - - var result = FailedTestCount > 0 ? "failed" : "passed"; - - if (e.ElapsedTimeInRunningTests != null) - { - testRunEndedOn = TestRunStartTime.Add(e.ElapsedTimeInRunningTests); - durationInMs = (long)e.ElapsedTimeInRunningTests.TotalMilliseconds; - } - - // Update Shard End - if (TestRunShard.Summary == null) - TestRunShard.Summary = new TestRunShardSummary(); - TestRunShard.Summary.Status = "CLIENT_COMPLETE"; - TestRunShard.Summary.StartTime = TestRunStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"); - TestRunShard.Summary.EndTime = testRunEndedOn.ToString("yyyy-MM-ddTHH:mm:ssZ"); - TestRunShard.Summary.TotalTime = durationInMs; - TestRunShard.Summary.UploadMetadata = new UploadMetadata() { NumTestResults = TotalTestCount, NumTotalAttachments = 0, SizeTotalAttachments = 0 }; - LogMessage("duration:" + durationInMs); - LogMessage("StartTime:" + TestRunShard.Summary.StartTime); - LogMessage("EndTime:" + TestRunShard.Summary.EndTime); - TestRunShard.ResultsSummary = new TestRunResultsSummary - { - NumTotalTests = TotalTestCount, - NumPassedTests = PassedTestCount, - NumFailedTests = FailedTestCount, - NumSkippedTests = SkippedTestCount, - NumFlakyTests = 0, // TODO: Implement flaky tests - Status = result - }; - TestRunShard.UploadCompleted = "true"; - var token = "Bearer " + AccessToken; - var corelationId = Guid.NewGuid().ToString(); - try + if (EnableResultPublish) { - _reportingTestRunsClient.PatchTestRunShardInfo(WorkspaceId, RunId, "1", RequestContent.Create(TestRunShard), "application/json", token, corelationId); + if (!IsInitialized || _reportingTestResultsClient == null || _reportingTestRunsClient == null || TestRun == null || TestRunShard == null) + { + // no-op + } + else + { + DateTime testRunStartedOn = DateTime.MinValue; + DateTime testRunEndedOn = DateTime.UtcNow; + long durationInMs = 0; + + var result = FailedTestCount > 0 ? "failed" : "passed"; + + if (e.ElapsedTimeInRunningTests != null) + { + testRunEndedOn = TestRunStartTime.Add(e.ElapsedTimeInRunningTests); + durationInMs = (long)e.ElapsedTimeInRunningTests.TotalMilliseconds; + } + + // Update Shard End + if (TestRunShard.Summary == null) + TestRunShard.Summary = new TestRunShardSummary(); + TestRunShard.Summary.Status = "CLIENT_COMPLETE"; + TestRunShard.Summary.StartTime = TestRunStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ"); + TestRunShard.Summary.EndTime = testRunEndedOn.ToString("yyyy-MM-ddTHH:mm:ssZ"); + TestRunShard.Summary.TotalTime = durationInMs; + TestRunShard.Summary.UploadMetadata = new UploadMetadata() { NumTestResults = TotalTestCount, NumTotalAttachments = 0, SizeTotalAttachments = 0 }; + LogMessage("duration:" + durationInMs); + LogMessage("StartTime:" + TestRunShard.Summary.StartTime); + LogMessage("EndTime:" + TestRunShard.Summary.EndTime); + TestRunShard.ResultsSummary = new TestRunResultsSummary + { + NumTotalTests = TotalTestCount, + NumPassedTests = PassedTestCount, + NumFailedTests = FailedTestCount, + NumSkippedTests = SkippedTestCount, + NumFlakyTests = 0, // TODO: Implement flaky tests + Status = result + }; + TestRunShard.UploadCompleted = "true"; + var token = "Bearer " + AccessToken; + var corelationId = Guid.NewGuid().ToString(); + try + { + _reportingTestRunsClient.PatchTestRunShardInfo(WorkspaceId, RunId, "1", RequestContent.Create(TestRunShard), "application/json", token, corelationId); + } + catch (Exception ex) + { + LogErrorMessage("Test Run shard failed: " + ex.ToString()); + throw; + } + + LogMessage("TestRun Shard updated"); + playwrightService?.Cleanup(); + Console.WriteLine("Visit MPT Portal for Debugging: " + Uri.EscapeUriString(PortalUrl!)); + if (EnableGithubSummary) + GenerateMarkdownSummary(); + } } - catch (Exception ex) + if (informationalMessages.Count > 0) + Console.WriteLine(); + int index = 1; + foreach (string message in informationalMessages) { - LogErrorMessage("Test Run shard failed: " + ex.ToString()); - throw; + Console.WriteLine($"{index}) {message}"); } - - LogMessage("TestRun Shard updated"); - playwrightService?.Cleanup(); - Console.WriteLine("Visit MPT Portal for Debugging: " + Uri.EscapeUriString(PortalUrl!)); - if (EnableGithubSummary) GenerateMarkdownSummary(); return true; } @@ -447,10 +480,12 @@ private TestResults GetTestCaseResultData(TestResult testResultSource) if (!string.IsNullOrEmpty(testResultSource.ErrorMessage)) { + ProcessTestResultMessage(testResultSource.ErrorMessage); // TODO send it in blob } if (!string.IsNullOrEmpty(testResultSource.ErrorStackTrace)) { + ProcessTestResultMessage(testResultSource.ErrorStackTrace); // TODO send it in blob } @@ -458,6 +493,24 @@ private TestResults GetTestCaseResultData(TestResult testResultSource) return testCaseResultData; } + private void ProcessTestResultMessage(string? message) + { + if (string.IsNullOrEmpty(message)) + { + return; + } + foreach (TestResultError testResultErrorObj in TestResultErrorConstants.ErrorConstants) + { + if (processedErrorMessageKeys.Contains(testResultErrorObj.Key!)) + continue; + if (testResultErrorObj.Pattern.IsMatch(message)) + { + AddInformationalMessage(testResultErrorObj.Message!); + processedErrorMessageKeys.Add(testResultErrorObj.Key!); + } + } + } + private TokenDetails ParseWorkspaceIdFromAccessToken(string accessToken) { TokenDetails tokenDetails = new(); @@ -609,9 +662,13 @@ private void InitializePlaywrightReporter(string xmlSettings) runParameters.TryGetValue(RunSettingKey.AZURE_TOKEN_CREDENTIAL_TYPE, out var azureTokenCredential); runParameters.TryGetValue(RunSettingKey.MANAGED_IDENTITY_CLIENT_ID, out var managedIdentityClientId); runParameters.TryGetValue(RunSettingKey.ENABLE_GITHUB_SUMMARY, out var enableGithubSummary); + runParameters.TryGetValue(RunSettingKey.ENABLE_RESULT_PUBLISH, out var enableResultPublish); string? enableGithubSummaryString = enableGithubSummary?.ToString(); + string? enableResultPublishString = enableResultPublish?.ToString(); EnableGithubSummary = string.IsNullOrEmpty(enableGithubSummaryString) || bool.Parse(enableGithubSummaryString!); + EnableResultPublish = string.IsNullOrEmpty(enableResultPublishString) || bool.Parse(enableResultPublishString!); + PlaywrightServiceSettings? playwrightServiceSettings = null; try { @@ -666,7 +723,7 @@ private void InitializePlaywrightReporter(string xmlSettings) LogMessage("Playwright Service Reporter Intialized"); } - public void GenerateMarkdownSummary() + internal void GenerateMarkdownSummary() { if (CiInfoProvider.GetCIProvider() == PlaywrightConstants.GITHUB_ACTIONS) { @@ -695,4 +752,9 @@ public void GenerateMarkdownSummary() } } } + + private void AddInformationalMessage(string message) + { + informationalMessages.Add(message); + } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs index ffc035c68b93..e04af7928a21 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.Collections.Generic; +using System.Text.RegularExpressions; + namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Utility; internal static class Constants @@ -44,3 +47,82 @@ internal static class Constants internal const string AZURE_DEVOPS = "Azure DevOps"; internal const string DEFAULT = "Default"; } + +internal enum TestErrorType +{ + Scalable +} + +internal class TestResultError +{ + internal string? Key { get; set; } = string.Empty; + internal string? Message { get; set; } = string.Empty; + internal Regex Pattern { get; set; } = new Regex(string.Empty); + internal TestErrorType Type { get; set; } +} + +internal static class TestResultErrorConstants +{ + public static List ErrorConstants = new() + { + new TestResultError + { + Key = "Unauthorized_Scalable", + Message = "The authentication token provided is invalid. Please check the token and try again.", + Pattern = new Regex(@"(?=.*Microsoft\.Playwright\.PlaywrightException)(?=.*401 Unauthorized)", RegexOptions.IgnoreCase), + Type = TestErrorType.Scalable + }, + new TestResultError + { + Key = "NoPermissionOnWorkspace_Scalable", + Message = @"You do not have the required permissions to run tests. This could be because: + + a. You do not have the required roles on the workspace. Only Owner and Contributor roles can run tests. Contact the service administrator. + b. The workspace you are trying to run the tests on is in a different Azure tenant than what you are signed into. Check the tenant id from Azure portal and login using the command 'az login --tenant '.", + Pattern = new Regex(@"(?=.*Microsoft\.Playwright\.PlaywrightException)(?=.*403 Forbidden)(?=[\s\S]*CheckAccess API call with non successful response)", RegexOptions.IgnoreCase), + Type = TestErrorType.Scalable + }, + new TestResultError + { + Key = "InvalidWorkspace_Scalable", + Message = "The specified workspace does not exist. Please verify your workspace settings.", + Pattern = new Regex(@"(?=.*Microsoft\.Playwright\.PlaywrightException)(?=.*403 Forbidden)(?=.*InvalidAccountOrSubscriptionState)", RegexOptions.IgnoreCase), + Type = TestErrorType.Scalable + }, + new TestResultError + { + Key = "AccessKeyBasedAuthNotSupported_Scalable", + Message = "Authentication through service access token is disabled for this workspace. Please use Entra ID to authenticate.", + Pattern = new Regex(@"(?=.*Microsoft\.Playwright\.PlaywrightException)(?=.*403 Forbidden)(?=.*AccessKeyBasedAuthNotSupported)", RegexOptions.IgnoreCase), + Type = TestErrorType.Scalable + }, + new TestResultError + { + Key = "ServiceUnavailable_Scalable", + Message = "The service is currently unavailable. Please check the service status and try again.", + Pattern = new Regex(@"(?=.*Microsoft\.Playwright\.PlaywrightException)(?=.*503 Service Unavailable)", RegexOptions.IgnoreCase), + Type = TestErrorType.Scalable + }, + new TestResultError + { + Key = "GatewayTimeout_Scalable", + Message = "The request to the service timed out. Please try again later.", + Pattern = new Regex(@"(?=.*Microsoft\.Playwright\.PlaywrightException)(?=.*504 Gateway Timeout)", RegexOptions.IgnoreCase), + Type = TestErrorType.Scalable + }, + new TestResultError + { + Key = "QuotaLimitError_Scalable", + Message = "It is possible that the maximum number of concurrent sessions allowed for your workspace has been exceeded.", + Pattern = new Regex(@"(Timeout .* exceeded)(?=[\s\S]*ws connecting)", RegexOptions.IgnoreCase), + Type = TestErrorType.Scalable + }, + new TestResultError + { + Key = "BrowserConnectionError_Scalable", + Message = "The service is currently unavailable. Please try again after some time.", + Pattern = new Regex(@"Target page, context or browser has been closed", RegexOptions.IgnoreCase), + Type = TestErrorType.Scalable + } + }; +} From 079daa07c2c85253319b109c4e7e90cfdb1449d7 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Thu, 5 Sep 2024 23:31:49 +0530 Subject: [PATCH 18/32] refactor(): convert API client class to internal --- .../src/TestLogger/Client/ReportingTestResultsClient.cs | 2 +- .../src/TestLogger/Client/ReportingTestRunsClient.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs index 9e4141d63ce9..ed2f8c76c3fe 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs @@ -14,7 +14,7 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client { // Data plane generated client. /// The TestResults service client. - public partial class ReportingTestResultsClient + internal partial class ReportingTestResultsClient { private readonly HttpPipeline _pipeline; private readonly Uri _endpoint; diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs index d1e4434ec21d..4bdb0cee6e0a 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs @@ -14,7 +14,7 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client { // Data plane generated client. /// The TestRuns service client. - public partial class ReportingTestRunsClient + internal partial class ReportingTestRunsClient { private readonly HttpPipeline _pipeline; private readonly Uri _endpoint; From 3888ff423bd6b5410d504219b3e482a32db3aa6d Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 16 Sep 2024 20:05:29 +0530 Subject: [PATCH 19/32] chore(): apiview review comments addressed for base sdk --- .../src/PlaywrightServiceNUnit.cs | 32 ++++-- .../src/Constants.cs | 43 ++++---- .../src/EntraLifecycle.cs | 4 +- .../src/PlaywrightService.cs | 52 +++++---- .../src/PlaywrightServiceSettings.cs | 15 +-- .../src/TestLogger/PlaywrightReporter.cs | 12 +- .../tests/EntraLifecycleTests.cs | 22 ++-- .../tests/PlaywrightServiceClientTests.cs | 4 +- .../tests/PlaywrightServiceSettingsTest.cs | 10 +- .../tests/PlaywrightServiceTests.cs | 103 +++++++++--------- 10 files changed, 165 insertions(+), 132 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs index 48718edd616a..7f3b90da8709 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using System.Threading.Tasks; using Azure.Developer.MicrosoftPlaywrightTesting; +using System.Runtime.InteropServices; namespace Azure.Developer.MicrosoftPlaywrightTesting.NUnit; @@ -27,13 +28,13 @@ public PlaywrightServiceNUnit(TokenCredential? tokenCredential = null) /// Creates a new instance of based on the runsettings file. /// public static PlaywrightServiceSettings playwrightServiceSettings = new( - os: TestContext.Parameters.Get(RunSettingKey.OS), - runId: TestContext.Parameters.Get(RunSettingKey.RUN_ID), - exposeNetwork: TestContext.Parameters.Get(RunSettingKey.EXPOSE_NETWORK), - defaultAuth: TestContext.Parameters.Get(RunSettingKey.DEFAULT_AUTH), - useCloudHostedBrowsers: TestContext.Parameters.Get(RunSettingKey.USE_CLOUD_HOSTED_BROWSERS), - azureTokenCredentialType: TestContext.Parameters.Get(RunSettingKey.AZURE_TOKEN_CREDENTIAL_TYPE), - managedIdentityClientId: TestContext.Parameters.Get(RunSettingKey.MANAGED_IDENTITY_CLIENT_ID) + os: GetOsPlatform(TestContext.Parameters.Get(RunSettingKey.Os)), + runId: TestContext.Parameters.Get(RunSettingKey.RunId), + exposeNetwork: TestContext.Parameters.Get(RunSettingKey.ExposeNetwork), + defaultAuth: TestContext.Parameters.Get(RunSettingKey.DefaultAuth), + useCloudHostedBrowsers: TestContext.Parameters.Get(RunSettingKey.UseCloudHostedBrowsers), + azureTokenCredentialType: TestContext.Parameters.Get(RunSettingKey.AzureTokenCredentialType), + managedIdentityClientId: TestContext.Parameters.Get(RunSettingKey.ManagedIdentityClientId) ); /// @@ -54,4 +55,21 @@ public void Teardown() { Cleanup(); } + + private static OSPlatform? GetOsPlatform(string? os) + { + if (string.IsNullOrEmpty(os)) + { + return null; + } + else if (os!.Equals("Windows", System.StringComparison.OrdinalIgnoreCase)) + { + return OSPlatform.Windows; + } + else if (os.Equals("Linux", System.StringComparison.OrdinalIgnoreCase)) + { + return OSPlatform.Linux; + } + return null; + } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs index 6baddbab464a..b821c7cfba2f 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs @@ -11,27 +11,27 @@ public class ServiceEnvironmentVariable /// /// The environment variable for the Playwright service access token. /// - public static readonly string PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_ACCESS_TOKEN"; + public static readonly string PlaywrightServiceAccessToken = "PLAYWRIGHT_SERVICE_ACCESS_TOKEN"; /// /// The environment variable for the Playwright service URL. /// - public static readonly string PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_URL"; + public static readonly string PlaywrightServiceUrl = "PLAYWRIGHT_SERVICE_URL"; /// /// The environment variable for exposing the Playwright service network. /// - public static readonly string PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_EXPOSE_NETWORK"; + public static readonly string PlaywrightServiceExposeNetwork = "PLAYWRIGHT_SERVICE_EXPOSE_NETWORK"; /// /// The environment variable for the Playwright service operating system. /// - public static readonly string PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_OS"; + public static readonly string PlaywrightServiceOs = "PLAYWRIGHT_SERVICE_OS"; /// /// The environment variable for the Playwright service run ID. /// - public static readonly string PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE = "PLAYWRIGHT_SERVICE_RUN_ID"; + public static readonly string PlaywrightServiceRunId = "PLAYWRIGHT_SERVICE_RUN_ID"; }; /// @@ -42,12 +42,12 @@ public class ServiceOs /// /// Linux operating system. /// - public static readonly string LINUX = "linux"; + public static readonly string Linux = "linux"; /// /// Windows operating system. /// - public static readonly string WINDOWS = "windows"; + public static readonly string Windows = "windows"; }; /// @@ -58,18 +58,18 @@ public class ServiceAuth /// /// Entra ID authentication method. /// - public static readonly string ENTRA = "ENTRA"; + public static readonly string Entra = "ENTRA"; /// /// Service token authentication method. /// - public static readonly string TOKEN = "TOKEN"; + public static readonly string Token = "TOKEN"; }; /// /// Contains constants for Azure token credential types. /// -public class AzureTokenCredentialType +internal class AzureTokenCredentialType { /// /// Environment Credential. @@ -135,53 +135,53 @@ public class RunSettingKey /// /// The operating system setting key. /// - public static readonly string OS = "Os"; + public static readonly string Os = "Os"; /// /// The run ID setting key. /// - public static readonly string RUN_ID = "RunId"; + public static readonly string RunId = "RunId"; /// /// The expose network setting key. /// - public static readonly string EXPOSE_NETWORK = "ExposeNetwork"; + public static readonly string ExposeNetwork = "ExposeNetwork"; /// /// The default authentication setting key. /// - public static readonly string DEFAULT_AUTH = "DefaultAuth"; + public static readonly string DefaultAuth = "DefaultAuth"; /// /// The use cloud-hosted browsers setting key. /// - public static readonly string USE_CLOUD_HOSTED_BROWSERS = "UseCloudHostedBrowsers"; + public static readonly string UseCloudHostedBrowsers = "UseCloudHostedBrowsers"; /// /// The Azure token credential type setting key. /// - public static readonly string AZURE_TOKEN_CREDENTIAL_TYPE = "AzureTokenCredentialType"; + public static readonly string AzureTokenCredentialType = "AzureTokenCredentialType"; /// /// The managed identity client ID setting key. /// - public static readonly string MANAGED_IDENTITY_CLIENT_ID = "ManagedIdentityClientId"; + public static readonly string ManagedIdentityClientId = "ManagedIdentityClientId"; /// /// Enable GitHub summary setting key. /// - public static readonly string ENABLE_GITHUB_SUMMARY = "EnableGitHubSummary"; + public static readonly string EnableGitHubSummary = "EnableGitHubSummary"; /// /// Enable Result publish. /// - public static readonly string ENABLE_RESULT_PUBLISH = "EnableResultPublish"; + public static readonly string EnableResultPublish = "EnableResultPublish"; } internal class Constants { // Default constants - internal static readonly string s_default_os = ServiceOs.LINUX; + internal static readonly string s_default_os = ServiceOs.Linux; internal static readonly string s_default_expose_network = ""; // Entra id access token constants @@ -198,8 +198,9 @@ internal class Constants internal static readonly string s_no_auth_error = "Could not authenticate with the service. Please refer to https://aka.ms/mpt/authentication for more information."; internal static readonly string s_invalid_mpt_pat_error = "The Access Token provided in the environment variable is invalid."; internal static readonly string s_expired_mpt_pat_error = "The Access Token you are using is expired. Create a new token."; + internal static readonly string s_invalid_os_error = "Invalid operating system, supported values are 'linux' and 'windows'."; internal static readonly string s_playwright_service_disable_scalable_execution_environment_variable = "PLAYWRIGHT_SERVICE_DISABLE_SCALABLE_EXECUTION"; internal static readonly string s_playwright_service_reporting_url_environment_variable = "PLAYWRIGHT_SERVICE_REPORTING_URL"; internal static readonly string s_playwright_service_workspace_id_environment_variable = "PLAYWRIGHT_SERVICE_WORKSPACE_ID"; -} \ No newline at end of file +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs index f3a55e468098..dc094dcd9223 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs @@ -31,7 +31,7 @@ internal async Task FetchEntraIdAccessTokenAsync() AccessToken accessToken = await _tokenCredential.GetTokenAsync(tokenRequestContext, default).ConfigureAwait(false); _entraIdAccessToken = accessToken.Token; _entraIdAccessTokenExpiry = accessToken.ExpiresOn.ToUnixTimeSeconds(); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, _entraIdAccessToken); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, _entraIdAccessToken); return true; } catch (Exception ex) @@ -55,7 +55,7 @@ private void SetEntraIdAccessTokenFromEnvironment() { try { - var token = Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE); + var token = Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken); JsonWebToken jsonWebToken = _jsonWebTokenHandler.ReadJsonWebToken(token); jsonWebToken.TryGetClaim( "aid", diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs index 5e4ce0b28f71..e94a77bbf99f 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -7,6 +7,7 @@ using Microsoft.IdentityModel.JsonWebTokens; using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -21,7 +22,7 @@ public class PlaywrightService /// /// Gets or sets the default authentication mechanism. /// - public string DefaultAuth { get; set; } = ServiceAuth.ENTRA; + public string DefaultAuth { get; set; } = ServiceAuth.Entra; /// /// Gets or sets a flag indicating whether to use cloud-hosted browsers. /// @@ -33,7 +34,7 @@ public class PlaywrightService /// /// Gets the service endpoint for the Playwright service. /// - public static string? ServiceEndpoint => Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE); + public static string? ServiceEndpoint => Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl); private readonly EntraLifecycle? _entraLifecycle; private readonly JsonWebTokenHandler? _jsonWebTokenHandler; @@ -64,22 +65,22 @@ public PlaywrightService(PlaywrightServiceSettings playwrightServiceSettings, To /// The default authentication mechanism. /// Whether to use cloud-hosted browsers. /// The token credential. - public PlaywrightService(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, TokenCredential? tokenCredential = null) + public PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, TokenCredential? tokenCredential = null) { if (string.IsNullOrEmpty(ServiceEndpoint)) return; _entraLifecycle = new EntraLifecycle(tokenCredential: tokenCredential); _jsonWebTokenHandler = new JsonWebTokenHandler(); - InitializePlaywrightServiceEnvironmentVariables(os, runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); + InitializePlaywrightServiceEnvironmentVariables(getServiceCompatibleOs(os), runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); } - internal PlaywrightService(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, EntraLifecycle? entraLifecycle = null, JsonWebTokenHandler? jsonWebTokenHandler = null, TokenCredential? tokenCredential = null) + internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, EntraLifecycle? entraLifecycle = null, JsonWebTokenHandler? jsonWebTokenHandler = null, TokenCredential? tokenCredential = null) { if (string.IsNullOrEmpty(ServiceEndpoint)) return; _entraLifecycle = entraLifecycle ?? new EntraLifecycle(tokenCredential); _jsonWebTokenHandler = jsonWebTokenHandler ?? new JsonWebTokenHandler(); - InitializePlaywrightServiceEnvironmentVariables(os, runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); + InitializePlaywrightServiceEnvironmentVariables(getServiceCompatibleOs(os), runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); } /// @@ -90,15 +91,15 @@ internal PlaywrightService(string? os = null, string? runId = null, string? expo /// The run ID. /// The network exposure. /// The connect options. - public async Task> GetConnectOptionsAsync(string? os = null, string? runId = null, string? exposeNetwork = null) where T : class, new() + public async Task> GetConnectOptionsAsync(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null) where T : class, new() { if (Environment.GetEnvironmentVariable(Constants.s_playwright_service_disable_scalable_execution_environment_variable) == "true") throw new Exception(Constants.s_service_endpoint_removed_since_scalable_execution_disabled_error_message); if (string.IsNullOrEmpty(ServiceEndpoint)) throw new Exception(Constants.s_no_service_endpoint_error_message); - string _serviceOs = Uri.EscapeDataString(os ?? Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE) ?? Constants.s_default_os); - string _runId = Uri.EscapeDataString(runId ?? Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE) ?? GetDefaultRunId()); - string _exposeNetwork = exposeNetwork ?? Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE) ?? Constants.s_default_expose_network; + string _serviceOs = Uri.EscapeDataString(getServiceCompatibleOs(os) ?? Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceOs) ?? Constants.s_default_os); + string _runId = Uri.EscapeDataString(runId ?? Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId) ?? GetDefaultRunId()); + string _exposeNetwork = exposeNetwork ?? Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceExposeNetwork) ?? Constants.s_default_expose_network; string wsEndpoint = $"{ServiceEndpoint}?os={_serviceOs}&runId={_runId}&api-version={Constants.s_api_version}"; @@ -141,10 +142,10 @@ public async Task InitializeAsync() { // Since playwright-dotnet checks PLAYWRIGHT_SERVICE_ACCESS_TOKEN and PLAYWRIGHT_SERVICE_URL to be set, remove PLAYWRIGHT_SERVICE_URL so that tests are run locally. // If customers use GetConnectOptionsAsync, after setting disableScalableExecution, an error will be thrown. - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); } // If default auth mechanism is Access token and token is available in the environment variable, no need to setup rotation handler - if (DefaultAuth == ServiceAuth.TOKEN && !string.IsNullOrEmpty(GetAuthToken())) + if (DefaultAuth == ServiceAuth.Token && !string.IsNullOrEmpty(GetAuthToken())) { ValidateMptPAT(); return; @@ -192,15 +193,15 @@ private void InitializePlaywrightServiceEnvironmentVariables(string? os = null, } if (!string.IsNullOrEmpty(os)) { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE, os); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceOs, os); } else { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE, Constants.s_default_os); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceOs, Constants.s_default_os); } if (!string.IsNullOrEmpty(runId)) { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId, runId); } else { @@ -208,23 +209,23 @@ private void InitializePlaywrightServiceEnvironmentVariables(string? os = null, } if (!string.IsNullOrEmpty(exposeNetwork)) { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE, exposeNetwork); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceExposeNetwork, exposeNetwork); } else { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE, Constants.s_default_expose_network); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceExposeNetwork, Constants.s_default_expose_network); } SetReportingUrlAndWorkspaceId(); } internal static string GetDefaultRunId() { - var runIdFromEnvironmentVariable = Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE); + var runIdFromEnvironmentVariable = Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId); if (!string.IsNullOrEmpty(runIdFromEnvironmentVariable)) return runIdFromEnvironmentVariable!; CIInfo ciInfo = CiInfoProvider.GetCIInfo(); var runId = ReporterUtils.GetRunId(ciInfo); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId, runId); return runId; } @@ -244,7 +245,7 @@ internal static void SetReportingUrlAndWorkspaceId() private static string? GetAuthToken() { - return Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE); + return Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken); } private void ValidateMptPAT() @@ -262,4 +263,15 @@ private void ValidateMptPAT() throw new Exception(Constants.s_invalid_mpt_pat_error); } } + + private string? getServiceCompatibleOs(OSPlatform? oSPlatform) + { + if (oSPlatform == null) + return null; + if (oSPlatform.Equals(OSPlatform.Linux)) + return ServiceOs.Linux; + if (oSPlatform.Equals(OSPlatform.Windows)) + return ServiceOs.Windows; + throw new ArgumentException(Constants.s_invalid_os_error); + } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs index 14094d353f4f..6bd986f1d442 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.Runtime.InteropServices; using Azure.Core; using Azure.Identity; @@ -11,7 +12,7 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting; /// public class PlaywrightServiceSettings { - internal string? Os { get; set; } + internal OSPlatform? Os { get; set; } internal string? RunId { get; set; } internal string? ExposeNetwork { get; set; } internal string DefaultAuth { get; set; } @@ -28,12 +29,12 @@ public class PlaywrightServiceSettings /// Whether to use cloud-hosted browsers. /// The Azure token credential type. /// The managed identity client ID. - public PlaywrightServiceSettings(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) + public PlaywrightServiceSettings(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) { Os = os; RunId = runId; ExposeNetwork = exposeNetwork; - DefaultAuth = defaultAuth ?? ServiceAuth.ENTRA; + DefaultAuth = defaultAuth ?? ServiceAuth.Entra; UseCloudHostedBrowsers = string.IsNullOrEmpty(useCloudHostedBrowsers) || bool.Parse(useCloudHostedBrowsers!); AzureTokenCredential = GetTokenCredential(azureTokenCredentialType, managedIdentityClientId); Validate(); @@ -41,13 +42,13 @@ public PlaywrightServiceSettings(string? os = null, string? runId = null, string private void Validate() { - if (!string.IsNullOrEmpty(Os) && Os != ServiceOs.LINUX && Os != ServiceOs.WINDOWS) + if (Os != null && Os != OSPlatform.Linux && Os != OSPlatform.Windows) { - throw new System.Exception($"Invalid value for {nameof(Os)}: {Os}. Supported values are {ServiceOs.LINUX} and {ServiceOs.WINDOWS}"); + throw new System.Exception($"Invalid value for {nameof(Os)}: {Os}. Supported values are {ServiceOs.Linux} and {ServiceOs.Windows}"); } - if (!string.IsNullOrEmpty(DefaultAuth) && DefaultAuth != ServiceAuth.ENTRA && DefaultAuth != ServiceAuth.TOKEN) + if (!string.IsNullOrEmpty(DefaultAuth) && DefaultAuth != ServiceAuth.Entra && DefaultAuth != ServiceAuth.Token) { - throw new System.Exception($"Invalid value for {nameof(DefaultAuth)}: {DefaultAuth}. Supported values are {ServiceAuth.ENTRA} and {ServiceAuth.TOKEN}"); + throw new System.Exception($"Invalid value for {nameof(DefaultAuth)}: {DefaultAuth}. Supported values are {ServiceAuth.Entra} and {ServiceAuth.Token}"); } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index 2114328f4992..c1c0dccf884a 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -643,7 +643,7 @@ private void InitializePlaywrightReporter(string xmlSettings) } Dictionary runParameters = XmlRunSettingsUtilities.GetTestRunParameters(xmlSettings); - runParameters.TryGetValue(RunSettingKey.RUN_ID, out var runId); + runParameters.TryGetValue(RunSettingKey.RunId, out var runId); // If run id is not provided and not set via env, try fetching it from CI info. CIInfo = CiInfoProvider.GetCIInfo(); if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(PlaywrightConstants.PLAYWRIGHT_SERVICE_RUN_ID))) @@ -658,11 +658,11 @@ private void InitializePlaywrightReporter(string xmlSettings) PlaywrightService.GetDefaultRunId(); // will not set run id if already present in the environment variable } - runParameters.TryGetValue(RunSettingKey.DEFAULT_AUTH, out var defaultAuth); - runParameters.TryGetValue(RunSettingKey.AZURE_TOKEN_CREDENTIAL_TYPE, out var azureTokenCredential); - runParameters.TryGetValue(RunSettingKey.MANAGED_IDENTITY_CLIENT_ID, out var managedIdentityClientId); - runParameters.TryGetValue(RunSettingKey.ENABLE_GITHUB_SUMMARY, out var enableGithubSummary); - runParameters.TryGetValue(RunSettingKey.ENABLE_RESULT_PUBLISH, out var enableResultPublish); + runParameters.TryGetValue(RunSettingKey.DefaultAuth, out var defaultAuth); + runParameters.TryGetValue(RunSettingKey.AzureTokenCredentialType, out var azureTokenCredential); + runParameters.TryGetValue(RunSettingKey.ManagedIdentityClientId, out var managedIdentityClientId); + runParameters.TryGetValue(RunSettingKey.EnableGitHubSummary, out var enableGithubSummary); + runParameters.TryGetValue(RunSettingKey.EnableResultPublish, out var enableResultPublish); string? enableGithubSummaryString = enableGithubSummary?.ToString(); string? enableResultPublishString = enableResultPublish?.ToString(); diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs index 250873adabe5..6959a949c4ef 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs @@ -30,7 +30,7 @@ private static string GetToken(Dictionary claims, DateTime? expi [TearDown] public void TearDown() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, null); } [Test] @@ -43,7 +43,7 @@ public void Constructor_WhenAccessTokenEnvironmentIsNotSet_DoesNotInitializeEntr [Test] public void Constructor_WhenAccessTokenEnvironmentIsSetButTokenIsNotValid_DoesNotInitializeEntraToken() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "valid_token"); EntraLifecycle entraLifecycle = new(); Assert.That(entraLifecycle._entraIdAccessToken, Is.Null); } @@ -55,7 +55,7 @@ public void Constructor_WhenAccessTokenEnvironmentIsSetAndTokenIsMPTCustomToken_ { {"aid", "account-id-guid"}, }); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); EntraLifecycle entraLifecycle = new(); Assert.That(entraLifecycle._entraIdAccessToken, Is.Null); } @@ -67,7 +67,7 @@ public void Constructor_WhenAccessTokenEnvironmentIsSetAndTokenIsMPTCustomTokenW { {"accountId", "account-id-guid"}, }); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); EntraLifecycle entraLifecycle = new(); Assert.That(entraLifecycle._entraIdAccessToken, Is.Null); } @@ -76,7 +76,7 @@ public void Constructor_WhenAccessTokenEnvironmentIsSetAndTokenIsMPTCustomTokenW public void Constructor_WhenJWTValidationThrowsException_DoesNotInitializeEntraToken() { var token = GetToken(new Dictionary()); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); var jsonWebTokenHandlerMock = new Mock(); jsonWebTokenHandlerMock .Setup(x => x.ReadJsonWebToken(token)) @@ -90,7 +90,7 @@ public void Constructor_WhenAccessTokenEnvironmentIsSetAndValid_InitializeEntraT { DateTime expiry = DateTime.UtcNow.AddMinutes(10); var token = GetToken(new Dictionary(), expiry); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); EntraLifecycle entraLifecycle = new(); Assert.Multiple(() => { @@ -109,9 +109,9 @@ public async Task FetchEntraIdAccessTokenAsync_WhenTokenIsFetched_SetsEnvironmen .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); EntraLifecycle entraLifecycle = new(defaultAzureCredentialMock.Object); await entraLifecycle.FetchEntraIdAccessTokenAsync(); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE), Is.EqualTo(token)); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken), Is.EqualTo(token)); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, null); } [Test] @@ -128,7 +128,7 @@ public async Task FetchEntraIdAccessTokenAsync_WhenTokenIsFetched_SetsTokenAndEx Assert.That(entraLifecycle._entraIdAccessToken, Is.EqualTo(token)); Assert.That(entraLifecycle._entraIdAccessTokenExpiry, Is.EqualTo((int)expiry.ToUnixTimeSeconds())); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, null); } [Test] @@ -143,7 +143,7 @@ public async Task FetchEntraIdAccessTokenAsync_WhenTokenIsFetched_ReturnsTrue() EntraLifecycle entraLifecycle = new(defaultAzureCredentialMock.Object); Assert.That(await entraLifecycle.FetchEntraIdAccessTokenAsync(), Is.True); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, null); } [Test] @@ -198,4 +198,4 @@ public void DoesEntraIdAccessTokenRequireRotation_WhenTokenIsAboutToExpire_Retur }; Assert.That(entraLifecycle.DoesEntraIdAccessTokenRequireRotation(), Is.True); } -} \ No newline at end of file +} diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs index 37ef26196817..34f2de02e198 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs @@ -12,7 +12,7 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; public class PlaywrightServiceClientTests : RecordedTestBase { private PlaywrightService? _playwrightService; - private static string Access_Token => Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE)!; + private static string Access_Token => Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken)!; public PlaywrightServiceClientTests(bool isAsync) : base(isAsync, RecordedTestMode.Live) { } @@ -22,7 +22,7 @@ public async Task Setup() var workspaceId = TestUtils.GetWorkspaceIdFromDashboardEndpoint(TestEnvironment.DashboardEndpoint); var region = TestEnvironment.Region; var serviceApiEndpoint = TestUtils.GetPlaywrightServiceAPIEndpoint(workspaceId, region); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, serviceApiEndpoint); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, serviceApiEndpoint); _playwrightService = new PlaywrightService(new PlaywrightServiceSettings(), tokenCredential: TestEnvironment.Credential); await _playwrightService.InitializeAsync(); } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs index 1b0831e93f55..7c17369e39dc 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs @@ -4,6 +4,7 @@ using Azure.Identity; using Azure.Developer.MicrosoftPlaywrightTesting; using System; +using System.Runtime.InteropServices; namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; @@ -14,10 +15,10 @@ public class PlaywrightServiceSettingsTest [Test] public void Constructor_ShouldInitializeProperties() { - var os = ServiceOs.LINUX; + var os = OSPlatform.Linux; var runId = "test-run-id"; var exposeNetwork = "true"; - var defaultAuth = ServiceAuth.ENTRA; + var defaultAuth = ServiceAuth.Entra; var useCloudHostedBrowsers = "true"; var azureTokenCredentialType = AzureTokenCredentialType.ManagedIdentityCredential; var managedIdentityClientId = "test-client-id"; @@ -45,7 +46,7 @@ public void Constructor_ShouldUseDefaultValues() Assert.That(settings.Os, Is.Null); Assert.That(settings.RunId, Is.Null); Assert.That(settings.ExposeNetwork, Is.Null); - Assert.That(settings.DefaultAuth, Is.EqualTo(ServiceAuth.ENTRA)); + Assert.That(settings.DefaultAuth, Is.EqualTo(ServiceAuth.Entra)); Assert.That(settings.UseCloudHostedBrowsers, Is.True); Assert.That(settings.AzureTokenCredential, Is.InstanceOf()); }); @@ -54,8 +55,7 @@ public void Constructor_ShouldUseDefaultValues() [Test] public void Validate_ShouldThrowExceptionForInvalidOs() { - var invalidOs = "InvalidOS"; - Exception? ex = Assert.Throws(() => new PlaywrightServiceSettings(os: invalidOs)); + Exception? ex = Assert.Throws(() => new PlaywrightServiceSettings(os: OSPlatform.Create("invalid"))); Assert.That(ex!.Message, Does.Contain("Invalid value for Os")); } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs index 0a633d304de5..6980eaaa75f3 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Azure.Core; @@ -32,16 +33,16 @@ private static string GetToken(Dictionary claims, DateTime? expi [SetUp] public void Setup() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, "https://playwright.microsoft.com"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, "https://playwright.microsoft.com"); } [TearDown] public void TearDown() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE, null); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, null); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceOs, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceExposeNetwork, null); Environment.SetEnvironmentVariable(Constants.s_playwright_service_disable_scalable_execution_environment_variable, null); Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, null); Environment.SetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable, null); @@ -51,7 +52,7 @@ public void TearDown() public void Constructor_NoConstructorParams_SetsEntraAuthMechanismAsDefault() { PlaywrightService service = new(entraLifecycle: null); - Assert.That(service.DefaultAuth, Is.EqualTo(ServiceAuth.ENTRA)); + Assert.That(service.DefaultAuth, Is.EqualTo(ServiceAuth.Entra)); } [Test] @@ -60,10 +61,10 @@ public void Constructor_NoServiceParams_SetsDefaultValues() var playwrightService = new PlaywrightService(entraLifecycle: null); Assert.Multiple(() => { - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE), Is.EqualTo(Constants.s_default_os)); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE), Is.EqualTo(Constants.s_default_expose_network)); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE), Is.Not.Null); - Assert.That(playwrightService.DefaultAuth, Is.EqualTo(ServiceAuth.ENTRA)); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceOs), Is.EqualTo(Constants.s_default_os)); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceExposeNetwork), Is.EqualTo(Constants.s_default_expose_network)); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId), Is.Not.Null); + Assert.That(playwrightService.DefaultAuth, Is.EqualTo(ServiceAuth.Entra)); Assert.That(playwrightService.UseCloudHostedBrowsers, Is.True); }); } @@ -71,29 +72,29 @@ public void Constructor_NoServiceParams_SetsDefaultValues() [Test] public void Constructor_PassServiceOS_SetsServiceOS() { - _ = new PlaywrightService(os: ServiceOs.WINDOWS, entraLifecycle: null); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE), Is.EqualTo(ServiceOs.WINDOWS)); + _ = new PlaywrightService(os: OSPlatform.Windows, entraLifecycle: null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceOs), Is.EqualTo(ServiceOs.Windows)); } [Test] public void Constructor_PassExposeNetwork_SetsExposeNetwork() { _ = new PlaywrightService(exposeNetwork: "new-expose", entraLifecycle: null); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE), Is.EqualTo("new-expose")); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceExposeNetwork), Is.EqualTo("new-expose")); } [Test] public void Constructor_PassRunId_SetsRunId() { _ = new PlaywrightService(runId: "new-run-id", entraLifecycle: null); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE), Is.EqualTo("new-run-id")); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId), Is.EqualTo("new-run-id")); } [Test] public void Constructor_PassDefaultAuthMechanism_SetsDefaultAuthMechanism() { - var playwrightService = new PlaywrightService(entraLifecycle: null, defaultAuth: ServiceAuth.TOKEN); - Assert.That(playwrightService.DefaultAuth, Is.EqualTo(ServiceAuth.TOKEN)); + var playwrightService = new PlaywrightService(entraLifecycle: null, defaultAuth: ServiceAuth.Token); + Assert.That(playwrightService.DefaultAuth, Is.EqualTo(ServiceAuth.Token)); } [Test] @@ -121,7 +122,7 @@ public void Constructor_PassUseCloudHostedBrowsersAsTrue_SetsDisableScalableExec [Test] public void Initialize_WhenServiceEnpointIsNotSet_NoOP() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); var defaultAzureCredentialMock = new Mock(); var jsonWebTokenHandlerMock = new Mock(); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); @@ -140,14 +141,14 @@ public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironm .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "access_token"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "access_token"); PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object); service.InitializeAsync().Wait(); defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); service.RotationTimer!.Dispose(); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE), Is.Not.Null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl), Is.Not.Null); } [Test] @@ -159,14 +160,14 @@ public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironm tokenCredential .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "access_token"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "access_token"); PlaywrightService service = new(new PlaywrightServiceSettings(), tokenCredential: tokenCredential.Object); service.InitializeAsync().Wait(); tokenCredential.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); service.RotationTimer!.Dispose(); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE), Is.Not.Null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl), Is.Not.Null); } [Test] @@ -179,17 +180,17 @@ public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironm .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "access_token"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "access_token"); PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, useCloudHostedBrowsers: false); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE), Is.Not.Null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl), Is.Not.Null); service.InitializeAsync().Wait(); defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); service.RotationTimer!.Dispose(); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE), Is.Null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl), Is.Null); } [Test] @@ -249,7 +250,7 @@ public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatIsSet_DoesNotSetUpRot { {"aid", "account-id-guid"}, }); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); var defaultAzureCredentialMock = new Mock(); defaultAzureCredentialMock .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) @@ -281,7 +282,7 @@ public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatIsNotSet_DoesNotSetUp public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatIsNotValid_ThrowsError() { var token = "sample token"; - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); var defaultAzureCredentialMock = new Mock(); defaultAzureCredentialMock .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) @@ -295,7 +296,7 @@ public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatIsNotValid_ThrowsErro public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatTokenParsingReturnsNull_ThrowsError() { var token = "sample token"; - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); var jsonWebTokenHandlerMock = new Mock(); #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. jsonWebTokenHandlerMock @@ -318,7 +319,7 @@ public void Initialize_WhenEntraIdAccessTokenFailsAndMptPatIsExpired_ThrowsError { {"aid", "account-id-guid"}, }, DateTime.UtcNow.AddMinutes(-1)); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); var defaultAzureCredentialMock = new Mock(); defaultAzureCredentialMock .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) @@ -336,10 +337,10 @@ public void Initialize_WhenDefaultAuthIsMptPATAndPATIsSet_DoesNotSetUpRotationHa { {"aid", "account-id-guid"}, }); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, token); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); var defaultAzureCredentialMock = new Mock(); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, new JsonWebTokenHandler()); - PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: new JsonWebTokenHandler(), defaultAuth: ServiceAuth.TOKEN); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: new JsonWebTokenHandler(), defaultAuth: ServiceAuth.Token); service.InitializeAsync().Wait(); Assert.That(service.RotationTimer, Is.Null); } @@ -377,7 +378,7 @@ public void RotationHandler_WhenEntraIdAccessTokenDoesNotRequireRotation_NoOp() [Test] public void GetConnectOptionsAsync_WhenServiceEndpointIsNotSet_ThrowsException() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); PlaywrightService service = new(entraLifecycle: null); Exception? ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); Assert.That(ex!.Message, Is.EqualTo(Constants.s_no_service_endpoint_error_message)); @@ -400,7 +401,7 @@ public async Task GetConnectOptionsAsync_WhenServiceEndpointIsSet_ReturnsConnect { var defaultAzureCredentialMock = new Mock(); var jsonWebTokenHandlerMock = new Mock(); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "valid_token"); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); entraLifecycleMock.Object._entraIdAccessToken = "valid_token"; entraLifecycleMock.Object._entraIdAccessTokenExpiry = (int)DateTimeOffset.UtcNow.AddMinutes(22).ToUnixTimeSeconds(); @@ -439,7 +440,7 @@ public async Task GetConnectOptionsAsync_WhenTokenRequiresRotation_RotatesEntraT public async Task GetConnectOptionsAsync_WhenTokenDoesNotRequireRotation_DoesNotRotateEntraToken() { var defaultAzureCredentialMock = new Mock(); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "valid_token"); defaultAzureCredentialMock .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new AccessToken("valid_token", DateTimeOffset.UtcNow.AddMinutes(5))); @@ -458,7 +459,7 @@ public async Task GetConnectOptionsAsync_WhenDefaultParametersAreProvided_SetsSe { var defaultAzureCredentialMock = new Mock(); var jsonWebTokenHandlerMock = new Mock(); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "valid_token"); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); entraLifecycleMock.Object ._entraIdAccessToken = "valid_token"; @@ -467,11 +468,11 @@ public async Task GetConnectOptionsAsync_WhenDefaultParametersAreProvided_SetsSe var runId = "run-id"; var service = new PlaywrightService(entraLifecycle: entraLifecycleMock.Object); - ConnectOptions connectOptions = await service.GetConnectOptionsAsync(runId: runId, os: ServiceOs.WINDOWS, exposeNetwork: "localhost"); + ConnectOptions connectOptions = await service.GetConnectOptionsAsync(runId: runId, os: OSPlatform.Windows, exposeNetwork: "localhost"); Assert.Multiple(() => { - Assert.That(connectOptions.WsEndpoint, Is.EqualTo($"https://playwright.microsoft.com?os={ServiceOs.WINDOWS}&runId={runId}&api-version={Constants.s_api_version}")); + Assert.That(connectOptions.WsEndpoint, Is.EqualTo($"https://playwright.microsoft.com?os={ServiceOs.Windows}&runId={runId}&api-version={Constants.s_api_version}")); Assert.That(connectOptions.Options!.ExposeNetwork, Is.EqualTo("localhost")); }); } @@ -481,7 +482,7 @@ public async Task GetConnectOptionsAsync_WhenDefaultParametersAreNotProvided_Set { var defaultAzureCredentialMock = new Mock(); var jsonWebTokenHandlerMock = new Mock(); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "valid_token"); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); entraLifecycleMock.Object ._entraIdAccessToken = "valid_token"; @@ -504,7 +505,7 @@ public async Task GetConnectOptionsAsync_WhenServiceParametersAreSetViaEnvironme { var defaultAzureCredentialMock = new Mock(); var jsonWebTokenHandlerMock = new Mock(); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, "valid_token"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "valid_token"); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); entraLifecycleMock.Object ._entraIdAccessToken = "valid_token"; @@ -513,14 +514,14 @@ public async Task GetConnectOptionsAsync_WhenServiceParametersAreSetViaEnvironme var runId = "run-id"; var service = new PlaywrightService(entraLifecycle: entraLifecycleMock.Object); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE, ServiceOs.WINDOWS); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE, "localhost"); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceOs, ServiceOs.Windows); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceExposeNetwork, "localhost"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId, runId); ConnectOptions connectOptions = await service.GetConnectOptionsAsync(); Assert.Multiple(() => { - Assert.That(connectOptions.WsEndpoint, Is.EqualTo($"https://playwright.microsoft.com?os={ServiceOs.WINDOWS}&runId={runId}&api-version={Constants.s_api_version}")); + Assert.That(connectOptions.WsEndpoint, Is.EqualTo($"https://playwright.microsoft.com?os={ServiceOs.Windows}&runId={runId}&api-version={Constants.s_api_version}")); Assert.That(connectOptions.Options!.ExposeNetwork, Is.EqualTo("localhost")); }); } @@ -533,7 +534,7 @@ public void GetConnectOptionsAsync_WhenNoAuthTokenIsSet_ThrowsException() var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); var service = new PlaywrightService(entraLifecycle: entraLifecycleMock.Object); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, null); Exception? ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); Assert.That(ex!.Message, Is.EqualTo(Constants.s_no_auth_error)); @@ -543,10 +544,10 @@ public void GetConnectOptionsAsync_WhenNoAuthTokenIsSet_ThrowsException() public void GetDefaultRunId_RunIdSetViaEnvironmentVariable_ReturnsRunId() { var runId = "run-id"; - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, runId); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId, runId); Assert.Multiple(() => { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId, null); Assert.That(PlaywrightService.GetDefaultRunId(), Is.Not.Null); }); } @@ -556,7 +557,7 @@ public void GetDefaultRunId_RunIdNotSetViaEnvironmentVariable_ReturnsRandomRunId { Assert.Multiple(() => { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId, null); Assert.That(PlaywrightService.GetDefaultRunId(), Is.Not.Null); }); } @@ -605,14 +606,14 @@ public void SetReportingUrlAndWorkspaceId_WhenServiceEndpointIsSet_SetsReporting foreach (Dictionary testRubric in testRubricCombinations) { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, $"{testRubric["url"]}"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, $"{testRubric["url"]}"); var service = new PlaywrightService(entraLifecycle: null); Assert.Multiple(() => { Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable), Is.EqualTo($"https://{testRubric["region"]}.reporting.api.{testRubric["domain"]}")); Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable), Is.EqualTo(testRubric["workspaceId"])); }); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, null); Environment.SetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable, null); } @@ -628,7 +629,7 @@ public void SetReportingUrlAndWorkspaceId_WhenReportingServiceEndpointIsSet_Only { "region", "eastus" }, { "domain", "playwright.microsoft.com" } }; - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, $"{testRubric["url"]}"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, $"{testRubric["url"]}"); Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, "https://playwright.microsoft.com"); var service = new PlaywrightService(entraLifecycle: null); Assert.Multiple(() => @@ -648,7 +649,7 @@ public void SetReportingUrlAndWorkspaceId_WhenReportingServiceEndpointAndWorkspa { "region", "eastus" }, { "domain", "playwright.microsoft.com" } }; - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE, $"{testRubric["url"]}"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, $"{testRubric["url"]}"); Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, "https://playwright.microsoft.com"); Environment.SetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable, "sample-id"); var service = new PlaywrightService(entraLifecycle: null); From 1ebca351796c2e94b24e57f24d6dd37009f1ea1d Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 16 Sep 2024 20:09:11 +0530 Subject: [PATCH 20/32] refactor(): rename tokenCredential to credential --- .../src/PlaywrightServiceNUnit.cs | 6 +++--- .../src/PlaywrightService.cs | 16 ++++++++-------- .../tests/PlaywrightServiceClientTests.cs | 2 +- .../tests/PlaywrightServiceTests.cs | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs index 7f3b90da8709..449b68ff38ca 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs @@ -18,9 +18,9 @@ public class PlaywrightServiceNUnit : PlaywrightService /// /// Initializes a new instance of the class. /// - /// The azure token credential to use for authentication. - public PlaywrightServiceNUnit(TokenCredential? tokenCredential = null) - : base(playwrightServiceSettings, tokenCredential: tokenCredential) + /// The azure token credential to use for authentication. + public PlaywrightServiceNUnit(TokenCredential? credential = null) + : base(playwrightServiceSettings, credential: credential) { } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs index e94a77bbf99f..6d5357baf340 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -43,14 +43,14 @@ public class PlaywrightService /// Initializes a new instance of the class. /// /// - /// - public PlaywrightService(PlaywrightServiceSettings playwrightServiceSettings, TokenCredential? tokenCredential = null) : this( + /// + public PlaywrightService(PlaywrightServiceSettings playwrightServiceSettings, TokenCredential? credential = null) : this( os: playwrightServiceSettings.Os, runId: playwrightServiceSettings.RunId, exposeNetwork: playwrightServiceSettings.ExposeNetwork, defaultAuth: playwrightServiceSettings.DefaultAuth, useCloudHostedBrowsers: playwrightServiceSettings.UseCloudHostedBrowsers, - tokenCredential: tokenCredential ?? playwrightServiceSettings.AzureTokenCredential + credential: credential ?? playwrightServiceSettings.AzureTokenCredential ) { // No-op @@ -64,21 +64,21 @@ public PlaywrightService(PlaywrightServiceSettings playwrightServiceSettings, To /// The network exposure. /// The default authentication mechanism. /// Whether to use cloud-hosted browsers. - /// The token credential. - public PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, TokenCredential? tokenCredential = null) + /// The token credential. + public PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, TokenCredential? credential = null) { if (string.IsNullOrEmpty(ServiceEndpoint)) return; - _entraLifecycle = new EntraLifecycle(tokenCredential: tokenCredential); + _entraLifecycle = new EntraLifecycle(tokenCredential: credential); _jsonWebTokenHandler = new JsonWebTokenHandler(); InitializePlaywrightServiceEnvironmentVariables(getServiceCompatibleOs(os), runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); } - internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, EntraLifecycle? entraLifecycle = null, JsonWebTokenHandler? jsonWebTokenHandler = null, TokenCredential? tokenCredential = null) + internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, EntraLifecycle? entraLifecycle = null, JsonWebTokenHandler? jsonWebTokenHandler = null, TokenCredential? credential = null) { if (string.IsNullOrEmpty(ServiceEndpoint)) return; - _entraLifecycle = entraLifecycle ?? new EntraLifecycle(tokenCredential); + _entraLifecycle = entraLifecycle ?? new EntraLifecycle(credential); _jsonWebTokenHandler = jsonWebTokenHandler ?? new JsonWebTokenHandler(); InitializePlaywrightServiceEnvironmentVariables(getServiceCompatibleOs(os), runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs index 34f2de02e198..0d00bbba7ce4 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs @@ -23,7 +23,7 @@ public async Task Setup() var region = TestEnvironment.Region; var serviceApiEndpoint = TestUtils.GetPlaywrightServiceAPIEndpoint(workspaceId, region); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, serviceApiEndpoint); - _playwrightService = new PlaywrightService(new PlaywrightServiceSettings(), tokenCredential: TestEnvironment.Credential); + _playwrightService = new PlaywrightService(new PlaywrightServiceSettings(), credential: TestEnvironment.Credential); await _playwrightService.InitializeAsync(); } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs index 6980eaaa75f3..d98725eb6446 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs @@ -161,7 +161,7 @@ public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironm .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "access_token"); - PlaywrightService service = new(new PlaywrightServiceSettings(), tokenCredential: tokenCredential.Object); + PlaywrightService service = new(new PlaywrightServiceSettings(), credential: tokenCredential.Object); service.InitializeAsync().Wait(); tokenCredential.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); From 1aad6926bde4fe4e0efbe1a6bc3e52cc7f77d4b5 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 16 Sep 2024 20:14:15 +0530 Subject: [PATCH 21/32] refactor(): rename PlaywrightServiceSettings to PlaywrightServiceOptions --- .../src/PlaywrightServiceNUnit.cs | 6 +++--- .../src/PlaywrightService.cs | 16 ++++++++-------- ...ceSettings.cs => PlaywrightServiceOptions.cs} | 8 ++++---- .../src/TestLogger/PlaywrightReporter.cs | 2 +- .../tests/PlaywrightServiceClientTests.cs | 2 +- ...gsTest.cs => PlaywrightServiceOptionsTest.cs} | 10 +++++----- .../tests/PlaywrightServiceTests.cs | 2 +- 7 files changed, 23 insertions(+), 23 deletions(-) rename sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/{PlaywrightServiceSettings.cs => PlaywrightServiceOptions.cs} (92%) rename sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/{PlaywrightServiceSettingsTest.cs => PlaywrightServiceOptionsTest.cs} (92%) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs index 449b68ff38ca..6852c53d38a6 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs @@ -20,14 +20,14 @@ public class PlaywrightServiceNUnit : PlaywrightService /// /// The azure token credential to use for authentication. public PlaywrightServiceNUnit(TokenCredential? credential = null) - : base(playwrightServiceSettings, credential: credential) + : base(playwrightServiceOptions, credential: credential) { } /// - /// Creates a new instance of based on the runsettings file. + /// Creates a new instance of based on the runsettings file. /// - public static PlaywrightServiceSettings playwrightServiceSettings = new( + public static PlaywrightServiceOptions playwrightServiceOptions = new( os: GetOsPlatform(TestContext.Parameters.Get(RunSettingKey.Os)), runId: TestContext.Parameters.Get(RunSettingKey.RunId), exposeNetwork: TestContext.Parameters.Get(RunSettingKey.ExposeNetwork), diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs index 6d5357baf340..3d022ef5e15a 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -42,15 +42,15 @@ public class PlaywrightService /// /// Initializes a new instance of the class. /// - /// + /// /// - public PlaywrightService(PlaywrightServiceSettings playwrightServiceSettings, TokenCredential? credential = null) : this( - os: playwrightServiceSettings.Os, - runId: playwrightServiceSettings.RunId, - exposeNetwork: playwrightServiceSettings.ExposeNetwork, - defaultAuth: playwrightServiceSettings.DefaultAuth, - useCloudHostedBrowsers: playwrightServiceSettings.UseCloudHostedBrowsers, - credential: credential ?? playwrightServiceSettings.AzureTokenCredential + public PlaywrightService(PlaywrightServiceOptions playwrightServiceOptions, TokenCredential? credential = null) : this( + os: playwrightServiceOptions.Os, + runId: playwrightServiceOptions.RunId, + exposeNetwork: playwrightServiceOptions.ExposeNetwork, + defaultAuth: playwrightServiceOptions.DefaultAuth, + useCloudHostedBrowsers: playwrightServiceOptions.UseCloudHostedBrowsers, + credential: credential ?? playwrightServiceOptions.AzureTokenCredential ) { // No-op diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs similarity index 92% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs index 6bd986f1d442..7fd8c0988fbd 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceSettings.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs @@ -8,9 +8,9 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting; /// -/// Settings for the Playwright service. +/// Options for the Playwright service. /// -public class PlaywrightServiceSettings +public class PlaywrightServiceOptions { internal OSPlatform? Os { get; set; } internal string? RunId { get; set; } @@ -20,7 +20,7 @@ public class PlaywrightServiceSettings internal TokenCredential AzureTokenCredential { get; set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The operating system. /// The run ID. @@ -29,7 +29,7 @@ public class PlaywrightServiceSettings /// Whether to use cloud-hosted browsers. /// The Azure token credential type. /// The managed identity client ID. - public PlaywrightServiceSettings(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) + public PlaywrightServiceOptions(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) { Os = os; RunId = runId; diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index c1c0dccf884a..667228c8df60 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -669,7 +669,7 @@ private void InitializePlaywrightReporter(string xmlSettings) EnableGithubSummary = string.IsNullOrEmpty(enableGithubSummaryString) || bool.Parse(enableGithubSummaryString!); EnableResultPublish = string.IsNullOrEmpty(enableResultPublishString) || bool.Parse(enableResultPublishString!); - PlaywrightServiceSettings? playwrightServiceSettings = null; + PlaywrightServiceOptions? playwrightServiceSettings = null; try { playwrightServiceSettings = new(runId: runId?.ToString(), defaultAuth: defaultAuth?.ToString(), azureTokenCredentialType: azureTokenCredential?.ToString(), managedIdentityClientId: managedIdentityClientId?.ToString()); diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs index 0d00bbba7ce4..d3412f210d07 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs @@ -23,7 +23,7 @@ public async Task Setup() var region = TestEnvironment.Region; var serviceApiEndpoint = TestUtils.GetPlaywrightServiceAPIEndpoint(workspaceId, region); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, serviceApiEndpoint); - _playwrightService = new PlaywrightService(new PlaywrightServiceSettings(), credential: TestEnvironment.Credential); + _playwrightService = new PlaywrightService(new PlaywrightServiceOptions(), credential: TestEnvironment.Credential); await _playwrightService.InitializeAsync(); } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs similarity index 92% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs index 7c17369e39dc..a801d30be7bc 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceSettingsTest.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs @@ -23,7 +23,7 @@ public void Constructor_ShouldInitializeProperties() var azureTokenCredentialType = AzureTokenCredentialType.ManagedIdentityCredential; var managedIdentityClientId = "test-client-id"; - var settings = new PlaywrightServiceSettings( + var settings = new PlaywrightServiceOptions( os, runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers, azureTokenCredentialType, managedIdentityClientId); Assert.Multiple(() => @@ -40,7 +40,7 @@ public void Constructor_ShouldInitializeProperties() [Test] public void Constructor_ShouldUseDefaultValues() { - var settings = new PlaywrightServiceSettings(); + var settings = new PlaywrightServiceOptions(); Assert.Multiple(() => { Assert.That(settings.Os, Is.Null); @@ -55,7 +55,7 @@ public void Constructor_ShouldUseDefaultValues() [Test] public void Validate_ShouldThrowExceptionForInvalidOs() { - Exception? ex = Assert.Throws(() => new PlaywrightServiceSettings(os: OSPlatform.Create("invalid"))); + Exception? ex = Assert.Throws(() => new PlaywrightServiceOptions(os: OSPlatform.Create("invalid"))); Assert.That(ex!.Message, Does.Contain("Invalid value for Os")); } @@ -63,7 +63,7 @@ public void Validate_ShouldThrowExceptionForInvalidOs() public void Validate_ShouldThrowExceptionForInvalidDefaultAuth() { var invalidAuth = "InvalidAuth"; - Exception? ex = Assert.Throws(() => new PlaywrightServiceSettings(defaultAuth: invalidAuth)); + Exception? ex = Assert.Throws(() => new PlaywrightServiceOptions(defaultAuth: invalidAuth)); Assert.That(ex!.Message, Does.Contain("Invalid value for DefaultAuth")); } @@ -82,7 +82,7 @@ public void Validate_ShouldThrowExceptionForInvalidDefaultAuth() [TestCase(null, typeof(DefaultAzureCredential))] public void GetTokenCredential_ShouldReturnCorrectCredential(string? credentialType, Type expectedType) { - var settings = new PlaywrightServiceSettings(azureTokenCredentialType: credentialType); + var settings = new PlaywrightServiceOptions(azureTokenCredentialType: credentialType); Assert.That(settings.AzureTokenCredential, Is.InstanceOf(expectedType)); } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs index d98725eb6446..7e09524cedc9 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs @@ -161,7 +161,7 @@ public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironm .Setup(x => x.GetTokenAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(new AccessToken(token, DateTimeOffset.UtcNow.AddMinutes(10))); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "access_token"); - PlaywrightService service = new(new PlaywrightServiceSettings(), credential: tokenCredential.Object); + PlaywrightService service = new(new PlaywrightServiceOptions(), credential: tokenCredential.Object); service.InitializeAsync().Wait(); tokenCredential.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); From 74ddbee3f7f3e4e8b66a5f1683fc4864da661d1c Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 16 Sep 2024 21:27:06 +0530 Subject: [PATCH 22/32] refactor(): use serviceAuth only --- .../Sample1_CustomisingServiceParameters.md | 14 ++++++------ ...mple2_SetDefaultAuthenticationMechanism.md | 4 ++-- .../src/PlaywrightServiceNUnit.cs | 2 +- .../src/Constants.cs | 10 ++++----- .../src/PlaywrightService.cs | 22 +++++++++---------- .../src/PlaywrightServiceOptions.cs | 12 +++++----- .../src/TestLogger/PlaywrightReporter.cs | 6 ++--- .../tests/PlaywrightServiceOptionsTest.cs | 14 ++++++------ .../tests/PlaywrightServiceTests.cs | 10 ++++----- 9 files changed, 47 insertions(+), 47 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md index 0d5d090fd0a9..b0b02f98ab30 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md @@ -64,14 +64,14 @@ public class PlaywrightServiceSetup : PlaywrightServiceNUnit } ``` -## Settings +## Options 1. **`Os`**: - **Description**: This setting allows you to choose the operating system where the browsers running Playwright tests will be hosted. - **Available Options**: - - `ServiceOS.WINDOWS` for Windows OS. - - `ServiceOS.LINUX` for Linux OS. - - **Default Value**: `ServiceOS.LINUX` + - `System.Runtime.InteropServices.OSPlatform.Windows` for Windows OS. + - `System.Runtime.InteropServices.OSPlatform.LINUX` for Linux OS. + - **Default Value**: `System.Runtime.InteropServices.OSPlatform.LINUX` 2. **`RunId`**: - **Description**: This setting allows you to set a unique ID for every test run to distinguish them in the service portal. @@ -82,9 +82,9 @@ public class PlaywrightServiceSetup : PlaywrightServiceNUnit 4. **`DefaultAuth`** - **Description**: This setting allows you to specify the default authentication mechanism to be used for sending requests to the service. - **Available Options**: - - `ServiceAuth.ENTRA` for Microsoft Entra ID authentication. - - `ServiceAuth.TOKEN` for MPT Access Token authentication. - - **Default Value**: `ServiceAuth.ENTRA` + - `ServiceAuthType.EntraId` for Microsoft Entra ID authentication. + - `ServiceAuthType.AccessToken` for MPT Access Token authentication. + - **Default Value**: `ServiceAuthType.EntraId` 5. **`UseCloudHostedBrowsers`** - **Description**: This setting allows you to select whether to use cloud-hosted browsers to run your Playwright tests. Reporting features remain available even if you disable this setting. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md index 85cc028890de..13c3ba68314c 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample2_SetDefaultAuthenticationMechanism.md @@ -23,8 +23,8 @@ public class PlaywrightServiceSetup : PlaywrightServiceNUnit {}; - - + + ``` diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs index 6852c53d38a6..283049f5bf5d 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs @@ -31,7 +31,7 @@ public PlaywrightServiceNUnit(TokenCredential? credential = null) os: GetOsPlatform(TestContext.Parameters.Get(RunSettingKey.Os)), runId: TestContext.Parameters.Get(RunSettingKey.RunId), exposeNetwork: TestContext.Parameters.Get(RunSettingKey.ExposeNetwork), - defaultAuth: TestContext.Parameters.Get(RunSettingKey.DefaultAuth), + serviceAuth: TestContext.Parameters.Get(RunSettingKey.ServiceAuthType), useCloudHostedBrowsers: TestContext.Parameters.Get(RunSettingKey.UseCloudHostedBrowsers), azureTokenCredentialType: TestContext.Parameters.Get(RunSettingKey.AzureTokenCredentialType), managedIdentityClientId: TestContext.Parameters.Get(RunSettingKey.ManagedIdentityClientId) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs index b821c7cfba2f..6982c6116fed 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs @@ -53,17 +53,17 @@ public class ServiceOs /// /// Contains constants for authentication methods. /// -public class ServiceAuth +public class ServiceAuthType { /// /// Entra ID authentication method. /// - public static readonly string Entra = "ENTRA"; + public static readonly string EntraId = "EntraId"; /// - /// Service token authentication method. + /// Access token authentication method. /// - public static readonly string Token = "TOKEN"; + public static readonly string AccessToken = "AccessToken"; }; /// @@ -150,7 +150,7 @@ public class RunSettingKey /// /// The default authentication setting key. /// - public static readonly string DefaultAuth = "DefaultAuth"; + public static readonly string ServiceAuthType = "ServiceAuthType"; /// /// The use cloud-hosted browsers setting key. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs index 3d022ef5e15a..5128092dd074 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -22,7 +22,7 @@ public class PlaywrightService /// /// Gets or sets the default authentication mechanism. /// - public string DefaultAuth { get; set; } = ServiceAuth.Entra; + public string ServiceAuth { get; set; } = ServiceAuthType.EntraId; /// /// Gets or sets a flag indicating whether to use cloud-hosted browsers. /// @@ -48,7 +48,7 @@ public PlaywrightService(PlaywrightServiceOptions playwrightServiceOptions, Toke os: playwrightServiceOptions.Os, runId: playwrightServiceOptions.RunId, exposeNetwork: playwrightServiceOptions.ExposeNetwork, - defaultAuth: playwrightServiceOptions.DefaultAuth, + serviceAuth: playwrightServiceOptions.ServiceAuth, useCloudHostedBrowsers: playwrightServiceOptions.UseCloudHostedBrowsers, credential: credential ?? playwrightServiceOptions.AzureTokenCredential ) @@ -62,25 +62,25 @@ public PlaywrightService(PlaywrightServiceOptions playwrightServiceOptions, Toke /// The operating system. /// The run ID. /// The network exposure. - /// The default authentication mechanism. + /// The service authentication mechanism. /// Whether to use cloud-hosted browsers. /// The token credential. - public PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, TokenCredential? credential = null) + public PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? serviceAuth = null, bool? useCloudHostedBrowsers = null, TokenCredential? credential = null) { if (string.IsNullOrEmpty(ServiceEndpoint)) return; _entraLifecycle = new EntraLifecycle(tokenCredential: credential); _jsonWebTokenHandler = new JsonWebTokenHandler(); - InitializePlaywrightServiceEnvironmentVariables(getServiceCompatibleOs(os), runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); + InitializePlaywrightServiceEnvironmentVariables(getServiceCompatibleOs(os), runId, exposeNetwork, serviceAuth, useCloudHostedBrowsers); } - internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null, EntraLifecycle? entraLifecycle = null, JsonWebTokenHandler? jsonWebTokenHandler = null, TokenCredential? credential = null) + internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? serviceAuth = null, bool? useCloudHostedBrowsers = null, EntraLifecycle? entraLifecycle = null, JsonWebTokenHandler? jsonWebTokenHandler = null, TokenCredential? credential = null) { if (string.IsNullOrEmpty(ServiceEndpoint)) return; _entraLifecycle = entraLifecycle ?? new EntraLifecycle(credential); _jsonWebTokenHandler = jsonWebTokenHandler ?? new JsonWebTokenHandler(); - InitializePlaywrightServiceEnvironmentVariables(getServiceCompatibleOs(os), runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers); + InitializePlaywrightServiceEnvironmentVariables(getServiceCompatibleOs(os), runId, exposeNetwork, serviceAuth, useCloudHostedBrowsers); } /// @@ -145,7 +145,7 @@ public async Task InitializeAsync() Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); } // If default auth mechanism is Access token and token is available in the environment variable, no need to setup rotation handler - if (DefaultAuth == ServiceAuth.Token && !string.IsNullOrEmpty(GetAuthToken())) + if (ServiceAuth == ServiceAuthType.AccessToken && !string.IsNullOrEmpty(GetAuthToken())) { ValidateMptPAT(); return; @@ -179,11 +179,11 @@ internal async void RotationHandlerAsync(object? _) } } - private void InitializePlaywrightServiceEnvironmentVariables(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = null) + private void InitializePlaywrightServiceEnvironmentVariables(string? os = null, string? runId = null, string? exposeNetwork = null, string? serviceAuth = null, bool? useCloudHostedBrowsers = null) { - if (!string.IsNullOrEmpty(defaultAuth)) + if (!string.IsNullOrEmpty(serviceAuth)) { - DefaultAuth = defaultAuth!; + ServiceAuth = serviceAuth!; } if (useCloudHostedBrowsers != null) { diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs index 7fd8c0988fbd..ba20721b7e6e 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs @@ -15,7 +15,7 @@ public class PlaywrightServiceOptions internal OSPlatform? Os { get; set; } internal string? RunId { get; set; } internal string? ExposeNetwork { get; set; } - internal string DefaultAuth { get; set; } + internal string ServiceAuth { get; set; } internal bool UseCloudHostedBrowsers { get; set; } internal TokenCredential AzureTokenCredential { get; set; } @@ -25,16 +25,16 @@ public class PlaywrightServiceOptions /// The operating system. /// The run ID. /// The network exposure. - /// The default authentication mechanism. + /// The default authentication mechanism. /// Whether to use cloud-hosted browsers. /// The Azure token credential type. /// The managed identity client ID. - public PlaywrightServiceOptions(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) + public PlaywrightServiceOptions(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, string? serviceAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) { Os = os; RunId = runId; ExposeNetwork = exposeNetwork; - DefaultAuth = defaultAuth ?? ServiceAuth.Entra; + ServiceAuth = serviceAuth ?? ServiceAuthType.EntraId; UseCloudHostedBrowsers = string.IsNullOrEmpty(useCloudHostedBrowsers) || bool.Parse(useCloudHostedBrowsers!); AzureTokenCredential = GetTokenCredential(azureTokenCredentialType, managedIdentityClientId); Validate(); @@ -46,9 +46,9 @@ private void Validate() { throw new System.Exception($"Invalid value for {nameof(Os)}: {Os}. Supported values are {ServiceOs.Linux} and {ServiceOs.Windows}"); } - if (!string.IsNullOrEmpty(DefaultAuth) && DefaultAuth != ServiceAuth.Entra && DefaultAuth != ServiceAuth.Token) + if (!string.IsNullOrEmpty(ServiceAuth) && ServiceAuth != ServiceAuthType.EntraId && ServiceAuth != ServiceAuthType.AccessToken) { - throw new System.Exception($"Invalid value for {nameof(DefaultAuth)}: {DefaultAuth}. Supported values are {ServiceAuth.Entra} and {ServiceAuth.Token}"); + throw new System.Exception($"Invalid value for {nameof(ServiceAuth)}: {ServiceAuth}. Supported values are {ServiceAuthType.EntraId} and {ServiceAuthType.AccessToken}"); } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs index 667228c8df60..bccfa0632517 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs @@ -658,7 +658,7 @@ private void InitializePlaywrightReporter(string xmlSettings) PlaywrightService.GetDefaultRunId(); // will not set run id if already present in the environment variable } - runParameters.TryGetValue(RunSettingKey.DefaultAuth, out var defaultAuth); + runParameters.TryGetValue(RunSettingKey.ServiceAuthType, out var serviceAuth); runParameters.TryGetValue(RunSettingKey.AzureTokenCredentialType, out var azureTokenCredential); runParameters.TryGetValue(RunSettingKey.ManagedIdentityClientId, out var managedIdentityClientId); runParameters.TryGetValue(RunSettingKey.EnableGitHubSummary, out var enableGithubSummary); @@ -672,7 +672,7 @@ private void InitializePlaywrightReporter(string xmlSettings) PlaywrightServiceOptions? playwrightServiceSettings = null; try { - playwrightServiceSettings = new(runId: runId?.ToString(), defaultAuth: defaultAuth?.ToString(), azureTokenCredentialType: azureTokenCredential?.ToString(), managedIdentityClientId: managedIdentityClientId?.ToString()); + playwrightServiceSettings = new(runId: runId?.ToString(), serviceAuth: serviceAuth?.ToString(), azureTokenCredentialType: azureTokenCredential?.ToString(), managedIdentityClientId: managedIdentityClientId?.ToString()); } catch (Exception ex) { @@ -681,7 +681,7 @@ private void InitializePlaywrightReporter(string xmlSettings) } // setup entra rotation handlers - playwrightService = new PlaywrightService(null, playwrightServiceSettings!.RunId, null, playwrightServiceSettings.DefaultAuth, null, playwrightServiceSettings.AzureTokenCredential); + playwrightService = new PlaywrightService(null, playwrightServiceSettings!.RunId, null, playwrightServiceSettings.ServiceAuth, null, playwrightServiceSettings.AzureTokenCredential); #pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. playwrightService.InitializeAsync().GetAwaiter().GetResult(); #pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult(). Use the TaskExtensions.EnsureCompleted() extension method instead. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs index a801d30be7bc..6467088dbacd 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs @@ -10,7 +10,7 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; [TestFixture] [Parallelizable(ParallelScope.Self)] -public class PlaywrightServiceSettingsTest +public class PlaywrightServiceOptionsTest { [Test] public void Constructor_ShouldInitializeProperties() @@ -18,20 +18,20 @@ public void Constructor_ShouldInitializeProperties() var os = OSPlatform.Linux; var runId = "test-run-id"; var exposeNetwork = "true"; - var defaultAuth = ServiceAuth.Entra; + var serviceAuth = ServiceAuthType.EntraId; var useCloudHostedBrowsers = "true"; var azureTokenCredentialType = AzureTokenCredentialType.ManagedIdentityCredential; var managedIdentityClientId = "test-client-id"; var settings = new PlaywrightServiceOptions( - os, runId, exposeNetwork, defaultAuth, useCloudHostedBrowsers, azureTokenCredentialType, managedIdentityClientId); + os, runId, exposeNetwork, serviceAuth, useCloudHostedBrowsers, azureTokenCredentialType, managedIdentityClientId); Assert.Multiple(() => { Assert.That(settings.Os, Is.EqualTo(os)); Assert.That(settings.RunId, Is.EqualTo(runId)); Assert.That(settings.ExposeNetwork, Is.EqualTo(exposeNetwork)); - Assert.That(settings.DefaultAuth, Is.EqualTo(defaultAuth)); + Assert.That(settings.ServiceAuth, Is.EqualTo(serviceAuth)); Assert.That(settings.UseCloudHostedBrowsers, Is.True); Assert.That(settings.AzureTokenCredential, Is.InstanceOf()); }); @@ -46,7 +46,7 @@ public void Constructor_ShouldUseDefaultValues() Assert.That(settings.Os, Is.Null); Assert.That(settings.RunId, Is.Null); Assert.That(settings.ExposeNetwork, Is.Null); - Assert.That(settings.DefaultAuth, Is.EqualTo(ServiceAuth.Entra)); + Assert.That(settings.ServiceAuth, Is.EqualTo(ServiceAuthType.EntraId)); Assert.That(settings.UseCloudHostedBrowsers, Is.True); Assert.That(settings.AzureTokenCredential, Is.InstanceOf()); }); @@ -63,8 +63,8 @@ public void Validate_ShouldThrowExceptionForInvalidOs() public void Validate_ShouldThrowExceptionForInvalidDefaultAuth() { var invalidAuth = "InvalidAuth"; - Exception? ex = Assert.Throws(() => new PlaywrightServiceOptions(defaultAuth: invalidAuth)); - Assert.That(ex!.Message, Does.Contain("Invalid value for DefaultAuth")); + Exception? ex = Assert.Throws(() => new PlaywrightServiceOptions(serviceAuth: invalidAuth)); + Assert.That(ex!.Message, Does.Contain("Invalid value for ServiceAuth")); } [TestCase("ManagedIdentityCredential", typeof(ManagedIdentityCredential))] diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs index 7e09524cedc9..e9c77507b63e 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs @@ -52,7 +52,7 @@ public void TearDown() public void Constructor_NoConstructorParams_SetsEntraAuthMechanismAsDefault() { PlaywrightService service = new(entraLifecycle: null); - Assert.That(service.DefaultAuth, Is.EqualTo(ServiceAuth.Entra)); + Assert.That(service.ServiceAuth, Is.EqualTo(ServiceAuthType.EntraId)); } [Test] @@ -64,7 +64,7 @@ public void Constructor_NoServiceParams_SetsDefaultValues() Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceOs), Is.EqualTo(Constants.s_default_os)); Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceExposeNetwork), Is.EqualTo(Constants.s_default_expose_network)); Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId), Is.Not.Null); - Assert.That(playwrightService.DefaultAuth, Is.EqualTo(ServiceAuth.Entra)); + Assert.That(playwrightService.ServiceAuth, Is.EqualTo(ServiceAuthType.EntraId)); Assert.That(playwrightService.UseCloudHostedBrowsers, Is.True); }); } @@ -93,8 +93,8 @@ public void Constructor_PassRunId_SetsRunId() [Test] public void Constructor_PassDefaultAuthMechanism_SetsDefaultAuthMechanism() { - var playwrightService = new PlaywrightService(entraLifecycle: null, defaultAuth: ServiceAuth.Token); - Assert.That(playwrightService.DefaultAuth, Is.EqualTo(ServiceAuth.Token)); + var playwrightService = new PlaywrightService(entraLifecycle: null, serviceAuth: ServiceAuthType.AccessToken); + Assert.That(playwrightService.ServiceAuth, Is.EqualTo(ServiceAuthType.AccessToken)); } [Test] @@ -340,7 +340,7 @@ public void Initialize_WhenDefaultAuthIsMptPATAndPATIsSet_DoesNotSetUpRotationHa Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, token); var defaultAzureCredentialMock = new Mock(); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, new JsonWebTokenHandler()); - PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: new JsonWebTokenHandler(), defaultAuth: ServiceAuth.Token); + PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, jsonWebTokenHandler: new JsonWebTokenHandler(), serviceAuth: ServiceAuthType.AccessToken); service.InitializeAsync().Wait(); Assert.That(service.RotationTimer, Is.Null); } From 71ee32fdcabc1f20fb4110872996e16fe8ad1e2c Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 16 Sep 2024 22:32:01 +0530 Subject: [PATCH 23/32] refactor(): remove defaultAuth references --- ...tPlaywrightTesting.NUnit.netstandard2.0.cs | 4 +- .../Sample1_CustomisingServiceParameters.md | 4 +- ...wrightTesting.TestLogger.netstandard2.0.cs | 76 +++++++++---------- 3 files changed, 41 insertions(+), 43 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs index abc3972b899c..aaf94570dcb6 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs @@ -3,8 +3,8 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting.NUnit [NUnit.Framework.SetUpFixtureAttribute] public partial class PlaywrightServiceNUnit : Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightService { - public static Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceSettings playwrightServiceSettings; - public PlaywrightServiceNUnit(Azure.Core.TokenCredential? tokenCredential = null) : base (default(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceSettings), default(Azure.Core.TokenCredential)) { } + public static Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions playwrightServiceOptions; + public PlaywrightServiceNUnit(Azure.Core.TokenCredential? credential = null) : base (default(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions), default(Azure.Core.TokenCredential)) { } [NUnit.Framework.OneTimeSetUpAttribute] public System.Threading.Tasks.Task SetupAsync() { throw null; } [NUnit.Framework.OneTimeTearDownAttribute] diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md index b0b02f98ab30..ef62a3929fe6 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/samples/Sample1_CustomisingServiceParameters.md @@ -16,7 +16,7 @@ This guide explains the different options available to you in the Azure.Develope - + @@ -79,7 +79,7 @@ public class PlaywrightServiceSetup : PlaywrightServiceNUnit 3. **`ExposeNetwork`**: - **Description**: This settings exposes network available on the connecting client to the browser being connected to. -4. **`DefaultAuth`** +4. **`ServiceAuth`** - **Description**: This setting allows you to specify the default authentication mechanism to be used for sending requests to the service. - **Available Options**: - `ServiceAuthType.EntraId` for Microsoft Entra ID authentication. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs index 79047844ccc8..69d70ef8d46d 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs @@ -1,20 +1,5 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting { - public partial class AzureTokenCredentialType - { - public static readonly string AzureCliCredential; - public static readonly string AzureDeveloperCliCredential; - public static readonly string AzurePowerShellCredential; - public static readonly string DefaultAzureCredential; - public static readonly string EnvironmentCredential; - public static readonly string InteractiveBrowserCredential; - public static readonly string ManagedIdentityCredential; - public static readonly string SharedTokenCacheCredential; - public static readonly string VisualStudioCodeCredential; - public static readonly string VisualStudioCredential; - public static readonly string WorkloadIdentityCredential; - public AzureTokenCredentialType() { } - } public partial class ConnectOptions where T : class, new() { public T? Options; @@ -23,50 +8,63 @@ public ConnectOptions() { } } public partial class PlaywrightService { - public PlaywrightService(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceSettings playwrightServiceSettings, Azure.Core.TokenCredential? tokenCredential = null) { } - public PlaywrightService(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, bool? useCloudHostedBrowsers = default(bool?), Azure.Core.TokenCredential? tokenCredential = null) { } - public string DefaultAuth { get { throw null; } set { } } + public PlaywrightService(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions playwrightServiceOptions, Azure.Core.TokenCredential? credential = null) { } + public PlaywrightService(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null, string? serviceAuth = null, bool? useCloudHostedBrowsers = default(bool?), Azure.Core.TokenCredential? credential = null) { } public System.Threading.Timer? RotationTimer { get { throw null; } set { } } + public string ServiceAuth { get { throw null; } set { } } public static string? ServiceEndpoint { get { throw null; } } public bool UseCloudHostedBrowsers { get { throw null; } set { } } public void Cleanup() { } - public System.Threading.Tasks.Task> GetConnectOptionsAsync(string? os = null, string? runId = null, string? exposeNetwork = null) where T : class, new() { throw null; } + public System.Threading.Tasks.Task> GetConnectOptionsAsync(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null) where T : class, new() { throw null; } public System.Threading.Tasks.Task InitializeAsync() { throw null; } } - public partial class PlaywrightServiceSettings + public partial class PlaywrightServiceOptions { - public PlaywrightServiceSettings(string? os = null, string? runId = null, string? exposeNetwork = null, string? defaultAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) { } + public PlaywrightServiceOptions(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null, string? serviceAuth = null, string? useCloudHostedBrowsers = null, string? azureTokenCredentialType = null, string? managedIdentityClientId = null) { } } public partial class RunSettingKey { - public static readonly string AZURE_TOKEN_CREDENTIAL_TYPE; - public static readonly string DEFAULT_AUTH; - public static readonly string EXPOSE_NETWORK; - public static readonly string MANAGED_IDENTITY_CLIENT_ID; - public static readonly string OS; - public static readonly string RUN_ID; - public static readonly string USE_CLOUD_HOSTED_BROWSERS; + public static readonly string AzureTokenCredentialType; + public static readonly string EnableGitHubSummary; + public static readonly string EnableResultPublish; + public static readonly string ExposeNetwork; + public static readonly string ManagedIdentityClientId; + public static readonly string Os; + public static readonly string RunId; + public static readonly string ServiceAuthType; + public static readonly string UseCloudHostedBrowsers; public RunSettingKey() { } } - public partial class ServiceAuth + public partial class ServiceAuthType { - public static readonly string ENTRA; - public static readonly string TOKEN; - public ServiceAuth() { } + public static readonly string AccessToken; + public static readonly string EntraId; + public ServiceAuthType() { } } public partial class ServiceEnvironmentVariable { - public static readonly string PLAYWRIGHT_SERVICE_ACCESS_TOKEN_ENVIRONMENT_VARIABLE; - public static readonly string PLAYWRIGHT_SERVICE_EXPOSE_NETWORK_ENVIRONMENT_VARIABLE; - public static readonly string PLAYWRIGHT_SERVICE_OS_ENVIRONMENT_VARIABLE; - public static readonly string PLAYWRIGHT_SERVICE_RUN_ID_ENVIRONMENT_VARIABLE; - public static readonly string PLAYWRIGHT_SERVICE_URL_ENVIRONMENT_VARIABLE; + public static readonly string PlaywrightServiceAccessToken; + public static readonly string PlaywrightServiceExposeNetwork; + public static readonly string PlaywrightServiceOs; + public static readonly string PlaywrightServiceRunId; + public static readonly string PlaywrightServiceUrl; public ServiceEnvironmentVariable() { } } public partial class ServiceOs { - public static readonly string LINUX; - public static readonly string WINDOWS; + public static readonly string Linux; + public static readonly string Windows; public ServiceOs() { } } } +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client +{ + public partial class TestReportingClientOptions : Azure.Core.ClientOptions + { + public TestReportingClientOptions(Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client.TestReportingClientOptions.ServiceVersion version = Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client.TestReportingClientOptions.ServiceVersion.V2024_05_20_Preview) { } + public enum ServiceVersion + { + V2024_05_20_Preview = 1, + } + } +} From a5adb8e4e7fec8d14b9c3730bc275ec63195e9fc Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Mon, 16 Sep 2024 22:38:14 +0530 Subject: [PATCH 24/32] refactor(): convert serviceOs class to internal --- ....MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs | 6 ------ .../src/Constants.cs | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs index 69d70ef8d46d..4cb34b4e16dd 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs @@ -50,12 +50,6 @@ public partial class ServiceEnvironmentVariable public static readonly string PlaywrightServiceUrl; public ServiceEnvironmentVariable() { } } - public partial class ServiceOs - { - public static readonly string Linux; - public static readonly string Windows; - public ServiceOs() { } - } } namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Client { diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs index 6982c6116fed..b6dcc9978194 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs @@ -37,7 +37,7 @@ public class ServiceEnvironmentVariable /// /// Contains constants for supported operating systems on Microsoft Playwright Testing. /// -public class ServiceOs +internal class ServiceOs { /// /// Linux operating system. From f28d86dd9dde1c20a4fa14406cc16304e0bad6cf Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Tue, 17 Sep 2024 14:25:31 +0530 Subject: [PATCH 25/32] refactor(): convert public fields into properties --- .../src/PlaywrightServiceNUnit.cs | 3 +-- .../src/ConnectOptions.cs | 4 ++-- .../src/Constants.cs | 2 +- .../src/PlaywrightService.cs | 4 ++-- .../tests/PlaywrightServiceClientTests.cs | 2 +- .../tests/PlaywrightServiceTests.cs | 24 +++++++++---------- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs index 283049f5bf5d..d569cbcb8550 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs @@ -4,7 +4,6 @@ using Azure.Core; using NUnit.Framework; using System.Threading.Tasks; -using Azure.Developer.MicrosoftPlaywrightTesting; using System.Runtime.InteropServices; namespace Azure.Developer.MicrosoftPlaywrightTesting.NUnit; @@ -27,7 +26,7 @@ public PlaywrightServiceNUnit(TokenCredential? credential = null) /// /// Creates a new instance of based on the runsettings file. /// - public static PlaywrightServiceOptions playwrightServiceOptions = new( + public static PlaywrightServiceOptions playwrightServiceOptions { get; } = new( os: GetOsPlatform(TestContext.Parameters.Get(RunSettingKey.Os)), runId: TestContext.Parameters.Get(RunSettingKey.RunId), exposeNetwork: TestContext.Parameters.Get(RunSettingKey.ExposeNetwork), diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs index 609f8143a185..2f63d5bc5bbf 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs @@ -14,11 +14,11 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting; /// /// A browser websocket endpoint to connect to. /// - public string? WsEndpoint; + public string? WsEndpoint { get; set; } /// /// Connect options for the service. /// - public T? Options; + public T? Options { get; set; } } internal class BrowserConnectOptions diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs index b6dcc9978194..99682b72b27b 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs @@ -16,7 +16,7 @@ public class ServiceEnvironmentVariable /// /// The environment variable for the Playwright service URL. /// - public static readonly string PlaywrightServiceUrl = "PLAYWRIGHT_SERVICE_URL"; + public static readonly string PlaywrightServiceUri = "PLAYWRIGHT_SERVICE_URL"; /// /// The environment variable for exposing the Playwright service network. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs index 5128092dd074..7f3d3d509e61 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -34,7 +34,7 @@ public class PlaywrightService /// /// Gets the service endpoint for the Playwright service. /// - public static string? ServiceEndpoint => Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl); + public static string? ServiceEndpoint => Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri); private readonly EntraLifecycle? _entraLifecycle; private readonly JsonWebTokenHandler? _jsonWebTokenHandler; @@ -142,7 +142,7 @@ public async Task InitializeAsync() { // Since playwright-dotnet checks PLAYWRIGHT_SERVICE_ACCESS_TOKEN and PLAYWRIGHT_SERVICE_URL to be set, remove PLAYWRIGHT_SERVICE_URL so that tests are run locally. // If customers use GetConnectOptionsAsync, after setting disableScalableExecution, an error will be thrown. - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, null); } // If default auth mechanism is Access token and token is available in the environment variable, no need to setup rotation handler if (ServiceAuth == ServiceAuthType.AccessToken && !string.IsNullOrEmpty(GetAuthToken())) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs index d3412f210d07..d3da77a3c294 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs @@ -22,7 +22,7 @@ public async Task Setup() var workspaceId = TestUtils.GetWorkspaceIdFromDashboardEndpoint(TestEnvironment.DashboardEndpoint); var region = TestEnvironment.Region; var serviceApiEndpoint = TestUtils.GetPlaywrightServiceAPIEndpoint(workspaceId, region); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, serviceApiEndpoint); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, serviceApiEndpoint); _playwrightService = new PlaywrightService(new PlaywrightServiceOptions(), credential: TestEnvironment.Credential); await _playwrightService.InitializeAsync(); } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs index e9c77507b63e..72598ed3e188 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs @@ -33,12 +33,12 @@ private static string GetToken(Dictionary claims, DateTime? expi [SetUp] public void Setup() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, "https://playwright.microsoft.com"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, "https://playwright.microsoft.com"); } [TearDown] public void TearDown() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, null); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, null); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceOs, null); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceRunId, null); @@ -122,7 +122,7 @@ public void Constructor_PassUseCloudHostedBrowsersAsTrue_SetsDisableScalableExec [Test] public void Initialize_WhenServiceEnpointIsNotSet_NoOP() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, null); var defaultAzureCredentialMock = new Mock(); var jsonWebTokenHandlerMock = new Mock(); var entraLifecycleMock = new Mock(defaultAzureCredentialMock.Object, jsonWebTokenHandlerMock.Object); @@ -148,7 +148,7 @@ public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironm service.RotationTimer!.Dispose(); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl), Is.Not.Null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri), Is.Not.Null); } [Test] @@ -167,7 +167,7 @@ public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironm service.RotationTimer!.Dispose(); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl), Is.Not.Null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri), Is.Not.Null); } [Test] @@ -183,14 +183,14 @@ public void Initialize_WhenDefaultAuthIsEntraIdAccessTokenAndAccessTokenEnvironm Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, "access_token"); PlaywrightService service = new(entraLifecycle: entraLifecycleMock.Object, useCloudHostedBrowsers: false); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl), Is.Not.Null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri), Is.Not.Null); service.InitializeAsync().Wait(); defaultAzureCredentialMock.Verify(x => x.GetTokenAsync(It.IsAny(), It.IsAny()), Times.Once); service.RotationTimer!.Dispose(); - Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl), Is.Null); + Assert.That(Environment.GetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri), Is.Null); } [Test] @@ -378,7 +378,7 @@ public void RotationHandler_WhenEntraIdAccessTokenDoesNotRequireRotation_NoOp() [Test] public void GetConnectOptionsAsync_WhenServiceEndpointIsNotSet_ThrowsException() { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, null); PlaywrightService service = new(entraLifecycle: null); Exception? ex = Assert.ThrowsAsync(() => service.GetConnectOptionsAsync()); Assert.That(ex!.Message, Is.EqualTo(Constants.s_no_service_endpoint_error_message)); @@ -606,14 +606,14 @@ public void SetReportingUrlAndWorkspaceId_WhenServiceEndpointIsSet_SetsReporting foreach (Dictionary testRubric in testRubricCombinations) { - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, $"{testRubric["url"]}"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, $"{testRubric["url"]}"); var service = new PlaywrightService(entraLifecycle: null); Assert.Multiple(() => { Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable), Is.EqualTo($"https://{testRubric["region"]}.reporting.api.{testRubric["domain"]}")); Assert.That(Environment.GetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable), Is.EqualTo(testRubric["workspaceId"])); }); - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, null); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, null); Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, null); Environment.SetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable, null); } @@ -629,7 +629,7 @@ public void SetReportingUrlAndWorkspaceId_WhenReportingServiceEndpointIsSet_Only { "region", "eastus" }, { "domain", "playwright.microsoft.com" } }; - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, $"{testRubric["url"]}"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, $"{testRubric["url"]}"); Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, "https://playwright.microsoft.com"); var service = new PlaywrightService(entraLifecycle: null); Assert.Multiple(() => @@ -649,7 +649,7 @@ public void SetReportingUrlAndWorkspaceId_WhenReportingServiceEndpointAndWorkspa { "region", "eastus" }, { "domain", "playwright.microsoft.com" } }; - Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUrl, $"{testRubric["url"]}"); + Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceUri, $"{testRubric["url"]}"); Environment.SetEnvironmentVariable(Constants.s_playwright_service_reporting_url_environment_variable, "https://playwright.microsoft.com"); Environment.SetEnvironmentVariable(Constants.s_playwright_service_workspace_id_environment_variable, "sample-id"); var service = new PlaywrightService(entraLifecycle: null); From 466f9ee10d427c8871e8b4f78f75dda737ea0ac8 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Tue, 17 Sep 2024 14:38:48 +0530 Subject: [PATCH 26/32] chore(): add cancellation token in async methods --- ....MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs | 4 ++-- .../src/PlaywrightServiceNUnit.cs | 6 ++++-- ...osoftPlaywrightTesting.TestLogger.netstandard2.0.cs | 10 +++++----- .../src/EntraLifecycle.cs | 5 +++-- .../src/PlaywrightService.cs | 9 +++++---- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs index aaf94570dcb6..4af1077eae46 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs @@ -3,10 +3,10 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting.NUnit [NUnit.Framework.SetUpFixtureAttribute] public partial class PlaywrightServiceNUnit : Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightService { - public static Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions playwrightServiceOptions; public PlaywrightServiceNUnit(Azure.Core.TokenCredential? credential = null) : base (default(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions), default(Azure.Core.TokenCredential)) { } + public static Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions playwrightServiceOptions { get { throw null; } } [NUnit.Framework.OneTimeSetUpAttribute] - public System.Threading.Tasks.Task SetupAsync() { throw null; } + public System.Threading.Tasks.Task SetupAsync(System.Threading.CancellationToken? cancellationToken = default(System.Threading.CancellationToken?)) { throw null; } [NUnit.Framework.OneTimeTearDownAttribute] public void Teardown() { } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs index d569cbcb8550..e60374993e3f 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using System.Threading.Tasks; using System.Runtime.InteropServices; +using System.Threading; namespace Azure.Developer.MicrosoftPlaywrightTesting.NUnit; @@ -39,11 +40,12 @@ public PlaywrightServiceNUnit(TokenCredential? credential = null) /// /// Setup the resources utilized by Playwright service. /// + /// Cancellation token. /// [OneTimeSetUp] - public async Task SetupAsync() + public async Task SetupAsync(CancellationToken? cancellationToken = null) { - await InitializeAsync().ConfigureAwait(false); + await InitializeAsync(cancellationToken).ConfigureAwait(false); } /// diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs index 4cb34b4e16dd..c98b73edc479 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs @@ -2,9 +2,9 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting { public partial class ConnectOptions where T : class, new() { - public T? Options; - public string? WsEndpoint; public ConnectOptions() { } + public T? Options { get { throw null; } set { } } + public string? WsEndpoint { get { throw null; } set { } } } public partial class PlaywrightService { @@ -15,8 +15,8 @@ public PlaywrightService(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightSe public static string? ServiceEndpoint { get { throw null; } } public bool UseCloudHostedBrowsers { get { throw null; } set { } } public void Cleanup() { } - public System.Threading.Tasks.Task> GetConnectOptionsAsync(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null) where T : class, new() { throw null; } - public System.Threading.Tasks.Task InitializeAsync() { throw null; } + public System.Threading.Tasks.Task> GetConnectOptionsAsync(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null, System.Threading.CancellationToken? cancellationToken = default(System.Threading.CancellationToken?)) where T : class, new() { throw null; } + public System.Threading.Tasks.Task InitializeAsync(System.Threading.CancellationToken? cancellationToken = default(System.Threading.CancellationToken?)) { throw null; } } public partial class PlaywrightServiceOptions { @@ -47,7 +47,7 @@ public partial class ServiceEnvironmentVariable public static readonly string PlaywrightServiceExposeNetwork; public static readonly string PlaywrightServiceOs; public static readonly string PlaywrightServiceRunId; - public static readonly string PlaywrightServiceUrl; + public static readonly string PlaywrightServiceUri; public ServiceEnvironmentVariable() { } } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs index dc094dcd9223..6afe10c4d9e2 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Threading; using System.Threading.Tasks; using Azure.Core; using Azure.Identity; @@ -23,12 +24,12 @@ public EntraLifecycle(TokenCredential? tokenCredential = null, JsonWebTokenHandl SetEntraIdAccessTokenFromEnvironment(); } - internal async Task FetchEntraIdAccessTokenAsync() + internal async Task FetchEntraIdAccessTokenAsync(CancellationToken? cancellationToken = null) { try { var tokenRequestContext = new TokenRequestContext(Constants.s_entra_access_token_scopes); - AccessToken accessToken = await _tokenCredential.GetTokenAsync(tokenRequestContext, default).ConfigureAwait(false); + AccessToken accessToken = await _tokenCredential.GetTokenAsync(tokenRequestContext, cancellationToken ?? default).ConfigureAwait(false); _entraIdAccessToken = accessToken.Token; _entraIdAccessTokenExpiry = accessToken.ExpiresOn.ToUnixTimeSeconds(); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, _entraIdAccessToken); diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs index 7f3d3d509e61..ad985c577d04 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -90,8 +90,9 @@ internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? /// The operating system. /// The run ID. /// The network exposure. + /// Cancellation token. /// The connect options. - public async Task> GetConnectOptionsAsync(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null) where T : class, new() + public async Task> GetConnectOptionsAsync(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, CancellationToken? cancellationToken = null) where T : class, new() { if (Environment.GetEnvironmentVariable(Constants.s_playwright_service_disable_scalable_execution_environment_variable) == "true") throw new Exception(Constants.s_service_endpoint_removed_since_scalable_execution_disabled_error_message); @@ -108,7 +109,7 @@ internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? // 2. Not close to expiry if (!string.IsNullOrEmpty(_entraLifecycle!._entraIdAccessToken) && _entraLifecycle!.DoesEntraIdAccessTokenRequireRotation()) { - _ = await _entraLifecycle.FetchEntraIdAccessTokenAsync().ConfigureAwait(false); + _ = await _entraLifecycle.FetchEntraIdAccessTokenAsync(cancellationToken).ConfigureAwait(false); } if (string.IsNullOrEmpty(GetAuthToken())) { @@ -134,7 +135,7 @@ internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? /// /// Initialises the resources used to setup entra id authentication. /// - public async Task InitializeAsync() + public async Task InitializeAsync(CancellationToken? cancellationToken = null) { if (string.IsNullOrEmpty(ServiceEndpoint)) return; @@ -150,7 +151,7 @@ public async Task InitializeAsync() ValidateMptPAT(); return; } - var operationStatus = await _entraLifecycle!.FetchEntraIdAccessTokenAsync().ConfigureAwait(false); + var operationStatus = await _entraLifecycle!.FetchEntraIdAccessTokenAsync(cancellationToken).ConfigureAwait(false); if (!operationStatus) { if (!string.IsNullOrEmpty(GetAuthToken())) From 2ec69f368b6ef5b1596d4504b1c6990322aed954 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Tue, 17 Sep 2024 14:43:36 +0530 Subject: [PATCH 27/32] refactor(): use default for null cancellation tokens --- ...veloper.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs | 2 +- .../src/PlaywrightServiceNUnit.cs | 2 +- ...er.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs | 4 ++-- .../src/EntraLifecycle.cs | 4 ++-- .../src/PlaywrightService.cs | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs index 4af1077eae46..4c94cbf7f5c0 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs @@ -6,7 +6,7 @@ public partial class PlaywrightServiceNUnit : Azure.Developer.MicrosoftPlaywrigh public PlaywrightServiceNUnit(Azure.Core.TokenCredential? credential = null) : base (default(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions), default(Azure.Core.TokenCredential)) { } public static Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions playwrightServiceOptions { get { throw null; } } [NUnit.Framework.OneTimeSetUpAttribute] - public System.Threading.Tasks.Task SetupAsync(System.Threading.CancellationToken? cancellationToken = default(System.Threading.CancellationToken?)) { throw null; } + public System.Threading.Tasks.Task SetupAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } [NUnit.Framework.OneTimeTearDownAttribute] public void Teardown() { } } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs index e60374993e3f..149b725eeb47 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs @@ -43,7 +43,7 @@ public PlaywrightServiceNUnit(TokenCredential? credential = null) /// Cancellation token. /// [OneTimeSetUp] - public async Task SetupAsync(CancellationToken? cancellationToken = null) + public async Task SetupAsync(CancellationToken cancellationToken = default) { await InitializeAsync(cancellationToken).ConfigureAwait(false); } diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs index c98b73edc479..5f1443ed1b60 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs @@ -15,8 +15,8 @@ public PlaywrightService(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightSe public static string? ServiceEndpoint { get { throw null; } } public bool UseCloudHostedBrowsers { get { throw null; } set { } } public void Cleanup() { } - public System.Threading.Tasks.Task> GetConnectOptionsAsync(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null, System.Threading.CancellationToken? cancellationToken = default(System.Threading.CancellationToken?)) where T : class, new() { throw null; } - public System.Threading.Tasks.Task InitializeAsync(System.Threading.CancellationToken? cancellationToken = default(System.Threading.CancellationToken?)) { throw null; } + public System.Threading.Tasks.Task> GetConnectOptionsAsync(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) where T : class, new() { throw null; } + public System.Threading.Tasks.Task InitializeAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } } public partial class PlaywrightServiceOptions { diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs index 6afe10c4d9e2..0a38f2238053 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs @@ -24,12 +24,12 @@ public EntraLifecycle(TokenCredential? tokenCredential = null, JsonWebTokenHandl SetEntraIdAccessTokenFromEnvironment(); } - internal async Task FetchEntraIdAccessTokenAsync(CancellationToken? cancellationToken = null) + internal async Task FetchEntraIdAccessTokenAsync(CancellationToken cancellationToken = default) { try { var tokenRequestContext = new TokenRequestContext(Constants.s_entra_access_token_scopes); - AccessToken accessToken = await _tokenCredential.GetTokenAsync(tokenRequestContext, cancellationToken ?? default).ConfigureAwait(false); + AccessToken accessToken = await _tokenCredential.GetTokenAsync(tokenRequestContext, cancellationToken).ConfigureAwait(false); _entraIdAccessToken = accessToken.Token; _entraIdAccessTokenExpiry = accessToken.ExpiresOn.ToUnixTimeSeconds(); Environment.SetEnvironmentVariable(ServiceEnvironmentVariable.PlaywrightServiceAccessToken, _entraIdAccessToken); diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs index ad985c577d04..58a0eb290bc7 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs @@ -92,7 +92,7 @@ internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? /// The network exposure. /// Cancellation token. /// The connect options. - public async Task> GetConnectOptionsAsync(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, CancellationToken? cancellationToken = null) where T : class, new() + public async Task> GetConnectOptionsAsync(OSPlatform? os = null, string? runId = null, string? exposeNetwork = null, CancellationToken cancellationToken = default) where T : class, new() { if (Environment.GetEnvironmentVariable(Constants.s_playwright_service_disable_scalable_execution_environment_variable) == "true") throw new Exception(Constants.s_service_endpoint_removed_since_scalable_execution_disabled_error_message); @@ -135,7 +135,7 @@ internal PlaywrightService(OSPlatform? os = null, string? runId = null, string? /// /// Initialises the resources used to setup entra id authentication. /// - public async Task InitializeAsync(CancellationToken? cancellationToken = null) + public async Task InitializeAsync(CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(ServiceEndpoint)) return; From 2649d4c70248d863648a0ee4eda187b136f8e17c Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Fri, 20 Sep 2024 12:11:24 +0530 Subject: [PATCH 28/32] refactor(): added users in CODEOWNERS --- .github/CODEOWNERS | 2 +- eng/Packages.Data.props | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4420ef5abe8b..38a50249faa4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -759,7 +759,7 @@ /sdk/playwrighttesting/ @Sid200026 @puagarwa @ShreyaAnand # ServiceLabel: %Microsoft Playwright Testing -# ServiceOwners: @shreyaanand @mjmadhu +# ServiceOwners: @Sid200026 @puagarwa @ShreyaAnand # ServiceLabel: %Policy # ServiceOwners: @aperezcloud @kenieva diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index d67fef2b0a5c..1cb7e5e28fa5 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -182,6 +182,11 @@ + + + + + on how to configurate different Azure Identity credentials. + ### Prerequisites - An [Azure subscription](https://azure.microsoft.com/free/dotnet/) @@ -26,6 +30,20 @@ dotnet add package Azure.Developer.MicrosoftPlaywrightTesting --prerelease - [Pricing](https://aka.ms/mpt/pricing) - [Share feedback](https://aka.ms/mpt/feedback) +## Key concepts + +Key concepts of the Microsoft Playwright Testing NUnit SDK for .NET can be found [here](https://aka.ms/mpt/what-is-mpt) + +## Examples + +Code samples for using this SDK can be found in the following locations +- [.NET Microsoft Playwright Testing NUnit Library Code Samples](https://aka.ms/mpt/sample) + +## Troubleshooting + +- File an issue via [GitHub Issues](https://github.com/Azure/azure-sdk-for-net/issues). +- Check [previous questions](https://stackoverflow.com/questions/tagged/azure+.net) or ask new ones on Stack Overflow using Azure and .NET tags. + ## Next steps - Run tests in a [CI/CD pipeline.](https://aka.ms/mpt/configure-pipeline) From 2d0b53cdf8936c5d207539a3e0a47c2555ac8075 Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Tue, 24 Sep 2024 01:39:49 +0530 Subject: [PATCH 31/32] refactor(): rename base package to Azure.Developer.MicrosoftPlaywrightTesting.TestLogger --- ...tPlaywrightTesting.NUnit.netstandard2.0.cs | 6 ++-- ...er.MicrosoftPlaywrightTesting.NUnit.csproj | 34 +++++++++---------- .../src/PlaywrightServiceNUnit.cs | 1 + ...MicrosoftPlaywrightTesting.TestLogger.sln} | 13 ++++--- .../CHANGELOG.md | 0 .../Directory.Build.props | 0 .../README.md | 4 +-- ...wrightTesting.TestLogger.netstandard2.0.cs | 6 ++-- .../src/AssemblyInfo.cs | 4 +-- ...crosoftPlaywrightTesting.TestLogger.csproj | 22 ++++++++++++ .../src}/Client/Internal/Argument.cs | 0 .../src}/Client/ReportingTestResultsClient.cs | 0 .../src}/Client/ReportingTestRunsClient.cs | 0 .../src}/Client/TestReportingClientOptions.cs | 0 .../src/ConnectOptions.cs | 2 +- .../src/Constants.cs | 2 +- .../src/EntraLifecycle.cs | 2 +- .../src}/Model/CIInfo.cs | 0 .../src}/Model/MPTResult.cs | 0 .../src}/Model/TestReporting.cs | 0 .../src}/PlaywrightReporter.cs | 0 .../src/PlaywrightService.cs | 2 +- .../src/PlaywrightServiceOptions.cs | 2 +- .../src}/Utility/CiInfoProvider.cs | 0 .../src}/Utility/Constants.cs | 0 .../src}/Utility/Logger.cs | 0 .../src}/Utility/ReporterUtils.cs | 0 ...PlaywrightTesting.TestLogger.Tests.csproj} | 2 +- .../tests/EntraLifecycleTests.cs | 2 +- .../tests/PlaywrightServiceClientTests.cs | 2 +- .../tests/PlaywrightServiceOptionsTest.cs | 3 +- .../tests/PlaywrightServiceTestEnvironment.cs | 2 +- .../tests/PlaywrightServiceTests.cs | 2 +- .../tests/TestUtils.cs | 2 +- ...eveloper.MicrosoftPlaywrightTesting.csproj | 27 --------------- sdk/playwrighttesting/ci.yml | 4 +-- 36 files changed, 72 insertions(+), 74 deletions(-) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/Azure.Developer.MicrosoftPlaywrightTesting.sln => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.sln} (67%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/CHANGELOG.md (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/Directory.Build.props (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/README.md (96%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs (85%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/src/AssemblyInfo.cs (61%) create mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.csproj rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Client/Internal/Argument.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Client/ReportingTestResultsClient.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Client/ReportingTestRunsClient.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Client/TestReportingClientOptions.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/src/ConnectOptions.cs (95%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/src/Constants.cs (99%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/src/EntraLifecycle.cs (97%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Model/CIInfo.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Model/MPTResult.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Model/TestReporting.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/PlaywrightReporter.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/src/PlaywrightService.cs (99%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/src/PlaywrightServiceOptions.cs (98%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Utility/CiInfoProvider.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Utility/Constants.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Utility/Logger.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src}/Utility/ReporterUtils.cs (100%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests.csproj} (93%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/tests/EntraLifecycleTests.cs (99%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/tests/PlaywrightServiceClientTests.cs (97%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/tests/PlaywrightServiceOptionsTest.cs (97%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/tests/PlaywrightServiceTestEnvironment.cs (83%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/tests/PlaywrightServiceTests.cs (99%) rename sdk/playwrighttesting/{Azure.Developer.MicrosoftPlaywrightTesting => Azure.Developer.MicrosoftPlaywrightTesting.TestLogger}/tests/TestUtils.cs (88%) delete mode 100644 sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs index 4c94cbf7f5c0..7e6eac3ac4c3 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/api/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.netstandard2.0.cs @@ -1,10 +1,10 @@ namespace Azure.Developer.MicrosoftPlaywrightTesting.NUnit { [NUnit.Framework.SetUpFixtureAttribute] - public partial class PlaywrightServiceNUnit : Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightService + public partial class PlaywrightServiceNUnit : Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.PlaywrightService { - public PlaywrightServiceNUnit(Azure.Core.TokenCredential? credential = null) : base (default(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions), default(Azure.Core.TokenCredential)) { } - public static Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions playwrightServiceOptions { get { throw null; } } + public PlaywrightServiceNUnit(Azure.Core.TokenCredential? credential = null) : base (default(Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.PlaywrightServiceOptions), default(Azure.Core.TokenCredential)) { } + public static Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.PlaywrightServiceOptions playwrightServiceOptions { get { throw null; } } [NUnit.Framework.OneTimeSetUpAttribute] public System.Threading.Tasks.Task SetupAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } [NUnit.Framework.OneTimeTearDownAttribute] diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj index f6d2849191fc..bd1387373538 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/Azure.Developer.MicrosoftPlaywrightTesting.NUnit.csproj @@ -1,19 +1,19 @@  - - Azure, Cloud, Playwright, Playwright Service, Reporting, Playwright Testing - - Package to integrate your Playwright test suite with Microsoft Playwright Testing - service - - 1.0.0-beta.1 - 1.0.0-beta.1 - true - $(RequiredTargetFrameworks) - enable - - - - - + + Azure, Cloud, Playwright, Playwright Service, Reporting, Playwright Testing + + Package to integrate your Playwright test suite with Microsoft Playwright Testing + service + + 1.0.0-beta.1 + 1.0.0-beta.1 + true + $(RequiredTargetFrameworks) + enable + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs index 149b725eeb47..46141565b2e9 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/src/PlaywrightServiceNUnit.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Threading; +using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; namespace Azure.Developer.MicrosoftPlaywrightTesting.NUnit; diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Azure.Developer.MicrosoftPlaywrightTesting.sln b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.sln similarity index 67% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Azure.Developer.MicrosoftPlaywrightTesting.sln rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.sln index fdf740cc6ede..127dd846d079 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Azure.Developer.MicrosoftPlaywrightTesting.sln +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.sln @@ -3,18 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Developer.MicrosoftPlaywrightTesting", "src\Azure.Developer.MicrosoftPlaywrightTesting.csproj", "{2C1F9880-AD7D-433E-A73E-43F503772CD8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Developer.MicrosoftPlaywrightTesting.TestLogger", "src\Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.csproj", "{2C1F9880-AD7D-433E-A73E-43F503772CD8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Developer.MicrosoftPlaywrightTesting.Tests", "tests\Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj", "{6C78D318-9B96-43B4-97A7-7B3C8088983C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests", "tests\Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests.csproj", "{6C78D318-9B96-43B4-97A7-7B3C8088983C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2C1F9880-AD7D-433E-A73E-43F503772CD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2C1F9880-AD7D-433E-A73E-43F503772CD8}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -25,4 +22,10 @@ Global {6C78D318-9B96-43B4-97A7-7B3C8088983C}.Release|Any CPU.ActiveCfg = Release|Any CPU {6C78D318-9B96-43B4-97A7-7B3C8088983C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C3BE422E-8FFF-4EF8-BA89-186F153965D8} + EndGlobalSection EndGlobal diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/CHANGELOG.md similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/CHANGELOG.md rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/CHANGELOG.md diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Directory.Build.props b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/Directory.Build.props similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/Directory.Build.props rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/Directory.Build.props diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/README.md similarity index 96% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/README.md index e115142ed2c8..34bbeced75f6 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/README.md @@ -9,7 +9,7 @@ Microsoft Playwright Testing is a fully managed service that uses the cloud to e Install the client library for .NET with [NuGet](https://www.nuget.org/): ```dotnetcli -dotnet add package Azure.Developer.MicrosoftPlaywrightTesting --prerelease +dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.TestLogger --prerelease ``` ### Authenticate the client @@ -63,4 +63,4 @@ This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For more information see the [Code of Conduct FAQ][coc_faq] or contact [opencode@microsoft.com][coc_contact] with any additional questions or comments. -![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/README.png) \ No newline at end of file +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/README.png) \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs similarity index 85% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs index 5f1443ed1b60..0880153e7dc9 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/api/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.netstandard2.0.cs @@ -1,4 +1,4 @@ -namespace Azure.Developer.MicrosoftPlaywrightTesting +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger { public partial class ConnectOptions where T : class, new() { @@ -8,14 +8,14 @@ public ConnectOptions() { } } public partial class PlaywrightService { - public PlaywrightService(Azure.Developer.MicrosoftPlaywrightTesting.PlaywrightServiceOptions playwrightServiceOptions, Azure.Core.TokenCredential? credential = null) { } + public PlaywrightService(Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.PlaywrightServiceOptions playwrightServiceOptions, Azure.Core.TokenCredential? credential = null) { } public PlaywrightService(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null, string? serviceAuth = null, bool? useCloudHostedBrowsers = default(bool?), Azure.Core.TokenCredential? credential = null) { } public System.Threading.Timer? RotationTimer { get { throw null; } set { } } public string ServiceAuth { get { throw null; } set { } } public static string? ServiceEndpoint { get { throw null; } } public bool UseCloudHostedBrowsers { get { throw null; } set { } } public void Cleanup() { } - public System.Threading.Tasks.Task> GetConnectOptionsAsync(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) where T : class, new() { throw null; } + public System.Threading.Tasks.Task> GetConnectOptionsAsync(System.Runtime.InteropServices.OSPlatform? os = default(System.Runtime.InteropServices.OSPlatform?), string? runId = null, string? exposeNetwork = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) where T : class, new() { throw null; } public System.Threading.Tasks.Task InitializeAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } } public partial class PlaywrightServiceOptions diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/AssemblyInfo.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/AssemblyInfo.cs similarity index 61% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/AssemblyInfo.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/AssemblyInfo.cs index a3e47e75d0c2..a50e22574711 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/AssemblyInfo.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/AssemblyInfo.cs @@ -3,5 +3,5 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("Azure.Developer.MicrosoftPlaywrightTesting.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] \ No newline at end of file +[assembly: InternalsVisibleTo("Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.csproj new file mode 100644 index 000000000000..547bab277e25 --- /dev/null +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.csproj @@ -0,0 +1,22 @@ + + + Azure, Cloud, Playwright, Playwright Service, Reporting, Playwright Testing + + Package to integrate your Playwright test suite with Microsoft Playwright Testing + service + + 1.0.0-beta.1 + 1.0.0-beta.1 + true + $(RequiredTargetFrameworks) + enable + true + + + + + + + + + \ No newline at end of file diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/Internal/Argument.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Client/Internal/Argument.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/Internal/Argument.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Client/Internal/Argument.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Client/ReportingTestResultsClient.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestResultsClient.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Client/ReportingTestResultsClient.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Client/ReportingTestRunsClient.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/ReportingTestRunsClient.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Client/ReportingTestRunsClient.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClientOptions.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Client/TestReportingClientOptions.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Client/TestReportingClientOptions.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Client/TestReportingClientOptions.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/ConnectOptions.cs similarity index 95% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/ConnectOptions.cs index 2f63d5bc5bbf..7b0b6e1fc17a 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/ConnectOptions.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/ConnectOptions.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; -namespace Azure.Developer.MicrosoftPlaywrightTesting; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; /// /// Represents the connect options for a generic type. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Constants.cs similarity index 99% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Constants.cs index 99682b72b27b..4b1f0b43a2bb 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Constants.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Constants.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -namespace Azure.Developer.MicrosoftPlaywrightTesting; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; /// /// Contains environment variable names used by the Playwright service. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/EntraLifecycle.cs similarity index 97% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/EntraLifecycle.cs index 0a38f2238053..a1c669902065 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/EntraLifecycle.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/EntraLifecycle.cs @@ -8,7 +8,7 @@ using Azure.Identity; using Microsoft.IdentityModel.JsonWebTokens; -namespace Azure.Developer.MicrosoftPlaywrightTesting; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; internal class EntraLifecycle { diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/CIInfo.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Model/CIInfo.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/CIInfo.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Model/CIInfo.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Model/MPTResult.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/MPTResult.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Model/MPTResult.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/TestReporting.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Model/TestReporting.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Model/TestReporting.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Model/TestReporting.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/PlaywrightReporter.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/PlaywrightReporter.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/PlaywrightReporter.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/PlaywrightService.cs similarity index 99% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/PlaywrightService.cs index 58a0eb290bc7..66e8c3866880 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightService.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/PlaywrightService.cs @@ -12,7 +12,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Azure.Developer.MicrosoftPlaywrightTesting; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; /// /// Sets up and manages the Playwright service. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/PlaywrightServiceOptions.cs similarity index 98% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/PlaywrightServiceOptions.cs index ba20721b7e6e..cda80ce6fc29 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/PlaywrightServiceOptions.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/PlaywrightServiceOptions.cs @@ -5,7 +5,7 @@ using Azure.Core; using Azure.Identity; -namespace Azure.Developer.MicrosoftPlaywrightTesting; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger; /// /// Options for the Playwright service. diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/CiInfoProvider.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Utility/CiInfoProvider.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/CiInfoProvider.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Utility/CiInfoProvider.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Utility/Constants.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Constants.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Utility/Constants.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Logger.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Utility/Logger.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/Logger.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Utility/Logger.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Utility/ReporterUtils.cs similarity index 100% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/TestLogger/Utility/ReporterUtils.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Utility/ReporterUtils.cs diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests.csproj similarity index 93% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests.csproj index d339be265b32..60229ecd863c 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/Azure.Developer.MicrosoftPlaywrightTesting.Tests.csproj +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/EntraLifecycleTests.cs similarity index 99% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/EntraLifecycleTests.cs index 6959a949c4ef..62930afb0fff 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/EntraLifecycleTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/EntraLifecycleTests.cs @@ -11,7 +11,7 @@ using Microsoft.IdentityModel.Tokens; using Moq; -namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests; [TestFixture] public class EntraLifecycleTests diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceClientTests.cs similarity index 97% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceClientTests.cs index d3da77a3c294..a1896981a53c 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceClientTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceClientTests.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using Azure.Core.TestFramework; -namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests; public class PlaywrightServiceClientTests : RecordedTestBase { diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceOptionsTest.cs similarity index 97% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceOptionsTest.cs index 6467088dbacd..be5afa3adc51 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceOptionsTest.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceOptionsTest.cs @@ -2,11 +2,10 @@ // Licensed under the MIT License. using Azure.Identity; -using Azure.Developer.MicrosoftPlaywrightTesting; using System; using System.Runtime.InteropServices; -namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests; [TestFixture] [Parallelizable(ParallelScope.Self)] diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTestEnvironment.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceTestEnvironment.cs similarity index 83% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTestEnvironment.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceTestEnvironment.cs index 6fc1a455403a..dbd0ca3ff17b 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTestEnvironment.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceTestEnvironment.cs @@ -3,7 +3,7 @@ using Azure.Core.TestFramework; -namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests; public class PlaywrightServiceTestEnvironment : TestEnvironment { diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceTests.cs similarity index 99% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceTests.cs index 72598ed3e188..8e1ab574e980 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/PlaywrightServiceTests.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/PlaywrightServiceTests.cs @@ -13,7 +13,7 @@ using Microsoft.IdentityModel.Tokens; using Moq; -namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests; [TestFixture] [Parallelizable(ParallelScope.Self)] diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/TestUtils.cs b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/TestUtils.cs similarity index 88% rename from sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/TestUtils.cs rename to sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/TestUtils.cs index 0d884ef39cad..52308c93a16c 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/tests/TestUtils.cs +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/TestUtils.cs @@ -3,7 +3,7 @@ using System.Linq; -namespace Azure.Developer.MicrosoftPlaywrightTesting.Tests; +namespace Azure.Developer.MicrosoftPlaywrightTesting.TestLogger.Tests; public class TestUtils { diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj deleted file mode 100644 index 81ff3d628bfb..000000000000 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting/src/Azure.Developer.MicrosoftPlaywrightTesting.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - Azure.Developer.MicrosoftPlaywrightTesting - Azure.Developer.MicrosoftPlaywrightTesting - Azure.Developer.MicrosoftPlaywrightTesting - - Azure.Developer.MicrosoftPlaywrightTesting.TestLogger - Azure, Cloud, Playwright, Playwright Service, Reporting, Playwright Testing - - Package to integrate your Playwright test suite with Microsoft Playwright Testing - service - - 1.0.0-beta.1 - 1.0.0-beta.1 - true - $(RequiredTargetFrameworks) - enable - true - - - - - - - - - \ No newline at end of file diff --git a/sdk/playwrighttesting/ci.yml b/sdk/playwrighttesting/ci.yml index 3ec09b524cef..c36cc48c299d 100644 --- a/sdk/playwrighttesting/ci.yml +++ b/sdk/playwrighttesting/ci.yml @@ -34,8 +34,8 @@ extends: Artifacts: - name: Azure.Developer.MicrosoftPlaywrightTesting.NUnit safeName: AzureDeveloperMicrosoftPlaywrightTestingNUnit - - name: Azure.Developer.MicrosoftPlaywrightTesting - safeName: AzureDeveloperMicrosoftPlaywrightTesting + - name: Azure.Developer.MicrosoftPlaywrightTesting.TestLogger + safeName: AzureDeveloperMicrosoftPlaywrightTesting.TestLogger From a831d187f88e11ac9507bbf84e9cb64541533c3c Mon Sep 17 00:00:00 2001 From: Siddharth Singha Roy Date: Tue, 24 Sep 2024 03:25:53 +0530 Subject: [PATCH 32/32] docs(): move authenticate client section after prerequisites --- .../README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md index 60c52428ffb3..bbca4b74ad9d 100644 --- a/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md +++ b/sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.NUnit/README.md @@ -26,6 +26,10 @@ dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit --prerelease - An [Azure subscription](https://azure.microsoft.com/free/dotnet/) - Your Azure account must be assigned the [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles). +### Authenticate the client + +To learn more about options for Microsoft Entra Id authentication, refer to [Azure.Identity credentials](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/identity/Azure.Identity#credentials). You can also refer to [our samples] on how to configurate different Azure Identity credentials. + #### Create a Workspace 1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account. @@ -72,10 +76,6 @@ public class PlaywrightServiceSetup : PlaywrightServiceNUnit {}; Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is available in your environment. -### Authenticate the client - -To learn more about options for Microsoft Entra Id authentication, refer to [Azure.Identity credentials](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/identity/Azure.Identity#credentials). You can also refer to [our samples] on how to configurate different Azure Identity credentials. - ### Run the tests Run Playwright tests against browsers managed by the service using the configuration you created above.