tkobayas opened a new issue, #7222:
URL: https://github.com/apache/incubator-kie/issues/7222
## Problem
While adding test coverage for `insert`/`delete`/`update` in the RHS in
sequential mode (#7221), 3 cases were found where sequential mode behaves
differently from non-sequential mode. The tests are added in
`SequentialInsertDeleteUpdateTest` and are `@Disabled` until this issue is
resolved.
All 3 tests pass with `SequentialOption.NO`.
### 1. Inserting an object which is already in the working memory creates
another fact
```java
@ParameterizedTest(name = "KieBase type={0}")
@MethodSource("parameters")
public void testInsertSameObjectAgain(KieBaseTestConfiguration
kieBaseTestConfiguration) {
String str =
"package org.drools.mvel.compiler.test\n" +
"import " + Cheese.class.getCanonicalName() + "\n" +
"global " + List.class.getCanonicalName() + " list\n" +
"rule R1 salience 100 when\n" +
" $c : Cheese()\n" +
"then\n" +
" insert( $c );\n" +
" list.add( \"R1\" );\n" +
"end\n" +
"rule R2 when\n" +
" $c : Cheese()\n" +
"then\n" +
" list.add( \"R2:\" + $c.getType() );\n" +
"end\n";
List<String> list = executeSequential(str, kieBaseTestConfiguration,
new Cheese("stilton", 10));
assertThat(list).containsExactly("R1", "R2:stilton");
}
```
- Expected (non-sequential): `[R1, R2:stilton]`
- Actual (sequential): `[R1, R2:stilton, R2:stilton]`
- Cause: in sequential mode, `NamedEntryPoint.insert` skips the lookup of an
existing handle for the object and always creates a new handle.
### 2. delete doesn't cancel the other pending matches of the same rule
A single-use Coupon is deleted when it is applied. R1 has 2 matches (one per
Order) with the same Coupon.
```java
@ParameterizedTest(name = "KieBase type={0}")
@MethodSource("parameters")
public void
testDeleteFactOfPendingMatchOfSameRule(KieBaseTestConfiguration
kieBaseTestConfiguration) {
String str =
"package org.drools.mvel.compiler.test\n" +
"import " + Order.class.getCanonicalName() + "\n" +
"import " + Coupon.class.getCanonicalName() + "\n" +
"global " + List.class.getCanonicalName() + " list\n" +
"rule R1 when\n" +
" $o : Order( discounted == false )\n" +
" $c : Coupon()\n" +
"then\n" +
" modify( $o ) { setTotal( $o.getTotal() -
$c.getDiscount() ), setDiscounted( true ) };\n" +
" delete( $c );\n" +
" list.add( \"R1:\" + $o.getId() + \":\" + $c.getCode()
);\n" +
"end\n";
Order o1 = new Order("o1", 100);
Order o2 = new Order("o2", 100);
List<String> list = executeSequential(str, kieBaseTestConfiguration,
o1, o2, new Coupon("A", 10));
assertThat(list).hasSize(1);
assertThat(Stream.of(o1, o2).filter(Order::isDiscounted)).hasSize(1);
}
```
- Expected (non-sequential): the Coupon is applied to only 1 Order
- Actual (sequential): `[R1:o1:A, R1:o2:A]` — the deleted Coupon is applied
to both Orders
### 3. update doesn't cancel the other pending matches of the same rule
Only one Coupon can be applied to an Order. R1 has 2 matches (one per
Coupon) with the same Order.
```java
@ParameterizedTest(name = "KieBase type={0}")
@MethodSource("parameters")
public void
testUpdateFactOfPendingMatchOfSameRule(KieBaseTestConfiguration
kieBaseTestConfiguration) {
String str =
"package org.drools.mvel.compiler.test\n" +
"import " + Order.class.getCanonicalName() + "\n" +
"import " + Coupon.class.getCanonicalName() + "\n" +
"global " + List.class.getCanonicalName() + " list\n" +
"rule R1 when\n" +
" $o : Order( discounted == false )\n" +
" $c : Coupon()\n" +
"then\n" +
" modify( $o ) { setTotal( $o.getTotal() -
$c.getDiscount() ), setDiscounted( true ) };\n" +
" list.add( \"R1:\" + $o.getId() + \":\" + $c.getCode()
);\n" +
"end\n";
Order o1 = new Order("o1", 100);
List<String> list = executeSequential(str, kieBaseTestConfiguration,
o1, new Coupon("A", 10), new Coupon("B", 20));
assertThat(list).hasSize(1);
assertThat(o1.getTotal()).isIn(90, 80);
}
```
- Expected (non-sequential): only 1 Coupon is applied to the Order
- Actual (sequential): `[R1:o1:A, R1:o1:B]` — both Coupons are applied
(total = 70) although the Order is already `discounted == true`
Cause of 2 and 3: `RuleExecutor.fire` doesn't call `evaluateNetworkIfDirty`
in sequential mode, so the matches of a rule are fixed when the rule is
evaluated, and changes made by the rule's own firings don't cancel its
remaining matches.
## What should be done
Decide whether each case is a bug or the intended semantics of sequential
mode.
- If it is a bug, fix it and enable the test.
- It may also be decided that this is the specification of sequential mode.
Sequential mode evaluates each rule only once, and before PHREAK all matches
were created up front and fired without re-evaluation, so 2 and 3 are
consistent with that concept. Case 1 can also be seen as a deliberate
optimization (skipping the handle lookup on insert). In that case, change the
tests to assert the actual behavior and document it in the sequential mode
documentation (#7210), for example:
- Within a rule, the matches are fixed when the rule is evaluated.
delete/update by the rule's own firing doesn't cancel its other matches.
- Inserting an object which is already in the working memory creates
another fact.
## Related
- #7221 — Add test coverage for insert/delete in sequential mode
- #7210 — Update sequential mode documentation to reflect PHREAK behavior
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]