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]

Reply via email to