From 61e46f1b3f57834af04c7a57e93e4fa8486c1548 Mon Sep 17 00:00:00 2001 From: Claire Kuang Date: Tue, 30 Jan 2024 13:09:03 +0000 Subject: [PATCH] adds regression logic --- .../AutomateFunction.cs | 184 +++++++++++++++++- .../FunctionInputs.cs | 6 +- ....csproj => SpeckleRegressionTester.csproj} | 0 ...Example.sln => SpeckleRegressionTester.sln | 2 +- 4 files changed, 179 insertions(+), 13 deletions(-) rename SpeckleAutomateDotnetExample/{SpeckleAutomateDotnetExample.csproj => SpeckleRegressionTester.csproj} (100%) rename SpeckleAutomateDotnetExample.sln => SpeckleRegressionTester.sln (83%) diff --git a/SpeckleAutomateDotnetExample/AutomateFunction.cs b/SpeckleAutomateDotnetExample/AutomateFunction.cs index d6e9d04..4697113 100644 --- a/SpeckleAutomateDotnetExample/AutomateFunction.cs +++ b/SpeckleAutomateDotnetExample/AutomateFunction.cs @@ -1,11 +1,17 @@ using Objects; -using Objects.Geometry; using Speckle.Automate.Sdk; -using Speckle.Core.Logging; +using Speckle.Automate.Sdk.Schema; +using Speckle.Core.Api; +using Speckle.Core.Models; using Speckle.Core.Models.Extensions; +using Speckle.Core.Transports; static class AutomateFunction { + public static string ADDED = "Added"; + public static string MODIFIED = "Modified"; + public static string DELETED = "Deleted"; + public static async Task Run( AutomationContext automationContext, FunctionInputs functionInputs @@ -14,16 +20,174 @@ static class AutomateFunction Console.WriteLine("Starting execution"); _ = typeof(ObjectsKit).Assembly; // INFO: Force objects kit to initialize - Console.WriteLine("Receiving version"); - var commitObject = await automationContext.ReceiveVersion(); + // get the test and release branch name + var testBranchName = automationContext.AutomationRunData.BranchName; + var releaseBranchName = testBranchName.Replace("/testing", "/release"); + Branch? releaseBranch = await automationContext.SpeckleClient + .BranchGet(automationContext.AutomationRunData.ProjectId, releaseBranchName, 1) + .ConfigureAwait(false); + if (releaseBranch is null) + { + throw new Exception("Release branch was null"); + } - Console.WriteLine("Received version: " + commitObject); + Commit releaseCommit = releaseBranch.commits.items.First(); + if (releaseCommit is null) + { + throw new Exception("Release branch has no commits"); + } - var count = commitObject - .Flatten() - .Count(b => b.speckle_type == functionInputs.SpeckleTypeToCount); + Console.WriteLine($"Comparing {testBranchName} against {releaseBranchName}"); - Console.WriteLine($"Counted {count} objects"); - automationContext.MarkRunSuccess($"Counted {count} objects"); + // get the test and release commits + Console.WriteLine("Receiving test version"); + Base? testingCommitObject = await automationContext.ReceiveVersion(); + Console.WriteLine("Received test version: " + testingCommitObject); + Console.WriteLine("Receiving release version"); + using ServerTransport transport = + new( + automationContext.SpeckleClient.Account, + automationContext.AutomationRunData.ProjectId + ); + Base? releaseCommitObject = await Operations + .Receive(releaseCommit.referencedObject, transport) + .ConfigureAwait(continueOnCapturedContext: false); + if (releaseCommitObject == null) + { + throw new Exception("Commit root object was null"); + } + + Console.WriteLine("Received release version: " + releaseCommitObject); + + // flatten both commits + IEnumerable releaseCommitObjects = releaseCommitObject.Flatten(); + IEnumerable testCommitObjects = testingCommitObject.Flatten(); + var releaseCommitObjectsDict = new Dictionary(); + foreach (var releaseObject in releaseCommitObjects) + { + if (!releaseCommitObjectsDict.ContainsKey(releaseObject.applicationId)) + { + releaseCommitObjectsDict.Add(releaseObject.applicationId, releaseObject); + } + } + + Console.WriteLine( + $"Found {releaseCommitObjects.Count()} objects in release version" + ); + Console.WriteLine($"Found {testCommitObjects.Count()} objects in release version"); + + // compare objects + int addedCount = 0; + int modifiedCount = 0; + int unchangedCount = 0; + foreach (Base testObject in testCommitObjects) + { + if (releaseCommitObjectsDict.ContainsKey(testObject.applicationId)) + { + Base releaseObject = releaseCommitObjectsDict[testObject.applicationId]; + + // if these have the same hash, no properties have changed + if (testObject.id == releaseObject.id) + { + unchangedCount++; + } + // if ids are different, find property differences + else + { + modifiedCount++; + var diffDictionary = new Dictionary(); + Dictionary releaseObjectPropDict = releaseObject.GetMembers(); + Dictionary testObjectPropDict = testObject.GetMembers(); + foreach (var entry in testObjectPropDict) + { + if (releaseObjectPropDict.ContainsKey(entry.Key)) + { + bool changed = false; + try + { + changed = entry.Value != releaseObjectPropDict[entry.Key]; + } + catch { } + if (changed) + { + string diff = + $"Property ({entry.Key}) changed from ({releaseObjectPropDict[entry.Key]}) to ({entry.Value})"; + if (!diffDictionary.ContainsKey(entry.Key)) + { + diffDictionary.Add(entry.Key, diff); + } + } + + releaseObjectPropDict.Remove(entry.Key); + } + else + { + if (!diffDictionary.ContainsKey(entry.Key)) + { + diffDictionary.Add(entry.Key, ADDED); + } + } + } + + // check if there are any props left on the release object - these were missing in the test object + foreach (var entry in releaseObjectPropDict) + { + if (!diffDictionary.ContainsKey(entry.Key)) + { + diffDictionary.Add(entry.Key, DELETED); + } + } + + // add the diff dict info to the object + if (diffDictionary.Count > 0) + { + var sb = new System.Text.StringBuilder(); + foreach (var entry in diffDictionary) + { + sb.AppendLine($"{entry.Key}: {entry.Value}"); + } + + automationContext.AttachWarningToObjects( + MODIFIED, + new List() { testObject.id }, + sb.ToString() + ); + } + } + + releaseCommitObjectsDict.Remove(testObject.applicationId); + } + else + { + addedCount++; + automationContext.AttachInfoToObjects( + ADDED, + new List() { testObject.id } + ); + } + } + + // if there are any remaining release commit objects, this indicates missing objects in the test run. + // mark run as failed and list missing object details. + if (releaseCommitObjectsDict.Keys.Count > 0) + { + automationContext.MarkRunFailed( + $"Missing {releaseCommitObjectsDict.Keys.Count} objects compared to the release commit." + ); + + foreach (var missingObject in releaseCommitObjectsDict) + { + Console.WriteLine( + $"Missing object info: id( {missingObject.Value.id} ), applicationId( {missingObject.Key} ), type( {missingObject.Value.speckle_type} )" + ); + } + } + // mark run as succeeded, noting any changed objects and added objects + else + { + automationContext.MarkRunSuccess( + $"Run passed with {addedCount} new objects, {modifiedCount} objects, and {unchangedCount} unchanged objects." + ); + } } } diff --git a/SpeckleAutomateDotnetExample/FunctionInputs.cs b/SpeckleAutomateDotnetExample/FunctionInputs.cs index f37a05a..a994b11 100644 --- a/SpeckleAutomateDotnetExample/FunctionInputs.cs +++ b/SpeckleAutomateDotnetExample/FunctionInputs.cs @@ -7,6 +7,8 @@ using System.ComponentModel.DataAnnotations; /// are valid and match the required schema. struct FunctionInputs { - [Required] - public string SpeckleTypeToCount; + //[Required] + //public double Tolerance; + + //public string Exclusions; } diff --git a/SpeckleAutomateDotnetExample/SpeckleAutomateDotnetExample.csproj b/SpeckleAutomateDotnetExample/SpeckleRegressionTester.csproj similarity index 100% rename from SpeckleAutomateDotnetExample/SpeckleAutomateDotnetExample.csproj rename to SpeckleAutomateDotnetExample/SpeckleRegressionTester.csproj diff --git a/SpeckleAutomateDotnetExample.sln b/SpeckleRegressionTester.sln similarity index 83% rename from SpeckleAutomateDotnetExample.sln rename to SpeckleRegressionTester.sln index 6aebe93..2637c74 100644 --- a/SpeckleAutomateDotnetExample.sln +++ b/SpeckleRegressionTester.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.002.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpeckleAutomateDotnetExample", "SpeckleAutomateDotnetExample/SpeckleAutomateDotnetExample.csproj", "{E1DE5809-1111-4817-9B7D-7ADCA087FA1C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpeckleRegressionTester", "SpeckleAutomateDotnetExample\SpeckleRegressionTester.csproj", "{E1DE5809-1111-4817-9B7D-7ADCA087FA1C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution