//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test public void testEvaluateDecisionByKeyAndTenantId() public virtual void testEvaluateDecisionByKeyAndTenantId() { DecisionDefinition mockDefinition = MockProvider.mockDecisionDefinition().tenantId(MockProvider.EXAMPLE_TENANT_ID).build(); UpRuntimeData = mockDefinition; DmnDecisionResult decisionResult = MockProvider.createMockDecisionResult(); when(decisionEvaluationBuilderMock.evaluate()).thenReturn(decisionResult); IDictionary <string, object> json = new Dictionary <string, object>(); json["variables"] = VariablesBuilder.create().variable("amount", 420).variable("invoiceCategory", "MISC").Variables; given().pathParam("key", MockProvider.EXAMPLE_DECISION_DEFINITION_KEY).pathParam("tenant-id", MockProvider.EXAMPLE_TENANT_ID).contentType(POST_JSON_CONTENT_TYPE).body(json).then().expect().statusCode(Status.OK.StatusCode).when().post(EVALUATE_DECISION_BY_KEY_AND_TENANT_ID_URL); IDictionary <string, object> expectedVariables = new Dictionary <string, object>(); expectedVariables["amount"] = 420; expectedVariables["invoiceCategory"] = "MISC"; verify(decisionDefinitionQueryMock).tenantIdIn(MockProvider.EXAMPLE_TENANT_ID); verify(decisionEvaluationBuilderMock).variables(expectedVariables); verify(decisionEvaluationBuilderMock).evaluate(); }
/// <summary> /// Creates the execution context snapshot - to be called by decision after the evaluation /// </summary> /// <param name="decision">Decision evaluated just before the snapshot</param> /// <param name="result"><paramref name="decision"/> result</param> internal virtual void CreateSnapshot(IDmnDecision decision, DmnDecisionResult result) { if (Options.RecordSnapshots) { Snapshots.CreateSnapshot(this, decision, result); } }
[DataRow(9, 9, null, 0)] //no hit public void UniqueHitPolicyTest(int?a, int?b, string hit, int hitsCount) { var def = new DmnDefinitionBuilder() .WithInput <int>("a", out var aRef) .WithInput <int>("b", out var bRef) .WithVariable <string>("o", out var oRef) .WithTableDecision("Unique", table => table .WithInput(aRef, out var inputARef) .WithInput(bRef, out var inputBRef) .WithOutput(oRef, out var outputRef) .WithHitPolicy(HitPolicyEnum.Unique) .WithRule("r1", r => r .When(inputARef, "< 5").And(inputBRef, "1").Then(outputRef, "\"r1\"")) .WithRule("r2", "err not unique for 5 - 2", r => r .When(inputARef, "<= 5").And(inputBRef, "2").Then(outputRef, "\"r2\"")) .WithRule("r3", r => r .When(inputARef, "5").And(inputBRef, "1").Then(outputRef, "\"r3\"")) .WithRule("r4", "err not unique for 5 - 2", r => r .When(inputARef, "5").And(inputBRef, "2").Then(outputRef, "\"r4\"")) .WithRule("r5", "err not unique for 6-3", r => r .When(inputARef, "6").Then(outputRef, "\"r5\"")) .WithRule("r6", r => r .When(inputARef, "> 6").And(inputBRef, "2").Then(outputRef, "\"r6\"")) .WithRule("rEmpty", "empty out", r => r .When(inputARef, "> 6").And(inputBRef, "1").Then(outputRef, "")) .WithRule("r8", "err not unique for 6-3", r => r .When(inputBRef, "3").Then(outputRef, "\"r8\"")) .Requires(aRef).Requires(bRef)) .Build(); var ctx = DmnExecutionContextFactory .CreateExecutionContext(def) .WithInputParameter("a", a) .WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Unique"); }; if (hitsCount < 0) { act.Should().Throw <DmnExecutorException>().WithMessage("UNIQUE hit policy violation*"); return; } act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); result.Results.Should().HaveCount(hitsCount); if (hitsCount == 0) { return; } result.Results[0].HitRules.Should().HaveCount(1); result.Results[0].HitRules[0].Name.Should().Be(hit ?? "rEmpty"); }
protected internal virtual ISet <string> collectOutputNames(DmnDecisionResult decisionResult) { ISet <string> outputNames = new HashSet <string>(); foreach (IDictionary <string, object> entryMap in decisionResult.ResultList) { outputNames.addAll(entryMap.Keys); } return(outputNames); }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test public void testEvaluateDecisionMultipleDecisionValues() public virtual void testEvaluateDecisionMultipleDecisionValues() { DmnDecisionResult decisionResult = (new MockDecisionResultBuilder()).resultEntries().entry("status", Variables.stringValue("gold")).entry("assignee", Variables.stringValue("manager")).build(); when(decisionEvaluationBuilderMock.evaluate()).thenReturn(decisionResult); IDictionary <string, object> json = new Dictionary <string, object>(); json["variables"] = Collections.emptyMap(); given().pathParam("id", MockProvider.EXAMPLE_DECISION_DEFINITION_ID).contentType(POST_JSON_CONTENT_TYPE).body(json).then().expect().statusCode(Status.OK.StatusCode).body("size()", @is(1)).body("[0].size()", @is(2)).body("[0].status.value", @is("gold")).body("[0].assignee.value", @is("manager")).when().post(EVALUATE_DECISION_URL); }
[DataRow(9, 9, null, 0, 0)] //no hit public void UniqueHitPolicyTest(int?a, int?b, string c, int hitsCount, int outVariableCount) { var dir = AppDomain.CurrentDomain.BaseDirectory; var file = Path.Combine(dir, "dmn/dmn1.3/hitpolicy_Unique.dmn"); var ctx = DmnExecutionContextFactory.CreateExecutionContext(DmnParser.Parse13(file)); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Unique"); }; if (hitsCount < 0) { act.Should().Throw <DmnExecutorException>().WithMessage("UNIQUE hit policy violation*"); return; } act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (hitsCount <= 0) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(hitsCount); result.HasResult.Should().Be(true); if (hitsCount == 1) { result.IsSingleResult.Should().Be(true); result.SingleResult.Should().NotBeNull(); result.SingleResult.Should().HaveCount(outVariableCount); } if (outVariableCount <= 0) { return; } var output = result.SingleResult[0]; output.Should().NotBeNull(); output.Name.Should().Be("o"); output.Value.Should().Be(c).And.BeOfType <string>(); output.Type.Should().Be(typeof(string)); }
[DataRow(9, 9, null, 0, 0)] //no hit public void UniqueHitPolicyTest(int?a, int?b, string c, int hitsCount, int outVariableCount) { var ctx = CTX("hitpolicy_Unique.dmn"); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Unique"); }; if (hitsCount < 0) { act.Should().Throw <DmnExecutorException>().WithMessage("UNIQUE hit policy violation*"); return; } act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (hitsCount <= 0) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(hitsCount); result.HasResult.Should().Be(true); if (hitsCount == 1) { result.IsSingleResult.Should().Be(true); result.FirstResultVariables.Should().NotBeNull(); result.FirstResultVariables.Should().HaveCount(outVariableCount); result.Results[0].HitRules.Should().HaveCount(1); } if (outVariableCount <= 0) { return; } var output = result.FirstResultVariables[0]; output.Should().NotBeNull(); output.Name.Should().Be("o"); output.Value.Should().Be(c).And.BeOfType <string>(); output.Type.Should().Be(typeof(string)); }
[DataRow(8, 8, null, 0, new[] { 0 })] //no hit public void OutputOrderHitPolicyTest(int?a, int?b, string[] c, int hitsCount, int[] outVariableCount) { var dir = AppDomain.CurrentDomain.BaseDirectory; var file = Path.Combine(dir, "dmn/dmn1.3/hitpolicy_OutputOrder.dmn"); var ctx = DmnExecutionContextFactory.CreateExecutionContext(DmnParser.Parse13(file)); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("OutputOrder"); }; act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (hitsCount <= 0) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(hitsCount); result.HasResult.Should().Be(true); if (hitsCount == 1) { result.IsSingleResult.Should().Be(true); result.SingleResult.Should().NotBeNull(); result.SingleResult.Should().HaveCount(outVariableCount[0]); } for (var i = 0; i < hitsCount; i++) { if (outVariableCount[i] <= 0) { result.Results[i].Variables.Should().HaveCount(0); continue; } result.Results[i].Variables.Should().HaveCount(1); var output = result.Results[i].Variables[0]; output.Should().NotBeNull(); output.Name.Should().Be("o"); output.Value.Should().Be(c[i]).And.BeOfType <string>(); output.Type.Should().Be(typeof(string)); } }
[DataRow(8, 8, null, 0, new[] { 0 })] //no hit public void OutputOrderHitPolicyTest(int?a, int?b, string[] c, int hitsCount, int[] outVariableCount) { var ctx = CTX("hitpolicy_OutputOrder.dmn"); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("OutputOrder"); }; act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (hitsCount <= 0) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(hitsCount); result.HasResult.Should().Be(true); if (hitsCount == 1) { result.IsSingleResult.Should().Be(true); result.FirstResultVariables.Should().NotBeNull(); result.FirstResultVariables.Should().HaveCount(outVariableCount[0]); } for (var i = 0; i < hitsCount; i++) { if (outVariableCount[i] <= 0) { result.Results[i].Variables.Should().HaveCount(0); continue; } result.Results[i].Variables.Should().HaveCount(1); result.Results[i].HitRules.Should().HaveCount(1); var output = result.Results[i].Variables[0]; output.Should().NotBeNull(); output.Name.Should().Be("o"); output.Value.Should().Be(c[i]).And.BeOfType <string>(); output.Type.Should().Be(typeof(string)); } }
[DataRow(8, 8, false, 0)] //no hit public void CollectMaxBoolHitPolicyTest(int?a, int?b, bool?c, int hitsCount) { var dir = AppDomain.CurrentDomain.BaseDirectory; var file = Path.Combine(dir, "dmn/dmn1.3/hitpolicy_Collect_MaxBool.dmn"); var ctx = DmnExecutionContextFactory.CreateExecutionContext(DmnParser.Parse13(file)); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Collect"); }; act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (hitsCount <= 0) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(hitsCount); result.HasResult.Should().Be(true); result.IsSingleResult.Should().Be(true); result.SingleResult.Should().NotBeNull(); result.SingleResult.Should().HaveCount(1); result.Results[0].Variables.Should().HaveCount(1); var output = result.Results[0].Variables[0]; output.Should().NotBeNull(); output.Name.Should().Be("o"); if (c != null) { output.Value.Should().Be(c).And.BeOfType <bool>(); output.Type.Should().Be(typeof(bool)); } else { output.Value.Should().BeNull(); output.Type.Should().Be(typeof(bool)); } }
[DataRow(8, 8, 0, 0)] //no hit public void CollectCountStrHitPolicyTest(int?a, int?b, int?c, int hitsCount) { var ctx = CTX("hitpolicy_Collect_CountStr.dmn"); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Collect"); }; act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (hitsCount <= 0) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(1); result.HasResult.Should().Be(true); result.IsSingleResult.Should().Be(true); result.FirstResultVariables.Should().NotBeNull(); result.FirstResultVariables.Should().HaveCount(1); result.Results[0].Variables.Should().HaveCount(1); result.Results[0].HitRules.Should().HaveCount(hitsCount); var output = result.Results[0].Variables[0]; output.Should().NotBeNull(); output.Name.Should().Be("o"); if (c != null) { output.Value.Should().Be(c.ToString()).And.BeOfType <string>(); output.Type.Should().Be(typeof(string)); } else { output.Value.Should().BeNull(); output.Type.Should().Be(typeof(string)); } }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test public void testEvaluateDecisionById() public virtual void testEvaluateDecisionById() { DmnDecisionResult decisionResult = MockProvider.createMockDecisionResult(); when(decisionEvaluationBuilderMock.evaluate()).thenReturn(decisionResult); IDictionary <string, object> json = new Dictionary <string, object>(); json["variables"] = VariablesBuilder.create().variable("amount", 420).variable("invoiceCategory", "MISC").Variables; given().pathParam("id", MockProvider.EXAMPLE_DECISION_DEFINITION_ID).contentType(POST_JSON_CONTENT_TYPE).body(json).then().expect().statusCode(Status.OK.StatusCode).when().post(EVALUATE_DECISION_URL); IDictionary <string, object> expectedVariables = new Dictionary <string, object>(); expectedVariables["amount"] = 420; expectedVariables["invoiceCategory"] = "MISC"; verify(decisionEvaluationBuilderMock).variables(expectedVariables); verify(decisionEvaluationBuilderMock).evaluate(); }
public virtual object mapDecisionResult(DmnDecisionResult decisionResult) { if (decisionResult.Empty) { return(Collections.emptyList()); } else { ISet <string> outputNames = collectOutputNames(decisionResult); if (outputNames.Count > 1) { throw LOG.decisionResultCollectMappingException(outputNames, decisionResult, this); } else { string outputName = outputNames.GetEnumerator().next(); return(decisionResult.collectEntries(outputName)); } } }
public void AllowedValuesTest(string a, string b, string c, bool validIn, bool validOut) { var ctx = CTX("allowedValues.dmn"); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Test"); }; if (!validIn && validOut) { act.Should().NotThrow(); result.HasResult.Should().BeFalse(); //act.Should().Throw<DmnExecutorException>().WithMessage("Decision table Test, *Input value * is not in allowed values list *"); return; } if (!validOut) { act.Should().Throw <DmnExecutorException>().WithMessage("Decision table Test,* Output value * is not in allowed values list *"); return; } act.Invoke(); result.Should().NotBeNull(); result.IsSingleResult.Should().Be(true); result.FirstResultVariables.Should().NotBeNull(); result.FirstResultVariables.Should().HaveCount(1); result.Results[0].HitRules.Should().HaveCount(1); var output = result.FirstResultVariables[0]; output.Should().NotBeNull(); output.Name.Should().Be("c"); output.Value.Should().Be(c).And.BeOfType <string>(); output.Type.Should().Be(typeof(string)); }
public void AllowedValuesTest(string a, string b, string c, bool validIn, bool validOut) { var dir = AppDomain.CurrentDomain.BaseDirectory; var file = Path.Combine(dir, "dmn/dmn1.3/allowedValues.dmn"); var ctx = DmnExecutionContextFactory.CreateExecutionContext(DmnParser.Parse(file, DmnParser.DmnVersionEnum.V1_3)); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Test"); }; if (!validIn && validOut) { act.Should().Throw <DmnExecutorException>().WithMessage("Decision table Test,* Input value * is not in allowed values list *"); return; } if (!validOut) { act.Should().Throw <DmnExecutorException>().WithMessage("Decision table Test,* Output value * is not in allowed values list *"); return; } act.Invoke(); result.Should().NotBeNull(); result.IsSingleResult.Should().Be(true); result.SingleResult.Should().NotBeNull(); result.SingleResult.Should().HaveCount(1); var output = result.SingleResult[0]; output.Should().NotBeNull(); output.Name.Should().Be("c"); output.Value.Should().Be(c).And.BeOfType <string>(); output.Type.Should().Be(typeof(string)); }
public virtual IList <IDictionary <string, VariableValueDto> > evaluateDecision(UriInfo context, EvaluateDecisionDto parameters) { DecisionService decisionService = engine.DecisionService; IDictionary <string, object> variables = VariableValueDto.toMap(parameters.Variables, engine, objectMapper); try { DmnDecisionResult decisionResult = decisionService.evaluateDecisionById(decisionDefinitionId).variables(variables).evaluate(); return(createDecisionResultDto(decisionResult)); } catch (AuthorizationException e) { throw e; } catch (NotFoundException e) { string errorMessage = string.Format("Cannot evaluate decision {0}: {1}", decisionDefinitionId, e.Message); throw new InvalidRequestException(Response.Status.NOT_FOUND, e, errorMessage); } catch (NotValidException e) { string errorMessage = string.Format("Cannot evaluate decision {0}: {1}", decisionDefinitionId, e.Message); throw new InvalidRequestException(Response.Status.BAD_REQUEST, e, errorMessage); } catch (ProcessEngineException e) { string errorMessage = string.Format("Cannot evaluate decision {0}: {1}", decisionDefinitionId, e.Message); throw new RestException(Response.Status.INTERNAL_SERVER_ERROR, e, errorMessage); } catch (DmnEngineException e) { string errorMessage = string.Format("Cannot evaluate decision {0}: {1}", decisionDefinitionId, e.Message); throw new RestException(Response.Status.INTERNAL_SERVER_ERROR, e, errorMessage); } }
[DataRow(8, 8, new int[] { }, 0, new[] { 0 })] //no hit public void CollectListHitPolicyTest(int?a, int?b, int[] cIn, int hitsCount, int[] outVariableCount) { var c = new int?[cIn.Length]; for (var i = 0; i < cIn.Length; i++) { if (cIn[i] >= 0) { c[i] = cIn[i]; } else { c[i] = null; } } var ctx = CTX("hitpolicy_Collect_List.dmn"); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Collect"); }; act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (hitsCount <= 0) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(hitsCount); result.HasResult.Should().Be(true); if (hitsCount == 1) { result.IsSingleResult.Should().Be(true); result.FirstResultVariables.Should().NotBeNull(); result.FirstResultVariables.Should().HaveCount(outVariableCount[0]); } for (var i = 0; i < hitsCount; i++) { if (outVariableCount[i] <= 0) { result.Results[i].Variables.Should().HaveCount(0); continue; } result.Results[i].Variables.Should().HaveCount(1); result.Results[i].HitRules.Should().HaveCount(1); var output = result.Results[i].Variables[0]; output.Should().NotBeNull(); output.Name.Should().Be("o"); output.Value.Should().Be(c[i]).And.BeOfType <long>(); output.Type.Should().Be(typeof(long)); } }
public virtual ProcessEngineException decisionResultMappingException(DmnDecisionResult decisionResult, DecisionResultMapper resultMapper, DmnEngineException cause) { return(new ProcessEngineException(exceptionMessage("001", "The decision result mapper '{}' failed to process '{}'", resultMapper, decisionResult), cause)); }
/// <summary> /// CTOR /// </summary> /// <param name="step">Sequence number of the execution step</param> /// <param name="ctx">Execution context to create snapshot for</param> /// <param name="decision">Decision executed just before snapshot</param> /// <param name="result">Result of the decision executed just before snapshot</param> internal DmnExecutionSnapshot(int step, DmnExecutionContext ctx, IDmnDecision decision, DmnDecisionResult result) : this(step, ctx) { Decision = decision; DecisionResult = result?.Clone(); }
[DataRow(null, null, new[] { "" }, new[] { -1 }, new[] { "" }, false)] //null -> 0 public void RuleOrderHitPolicyMultiOutTest(int?a, int?b, string[] o1, int[] o2, string[] o3, bool hasHit) { var ctx = CTX("hitpolicy_MultiOut_RuleOrder.dmn"); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("RuleOrder"); }; act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (!hasHit) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } var hitsCount = o1.Length; result.Results.Should().HaveCount(hitsCount); result.HasResult.Should().Be(true); if (hitsCount == 1) { result.IsSingleResult.Should().Be(true); result.FirstResultVariables.Should().NotBeNull(); } result.Results.Should().HaveCount(hitsCount); var idx = 0; foreach (var resultHit in result.Results) { resultHit.HitRules.Should().HaveCount(1); var o1Result = resultHit.Variables?.FirstOrDefault(v => v.Name == "o1"); var o2Result = resultHit.Variables?.FirstOrDefault(v => v.Name == "o2"); var o3Result = resultHit.Variables?.FirstOrDefault(v => v.Name == "o3"); var o1Assert = o1[idx]; var o2Assert = o2[idx]; var o3Assert = o3[idx]; if (o1Result == null) { o1Assert.Should().BeNull(); } else { o1Result.Should().NotBeNull(); o1Result.Value.Should().NotBeNull(); o1Result.Value.Should().Be(o1Assert).And.BeOfType <string>(); o1Result.Type.Should().Be(typeof(string)); } if (o2Result == null) { o2Assert.Should().Be(-1); //-1 means null } else { o2Result.Should().NotBeNull(); o2Result.Value.Should().NotBeNull(); o2Result.Value.Should().Be(o2Assert).And.BeOfType <int>(); o2Result.Type.Should().Be(typeof(int)); } if (o3Result == null) { o3Assert.Should().BeNull(); } else { o3Result.Should().NotBeNull(); o3Result.Value.Should().NotBeNull(); o3Result.Value.Should().Be(o3Assert).And.BeOfType <string>(); o3Result.Type.Should().Be(typeof(string)); } idx++; } }
/// <summary> /// Evaluates the decision table. /// </summary> /// <remarks> /// While evaluating the decision table, the <seealso cref="Rules"/> are evaluated first. /// Then it evaluates (calculates) the outputs for positive rules and applies the hit policy. /// </remarks> /// <param name="context">DMN Engine execution context</param> /// <param name="correlationId">Optional correlation ID used while logging</param> /// <returns>Decision result</returns> /// <exception cref="ArgumentNullException"><paramref name="context"/> is null</exception> protected override DmnDecisionResult Evaluate(DmnExecutionContext context, string correlationId = null) { if (context == null) { throw Logger.FatalCorr <ArgumentNullException>(correlationId, $"{nameof(context)} is null"); } //EVALUATE RULES var positiveRules = EvaluateRules(context, correlationId); //EVALUATE OUTPUTS for positive rules var results = EvaluateOutputsForPositiveRules(context, correlationId, positiveRules); //APPLY HIT POLICY if (positiveRules.Count <= 0) { return(new DmnDecisionResult()); } var retVal = new DmnDecisionResult(); var positiveMatchOutputRules = new List <DmnDecisionTableRule>(); // ReSharper disable once SwitchStatementMissingSomeCases switch (HitPolicy) { case HitPolicyEnum.Unique: // No overlap is possible and all rules are disjoint. Only a single rule can be matched // Overlapping rules represent an error. if (positiveRules.Count > 1) { throw Logger.ErrorCorr <DmnExecutorException>( correlationId, $"UNIQUE hit policy violation - {positiveRules.Count} matches"); } positiveMatchOutputRules.Add(positiveRules[0]); break; case HitPolicyEnum.First: //Multiple(overlapping) rules can match, with different output entries. The first hit by rule order is returned positiveMatchOutputRules.Add(positiveRules[0]); break; case HitPolicyEnum.Priority: // Multiple rules can match, with different output entries. This policy returns the matching rule with the highest output priority. // Output priorities are specified in the ordered list of output values, in decreasing order of priority. Note that priorities are independent from rule sequence // A P table that omits allowed output values is an error. var orderedPositiveRules = OrderPositiveRulesByOutputPriority(positiveRules, results, correlationId); if (orderedPositiveRules == null) { //A P table that omits allowed output values is an error. throw Logger.ErrorCorr <DmnExecutorException>( correlationId, $"PRIORITY hit policy violation - no outputs with Allowed Values"); } positiveMatchOutputRules.Add(orderedPositiveRules.ToArray()[0]); break; case HitPolicyEnum.Any: // There may be overlap, but all of the matching rules show equal output entries for each output, so any match can be used. // If the output entries are non-equal, the hit policy is incorrect and the result is an error. if (!MatchRuleOutputs(positiveRules, results)) { throw Logger.ErrorCorr <DmnExecutorException>( correlationId, $"ANY hit policy violation - the outputs don't match"); } positiveMatchOutputRules.Add(positiveRules[0]); break; case HitPolicyEnum.Collect: // Multiple rules can be satisfied. The decision table result contains the output of all satisfied rules in an arbitrary order as a list. // If an aggregator is specified, the decision table result will only contain a single output entry. The aggregator will generate the output entry from all satisfied rules. // Except for C-count and C-list, the rules must have numeric output values (bool is also allowed - 0=false, 1=true). // If the Collect hit policy is used with an aggregator, the decision table can only have one output. if (Outputs.Count > 1 && Aggregation != CollectHitPolicyAggregationEnum.List) { throw Logger.ErrorCorr <DmnExecutorException>( correlationId, $"COLLECT hit policy violation - multiple outputs not allowed for aggregation {Aggregation}"); } var outType = Outputs[0].Variable.Type; var outTypeIsNumeric = outType == typeof(int) || outType == typeof(long) || outType == typeof(double); var outTypeIsBool = outType == typeof(bool); var outTypeIsStr = outType == typeof(string); var isAllowedForCount = outTypeIsNumeric || outTypeIsStr; var isAllowedForSumMinMax = outTypeIsNumeric || outTypeIsBool; if (! (Aggregation == CollectHitPolicyAggregationEnum.List || (Aggregation == CollectHitPolicyAggregationEnum.Count && isAllowedForCount) || Aggregation != CollectHitPolicyAggregationEnum.List && Aggregation != CollectHitPolicyAggregationEnum.Count && isAllowedForSumMinMax)) { throw Logger.ErrorCorr <DmnExecutorException>( correlationId, $"COLLECT hit policy violation - type {outType.Name} not allowed for aggregation {Aggregation}"); } if (Aggregation == CollectHitPolicyAggregationEnum.List) { positiveMatchOutputRules.AddRange(positiveRules); } else { var collectValues = isAllowedForSumMinMax ? CalculatePositiveRulesCollectValues(positiveRules, results) : CalculatePositiveRulesCollectCountValue(positiveRules, results); var output = Outputs[0]; var outputVariable = context.GetVariable(output.Variable); if (collectValues.Count == 0 && Aggregation != CollectHitPolicyAggregationEnum.Count) { //no value for sum, min, max outputVariable.Value = null; retVal += new DmnDecisionSingleResult() + outputVariable.Clone(); return(retVal); } // ReSharper disable once SwitchStatementMissingSomeCases switch (Aggregation) { case CollectHitPolicyAggregationEnum.Sum: outputVariable.Value = collectValues.Sum; break; case CollectHitPolicyAggregationEnum.Min: outputVariable.Value = collectValues.Min; break; case CollectHitPolicyAggregationEnum.Max: outputVariable.Value = collectValues.Max; break; case CollectHitPolicyAggregationEnum.Count: outputVariable.Value = collectValues.Count; break; } retVal += new DmnDecisionSingleResult() + outputVariable.Clone(); return(retVal); } break; case HitPolicyEnum.RuleOrder: //Multiple rules can be satisfied.The decision table result contains the output of all satisfied rules in the order of the rules in the decision table. positiveMatchOutputRules.AddRange(positiveRules); break; case HitPolicyEnum.OutputOrder: //Returns all hits in decreasing output priority order. // Output priorities are specified in the ordered list of output values in decreasing order of priority var orderedPositiveRules2 = OrderPositiveRulesByOutputPriority(positiveRules, results, correlationId); if (orderedPositiveRules2 == null) { //A P table that omits allowed output values is an error. throw Logger.ErrorCorr <DmnExecutorException>( correlationId, $"OUTPUT ORDER hit policy violation - no outputs with Allowed Values"); } positiveMatchOutputRules.AddRange(orderedPositiveRules2); break; } //Return (multiple) matches foreach (var multiMatchOutputRule in positiveMatchOutputRules) { var singleResult = new DmnDecisionSingleResult(); foreach (var ruleOutput in multiMatchOutputRule.Outputs) { var resultOutput = results.GetResult(multiMatchOutputRule, ruleOutput); if (resultOutput == null) { continue; } context.GetVariable(ruleOutput.Output.Variable).Value = resultOutput.Value; singleResult += resultOutput; } retVal += singleResult; } return(retVal); }
/// <summary> /// Creates the snapshot with the decision information /// </summary> /// <param name="ctx">Execution context to create snapshot for</param> /// <param name="decision">Decision executed just before snapshot</param> /// <param name="result">Result of the decision executed just before snapshot</param> internal void CreateSnapshot(DmnExecutionContext ctx, IDmnDecision decision, DmnDecisionResult result) { snapshots.Add(new DmnExecutionSnapshot(snapshots.Count, ctx, decision, result)); }
[DataRow(8, 8, new int[] { }, 0, new[] { 0 })] //no hit public void CollectListHitPolicyTest(int?a, int?b, int[] cIn, int hitsCount, int[] outVariableCount) { var c = new int?[cIn.Length]; for (var i = 0; i < cIn.Length; i++) { if (cIn[i] >= 0) { c[i] = cIn[i]; } else { c[i] = null; } } var dir = AppDomain.CurrentDomain.BaseDirectory; var file = Path.Combine(dir, "dmn/hitpolicy_Collect_List.dmn"); var ctx = DmnExecutionContextFactory.CreateExecutionContext(DmnParser.Parse(file)); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Collect"); }; act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (hitsCount <= 0) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(hitsCount); result.HasResult.Should().Be(true); if (hitsCount == 1) { result.IsSingleResult.Should().Be(true); result.SingleResult.Should().NotBeNull(); result.SingleResult.Should().HaveCount(outVariableCount[0]); } for (var i = 0; i < hitsCount; i++) { if (outVariableCount[i] <= 0) { result.Results[i].Variables.Should().HaveCount(0); continue; } result.Results[i].Variables.Should().HaveCount(1); var output = result.Results[i].Variables[0]; output.Should().NotBeNull(); output.Name.Should().Be("o"); output.Value.Should().Be(c[i]).And.BeOfType <long>(); output.Type.Should().Be(typeof(long)); } }
protected internal virtual IList <IDictionary <string, VariableValueDto> > createDecisionResultDto(DmnDecisionResult decisionResult) { IList <IDictionary <string, VariableValueDto> > dto = new List <IDictionary <string, VariableValueDto> >(); foreach (DmnDecisionResultEntries entries in decisionResult) { IDictionary <string, VariableValueDto> resultEntriesDto = createResultEntriesDto(entries); dto.Add(resultEntriesDto); } return(dto); }
public void AnyHitPolicyMultiOutTest(int?a, int?b, string o1, int?o2, bool hasHit, bool isErr) { var dir = AppDomain.CurrentDomain.BaseDirectory; var file = Path.Combine(dir, "dmn/dmn1.3/hitpolicy_MultiOut_Any.dmn"); var ctx = DmnExecutionContextFactory.CreateExecutionContext(DmnParser.Parse13(file)); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Any"); }; if (isErr) { act.Should().Throw <DmnExecutorException>().WithMessage("ANY hit policy violation - the outputs don't match"); return; } act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (!hasHit) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(1); result.HasResult.Should().Be(true); result.IsSingleResult.Should().Be(true); result.SingleResult.Should().NotBeNull(); var outCount = 2; var o1Index = 0; var o2Index = 1; if (o1 == null) { outCount--; o1Index = -1; o2Index--; } if (o2 == null) { outCount--; o2Index = -1; } result.SingleResult.Should().HaveCount(outCount); if (o1Index >= 0) { var output1 = result.SingleResult[o1Index]; output1.Should().NotBeNull(); output1.Name.Should().Be("o1"); output1.Value.Should().Be(o1).And.BeOfType <string>(); output1.Type.Should().Be(typeof(string)); } // ReSharper disable once InvertIf if (o2Index >= 0) { var output2 = result.SingleResult[o2Index]; output2.Should().NotBeNull(); output2.Name.Should().Be("o2"); output2.Value.Should().Be(o2).And.BeOfType <int>(); output2.Type.Should().Be(typeof(int)); } }
public void AnyHitPolicyMultiOutTest(int?a, int?b, string o1, int?o2, bool hasHit, bool isErr) { var ctx = CTX("hitpolicy_MultiOut_Any.dmn"); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("Any"); }; if (isErr) { act.Should().Throw <DmnExecutorException>().WithMessage("ANY hit policy violation - the outputs don't match"); return; } act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (!hasHit) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } result.Results.Should().HaveCount(1); result.HasResult.Should().Be(true); result.Results[0].HitRules.Should().HaveCount(1); result.IsSingleResult.Should().Be(true); result.FirstResultVariables.Should().NotBeNull(); var outCount = 2; var o1Index = 0; var o2Index = 1; if (o1 == null) { outCount--; o1Index = -1; o2Index--; } if (o2 == null) { outCount--; o2Index = -1; } result.FirstResultVariables.Should().HaveCount(outCount); if (o1Index >= 0) { var output1 = result.FirstResultVariables[o1Index]; output1.Should().NotBeNull(); output1.Name.Should().Be("o1"); output1.Value.Should().Be(o1).And.BeOfType <string>(); output1.Type.Should().Be(typeof(string)); } // ReSharper disable once InvertIf if (o2Index >= 0) { var output2 = result.FirstResultVariables[o2Index]; output2.Should().NotBeNull(); output2.Name.Should().Be("o2"); output2.Value.Should().Be(o2).And.BeOfType <int>(); output2.Type.Should().Be(typeof(int)); } }
[DataRow(null, null, new[] { "" }, new[] { -1 }, new[] { "" }, false)] //null -> 0 public void RuleOrderHitPolicyMultiOutTest(int?a, int?b, string[] o1, int[] o2, string[] o3, bool hasHit) { var dir = AppDomain.CurrentDomain.BaseDirectory; var file = Path.Combine(dir, "dmn/dmn1.3/hitpolicy_MultiOut_RuleOrder.dmn"); var ctx = DmnExecutionContextFactory.CreateExecutionContext(DmnParser.Parse13(file)); ctx.WithInputParameter("a", a); ctx.WithInputParameter("b", b); DmnDecisionResult result = null; Action act = () => { result = ctx.ExecuteDecision("RuleOrder"); }; act.Invoke(); result.Should().NotBeNull(); result.Results.Should().NotBeNull(); if (!hasHit) { result.Results.Should().HaveCount(0); result.HasResult.Should().Be(false); result.IsSingleResult.Should().Be(false); return; } var hitsCount = o1.Length; result.Results.Should().HaveCount(hitsCount); result.HasResult.Should().Be(true); if (hitsCount == 1) { result.IsSingleResult.Should().Be(true); result.SingleResult.Should().NotBeNull(); } result.Results.Should().HaveCount(hitsCount); var idx = 0; foreach (var resultHit in result.Results) { var o1Result = resultHit.Variables?.FirstOrDefault(v => v.Name == "o1"); var o2Result = resultHit.Variables?.FirstOrDefault(v => v.Name == "o2"); var o3Result = resultHit.Variables?.FirstOrDefault(v => v.Name == "o3"); var o1Asserrt = o1[idx]; var o2Asserrt = o2[idx]; var o3Asserrt = o3[idx]; if (o1Result == null) { o1Asserrt.Should().BeNull(); } else { o1Result.Should().NotBeNull(); o1Result.Value.Should().NotBeNull(); o1Result.Value.Should().Be(o1Asserrt).And.BeOfType <string>(); o1Result.Type.Should().Be(typeof(string)); } if (o2Result == null) { o2Asserrt.Should().Be(-1); //-1 means null } else { o2Result.Should().NotBeNull(); o2Result.Value.Should().NotBeNull(); o2Result.Value.Should().Be(o2Asserrt).And.BeOfType <int>(); o2Result.Type.Should().Be(typeof(int)); } if (o3Result == null) { o3Asserrt.Should().BeNull(); } else { o3Result.Should().NotBeNull(); o3Result.Value.Should().NotBeNull(); o3Result.Value.Should().Be(o3Asserrt).And.BeOfType <string>(); o3Result.Type.Should().Be(typeof(string)); } idx++; } }
public virtual ProcessEngineException decisionResultCollectMappingException(ICollection <string> outputNames, DmnDecisionResult decisionResult, DecisionResultMapper resultMapper) { return(new ProcessEngineException(exceptionMessage("002", "The decision result mapper '{}' failed to process '{}'. The decision outputs should only contains values for one output name but found '{}'.", resultMapper, decisionResult, outputNames))); }