Skip to content

Commit cf787a1

Browse files
authored
feat(playwrighttesting): Add support to publish attachments (Azure#46780)
* Add support to upload attachments * fix tests * minor comments fixes
1 parent 02c5753 commit cf787a1

File tree

3 files changed

+90
-11
lines changed

3 files changed

+90
-11
lines changed

sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Processor/TestProcessor.cs

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ internal class TestProcessor : ITestProcessor
3434
internal int PassedTestCount { get; set; } = 0;
3535
internal int FailedTestCount { get; set; } = 0;
3636
internal int SkippedTestCount { get; set; } = 0;
37+
internal int TotalArtifactCount { get; set; } = 0;
38+
internal int TotalArtifactSizeInBytes { get; set; } = 0;
3739
internal List<TestResults> TestResults { get; set; } = new List<TestResults>();
3840
internal ConcurrentDictionary<string, RawTestResult?> RawTestResultsMap { get; set; } = new();
3941
internal bool FatalTestExecution { get; set; } = false;
4042
internal TestRunShardDto? _testRunShard;
43+
internal TestResultsUri? _testResultsSasUri;
4144

4245
public TestProcessor(CloudRunMetadata cloudRunMetadata, CIInfo cIInfo, ILogger? logger = null, IDataProcessor? dataProcessor = null, ICloudRunErrorParser? cloudRunErrorParser = null, IServiceClient? serviceClient = null, IConsoleWriter? consoleWriter = null)
4346
{
@@ -93,15 +96,22 @@ public void TestCaseResultHandler(object? sender, TestResultEventArgs e)
9396
TestResult testResultSource = e.Result;
9497
TestResults? testResult = _dataProcessor.GetTestCaseResultData(testResultSource);
9598
RawTestResult rawResult = DataProcessor.GetRawResultObject(testResultSource);
96-
RawTestResultsMap.TryAdd(testResult.TestExecutionId, rawResult);
9799

98100
// TODO - Send error to blob
99101
_cloudRunErrorParser.HandleScalableRunErrorMessage(testResultSource.ErrorMessage);
100102
_cloudRunErrorParser.HandleScalableRunErrorMessage(testResultSource.ErrorStackTrace);
101-
if (!_cloudRunMetadata.EnableResultPublish)
103+
if (!_cloudRunMetadata.EnableResultPublish || FatalTestExecution)
102104
{
103105
return;
104106
}
107+
108+
// TODO move rawResult upload here same as JS
109+
RawTestResultsMap.TryAdd(testResult.TestExecutionId, rawResult);
110+
111+
// Upload Attachments
112+
UploadAttachment(e, testResult.TestExecutionId);
113+
114+
// Update Test Count
105115
if (testResult != null)
106116
{
107117
TotalTestCount++;
@@ -143,20 +153,15 @@ public void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e)
143153
}
144154
try
145155
{
146-
TestResultsUri? sasUri = _serviceClient.GetTestRunResultsUri();
156+
TestResultsUri? sasUri = CheckAndRenewSasUri();
147157
if (!string.IsNullOrEmpty(sasUri?.Uri))
148158
{
149159
foreach (TestResults testResult in TestResults)
150160
{
151161
if (RawTestResultsMap.TryGetValue(testResult.TestExecutionId!, out RawTestResult? rawResult) && rawResult != null)
152162
{
153163
// Renew the SAS URI if needed
154-
var reporterUtils = new ReporterUtils();
155-
if (sasUri == null || !reporterUtils.IsTimeGreaterThanCurrentPlus10Minutes(sasUri.Uri))
156-
{
157-
sasUri = _serviceClient.GetTestRunResultsUri(); // Create new SAS URI
158-
_logger.Info($"Fetched SAS URI with validity: {sasUri?.ExpiresAt} and access: {sasUri?.AccessLevel}.");
159-
}
164+
sasUri = CheckAndRenewSasUri();
160165
if (sasUri == null)
161166
{
162167
_logger.Warning("SAS URI is empty");
@@ -189,6 +194,60 @@ public void TestRunCompleteHandler(object? sender, TestRunCompleteEventArgs e)
189194
}
190195

191196
#region Test Processor Helper Methods
197+
198+
private void UploadAttachment(TestResultEventArgs e, string testExecutionId)
199+
{
200+
_testResultsSasUri = CheckAndRenewSasUri();
201+
if (e.Result.Attachments != null)
202+
{
203+
foreach (var attachmentSet in e.Result.Attachments)
204+
{
205+
foreach (var attachmentData in attachmentSet.Attachments)
206+
{
207+
var filePath = attachmentData.Uri.LocalPath;
208+
_logger.Info($"Uploading attachment: {filePath}");
209+
if (!File.Exists( filePath ))
210+
{
211+
_logger.Error($"Attachment file not found: {filePath}");
212+
continue;
213+
}
214+
try
215+
{
216+
// get file size
217+
var fileSize = new FileInfo(filePath).Length;
218+
var cloudFileName = ReporterUtils.GetCloudFileName(filePath, testExecutionId);
219+
if (cloudFileName != null) {
220+
UploadBlobFile(_testResultsSasUri!.Uri!, cloudFileName, filePath);
221+
TotalArtifactCount++;
222+
TotalArtifactSizeInBytes = TotalArtifactSizeInBytes + (int)fileSize;
223+
}
224+
else
225+
{
226+
_logger.Error($"Attachment file Upload Failed: {filePath}");
227+
}
228+
}
229+
catch (Exception ex)
230+
{
231+
var error = $"Cannot Upload '{filePath}' file: {ex.Message}";
232+
233+
_logger.Error(error);
234+
}
235+
}
236+
}
237+
}
238+
}
239+
240+
private TestResultsUri? CheckAndRenewSasUri()
241+
{
242+
var reporterUtils = new ReporterUtils();
243+
if (_testResultsSasUri == null || !reporterUtils.IsTimeGreaterThanCurrentPlus10Minutes(_testResultsSasUri.Uri))
244+
{
245+
_testResultsSasUri = _serviceClient.GetTestRunResultsUri();
246+
_logger.Info($"Fetched SAS URI with validity: {_testResultsSasUri?.ExpiresAt} and access: {_testResultsSasUri?.AccessLevel}.");
247+
}
248+
return _testResultsSasUri;
249+
}
250+
192251
private void EndTestRun(TestRunCompleteEventArgs e)
193252
{
194253
if (_cloudRunMetadata.EnableResultPublish && !FatalTestExecution)
@@ -227,6 +286,16 @@ private void UploadBuffer(string uri, string buffer, string fileRelativePath)
227286
blobClient.Upload(new BinaryData(bufferBytes), overwrite: true);
228287
_logger.Info($"Uploaded buffer to {fileRelativePath}");
229288
}
289+
290+
private void UploadBlobFile(string uri, string fileRelativePath, string filePath)
291+
{
292+
string cloudFilePath = GetCloudFilePath(uri, fileRelativePath);
293+
BlobClient blobClient = new(new Uri(cloudFilePath));
294+
// Upload filePath to Blob
295+
blobClient.Upload(filePath, overwrite: true);
296+
_logger.Info($"Uploaded file {filePath} to {fileRelativePath}");
297+
}
298+
230299
private TestRunShardDto GetTestRunEndShard(TestRunCompleteEventArgs e)
231300
{
232301
DateTime testRunEndedOn = DateTime.UtcNow;
@@ -247,7 +316,7 @@ private TestRunShardDto GetTestRunEndShard(TestRunCompleteEventArgs e)
247316
testRunShard.Summary.StartTime = _cloudRunMetadata.TestRunStartTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
248317
testRunShard.Summary.EndTime = testRunEndedOn.ToString("yyyy-MM-ddTHH:mm:ssZ");
249318
testRunShard.Summary.TotalTime = durationInMs;
250-
testRunShard.Summary.UploadMetadata = new UploadMetadata() { NumTestResults = TotalTestCount, NumTotalAttachments = 0, SizeTotalAttachments = 0 };
319+
testRunShard.Summary.UploadMetadata = new UploadMetadata() { NumTestResults = TotalTestCount, NumTotalAttachments = TotalArtifactCount, SizeTotalAttachments = TotalArtifactSizeInBytes };
251320
testRunShard.UploadCompleted = true;
252321
return testRunShard;
253322
}

sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/src/Utility/ReporterUtils.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Diagnostics;
6+
using System.IO;
67
using System.Linq;
78
using System.Security.Cryptography;
89
using System.Threading.Tasks;
@@ -114,6 +115,15 @@ internal static string GetCurrentOS()
114115
else
115116
return OSConstants.s_wINDOWS;
116117
}
118+
internal static string? GetCloudFileName(string filePath, string testExecutionId)
119+
{
120+
var fileName = Path.GetFileName(filePath);
121+
if (fileName == null)
122+
{
123+
return null;
124+
}
125+
return $"{testExecutionId}/{fileName}"; // TODO check if we need to add {Guid.NewGuid()} for file with same name
126+
}
117127

118128
internal TokenDetails ParseWorkspaceIdFromAccessToken(JsonWebTokenHandler? jsonWebTokenHandler, string? accessToken)
119129
{

sdk/playwrighttesting/Azure.Developer.MicrosoftPlaywrightTesting.TestLogger/tests/Processor/TestProcessorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ public void TestCaseResultHandler_EnableResultPublishFalse_OnlyParseScalableErro
355355
testProcessor.TestCaseResultHandler(sender, new TestResultEventArgs(testResult));
356356

357357
Assert.AreEqual(0, testProcessor.TestResults.Count);
358-
Assert.IsTrue(testProcessor.RawTestResultsMap.Keys.Count == 1);
358+
Assert.IsTrue(testProcessor.RawTestResultsMap.Keys.Count == 0);
359359
Assert.IsTrue(testProcessor.PassedTestCount == 0);
360360
Assert.IsTrue(testProcessor.FailedTestCount == 0);
361361
Assert.IsTrue(testProcessor.SkippedTestCount == 0);

0 commit comments

Comments
 (0)