From e652b9784277c3e09160a658aa8fe4b425dfa09d Mon Sep 17 00:00:00 2001 From: Stig Killendahl Date: Thu, 28 Nov 2024 16:37:44 +0100 Subject: [PATCH] Add multi turn accuracy and export of results --- src/Tools/AI Test Toolkit/Results.xlsx | Bin 0 -> 24641 bytes .../src/AITTestContext.Codeunit.al | 9 +++ .../src/AITTestContextImpl.Codeunit.al | 53 +++++++++++-- .../src/AITTestRunIteration.Codeunit.al | 40 ++++++++++ .../src/Logs/AITLogEntries.Page.al | 51 ++++++++++++ .../src/Logs/AITLogEntry.Table.al | 15 ++++ .../src/Logs/AITResults.Report.al | 73 ++++++++++++++++++ .../src/Logs/AITRunHistory.Page.al | 12 +++ .../src/Logs/AITRunHistory.Table.al | 16 ++++ .../src/TestSuite/AITTestMethodLine.Table.al | 24 ++++++ .../src/TestSuite/AITTestMethodLines.Page.al | 52 +++++++++++++ .../src/TestSuite/AITTestSuite.Page.al | 18 +++++ .../src/TestSuite/AITTestSuite.Table.al | 8 ++ .../src/TestSuite/AITTestSuiteMgt.Codeunit.al | 35 +++++++++ 14 files changed, 401 insertions(+), 5 deletions(-) create mode 100644 src/Tools/AI Test Toolkit/Results.xlsx create mode 100644 src/Tools/AI Test Toolkit/src/Logs/AITResults.Report.al diff --git a/src/Tools/AI Test Toolkit/Results.xlsx b/src/Tools/AI Test Toolkit/Results.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..67acce438bdc053bc76f3ba8855e86b501056dbe GIT binary patch literal 24641 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 mt`B}jFjOj@+3*Kymgul@(dieGjB literal 0 HcmV?d00001 diff --git a/src/Tools/AI Test Toolkit/src/AITTestContext.Codeunit.al b/src/Tools/AI Test Toolkit/src/AITTestContext.Codeunit.al index dd68b22f82..59d2417505 100644 --- a/src/Tools/AI Test Toolkit/src/AITTestContext.Codeunit.al +++ b/src/Tools/AI Test Toolkit/src/AITTestContext.Codeunit.al @@ -123,6 +123,15 @@ codeunit 149044 "AIT Test Context" AITTestContextImpl.SetTestMetric(TestMetric); end; + /// + /// Sets the accuracy of the test. + /// + /// The accuracy as a decimal between 0 and 1. + procedure SetAccuracy(Accuracy: Decimal) + begin + AITTestContextImpl.SetAccuracy(Accuracy); + end; + var AITTestContextImpl: Codeunit "AIT Test Context Impl."; } \ No newline at end of file diff --git a/src/Tools/AI Test Toolkit/src/AITTestContextImpl.Codeunit.al b/src/Tools/AI Test Toolkit/src/AITTestContextImpl.Codeunit.al index 1499ffb8df..74d038b737 100644 --- a/src/Tools/AI Test Toolkit/src/AITTestContextImpl.Codeunit.al +++ b/src/Tools/AI Test Toolkit/src/AITTestContextImpl.Codeunit.al @@ -18,9 +18,12 @@ codeunit 149043 "AIT Test Context Impl." var AITTestSuiteMgt: Codeunit "AIT Test Suite Mgt."; GlobalTestOutputJson: Codeunit "Test Output Json"; + Accuracy: Decimal; CurrentTurn: Integer; NumberOfTurns: Integer; IsMultiTurn: Boolean; + AccuracySetManually: Boolean; + AccuracyErr: Label 'Accuracy must be between 0.0 and 1.0.'; AnswerTok: Label 'answer', Locked = true; ContextTok: Label 'context', Locked = true; GroundTruthTok: Label 'ground_truth', Locked = true; @@ -146,6 +149,33 @@ codeunit 149043 "AIT Test Context Impl." SetSuiteTestOutput(CurrentTestOutputJson.ToText()); end; + /// + /// Sets the accuracy of the test. + /// + /// The accuracy as a decimal between 0 and 1. + procedure SetAccuracy(AccuracyPct: Decimal) + begin + if (AccuracyPct < 0) or (AccuracyPct > 1.0) then + Error(AccuracyErr); + + AccuracySetManually := true; + Accuracy := AccuracyPct; + end; + + /// + /// Gets the accuracy of the test. + /// + /// True if the accuracy was set, false otherwise. + procedure GetAccuracy(var AccuracyPct: Decimal): Boolean + begin + if AccuracySetManually then begin + AccuracyPct := Accuracy; + exit(true); + end; + + exit(false); + end; + /// /// Sets to next turn for multiturn testing. /// @@ -155,7 +185,7 @@ codeunit 149043 "AIT Test Context Impl." if not IsMultiTurn then exit(false); - if CurrentTurn + 1 > NumberOfTurns then + if CurrentTurn > NumberOfTurns then exit(false); CurrentTurn := CurrentTurn + 1; @@ -164,7 +194,7 @@ codeunit 149043 "AIT Test Context Impl." end; /// - /// Gets the current turn for multiturn testing. Turns start from turn 0. + /// Gets the current turn for multiturn testing. Turns start from turn 1. /// /// The current turn number. procedure GetCurrentTurn(): Integer @@ -172,6 +202,15 @@ codeunit 149043 "AIT Test Context Impl." exit(CurrentTurn); end; + /// + /// Gets the total number of turns for multiturn testing. + /// + /// The total number of turns for the line. + procedure GetNumberOfTurns(): Integer + begin + exit(NumberOfTurns); + end; + /// /// This method starts the scope of the Run Procedure scenario. /// @@ -205,12 +244,16 @@ codeunit 149043 "AIT Test Context Impl." TestInput: Codeunit "Test Input"; TurnsInputJson: Codeunit "Test Input Json"; begin - CurrentTurn := 0; + AccuracySetManually := false; + Accuracy := 0; + CurrentTurn := 1; GlobalTestOutputJson.Initialize(); TurnsInputJson := TestInput.GetTestInput().ElementExists(TurnsTok, IsMultiTurn); if IsMultiTurn then - NumberOfTurns := TurnsInputJson.GetElementCount() - 1; + NumberOfTurns := TurnsInputJson.GetElementCount() + else + NumberOfTurns := 1; end; /// @@ -223,7 +266,7 @@ codeunit 149043 "AIT Test Context Impl." TestInput: Codeunit "Test Input"; begin if IsMultiTurn then - TestInputJson := TestInput.GetTestInput(TurnsTok).ElementAt(CurrentTurn).Element(ElementName) + TestInputJson := TestInput.GetTestInput(TurnsTok).ElementAt(CurrentTurn - 1).Element(ElementName) else TestInputJson := TestInput.GetTestInput(ElementName); end; diff --git a/src/Tools/AI Test Toolkit/src/AITTestRunIteration.Codeunit.al b/src/Tools/AI Test Toolkit/src/AITTestRunIteration.Codeunit.al index 4565bd168a..a5cfe45c7f 100644 --- a/src/Tools/AI Test Toolkit/src/AITTestRunIteration.Codeunit.al +++ b/src/Tools/AI Test Toolkit/src/AITTestRunIteration.Codeunit.al @@ -21,6 +21,9 @@ codeunit 149042 "AIT Test Run Iteration" GlobalTestMethodLine: Record "Test Method Line"; NoOfInsertedLogEntries: Integer; GlobalAITokenUsedByLastTestMethodLine: Integer; + GlobalNumberOfTurnsForLastTestMethodLine: Integer; + GlobalNumberOfTurnsPassedForLastTestMethodLine: Integer; + GlobalTestAccuracy: Decimal; GlobalSessionAITokenUsed: Integer; trigger OnRun() @@ -124,6 +127,21 @@ codeunit 149042 "AIT Test Run Iteration" exit(GlobalAITokenUsedByLastTestMethodLine); end; + procedure GetNumberOfTurnsForLastTestMethodLine(): Integer + begin + exit(GlobalNumberOfTurnsForLastTestMethodLine); + end; + + procedure GetNumberOfTurnsPassedForLastTestMethodLine(): Integer + begin + exit(GlobalNumberOfTurnsPassedForLastTestMethodLine); + end; + + procedure GetAccuracyForLastTestMethodLine(): Decimal + begin + exit(GlobalTestAccuracy); + end; + [InternalEvent(false)] procedure OnBeforeRunIteration(var AITTestSuite: Record "AIT Test Suite"; var AITTestMethodLine: Record "AIT Test Method Line") begin @@ -144,6 +162,14 @@ codeunit 149042 "AIT Test Run Iteration" // Update AI Token Consumption GlobalAITokenUsedByLastTestMethodLine := 0; + + // Update Turns + GlobalNumberOfTurnsPassedForLastTestMethodLine := 0; + GlobalNumberOfTurnsForLastTestMethodLine := 1; + + // Update Test Accuracy + GlobalTestAccuracy := 0.0; + GlobalSessionAITokenUsed := AOAIToken.GetTotalServerSessionTokensConsumed(); AITContextCU.StartRunProcedureScenario(); @@ -154,6 +180,7 @@ codeunit 149042 "AIT Test Run Iteration" var AITContextCU: Codeunit "AIT Test Context Impl."; AOAIToken: Codeunit "AOAI Token"; + Accuracy: Decimal; begin if ActiveAITTestSuite.Code = '' then exit; @@ -166,6 +193,19 @@ codeunit 149042 "AIT Test Run Iteration" // Update AI Token Consumption GlobalAITokenUsedByLastTestMethodLine := AOAIToken.GetTotalServerSessionTokensConsumed() - GlobalSessionAITokenUsed; + // Update Turns + GlobalNumberOfTurnsForLastTestMethodLine := AITContextCU.GetNumberOfTurns(); + GlobalNumberOfTurnsPassedForLastTestMethodLine := AITContextCU.GetCurrentTurn(); + + if not IsSuccess then + GlobalNumberOfTurnsPassedForLastTestMethodLine -= 1; + + // Update Test Accuracy + if AITContextCU.GetAccuracy(Accuracy) then + GlobalTestAccuracy := Accuracy + else + GlobalTestAccuracy := GlobalNumberOfTurnsPassedForLastTestMethodLine / GlobalNumberOfTurnsForLastTestMethodLine; + AITContextCU.EndRunProcedureScenario(CurrentTestMethodLine, IsSuccess); Commit(); end; diff --git a/src/Tools/AI Test Toolkit/src/Logs/AITLogEntries.Page.al b/src/Tools/AI Test Toolkit/src/Logs/AITLogEntries.Page.al index 123d63634e..14186a9b4f 100644 --- a/src/Tools/AI Test Toolkit/src/Logs/AITLogEntries.Page.al +++ b/src/Tools/AI Test Toolkit/src/Logs/AITLogEntries.Page.al @@ -68,6 +68,23 @@ page 149033 "AIT Log Entries" { StyleExpr = StatusStyleExpr; } + field(Accuracy; Rec.Accuracy) + { + } + field("No. of Turns Passed"; Rec."No. of Turns Passed") + { + Visible = false; + } + field("No. of Turns Executed"; Rec."No. of Turns Executed") + { + Visible = false; + } + field(TurnsText; TurnsText) + { + StyleExpr = TurnsStyleExpr; + Caption = 'No. of Turns Passed'; + ToolTip = 'Specifies the number of turns that passed out of the total number of turns.'; + } field("Orig. Status"; Rec."Original Status") { Visible = false; @@ -253,6 +270,19 @@ page 149033 "AIT Log Entries" Page.Run(Page::"AIT Test Data Compare", Rec); end; } + action("Export Results") + { + Caption = 'Export Results'; + Image = Export; + ToolTip = 'Exports the results.'; + + trigger OnAction() + var + AITTestSuiteMgt: Codeunit "AIT Test Suite Mgt."; + begin + AITTestSuiteMgt.ExportResults(Rec); + end; + } } area(Promoted) { @@ -279,6 +309,9 @@ page 149033 "AIT Log Entries" actionref("View Test Data_Promoted"; "View Test Data") { } + actionref("Export Results_Promoted"; "Export Results") + { + } } } } @@ -287,20 +320,26 @@ page 149033 "AIT Log Entries" ClickToShowLbl: Label 'Show data input'; DoYouWantToDeleteQst: Label 'Do you want to delete all entries within the filter?'; InputText: Text; + TurnsText: Text; OutputText: Text; ErrorMessage: Text; ErrorCallStack: Text; StatusStyleExpr: Text; + TurnsStyleExpr: Text; TestRunDuration: Duration; IsFilteredToErrors: Boolean; ShowSensitiveData: Boolean; trigger OnAfterGetRecord() + var + AITTestSuiteMgt: Codeunit "AIT Test Suite Mgt."; begin TestRunDuration := Rec."Duration (ms)"; + TurnsText := AITTestSuiteMgt.GetTurnsAsText(Rec); SetInputOutputDataFields(); SetErrorFields(); SetStatusStyleExpr(); + SetTurnsStyleExpr(); end; local procedure SetStatusStyleExpr() @@ -315,6 +354,18 @@ page 149033 "AIT Log Entries" end; end; + local procedure SetTurnsStyleExpr() + begin + case Rec."No. of Turns Passed" of + Rec."No. of Turns Executed": + TurnsStyleExpr := 'Favorable'; + 0: + TurnsStyleExpr := 'Unfavorable'; + else + TurnsStyleExpr := 'Ambiguous'; + end; + end; + local procedure SetErrorFields() begin ErrorMessage := ''; diff --git a/src/Tools/AI Test Toolkit/src/Logs/AITLogEntry.Table.al b/src/Tools/AI Test Toolkit/src/Logs/AITLogEntry.Table.al index 808e0111f3..d4bba081c0 100644 --- a/src/Tools/AI Test Toolkit/src/Logs/AITLogEntry.Table.al +++ b/src/Tools/AI Test Toolkit/src/Logs/AITLogEntry.Table.al @@ -159,6 +159,21 @@ table 149034 "AIT Log Entry" { Caption = 'Output Data'; } + field(40; "No. of Turns Executed"; Integer) + { + Caption = 'Total number of turns'; + ToolTip = 'Specifies the total number of turns executed.'; + } + field(41; "No. of Turns Passed"; Integer) + { + Caption = 'Number of turns passed'; + ToolTip = 'Specifies the number of turns passed.'; + } + field(45; Accuracy; Decimal) + { + Caption = 'Accuracy'; + ToolTip = 'Specifies the accuracy of the test line.'; + } field(50; "Tokens Consumed"; Integer) { Caption = 'Total Tokens Consumed'; diff --git a/src/Tools/AI Test Toolkit/src/Logs/AITResults.Report.al b/src/Tools/AI Test Toolkit/src/Logs/AITResults.Report.al new file mode 100644 index 0000000000..228e58633c --- /dev/null +++ b/src/Tools/AI Test Toolkit/src/Logs/AITResults.Report.al @@ -0,0 +1,73 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace System.TestTools.AITestToolkit; + +report 149030 "AIT Results" +{ + Caption = 'AI Test Results'; + ApplicationArea = All; + UsageCategory = Tasks; + DefaultLayout = Excel; + ExcelLayout = 'Results.xlsx'; + + dataset + { + dataitem(Results; "AIT Log Entry") + { + + RequestFilterFields = Version; + RequestFilterHeading = 'AI Test Log Entries'; + + column(CodeunitID; Results."Codeunit ID") + { + } + column(Name; Results."Codeunit Name") + { + } + column(TestName; Results."Procedure Name") + { + } + column(Status; Results.Status) + { + } + column(Accuracy; Results.Accuracy) + { + } + column(TurnsExecuted; Results."No. of Turns Executed") + { + } + column(TurnsPassed; Results."No. of Turns Passed") + { + } + column(Input; Input) + { + } + column(Output; Output) + { + } + column(Error_Message; ErrorMessage) + { + } + column(Error; ErrorCallstack) + { + } + + trigger OnAfterGetRecord() + begin + Input := Results.GetInputBlob(); + Output := Results.GetOutputBlob(); + ErrorMessage := Results.GetMessage(); + ErrorCallstack := Results.GetErrorCallStack(); + end; + } + } + + var + Input: Text; + Output: Text; + ErrorMessage: Text; + ErrorCallstack: Text; +} \ No newline at end of file diff --git a/src/Tools/AI Test Toolkit/src/Logs/AITRunHistory.Page.al b/src/Tools/AI Test Toolkit/src/Logs/AITRunHistory.Page.al index 456639fbb0..d5fa13ed6a 100644 --- a/src/Tools/AI Test Toolkit/src/Logs/AITRunHistory.Page.al +++ b/src/Tools/AI Test Toolkit/src/Logs/AITRunHistory.Page.al @@ -121,6 +121,12 @@ page 149032 "AIT Run History" AITLogEntryCodeunit.DrillDownFailedAITLogEntries(Rec."Test Suite Code", Rec."Line No. Filter", Rec.Version); end; } + field("Accuracy - By Version"; Rec.Accuracy) + { + Visible = ViewBy = ViewBy::Version; + Caption = 'Accuracy'; + ToolTip = 'Specifies the average accuracy of the version.'; + } field("Duration - By Version"; Rec."Total Duration (ms)") { Visible = ViewBy = ViewBy::Version; @@ -161,6 +167,12 @@ page 149032 "AIT Run History" AITLogEntryCodeunit.DrillDownFailedAITLogEntries(Rec."Test Suite Code", Rec."Line No. Filter", Rec.Tag); end; } + field("Accuracy - By Tag"; Rec."Accuracy - By Tag") + { + Visible = ViewBy = ViewBy::Tag; + Caption = 'Accuracy'; + ToolTip = 'Specifies the average accuracy of the tag.'; + } field("Duration - By Tag"; Rec."Total Duration (ms) - By Tag") { Visible = ViewBy = ViewBy::Tag; diff --git a/src/Tools/AI Test Toolkit/src/Logs/AITRunHistory.Table.al b/src/Tools/AI Test Toolkit/src/Logs/AITRunHistory.Table.al index 8194182f71..3a114eddfb 100644 --- a/src/Tools/AI Test Toolkit/src/Logs/AITRunHistory.Table.al +++ b/src/Tools/AI Test Toolkit/src/Logs/AITRunHistory.Table.al @@ -73,6 +73,14 @@ table 149036 "AIT Run History" FieldClass = FlowField; CalcFormula = sum("AIT Log Entry"."Tokens Consumed" where("Test Suite Code" = field("Test Suite Code"), Version = field("Version"), "Test Method Line No." = field("Line No. Filter"), Operation = const('Run Procedure'), "Procedure Name" = filter(<> ''))); } + field(14; "Accuracy"; Decimal) + { + Caption = 'Accuracy'; + ToolTip = 'Specifies the average accuracy of the version.'; + Editable = false; + FieldClass = FlowField; + CalcFormula = average("AIT Log Entry"."Accuracy" where("Test Suite Code" = field("Test Suite Code"), "Test Method Line No." = field("Line No. Filter"), Version = field("Version"), Operation = const('Run Procedure'), "Procedure Name" = filter(<> ''))); + } field(20; "No. of Tests Executed - By Tag"; Integer) { Caption = 'No. of Tests Executed'; @@ -105,6 +113,14 @@ table 149036 "AIT Run History" FieldClass = FlowField; CalcFormula = sum("AIT Log Entry"."Tokens Consumed" where("Test Suite Code" = field("Test Suite Code"), "Test Method Line No." = field("Line No. Filter"), Tag = field(Tag), Operation = const('Run Procedure'), "Procedure Name" = filter(<> ''))); } + field(24; "Accuracy - By Tag"; Decimal) + { + Caption = 'Accuracy'; + ToolTip = 'Specifies the average accuracy of the tag.'; + Editable = false; + FieldClass = FlowField; + CalcFormula = average("AIT Log Entry"."Accuracy" where("Test Suite Code" = field("Test Suite Code"), "Test Method Line No." = field("Line No. Filter"), Tag = field(Tag), Operation = const('Run Procedure'), "Procedure Name" = filter(<> ''))); + } } keys diff --git a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestMethodLine.Table.al b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestMethodLine.Table.al index 7f582e6ed4..03b666b7e9 100644 --- a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestMethodLine.Table.al +++ b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestMethodLine.Table.al @@ -166,6 +166,30 @@ table 149032 "AIT Test Method Line" FieldClass = FlowField; CalcFormula = count("AIT Log Entry" where("Test Suite Code" = field("Test Suite Code"), "Test Method Line No." = field("Line No."), Version = field("Base Version Filter"))); } + field(40; "No. of Turns Executed"; Integer) + { + Caption = 'No. of Turns Executed'; + ToolTip = 'Specifies the total number of turns for the test line.'; + Editable = false; + FieldClass = FlowField; + CalcFormula = sum("AIT Log Entry"."No. of Turns Executed" where("Test Suite Code" = field("Test Suite Code"), "Test Method Line No." = field("Line No."), Version = field("Version Filter"), Operation = const('Run Procedure'), "Procedure Name" = filter(<> ''))); + } + field(41; "No. of Turns Passed"; Integer) + { + Caption = 'No. of Turns Passed'; + ToolTip = 'Specifies the total number of passed turns for the test line.'; + Editable = false; + FieldClass = FlowField; + CalcFormula = sum("AIT Log Entry"."No. of Turns Passed" where("Test Suite Code" = field("Test Suite Code"), "Test Method Line No." = field("Line No."), Version = field("Version Filter"), Operation = const('Run Procedure'), "Procedure Name" = filter(<> ''))); + } + field(45; Accuracy; Decimal) + { + Caption = 'Accuracy'; + ToolTip = 'Specifies the average accuracy of the test line.'; + Editable = false; + FieldClass = FlowField; + CalcFormula = average("AIT Log Entry"."Accuracy" where("Test Suite Code" = field("Test Suite Code"), "Test Method Line No." = field("Line No."), Version = field("Version Filter"), Operation = const('Run Procedure'), "Procedure Name" = filter(<> ''))); + } field(101; "AL Test Suite"; Code[10]) { Caption = 'AL Test Suite'; diff --git a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestMethodLines.Page.al b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestMethodLines.Page.al index 7af836cbed..9faae8490a 100644 --- a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestMethodLines.Page.al +++ b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestMethodLines.Page.al @@ -73,6 +73,52 @@ page 149034 "AIT Test Method Lines" AITLogEntry.DrillDownFailedAITLogEntries(Rec."Test Suite Code", Rec."Line No.", AITTestSuite.Version); end; } + field(Accuracy; Rec.Accuracy) + { + } + field(TurnsText; TurnsText) + { + Visible = false; + Editable = false; + Caption = 'No. of Turns Passed'; + ToolTip = 'Specifies the number of turns that passed out of the total number of turns.'; + + trigger OnDrillDown() + var + AITTestSuite: Record "AIT Test Suite"; + AITLogEntry: Codeunit "AIT Log Entry"; + begin + AITTestSuite.SetLoadFields("Base Version"); + AITTestSuite.Get(Rec."Test Suite Code"); + AITLogEntry.DrillDownFailedAITLogEntries(Rec."Test Suite Code", Rec."Line No.", AITTestSuite."Base Version"); + end; + } + field("No. of Turns"; Rec."No. of Turns Executed") + { + Visible = false; + } + field("No. of Turns Passed"; Rec."No. of Turns Passed") + { + Visible = false; + } + field("No. of Turns Failed"; Rec."No. of Turns Executed" - Rec."No. of Turns Passed") + { + Visible = false; + Editable = false; + Caption = 'No. of Turns Failed'; + ToolTip = 'Specifies the number of failed turns of the test line.'; + Style = Unfavorable; + + trigger OnDrillDown() + var + AITTestSuite: Record "AIT Test Suite"; + AITLogEntry: Codeunit "AIT Log Entry"; + begin + AITTestSuite.SetLoadFields("Base Version"); + AITTestSuite.Get(Rec."Test Suite Code"); + AITLogEntry.DrillDownFailedAITLogEntries(Rec."Test Suite Code", Rec."Line No.", AITTestSuite."Base Version"); + end; + } field("No. of Operations"; Rec."No. of Operations") { Visible = false; @@ -196,6 +242,7 @@ page 149034 "AIT Test Method Lines" AITTestSuite: Record "AIT Test Suite"; AITTestSuiteMgt: Codeunit "AIT Test Suite Mgt."; NoLineSelectedErr: Label 'Select a line to compare'; + TurnsText: Text; trigger OnInsertRecord(BelowxRec: Boolean): Boolean begin @@ -205,6 +252,11 @@ page 149034 "AIT Test Method Lines" if AITTestSuite.Get(Rec."Test Suite Code") then; end; + trigger OnAfterGetRecord() + begin + TurnsText := AITTestSuiteMgt.GetTurnsAsText(Rec); + end; + local procedure GetAvg(NumIterations: Integer; TotalNo: Integer): Integer begin if NumIterations = 0 then diff --git a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuite.Page.al b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuite.Page.al index a8fc966f54..a26ce9643c 100644 --- a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuite.Page.al +++ b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuite.Page.al @@ -127,6 +127,9 @@ page 149031 "AIT Test Suite" AITLogEntry.DrillDownFailedAITLogEntries(Rec.Code, 0, Rec.Version); end; } + field(Accuracy; Rec.Accuracy) + { + } field("No. of Operations"; Rec."No. of Operations") { Visible = false; @@ -257,6 +260,21 @@ page 149031 "AIT Test Suite" end; end; } + action("Export Results") + { + Caption = 'Export Results'; + Image = Export; + ToolTip = 'Exports the results.'; + + trigger OnAction() + var + AITLogEntry: Record "AIT Log Entry"; + AITTestSuiteMgt: Codeunit "AIT Test Suite Mgt."; + begin + AITLogEntry.SetRange(Version, Rec.Version); + AITTestSuiteMgt.ExportResults(AITLogEntry); + end; + } } area(Navigation) { diff --git a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuite.Table.al b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuite.Table.al index cf97553ad6..85c78c81de 100644 --- a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuite.Table.al +++ b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuite.Table.al @@ -161,6 +161,14 @@ table 149030 "AIT Test Suite" FieldClass = FlowField; CalcFormula = sum("AIT Log Entry"."Tokens Consumed" where("Test Suite Code" = field("Code"), Version = field("Version"), Operation = const('Run Procedure'), "Procedure Name" = filter(<> ''))); } + field(25; Accuracy; Decimal) + { + Caption = 'Accuracy'; + ToolTip = 'Specifies the average accuracy of the test suite.'; + Editable = false; + FieldClass = FlowField; + CalcFormula = average("AIT Log Entry"."Accuracy" where("Test Suite Code" = field("Code"), Version = field("Version"), Operation = const('Run Procedure'), "Procedure Name" = filter(<> ''))); + } field(50; "Test Runner Id"; Integer) { Caption = 'Test Runner Id'; diff --git a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuiteMgt.Codeunit.al b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuiteMgt.Codeunit.al index 5e080cd368..7ce127971c 100644 --- a/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuiteMgt.Codeunit.al +++ b/src/Tools/AI Test Toolkit/src/TestSuite/AITTestSuiteMgt.Codeunit.al @@ -28,6 +28,9 @@ codeunit 149034 "AIT Test Suite Mgt." CannotRunMultipleSuitesInParallelErr: Label 'There is already a test run in progress. You need to wait for it to finish or cancel it before starting a new test run.'; FeatureNameLbl: Label 'AI Test Toolkit', Locked = true; LineNoFilterLbl: Label 'Codeunit %1 "%2" (Input: %3)', Locked = true; + TurnsLbl: Label '%1/%2', Comment = '%1 - No. of turns that passed, %2 - Total no. of turns'; + DownloadResultsLbl: Label 'Download results'; + ResultsFileNameLbl: Label 'Results.xlsx', Locked = true; procedure StartAITSuite(Iterations: Integer; var AITTestSuite: Record "AIT Test Suite") var @@ -355,6 +358,9 @@ codeunit 149034 "AIT Test Suite Mgt." AITLogEntry."Procedure Name" := CurrentTestMethodLine.Function; AITLogEntry."Tokens Consumed" := AITTestRunIteration.GetAITokenUsedByLastTestMethodLine(); + AITLogEntry."No. of Turns Executed" := AITTestRunIteration.GetNumberOfTurnsForLastTestMethodLine(); + AITLogEntry."No. of Turns Passed" := AITTestRunIteration.GetNumberOfTurnsPassedForLastTestMethodLine(); + AITLogEntry.Accuracy := AITTestRunIteration.GetAccuracyForLastTestMethodLine(); AITLogEntry.Insert(true); Commit(); @@ -371,6 +377,17 @@ codeunit 149034 "AIT Test Suite Mgt." TelemetryCustomDimensions.Add('TotalDurationInMs', Format(TotalDurationInMs)); end; + internal procedure GetTurnsAsText(var AITTestMethodLine: Record "AIT Test Method Line"): Text + begin + AITTestMethodLine.CalcFields("No. of Turns Passed", "No. of Turns Executed"); + exit(StrSubstNo(TurnsLbl, AITTestMethodLine."No. of Turns Passed", AITTestMethodLine."No. of Turns Executed")); + end; + + internal procedure GetTurnsAsText(var AITLogEntry: Record "AIT Log Entry"): Text + begin + exit(StrSubstNo(TurnsLbl, AITLogEntry."No. of Turns Passed", AITLogEntry."No. of Turns Executed")); + end; + internal procedure GetAvgDuration(AITTestMethodLine: Record "AIT Test Method Line"): Integer begin if AITTestMethodLine."No. of Tests Executed" = 0 then @@ -440,6 +457,24 @@ codeunit 149034 "AIT Test Suite Mgt." exit(FeatureNameLbl); end; + internal procedure ExportResults(var AITLogEntries: Record "AIT Log Entry") + var + AITResults: Report "AIT Results"; + ResultsTempBlob: Codeunit "Temp Blob"; + ResultsOutStream: OutStream; + ResultsInStream: InStream; + Filename: Text; + begin + Filename := ResultsFileNameLbl; + ResultsTempBlob.CreateOutStream(ResultsOutStream); + + AITResults.SetTableView(AITLogEntries); + AITResults.SaveAs('', ReportFormat::Excel, ResultsOutStream); + + ResultsTempBlob.CreateInStream(ResultsInStream); + DownloadFromStream(ResultsInStream, DownloadResultsLbl, '', 'xlsx', Filename); + end; + [EventSubscriber(ObjectType::Table, Database::"AIT Test Suite", OnBeforeDeleteEvent, '', false, false)] local procedure DeleteLinesOnDeleteAITTestSuite(var Rec: Record "AIT Test Suite"; RunTrigger: Boolean) var