Skip to content

Commit

Permalink
Adding support for the ingestion of test results from a test result f…
Browse files Browse the repository at this point in the history
…ile. WIP
  • Loading branch information
MeindertN committed Oct 7, 2024
1 parent 937a80f commit 234dc2a
Show file tree
Hide file tree
Showing 19 changed files with 993 additions and 40 deletions.
8 changes: 3 additions & 5 deletions RoboClerk.DependenciesFile/DependenciesFilePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ public class DependenciesFilePlugin : DataSourcePluginBase
private List<string> fileLocations = new List<string>();
private List<string> fileFormats = new List<string>();

private List<ExternalDependency> externalDependencies = new List<ExternalDependency>();

public DependenciesFilePlugin(IFileSystem fileSystem)
: base(fileSystem)
{
Expand Down Expand Up @@ -51,7 +49,7 @@ public override void Initialize(IConfiguration configuration)
public override void RefreshItems()
{
logger.Info("Refreshing the external dependencies from file.");
externalDependencies.Clear();
dependencies.Clear();
for (int i = 0; i < fileLocations.Count; i++)
{
switch (fileFormats[i])
Expand Down Expand Up @@ -85,7 +83,7 @@ private void ParseDotnetFile(string filename)
{
throw new Exception($"DOTNET dependencies file does not match expected format. Error in line \"{trimmedLine}\". Cannot continue.");
}
externalDependencies.Add(new ExternalDependency(elements[1], elements[3], elements[2] != elements[3]));
dependencies.Add(new ExternalDependency(elements[1], elements[3], elements[2] != elements[3]));
}
}
}
Expand Down Expand Up @@ -113,7 +111,7 @@ private void ParseGradleFile(string filename)
version = version.Split("->")[0].Trim();
conflict = true;
}
externalDependencies.Add(new ExternalDependency($"{elements[0]}:{elements[1]}", version, conflict));
dependencies.Add(new ExternalDependency($"{elements[0]}:{elements[1]}", version, conflict));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This is the RoboClerk test results file plugin configuration. Using this plugin,
# test results, both system, integration and unit test results can be read from files.
# The plugin is intended to support different file formats.

# Dependencies file locations array, supports multiple files

FileLocations = ["{PROJECTROOT}results.json"]

# The following formats are supported:
# JSON - assumes the following format for the contents of the file:
# [
# {
# "id": "12264", <--- REQUIRED matching with known test cases / unit tests
# "name": "testLoginSuccess",
# "type": "UNIT", <--- REQUIRED can be either "UNIT" or "SYSTEM"
# "status": "PASS", <----- REQUIRED can be either "PASS" or "FAIL"
# "message": "all good",
# "executionTime": "2023-10-01T12:34:56Z"
# }
# ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Library</OutputType>
<StartupObject />
<EnableDynamicLoading>true</EnableDynamicLoading>
<Authors>Meindert Niemeijer</Authors>
<Company>RoboClerk Project</Company>
<Product>Test Results File Plugin</Product>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<Configurations>Debug;Release;ReleasePublish</Configurations>
<BaseOutputPath>bin</BaseOutputPath>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleasePublish|AnyCPU'">
<Optimize>True</Optimize>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\RoboClerk\RoboClerk.csproj">
<Private>false</Private>
<ExcludeAssets>runtime</ExcludeAssets>
</ProjectReference>
</ItemGroup>

<Target Name="CopyFiles" AfterTargets="Build" Condition=" '$(Configuration)' == 'ReleasePublish' ">
<ItemGroup>
<PluginFiles Include="$(ProjectDir)$(OutDir)*.dll" />
</ItemGroup>

<Copy SourceFiles="@(PluginFiles)" DestinationFolder="$(ProjectDir)../RoboClerkDocker/publish/plugins" />
<Copy SourceFiles="$(ProjectDir)$(OutDir)RoboClerk.TestResultsFilePlugin.runtimeconfig.json" DestinationFolder="$(ProjectDir)../RoboClerkDocker/publish/plugins" />
<Copy SourceFiles="$(ProjectDir)$(OutDir)RoboClerk.TestResultsFilePlugin.deps.json" DestinationFolder="$(ProjectDir)../RoboClerkDocker/publish/plugins" />
</Target>
<Target Name="CopyPlugin" AfterTargets="Build">
<ItemGroup>
<PluginFiles Include="$(ProjectDir)$(OutDir)*.dll" />
</ItemGroup>
<Copy SourceFiles="$(ProjectDir)Configuration/TestResultsFilePlugin.toml" DestinationFolder="$(ProjectDir)../RoboClerk/$(OutDir)RoboClerk_input/PluginConfig" />
<Copy SourceFiles="@(PluginFiles)" DestinationFolder="$(ProjectDir)../RoboClerk/$(OutDir)plugins" />
</Target>
<Target Name="AdaptConfigFiles" AfterTargets="Build" Condition=" '$(Configuration)' != 'ReleasePublish' ">
<ReplaceFileText
InputFileName="$(ProjectDir)../RoboClerk/$(OutDir)RoboClerk_input/PluginConfig/TestResultsFilePlugin.toml"
MatchExpression="{PROJECTROOT}"
ReplacementText="$(ProjectDir)../" />
</Target>
<Target Name="AdaptConfigFilesRP" AfterTargets="Build" Condition=" '$(Configuration)' == 'ReleasePublish' ">
<ReplaceFileText
InputFileName="$(ProjectDir)../RoboClerk/$(OutDir)RoboClerk_input/PluginConfig/TestResultsFilePlugin.toml"
MatchExpression="{PROJECTROOT}"
ReplacementText="/mnt/" />
</Target>

