Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure build is shared across all test classes #12

Merged
merged 30 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions visual-dotnet/SauceLabs.Visual.Tests/VisualApiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace SauceLabs.Visual.Tests;

public class VisualApiTest
{
internal VisualApi<MockedWebDriver>? Api { get; set; }
internal VisualApi? Api { get; set; }
internal MockedWebDriver? WdMock { get; set; }
internal MockHttpMessageHandler? MockedHandler { get; set; }

Expand All @@ -27,7 +27,7 @@ public void Setup()

var caps = new MockedCapabilities(new Dictionary<string, object> { { "jobUuid", _jobUuid } });
WdMock = new MockedWebDriver(caps, _jobUuid);
Api = new VisualApi<MockedWebDriver>(WdMock, Region.Staging, _username, _accessKey, MockedHandler.ToHttpClient());
Api = new VisualApi(Region.Staging, _username, _accessKey, MockedHandler.ToHttpClient());
}

[Test]
Expand Down
13 changes: 10 additions & 3 deletions visual-dotnet/SauceLabs.Visual/VisualApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,28 @@
using GraphQL.Client.Http;
using GraphQL.Client.Serializer.Newtonsoft;
using Newtonsoft.Json;
using OpenQA.Selenium;
using SauceLabs.Visual.GraphQL;
using SauceLabs.Visual.Utils;

namespace SauceLabs.Visual
{
internal class VisualApi<T> : IDisposable where T : IHasCapabilities, IHasSessionId
internal class VisualApi : IDisposable
{
private readonly Region _region;
private readonly string _username;
private readonly string _accessKey;
private readonly GraphQLHttpClient _graphQlClient;

public VisualApi(T webdriver, Region region, string username, string accessKey, HttpClient? httpClient = null)
public VisualApi(Region region, string username, string accessKey, HttpClient? httpClient = null)
{

if (StringUtils.IsNullOrEmpty(username) || StringUtils.IsNullOrEmpty(accessKey))
{
throw new VisualClientException(
"Invalid SauceLabs credentials. Please check your SauceLabs username and access key at https://app.saucelabs.com/user-setting");
}

_region = region;
_username = username.Trim();
_accessKey = accessKey.Trim();

Expand Down Expand Up @@ -117,5 +119,10 @@ public void Dispose()
{
_graphQlClient.Dispose();
}

internal VisualApi Clone()
{
return new VisualApi(_region, _username, _accessKey);
}
}
}
5 changes: 5 additions & 0 deletions visual-dotnet/SauceLabs.Visual/VisualBuild.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;
using System.Threading.Tasks;
using SauceLabs.Visual.Models;

namespace SauceLabs.Visual
Expand All @@ -12,6 +14,9 @@ public class VisualBuild

public BuildMode Mode { get; internal set; }

internal bool IsExternal { get; set; } = false;
FriggaHel marked this conversation as resolved.
Show resolved Hide resolved
internal Func<Task>? Close;

internal VisualBuild(string id, string url, BuildMode mode)
{
Id = id;
Expand Down
2 changes: 1 addition & 1 deletion visual-dotnet/SauceLabs.Visual/VisualCheckOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class VisualCheckOptions

internal void EnsureTestContextIsPopulated(string callerMemberName, string? previousSuiteName)
{
if (string.IsNullOrEmpty(callerMemberName) || HasIncompleteTestContext())
if (string.IsNullOrEmpty(callerMemberName) || !HasIncompleteTestContext())
FriggaHel marked this conversation as resolved.
Show resolved Hide resolved
{
return;
}
Expand Down
49 changes: 36 additions & 13 deletions visual-dotnet/SauceLabs.Visual/VisualClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
/// </summary>
public class VisualClient : IDisposable
{
private readonly VisualApi<WebDriver> _api;
private static VisualBuild? _sharedBuild;

private readonly VisualApi _api;
private readonly string _sessionId;
private readonly string _jobId;
private string? _sessionMetadataBlob;
private readonly List<string> _screenshotIds = new List<string>();
public VisualBuild Build { get; private set; }
private bool _externalBuild;

Check warning on line 28 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

The field 'VisualClient._externalBuild' is never used

Check warning on line 28 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

The field 'VisualClient._externalBuild' is never used

Check warning on line 28 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

The field 'VisualClient._externalBuild' is never used

Check warning on line 28 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

The field 'VisualClient._externalBuild' is never used
public bool CaptureDom { get; set; } = false;
private readonly ResiliencePipeline _retryPipeline;

Expand Down Expand Up @@ -79,10 +81,16 @@

private async Task SetupBuild(CreateBuildOptions buildOptions)
{
var response = await this._api.WebDriverSessionInfo(_jobId, _sessionId);
var response = await _api.WebDriverSessionInfo(_jobId, _sessionId);
var metadata = response.EnsureValidResponse();
_sessionMetadataBlob = metadata.Result.Blob;

if (_sharedBuild != null)
FriggaHel marked this conversation as resolved.
Show resolved Hide resolved
{
Build = _sharedBuild;
return;
}

var build = await GetEffectiveBuild(EnvVars.BuildId, EnvVars.CustomId);
if (build != null)
{
Expand All @@ -91,15 +99,24 @@
throw new VisualClientException($"build {build.Id} is not RUNNING");
}
Build = build;
_externalBuild = true;
Build.IsExternal = true;
_sharedBuild = Build;
return;
}
else

buildOptions.CustomId ??= EnvVars.CustomId;
var createBuildResponse = await CreateBuild(buildOptions);
Build = new VisualBuild(createBuildResponse.Id, createBuildResponse.Url, createBuildResponse.Mode)
{
buildOptions.CustomId ??= EnvVars.CustomId;
var createBuildResponse = await CreateBuild(buildOptions);
Build = new VisualBuild(createBuildResponse.Id, createBuildResponse.Url, createBuildResponse.Mode);
_externalBuild = false;
}
IsExternal = false
};
var copiedApi = _api.Clone();
FriggaHel marked this conversation as resolved.
Show resolved Hide resolved
Build.Close = async () =>
{
await copiedApi.FinishBuild(Build.Id);
copiedApi.Dispose();
};
_sharedBuild = Build;
}

/// <summary>
Expand All @@ -109,14 +126,14 @@
/// <param name="region">the Sauce Labs region to connect to</param>
/// <param name="username">the Sauce Labs username</param>
/// <param name="accessKey">the Sauce Labs access key</param>
private VisualClient(WebDriver wd, Region region, string username, string accessKey)

Check warning on line 129 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Build' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 129 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Build' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 129 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Build' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 129 in visual-dotnet/SauceLabs.Visual/VisualClient.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Build' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
{
if (StringUtils.IsNullOrEmpty(username) || StringUtils.IsNullOrEmpty(accessKey))
{
throw new VisualClientException("Username or Access Key not set");
}

_api = new VisualApi<WebDriver>(wd, region, username, accessKey);
_api = new VisualApi(region, username, accessKey);
_sessionId = wd.SessionId.ToString();
_jobId = wd.Capabilities.HasCapability("jobUuid") ? wd.Capabilities.GetCapability("jobUuid").ToString() : _sessionId;

Expand Down Expand Up @@ -258,11 +275,17 @@
/// <summary>
/// <c>Cleanup</c> set a correct status to the build. No action should be made after that calling <c>Cleanup</c>.
/// </summary>
public async Task Cleanup()
public static async Task Cleanup()
{
if (!_externalBuild)
if (_sharedBuild == null)
{
return;
}

if (_sharedBuild.Close != null)
{
await FinishBuild(Build);
await _sharedBuild.Close();
_sharedBuild = null;
}
}

Expand Down