Search code examples
droolsrule-engine

Problem with pattern matching in Drools 7.57.0.Final


I'm trying to run this GitHub project using Drools 7.57.0.Final instead of 7.39.0.Final which was used in original project. And I found some issues. The issue that most triggers me is the one in the Section 6, Step 5. The problem lies in the Drools file VisaApplicationValidationWithAgendaAndSalience.drl. Here is the content with the "debug" statement that I have added:

package io.github.aasaru.drools.section06.step5

import io.github.aasaru.drools.domain.Passport;
import io.github.aasaru.drools.domain.Validation;
import io.github.aasaru.drools.domain.VisaApplication;

import java.time.LocalDate;

rule "Invalidate visa application with invalid passport"
  dialect "mvel"
  agenda-group "validate-application"
  salience 20
  when
    $passport: Passport( validation == Validation.FAILED )
    $visaApplication: VisaApplication( passportNumber == $passport.passportNumber,
                                       validation != Validation.FAILED )
  then
    System.out.println( "Set " + $visaApplication + " invalid as " + $passport + " hasn't passed validation");
    modify($visaApplication) {
      setValidation( Validation.FAILED )
    }
end

rule "Set application without validation info as passed"
  dialect "mvel"
  agenda-group "validate-application"
  salience 10
  when
    $visaApplication: VisaApplication( validation == Validation.UNKNOWN )
  then
  System.out.println("debug >>>>>>>>>>>>>  " + $visaApplication.validation);
    System.out.println( $visaApplication + " is without validation info, consider OK for now" );
    modify($visaApplication) {
      setValidation( Validation.PASSED )
    }
end

rule "Invalidate visa application where passport expires earlier than 6 months after visit end date"
  dialect "mvel"
  agenda-group "validate-application"
  salience 20
  when
    $passport: Passport( validation != Validation.FAILED )
    $visaApplication: VisaApplication( passportNumber == $passport.passportNumber,
                                       $passport.expiresOn.isBefore(visitEndDate.plusMonths(6)),
                                       validation != Validation.FAILED )
  then
    System.out.println( "Set " + $visaApplication + " invalid as " + $passport + " not valid 6 months after visit");
    modify($visaApplication) {
      setValidation( Validation.FAILED )
    }
end

and here is the part of the console output that regards to the previous rules:

Set VisaApplication(#1, pass:CA-SARAH-1) invalid as Passport[no:CA-SARAH-1, name:Sarah Murphy] hasn't passed validation
Set VisaApplication(#4, pass:AU-JAMES-4) invalid as Passport[no:AU-JAMES-4, name:James Brown] not valid 6 months after visit
debug >>>>>>>>>>>>>  FAILED
VisaApplication(#1, pass:CA-SARAH-1) is without validation info, consider OK for now
Set VisaApplication(#1, pass:CA-SARAH-1) invalid as Passport[no:CA-SARAH-1, name:Sarah Murphy] hasn't passed validation
debug >>>>>>>>>>>>>  UNKNOWN
VisaApplication(#2, pass:CA-SIMON-2) is without validation info, consider OK for now
debug >>>>>>>>>>>>>  UNKNOWN
VisaApplication(#3, pass:AU-EMILY-3) is without validation info, consider OK for now

As is obvious, the middle rule, the one with the salience 10, has been fired not only for the pattern validation == Validation.UNKNOWN but also for the pattern validation == Validation.FAILED! That is wrong and it happens in Drools 7.57.0.Final and doesn't happen in Drools 7.39.0.Final used by the original project. Is it a Drools bug or what? I'm pretty new to Drools so this really confuses me.

Second, why do I get the console output Set VisaApplication(#1, pass:CA-SARAH-1) ... twice? It seems to be a consequence of the reevaluation of the 1st rule, but this shouldn't have happened as this is the stateful and not the stateless session.

If you want to reproduce the console log, download the project, change Drools version to the latest one 7.57.0.Final, run the app io.github.aasaru.drools.section06.VisaIssue, and when asked, enter 5 for the step and no when asked whether all passports should be considered as expired.


Solution

  • Congratulation, you found drools bug DROOLS-6542 - fixed in 7.60.0.Final
    There is a workaround - remove mvel dialect for the rule "Invalidate visa application with invalid passport".

    BTW, I'd like to propose you drools testing library which may save you great amount of time to mind complicated rules and simplify writing test scenarios. Here is how test may look like.

    @DroolsSession(
            resources = "classpath*:**/section06/step5/*",
            showStateTransitionPopup = true)
    public class Section6Step5Test {
        
        @RegisterExtension
        public DroolsAssert drools = new DroolsAssert();
        
        @Test
        public void test() {
            
            ApplicationRepository.getPassports().forEach(drools::insert);
            ApplicationRepository.getVisaApplications().forEach(drools::insert);
            
            drools.getSession().getAgenda().getAgendaGroup("issue-visa").setFocus();
            drools.getSession().getAgenda().getAgendaGroup("validate-application").setFocus();
            drools.getSession().getAgenda().getAgendaGroup("validate-passport").setFocus();
            
            drools.fireAllRules();
            
            assertEquals(1, drools.getObjects(Visa.class).size());
        }
    }
    

    Here is visualization popup of the test on 7.39.0.Final (or 7.57.0.Final without mvel dialect).

    enter image description here

    and the same on 7.57.0.Final (with mvel dialect)

    enter image description here