</Project>
32 changes: 32 additions & 0 deletions RoboClerk.TestResultsFilePlugin/TestResultJSONObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Text.Json.Serialization;

namespace RoboClerk.TestResultsFilePlugin
{
public class TestResultJSONObject
{
[JsonPropertyName("id")]
[JsonRequired]
public string? ID { get; set; }

Check warning on line 10 in RoboClerk.TestResultsFilePlugin/TestResultJSONObject.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x)

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 10 in RoboClerk.TestResultsFilePlugin/TestResultJSONObject.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x)

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

[JsonPropertyName("name")]
public string? Name { get; set; }

Check warning on line 13 in RoboClerk.TestResultsFilePlugin/TestResultJSONObject.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x)

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 13 in RoboClerk.TestResultsFilePlugin/TestResultJSONObject.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x)

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

[JsonPropertyName("type")]
[JsonRequired]
[JsonConverter(typeof(JsonStringEnumConverter))]
public TestResultType Type { get; set; }

[JsonPropertyName("status")]
[JsonRequired]
[JsonConverter(typeof(JsonStringEnumConverter))]
public TestResultStatus Status { get; set; }

[JsonPropertyName("message")]
public string? Message { get; set; }

Check warning on line 26 in RoboClerk.TestResultsFilePlugin/TestResultJSONObject.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x)

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 26 in RoboClerk.TestResultsFilePlugin/TestResultJSONObject.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x)

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

[JsonPropertyName("executionTime")]
public DateTime? ExecutionTime { get; set; }
}

}
72 changes: 72 additions & 0 deletions RoboClerk.TestResultsFilePlugin/TestResultsFilePlugin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using RoboClerk.Configuration;
using System.Collections.Generic;
using System.IO.Abstractions;
using System.Text.Json;
using Tomlyn.Model;
using System;

namespace RoboClerk.TestResultsFilePlugin
{
public class TestResultsFilePlugin : DataSourcePluginBase
{
private List<string> fileLocations = new List<string>();

public TestResultsFilePlugin(IFileSystem fileSystem)
: base(fileSystem)
{
name = "TestResultsFilePlugin";
description = "A plugin that retrieves the test results via one or more files.";
}

public override void Initialize(IConfiguration configuration)
{
logger.Info("Initializing the Test Results File Plugin");
try
{
var config = GetConfigurationTable(configuration.PluginConfigDir, $"{name}.toml");
foreach (var item in (TomlArray)config["FileLocations"])
{
if (item == null)
{
logger.Warn($"In the Test Results File Plugin configuration file (\"{name}.toml\"), there is a null valued item in \"FileLocations\".");
continue;
}
fileLocations.Add((string)item);
}
}
catch (Exception e)
{
logger.Error("Error reading configuration file for Test Results File plugin.");
logger.Error(e);
throw new Exception("The Test Results File plugin could not read its configuration. Aborting...");
}
}

public override void RefreshItems()
{
logger.Info("Refreshing the test results from file.");
testResults.Clear();
for (int i = 0; i < fileLocations.Count; i++)
{
string json = fileSystem.File.ReadAllText(fileLocations[i]);
try
{
var fileTestResults = JsonSerializer.Deserialize<List<TestResultJSONObject>>(json);

foreach (var result in testResults)
{
if (string.IsNullOrEmpty(result.ID))
throw new JsonException("The 'id' field is required.");

testResults.Add(new TestResult(result.ID,result.Type,result.Status,result.Name,result.Message,result.ExecutionTime));
}
}
catch (JsonException)
{
logger.Error($"Error parsing the file with test results: {fileLocations[i]}");
throw;
}
}
}
}
}
Loading

0 comments on commit 234dc2a

Please sign in to comment.