diff --git a/src/Core/Riganti.Selenium.Core.Abstractions/Exceptions/TestExceptionBase.cs b/src/Core/Riganti.Selenium.Core.Abstractions/Exceptions/TestExceptionBase.cs index 4d07e769..ef48935d 100644 --- a/src/Core/Riganti.Selenium.Core.Abstractions/Exceptions/TestExceptionBase.cs +++ b/src/Core/Riganti.Selenium.Core.Abstractions/Exceptions/TestExceptionBase.cs @@ -7,7 +7,6 @@ using System.Text; using OpenQA.Selenium; using Riganti.Selenium.Core.Abstractions.Attributes; -using Riganti.Selenium.Core.Abstractions.Reporting; namespace Riganti.Selenium.Core.Abstractions.Exceptions { @@ -61,7 +60,6 @@ public override string StackTrace public string WebBrowser { get; set; } public string CurrentUrl { get; set; } public string Screenshot { get; set; } - public Dictionary ReporterResults { get; set; } protected TestExceptionBase() { @@ -109,41 +107,10 @@ private string RenderMetadata() AppendField(sb, "Browser", WebBrowser); AppendField(sb, "Url", CurrentUrl); AppendField(sb, "Screenshot", Screenshot); - AppendReportersResults(sb, ReporterResults); return sb.ToString(); } - private void AppendReportersResults(StringBuilder sb, Dictionary reporterResults) - { - if (reporterResults != null && reporterResults.Any()) - { - sb.AppendLine("Reporters results: "); - foreach (var result in reporterResults) - { - if (result.Value is FailedTestRunInputResult failedResult) - { - if (failedResult.Exception != null) - { - AppendField(sb, $"{result.Key}.Exception ", failedResult.Exception?.Message); - } - - continue; - } - - if (!string.IsNullOrWhiteSpace(result.Value?.TestResultUrl)) - { - AppendField(sb, $"{result.Key}.TestResultUrl ", result.Value.TestResultUrl); - } - - if (!string.IsNullOrWhiteSpace(result.Value?.TestSuiteUrl)) - { - AppendField(sb, $"{result.Key}.TestSuiteUrl ", result.Value.TestSuiteUrl); - } - } - } - } - private void RenderExceptionMessage(StringBuilder sb) { if (ExceptionMessage == null || ExceptionMessage.Length <= 0) diff --git a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/FailedTestRunInputResult.cs b/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/FailedTestRunInputResult.cs deleted file mode 100644 index 9eb67aee..00000000 --- a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/FailedTestRunInputResult.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Riganti.Selenium.Core.Abstractions.Reporting -{ - /// - /// This is special result that indicates that reporting a result to service failed. - /// - public class FailedTestRunInputResult : TestRunInputResult - { - public Exception Exception { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/IReportingMetadataProvider.cs b/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/IReportingMetadataProvider.cs deleted file mode 100644 index de64fa7c..00000000 --- a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/IReportingMetadataProvider.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Riganti.Selenium.Core -{ - public interface IReportingMetadataProvider - { - string GetBuildNumber(); - - string GetProjectName(); - - string GetTestSuiteName(); - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/ITestResultReporter.cs b/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/ITestResultReporter.cs deleted file mode 100644 index 674e4e17..00000000 --- a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/ITestResultReporter.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Riganti.Selenium.Core.Abstractions.Reporting -{ - public interface ITestResultReporter - { - Task ReportTestResult(TestRunInputData data); - - IDictionary Options { get; } - string Name { get; } - string ReportTestResultUrl { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/TestRunAttachmentInputData.cs b/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/TestRunAttachmentInputData.cs deleted file mode 100644 index 67bb30e4..00000000 --- a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/TestRunAttachmentInputData.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Riganti.Selenium.Core.Abstractions.Reporting -{ - public class TestRunAttachmentInputData - { - public string FileName { get; set; } - - public string ContentBase64 { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/TestRunInputData.cs b/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/TestRunInputData.cs deleted file mode 100644 index a13afee0..00000000 --- a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/TestRunInputData.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; - -namespace Riganti.Selenium.Core.Abstractions.Reporting -{ - public class TestRunInputData - { - public string ProjectName { get; set; } - - public string TestSuiteName { get; set; } - - public string BuildNumber { get; set; } - - public string TestFullName { get; set; } - - /// - /// Enum serialization doesn't work in latest SDK for Azure Functions - /// 0 = Failed, 1 = Success - /// - public int TestResult { get; set; } - - public string TestOutput { get; set; } - - public List Attachments { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/TestRunInputResult.cs b/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/TestRunInputResult.cs deleted file mode 100644 index f62af685..00000000 --- a/src/Core/Riganti.Selenium.Core.Abstractions/Reporting/TestRunInputResult.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Riganti.Selenium.Core.Abstractions.Reporting -{ - public class TestRunInputResult - { - public string TestSuiteUrl { get; set; } - - public string TestResultUrl { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Configuration/ReportingConfiguration.cs b/src/Core/Riganti.Selenium.Core/Configuration/ReportingConfiguration.cs deleted file mode 100644 index dc3685c6..00000000 --- a/src/Core/Riganti.Selenium.Core/Configuration/ReportingConfiguration.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace Riganti.Selenium.Core.Configuration -{ - public class ReportingConfiguration - { - /// - /// Url of endpoint for reporting test results - /// - public string ReportTestResultUrl { get; set; } - - /// - /// Determine whether the reporter is enabled. - /// - public bool Enabled { get; set; } = true; - - /// - /// Additional configuration - /// - public IDictionary Options { get; } = new Dictionary(); - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Configuration/ReportingOptions.cs b/src/Core/Riganti.Selenium.Core/Configuration/ReportingOptions.cs deleted file mode 100644 index 14e7763c..00000000 --- a/src/Core/Riganti.Selenium.Core/Configuration/ReportingOptions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace Riganti.Selenium.Core.Configuration -{ - public class ReportingOptions - { - public Dictionary Reporters { get; } = new Dictionary(); - - /// - /// Report the results parallel. - /// - public bool Parallel { get; set; } = true; - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Configuration/SeleniumTestsConfiguration.cs b/src/Core/Riganti.Selenium.Core/Configuration/SeleniumTestsConfiguration.cs index d31f22b5..ae98ee9b 100644 --- a/src/Core/Riganti.Selenium.Core/Configuration/SeleniumTestsConfiguration.cs +++ b/src/Core/Riganti.Selenium.Core/Configuration/SeleniumTestsConfiguration.cs @@ -11,6 +11,5 @@ public class SeleniumTestsConfiguration public TestRunOptions TestRunOptions { get; } = new TestRunOptions(); public LoggingOptions Logging { get; } = new LoggingOptions(); - public ReportingOptions Reporting { get; } = new ReportingOptions(); } } \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Discovery/ResultReportersFactory.cs b/src/Core/Riganti.Selenium.Core/Discovery/ResultReportersFactory.cs deleted file mode 100644 index ec9cc6cf..00000000 --- a/src/Core/Riganti.Selenium.Core/Discovery/ResultReportersFactory.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Riganti.Selenium.Core.Abstractions.Exceptions; -using Riganti.Selenium.Core.Abstractions.Reporting; -using Riganti.Selenium.Core.Configuration; - -namespace Riganti.Selenium.Core.Discovery -{ - public class ResultReportersFactory - { - public Dictionary CreateReporters(IEnumerable assemblies, SeleniumTestsConfiguration configuration) - { - // find all factories - var foundTypes = DiscoverReporters(assemblies); - var reporters = InstantiateReporters(foundTypes); - - // create instances and configure them - var result = new Dictionary(); - foreach (var factoryConfiguration in configuration.Reporting.Reporters.Where(s => s.Value.Enabled)) - { - // try to find factory instance - var instance = reporters.SingleOrDefault(f => f.Name == factoryConfiguration.Key); - if (instance == null) - { - throw new SeleniumTestConfigurationException($"The reporter '{factoryConfiguration.Key}' was not found!"); - } - - instance.ReportTestResultUrl = factoryConfiguration.Value.ReportTestResultUrl; - - //load options - foreach (var entry in factoryConfiguration.Value.Options) - { - instance.Options[entry.Key] = entry.Value; - } - - // return the instance - result[factoryConfiguration.Key] = instance; - } - return result; - } - - /// - /// Returns discovered types of Reporters that implements . - /// - /// - protected virtual IEnumerable DiscoverReporters(IEnumerable assemblies) - { - var foundTypes = GetExportedTypes(assemblies) - .Where(t => typeof(ITestResultReporter).IsAssignableFrom(t)) - .Where(t => !t.IsAbstract); - return foundTypes; - } - - private static IEnumerable GetExportedTypes(IEnumerable assemblies) - { - try - { - return assemblies.SelectMany(a => a.GetExportedTypes()); - } - catch (ReflectionTypeLoadException e) - { - return e.Types.ToArray(); - } - } - - private IList InstantiateReporters(IEnumerable foundTypes) - { - var instances = new List(); - foreach (var type in foundTypes) - { - try - { - var instance = (ITestResultReporter)Activator.CreateInstance(type); - instances.Add(instance); - } - catch (Exception ex) - { - throw new SeleniumTestConfigurationException($"Failed to create an instance of the '{type}'! Make sure that the reporter has a parameterless constructor.", ex); - } - } - return instances; - } - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Reporting/AggregatedReporter.cs b/src/Core/Riganti.Selenium.Core/Reporting/AggregatedReporter.cs deleted file mode 100644 index 8f5e1952..00000000 --- a/src/Core/Riganti.Selenium.Core/Reporting/AggregatedReporter.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Riganti.Selenium.Core.Abstractions.Exceptions; -using Riganti.Selenium.Core.Abstractions.Reporting; -using Riganti.Selenium.Core.Configuration; -using Riganti.Selenium.Core.Riganti.Utils.Infrastructure.Core; - -namespace Riganti.Selenium.Core.Reporting -{ - internal class AggregatedReporter - { - private readonly IDictionary reporters; - private readonly IReportingMetadataProvider reportingMetadataProvider; - private readonly SeleniumTestsConfiguration configuration; - private static ConcurrentQueue Queue { get; } - - static AggregatedReporter() - { - Queue = new ConcurrentQueue(); - } - - public AggregatedReporter(IDictionary reporters, - IReportingMetadataProvider reportingMetadataProvider, SeleniumTestsConfiguration configuration) - { - this.reporters = reporters; - this.reportingMetadataProvider = reportingMetadataProvider; - this.configuration = configuration; - if (configuration.Reporting.Parallel) - { - Tasks = new List() { - new Task(async () => await SendResult()), - new Task(async () => await SendResult()) - }; - } - } - - public List Tasks { get; set; } - - public void ReportFailedTest(Exception exception, string testName, string callerFilePath, int callerLineNumber) - { - if (exception == null) return; - - var sExecption = exception as SeleniumTestFailedException; - - var unwrappedTestExceptions = sExecption?.InnerExceptions.OfType().ToList(); - List attachments = GetAttachments(unwrappedTestExceptions); - - var data = new TestRunInputData() - { - TestResult = 0, - Attachments = attachments, - TestFullName = testName, - TestOutput = exception.ToString(), - BuildNumber = reportingMetadataProvider.GetBuildNumber(), - ProjectName = reportingMetadataProvider.GetProjectName(), - TestSuiteName = reportingMetadataProvider.GetTestSuiteName(), - }; - - EnqueueResult(data); - } - - private void EnqueueResult(TestRunInputData data) - { - if (configuration.Reporting.Parallel) - { - SendResultSync(data); - } - else - { - Queue.Enqueue(data); - } - } - - private IEnumerable SendResultSync(TestRunInputData data) - { - var results = ReportTestResult(data).RunSync(); - return results; - } - - public void ReportSuccessfulTest(string testName, string callerFilePath, int callerLineNumber) - { - var data = new TestRunInputData() - { - TestResult = 1, - TestFullName = testName, - BuildNumber = reportingMetadataProvider.GetBuildNumber(), - ProjectName = reportingMetadataProvider.GetProjectName(), - TestOutput = "", - TestSuiteName = reportingMetadataProvider.GetTestSuiteName(), - Attachments = new List() - }; - - EnqueueResult(data); - } - - public async Task SendResult() - { - while (true) - { - if (Queue.TryDequeue(out var result) && result != null) - { - var results = await ReportTestResult(result); - } - else - { - Thread.Sleep(50); - } - } - // ReSharper disable once FunctionNeverReturns - } - - private static List GetAttachments(List unwrappedTestExceptions) - { - return unwrappedTestExceptions?.Select(s => s.Screenshot).Select(s => - { - try - { - var bytes = File.ReadAllBytes(s); - return new TestRunAttachmentInputData() { ContentBase64 = Convert.ToBase64String(bytes), FileName = s }; - } - catch (Exception e) - { - return null; - } - }).Where(s => s != null).ToList(); - } - - private async Task> ReportTestResult(TestRunInputData data) - { - var results = new List(); - foreach (var testResultReporter in reporters) - { - try - { - results.Add(await testResultReporter.Value.ReportTestResult(data)); - } - catch (Exception e) - { - results.Add(new FailedTestRunInputResult() { Exception = e }); - } - } - return results; - } - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Reporting/AzureDevOpsReporter.cs b/src/Core/Riganti.Selenium.Core/Reporting/AzureDevOpsReporter.cs deleted file mode 100644 index 9208ec05..00000000 --- a/src/Core/Riganti.Selenium.Core/Reporting/AzureDevOpsReporter.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Riganti.Selenium.Core.Abstractions.Reporting; - -namespace Riganti.Selenium.Core.Reporting -{ - /// - /// Reporter for Azure DevOps test runner - /// - public class AzureDevOpsReporter : ITestResultReporter - { - public HttpClient Client { get; set; } - - public AzureDevOpsReporter() - { - Client = new HttpClient(); - } - - public Task ReportTestResult(TestRunInputData data) - { - RewriteMetadata(data); - return SendReport(data); - } - - protected virtual async Task SendReport(TestRunInputData data) - { - var response = await Client.PostAsync(new Uri(ReportTestResultUrl), new StringContent(JsonConvert.SerializeObject(data))); - return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - } - - /// - /// Rewrite or add metadata before the result is sent to the reporting app. - /// - /// - protected virtual void RewriteMetadata(TestRunInputData data) - { - // rewrite metadata - string buildId = Environment.GetEnvironmentVariable("BUILD_BUILDID"); - if (!string.IsNullOrWhiteSpace(buildId)) - { - data.BuildNumber = buildId; - data.ProjectName = - Environment.GetEnvironmentVariable("SYSTEM_TEAMPROJECT") + "|" + - Environment.GetEnvironmentVariable("BUILD_BUILDNUMBER") + "|" + - Environment.GetEnvironmentVariable("BUILD_DEFINITIONNAME"); - } - } - - public IDictionary Options { get; } = new Dictionary(); - - /// - public string Name { get; } = "azureDevOps"; - - /// - public string ReportTestResultUrl { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Reporting/DefaultReportingMetadataProvider.cs b/src/Core/Riganti.Selenium.Core/Reporting/DefaultReportingMetadataProvider.cs deleted file mode 100644 index ca13910a..00000000 --- a/src/Core/Riganti.Selenium.Core/Reporting/DefaultReportingMetadataProvider.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; - -using System.Reflection; - -namespace Riganti.Selenium.Core.Reporting -{ - public class DefaultReportingMetadataProvider : IReportingMetadataProvider - { - private readonly ITestContextProvider testContextProvider; - private static DateTime Date = DateTime.Now; - - public DefaultReportingMetadataProvider(ITestContextProvider testContextProvider) - { - this.testContextProvider = testContextProvider; - } - - public string GetBuildNumber() - { - return $"{Date:yyyyMMdd}-{Date:hhmmss}"; - } - - public string GetProjectName() - { - try - { - return Assembly.GetExecutingAssembly().GetName().Name; - } - catch (Exception e) - { - return ""; - } - } - - public string GetTestSuiteName() - { - return Type.GetType(testContextProvider.GetGlobalScopeTestContext().FullyQualifiedTestClassName)?.Name ?? "Test Suite"; - } - } -} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/TestSuiteRunner.cs b/src/Core/Riganti.Selenium.Core/TestSuiteRunner.cs index b5abe85c..04105433 100644 --- a/src/Core/Riganti.Selenium.Core/TestSuiteRunner.cs +++ b/src/Core/Riganti.Selenium.Core/TestSuiteRunner.cs @@ -7,12 +7,10 @@ using Riganti.Selenium.Core.Abstractions; using Riganti.Selenium.Core.Abstractions.Attributes; using Riganti.Selenium.Core.Abstractions.Exceptions; -using Riganti.Selenium.Core.Abstractions.Reporting; using Riganti.Selenium.Core.Configuration; using Riganti.Selenium.Core.Discovery; using Riganti.Selenium.Core.Factories; using Riganti.Selenium.Core.Logging; -using Riganti.Selenium.Core.Reporting; namespace Riganti.Selenium.Core { @@ -31,8 +29,6 @@ public class TestSuiteRunner : IDisposable public ITestContextProvider TestContextProvider { get; } - public IReportingMetadataProvider ReportingMetadataProvider { get; } - public LoggerService LoggerService { get; set; } public ServiceFactory ServiceFactory { get; } = new ServiceFactory(); @@ -40,7 +36,6 @@ public TestSuiteRunner(SeleniumTestsConfiguration configuration, ITestContextPro { SearchAssemblies = new List() { Assembly.GetExecutingAssembly() }; ServiceFactory.RegisterTransient, WebBrowserFactoryResolver>(); - ServiceFactory.RegisterTransient(); registerServices?.Invoke(ServiceFactory, this); @@ -48,7 +43,6 @@ public TestSuiteRunner(SeleniumTestsConfiguration configuration, ITestContextPro this.TestContextProvider = testContextProvider; this.WebBrowserPool = new WebBrowserPool(this); this.TestContextAccessor = new TestContextAccessor(); - ReportingMetadataProvider = new DefaultReportingMetadataProvider(testContextProvider); } /// @@ -61,8 +55,6 @@ private void Initialize() return; LoggerService = CreateLoggerService(SearchAssemblies); factories = CreateWebBrowserFactories(); - var reporters = CreateReporters(); - Reporter = new AggregatedReporter(reporters, ReportingMetadataProvider, Configuration); this.LogInfo("RIGANTI Selenium-Utils Test framework initialized."); this.LogVerbose("WebBrowserFactories discovered: "); @@ -87,14 +79,6 @@ private void Initialize() } } - internal AggregatedReporter Reporter { get; set; } - - protected virtual Dictionary CreateReporters() - { - var factoryResolver = ServiceFactory.Resolve(); - return factoryResolver.CreateReporters(SearchAssemblies, Configuration); - } - private LoggerService CreateLoggerService(IEnumerable assemblies) { var discoveryService = new LoggerResolver(); @@ -173,11 +157,9 @@ public virtual void RunInAllBrowsers(ISeleniumTest testClass, Action