private static ServiceCallStatus SendFinalResponse( [CanBeNull] QualityVerification verification, [CanBeNull] string qaServiceCancellationMessage, ConcurrentBag <IssueMsg> issues, List <GdbObjRefMsg> deletableAllowedErrors, [CanBeNull] IEnvelope verifiedPerimeter, Action <VerificationResponse> writeAction) { var response = new VerificationResponse(); while (issues.TryTake(out IssueMsg issue)) { response.Issues.Add(issue); } response.ObsoleteExceptions.AddRange(deletableAllowedErrors); ServiceCallStatus finalStatus = GetFinalCallStatus(verification, qaServiceCancellationMessage); response.ServiceCallStatus = (int)finalStatus; if (!string.IsNullOrEmpty(qaServiceCancellationMessage)) { response.Progress = new VerificationProgressMsg { Message = qaServiceCancellationMessage }; } PackVerification(verification, response); if (verifiedPerimeter != null) { response.VerifiedPerimeter = ProtobufGeometryUtils.ToShapeMsg(verifiedPerimeter); } _msg.DebugFormat( "Sending final message with {0} errors back to client...", issues.Count); try { writeAction(response); } catch (InvalidOperationException ex) { // For example: System.InvalidOperationException: Only one write can be pending at a time _msg.Warn( "Error sending progress to the client. Retrying the last response in 1s...", ex); // Re-try (only for final message) Task.Delay(1000); writeAction(response); } return(finalStatus); }
public static void ShowResults( [CanBeNull] IWin32Window owner, [NotNull] QualityVerification verification, string contextType, string contextName, [NotNull] IDomainTransactionManager domainTransactionManager) { Assert.ArgumentNotNull(verification, nameof(verification)); Assert.ArgumentNotNull(domainTransactionManager, nameof(domainTransactionManager)); using (var form = new QAVerificationForm(domainTransactionManager)) { domainTransactionManager.UseTransaction( delegate { Initialize(verification, domainTransactionManager); // ReSharper disable once AccessToDisposedClosure form.SetVerification(verification, contextType, contextName); }); form.StartPosition = FormStartPosition.CenterScreen; //if (owner != null) //{ // owner = owner.TopLevelControl; //} UIEnvironment.ShowDialog(form, owner); } }
private static double GetLoadTime([NotNull] TreeNode node, [NotNull] QualityVerification verification, [NotNull] ICollection <Dataset> included) { double loadTime = 0; foreach (TreeNode child in node.Nodes) { var dataset = node.Tag as Dataset; if (dataset != null && !included.Contains(dataset)) { QualityVerificationDataset verificationDataset = verification.GetVerificationDataset(dataset); if (verificationDataset != null) { loadTime += verificationDataset.LoadTime; } included.Add(dataset); } loadTime += GetLoadTime(child, verification, included); } return(loadTime); }
public void RenderHierarchicView( [NotNull] QualityVerification qualityVerifiation, [NotNull] Predicate <QualityConditionVerification> includeConditionVerification) { bool oldRendering = _rendering; _rendering = true; try { _verification = qualityVerifiation; _treeViewConditions.ShowHierarchic(GetSpecificationDatasets( qualityVerifiation, includeConditionVerification), new DatasetCategoryItemComparer(), new DatasetComparer(), new SpecificationDatasetComparer()); _treeViewConditions.SetDatasetIcons(_treeViewConditions.Nodes); _panelExecuteInfo.Invalidate(); } finally { _rendering = oldRendering; } }
protected override IList <ITest> GetTests(QualitySpecification specification, out QualityVerification qualityVerification) { IList <ITest> result = null; QualityVerification verification = null; // TODO: Copy from QualityVerificationService // Consider moving to base or provide the (properly initialized) tests together with the // verification in VerifyQuality() or move the condition/test dictionaries and collections // to a separate factory/provider class that can be called previously inside the appropriate // transaction _domainTransactions.UseTransaction( delegate { ICollection <Dataset> datasets = QualitySpecificationUtils.GetQualityConditionDatasets(specification); _domainTransactions.Reattach(datasets); _backgroundVerificationInputs.InitializeSchema(datasets); result = GetTestsCore(specification, out verification); }); qualityVerification = verification; return(result); }
public QualityVerification Verify( [NotNull] IBackgroundVerificationInputs backgroundVerificationInputs, [CanBeNull] ITrackCancel trackCancel) { QualitySpecification qualitySpecification = null; _backgroundVerificationInputs = backgroundVerificationInputs; _domainTransactions.UseTransaction( delegate { backgroundVerificationInputs.LoadInputsTx( _domainTransactions, trackCancel, OnProgress); qualitySpecification = PrepareQualitySpecificationTx(backgroundVerificationInputs); }); IVerificationContext verificationContext = Assert.NotNull(backgroundVerificationInputs.VerificationContext); VerificationServiceParameters parameters = Assert.NotNull(backgroundVerificationInputs.VerificationParameters); QualityVerification verification = Verify( verificationContext, qualitySpecification, parameters, backgroundVerificationInputs.VerifiedObjects); if (parameters.SaveVerificationStatistics && !verification.Cancelled) { backgroundVerificationInputs.SaveVerification(verification, _domainTransactions); } return(verification); }
private static ServiceCallStatus GetFinalCallStatus( [CanBeNull] QualityVerification verification, [CanBeNull] string qaServiceCancellationMessage) { ServiceCallStatus finalStatus; if (verification == null) { return(ServiceCallStatus.Failed); } if (verification.Cancelled) { if (string.IsNullOrEmpty(qaServiceCancellationMessage)) { finalStatus = ServiceCallStatus.Cancelled; } else { finalStatus = ServiceCallStatus.Failed; } } else { finalStatus = ServiceCallStatus.Finished; } return(finalStatus); }
public QualityVerification GetQualityVerification() { if (_qualityVerification == null) { _domainTransactions.UseTransaction( () => { if (VerificationMsg.SavedVerificationId >= 0) { _qualityVerification = _qualityVerificationRepository.Get( VerificationMsg.SavedVerificationId); Assert.NotNull(_qualityVerification, "Quality verification not found."); _domainTransactions.Initialize( _qualityVerification.ConditionVerifications); _domainTransactions.Initialize( _qualityVerification.VerificationDatasets); } else { _qualityVerification = GetQualityVerificationTx(VerificationMsg); } }); } return(_qualityVerification); }
public void Bind( [NotNull] QualityVerification qualityVerification, [NotNull] Predicate <QualityConditionVerification> includeConditionVerification) { double maximumTime; SortableBindingList <VerifiedDatasetItem> bindingList = GetVerifiedDatasetItems(qualityVerification, includeConditionVerification, out maximumTime); _dataGridView.SuspendLayout(); try { _columnFullTime.MaximumTime = maximumTime; _latch.RunInsideLatch(() => { DataGridViewSortState sortState = GetSortState(); _gridHandler.BindTo(bindingList); RestoreSortState(sortState); }); } finally { _dataGridView.ResumeLayout(); } OnSelectionChanged(); }
private ServiceCallStatus VerifyQualityCore( VerificationRequest request, IServerStreamWriter <VerificationResponse> responseStream, ITrackCancel trackCancel) { SetupUserNameProvider(request); void SendResponse(VerificationResponse r) => responseStream.WriteAsync(r); BackgroundVerificationService qaService = null; List <GdbObjRefMsg> deletableAllowedErrorRefs = new List <GdbObjRefMsg>(); QualityVerification verification = null; var issueCollection = new ConcurrentBag <IssueMsg>(); string cancellationMessage = null; try { // TODO: Separate long-lived objects, such as datasetLookup, domainTransactions (add to this class) from // short-term objects (request) -> add to background verification inputs IBackgroundVerificationInputs backgroundVerificationInputs = _verificationInputsFactoryMethod(request); qaService = CreateVerificationService(backgroundVerificationInputs, issueCollection, SendResponse, trackCancel); int maxParallelRequested = request.MaxParallelProcessing; if (backgroundVerificationInputs.WorkerClient != null && maxParallelRequested > 1) { // allow directly adding issues found by client processes: qaService.DistributedTestRunner = new DistributedTestRunner( backgroundVerificationInputs.WorkerClient, request, issueCollection); } verification = qaService.Verify(backgroundVerificationInputs, trackCancel); deletableAllowedErrorRefs.AddRange( GetDeletableAllowedErrorRefs(request.Parameters, qaService)); } catch (Exception e) { _msg.Error($"Error checking quality for request {request}", e); cancellationMessage = $"Server error: {e.Message}"; if (!EnvironmentUtils.GetBooleanEnvironmentVariableValue( "PROSUITE_QA_SERVER_KEEP_SERVING_ON_ERROR")) { SetUnhealthy(); } } ServiceCallStatus result = SendFinalResponse( verification, cancellationMessage ?? qaService.CancellationMessage, issueCollection, deletableAllowedErrorRefs, qaService?.VerifiedPerimeter, SendResponse); return(result); }
public void SetVerification([NotNull] QualityVerification verification, string contextType, string contextName) { Assert.ArgumentNotNull(verification, nameof(verification)); _verification = verification; _contextType = contextType; _contextName = contextName; }
private static QualityConditionVerification FindQualityConditionVerification( QualityVerification toOverallVerification, int conditionId) { QualityConditionVerification conditionVerification = toOverallVerification.ConditionVerifications.First( c => Assert.NotNull(c.QualityCondition).Id == conditionId); return(conditionVerification); }
private static void StartVerification([CanBeNull] QualityVerification qualityVerification) { if (qualityVerification == null) { return; } qualityVerification.Operator = EnvironmentUtils.UserDisplayName; qualityVerification.StartDate = DateTime.Now; }
protected override ITestRunner CreateTestRunner( QualityVerification qualityVerification) { if (DistributedTestRunner == null) { return(base.CreateTestRunner(qualityVerification)); } return(DistributedTestRunner); }
private static void AddVerification([NotNull] QualityVerificationMsg verificationMsg, [CanBeNull] QualityVerification toOverallVerification) { if (toOverallVerification == null) { return; } if (verificationMsg.Cancelled) { toOverallVerification.Cancelled = true; } foreach (var conditionVerificationMsg in verificationMsg.ConditionVerifications) { int conditionId = conditionVerificationMsg.QualityConditionId; QualityConditionVerification conditionVerification = FindQualityConditionVerification(toOverallVerification, conditionId); conditionVerification.ErrorCount += conditionVerificationMsg.ErrorCount; conditionVerification.ExecuteTime += conditionVerificationMsg.ExecuteTime; conditionVerification.RowExecuteTime += conditionVerificationMsg.RowExecuteTime; conditionVerification.TileExecuteTime += conditionVerificationMsg.TileExecuteTime; if (!conditionVerificationMsg.Fulfilled) { conditionVerification.Fulfilled = false; } if (conditionVerificationMsg.StopConditionId >= 0) { conditionVerification.StopCondition = FindQualityConditionVerification(toOverallVerification, conditionVerificationMsg.StopConditionId) .QualityCondition; } } foreach (var datasetMsg in verificationMsg.VerificationDatasets) { QualityVerificationDataset qualityVerificationDataset = toOverallVerification.VerificationDatasets.First( d => d.Dataset.Id == datasetMsg.DatasetId); qualityVerificationDataset.LoadTime += datasetMsg.LoadTime; } toOverallVerification.ContextName = verificationMsg.ContextName; toOverallVerification.ContextType = verificationMsg.ContextType; toOverallVerification.ProcessorTimeSeconds += verificationMsg.ProcessorTimeSeconds; toOverallVerification.RowsWithStopConditions += verificationMsg.RowsWithStopConditions; toOverallVerification.Operator = verificationMsg.UserName; }
private void EndVerification([CanBeNull] QualityVerification qualityVerification) { if (qualityVerification == null) { return; } qualityVerification.EndDate = DateTime.Now; qualityVerification.Cancelled = Cancelled; qualityVerification.CalculateStatistics(); }
private static VerifiedDatasetItem CreateVerifiedDatasetItem( [NotNull] QualityVerification qualityVerification, [NotNull] Dataset dataset, [NotNull] QualityConditionVerification conditionVerification) { QualityVerificationDataset verifiedDataset = qualityVerification.GetVerificationDataset(dataset); return(new VerifiedDatasetItem(conditionVerification, dataset, verifiedDataset == null ? 0 : verifiedDataset.LoadTime)); }
private static SortableBindingList <VerifiedDatasetItem> GetVerifiedDatasetItems( [NotNull] QualityVerification qualityVerification, [NotNull] Predicate <QualityConditionVerification> includeConditionVerification, out double maximumTime) { var result = new SortableBindingList <VerifiedDatasetItem>(); maximumTime = 0; foreach ( QualityConditionVerification conditionVerification in qualityVerification.ConditionVerifications) { if (!includeConditionVerification(conditionVerification)) { continue; } var datasets = new SimpleSet <Dataset>(); QualityCondition condition = conditionVerification.DisplayableCondition; foreach (Dataset dataset in condition.GetDatasetParameterValues()) { if (datasets.Contains(dataset)) { continue; } datasets.Add(dataset); VerifiedDatasetItem item = CreateVerifiedDatasetItem( qualityVerification, dataset, conditionVerification); if (item.TotalTime > maximumTime) { maximumTime = item.TotalTime; } result.Add(item); } } return(result); }
private static void Initialize( [NotNull] QualityVerification verification, [NotNull] IDomainTransactionManager domainTransactionManager) { Assert.ArgumentNotNull(verification, nameof(verification)); Assert.ArgumentNotNull(domainTransactionManager, nameof(domainTransactionManager)); if (verification.IsPersistent) { domainTransactionManager.Reattach(verification); domainTransactionManager.Initialize(verification.VerificationDatasets); } foreach ( QualityConditionVerification conditionVerification in verification.ConditionVerifications) { QualityCondition qualityCondition = conditionVerification.DisplayableCondition; if (qualityCondition.IsPersistent) { domainTransactionManager.Reattach(qualityCondition); } foreach (TestParameterValue value in qualityCondition.ParameterValues) { if (value.IsPersistent) { domainTransactionManager.Reattach(value); } } } // NOTE this causes NonUniqueObjectExceptions in case of datasets from other models (only?) // But: it does not seem to be really needed //foreach ( // QualityVerificationDataset verificationDataset in // verification.VerificationDatasets) //{ // domainTransactionManager.Reattach(verificationDataset.Dataset); //} }
private static void LogVerificationDetails( [NotNull] QualityVerification verification) { _msg.Debug("Verified quality conditions:"); using (_msg.IncrementIndentation()) { List <QualityConditionVerification> sortedList = verification.ConditionVerifications.ToList(); sortedList.Sort((v1, v2) => string.Compare(v1.QualityCondition == null ? "<null>" : v1.QualityCondition.Name, v2.QualityCondition == null ? "<null>" : v2.QualityCondition.Name, StringComparison.CurrentCultureIgnoreCase)); foreach (QualityConditionVerification conditionVerification in sortedList) { LogConditionVerification(conditionVerification); } } _msg.Debug("Load times for verified datasets:"); using (_msg.IncrementIndentation()) { List <QualityVerificationDataset> sortedList = verification.VerificationDatasets.ToList(); sortedList.Sort((d1, d2) => string.Compare(d1.Dataset.Name, d2.Dataset.Name, StringComparison.CurrentCultureIgnoreCase)); foreach (QualityVerificationDataset verifiedDataset in sortedList) { LogVerificationDataset(verifiedDataset); } } }
private static IList <SpecificationDataset> GetSpecificationDatasets( [NotNull] QualityVerification qualityVerifiation, [NotNull] Predicate <QualityConditionVerification> includeConditionVerification) { var result = new List <SpecificationDataset>( qualityVerifiation.ConditionVerifications.Count); foreach (QualityConditionVerification conditionVerification in qualityVerifiation.ConditionVerifications) { if (includeConditionVerification(conditionVerification)) { result.Add(new SpecificationDataset(conditionVerification) { UseAliasDatasetName = true }); } } return(result); }
private QualityVerification GetQualityVerificationTx([NotNull] QualityVerificationMsg msg) { List <QualityConditionVerification> conditionVerifications = GetQualityConditionVerifications(msg); var result = new QualityVerification( msg.SpecificationId, msg.SpecificationName, msg.SpecificationDescription, msg.UserName, conditionVerifications); result.Cancelled = msg.Cancelled; result.ContextName = msg.ContextName; result.ContextType = msg.ContextType; result.StartDate = new DateTime(msg.StartTimeTicks); result.EndDate = new DateTime(msg.EndTimeTicks); result.ProcessorTimeSeconds = msg.ProcessorTimeSeconds; result.RowsWithStopConditions = msg.RowsWithStopConditions; result.CalculateStatistics(); return(result); }
private QualityVerification Verify([NotNull] IVerificationContext verificationContext, [NotNull] QualitySpecification qualitySpecification, [NotNull] VerificationServiceParameters parameters, [CanBeNull] ICollection <IObject> objects) { ISpatialReference spatialReference = verificationContext.SpatialReferenceDescriptor.SpatialReference; if (objects != null) { IEnvelope selectionEnvelope = InitSelection( objects, parameters.AreaOfInterest?.Extent, null); if (selectionEnvelope != null) { VerifiedPerimeter = selectionEnvelope; TestPerimeter = selectionEnvelope; } } if (TestPerimeter == null) { SetTestPerimeter(parameters.AreaOfInterest, spatialReference); } SetParameters(parameters); VerificationContext = verificationContext; AllowEditing = false; QualityVerification verification = VerifyEditableDatasets(qualitySpecification); verification.ContextType = parameters.VerificationContextType; verification.ContextName = parameters.VerificationContextName; return(verification); }
internal static void AssignExecutionTimes( [NotNull] QualityVerification qualityVerification, [NotNull] IEnumerable <KeyValuePair <ITest, TestVerification> > testVerifications, [NotNull] VerificationTimeStats verificationTimeStats, [NotNull] IDatasetLookup datasetLookup) { // Assign execute time foreach (KeyValuePair <ITest, TestVerification> pair in testVerifications) { AssignExecutionTime(pair.Key, pair.Value.QualityConditionVerification, verificationTimeStats); } // Assign load time foreach ( KeyValuePair <IDataset, double> pair in verificationTimeStats.DatasetLoadTimes) { IDataset gdbDataset = pair.Key; Dataset dataset = datasetLookup.GetDataset((IDatasetName)gdbDataset.FullName); if (dataset == null) { continue; } QualityVerificationDataset verificationDataset = qualityVerification.GetVerificationDataset(dataset); if (verificationDataset != null) { verificationDataset.LoadTime = pair.Value / 1000.0; } } }
private void EndVerification(QualityVerification qualityVerification, TimeSpan startTime) { if (qualityVerification == null) { return; } TimeSpan endTime = Process.GetCurrentProcess().UserProcessorTime; TimeSpan t = endTime - startTime; qualityVerification.ProcessorTimeSeconds = t.TotalSeconds; qualityVerification.EndDate = DateTime.Now; qualityVerification.Cancelled = Cancelled; qualityVerification.CalculateStatistics(); qualityVerification.RowsWithStopConditions = RowsWithStopConditions.Count; TestExecutionUtils.AssignExecutionTimes( qualityVerification, _testVerifications, VerificationTimeStats, Assert.NotNull(DatasetLookup)); }
public void RenderConditionsByCategoryView( [NotNull] QualityVerification verification, [NotNull] Func <QualityConditionVerification, bool> includeConditionVerification) { bool oldRendering = _rendering; _rendering = true; try { _verification = verification; _treeViewConditions.ShowQualityConditionsByCategory( verification.ConditionVerifications.Where(includeConditionVerification) .Select(x => new SpecificationDataset(x))); _treeViewConditions.SetDatasetIcons(_treeViewConditions.Nodes); _panelExecuteInfo.Invalidate(); } finally { _rendering = oldRendering; } }
private double GetLoadTime([NotNull] TreeNode node, [NotNull] QualityVerification verification) { return(GetLoadTime(node, verification, new HashSet <Dataset>())); }
private ServiceCallStatus VerifyDataQualityCore( [NotNull] DataVerificationRequest initialRequest, Func <DataVerificationResponse, DataVerificationRequest> moreDataRequest, IServerStreamWriter <DataVerificationResponse> responseStream, ITrackCancel trackCancel) { var request = initialRequest.Request; SetupUserNameProvider(request); void SendResponse(VerificationResponse r) => responseStream.WriteAsync( new DataVerificationResponse { Response = r }); BackgroundVerificationService qaService = null; List <GdbObjRefMsg> deletableAllowedErrorRefs = new List <GdbObjRefMsg>(); QualityVerification verification = null; var issueCollection = new ConcurrentBag <IssueMsg>(); string cancellationMessage = null; try { // TODO: Separate long-lived objects, such as datasetLookup, domainTransactions (add to this class) from // short-term objects (request) -> add to background verification inputs IBackgroundVerificationInputs backgroundVerificationInputs = _verificationInputsFactoryMethod(request); if (initialRequest.Schema != null) { backgroundVerificationInputs.SetGdbSchema( ProtobufConversionUtils.CreateSchema(initialRequest.Schema.ClassDefinitions, initialRequest .Schema.RelclassDefinitions, moreDataRequest)); } else if (moreDataRequest != null) { backgroundVerificationInputs.SetRemoteDataAccess(moreDataRequest); } qaService = CreateVerificationService(backgroundVerificationInputs, issueCollection, SendResponse, trackCancel); verification = qaService.Verify(backgroundVerificationInputs, trackCancel); deletableAllowedErrorRefs.AddRange( GetDeletableAllowedErrorRefs(request.Parameters, qaService)); } catch (Exception e) { _msg.Error($"Error checking quality for request {request}", e); cancellationMessage = $"Server error: {e.Message}"; SetUnhealthy(); } ServiceCallStatus result = SendFinalResponse( verification, cancellationMessage ?? qaService.CancellationMessage, issueCollection, deletableAllowedErrorRefs, qaService?.VerifiedPerimeter, SendResponse); return(result); }
private static void PackVerification([CanBeNull] QualityVerification verification, [NotNull] VerificationResponse response) { if (verification == null) { return; } QualityVerificationMsg result = new QualityVerificationMsg(); result.SavedVerificationId = verification.Id; result.SpecificationId = verification.SpecificationId; CallbackUtils.DoWithNonNull( verification.SpecificationName, s => result.SpecificationName = s); CallbackUtils.DoWithNonNull( verification.SpecificationDescription, s => result.SpecificationDescription = s); CallbackUtils.DoWithNonNull(verification.Operator, s => result.UserName = s); result.StartTimeTicks = verification.StartDate.Ticks; result.EndTimeTicks = verification.EndDate.Ticks; result.Fulfilled = verification.Fulfilled; result.Cancelled = verification.Cancelled; result.ProcessorTimeSeconds = verification.ProcessorTimeSeconds; CallbackUtils.DoWithNonNull(verification.ContextType, (s) => result.ContextType = s); CallbackUtils.DoWithNonNull(verification.ContextName, (s) => result.ContextName = s); result.RowsWithStopConditions = verification.RowsWithStopConditions; foreach (var conditionVerification in verification.ConditionVerifications) { var conditionVerificationMsg = new QualityConditionVerificationMsg { QualityConditionId = Assert.NotNull(conditionVerification.QualityCondition).Id, StopConditionId = conditionVerification.StopCondition?.Id ?? -1, Fulfilled = conditionVerification.Fulfilled, ErrorCount = conditionVerification.ErrorCount, ExecuteTime = conditionVerification.ExecuteTime, RowExecuteTime = conditionVerification.RowExecuteTime, TileExecuteTime = conditionVerification.TileExecuteTime }; result.ConditionVerifications.Add(conditionVerificationMsg); } foreach (var verificationDataset in verification.VerificationDatasets) { var verificationDatasetMsg = new QualityVerificationDatasetMsg { DatasetId = verificationDataset.Dataset.Id, LoadTime = verificationDataset.LoadTime }; result.VerificationDatasets.Add(verificationDatasetMsg); } response.QualityVerification = result; }
internal static void LogQualityVerification( [NotNull] QualityVerification verification) { try { var sb = new StringBuilder(); sb.AppendLine(verification.Cancelled ? "The quality verification was cancelled" : "Quality verified"); int conditionCount = verification.ConditionVerifications.Count; sb.AppendFormat("- {0:N0} quality condition{1} verified", conditionCount, conditionCount == 1 ? "" : "s"); sb.AppendLine(); int issueCount = verification.IssueCount; if (issueCount == 0) { sb.AppendLine("- No issues found"); } else { sb.AppendFormat(issueCount == 1 ? "- {0:N0} issue found" : "- {0:N0} issues found", issueCount); sb.AppendLine(); sb.AppendFormat(" - Errors: {0:N0}", verification.ErrorCount); sb.AppendLine(); sb.AppendFormat(" - Warnings: {0:N0}", verification.WarningCount); sb.AppendLine(); if (verification.RowsWithStopConditions > 0) { sb.AppendFormat(" - Number of rows with a stop condition error: {0:N0}", verification.RowsWithStopConditions); sb.AppendLine(); } } if (!verification.Cancelled) { sb.AppendLine(verification.Fulfilled ? "- The quality specification is fulfilled" : "- The quality specification is not fulfilled"); } if (verification.Fulfilled) { _msg.InfoFormat(sb.ToString()); } else { _msg.WarnFormat(sb.ToString()); } LogVerificationDetails(verification); } catch (Exception e) { _msg.Warn("Error writing report to log", e); // continue } }