diff --git a/engine/GruleEngine.go b/engine/GruleEngine.go index 2685c840..628e8fab 100755 --- a/engine/GruleEngine.go +++ b/engine/GruleEngine.go @@ -120,6 +120,11 @@ func (g *GruleEngine) notifyBeginCycle(cycle uint64) { // The engine will evaluate context cancelation status in each cycle. // The engine also do conflict resolution of which rule to execute. func (g *GruleEngine) ExecuteWithContext(ctx context.Context, dataCtx ast.IDataContext, knowledge *ast.KnowledgeBase) error { + if knowledge == nil || dataCtx == nil { + + return fmt.Errorf("nil KnowledgeBase or DataContext is not allowed") + } + log.Debugf("Starting rule execution using knowledge '%s' version %s. Contains %d rule entries", knowledge.Name, knowledge.Version, len(knowledge.RuleEntries)) // Prepare the timer, we need to measure the processing time in debug mode. @@ -241,6 +246,11 @@ func (g *GruleEngine) ExecuteWithContext(ctx context.Context, dataCtx ast.IDataC // FetchMatchingRules function is responsible to fetch all the rules that matches to a fact against all rule entries // Returns []*ast.RuleEntry order by salience func (g *GruleEngine) FetchMatchingRules(dataCtx ast.IDataContext, knowledge *ast.KnowledgeBase) ([]*ast.RuleEntry, error) { + if knowledge == nil || dataCtx == nil { + + return nil, fmt.Errorf("nil KnowledgeBase or DataContext is not allowed") + } + log.Debugf("Starting rule matching using knowledge '%s' version %s. Contains %d rule entries", knowledge.Name, knowledge.Version, len(knowledge.RuleEntries)) // Prepare the build-in function and add to datacontext. defunc := &ast.BuiltInFunctions{ diff --git a/examples/Concurrency_test.go b/examples/Concurrency_test.go index 9767a00c..81ad7e57 100644 --- a/examples/Concurrency_test.go +++ b/examples/Concurrency_test.go @@ -66,9 +66,9 @@ var ( type Vibonaci struct { fmt.Stringer Count int - A uint - B uint - C uint + A uint64 + B uint64 + C uint64 } func startThread(threadName string) { diff --git a/examples/NilKnowledgeBasePanic_test.go b/examples/NilKnowledgeBasePanic_test.go new file mode 100644 index 00000000..fad4ee7b --- /dev/null +++ b/examples/NilKnowledgeBasePanic_test.go @@ -0,0 +1,54 @@ +// Copyright hyperjumptech/grule-rule-engine Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package examples + +import ( + "testing" + + "github.com/hyperjumptech/grule-rule-engine/ast" + "github.com/hyperjumptech/grule-rule-engine/engine" + + "github.com/stretchr/testify/assert" +) + +func Test_NoPanicOnEmptyKnowledgeBase(t *testing.T) { + // create a new fact for user + user := &User{ + Name: "Calo", + Age: 0, + Male: true, + } + // create an empty data context + dataContext := ast.NewDataContext() + // add the fact struct to the data context + err := dataContext.Add("User", user) + if err != nil { + t.Fatal(err) + } + + t.Run("with nil knowledge base in execute", func(t *testing.T) { + eng := &engine.GruleEngine{MaxCycle: 10} + err = eng.Execute(dataContext, nil) + + assert.NotNil(t, err) + }) + + t.Run("with nil knowledge base in FetchMatchingRules", func(t *testing.T) { + eng := &engine.GruleEngine{MaxCycle: 10} + _, err = eng.FetchMatchingRules(dataContext, nil) + + assert.NotNil(t, err) + }) +}