diff --git a/Ginger/Ginger/ALM/ALMDefectsProfilesPage.xaml.cs b/Ginger/Ginger/ALM/ALMDefectsProfilesPage.xaml.cs index 4be0871dd4..2590752e30 100644 --- a/Ginger/Ginger/ALM/ALMDefectsProfilesPage.xaml.cs +++ b/Ginger/Ginger/ALM/ALMDefectsProfilesPage.xaml.cs @@ -226,7 +226,7 @@ private void DeleteDefectsProfile(object sender, RoutedEventArgs e) if (grdDefectsProfiles.Grid.SelectedItems.Count > 0) { if (Reporter.ToUser(eUserMsgKey.AskBeforeDefectProfileDeleting) == Amdocs.Ginger.Common.eUserMsgSelection.Yes) - { + { foreach (ALMDefectProfile profileToDelete in grdDefectsProfiles.Grid.SelectedItems) { WorkSpace.Instance.SolutionRepository.DeleteRepositoryItem(profileToDelete); @@ -242,27 +242,35 @@ private void RefreshgrdDefectsProfilesHandler(object sender, RoutedEventArgs e) private void RefreshgrdDefectsFieldsHandler(object sender, RoutedEventArgs e) { - ALMDefectProfile AlmDefectProfile = (ALMDefectProfile)grdDefectsProfiles.CurrentItem; + try { - mALMDefectProfileFields = FetchDefectFields(AlmDefectProfile.AlmType); - mALMDefectProfileFields.Where(z => z.Mandatory).ToList().ForEach(x => x.SelectedValue = string.Empty); - mALMDefectProfileFieldsExisted = []; - foreach (ExternalItemFieldBase aLMDefectProfileField in mALMDefectProfileFields) + ALMDefectProfile AlmDefectProfile = (ALMDefectProfile)grdDefectsProfiles.CurrentItem; { - ExternalItemFieldBase aLMDefectProfileFieldExisted = (ExternalItemFieldBase)aLMDefectProfileField.CreateCopy(); - if (!string.IsNullOrEmpty(aLMDefectProfileField.ExternalID)) - { - aLMDefectProfileFieldExisted.ExternalID = string.Copy(aLMDefectProfileField.ExternalID); - } - ExternalItemFieldBase field = AlmDefectProfile.ALMDefectProfileFields.FirstOrDefault(x => x.ID == aLMDefectProfileField.ID); - if (field != null) + mALMDefectProfileFields = FetchDefectFields(AlmDefectProfile.AlmType); + mALMDefectProfileFields.Where(z => z.Mandatory).ToList().ForEach(x => x.SelectedValue = string.Empty); + mALMDefectProfileFieldsExisted = []; + foreach (ExternalItemFieldBase aLMDefectProfileField in mALMDefectProfileFields) { - aLMDefectProfileFieldExisted.SelectedValue = field.SelectedValue; + ExternalItemFieldBase aLMDefectProfileFieldExisted = (ExternalItemFieldBase)aLMDefectProfileField.CreateCopy(); + if (!string.IsNullOrEmpty(aLMDefectProfileField.ExternalID)) + { + aLMDefectProfileFieldExisted.ExternalID = string.Copy(aLMDefectProfileField.ExternalID); + } + ExternalItemFieldBase field = AlmDefectProfile.ALMDefectProfileFields.FirstOrDefault(x => x.ID == aLMDefectProfileField.ID); + if (field != null) + { + aLMDefectProfileFieldExisted.SelectedValue = field.SelectedValue; + } + aLMDefectProfileFieldExisted.PossibleValues = aLMDefectProfileField.PossibleValues; + mALMDefectProfileFieldsExisted.Add(aLMDefectProfileFieldExisted); } - aLMDefectProfileFieldExisted.PossibleValues = aLMDefectProfileField.PossibleValues; - mALMDefectProfileFieldsExisted.Add(aLMDefectProfileFieldExisted); + AlmDefectProfile.ALMDefectProfileFields = mALMDefectProfileFieldsExisted; } - AlmDefectProfile.ALMDefectProfileFields = mALMDefectProfileFieldsExisted; + } + catch (Exception ex) + { + Reporter.ToLog(eLogLevel.ERROR, "No Defect Profile is created"); + Reporter.ToUser(eUserMsgKey.NoDefectProfileCreated); } } private void FetchgrdDefectsFieldsHandler(object sender, RoutedEventArgs e) diff --git a/Ginger/Ginger/ALM/Repository/OctaneRepository.cs b/Ginger/Ginger/ALM/Repository/OctaneRepository.cs index 225991c2bc..a973436de4 100644 --- a/Ginger/Ginger/ALM/Repository/OctaneRepository.cs +++ b/Ginger/Ginger/ALM/Repository/OctaneRepository.cs @@ -169,26 +169,37 @@ public override bool ExportBusinessFlowToALM(BusinessFlow businessFlow, bool per if (!String.IsNullOrEmpty(businessFlow.ExternalID)) { matchingTS = ((OctaneCore)ALMIntegration.Instance.AlmCore).GetTestSuiteById(businessFlow.ExternalID); - if (matchingTS != null) + if (businessFlow.ALMTestSetLevel.Equals("RunSet", StringComparison.CurrentCultureIgnoreCase)) { - //ask user if want to continute - userSelec = Reporter.ToUser(eUserMsgKey.BusinessFlowAlreadyMappedToTC, businessFlow.Name, matchingTS.Name); - if (userSelec == eUserMsgSelection.Cancel) - { - return false; - } - else if (userSelec == eUserMsgSelection.No) + if (String.IsNullOrEmpty(testPlanUploadPath)) { - matchingTS = null; + testPlanUploadPath = matchingTS.ParentId; } - else + } + else + { + if (matchingTS != null) { - if (String.IsNullOrEmpty(testPlanUploadPath)) + //ask user if want to continute + userSelec = Reporter.ToUser(eUserMsgKey.BusinessFlowAlreadyMappedToTC, businessFlow.Name, matchingTS.Name); + if (userSelec == eUserMsgSelection.Cancel) { - testPlanUploadPath = matchingTS.ParentId; + return false; + } + else if (userSelec == eUserMsgSelection.No) + { + matchingTS = null; + } + else + { + if (String.IsNullOrEmpty(testPlanUploadPath)) + { + testPlanUploadPath = matchingTS.ParentId; + } } } } + } diff --git a/Ginger/Ginger/ALM/Repository/RQMRepository.cs b/Ginger/Ginger/ALM/Repository/RQMRepository.cs index 22bc6ce02e..a49ce34384 100644 --- a/Ginger/Ginger/ALM/Repository/RQMRepository.cs +++ b/Ginger/Ginger/ALM/Repository/RQMRepository.cs @@ -18,6 +18,7 @@ limitations under the License. using amdocs.ginger.GingerCoreNET; using Amdocs.Ginger.Common; +using Amdocs.Ginger.Repository; using Ginger.ALM.RQM; using GingerCore; using GingerCore.Activities; @@ -240,7 +241,9 @@ public override bool ExportBusinessFlowToALM(BusinessFlow businessFlow, bool per { return false; } - if (WorkSpace.Instance.Solution.ExternalItemsFields.Where(x => x.ItemType == "TestCase").ToList().Count == 0) + var originalExternalFields = GingerCoreNET.GeneralLib.General.GetExternalFields(); + + if (!originalExternalFields.Any(x => x.ItemType == "TestCase")) { Reporter.ToUser(eUserMsgKey.StaticInfoMessage, "Current solution have no predefined values for RQM's mandatory fields. Please configure before doing export. ('ALM'-'ALM Items Fields Configuration')"); return false; @@ -256,7 +259,7 @@ public override bool ExportBusinessFlowToALM(BusinessFlow businessFlow, bool per string res = string.Empty; Reporter.ToStatus(eStatusMsgKey.ExportItemToALM, null, businessFlow.Name); - exportRes = ((RQMCore)ALMIntegration.Instance.AlmCore).ExportBusinessFlowToRQM(businessFlow, WorkSpace.Instance.Solution.ExternalItemsFields, ref res); + exportRes = ((RQMCore)ALMIntegration.Instance.AlmCore).ExportBusinessFlowToRQM(businessFlow, originalExternalFields, ref res); if (exportRes) { @@ -288,6 +291,7 @@ public override bool ExportBusinessFlowToALM(BusinessFlow businessFlow, bool per return exportRes; } + #region External Item Fields public override eUserMsgKey GetDownloadPossibleValuesMessage() diff --git a/Ginger/Ginger/App.xaml.cs b/Ginger/Ginger/App.xaml.cs index 9fbc2513f7..c3090e8bd7 100644 --- a/Ginger/Ginger/App.xaml.cs +++ b/Ginger/Ginger/App.xaml.cs @@ -261,7 +261,6 @@ private async void Application_Startup(object sender, StartupEventArgs e) bool startGrid = ShouldStartGrid(e.Args); WorkSpace.Init(new WorkSpaceEventHandler(), startGrid); - var parserResult = ParseCommandLineArguments(e.Args); DoOptions doOptions = ExtractDoOptions(parserResult); @@ -271,9 +270,7 @@ private async void Application_Startup(object sender, StartupEventArgs e) WorkSpace.Instance.RunningInExecutionMode = true; Reporter.ReportAllAlsoToConsole = true; } - InitializeGingerCore(); - if (!WorkSpace.Instance.RunningInExecutionMode) { ProcessGingerUIStartup(doOptions); @@ -287,8 +284,8 @@ private async void Application_Startup(object sender, StartupEventArgs e) { Reporter.ToLog(eLogLevel.ERROR, "Unhandled exception in Application_Startup", ex); } - } - + } + /// /// Initializes the logging mechanism for the application using log4net. @@ -325,11 +322,16 @@ private ParserResult ParseCommandLineArguments(string[] args) if (args.Length == 1) { string input = args[0]; + input = input.Replace("\n", "").Replace("\r", ""); input = System.Web.HttpUtility.UrlDecode(input); if (input.StartsWith("ginger://")) { input = input.Substring("ginger://".Length); } + if (input.EndsWith("/")) + { + input = input.Substring(0, input.Length - 1); + } List resultList = General.SplitWithPaths(input).Select(s => s.Trim('\"', '\'')).ToList(); arguments = resultList.ToArray(); } @@ -338,11 +340,9 @@ private ParserResult ParseCommandLineArguments(string[] args) arguments = args; } - cliProcessor = new CLIProcessor(); return arguments.Length != 0 ? cliProcessor.ParseArguments(arguments) : null; } - /// /// Extracts the DoOptions object from the parser result if available and the operation is 'open'. /// Otherwise, returns null. diff --git a/Ginger/Ginger/AutomatePageLib/ExecutionSummaryPage.xaml.cs b/Ginger/Ginger/AutomatePageLib/ExecutionSummaryPage.xaml.cs index 9e8151c2d9..a576f024f4 100644 --- a/Ginger/Ginger/AutomatePageLib/ExecutionSummaryPage.xaml.cs +++ b/Ginger/Ginger/AutomatePageLib/ExecutionSummaryPage.xaml.cs @@ -148,13 +148,6 @@ public void SwitchLegend(string status) private void ShowStatus() { - // Why we create new GR? !!! - GingerExecutionEngine Gr = new GingerExecutionEngine(new GingerRunner()); - foreach (Activity activity in mContext.BusinessFlow.Activities) - { - Gr.CalculateActivityFinalStatus(activity); - } - Gr.CalculateBusinessFlowFinalStatus(mContext.BusinessFlow); StatusLabel.Content = mContext.BusinessFlow.RunStatus; StatusLabel.Foreground = General.GetStatusBrush(mContext.BusinessFlow.RunStatus); } diff --git a/Ginger/Ginger/AutomatePageLib/NewAutomatePage.xaml.cs b/Ginger/Ginger/AutomatePageLib/NewAutomatePage.xaml.cs index b1d4609de7..5c73ae92f0 100644 --- a/Ginger/Ginger/AutomatePageLib/NewAutomatePage.xaml.cs +++ b/Ginger/Ginger/AutomatePageLib/NewAutomatePage.xaml.cs @@ -1015,6 +1015,7 @@ private async Task RunAutomateTabFlow() await mExecutionEngine.RunBusinessFlowAsync(mBusinessFlow, true, false).ConfigureAwait(false); this.Dispatcher.Invoke(() => { + CalculateFinalStatusForReport(); if (WorkSpace.Instance.UserProfile.AutoGenerateAutomatePageReport) { GenerateReport(); @@ -1315,66 +1316,21 @@ private async Task ContinueRunFromAutomatePage(eContinueFrom continueFrom, objec switch (continueFrom) { case eContinueFrom.LastStoppedAction: + + LogExecutionDetailsUpToLastExecutedAction(mExecutionEngine.ExecutedActivityWhenStopped, mExecutionEngine.ExecutedActionWhenStopped); await mExecutionEngine.ContinueRunAsync(eContinueLevel.StandalonBusinessFlow, eContinueFrom.LastStoppedAction); break; case eContinueFrom.SpecificAction: Activity parentActivity = ((Tuple)executedItem).Item1; Act actionToExecute = ((Tuple)executedItem).Item2; - try - { - if (mExecutionEngine.ExecutionLoggerManager.Configuration.SelectedDataRepositoryMethod == ExecutionLoggerConfiguration.DataRepositoryMethod.LiteDB) - { - bool reachedCurrentAction = false; - foreach (Activity activity in mBusinessFlow.Activities) - { - foreach (Act action in activity.Acts.Cast()) - { - if (activity == parentActivity && action == actionToExecute) - { - reachedCurrentAction = true; - break; - } - mExecutionEngine.ExecutionLoggerManager.ActionEnd(0, action); - } - if (reachedCurrentAction) - { - break; - } - mExecutionEngine.ExecutionLoggerManager.ActivityEnd(0, activity); - } - } - } - catch (Exception ex) - { - Reporter.ToLog(eLogLevel.ERROR, "Error while logging previous activity and actions", ex); - } + LogExecutionDetailsUpToLastExecutedAction(parentActivity, actionToExecute); await mExecutionEngine.ContinueRunAsync(eContinueLevel.StandalonBusinessFlow, eContinueFrom.SpecificAction, mBusinessFlow, parentActivity, actionToExecute); break; case eContinueFrom.SpecificActivity: Activity activityToExecute = (Activity)executedItem; - try - { - if (mExecutionEngine.ExecutionLoggerManager.Configuration.SelectedDataRepositoryMethod == ExecutionLoggerConfiguration.DataRepositoryMethod.LiteDB) - { - foreach (Activity activity in mBusinessFlow.Activities) - { - if (activity == activityToExecute) - { - break; - } - foreach (Act action in activity.Acts.Cast()) - { - mExecutionEngine.ExecutionLoggerManager.ActionEnd(0, action); - } - mExecutionEngine.ExecutionLoggerManager.ActivityEnd(0, activity); - } - } - } - catch (Exception ex) - { - Reporter.ToLog(eLogLevel.ERROR, "Error while logging previous activity and actions", ex); - } + + LogExecutionDetailsUpToLastExecutedActivity(activityToExecute); mBusinessFlow.CurrentActivity = activityToExecute; @@ -1390,11 +1346,79 @@ private async Task ContinueRunFromAutomatePage(eContinueFrom continueFrom, objec } finally { + CalculateFinalStatusForReport(); //mExecutionIsInProgress = false; //SetUIElementsBehaverDuringExecution(); } } + /// + /// Logs the execution details up to the last executed activity. + /// + /// The activity to execute. + private void LogExecutionDetailsUpToLastExecutedActivity(Activity activityToExecute) + { + try + { + if (mExecutionEngine.ExecutionLoggerManager.Configuration.SelectedDataRepositoryMethod == ExecutionLoggerConfiguration.DataRepositoryMethod.LiteDB) + { + foreach (Activity activity in mBusinessFlow.Activities) + { + if (activity == activityToExecute) + { + break; + } + foreach (Act action in activity.Acts.Cast()) + { + mExecutionEngine.ExecutionLoggerManager.ActionEnd(0, action); + } + mExecutionEngine.ExecutionLoggerManager.ActivityEnd(0, activity); + } + } + } + catch (Exception ex) + { + Reporter.ToLog(eLogLevel.ERROR, "Error while logging previous activity and actions", ex); + } + } + + /// + /// Logs the execution details of actions and activities up to the last executed action. + /// + /// The parent activity containing the actions. + /// The action up to which the logging should be performed. + private void LogExecutionDetailsUpToLastExecutedAction(Activity parentActivity, Act actionToExecute) + { + try + { + if (mExecutionEngine.ExecutionLoggerManager.Configuration.SelectedDataRepositoryMethod == ExecutionLoggerConfiguration.DataRepositoryMethod.LiteDB) + { + bool reachedCurrentAction = false; + foreach (Activity activity in mBusinessFlow.Activities) + { + foreach (Act action in activity.Acts.Cast()) + { + if (activity == parentActivity && action == actionToExecute) + { + reachedCurrentAction = true; + break; + } + mExecutionEngine.ExecutionLoggerManager.ActionEnd(0, action); + } + if (reachedCurrentAction) + { + break; + } + mExecutionEngine.ExecutionLoggerManager.ActivityEnd(0, activity); + } + } + } + catch (Exception ex) + { + Reporter.ToLog(eLogLevel.ERROR, "Error while logging previous activity and actions", ex); + } + } + private void WorkSpacePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == nameof(WorkSpace.Solution)) @@ -1812,7 +1836,6 @@ private void GenerateReport() { if (mExecutionEngine.ExecutionLoggerManager.Configuration.SelectedDataRepositoryMethod == ExecutionLoggerConfiguration.DataRepositoryMethod.LiteDB) { - ((ExecutionLogger)mExecutionEngine.ExecutionLoggerManager.mExecutionLogger).RunSetUpdate(mRunSetLiteDbId, mRunnerLiteDbId, mExecutionEngine); CreateLiteDBReport(); return; } @@ -1883,14 +1906,31 @@ private void CreateLiteDBReport() private void ShowExecutionSummaryPage() { - if (mExecutionEngine.ExecutionLoggerManager.Configuration.SelectedDataRepositoryMethod == ExecutionLoggerConfiguration.DataRepositoryMethod.LiteDB) - { - ((ExecutionLogger)mExecutionEngine.ExecutionLoggerManager.mExecutionLogger).RunSetUpdate(mRunSetLiteDbId, mRunnerLiteDbId, mExecutionEngine); - } ExecutionSummaryPage w = new ExecutionSummaryPage(mContext); w.ShowAsWindow(); } + private void CalculateFinalStatusForReport() + { + try + { + if (mExecutionEngine.ExecutionLoggerManager.Configuration.SelectedDataRepositoryMethod == ExecutionLoggerConfiguration.DataRepositoryMethod.LiteDB) + { + ((ExecutionLogger)mExecutionEngine.ExecutionLoggerManager.mExecutionLogger).RunSetUpdate(mRunSetLiteDbId, mRunnerLiteDbId, mExecutionEngine); + } + + foreach (Activity activity in mContext.BusinessFlow.Activities) + { + mExecutionEngine.CalculateActivityFinalStatus(activity); + } + mExecutionEngine.CalculateBusinessFlowFinalStatus(mContext.BusinessFlow); + } + catch (Exception ex) + { + Reporter.ToLog(eLogLevel.DEBUG, "Error while CalculateFinalStatusForReport", ex); + } + } + private void xSummaryPageMenuItem_Click(object sender, RoutedEventArgs e) { if (CheckIfExecutionIsInProgress()) diff --git a/Ginger/Ginger/DLLs/AzureDevOpsRepo.dll b/Ginger/Ginger/DLLs/AzureDevOpsRepo.dll index 93aaa0cdc7..bd4160996c 100644 Binary files a/Ginger/Ginger/DLLs/AzureDevOpsRepo.dll and b/Ginger/Ginger/DLLs/AzureDevOpsRepo.dll differ diff --git a/Ginger/Ginger/External/Katalon/ImportKatalonObjectRepositoryIntro.md b/Ginger/Ginger/External/Katalon/ImportKatalonObjectRepositoryIntro.md index 65b7b2db64..7fbb91ba98 100644 --- a/Ginger/Ginger/External/Katalon/ImportKatalonObjectRepositoryIntro.md +++ b/Ginger/Ginger/External/Katalon/ImportKatalonObjectRepositoryIntro.md @@ -1,7 +1,12 @@ -### Introduction -Import Katalon Object-Repositories as Ginger Page Object Models. +### Katalon Object Repository Import Introduction +Katalon Object Repositories store GUI page objects (buttons, text boxes, drop-down lists) from Katalon projects. +Import these repositories to Ginger to reuse existing automation assets efficiently. -You need to select the folder containing the Katalon Object-Repositories. -You will be shown the list of Page Object Models that will be imported. -You can provide the Target Application and URL for each Page Object Model. -Clicking on 'Finish' will import the Page Object Models. \ No newline at end of file +### How to create a Katalon Object Repository Import? +Right-click on POM folder in Ginger > select "Import" > "Katalon Object Repository". +Browse to your Katalon project folder, set Target Application and URL. +Click finish to convert repositories to Ginger's POM format. + +### How to use Katalon Object Repository in Execution? +Set 'Locate By' to 'Page Objects Model Element' and select the desired object. +Imported repositories can be edited and assigned to Target Applications as needed. \ No newline at end of file diff --git a/Ginger/Ginger/External/Katalon/ImportKatalonObjectRepositoryWizard.cs b/Ginger/Ginger/External/Katalon/ImportKatalonObjectRepositoryWizard.cs index 3072bb9b2f..bdd7a1dfab 100644 --- a/Ginger/Ginger/External/Katalon/ImportKatalonObjectRepositoryWizard.cs +++ b/Ginger/Ginger/External/Katalon/ImportKatalonObjectRepositoryWizard.cs @@ -2,6 +2,7 @@ using Amdocs.Ginger.Repository; using Ginger.WizardLib; using GingerWPF.WizardLib; +using System; using System.ComponentModel; namespace Ginger.External.Katalon @@ -11,9 +12,21 @@ public sealed class ImportKatalonObjectRepositoryWizard : WizardBase, INotifyPro private readonly RepositoryFolder _importTargetDirectory; private string _selectedDirectory; + private int _importedPOMCount; public ObservableList POMViewModels { get; } + public int ImportedPOMCount + { + get => _importedPOMCount; + private set + { + _importedPOMCount = value; + PropertyChanged?.Invoke(sender: this, new(nameof(ImportedPOMCount))); + } + } + + public string ImportTargetDirectoryPath => _importTargetDirectory.FolderFullPath; public string SelectedDirectory { @@ -39,22 +52,53 @@ internal ImportKatalonObjectRepositoryWizard(RepositoryFolder + - + + + + + + + + + + + + + diff --git a/Ginger/Ginger/External/Katalon/ImportPOMFromObjectRepositoryWizardPage.xaml.cs b/Ginger/Ginger/External/Katalon/ImportPOMFromObjectRepositoryWizardPage.xaml.cs index b0aec5b8c7..a2a8682e57 100644 --- a/Ginger/Ginger/External/Katalon/ImportPOMFromObjectRepositoryWizardPage.xaml.cs +++ b/Ginger/Ginger/External/Katalon/ImportPOMFromObjectRepositoryWizardPage.xaml.cs @@ -6,10 +6,12 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using System.Windows.Data; namespace Ginger.External.Katalon { @@ -84,7 +86,7 @@ private void InitImportedPOMGrid() "Set highlighted Target Application for all", ImportedPOMGrid_Toolbar_SyncTargetApplication); ImportedPOMGrid.AddToolbarTool( - eImageType.Browser, + eImageType.Globe, "Set highlighted URL for all", ImportedPOMGrid_Toolbar_SyncURL); @@ -123,7 +125,11 @@ private void ImportedPOMGrid_Toolbar_SyncTargetApplication(object? sender, Route .GetFilteredItems() .Cast(); - KatalonConvertedPOMViewModel highlightedItem = (KatalonConvertedPOMViewModel)ImportedPOMGrid.CurrentItem; + KatalonConvertedPOMViewModel? highlightedItem = (KatalonConvertedPOMViewModel)ImportedPOMGrid.CurrentItem; + if (highlightedItem == null) + { + return; + } foreach (KatalonConvertedPOMViewModel item in visibleItems) { @@ -149,7 +155,11 @@ private void ImportedPOMGrid_Toolbar_SyncURL(object? sender, RoutedEventArgs e) .GetFilteredItems() .Cast(); - KatalonConvertedPOMViewModel highlightedItem = (KatalonConvertedPOMViewModel)ImportedPOMGrid.CurrentItem; + KatalonConvertedPOMViewModel? highlightedItem = (KatalonConvertedPOMViewModel)ImportedPOMGrid.CurrentItem; + if (highlightedItem == null) + { + return; + } foreach (KatalonConvertedPOMViewModel item in visibleItems) { @@ -169,6 +179,22 @@ public void WizardEvent(WizardEventArgs e) case EventType.Active: _ = ImportPOMsAsync(); break; + case EventType.LeavingForNextPage: + bool hasAnyInvalidPOM = false; + foreach (KatalonConvertedPOMViewModel pom in _wizard.POMViewModels) + { + if (pom.Active && !pom.IsValid()) + { + hasAnyInvalidPOM = true; + pom.ShowAllErrorHighlights(); + } + } + e.CancelEvent = hasAnyInvalidPOM; + if (!hasAnyInvalidPOM) + { + _wizard.AddPOMs(); + } + break; default: break; } @@ -178,6 +204,7 @@ private async Task ImportPOMsAsync() { try { + _wizard.ProcessStarted(); _wizard.POMViewModels.ClearAll(); _conversionResults.ClearAll(); ImportedPOMGrid.DisableGridColoumns(); @@ -188,6 +215,10 @@ private async Task ImportPOMsAsync() { Reporter.ToLog(eLogLevel.ERROR, "Error while importing Katalon Object-Repository as Ginger POM", ex); } + finally + { + _wizard.ProcessEnded(); + } } private void ConversionResults_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) @@ -207,4 +238,21 @@ private void ConversionResults_CollectionChanged(object? sender, NotifyCollectio _wizard.POMViewModels.Add(new(conversionResult.POM, conversionResult.Platform)); } } + + public sealed class BoolToErrorBorderThicknessConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is bool boolValue) + { + return boolValue ? new Thickness(uniformLength: 1) : new Thickness(uniformLength: 0); + } + return new Thickness(uniformLength: 0); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } } diff --git a/Ginger/Ginger/External/Katalon/ImportPOMSummaryWizardPage.xaml b/Ginger/Ginger/External/Katalon/ImportPOMSummaryWizardPage.xaml new file mode 100644 index 0000000000..05fe90b17b --- /dev/null +++ b/Ginger/Ginger/External/Katalon/ImportPOMSummaryWizardPage.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Ginger/Ginger/External/Katalon/ImportPOMSummaryWizardPage.xaml.cs b/Ginger/Ginger/External/Katalon/ImportPOMSummaryWizardPage.xaml.cs new file mode 100644 index 0000000000..db1bec3677 --- /dev/null +++ b/Ginger/Ginger/External/Katalon/ImportPOMSummaryWizardPage.xaml.cs @@ -0,0 +1,55 @@ +using GingerWPF.WizardLib; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; + +namespace Ginger.External.Katalon +{ + /// + /// Interaction logic for ImportPOMSummaryWizardPage.xaml + /// + public partial class ImportPOMSummaryWizardPage : Page, IWizardPage + { + private readonly ImportKatalonObjectRepositoryWizard _wizard; + + public ImportPOMSummaryWizardPage(ImportKatalonObjectRepositoryWizard wizard) + { + InitializeComponent(); + _wizard = wizard; + _wizard.PropertyChanged += Wizard_PropertyChanged; + } + + private void Wizard_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (!string.Equals(e.PropertyName, nameof(ImportKatalonObjectRepositoryWizard.ImportedPOMCount))) + { + return; + } + + UpdateSummary(_wizard.ImportedPOMCount); + } + + public void WizardEvent(WizardEventArgs e) + { + + } + + private void UpdateSummary(int importedPOMCount) + { + if (!string.Equals(ImportCountTextBlock.Text, importedPOMCount.ToString())) + { + ImportCountTextBlock.Text = importedPOMCount.ToString(); + } + + if (importedPOMCount <= 0 && ImportLocationStackPanel.Visibility != Visibility.Collapsed) + { + ImportLocationStackPanel.Visibility = Visibility.Collapsed; + } + else if (ImportLocationStackPanel.Visibility != Visibility.Visible) + { + ImportLocationStackPanel.Visibility = Visibility.Visible; + ImportLocationTextBlock.Text = _wizard.ImportTargetDirectoryPath; + } + } + } +} diff --git a/Ginger/Ginger/External/Katalon/KatalonConvertedPOMViewModel.cs b/Ginger/Ginger/External/Katalon/KatalonConvertedPOMViewModel.cs index 18b14f5bdd..0ba8d5f5ea 100644 --- a/Ginger/Ginger/External/Katalon/KatalonConvertedPOMViewModel.cs +++ b/Ginger/Ginger/External/Katalon/KatalonConvertedPOMViewModel.cs @@ -14,6 +14,7 @@ public sealed class KatalonConvertedPOMViewModel : INotifyPropertyChanged private string _name; private string _url; private string _targetApplication; + private bool _showTargetApplicationErrorHighlight; public bool Active { @@ -51,12 +52,26 @@ public string TargetApplication set { _targetApplication = value ?? string.Empty; + if (IsTargetApplicationValid()) + { + ShowTargetApplicationErrorHighlight = false; + } PropertyChanged?.Invoke(sender: this, new(nameof(TargetApplication))); } } public IEnumerable TargetApplicationOptions { get; } + public bool ShowTargetApplicationErrorHighlight + { + get => _showTargetApplicationErrorHighlight; + set + { + _showTargetApplicationErrorHighlight = value; + PropertyChanged?.Invoke(sender: this, new(nameof(ShowTargetApplicationErrorHighlight))); + } + } + public ApplicationPOMModel POM { get; } public event PropertyChangedEventHandler? PropertyChanged; @@ -71,13 +86,18 @@ public KatalonConvertedPOMViewModel(ApplicationPOMModel pom, ePlatformType platf _url = string.Empty; _targetApplication = string.Empty; - TargetApplicationOptions = WorkSpace + List solutionTargetApps = WorkSpace .Instance .Solution .GetSolutionTargetApplications() .Where(ta => GetApplicationPlatform(ta.Name) == platform) .Select(ta => ta.Name) .ToList(); + + TargetApplicationOptions = + new string[] { string.Empty } + .Concat(solutionTargetApps) + .ToArray(); } private ePlatformType GetApplicationPlatform(string application) @@ -92,6 +112,33 @@ private ePlatformType GetApplicationPlatform(string application) return WorkSpace.Instance.Solution.GetApplicationPlatformForTargetApp(application); } + public bool IsValid() + { + if (!IsTargetApplicationValid()) + { + return false; + } + return true; + } + + public void ShowAllErrorHighlights() + { + if (!IsTargetApplicationValid()) + { + ShowTargetApplicationErrorHighlight = true; + } + } + + public void ClearAllErrorHighlights() + { + ShowTargetApplicationErrorHighlight = false; + } + + public bool IsTargetApplicationValid() + { + return !string.IsNullOrWhiteSpace(TargetApplication); + } + public void CommitChanges() { if (!string.IsNullOrWhiteSpace(URL)) diff --git a/Ginger/Ginger/RunSetPageLib/RunnerItemPage.xaml.cs b/Ginger/Ginger/RunSetPageLib/RunnerItemPage.xaml.cs index fa747495ad..d5c82eca4a 100644 --- a/Ginger/Ginger/RunSetPageLib/RunnerItemPage.xaml.cs +++ b/Ginger/Ginger/RunSetPageLib/RunnerItemPage.xaml.cs @@ -77,7 +77,7 @@ public eRunnerItemType ItemtType { return eRunnerItemType.BusinessFlow; } - else if (ItemObject.GetType() == typeof(GingerCore.Activity)) + else if (ItemObject is Activity) { return eRunnerItemType.Activity; } @@ -186,7 +186,7 @@ public void LoadChildRunnerItems() } else if (ItemObject is Activity activity) { - IEnumerable acts = null; + IEnumerable acts = ((Activity)ItemObject).Acts.OfType(); if (acts != null) { diff --git a/Ginger/Ginger/SolutionWindows/TreeViewItems/ApplicationModelsTreeItems/ApplicationPOMsTreeItem.cs b/Ginger/Ginger/SolutionWindows/TreeViewItems/ApplicationModelsTreeItems/ApplicationPOMsTreeItem.cs index 6311fcdbff..1cceab40a2 100644 --- a/Ginger/Ginger/SolutionWindows/TreeViewItems/ApplicationModelsTreeItems/ApplicationPOMsTreeItem.cs +++ b/Ginger/Ginger/SolutionWindows/TreeViewItems/ApplicationModelsTreeItems/ApplicationPOMsTreeItem.cs @@ -131,7 +131,7 @@ void ITreeViewItem.SetTools(ITreeView TV) { AddFolderNodeBasicManipulationsOptions(mContextMenu, "Page Objects Model", allowAddNew: false, allowRefresh: false); } - MenuItem importMenu = TreeViewUtils.CreateSubMenu(mContextMenu, "Import", eImageType.Add); + MenuItem importMenu = TreeViewUtils.CreateSubMenu(mContextMenu, "Import", eImageType.ImportFile); TreeViewUtils.AddSubMenuItem(importMenu, "Katalon Object-Repository", ImportFromKatalonObjectRepository, CommandParameter: null!, icon: eImageType.Katalon); AddSourceControlOptions(mContextMenu); diff --git a/Ginger/Ginger/Variables/VariableEditPage.xaml.cs b/Ginger/Ginger/Variables/VariableEditPage.xaml.cs index ec35211210..bbf800f640 100644 --- a/Ginger/Ginger/Variables/VariableEditPage.xaml.cs +++ b/Ginger/Ginger/Variables/VariableEditPage.xaml.cs @@ -85,7 +85,7 @@ public VariableEditPage(VariableBase v, Context context, bool setGeneralConfigsA xVarNameTxtBox.GotFocus += XVarNameTxtBox_GotFocus; xVarNameTxtBox.LostFocus += XVarNameTxtBox_LostFocus; - if (parent.GOpsFlag) + if (parent is not null && parent.GOpsFlag) { xVarNameTxtBox.IsEnabled = false; xVarDescritpiontxtBox.IsEnabled = false; diff --git a/Ginger/GingerCoreCommon/Actions/Act.cs b/Ginger/GingerCoreCommon/Actions/Act.cs index 6c6d220ae3..35b615007d 100644 --- a/Ginger/GingerCoreCommon/Actions/Act.cs +++ b/Ginger/GingerCoreCommon/Actions/Act.cs @@ -2075,5 +2075,49 @@ public override string GetItemType() } + /// + /// Compares the current Act instance with another Act instance to determine equality. + /// + /// The other Act instance to compare with. + /// True if the instances are equal; otherwise, false. + public bool AreEqual(Act other) + { + if (other == null || this.ActInputValues.Count != other.ActInputValues.Count) + { + return false; + } + + if (this.Description != other.Description || + this.Platform != other.Platform) + { + return false; + } + + for (int i = 0; i < this.ActInputValues.Count; i++) + { + if (!this.ActInputValues[i].AreEqual(other.ActInputValues[i])) + { + return false; + } + } + + return true; + } + + /// + /// Compares the current Act instance with another object to determine equality. + /// + /// The object to compare with. + /// True if the object is an Act instance and is equal to the current instance; otherwise, false. + public bool AreEqual(object obj) + { + if (obj == null || obj.GetType() != this.GetType()) + { + return false; + } + + return Equals(obj as Act); + } + } } diff --git a/Ginger/GingerCoreCommon/Actions/ActInputValue.cs b/Ginger/GingerCoreCommon/Actions/ActInputValue.cs index 3f6898eed4..94476764fe 100644 --- a/Ginger/GingerCoreCommon/Actions/ActInputValue.cs +++ b/Ginger/GingerCoreCommon/Actions/ActInputValue.cs @@ -1,4 +1,4 @@ -#region License +#region License /* Copyright © 2014-2024 European Support Limited @@ -226,5 +226,37 @@ public override string ItemNameField } } + /// + /// Compares this instance with another ActInputValue instance for equality. + /// + /// The other ActInputValue instance to compare with. + /// True if both instances are equal; otherwise, false. + public bool AreEqual(ActInputValue other) + { + if (other == null) + { + return false; + } + + return this.Param == other.Param && + this.Value == other.Value; + } + + /// + /// Compares this instance with another object for equality. + /// + /// The object to compare with. + /// True if the object is an ActInputValue instance and both instances are equal; otherwise, false. + public bool AreEqual(object obj) + { + if (obj == null || obj.GetType() != this.GetType()) + { + return false; + } + + return Equals(obj as ActInputValue); + } + + } } diff --git a/Ginger/GingerCoreCommon/GingerCoreCommon.csproj b/Ginger/GingerCoreCommon/GingerCoreCommon.csproj index 1f9aeb8bfb..e0e8a73099 100644 --- a/Ginger/GingerCoreCommon/GingerCoreCommon.csproj +++ b/Ginger/GingerCoreCommon/GingerCoreCommon.csproj @@ -11,8 +11,8 @@ net8.0 Amdocs.Ginger.Common - 24.4.0.0 - 24.4.0.0 + 24.5.1.0 + 24.5.1.0 Ginger.Core.Common Amdocs @@ -20,7 +20,7 @@ Ginger by Amdocs Copyright © 2014-2024 European Support Limited - 24.4.0.0 + 24.5.1.0 Ginger Core Common True diff --git a/Ginger/GingerCoreCommon/InterfacesLib/IAct.cs b/Ginger/GingerCoreCommon/InterfacesLib/IAct.cs index 9b56148844..099580f97c 100644 --- a/Ginger/GingerCoreCommon/InterfacesLib/IAct.cs +++ b/Ginger/GingerCoreCommon/InterfacesLib/IAct.cs @@ -21,6 +21,7 @@ limitations under the License. using Amdocs.Ginger.Common.Actions; using Amdocs.Ginger.CoreNET.Execution; using Amdocs.Ginger.Repository; +using GingerCore.Actions; using GingerCore.FlowControlLib; using GingerCore.Variables; @@ -77,6 +78,7 @@ public interface IAct /// Gets a value indicating whether automatic screenshot capture is enabled on failure. /// bool AutoScreenShotOnFailure { get; } - + public bool AreEqual(Act other); + public bool AreEqual(object other); } } diff --git a/Ginger/GingerCoreCommon/Repository/ALMLib/ExternalItemFieldBase.cs b/Ginger/GingerCoreCommon/Repository/ALMLib/ExternalItemFieldBase.cs index 7d0628a285..b71d87727e 100644 --- a/Ginger/GingerCoreCommon/Repository/ALMLib/ExternalItemFieldBase.cs +++ b/Ginger/GingerCoreCommon/Repository/ALMLib/ExternalItemFieldBase.cs @@ -58,6 +58,12 @@ public static class Fields public bool SystemFieled { get; set; } public bool IsMultiple { get; set; } = false; + [IsSerializedForLocalRepository] + public bool IsCustomField { get; set; } = false; + + [IsSerializedForLocalRepository] + public string ProjectGuid { get; set; } + ObservableList mPossibleValues = []; public ObservableList PossibleValues { diff --git a/Ginger/GingerCoreCommon/Repository/BusinessFlowLib/Activity.cs b/Ginger/GingerCoreCommon/Repository/BusinessFlowLib/Activity.cs index 61274b7108..36c22c9817 100644 --- a/Ginger/GingerCoreCommon/Repository/BusinessFlowLib/Activity.cs +++ b/Ginger/GingerCoreCommon/Repository/BusinessFlowLib/Activity.cs @@ -1278,5 +1278,56 @@ public List VariablesSummary } } + /// + /// Compares this instance with another Activity instance to determine if they are equal. + /// + /// The other Activity instance to compare with. + /// True if the instances are equal; otherwise, false. + public bool AreEqual(Activity other) + { + if (other == null || this.Acts.Count != other.Acts.Count || this.Variables.Count != other.Variables.Count) + { + return false; + } + + if (this.ActivityName != other.ActivityName || this.TargetApplication != other.TargetApplication || + this.Type != other.Type || this.ActivitiesGroupID != other.ActivitiesGroupID) + { + return false; + } + + for (int i = 0; i < this.Acts.Count; i++) + { + if (!this.Acts[i].AreEqual(other.Acts[i])) + { + return false; + } + } + + for (int i = 0; i < this.Variables.Count; i++) + { + if (!this.Variables[i].AreEqual(other.Variables[i])) + { + return false; + } + } + + return true; + } + + /// + /// Compares this instance with another object to determine if they are equal. + /// + /// The object to compare with. + /// True if the objects are equal; otherwise, false. + public bool AreEqual(object obj) + { + if (obj == null || obj.GetType() != this.GetType()) + { + return false; + } + + return AreEqual(obj as Activity); + } } } diff --git a/Ginger/GingerCoreCommon/Repository/BusinessFlowLib/BusinessFlow.cs b/Ginger/GingerCoreCommon/Repository/BusinessFlowLib/BusinessFlow.cs index b2a4e4b192..63b7841024 100644 --- a/Ginger/GingerCoreCommon/Repository/BusinessFlowLib/BusinessFlow.cs +++ b/Ginger/GingerCoreCommon/Repository/BusinessFlowLib/BusinessFlow.cs @@ -2045,5 +2045,58 @@ public List VariablesSummary return variableDetails; } } + + public bool AreEqual(BusinessFlow other) + { + if (other == null || this.Name != other.Name + || this.Activities.Count != other.Activities.Count + || this.Variables.Count != other.Variables.Count + || this.TargetApplications.Count != other.TargetApplications.Count) + { + return false; + } + + for (int i = 0; i < this.TargetApplications.Count; i++) + { + if (!other.TargetApplications.Any(f => f.Name.Equals(this.TargetApplications[i].Name) + && f.Guid.Equals(this.TargetApplications[i].Guid))) + { + return false; + } + } + + for (int i = 0; i < this.Variables.Count; i++) + { + if (!this.Variables[i].AreEqual(other.Variables[i])) + { + return false; + } + } + + for (int i = 0; i < this.Activities.Count; i++) + { + if (!this.Activities[i].AreEqual(other.Activities[i])) + { + return false; + } + } + + return true; + } + + /// + /// Compares this instance with another object to determine if they are equal. + /// + /// The object to compare with. + /// True if the objects are equal; otherwise, false. + public bool AreEqual(object obj) + { + if (obj == null || obj.GetType() != this.GetType()) + { + return false; + } + + return AreEqual(obj as BusinessFlow); + } } } diff --git a/Ginger/GingerCoreCommon/VariablesLib/VariableBase.cs b/Ginger/GingerCoreCommon/VariablesLib/VariableBase.cs index eeca70ed7f..7f4a0d5cae 100644 --- a/Ginger/GingerCoreCommon/VariablesLib/VariableBase.cs +++ b/Ginger/GingerCoreCommon/VariablesLib/VariableBase.cs @@ -706,5 +706,37 @@ public virtual string GetInitialValue() { return string.Empty; } + + /// + /// Compares this instance with another VariableBase instance for equality. + /// + /// The other VariableBase instance to compare with. + /// True if the instances are equal; otherwise, false. + public bool AreEqual(VariableBase other) + { + if (other == null) + { + return false; + } + + return this.Name == other.Name && + this.VariableType == other.VariableType && + this.GetInitialValue() == other.GetInitialValue(); + } + + /// + /// Compares this instance with another object for equality. + /// + /// The object to compare with. + /// True if the objects are equal; otherwise, false. + public bool AreEqual(object obj) + { + if (obj == null || obj.GetType() != this.GetType()) + { + return false; + } + + return Equals(obj as VariableBase); + } } } diff --git a/Ginger/GingerCoreNET/ALMLib/Azure/AzureDevOpsCore.cs b/Ginger/GingerCoreNET/ALMLib/Azure/AzureDevOpsCore.cs index c9b17ac242..0aa20d8294 100644 --- a/Ginger/GingerCoreNET/ALMLib/Azure/AzureDevOpsCore.cs +++ b/Ginger/GingerCoreNET/ALMLib/Azure/AzureDevOpsCore.cs @@ -22,6 +22,7 @@ limitations under the License. using Amdocs.Ginger.CoreNET.ALMLib.Azure; using Amdocs.Ginger.CoreNET.ALMLib.DataContract; using Amdocs.Ginger.Repository; +using Applitools.Utils; using AzureRepositoryStd; using AzureRepositoryStd.BLL; using GingerCore.Activities; @@ -122,7 +123,7 @@ public override bool ConnectALMServer() public Dictionary AzureProjectList() { - dynamic list = AzureDevOpsRepository.GetLoginProjects(ALMCore.DefaultAlmConfig.ALMServerURL, ALMCore.DefaultAlmConfig.ALMPassword); + dynamic list = AzureDevOpsManager.GetProjectsList(ALMCore.DefaultAlmConfig.ALMServerURL, ALMCore.DefaultAlmConfig.ALMPassword); Dictionary listOfItems = []; if (list.DataResult is null) { @@ -146,27 +147,9 @@ public override Dictionary CreateNewALMDefects(Dictionary defectsOpeningResults = []; - List screenshots = []; foreach (KeyValuePair> defectForOpening in defectsForOpening) { - string summaryValue = defectForOpening.Value.ContainsKey("Summary") ? defectForOpening.Value["Summary"] : string.Empty; - if (!string.IsNullOrEmpty(summaryValue)) - { - string defectId = CheckIfDefectExist(summaryValue); - if (!string.IsNullOrEmpty(defectId)) - { - defectsOpeningResults.Add(defectForOpening.Key, defectId); - continue; - } - else - { - string paths = defectForOpening.Value.ContainsKey("screenshots") ? defectForOpening.Value["screenshots"] : string.Empty; - screenshots.Add(paths); - } - } - - defectsOpeningResults.Add(defectForOpening.Key, CreateDefectData(defectForOpening).Id.ToString()); - + defectsOpeningResults.Add(defectForOpening.Key, CreateOrUpdateDefectData(defectForOpening).Id.ToString()); } return defectsOpeningResults; } @@ -178,16 +161,30 @@ public override Dictionary CreateNewALMDefects(Dictionary> defectForOpening) + private static WorkItem CreateOrUpdateDefectData(KeyValuePair> defectForOpening) { try { + string tempDefectId = string.Empty; + + string summaryValue = defectForOpening.Value.ContainsKey("Summary") ? defectForOpening.Value["Summary"] : string.Empty; + if (!string.IsNullOrEmpty(summaryValue)) + { + string defectId = CheckIfDefectExist(summaryValue); + if (!string.IsNullOrEmpty(defectId)) + { + tempDefectId = defectId; + } + } + LoginDTO login = GetLoginDTO(); VssConnection connection = AzureDevOpsRepository.LoginAzure(login); WorkItemTrackingHttpClient workItemTrackingClient = connection.GetClient(); + Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItem newWorkItem = null; + JsonPatchDocument patchDocument = [ new JsonPatchOperation() @@ -206,7 +203,14 @@ private static WorkItem CreateDefectData(KeyValuePair GetALMItemFields(Backgroun string[] witType = ["Test Case", "Test Suite", "Test Plan"]; foreach (var i in witType) { - List listnodes = AzureDevOpsRepository.GetListNodes(_loginDto, i); + List listnodes = AzureDevOpsManager.GetListNodes(_loginDto, i); ExtractFields(fields, i, listnodes); } diff --git a/Ginger/GingerCoreNET/ALMLib/RQM/ExportToRQM.cs b/Ginger/GingerCoreNET/ALMLib/RQM/ExportToRQM.cs index a30717812e..91670ee6d0 100644 --- a/Ginger/GingerCoreNET/ALMLib/RQM/ExportToRQM.cs +++ b/Ginger/GingerCoreNET/ALMLib/RQM/ExportToRQM.cs @@ -22,9 +22,9 @@ limitations under the License. using Amdocs.Ginger.Common; using Amdocs.Ginger.Common.InterfacesLib; using Amdocs.Ginger.IO; -using Amdocs.Ginger.Repository; using GingerCore.Activities; using GingerCore.Environments; +using GingerCoreNET.GeneralLib; using Newtonsoft.Json; using RQMExportStd.ExportBLL; using System; @@ -38,6 +38,7 @@ limitations under the License. using System.Threading; using System.Xml; using System.Xml.Serialization; +using ExternalItemFieldBase = Amdocs.Ginger.Repository.ExternalItemFieldBase; //using AlmDataContractsStd.Contracts; namespace GingerCore.ALM.RQM @@ -107,6 +108,14 @@ private void GetRQMProjectListConfiguration() RQMTestPlan testPlan; public bool ExportExecutionDetailsToRQM(BusinessFlow businessFlow, ref string result, bool exectutedFromAutomateTab = false, PublishToALMConfig publishToALMConfig = null, ProjEnvironment projEnvironment = null) { + var originalExternalFields = General.GetExternalFields(); + + if (!originalExternalFields.Any(x => x.ItemType == "TestCase")) + { + Reporter.ToUser(eUserMsgKey.StaticInfoMessage, "Current solution have no predefined values for RQM's mandatory fields. Please configure before doing export. ('ALM'-'ALM Items Fields Configuration')"); + return false; + } + List ExternalFields = ConvertExternalFieldsToACLDataContractfields(originalExternalFields); result = string.Empty; string bfExportedID = GetExportedIDString(businessFlow.ExternalIdCalCulated, "RQMID"); if (string.IsNullOrEmpty(bfExportedID) || bfExportedID.Equals("0")) @@ -192,7 +201,7 @@ public bool ExportExecutionDetailsToRQM(BusinessFlow businessFlow, ref string re || publishToALMConfig.FilterStatus == FilterByStatus.All) { testPlan.Name = !string.IsNullOrEmpty(publishToALMConfig.VariableForTCRunNameCalculated) ? publishToALMConfig.VariableForTCRunNameCalculated : testPlan.Name; - ExecutionResult exeResult = GetExeResultforActivityGroup(businessFlow, bfExportedID, activGroup, ref result, testPlan, currentRQMProjectMapping, loginData, publishToALMConfig); + ExecutionResult exeResult = GetExeResultforActivityGroup(businessFlow, bfExportedID, activGroup, ref result, testPlan, currentRQMProjectMapping, loginData, publishToALMConfig, ExternalFields); if (exeResult != null) { exeResultList.Add(exeResult); @@ -240,7 +249,7 @@ public bool ExportExecutionDetailsToRQM(BusinessFlow businessFlow, ref string re } valuelist.Add(exeResultList.FirstOrDefault().TestCaseExportID); - resultInfo = RQMConnect.Instance.RQMRep.ExportExecutionResult(loginData, exeResultList, RQMCore.ALMProjectGuid, ALMCore.DefaultAlmConfig.ALMProjectName, RQMCore.ALMProjectGroupName); + resultInfo = RQMConnect.Instance.RQMRep.ExportExecutionResult(loginData, exeResultList, RQMCore.ALMProjectGuid, ALMCore.DefaultAlmConfig.ALMProjectName, RQMCore.ALMProjectGroupName,null, ExternalFields); if (!resultInfo.IsSuccess) { Reporter.ToLog(eLogLevel.ERROR, $"Failed to Update Execution Record Results for {businessFlow.Name} and testplan {bfExportedID}, execution record id {exeResultList.FirstOrDefault().ExecutionRecordExportID} Error: {resultInfo.ErrorDesc}"); @@ -372,7 +381,7 @@ public bool ExportExecutionDetailsToRQM(BusinessFlow businessFlow, ref string re // get data about execution records per current test plan - finish return false; } - private ExecutionResult GetExeResultforActivityGroup(BusinessFlow businessFlow, string bfExportedID, ActivitiesGroup activGroup, ref string result, RQMTestPlan testPlan, RQMProject currentRQMProjectMapping, LoginDTO loginData, PublishToALMConfig publishToALMConfig) + private ExecutionResult GetExeResultforActivityGroup(BusinessFlow businessFlow, string bfExportedID, ActivitiesGroup activGroup, ref string result, RQMTestPlan testPlan, RQMProject currentRQMProjectMapping, LoginDTO loginData, PublishToALMConfig publishToALMConfig, List ExternalFields = null) { try { @@ -505,7 +514,7 @@ private ExecutionResult GetExeResultforActivityGroup(BusinessFlow businessFlow, if (string.IsNullOrEmpty(exeRecordId) || exeRecordId.Equals("0")) { Reporter.ToLog(eLogLevel.DEBUG, $"Record id not found for {businessFlow.Name}, creating new record"); - result = CreateExecutionRecord(bfExportedID, activGroup, testPlan, loginData, testCaseId, testScriptId, ref exeRecordId); + result = CreateExecutionRecord(bfExportedID, activGroup, testPlan, loginData, testCaseId, testScriptId, ref exeRecordId,ExternalFields); } } @@ -648,14 +657,15 @@ private ExecutionResult GetExeResultforActivityGroup(BusinessFlow businessFlow, } } - private string CreateExecutionRecord(string bfExportedID, ActivitiesGroup activGroup, RQMTestPlan testPlan, LoginDTO loginData, string txExportID, string tsExportID, ref string erExportID) + private string CreateExecutionRecord(string bfExportedID, ActivitiesGroup activGroup, RQMTestPlan testPlan, LoginDTO loginData, string txExportID, string tsExportID, ref string erExportID, List ExternalFields = null) { string result = string.Empty; ACL_Data_Contract.Activity currentActivity = GetTestCaseFromActivityGroup(activGroup); try { + // if executionRecord not updated and not exists - so create one in RQM and update BussinesFlow object (this may be not saved due not existed "autosave" functionality) - var resultInfo = RQMConnect.Instance.RQMRep.CreateExecutionRecordPerActivity(loginData, RQMCore.ALMProjectGuid, ALMCore.DefaultAlmConfig.ALMProjectName, RQMCore.ALMProjectGroupName, currentActivity, bfExportedID, testPlan.Name); + var resultInfo = RQMConnect.Instance.RQMRep.CreateExecutionRecordPerActivity(loginData, RQMCore.ALMProjectGuid, ALMCore.DefaultAlmConfig.ALMProjectName, RQMCore.ALMProjectGroupName, currentActivity, bfExportedID, testPlan.Name, ExternalFields); if (resultInfo != null && !string.IsNullOrEmpty(resultInfo.ErrorDesc)) { Reporter.ToLog(eLogLevel.ERROR, $"Method - {MethodBase.GetCurrentMethod().Name}, Error - Test Case not found {resultInfo.ErrorCode}, {resultInfo.ErrorDesc}"); @@ -681,7 +691,6 @@ private string CreateExecutionRecord(string bfExportedID, ActivitiesGroup activG } return result; } - public bool ExportBfActivitiesGroupsToALM(BusinessFlow businessFlow, ObservableList grdActivitiesGroups, ref string result) { LoginDTO loginData = new LoginDTO() { User = ALMCore.DefaultAlmConfig.ALMUserName, Password = ALMCore.DefaultAlmConfig.ALMPassword, Server = ALMCore.DefaultAlmConfig.ALMServerURL }; @@ -777,7 +786,7 @@ public bool ExportBusinessFlowToRQM(BusinessFlow businessFlow, ObservableList ExternalFields = ConvertExternalFieldsToACLDataContractfields(mExternalItemsFields); RQMConnect.Instance.RQMRep.GetConection(); - resultInfo = RQMConnect.Instance.RQMRep.ExportTestPlan(loginData, testPlanList, ALMCore.DefaultAlmConfig.ALMServerURL, RQMCore.ALMProjectGuid, ALMCore.DefaultAlmConfig.ALMProjectName, RQMCore.ALMProjectGroupName, null); + resultInfo = RQMConnect.Instance.RQMRep.ExportTestPlan(loginData, testPlanList, ALMCore.DefaultAlmConfig.ALMServerURL, RQMCore.ALMProjectGuid, ALMCore.DefaultAlmConfig.ALMProjectName, RQMCore.ALMProjectGroupName, null,null, ExternalFields); } catch (Exception ex) { @@ -905,6 +914,31 @@ public bool ExportBusinessFlowToRQM(BusinessFlow businessFlow, ObservableList ConvertExternalFieldsToACLDataContractfields(ObservableList fields) + { + List fieldsToReturn = []; + + //Going through the fields to leave only Test Set fields + for (int indx = 0; indx < fields.Count; indx++) + { + ACL_Data_Contract.ExternalItemFieldBase field = new ACL_Data_Contract.ExternalItemFieldBase(); + field.ItemType = fields[indx].ItemType; + field.Name = fields[indx].Name; + field.SelectedValue = fields[indx].SelectedValue; + field.ID = fields[indx].ID; + field.Type = fields[indx].Type; + field.TypeIdentifier = fields[indx].TypeIdentifier; + field.IsMultiple = fields[indx].IsMultiple; + + if (!fieldsToReturn.Any(f => f.ID == field.ID)) + { + // Add it if it doesn't already exist + fieldsToReturn.Add(field); + } + } + return fieldsToReturn; + } + private ActivityPlan GetTestPlanFromBusinessFlow(BusinessFlow businessFlow) { ActivityPlan testPlan = new ActivityPlan(); @@ -1105,7 +1139,10 @@ private Dictionary GetCustomProperties(string ItemType) { if (itemField.Mandatory == true || itemField.ToUpdate == true) { - propertiesList.Add(itemField.Name, itemField.SelectedValue); + if (!propertiesList.ContainsKey(itemField.Name)) + { + propertiesList.Add(itemField.Name, itemField.SelectedValue); + } } } } diff --git a/Ginger/GingerCoreNET/ALMLib/RQM/ImportFromRQM.cs b/Ginger/GingerCoreNET/ALMLib/RQM/ImportFromRQM.cs index b4e249086b..b446f6978d 100644 --- a/Ginger/GingerCoreNET/ALMLib/RQM/ImportFromRQM.cs +++ b/Ginger/GingerCoreNET/ALMLib/RQM/ImportFromRQM.cs @@ -946,7 +946,8 @@ private static void SaveItemFields(ObservableList refresh Mandatory = field.Mandatory, PossibleValues = field.PossibleValues, Selected = field.SelectedValue, - ToUpdate = field.ToUpdate + ToUpdate = field.ToUpdate, + IsCustomField = field.IsCustomField, }; externalItemsListForJson.Add(JEIF); @@ -959,8 +960,21 @@ public static ObservableList GetOnlineItemFields(Backgrou { ObservableList fields = []; + fields = GetOnlineFields(bw); + SaveItemFields(fields); + return fields; + } + + public static ObservableList GetOnlineFields(BackgroundWorker bw) + { + ObservableList fields = []; + GetItemFieldsAll(bw, fields); + return fields; + } + private static void GetItemFieldsAll(BackgroundWorker bw, ObservableList fields) + { try { //TODO : receive as parameters: @@ -1100,7 +1114,7 @@ public static ObservableList GetOnlineItemFields(Backgrou itemfield.ToUpdate = false; itemfield.Mandatory = false; } - + itemfield.ProjectGuid = ALMCore.DefaultAlmConfig.ALMProjectGUID; catTypeRsult.Add(itemfield); PopulateLogOnFieldMappingwinodw(bw, $"Populating field :{categoryTypeName} \r\nNumber of fields populated :{catTypeRsult.Count}"); @@ -1174,6 +1188,7 @@ public static ObservableList GetOnlineItemFields(Backgrou itemfield.ToUpdate = false; itemfield.Mandatory = false; } + itemfield.ProjectGuid = ALMCore.DefaultAlmConfig.ALMProjectGUID; catTypeRsult.Add(itemfield); PopulateLogOnFieldMappingwinodw(bw, $"Populating field :{categoryTypeName} \r\nNumber of fields populated :{catTypeRsult.Count}"); } @@ -1227,10 +1242,373 @@ public static ObservableList GetOnlineItemFields(Backgrou #endregion } + + + //step 1. Get Custom attribute list by API + //step 2. Get all the custom attribute link as per the response + //setp 3. Get all Custom Attribute details by API + //step 4. Get All custom Attribute Possible values + ObservableList Customfields; + Customfields = GetCustomAttributes(bw, rqmSserverUrl, loginData, ref baseUri_, ref selfLink_, ref maxPageNumber_); + foreach (var CustomfieldItem in Customfields) + { + fields.Add(CustomfieldItem); + } } catch (Exception e) { Reporter.ToLog(eLogLevel.ERROR, $"Method - {MethodBase.GetCurrentMethod().Name}, Error - {e.Message}", e); } + } - SaveItemFields(fields); + private static ObservableList GetCustomAttributes(BackgroundWorker bw, string rqmSserverUrl, LoginDTO loginData, ref string baseUri_, ref string selfLink_, ref int maxPageNumber_) + { + ObservableList fields = new ObservableList(); + try + { + Reporter.ToLog(eLogLevel.DEBUG, $"starting Custom attribute fields retrieve process..."); + PopulateLogOnFieldMappingwinodw(bw, "starting Custom attribute fields retrieve process..."); + RqmResponseData CustomAttribute = RQM.RQMConnect.Instance.RQMRep.GetRqmResponse(loginData, new Uri(rqmSserverUrl + RQMCore.ALMProjectGroupName + "/service/com.ibm.rqm.integration.service.IIntegrationService/resources/" + ALMCore.DefaultAlmConfig.ALMProjectGUID + "/customAttribute")); + XmlDocument CustomAttributeList = new XmlDocument(); + if (!string.IsNullOrEmpty(CustomAttribute.responseText)) + { + + CustomAttributeList.LoadXml(CustomAttribute.responseText); + } + //TODO: Get 'next' and 'last links + XmlNodeList CustomAttributelinkList_ = CustomAttributeList.GetElementsByTagName("link"); + if (CustomAttributelinkList_.Count > 0) + { + XmlNode selfPage = CustomAttributelinkList_.Item(1); + XmlNode lastPage_ = CustomAttributelinkList_.Item(3); + + if (selfPage.Attributes["rel"].Value.ToString() == "self") //verify self link is present + { + selfLink_ = selfPage.Attributes["href"].Value.ToString(); + baseUri_ = selfLink_; + } + + if (lastPage_.Attributes["rel"].Value.ToString() == "last") //verify there is more than one page + { + if (selfPage.Attributes["rel"].Value.ToString() == "self") //verify self link is present + { + selfLink_ = selfPage.Attributes["href"].Value.ToString(); + baseUri_ = selfLink_[..^1]; + } + + string tempString_ = lastPage_.Attributes["href"].Value.ToString(); + maxPageNumber_ = System.Convert.ToInt32(tempString_[(tempString_.LastIndexOf('=') + 1)..]); + } + string newUri_ = string.Empty; + List CustomAttributeUriPages = []; + ConcurrentBag CustomAttributeRsult = []; + + for (int k = 0; k <= maxPageNumber_; k++) + { + if (maxPageNumber_ > 0) + { + newUri_ = baseUri_ + k.ToString(); + CustomAttributeUriPages.Add(newUri_); + } + else + { + newUri_ = baseUri_; + CustomAttributeUriPages.Add(newUri_); + } + } + + //Parallel computing solution CustomAttribute + List entryList = []; + if (CustomAttributeUriPages.Count > 1) + { + Parallel.ForEach(CustomAttributeUriPages.AsParallel(), new ParallelOptions { MaxDegreeOfParallelism = 5 }, CustomAttributeUri => + { + newUri_ = CustomAttributeUri; + CustomAttribute = RQM.RQMConnect.Instance.RQMRep.GetRqmResponse(loginData, new Uri(newUri_)); + if (!string.IsNullOrEmpty(CustomAttribute.responseText)) + { + CustomAttributeList.LoadXml(CustomAttribute.responseText); + } + //TODO: Get all ID links under entry: + XmlNodeList CustomAttributeEntry_ = CustomAttributeList.GetElementsByTagName("entry"); + + foreach (XmlNode entryNode in CustomAttributeEntry_) + { + entryList.Add(entryNode); + } + ParallelLoopResult innerResult = Parallel.ForEach(entryList.AsParallel(), new ParallelOptions { MaxDegreeOfParallelism = 5 }, singleEntry => + { + + XmlNodeList innerNodes = singleEntry.ChildNodes; + XmlNode linkNode = innerNodes.Item(4); + ExternalItemFieldBase itemfield = new ExternalItemFieldBase(); + + string getIDlink = string.Empty; + getIDlink = linkNode.Attributes["href"].Value.ToString(); // retrived CategoryType link + + + RqmResponseData CustomAttributeDetail = RQM.RQMConnect.Instance.RQMRep.GetRqmResponse(loginData, new Uri(getIDlink)); + + XmlDocument CustomAttributeListing = new(); + if (!string.IsNullOrEmpty(CustomAttributeDetail.responseText)) + { + CustomAttributeListing.LoadXml(CustomAttributeDetail.responseText); + } + string CustomAttributeName = string.Empty; // -->itemfield.Name + string CustomAttributeItemType = string.Empty; //-->itemfield.ItemType + string CustomAttributeMandatory = string.Empty; // --> itemfield.Mandatory & initial value for : --> itemfield.ToUpdate + string CustomAttributeID = string.Empty; + + string typeIdentifier = CustomAttributeListing.GetElementsByTagName("ns4:identifier").Item(0).InnerText; + CustomAttributeID = typeIdentifier[(typeIdentifier.LastIndexOf(':') + 1)..]; + CustomAttributeName = CustomAttributeListing.GetElementsByTagName("ns4:title").Item(0).InnerText; + CustomAttributeItemType = CustomAttributeListing.GetElementsByTagName("ns2:scope").Item(0).InnerText; + string CustomAttributefieldType = CustomAttributeListing.GetElementsByTagName("ns2:type").Item(0).InnerText; + // Define the namespace manager for the XML document + XmlNamespaceManager nsManager = new XmlNamespaceManager(CustomAttributeListing.NameTable); + nsManager.AddNamespace("ns2", "http://jazz.net/xmlns/alm/qm/v0.1/"); + + // XPath query to find ns2:required + string xpath = "//ns2:required"; + + // Use SelectSingleNode to check if ns2:required element exists + XmlNode requiredNode = CustomAttributeListing.SelectSingleNode(xpath, nsManager); + + if (requiredNode != null) + { + CustomAttributeMandatory = requiredNode.InnerText; + } + else + { + CustomAttributeMandatory = "false"; + } + + + + itemfield.ItemType = CustomAttributeItemType; + itemfield.ID = CustomAttributeID; + itemfield.Name = CustomAttributeName; + itemfield.Type = CustomAttributefieldType; + itemfield.TypeIdentifier = typeIdentifier; + if (CustomAttributeMandatory.Equals("true", StringComparison.CurrentCultureIgnoreCase)) + { + itemfield.ToUpdate = true; + itemfield.Mandatory = true; + if (itemfield.Type.Equals("INTEGER", StringComparison.CurrentCultureIgnoreCase)) + { + itemfield.SelectedValue = "1"; + } + else if (itemfield.Type.Equals("MEDIUMSTRING", StringComparison.CurrentCultureIgnoreCase) || itemfield.Type.Equals("SMALLSTRING", StringComparison.CurrentCultureIgnoreCase)) + { + itemfield.SelectedValue = "dummy"; + } + else if (itemfield.Type.Equals("TIMESTAMP", StringComparison.CurrentCultureIgnoreCase)) + { + itemfield.SelectedValue = DateTime.Now.ToString("yyyy-MM-dd"); + } + Reporter.ToLog(eLogLevel.INFO, $" CustomAttributeMandatory {CustomAttributeMandatory} itemfield.Name {itemfield.Name} itemfield.Type {itemfield.Type} itemfield..SelectedValue {itemfield.SelectedValue}"); + } + else + { + itemfield.ToUpdate = false; + itemfield.Mandatory = false; + } + + if (itemfield.SelectedValue == null) + { + itemfield.SelectedValue = "Unassigned"; + } + + if (CustomAttributeMandatory == "true") + { + itemfield.ToUpdate = true; + itemfield.Mandatory = true; + } + else + { + itemfield.ToUpdate = false; + itemfield.Mandatory = false; + } + itemfield.ProjectGuid = ALMCore.DefaultAlmConfig.ALMProjectGUID; + CustomAttributeRsult.Add(itemfield); + PopulateLogOnFieldMappingwinodw(bw, $"Populating field :{CustomAttributeName} \r\nNumber of fields populated :{CustomAttributeRsult.Count}"); + + } + ); + } + ); + } + else + { + populatedValue = string.Empty; + newUri_ = baseUri_; + CustomAttribute = RQM.RQMConnect.Instance.RQMRep.GetRqmResponse(loginData, new Uri(newUri_)); + + if (!string.IsNullOrEmpty(CustomAttribute.responseText)) + { + CustomAttributeList.LoadXml(CustomAttribute.responseText); + } + + //TODO: Get all ID links under entry: + XmlNodeList CustomAttributeEntry_ = CustomAttributeList.GetElementsByTagName("entry"); + + foreach (XmlNode entryNode in CustomAttributeEntry_) + { + entryList.Add(entryNode); + } + ParallelLoopResult innerResult = Parallel.ForEach(entryList.AsParallel(), new ParallelOptions { MaxDegreeOfParallelism = 5 }, singleEntry => + { + XmlNodeList innerNodes = singleEntry.ChildNodes; + XmlNode linkNode = innerNodes.Item(4); + ExternalItemFieldBase itemfield = new ExternalItemFieldBase(); + + string getIDlink = string.Empty; + getIDlink = linkNode.Attributes["href"].Value.ToString(); // retrived CategoryType link + + RqmResponseData CustomAttributeDetail = RQM.RQMConnect.Instance.RQMRep.GetRqmResponse(loginData, new Uri(getIDlink)); + + XmlDocument CustomAttributeListing = new XmlDocument(); + + if (!string.IsNullOrEmpty(CustomAttributeDetail.responseText)) + { + CustomAttributeListing.LoadXml(CustomAttributeDetail.responseText); + } + + string CustomAttributeName = string.Empty; // -->itemfield.Name + string CustomAttributeItemType = string.Empty; //-->itemfield.ItemType + string CustomAttributeMandatory = string.Empty; // --> itemfield.Mandatory & initial value for : --> itemfield.ToUpdate + string CustomAttributeID = string.Empty; + + string typeIdentifier = CustomAttributeListing.GetElementsByTagName("ns4:identifier").Item(0).InnerText; + CustomAttributeID = typeIdentifier[(typeIdentifier.LastIndexOf(':') + 1)..]; + CustomAttributeName = CustomAttributeListing.GetElementsByTagName("ns4:title").Item(0).InnerText; + CustomAttributeItemType = CustomAttributeListing.GetElementsByTagName("ns2:scope").Item(0).InnerText; + string CustomAttributefieldType = CustomAttributeListing.GetElementsByTagName("ns2:type").Item(0).InnerText; + // Define the namespace manager for the XML document + XmlNamespaceManager nsManager = new XmlNamespaceManager(CustomAttributeListing.NameTable); + nsManager.AddNamespace("ns2", "http://jazz.net/xmlns/alm/qm/v0.1/"); + + // XPath query to find ns2:required + string xpath = "//ns2:required"; + + // Use SelectSingleNode to check if ns2:required element exists + XmlNode requiredNode = CustomAttributeListing.SelectSingleNode(xpath, nsManager); + + if (requiredNode != null) + { + CustomAttributeMandatory = requiredNode.InnerText; + } + else + { + CustomAttributeMandatory = "false"; + } + + + itemfield.ItemType = CustomAttributeItemType; + itemfield.ID = CustomAttributeID; + itemfield.TypeIdentifier = typeIdentifier; + itemfield.Name = CustomAttributeName; + itemfield.Type = CustomAttributefieldType; + if (CustomAttributeMandatory.Equals("true",StringComparison.CurrentCultureIgnoreCase)) + { + itemfield.ToUpdate = true; + itemfield.Mandatory = true; + if(itemfield.Type.Equals("INTEGER",StringComparison.CurrentCultureIgnoreCase)) + { + itemfield.SelectedValue = "1"; + } + else if(itemfield.Type.Equals("MEDIUMSTRING", StringComparison.CurrentCultureIgnoreCase) || itemfield.Type.Equals("SMALLSTRING", StringComparison.CurrentCultureIgnoreCase)) + { + itemfield.SelectedValue = "dummy"; + } + else if(itemfield.Type.Equals("TIMESTAMP", StringComparison.CurrentCultureIgnoreCase)) + { + itemfield.SelectedValue = DateTime.Now.ToString("yyyy-MM-dd"); + } + Reporter.ToLog(eLogLevel.INFO, $" CustomAttributeMandatory {CustomAttributeMandatory} itemfield.Name {itemfield.Name} itemfield.Type {itemfield.Type} itemfield..SelectedValue {itemfield.SelectedValue}"); + } + else + { + itemfield.ToUpdate = false; + itemfield.Mandatory = false; + } + if (itemfield.SelectedValue == null) + { + itemfield.SelectedValue = "Unassigned"; + } + + + itemfield.IsCustomField = true; + itemfield.ProjectGuid = ALMCore.DefaultAlmConfig.ALMProjectGUID; + CustomAttributeRsult.Add(itemfield); + PopulateLogOnFieldMappingwinodw(bw, $"Populating field :{CustomAttributeName} \r\nNumber of fields populated :{CustomAttributeRsult.Count}"); + } + ); + } + foreach (ExternalItemFieldBase field in CustomAttributeRsult) + { + fields.Add(field); + }//TODO: Add Values to CategoryTypes Parallel + PopulateLogOnFieldMappingwinodw(bw, $"Starting values retrieve process... "); + #region new Get Values by filed Custom Attributes + foreach (ExternalItemFieldBase field in fields) + { + if(field.IsMultiple) + { + string baseUrl = $"{rqmSserverUrl}{RQMCore.ALMProjectGroupName}/service/com.ibm.rqm.integration.service.IIntegrationService/resources/{ALMCore.DefaultAlmConfig.ALMProjectGUID}/customAttribute/?fields=feed/entry/content/customAttribute/"; + + // Construct URL + string fullUrl = $"{baseUrl}(customAttribute[@href='{field.TypeIdentifier}']|*))"; + Reporter.ToLog(eLogLevel.DEBUG, $"fullUrl : {fullUrl}"); + RqmResponseData CustomAttributefieldlist = RQM.RQMConnect.Instance.RQMRep.GetRqmResponse(loginData, + new Uri(fullUrl)); + + XDocument doc = XDocument.Parse(CustomAttributefieldlist.responseText); + XNamespace ns = "http://www.w3.org/2005/Atom"; + + // Query the XML to get all titles inside entry nodes + var titles = doc.Descendants(ns + "entry") + .Select(entry => entry.Element(ns + "title")?.Value) + .Where(title => title != null); + + PopulateLogOnFieldMappingwinodw(bw, $"Number of values populated :{titles.Count()}"); + if (bw != null) + { + bw.ReportProgress(CustomAttributeRsult.Count, populatedValue); + } + + if (titles != null && titles.Any()) + { + foreach (var title in titles) + { + field.PossibleValues.Add(title); + } + + // Set the first item as SelectedValue if PossibleValues is not empty + if (field.PossibleValues.Count > 0) + { + field.SelectedValue = field.PossibleValues[0]; + } + } + } + else + { + if(field.Type != null && (field.Type.Equals("MEDIUM_STRING",StringComparison.CurrentCultureIgnoreCase) || field.Type.Equals("SMALL_STRING", StringComparison.CurrentCultureIgnoreCase))) + { + field.SelectedValue = string.Empty; + } + else + { + field.SelectedValue = null; + } + + } + } + #endregion + } + + } + catch (Exception e) + { + Reporter.ToLog(eLogLevel.ERROR, $"Method - {MethodBase.GetCurrentMethod().Name}, Error - {e.Message}", e); + } return fields; } diff --git a/Ginger/GingerCoreNET/DLLS/ACL_Data_Contract.dll b/Ginger/GingerCoreNET/DLLS/ACL_Data_Contract.dll index a96453cda4..8811e2e4c1 100644 Binary files a/Ginger/GingerCoreNET/DLLS/ACL_Data_Contract.dll and b/Ginger/GingerCoreNET/DLLS/ACL_Data_Contract.dll differ diff --git a/Ginger/GingerCoreNET/DLLS/AzureDevOpsRepo.dll b/Ginger/GingerCoreNET/DLLS/AzureDevOpsRepo.dll index 93aaa0cdc7..bd4160996c 100644 Binary files a/Ginger/GingerCoreNET/DLLS/AzureDevOpsRepo.dll and b/Ginger/GingerCoreNET/DLLS/AzureDevOpsRepo.dll differ diff --git a/Ginger/GingerCoreNET/DLLS/RQMExportStd.dll b/Ginger/GingerCoreNET/DLLS/RQMExportStd.dll index ae70eeb6bc..b501038630 100644 Binary files a/Ginger/GingerCoreNET/DLLS/RQMExportStd.dll and b/Ginger/GingerCoreNET/DLLS/RQMExportStd.dll differ diff --git a/Ginger/GingerCoreNET/DLLS/RQM_RepositoryStd.dll b/Ginger/GingerCoreNET/DLLS/RQM_RepositoryStd.dll index bce9e1e122..171f90913d 100644 Binary files a/Ginger/GingerCoreNET/DLLS/RQM_RepositoryStd.dll and b/Ginger/GingerCoreNET/DLLS/RQM_RepositoryStd.dll differ diff --git a/Ginger/GingerCoreNET/DLLS/VisualRegressionTracker.dll b/Ginger/GingerCoreNET/DLLS/VisualRegressionTracker.dll new file mode 100644 index 0000000000..a1f26b0b13 Binary files /dev/null and b/Ginger/GingerCoreNET/DLLS/VisualRegressionTracker.dll differ diff --git a/Ginger/GingerCoreNET/Database/NoSqlBase/GingerHbase.cs b/Ginger/GingerCoreNET/Database/NoSqlBase/GingerHbase.cs index 6ba93582e8..09ed13f0a9 100644 --- a/Ginger/GingerCoreNET/Database/NoSqlBase/GingerHbase.cs +++ b/Ginger/GingerCoreNET/Database/NoSqlBase/GingerHbase.cs @@ -445,6 +445,22 @@ public override async void PerformDBAction() scanInfo = actionClient.CreateScannerAsync(table, scanner, requestOption).Result; int path1 = 1; + + //var tableDescriptor = await actionClient.GetTableSchemaAsync(table, null); + //Console.WriteLine($"Table: {tableDescriptor.Name}"); + + // Iterating over column families + //foreach (var columnFamily in tableDescriptor..ColumnFamilies) + //{ + // Console.WriteLine($"Column Family: {columnFamily.Name}"); + + // // Here you can add logic to infer or define data types. + // // HBase doesn't store data types inherently, you may need to + // // map them based on your application's logic or design. + // // For instance: + // // - You might have a convention where specific column families + // // relate to specific data types. + //} if (SQLCalculated.Contains('*')) { @@ -458,11 +474,27 @@ public override async void PerformDBAction() List cells = row.values; - foreach (Cell c in cells) + try { + foreach (Cell c in cells) + { + + try + { + Act.AddOrUpdateReturnParamActualWithPath(ExtractColumnName(c.column), DisplayInferredTypeAndValue(c.data), path1.ToString()); + } + catch (Exception) + { + + // throw; + } - Act.AddOrUpdateReturnParamActualWithPath(ExtractColumnName(c.column), Encoding.ASCII.GetString(c.data), path1.ToString()); + } + } + catch (Exception) + { + // throw; } path1++; } @@ -497,7 +529,7 @@ public override async void PerformDBAction() string colname = ExtractColumnName(c.column); if (list.Contains(colname)) { - Act.AddOrUpdateReturnParamActualWithPath(colname, Encoding.ASCII.GetString(c.data), path1.ToString()); + Act.AddOrUpdateReturnParamActualWithPath(colname, DisplayInferredTypeAndValue(c.data), path1.ToString()); } @@ -527,6 +559,94 @@ public override async void PerformDBAction() } + public enum DataType + { + Int, + Long, + Float, + Double, + String, + Unknown + } + + public static string DisplayInferredTypeAndValue(byte[] byteArray) + { + + + if (byteArray == null || byteArray.Length == 0) + { + return ""; + } + DataType inferredType = DataType.String; + if (byteArray != null && byteArray.Length > 0 && (byteArray[0] == 0)) + { + inferredType = InferDataType(byteArray); + } + if (inferredType != DataType.String) + { + Array.Reverse(byteArray); + } + object value = ConvertByteArrayToType(byteArray, inferredType); + + if (inferredType == DataType.Long && value != null && value.ToString()[0] == '-' && value.ToString().Length >= 20) + { + inferredType = DataType.Double; + value = ConvertByteArrayToType(byteArray, inferredType); + } + + if (value != null && value.ToString().Contains('�')) + { + inferredType = InferDataType(byteArray); + if (inferredType != DataType.String) + { + Array.Reverse(byteArray); + } + value = ConvertByteArrayToType(byteArray, inferredType); + } + //Console.WriteLine($"Inferred Type: {inferredType}, Value: {value}"); + return value?.ToString(); + } + + public static DataType InferDataType(byte[] byteArray) + { + switch (byteArray.Length) + { + case 4: + // Potentially int or float + if (System.BitConverter.ToInt32(byteArray, 0) != 0) // Example heuristic, adjust as necessary + return DataType.Int; // could be an int + if (System.BitConverter.ToSingle(byteArray, 0) != 0) + return DataType.Float; // could be a float + + return DataType.Unknown; + + case 8: + // Potentially long or double + if (System.BitConverter.ToInt64(byteArray, 0) != 0) // Example heuristic, adjust as necessary + return DataType.Long; // could be a long + if (System.BitConverter.ToDouble(byteArray, 0) != 0) + return DataType.Double; // could be a double + + return DataType.Unknown; + + default: + // Consider any string values or unknowns + return DataType.String; // treating as string for variable lengths + } + } + + public static object ConvertByteArrayToType(byte[] byteArray, DataType dataType) + { + return dataType switch + { + DataType.Int => System.BitConverter.ToInt32(byteArray, 0), + DataType.Long => System.BitConverter.ToInt64(byteArray, 0), + DataType.Float => System.BitConverter.ToSingle(byteArray, 0), + DataType.Double => System.BitConverter.ToDouble(byteArray, 0), + DataType.String => System.Text.Encoding.UTF8.GetString(byteArray), + _ => null,// or throw an exception based on your needs + }; + } public string Base64Encode(string text) { diff --git a/Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs b/Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs index 94926bf98f..8159a92631 100644 --- a/Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs +++ b/Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs @@ -808,6 +808,7 @@ public override void StartDriver() { SetProxy(EDOpts); } + if (SeleniumUserArgs != null) { foreach (string arg in SeleniumUserArgs) diff --git a/Ginger/GingerCoreNET/External/JsonExternalItemField.cs b/Ginger/GingerCoreNET/External/JsonExternalItemField.cs index 25c1a981a8..5a92901848 100644 --- a/Ginger/GingerCoreNET/External/JsonExternalItemField.cs +++ b/Ginger/GingerCoreNET/External/JsonExternalItemField.cs @@ -29,5 +29,6 @@ public class JsonExternalItemField public ObservableList PossibleValues { get; set; } public string Selected { get; set; } public bool ToUpdate { get; set; } + public bool IsCustomField { get; set; } } } diff --git a/Ginger/GingerCoreNET/GeneralLib/General.cs b/Ginger/GingerCoreNET/GeneralLib/General.cs index eab1f88f3b..be753da5b2 100644 --- a/Ginger/GingerCoreNET/GeneralLib/General.cs +++ b/Ginger/GingerCoreNET/GeneralLib/General.cs @@ -24,6 +24,7 @@ limitations under the License. using Ginger.Configurations; using GingerCore; using GingerCore.Actions; +using GingerCore.ALM.RQM; using GingerCore.DataSource; using GingerCore.Environments; using GingerCoreNET.SolutionRepositoryLib.RepositoryObjectsLib.PlatformsLib; @@ -703,6 +704,110 @@ public static bool IsConfigPackageExists(string PackagePath, GingerCoreNET.ALMLi } return false; } + + /// + /// Retrieves external fields from either online RQM or workspace solution based on configuration. + /// + /// List of external fields with their values. + public static ObservableList GetExternalFields() + { + ObservableList originalExternalFields = new ObservableList(); + + var defaultALMConfig = WorkSpace.Instance.Solution.ALMConfigs.FirstOrDefault(x => x.DefaultAlm); + var firstExternalItemField = WorkSpace.Instance.Solution.ExternalItemsFields.FirstOrDefault(); + + if (defaultALMConfig != null && firstExternalItemField != null && + defaultALMConfig.ALMProjectGUID != firstExternalItemField.ProjectGuid) + { + var externalOnlineItemsFields = ImportFromRQM.GetOnlineFields(null); + if (externalOnlineItemsFields == null) + { + Reporter.ToLog(eLogLevel.ERROR, "Failed to retrieve online fields from RQM"); + return originalExternalFields; + } + foreach (var externalItemField in externalOnlineItemsFields) + { + ExternalItemFieldBase item = MapExternalField(externalItemField); + if(item != null) + { + originalExternalFields.Add(item); + } + } + } + else + { + originalExternalFields = WorkSpace.Instance.Solution.ExternalItemsFields; + } + + return originalExternalFields; + } + + private static ExternalItemFieldBase MapExternalField(ExternalItemFieldBase externalItemField) + { + try + { + var existingField = WorkSpace.Instance.Solution.ExternalItemsFields + .FirstOrDefault(x => x.Name.Equals(externalItemField.Name, StringComparison.CurrentCultureIgnoreCase) && x.ProjectGuid == externalItemField.ProjectGuid); + + string value = ""; + + if (existingField == null) + { + if (externalItemField.Mandatory) + { + if (!string.IsNullOrEmpty(externalItemField.SelectedValue)) + { + value = externalItemField.SelectedValue; + } + else + { + value = GetDefaultValue(externalItemField); + } + } + } + else + { + if (externalItemField.Mandatory) + { + if (!string.IsNullOrEmpty(existingField.SelectedValue)) + { + value = existingField.SelectedValue; + } + else + { + value = GetDefaultValue(externalItemField); + } + } + } + return new ExternalItemFieldBase + { + Name = externalItemField.Name, + ID = externalItemField.ID, + ItemType = externalItemField.ItemType, + Type = externalItemField.Type, + Guid = externalItemField.Guid, + IsCustomField = externalItemField.IsCustomField, + SelectedValue = value + }; + } + catch (Exception ex) + { + Reporter.ToLog(eLogLevel.ERROR,"Failed to Map External Fields",ex.InnerException); + return null; + } + } + + private static string GetDefaultValue(ExternalItemFieldBase externalItemField) + { + // Return default values based on the field type. + return (externalItemField.Type.ToUpperInvariant()) switch + { + "INTEGER" => "1", + "MEDIUMSTRING" => "Dummy", + "SMALLSTRING" => "Dummy", + _ => externalItemField.SelectedValue + }; + } } } diff --git a/Ginger/GingerCoreNET/GingerCoreNET.csproj b/Ginger/GingerCoreNET/GingerCoreNET.csproj index 34e67301ce..7e4120794b 100644 --- a/Ginger/GingerCoreNET/GingerCoreNET.csproj +++ b/Ginger/GingerCoreNET/GingerCoreNET.csproj @@ -337,7 +337,6 @@ - @@ -460,6 +459,9 @@ DLLS\SubAppUtils.dll + + DLLS\VisualRegressionTracker.dll + DLLS\ZephyrEntStdSDK.dll diff --git a/Ginger/GingerCoreNET/Logger/WebReportGenerator.cs b/Ginger/GingerCoreNET/Logger/WebReportGenerator.cs index 5ae01ab94e..454002b573 100644 --- a/Ginger/GingerCoreNET/Logger/WebReportGenerator.cs +++ b/Ginger/GingerCoreNET/Logger/WebReportGenerator.cs @@ -77,6 +77,11 @@ public LiteDbRunSet RunNewHtmlReport(string reportResultsFolderPath = "", string IoHandler.Instance.TryFolderDelete(rootFolder); } IoHandler.Instance.CopyFolderRec(clientAppFolderPath, ReportrootPath, true); + + if(!Directory.Exists(Path.Combine(ReportrootPath, "assets", "screenshots"))) + { + Directory.CreateDirectory(Path.Combine(ReportrootPath, "assets", "screenshots")); + } } } catch (Exception ex) diff --git a/Ginger/GingerCoreNET/Run/GingerExecutionEngine.cs b/Ginger/GingerCoreNET/Run/GingerExecutionEngine.cs index 5cc2a8c61c..49675bb551 100644 --- a/Ginger/GingerCoreNET/Run/GingerExecutionEngine.cs +++ b/Ginger/GingerCoreNET/Run/GingerExecutionEngine.cs @@ -109,6 +109,10 @@ public Context Context Activity mExecutedActivityWhenStopped = null; Act mExecutedActionWhenStopped = null; + public BusinessFlow ExecutedBusinessFlowWhenStopped => mExecutedBusinessFlowWhenStopped; + public Activity ExecutedActivityWhenStopped => mExecutedActivityWhenStopped; + public Act ExecutedActionWhenStopped => mExecutedActionWhenStopped; + Activity mLastExecutedActivity; private eRunSource? mRunSource = null; @@ -2067,6 +2071,8 @@ private void ExecuteCleanUpActivities() { foreach (CleanUpActivity cleanUpActivity in cleanUpActivities) { + CurrentBusinessFlow.CurrentActivity = cleanUpActivity; + RunActivity(cleanUpActivity); } } @@ -2461,69 +2467,69 @@ private void RunActionWithTimeOutControl(Act act, GingerRunner.eActionExecutorTy switch (ActExecutorType) { case GingerRunner.eActionExecutorType.RunOnDriver: + { + if (currentAgent == null) { - if (currentAgent == null) + if (string.IsNullOrEmpty(act.Error)) { - if (string.IsNullOrEmpty(act.Error)) - { - act.Error = "No Agent was found for the " + GingerDicser.GetTermResValue(eTermResKey.Activity) + " Application."; - } - - act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed; + act.Error = "No Agent was found for the " + GingerDicser.GetTermResValue(eTermResKey.Activity) + " Application."; } - else + + act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed; + } + else + { + if (((Agent)CurrentBusinessFlow.CurrentActivity.CurrentAgent).AgentType == Agent.eAgentType.Driver) { - if (((Agent)CurrentBusinessFlow.CurrentActivity.CurrentAgent).AgentType == Agent.eAgentType.Driver) + if (((AgentOperations)currentAgent.AgentOperations).Status != Agent.eStatus.Running) { - if (((AgentOperations)currentAgent.AgentOperations).Status != Agent.eStatus.Running) + if (string.IsNullOrEmpty(act.Error)) { - if (string.IsNullOrEmpty(act.Error)) + if (((AgentOperations)currentAgent.AgentOperations).Driver != null && !string.IsNullOrEmpty(((AgentOperations)currentAgent.AgentOperations).Driver.ErrorMessageFromDriver)) { - if (((AgentOperations)currentAgent.AgentOperations).Driver != null && !string.IsNullOrEmpty(((AgentOperations)currentAgent.AgentOperations).Driver.ErrorMessageFromDriver)) - { - act.Error = ((AgentOperations)currentAgent.AgentOperations).Driver.ErrorMessageFromDriver; - } - else - { - act.Error = $"Agent failed to start for the {GingerDicser.GetTermResValue(eTermResKey.Activity)} Application. Current Agent Status {((AgentOperations)currentAgent.AgentOperations).Status}"; - } + act.Error = ((AgentOperations)currentAgent.AgentOperations).Driver.ErrorMessageFromDriver; } - - act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed; - } - else - { - using (IFeatureTracker rodFeatureTracker = Reporter.StartFeatureTracking(FeatureId.ActionExecution)) + else { - rodFeatureTracker.Metadata.Add("Type", act.GetType().Name); - rodFeatureTracker.Metadata.Add("ExecutorType", GingerRunner.eActionExecutorType.RunOnDriver.ToString()); - rodFeatureTracker.Metadata.Add("IsSharedRepositoryInstance", act.IsSharedRepositoryInstance.ToString()); - ((AgentOperations)((Agent)CurrentBusinessFlow.CurrentActivity.CurrentAgent).AgentOperations).RunAction(act); + act.Error = $"Agent failed to start for the {GingerDicser.GetTermResValue(eTermResKey.Activity)} Application. Current Agent Status {((AgentOperations)currentAgent.AgentOperations).Status}"; } } + + act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed; } else { - - if (act is IActPluginExecution PluginAction) + using (IFeatureTracker rodFeatureTracker = Reporter.StartFeatureTracking(FeatureId.ActionExecution)) { - - Agent PluginAgent = (Agent)CurrentBusinessFlow.CurrentActivity.CurrentAgent; - ExecuteOnPlugin.ExecutePlugInActionOnAgent(PluginAgent, PluginAction); + rodFeatureTracker.Metadata.Add("Type", act.GetType().Name); + rodFeatureTracker.Metadata.Add("ExecutorType", GingerRunner.eActionExecutorType.RunOnDriver.ToString()); + rodFeatureTracker.Metadata.Add("IsSharedRepositoryInstance", act.IsSharedRepositoryInstance.ToString()); + ((AgentOperations)((Agent)CurrentBusinessFlow.CurrentActivity.CurrentAgent).AgentOperations).RunAction(act); } + } + } + else + { - else - { - act.Error = "Current Plugin Agent does not support execution for " + act.ActionDescription; - act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed; + if (act is IActPluginExecution PluginAction) + { - } + Agent PluginAgent = (Agent)CurrentBusinessFlow.CurrentActivity.CurrentAgent; + ExecuteOnPlugin.ExecutePlugInActionOnAgent(PluginAgent, PluginAction); } + else + { + act.Error = "Current Plugin Agent does not support execution for " + act.ActionDescription; + act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed; + + } } + } + } - break; + break; case GingerRunner.eActionExecutorType.RunWithoutDriver: using (IFeatureTracker rwdFeatureTracker = Reporter.StartFeatureTracking(FeatureId.ActionExecution)) @@ -4411,78 +4417,92 @@ public void RunBusinessFlow(BusinessFlow businessFlow, bool standaloneExecution while (ExecutingActivity != null) { - ExecutingActivity.Status = eRunStatus.Running; - GiveUserFeedback(); - SetMappedValuesToActivityVariables(ExecutingActivity, previouslyExecutedActivities.ToArray()); - if (doContinueRun && FirstExecutedActivity.Equals(ExecutingActivity)) + if (ExecutingActivity is CleanUpActivity) + { + if (!CurrentBusinessFlow.Activities.IsLastItem()) { - // We run the first Activity in Continue mode, if it came from RunFlow, then it is set to first action - RunActivity(ExecutingActivity, true, resetErrorHandlerExecutedFlag: doResetErrorHandlerExecutedFlag); + GotoNextActivity(); + ExecutingActivity = (Activity)CurrentBusinessFlow.Activities.CurrentItem; + continue; } else { - RunActivity(ExecutingActivity, resetErrorHandlerExecutedFlag: doResetErrorHandlerExecutedFlag); - } - previouslyExecutedActivities.Add(ExecutingActivity); - //TODO: Why this is here? do we need to rehook - CurrentBusinessFlow.PropertyChanged -= CurrentBusinessFlow_PropertyChanged; - if (ExecutingActivity.Status == Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed) - { - CurrentBusinessFlow.LastFailedActivity = ExecutingActivity; + ExecutingActivity = null; + break; } - if (ExecutingActivity.Mandatory && ExecutingActivity.Status == Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed) + } + ExecutingActivity.Status = eRunStatus.Running; + GiveUserFeedback(); + SetMappedValuesToActivityVariables(ExecutingActivity, previouslyExecutedActivities.ToArray()); + if (doContinueRun && FirstExecutedActivity.Equals(ExecutingActivity)) + { + // We run the first Activity in Continue mode, if it came from RunFlow, then it is set to first action + RunActivity(ExecutingActivity, true, resetErrorHandlerExecutedFlag: doResetErrorHandlerExecutedFlag); + } + else + { + RunActivity(ExecutingActivity, resetErrorHandlerExecutedFlag: doResetErrorHandlerExecutedFlag); + } + previouslyExecutedActivities.Add(ExecutingActivity); + //TODO: Why this is here? do we need to rehook + CurrentBusinessFlow.PropertyChanged -= CurrentBusinessFlow_PropertyChanged; + if (ExecutingActivity.Status == Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed) + { + CurrentBusinessFlow.LastFailedActivity = ExecutingActivity; + } + if (ExecutingActivity.Mandatory && ExecutingActivity.Status == Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed) + { + //CurrentBusinessFlow.Elapsed = st.ElapsedMilliseconds; + CurrentBusinessFlow.RunStatus = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed; + if (!CurrentBusinessFlow.Activities.IsLastItem()) { - //CurrentBusinessFlow.Elapsed = st.ElapsedMilliseconds; - CurrentBusinessFlow.RunStatus = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed; - if (!(CurrentBusinessFlow.Activities.IsLastItem())) - { - GotoNextActivity(); - SetNextActivitiesBlockedStatus(); - } - return; + GotoNextActivity(); + SetNextActivitiesBlockedStatus(); } + return; + } + + if (mStopRun || mStopBusinessFlow) + { + //CurrentBusinessFlow.Elapsed = st.ElapsedMilliseconds; + SetBusinessFlowActivitiesAndActionsSkipStatus(); + SetActivityGroupsExecutionStatus(); + CurrentBusinessFlow.RunStatus = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Stopped; + return; + } - if (mStopRun || mStopBusinessFlow) + if (mErrorPostExecutionActionFlowBreaker) + { + if (handlerPostExecutionAction == eErrorHandlerPostExecutionAction.ContinueFromNextActivity) { - //CurrentBusinessFlow.Elapsed = st.ElapsedMilliseconds; - SetBusinessFlowActivitiesAndActionsSkipStatus(); - SetActivityGroupsExecutionStatus(); - CurrentBusinessFlow.RunStatus = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Stopped; - return; + mErrorPostExecutionActionFlowBreaker = false; } - - if (mErrorPostExecutionActionFlowBreaker) + else { - if (handlerPostExecutionAction == eErrorHandlerPostExecutionAction.ContinueFromNextActivity) - { - mErrorPostExecutionActionFlowBreaker = false; - } - else - { - break; - } + break; } + } - if ((Activity)CurrentBusinessFlow.Activities.CurrentItem != ExecutingActivity) + if ((Activity)CurrentBusinessFlow.Activities.CurrentItem != ExecutingActivity) + { + //If not equal means flow control update current item to target activity, no need to do next activity + ExecutingActivity = (Activity)CurrentBusinessFlow.Activities.CurrentItem; + } + else + { + if (!CurrentBusinessFlow.Activities.IsLastItem()) { - //If not equal means flow control update current item to target activity, no need to do next activity + Thread.Sleep(1); + GotoNextActivity(); ExecutingActivity = (Activity)CurrentBusinessFlow.Activities.CurrentItem; } else { - if (!CurrentBusinessFlow.Activities.IsLastItem()) - { - Thread.Sleep(1); - GotoNextActivity(); - ExecutingActivity = (Activity)CurrentBusinessFlow.Activities.CurrentItem; - } - else - { - ExecutingActivity = null; - } + ExecutingActivity = null; } + } + - } } catch (Exception ex)