diff --git a/README.md b/README.md
index 865f4d1..6eb50e4 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ A `Rule` constitutes of multiple Conditions and the rule triggers when all its c
A `Condition` is an expression involving one or more tuple types. When the expression evaluates to true, the condition passes. In order to optimize a Rule's evaluation, the Rule network needs to know of the TupleTypes and the properties of the TupleType which participate in the `Condition` evaluation. These are provided when constructing the condition and adding it to the rule.
-A `Action` is a function that is invoked each time that a matching combination of tuples are found that result in a `true` evaluation of all its conditions. Those matching tuples are passed to the action function.
+A `ActionService` can be either go-funtion or a flogo-activity, this gets invoked each time that a matching combination of tuples are found that result in a `true` evaluation of all its conditions. Those matching tuples are passed to the service.
A `RuleSession` is a handle to interact with the rules API. You can create and register multiple rule sessions. Rule sessions are silos for the data that they hold, they are similar to namespaces. Sharing objects/state across rule sessions is not supported.
@@ -70,7 +70,13 @@ Next create a `RuleSession` and add all the `Rule`s with their `Condition`s and
//// check for name "Bob" in n1
rule := ruleapi.NewRule("n1.name == Bob")
rule.AddCondition("c1", []string{"n1"}, checkForBob, nil)
- rule.SetAction(checkForBobAction)
+ serviceCfg := &config.ServiceDescriptor{
+ Name: "checkForBobAction",
+ Type: config.TypeServiceFunction,
+ Function: checkForBobAction,
+ }
+ aService, _ := ruleapi.NewActionService(serviceCfg)
+ rule.SetActionService(aService)
rule.SetContext("This is a test of context")
rs.AddRule(rule)
fmt.Printf("Rule added: [%s]\n", rule.GetName())
@@ -80,12 +86,17 @@ Next create a `RuleSession` and add all the `Rule`s with their `Condition`s and
rule2 := ruleapi.NewRule("n1.name == Bob && n1.name == n2.name")
rule2.AddCondition("c1", []string{"n1"}, checkForBob, nil)
rule2.AddCondition("c2", []string{"n1", "n2"}, checkSameNamesCondition, nil)
- rule2.SetAction(checkSameNamesAction)
+ serviceCfg2 := &config.ServiceDescriptor{
+ Name: "checkSameNamesAction",
+ Type: config.TypeServiceFunction,
+ Function: checkSameNamesAction,
+ }
+ aService2, _ := ruleapi.NewActionService(serviceCfg2)
+ rule2.SetActionService(aService2)
rs.AddRule(rule2)
fmt.Printf("Rule added: [%s]\n", rule2.GetName())
-
- //Finally, start the rule session before asserting tuples
- //Your startup function, if registered will be invoked here
+
+ //Start the rule session
rs.Start(nil)
Here we create and assert the actual `Tuple's` which will be evaluated against the `Rule's` `Condition's` defined above.
diff --git a/common/model/types.go b/common/model/types.go
index 3996c10..7229033 100644
--- a/common/model/types.go
+++ b/common/model/types.go
@@ -12,7 +12,7 @@ type Rule interface {
GetName() string
GetIdentifiers() []TupleType
GetConditions() []Condition
- GetActionFn() ActionFunction
+ GetActionService() ActionService
String() string
GetPriority() int
GetDeps() map[TupleType]map[string]bool
@@ -23,7 +23,7 @@ type Rule interface {
type MutableRule interface {
Rule
AddCondition(conditionName string, idrs []string, cFn ConditionEvaluator, ctx RuleContext) (err error)
- SetAction(actionFn ActionFunction)
+ SetActionService(actionService ActionService)
SetPriority(priority int)
SetContext(ctx RuleContext)
AddExprCondition(conditionName string, cExpr string, ctx RuleContext) error
@@ -86,6 +86,12 @@ type ConditionEvaluator func(string, string, map[TupleType]Tuple, RuleContext) b
//i.e part of the server side API
type ActionFunction func(context.Context, RuleSession, string, map[TupleType]Tuple, RuleContext)
+// ActionService action service
+type ActionService interface {
+ SetInput(input map[string]interface{})
+ Execute(context.Context, RuleSession, string, map[TupleType]Tuple, RuleContext) (done bool, err error)
+}
+
//StartupRSFunction is called once after creation of a RuleSession
type StartupRSFunction func(ctx context.Context, rs RuleSession, sessionCtx map[string]interface{}) (err error)
diff --git a/config/config.go b/config/config.go
index 85836be..61c4b25 100644
--- a/config/config.go
+++ b/config/config.go
@@ -3,31 +3,41 @@ package config
import (
"bytes"
"encoding/json"
+ "fmt"
"strconv"
"github.com/project-flogo/core/data/metadata"
"github.com/project-flogo/rules/common/model"
)
+const (
+ // TypeServiceFunction represents go function based rule service
+ TypeServiceFunction = "function"
+ // TypeServiceActivity represents flgo-activity based rule service
+ TypeServiceActivity = "activity"
+)
+
// RuleSessionDescriptor is a collection of rules to be loaded
type RuleActionDescriptor struct {
Name string `json:"name"`
IOMetadata *metadata.IOMetadata `json:"metadata"`
Rules []*RuleDescriptor `json:"rules"`
+ Services []*ServiceDescriptor `json:"services,omitempty"`
}
type RuleSessionDescriptor struct {
- Rules []*RuleDescriptor `json:"rules"`
+ Rules []*RuleDescriptor `json:"rules"`
+ Services []*ServiceDescriptor `json:"services,omitempty"`
}
// RuleDescriptor defines a rule
type RuleDescriptor struct {
- Name string
- Conditions []*ConditionDescriptor
- ActionFunc model.ActionFunction
- Priority int
- Identifiers []string
+ Name string
+ Conditions []*ConditionDescriptor
+ ActionService *ActionServiceDescriptor
+ Priority int
+ Identifiers []string
}
// ConditionDescriptor defines a condition in a rule
@@ -38,13 +48,30 @@ type ConditionDescriptor struct {
Expression string
}
+// ActionServiceDescriptor defines rule action service
+type ActionServiceDescriptor struct {
+ Service string `json:"service"`
+ Input map[string]interface{} `json:"input,omitempty"`
+}
+
+// ServiceDescriptor defines a functional target that may be invoked by a rule
+type ServiceDescriptor struct {
+ Name string
+ Description string
+ Type string
+ Function model.ActionFunction
+ Ref string
+ Settings map[string]interface{}
+}
+
+// UnmarshalJSON unmarshals JSON into struct RuleDescriptor
func (c *RuleDescriptor) UnmarshalJSON(d []byte) error {
ser := &struct {
- Name string `json:"name"`
- Conditions []*ConditionDescriptor `json:"conditions"`
- ActionFuncId string `json:"actionFunction"`
- Priority int `json:"priority"`
- Identifiers []string `json:"identifiers"`
+ Name string `json:"name"`
+ Conditions []*ConditionDescriptor `json:"conditions"`
+ ActionService *ActionServiceDescriptor `json:"actionService,omitempty"`
+ Priority int `json:"priority"`
+ Identifiers []string `json:"identifiers"`
}{}
if err := json.Unmarshal(d, ser); err != nil {
@@ -53,13 +80,14 @@ func (c *RuleDescriptor) UnmarshalJSON(d []byte) error {
c.Name = ser.Name
c.Conditions = ser.Conditions
- c.ActionFunc = GetActionFunction(ser.ActionFuncId)
+ c.ActionService = ser.ActionService
c.Priority = ser.Priority
c.Identifiers = ser.Identifiers
return nil
}
+// MarshalJSON returns JSON encoding of RuleDescriptor
func (c *RuleDescriptor) MarshalJSON() ([]byte, error) {
buffer := bytes.NewBufferString("{")
buffer.WriteString("\"name\":" + "\"" + c.Name + "\",")
@@ -82,13 +110,16 @@ func (c *RuleDescriptor) MarshalJSON() ([]byte, error) {
buffer.Truncate(buffer.Len() - 1)
buffer.WriteString("],")
- actionFunctionID := GetActionFunctionID(c.ActionFunc)
- buffer.WriteString("\"actionFunction\":\"" + actionFunctionID + "\",")
+ jsonActionService, err := json.Marshal(c.ActionService)
+ if err == nil {
+ buffer.WriteString("\"actionService\":" + string(jsonActionService) + ",")
+ }
buffer.WriteString("\"priority\":" + strconv.Itoa(c.Priority) + "}")
return buffer.Bytes(), nil
}
+// UnmarshalJSON unmarshals JSON into struct ConditionDescriptor
func (c *ConditionDescriptor) UnmarshalJSON(d []byte) error {
ser := &struct {
Name string `json:"name"`
@@ -109,6 +140,7 @@ func (c *ConditionDescriptor) UnmarshalJSON(d []byte) error {
return nil
}
+// MarshalJSON returns JSON encoding of ConditionDescriptor
func (c *ConditionDescriptor) MarshalJSON() ([]byte, error) {
buffer := bytes.NewBufferString("{")
buffer.WriteString("\"name\":" + "\"" + c.Name + "\",")
@@ -128,6 +160,58 @@ func (c *ConditionDescriptor) MarshalJSON() ([]byte, error) {
return buffer.Bytes(), nil
}
+// UnmarshalJSON unmarshals JSON into struct ServiceDescriptor
+func (sd *ServiceDescriptor) UnmarshalJSON(d []byte) error {
+ ser := &struct {
+ Name string `json:"name"`
+ Description string `json:"description,omitempty"`
+ Type string `json:"type"`
+ FunctionID string `json:"function,omitempty"`
+ Ref string `json:"ref"`
+ Settings map[string]interface{} `json:"settings,omitempty"`
+ }{}
+
+ if err := json.Unmarshal(d, ser); err != nil {
+ return err
+ }
+
+ sd.Name = ser.Name
+ sd.Description = ser.Description
+ if ser.Type == TypeServiceFunction || ser.Type == TypeServiceActivity {
+ sd.Type = ser.Type
+ } else {
+ return fmt.Errorf("unsupported type - '%s' is referenced in the service '%s'", ser.Type, ser.Name)
+ }
+ if ser.FunctionID != "" {
+ fn := GetActionFunction(ser.FunctionID)
+ if fn == nil {
+ return fmt.Errorf("function - '%s' not found", ser.FunctionID)
+ }
+ sd.Function = fn
+ }
+ sd.Ref = ser.Ref
+ sd.Settings = ser.Settings
+
+ return nil
+}
+
+// MarshalJSON returns JSON encoding of ServiceDescriptor
+func (sd *ServiceDescriptor) MarshalJSON() ([]byte, error) {
+ buffer := bytes.NewBufferString("{")
+ buffer.WriteString("\"name\":" + "\"" + sd.Name + "\",")
+ buffer.WriteString("\"description\":" + "\"" + sd.Description + "\",")
+ buffer.WriteString("\"type\":" + "\"" + sd.Type + "\",")
+ functionID := GetActionFunctionID(sd.Function)
+ buffer.WriteString("\"function\":" + "\"" + functionID + "\",")
+ buffer.WriteString("\"ref\":" + "\"" + sd.Ref + "\",")
+ jsonSettings, err := json.Marshal(sd.Settings)
+ if err == nil {
+ buffer.WriteString("\"settings\":" + string(jsonSettings) + "}")
+ }
+
+ return buffer.Bytes(), nil
+}
+
//metadata support
type DefinitionConfig struct {
Name string `json:"name"`
diff --git a/config/config_test.go b/config/config_test.go
index 983ff3e..ea42644 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -21,7 +21,9 @@ var testRuleSessionDescriptorJson = `{
"evaluator": "checkForBob"
}
],
- "actionFunction": "checkForBobAction"
+ "actionService": {
+ "service": "checkForBobService"
+ }
},
{
"name": "n1.name == Bob && n1.name == n2.name",
@@ -39,8 +41,24 @@ var testRuleSessionDescriptorJson = `{
"evaluator": "checkSameNamesCondition"
}
],
- "actionFunction": "checkSameNamesAction"
+ "actionService": {
+ "service": "checkSameNamesService"
+ }
}
+ ],
+ "services": [
+ {
+ "name": "checkForBobService",
+ "description": "service checkForBobService",
+ "type": "function",
+ "function": "checkForBobAction"
+ },
+ {
+ "name": "checkSameNamesService",
+ "description": "service checkSameNamesService",
+ "type": "function",
+ "function": "checkSameNamesAction"
+ }
]
}
`
@@ -59,35 +77,32 @@ func TestDeserialize(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, ruleSessionDescriptor.Rules)
assert.Equal(t, 2, len(ruleSessionDescriptor.Rules))
+ assert.Equal(t, 2, len(ruleSessionDescriptor.Services))
+ // rule-0
r1Cfg := ruleSessionDescriptor.Rules[0]
assert.Equal(t, "n1.name == Bob", r1Cfg.Name)
assert.NotNil(t, r1Cfg.Conditions)
assert.Equal(t, 1, len(r1Cfg.Conditions))
-
- sf1 := reflect.ValueOf(checkForBobAction)
- sf2 := reflect.ValueOf(r1Cfg.ActionFunc)
- assert.Equal(t, sf1.Pointer(), sf2.Pointer())
+ assert.Equal(t, "checkForBobService", r1Cfg.ActionService.Service)
r1c1Cfg := r1Cfg.Conditions[0]
assert.Equal(t, "c1", r1c1Cfg.Name)
assert.NotNil(t, r1c1Cfg.Identifiers)
assert.Equal(t, 1, len(r1c1Cfg.Identifiers))
- sf1 = reflect.ValueOf(checkForBob)
- sf2 = reflect.ValueOf(r1c1Cfg.Evaluator)
+ sf1 := reflect.ValueOf(checkForBob)
+ sf2 := reflect.ValueOf(r1c1Cfg.Evaluator)
assert.Equal(t, sf1.Pointer(), sf2.Pointer())
+ // rule-1
r2Cfg := ruleSessionDescriptor.Rules[1]
assert.Equal(t, "n1.name == Bob && n1.name == n2.name", r2Cfg.Name)
assert.NotNil(t, r2Cfg.Conditions)
assert.Equal(t, 2, len(r2Cfg.Conditions))
-
- sf1 = reflect.ValueOf(checkSameNamesAction)
- sf2 = reflect.ValueOf(r2Cfg.ActionFunc)
- assert.Equal(t, sf1.Pointer(), sf2.Pointer())
+ assert.Equal(t, "checkSameNamesService", r2Cfg.ActionService.Service)
r2c1Cfg := r2Cfg.Conditions[0]
assert.Equal(t, "c1", r2c1Cfg.Name)
@@ -106,6 +121,22 @@ func TestDeserialize(t *testing.T) {
sf1 = reflect.ValueOf(checkSameNamesCondition)
sf2 = reflect.ValueOf(r2c2Cfg.Evaluator)
assert.Equal(t, sf1.Pointer(), sf2.Pointer())
+
+ // service-0
+ s1Cfg := ruleSessionDescriptor.Services[0]
+ assert.Equal(t, "checkForBobService", s1Cfg.Name)
+ assert.Equal(t, "service checkForBobService", s1Cfg.Description)
+ sf1 = reflect.ValueOf(checkForBobAction)
+ sf2 = reflect.ValueOf(s1Cfg.Function)
+ assert.Equal(t, sf1.Pointer(), sf2.Pointer())
+
+ // service-1
+ s2Cfg := ruleSessionDescriptor.Services[1]
+ assert.Equal(t, "checkSameNamesService", s2Cfg.Name)
+ assert.Equal(t, "service checkSameNamesService", s2Cfg.Description)
+ sf1 = reflect.ValueOf(checkSameNamesAction)
+ sf2 = reflect.ValueOf(s2Cfg.Function)
+ assert.Equal(t, sf1.Pointer(), sf2.Pointer())
}
// TEST FUNCTIONS
diff --git a/config/manager.go b/config/manager.go
index 25d43be..2a99ec2 100644
--- a/config/manager.go
+++ b/config/manager.go
@@ -43,7 +43,8 @@ func (m *ResourceManager) GetResource(id string) interface{} {
func (m *ResourceManager) GetRuleSessionDescriptor(uri string) (*RuleSessionDescriptor, error) {
if strings.HasPrefix(uri, uriSchemeRes) {
- return &RuleSessionDescriptor{m.configs[uri[len(uriSchemeRes):]].Rules}, nil
+ id := uri[len(uriSchemeRes):]
+ return &RuleSessionDescriptor{Rules: m.configs[id].Rules, Services: m.configs[id].Services}, nil
}
return nil, errors.New("cannot find RuleSession: " + uri)
diff --git a/examples/flogo/creditcard/creditcard_test.go b/examples/flogo/creditcard/creditcard_test.go
new file mode 100644
index 0000000..f666b52
--- /dev/null
+++ b/examples/flogo/creditcard/creditcard_test.go
@@ -0,0 +1,54 @@
+package main
+
+import (
+ "bytes"
+ "io/ioutil"
+ "net/http"
+ "path/filepath"
+ "testing"
+
+ "github.com/project-flogo/core/engine"
+ "github.com/project-flogo/rules/ruleapi/tests"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCreditCard(t *testing.T) {
+
+ data, err := ioutil.ReadFile(filepath.FromSlash("flogo.json"))
+ assert.Nil(t, err)
+ cfg, err := engine.LoadAppConfig(string(data), false)
+ assert.Nil(t, err)
+ e, err := engine.New(cfg)
+ assert.Nil(t, err)
+ tests.Drain("7777")
+ err = e.Start()
+ assert.Nil(t, err)
+ defer func() {
+ err := e.Stop()
+ assert.Nil(t, err)
+ }()
+ tests.Pour("7777")
+
+ client := &http.Client{}
+ request := func() {
+ req, err := http.NewRequest("PUT", "http://localhost:7777/newaccount", bytes.NewBuffer([]byte(`{"Name":"Test","Age":"26","Income":"60100","Address":"TEt","Id":"12312","Gender":"male","maritalStatus":"single"}`)))
+ req.Header.Set("Content-Type", "application/json")
+ response, err := client.Do(req)
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output := tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "Rule fired: NewUser")
+
+ request = func() {
+ req, err := http.NewRequest("PUT", "http://localhost:7777/credit", bytes.NewBuffer([]byte(`{"Id":12312,"creditScore":680}`)))
+ req.Header.Set("Content-Type", "application/json")
+ response, err := client.Do(req)
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output = tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "Rule fired: Rejected")
+
+}
diff --git a/examples/flogo/creditcard/flogo.json b/examples/flogo/creditcard/flogo.json
index 30f4b90..5c02b5c 100644
--- a/examples/flogo/creditcard/flogo.json
+++ b/examples/flogo/creditcard/flogo.json
@@ -83,7 +83,9 @@
"evaluator": "cBadUser"
}
],
- "actionFunction": "aBadUser"
+ "actionService": {
+ "service": "FunctionService"
+ }
},
{
"name": "NewUser",
@@ -96,7 +98,9 @@
"evaluator": "cNewUser"
}
],
- "actionFunction": "aNewUser"
+ "actionService": {
+ "service": "FunctionService1"
+ }
},
{
"name": "NewUser1",
@@ -117,7 +121,9 @@
"evaluator": "cUserCreditScore"
}
],
- "actionFunction": "aApproveWithLowerLimit"
+ "actionService": {
+ "service": "FunctionService2"
+ }
},
{
"name": "NewUser2",
@@ -138,7 +144,9 @@
"evaluator": "cUserHighCreditScore"
}
],
- "actionFunction": "aApproveWithHigherLimit"
+ "actionService": {
+ "service": "FunctionService3"
+ }
},
{
"name": "Rejected",
@@ -159,7 +167,41 @@
"evaluator": "cUserLowCreditScore"
}
],
- "actionFunction": "aUserReject"
+ "actionService": {
+ "service": "FunctionService4"
+ }
+ }
+ ],
+ "services": [
+ {
+ "name": "FunctionService",
+ "description": "function service for aBadUser",
+ "type": "function",
+ "function": "aBadUser"
+ },
+ {
+ "name": "FunctionService1",
+ "description": "function service for aNewUser",
+ "type": "function",
+ "function": "aNewUser"
+ },
+ {
+ "name": "FunctionService2",
+ "description": "function service for aApproveWithLowerLimit",
+ "type": "function",
+ "function": "aApproveWithLowerLimit"
+ },
+ {
+ "name": "FunctionService3",
+ "description": "function service for aApproveWithHigherLimit",
+ "type": "function",
+ "function": "aApproveWithHigherLimit"
+ },
+ {
+ "name": "FunctionService4",
+ "description": "function service for aUserReject",
+ "type": "function",
+ "function": "aUserReject"
}
]
}
diff --git a/examples/flogo/creditcard/sanity.sh b/examples/flogo/creditcard/sanity.sh
deleted file mode 100644
index 74e2bb5..0000000
--- a/examples/flogo/creditcard/sanity.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/bash
-
-function get_test_cases {
- local my_list=( testcase1 testcase2 testcase3 )
- echo "${my_list[@]}"
-}
-
-# Test cases performs credit card application status as approved if Creditscore > 750
-function testcase1 {
-pushd $GOPATH/src/github.com/project-flogo/rules/examples/flogo/creditcard
-go build
-./creditcard > /tmp/testcase1.log 2>&1 &
-pId=$!
-
-response=$(curl -X PUT http://localhost:7777/newaccount -H 'Content-Type: application/json' -d '{"Name":"Sam4","Age":"26","Income":"50100","Address":"SFO","Id":"4"}' --write-out '%{http_code}' --silent --output /dev/null)
-response1=$(curl -X PUT http://localhost:7777/credit -H 'Content-Type: application/json' -d '{"Id":"4","creditScore":"850"}' --write-out '%{http_code}' --silent --output /dev/null)
-kill -9 $pId
-
-if [ $response -eq 200 ] && [ $response1 -eq 200 ] && [[ "echo $(cat /tmp/testcase1.log)" =~ "Rule fired" ]]
- then
- echo "PASS"
- else
- echo "FAIL"
-fi
-cd ..
-rm -rf /tmp/testcase1.log
-popd
-}
-
-# Test cases performs credit card application status rejected if Creditscore < 750
-function testcase2 {
-pushd $GOPATH/src/github.com/project-flogo/rules/examples/flogo/creditcard
-go build
-./creditcard > /tmp/testcase2.log 2>&1 &
-pId=$!
-
-response=$(curl -X PUT http://localhost:7777/newaccount -H 'Content-Type: application/json' -d '{"Name":"Sam4","Age":"26","Income":"50100","Address":"SFO","Id":"5"}' --write-out '%{http_code}' --silent --output /dev/null)
-response1=$(curl -X PUT http://localhost:7777/credit -H 'Content-Type: application/json' -d '{"Id":"5","creditScore":"650"}' --write-out '%{http_code}' --silent --output /dev/null)
-
-kill -9 $pId
-if [ $response -eq 200 ] && [ $response1 -eq 200 ] && [[ "echo $(cat /tmp/testcase2.log)" =~ "c" ]]
- then
- echo "PASS"
- else
- echo "FAIL"
-fi
-cd ..
-rm -rf /tmp/testcase2.log
-popd
-}
-
-
-# Test cases performs invalid applicant when age address or income data is not matching requirements
-function testcase3 {
-pushd $GOPATH/src/github.com/project-flogo/rules/examples/flogo/creditcard
-go build
-./creditcard > /tmp/testcase3.log 2>&1 &
-pId=$!
-
-response=$(curl -X PUT http://localhost:7777/newaccount -H 'Content-Type: application/json' -d '{"Name":"Sam4","Age":"26","Income":"5010","Address":"SFO","Id":"6"}' --write-out '%{http_code}' --silent --output /dev/null)
-
-kill -9 $pId
-if [ $response -eq 200 ] && [[ "echo $(cat /tmp/testcase3.log)" =~ "Applicant is not eligible to apply for creditcard" ]]
- then
- echo "PASS"
- else
- echo "FAIL"
-fi
-cd ..
-rm -rf /tmp/testcase3.log
-popd
-}
diff --git a/examples/flogo/invokeservice/README.md b/examples/flogo/invokeservice/README.md
new file mode 100644
index 0000000..4671338
--- /dev/null
+++ b/examples/flogo/invokeservice/README.md
@@ -0,0 +1,36 @@
+# Invoke Rule Service
+
+This example demonstrates how a rule can invoke a rule `service`. A rule `service` is a `go-function` or a `flogo-activity`.
+
+## Setup and build
+Once you have the `flogo.json` file and a `functions.go` file, you are ready to build your Flogo App
+
+### Steps
+
+```sh
+cd $GOPATH/src/github.com/project-flogo/rules/examples/flogo/invokeservice
+flogo create -f flogo.json invokeservice
+cp functions.go ./invokeservice/src
+cd invokeservice
+flogo build
+cd bin
+./invokeservice
+```
+### Testing
+
+#### #1 Invoke go-function based service
+
+Send a curl request
+`curl http://localhost:7777/test/n1?name=function`
+You should see following output:
+```
+Rule[n1.name == function] fired. serviceFunctionAction() function got invoked.
+```
+
+#### #2 Invoke flogo-activity based service
+Send a curl request
+`curl http://localhost:7777/test/n1?name=activity`
+You should see following output:
+```
+2019-08-19T20:11:11.068+0530 INFO [flogo.test] - activity
+```
\ No newline at end of file
diff --git a/examples/flogo/invokeservice/flogo.json b/examples/flogo/invokeservice/flogo.json
new file mode 100644
index 0000000..bba18e9
--- /dev/null
+++ b/examples/flogo/invokeservice/flogo.json
@@ -0,0 +1,175 @@
+{
+ "name": "invokeservice",
+ "type": "flogo:app",
+ "version": "0.0.1",
+ "description": "Sample Flogo App",
+ "appModel": "1.0.0",
+ "imports": [
+ "github.com/project-flogo/contrib/trigger/rest",
+ "github.com/project-flogo/rules/ruleaction@feature-invoke-activity",
+ "github.com/project-flogo/contrib/activity/log",
+ "github.com/project-flogo/flow"
+ ],
+ "triggers": [
+ {
+ "id": "receive_http_message",
+ "ref": "github.com/project-flogo/contrib/trigger/rest",
+ "settings": {
+ "port": "7777"
+ },
+ "handlers": [
+ {
+ "settings": {
+ "method": "GET",
+ "path": "/test/n1"
+ },
+ "actions": [
+ {
+ "id": "simple_rule",
+ "input": {
+ "tupletype": "n1",
+ "values": "=$.queryParams"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "resources": [
+ {
+ "id": "rulesession:simple",
+ "data": {
+ "metadata": {
+ "input": [
+ {
+ "name": "values",
+ "type": "string"
+ },
+ {
+ "name": "tupletype",
+ "type": "string"
+ }
+ ],
+ "output": [
+ {
+ "name": "outputData",
+ "type": "any"
+ }
+ ]
+ },
+ "rules": [
+ {
+ "name": "n1.name == function",
+ "conditions": [
+ {
+ "name": "c1",
+ "identifiers": [
+ "n1"
+ ],
+ "evaluator": "cServiceFunction"
+ }
+ ],
+ "actionService": {
+ "service": "ServiceFunction",
+ "input": {
+ "message": "=$.n1.name"
+ }
+ }
+ },
+ {
+ "name": "n1.name == activity",
+ "conditions": [
+ {
+ "name": "c1",
+ "identifiers": [
+ "n1"
+ ],
+ "evaluator": "cServiceActivity"
+ }
+ ],
+ "actionService": {
+ "service": "ServiceLogActivity",
+ "input": {
+ "message": "=$.n1.name"
+ }
+ }
+ }
+ ],
+ "services": [
+ {
+ "name": "ServiceFunction",
+ "description": "function service",
+ "type": "function",
+ "function": "serviceFunctionAction"
+ },
+ {
+ "name": "ServiceLogActivity",
+ "description": "log activity service",
+ "type": "activity",
+ "ref": "github.com/project-flogo/contrib/activity/log"
+ }
+ ]
+ }
+ },
+ {
+ "id": "flow:sample_flow",
+ "data": {
+ "name": "SampleFlow",
+ "metadata": {
+ "input": [
+ {
+ "name": "message",
+ "type": "string"
+ }
+ ]
+ },
+ "tasks": [
+ {
+ "id": "log_message",
+ "name": "Log Message",
+ "description": "Simple Log Activity",
+ "activity": {
+ "ref": "#log",
+ "input": {
+ "message": "=$flow.message"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ],
+ "actions": [
+ {
+ "ref": "github.com/project-flogo/rules/ruleaction",
+ "settings": {
+ "ruleSessionURI": "res://rulesession:simple",
+ "tds": [
+ {
+ "name": "n1",
+ "properties": [
+ {
+ "name": "name",
+ "pk-index": 0,
+ "type": "string"
+ }
+ ],
+ "ttl": 0
+ },
+ {
+ "name": "n2",
+ "properties": [
+ {
+ "name": "name",
+ "pk-index": 0,
+ "type": "string"
+ }
+ ]
+ }
+ ]
+ },
+ "id": "simple_rule"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/flogo/invokeservice/functions.go b/examples/flogo/invokeservice/functions.go
new file mode 100644
index 0000000..b6de0ce
--- /dev/null
+++ b/examples/flogo/invokeservice/functions.go
@@ -0,0 +1,83 @@
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/project-flogo/rules/config"
+
+ "github.com/project-flogo/rules/common/model"
+)
+
+//add this sample file to your flogo project
+func init() {
+ config.RegisterActionFunction("serviceFunctionAction", serviceFunctionAction)
+
+ config.RegisterConditionEvaluator("cServiceFunction", cServiceFunction)
+ config.RegisterConditionEvaluator("cServiceActivity", cServiceActivity)
+
+ config.RegisterStartupRSFunction("simple", StartupRSFunction)
+}
+
+func cServiceFunction(ruleName string, condName string, tuples map[model.TupleType]model.Tuple, ctx model.RuleContext) bool {
+ t1 := tuples["n1"]
+ if t1 == nil {
+ fmt.Println("Should not get a nil tuple in FilterCondition! This is an error")
+ return false
+ }
+ name, _ := t1.GetString("name")
+ return name == "function"
+}
+
+func cServiceActivity(ruleName string, condName string, tuples map[model.TupleType]model.Tuple, ctx model.RuleContext) bool {
+ t1 := tuples["n1"]
+ if t1 == nil {
+ fmt.Println("Should not get a nil tuple in FilterCondition! This is an error")
+ return false
+ }
+ name, _ := t1.GetString("name")
+ return name == "activity"
+}
+
+func serviceFunctionAction(ctx context.Context, rs model.RuleSession, ruleName string, tuples map[model.TupleType]model.Tuple, ruleCtx model.RuleContext) {
+ fmt.Printf("Rule[%s] fired. serviceFunctionAction() function got invoked. \n", ruleName)
+ t1 := tuples["n1"]
+ if t1 == nil {
+ fmt.Println("Should not get nil tuples here in JoinCondition! This is an error")
+ return
+ }
+}
+
+func checkSameNamesCondition(ruleName string, condName string, tuples map[model.TupleType]model.Tuple, ctx model.RuleContext) bool {
+ t1 := tuples["n1"]
+ t2 := tuples["n2"]
+ if t1 == nil || t2 == nil {
+ fmt.Println("Should not get nil tuples here in JoinCondition! This is an error")
+ return false
+ }
+ name1, _ := t1.GetString("name")
+ name2, _ := t2.GetString("name")
+ return name1 == name2
+}
+
+func checkSameNamesAction(ctx context.Context, rs model.RuleSession, ruleName string, tuples map[model.TupleType]model.Tuple, ruleCtx model.RuleContext) {
+ fmt.Printf("Rule fired: [%s]\n", ruleName)
+ t1 := tuples["n1"]
+ t2 := tuples["n2"]
+ if t1 == nil || t2 == nil {
+ fmt.Println("Should not get nil tuples here in Action! This is an error")
+ return
+ }
+ name1, _ := t1.GetString("name")
+ name2, _ := t2.GetString("name")
+ fmt.Printf("n1.name = [%s], n2.name = [%s]\n", name1, name2)
+}
+
+func StartupRSFunction(ctx context.Context, rs model.RuleSession, startupCtx map[string]interface{}) (err error) {
+
+ fmt.Printf("In startup rule function..\n")
+ t3, _ := model.NewTupleWithKeyValues("n1", "Bob")
+ t3.SetString(nil, "name", "Bob")
+ rs.Assert(nil, t3)
+ return nil
+}
diff --git a/examples/flogo/invokeservice/imports.go b/examples/flogo/invokeservice/imports.go
new file mode 100644
index 0000000..fd7980d
--- /dev/null
+++ b/examples/flogo/invokeservice/imports.go
@@ -0,0 +1,8 @@
+package main
+
+import (
+ _ "github.com/project-flogo/contrib/activity/log"
+ _ "github.com/project-flogo/contrib/trigger/rest"
+ _ "github.com/project-flogo/flow"
+ _ "github.com/project-flogo/rules/ruleaction"
+)
diff --git a/examples/flogo/invokeservice/invokeservice_test.go b/examples/flogo/invokeservice/invokeservice_test.go
new file mode 100644
index 0000000..775bfe9
--- /dev/null
+++ b/examples/flogo/invokeservice/invokeservice_test.go
@@ -0,0 +1,49 @@
+package main
+
+import (
+ "io/ioutil"
+ "net/http"
+ "path/filepath"
+ "testing"
+
+ "github.com/project-flogo/core/engine"
+ "github.com/project-flogo/rules/ruleapi/tests"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestInvokeService(t *testing.T) {
+
+ data, err := ioutil.ReadFile(filepath.FromSlash("flogo.json"))
+ assert.Nil(t, err)
+ cfg, err := engine.LoadAppConfig(string(data), false)
+ assert.Nil(t, err)
+ e, err := engine.New(cfg)
+ assert.Nil(t, err)
+ tests.Drain("7777")
+ err = e.Start()
+ assert.Nil(t, err)
+ defer func() {
+ err := e.Stop()
+ assert.Nil(t, err)
+ }()
+ tests.Pour("7777")
+
+ client := &http.Client{}
+ request := func() {
+ response, err := client.Get("http://localhost:7777/test/n1?name=function")
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output := tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "Rule[n1.name == function] fired. serviceFunctionAction() function got invoked.")
+
+ request = func() {
+ response, err := client.Get("http://localhost:7777/test/n1?name=activity")
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output = tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "")
+
+}
diff --git a/examples/flogo/invokeservice/main.go b/examples/flogo/invokeservice/main.go
new file mode 100644
index 0000000..b0ed757
--- /dev/null
+++ b/examples/flogo/invokeservice/main.go
@@ -0,0 +1,74 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "runtime"
+ "runtime/pprof"
+
+ _ "github.com/project-flogo/core/data/expression/script"
+ "github.com/project-flogo/core/engine"
+)
+
+var (
+ cpuProfile = flag.String("cpuprofile", "", "Writes CPU profile to the specified file")
+ memProfile = flag.String("memprofile", "", "Writes memory profile to the specified file")
+ cfgJson string
+ cfgEngine string
+ cfgCompressed bool
+)
+
+func main() {
+
+ cpuProfiling := false
+
+ flag.Parse()
+ if *cpuProfile != "" {
+ f, err := os.Create(*cpuProfile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to create CPU profiling file: %v\n", err)
+ os.Exit(1)
+ }
+ if err = pprof.StartCPUProfile(f); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to start CPU profiling: %v\n", err)
+ os.Exit(1)
+ }
+ cpuProfiling = true
+ }
+
+ cfg, err := engine.LoadAppConfig(cfgJson, cfgCompressed)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to create engine: %v\n", err)
+ os.Exit(1)
+ }
+
+ e, err := engine.New(cfg, engine.ConfigOption(cfgEngine, cfgCompressed))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to create engine: %v\n", err)
+ os.Exit(1)
+ }
+
+ code := engine.RunEngine(e)
+
+ if *memProfile != "" {
+ f, err := os.Create(*memProfile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to create memory profiling file: %v\n", err)
+ os.Exit(1)
+ }
+
+ runtime.GC() // get up-to-date statistics
+ if err := pprof.WriteHeapProfile(f); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to write memory profiling data: %v", err)
+ os.Exit(1)
+ }
+ _ = f.Close()
+ }
+
+ if cpuProfiling {
+ pprof.StopCPUProfile()
+ }
+
+ os.Exit(code)
+}
diff --git a/examples/flogo/simple-kafka/docker-compose.yaml b/examples/flogo/simple-kafka/docker-compose.yaml
new file mode 100644
index 0000000..eacafc7
--- /dev/null
+++ b/examples/flogo/simple-kafka/docker-compose.yaml
@@ -0,0 +1,19 @@
+version: '2'
+
+services:
+
+ zookeeper:
+ image: wurstmeister/zookeeper:3.4.6
+ expose:
+ - "2181"
+
+ kafka:
+ image: wurstmeister/kafka:2.11-2.0.0
+ depends_on:
+ - zookeeper
+ ports:
+ - "9092:9092"
+ environment:
+ KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
+ KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
+ KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
\ No newline at end of file
diff --git a/examples/flogo/simple-kafka/flogo.json b/examples/flogo/simple-kafka/flogo.json
index 5786d21..c4a4883 100644
--- a/examples/flogo/simple-kafka/flogo.json
+++ b/examples/flogo/simple-kafka/flogo.json
@@ -105,7 +105,9 @@
"evaluator": "checkForGrocery"
}
],
- "actionFunction": "groceryAction"
+ "actionService": {
+ "service": "FunctionService"
+ }
},
{
"name": "furnitureCheckRule",
@@ -118,7 +120,23 @@
"evaluator": "checkForFurniture"
}
],
- "actionFunction": "furnitureAction"
+ "actionService": {
+ "service": "FunctionService1"
+ }
+ }
+ ],
+ "services": [
+ {
+ "name": "FunctionService",
+ "description": "function service for groceryAction",
+ "type": "function",
+ "function": "groceryAction"
+ },
+ {
+ "name": "FunctionService1",
+ "description": "function service",
+ "type": "function",
+ "function": "furnitureAction"
}
]
}
diff --git a/examples/flogo/simple-kafka/simple-kafka_test.go b/examples/flogo/simple-kafka/simple-kafka_test.go
new file mode 100644
index 0000000..fab9dbe
--- /dev/null
+++ b/examples/flogo/simple-kafka/simple-kafka_test.go
@@ -0,0 +1,104 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/Shopify/sarama"
+ "github.com/project-flogo/core/engine"
+ "github.com/project-flogo/rules/ruleapi/tests"
+ "github.com/stretchr/testify/assert"
+)
+
+const (
+ kafkaConn = "localhost:9092"
+ topic = "orderinfo"
+)
+
+func initProducer() (sarama.SyncProducer, error) {
+
+ // producer config
+ config := sarama.NewConfig()
+ config.Producer.Retry.Max = 5
+ config.Producer.RequiredAcks = sarama.WaitForAll
+ config.Producer.Return.Successes = true
+
+ // sync producer
+ prd, err := sarama.NewSyncProducer([]string{kafkaConn}, config)
+
+ return prd, err
+}
+
+func publish(message string, producer sarama.SyncProducer) {
+ // publish sync
+ msg := &sarama.ProducerMessage{
+ Topic: topic,
+ Value: sarama.StringEncoder(message),
+ }
+ p, o, err := producer.SendMessage(msg)
+ if err != nil {
+ fmt.Println("Error publish: ", err.Error())
+ }
+
+ fmt.Println("Partition: ", p)
+ fmt.Println("Offset: ", o)
+}
+
+func testApplication(t *testing.T, e engine.Engine) {
+ err := e.Start()
+ assert.Nil(t, err)
+ defer func() {
+ err := e.Stop()
+ assert.Nil(t, err)
+ tests.Command("docker-compose", "down")
+ }()
+ tests.Pour("9092")
+
+ producer, err := initProducer()
+ if err != nil {
+ fmt.Println("Error producer: ", err.Error())
+ os.Exit(1)
+ }
+
+ request := func() {
+ publish(`{"type":"grocery","totalPrice":"2001.0"}`, producer)
+ }
+ outpt := tests.CaptureStdOutput(request)
+
+ var result string
+ if strings.Contains(outpt, "Rule fired") {
+ result = "success"
+ }
+ assert.Equal(t, "success", result)
+ outpt = ""
+ result = ""
+
+}
+
+func TestSimpleKafkaJSON(t *testing.T) {
+
+ if testing.Short() {
+ t.Skip("skipping simpleKafkaJSON test")
+ }
+
+ _, err := exec.LookPath("docker-compose")
+ if err != nil {
+ t.Skip("skipping test - docker-compose not found")
+ }
+
+ data, err := ioutil.ReadFile(filepath.FromSlash("flogo.json"))
+ assert.Nil(t, err)
+ tests.Command("docker-compose", "up", "-d")
+ time.Sleep(50 * time.Second)
+ cfg, err := engine.LoadAppConfig(string(data), false)
+ assert.Nil(t, err)
+ e, err := engine.New(cfg)
+ assert.Nil(t, err)
+ testApplication(t, e)
+}
diff --git a/examples/flogo/simple/README.md b/examples/flogo/simple/README.md
index f362379..7a4a3ce 100644
--- a/examples/flogo/simple/README.md
+++ b/examples/flogo/simple/README.md
@@ -15,13 +15,24 @@
## Steps to configure and build a Rules based Flogo App
Below is the `flogo.json` file used in this example application. We will use this example to explain the configuration and setup of a Flogo/Rules App
-```
+```json
{
"name": "simplerules",
"type": "flogo:app",
"version": "0.0.1",
"description": "Sample Flogo App",
"appModel": "1.0.0",
+ "imports": [
+ "github.com/project-flogo/contrib/trigger/rest",
+ "github.com/project-flogo/rules/ruleaction"
+ ],
+ "properties": [
+ {
+ "name": "name",
+ "type": "string",
+ "value": "testprop"
+ }
+ ],
"triggers": [
{
"id": "receive_http_message",
@@ -30,31 +41,16 @@ Below is the `flogo.json` file used in this example application. We will use thi
"port": "7777"
},
"handlers": [
- {
- "settings": {
- "method": "GET",
- "path": "/test/n1"
- },
- "actions": [
- {
- "id": "simple_rule",
- "input": {
- "tupletype": "n1",
- "values": "=$.queryParams"
- }
- }
- ]
- },
{
"settings": {
"method": "GET",
- "path": "/test/n2"
+ "path": "/test/:tupleType"
},
"actions": [
{
"id": "simple_rule",
"input": {
- "tupletype": "n2",
+ "tupletype": "=$.pathParams.tupleType",
"values": "=$.queryParams"
}
}
@@ -110,10 +106,10 @@ Below is the `flogo.json` file used in this example application. We will use thi
}
],
"output": [
- {
- "name": "outputData",
- "type": "any"
- }
+ {
+ "name": "outputData",
+ "type": "any"
+ }
]
},
"rules": [
@@ -121,41 +117,49 @@ Below is the `flogo.json` file used in this example application. We will use thi
"name": "n1.name == Bob",
"conditions": [
{
- "name": "c1",
- "identifiers": [
- "n1"
- ],
- "evaluator": "checkForBob"
+ "expression" : "$.n1.name == 'Bob'"
}
],
- "actionFunction": "checkForBobAction"
+ "actionService": {
+ "service": "FunctionService"
+ }
},
{
"name": "n1.name == Bob \u0026\u0026 n1.name == n2.name",
"conditions": [
{
- "name": "c1",
"identifiers": [
"n1"
],
"evaluator": "checkForBob"
},
{
- "name": "c2",
- "identifiers": [
- "n1",
- "n2"
- ],
- "evaluator": "checkSameNamesCondition"
+ "expression" : "($.n1.name == 'Bob') \u0026\u0026 ($.n1.name == $.n2.name)"
}
],
- "actionFunction": "checkSameNamesAction"
+ "actionService": {
+ "service": "FunctionService1"
+ }
+ }
+ ],
+ "services": [
+ {
+ "name": "FunctionService",
+ "description": "function service for checkForBobAction",
+ "type": "function",
+ "function": "checkForBobAction"
+ },
+ {
+ "name": "FunctionService1",
+ "description": "function service for checkSameNamesAction",
+ "type": "function",
+ "function": "checkSameNamesAction"
}
]
}
}
]
-}
+}
```
## Action configuration
First configure the top level `actions` section. Here, the tags `id`, `ruleSessionURI` and `tds` are user configurable.
@@ -179,8 +183,9 @@ under `identifiers`. These identifiers should be one of `tds/names` defined in t
be an unique string. This string will bind to a Go function at runtime (explained later)
Note how you can have multiple conditions (See the second condition in the example above)
-The `actionFunction` is your rule's action. It means that when the `evaluator` condition is met, invoke this function
-Again, this is a unique string whose value binds to a Go function at runtime (explained later)
+The `actionService` is your rule's action. It means that when the `evaluator` condition is met, this service
+gets invoked which will call either a go-funtion or flogo-activity as defined under the `service` section.
+In this example if `checkForBob` and expression `($.n1.name == 'Bob') \u0026\u0026 ($.n1.name == $.n2.name)` are true then service named `FunctionService` gets invoked (i.e go-function named `checkForBobAction`).
## Configure the trigger handler
Flogo users are perhaps already familiar with the trigger configurations.
@@ -216,6 +221,8 @@ corresponding string tokens defined in the `resources/rules/conditions/evaluator
func init() {
config.RegisterActionFunction("checkForBobAction", checkForBobAction)
config.RegisterActionFunction("checkSameNamesAction", checkSameNamesAction)
+ config.RegisterActionFunction("envVarExampleAction", envVarExampleAction)
+ config.RegisterActionFunction("propertyExampleAction", propertyExampleAction)
config.RegisterConditionEvaluator("checkForBob", checkForBob)
config.RegisterConditionEvaluator("checkSameNamesCondition", checkSameNamesCondition)
diff --git a/examples/flogo/simple/flogo.json b/examples/flogo/simple/flogo.json
index e845683..8682e11 100644
--- a/examples/flogo/simple/flogo.json
+++ b/examples/flogo/simple/flogo.json
@@ -102,7 +102,9 @@
"expression" : "$.n1.name == 'Bob'"
}
],
- "actionFunction": "checkForBobAction"
+ "actionService": {
+ "service": "FunctionService"
+ }
},
{
"name": "n1.name == Bob \u0026\u0026 n1.name == n2.name",
@@ -117,16 +119,20 @@
"expression" : "($.n1.name == 'Bob') \u0026\u0026 ($.n1.name == $.n2.name)"
}
],
- "actionFunction": "checkSameNamesAction"
+ "actionService": {
+ "service": "FunctionService1"
+ }
},
{
"name": "env variable example",
"conditions": [
{
- "expression" : "($.n1.name == $env['name'])"
+ "expression" : "($.n1.name == $env['simpleappname'])"
}
],
- "actionFunction": "envVarExampleAction"
+ "actionService": {
+ "service": "envVarExampleAction"
+ }
},
{
"name": "flogo property example",
@@ -138,7 +144,35 @@
"expression" : "($.n1.name == $property['name'])"
}
],
- "actionFunction": "propertyExampleAction"
+ "actionService": {
+ "service": "propertyExampleAction"
+ }
+ }
+ ],
+ "services": [
+ {
+ "name": "FunctionService",
+ "description": "function service for checkForBobAction",
+ "type": "function",
+ "function": "checkForBobAction"
+ },
+ {
+ "name": "FunctionService1",
+ "description": "function service for checkSameNamesAction",
+ "type": "function",
+ "function": "checkSameNamesAction"
+ },
+ {
+ "name": "envVarExampleAction",
+ "description": "function service for envVarExampleAction",
+ "type": "function",
+ "function": "envVarExampleAction"
+ },
+ {
+ "name": "propertyExampleAction",
+ "description": "function service for propertyExampleAction",
+ "type": "function",
+ "function": "propertyExampleAction"
}
]
}
diff --git a/examples/flogo/simple/sanity.sh b/examples/flogo/simple/sanity.sh
deleted file mode 100755
index b43527e..0000000
--- a/examples/flogo/simple/sanity.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-function get_test_cases {
- local my_list=( testcase1 )
- echo "${my_list[@]}"
-}
-
-# This Testcase creates flogo rules binary and checks for name bob
-function testcase1 {
-pushd $GOPATH/src/github.com/project-flogo/rules/examples/flogo/simple
-flogo create -f flogo.json
-cp functions.go simplerules/src
-cd simplerules
-flogo build
-./bin/simplerules > /tmp/testcase1.log 2>&1 &
-pId=$!
-
-response=$(curl --request GET localhost:7777/test/n1?name=Bob --write-out '%{http_code}' --silent --output /dev/null)
-response1=$(curl --request GET localhost:7777/test/n2?name=Bob --write-out '%{http_code}' --silent --output /dev/null)
-
-kill -9 $pId
-if [ $response -eq 200 ] && [ $response1 -eq 200 ] && [[ "echo $(cat /tmp/testcase1.log)" =~ "Rule fired" ]]
- then
- echo "PASS"
- else
- echo "FAIL"
-fi
-cd ..
-rm -rf simplerules
-popd
-}
\ No newline at end of file
diff --git a/examples/flogo/simple/simple_test.go b/examples/flogo/simple/simple_test.go
new file mode 100644
index 0000000..b8865e5
--- /dev/null
+++ b/examples/flogo/simple/simple_test.go
@@ -0,0 +1,73 @@
+package main
+
+import (
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/project-flogo/core/engine"
+ "github.com/project-flogo/rules/ruleapi/tests"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSimpleApp(t *testing.T) {
+
+ data, err := ioutil.ReadFile(filepath.FromSlash("flogo.json"))
+ assert.Nil(t, err)
+ cfg, err := engine.LoadAppConfig(string(data), false)
+ assert.Nil(t, err)
+ e, err := engine.New(cfg)
+ assert.Nil(t, err)
+ tests.Drain("7777")
+ err = e.Start()
+ assert.Nil(t, err)
+ defer func() {
+ err := e.Stop()
+ assert.Nil(t, err)
+ }()
+ tests.Pour("7777")
+
+ client := &http.Client{}
+ request := func() {
+ response, err := client.Get("http://localhost:7777//test/n1?name=Bob")
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output := tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "Rule fired: [n1.name == Bob]")
+
+ request = func() {
+ response, err := client.Get("http://localhost:7777//test/n2?name=Bob")
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output = tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "Rule fired: [n1.name == Bob && n1.name == n2.name]")
+
+ request = func() {
+ response, err := client.Get("http://localhost:7777//test/n1?name=testprop")
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output = tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "Rule fired: [flogo property example]")
+
+ // set env variable used for the testcase
+ defaultVal := os.Getenv("simpleappname")
+ os.Setenv("simpleappname", "test1234")
+ defer func() {
+ os.Setenv("simpleappname", defaultVal)
+ }()
+
+ request = func() {
+ response, err := client.Get("http://localhost:7777//test/n1?name=test1234")
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output = tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "Rule fired: [env variable example]")
+
+}
diff --git a/examples/flogo/trackntrace/flogo.json b/examples/flogo/trackntrace/flogo.json
index b41e0a1..2de1373 100644
--- a/examples/flogo/trackntrace/flogo.json
+++ b/examples/flogo/trackntrace/flogo.json
@@ -112,14 +112,13 @@
}
],
"output": [
- {
- "name": "outputData",
- "type": "any"
- }
+ {
+ "name": "outputData",
+ "type": "any"
+ }
]
},
"rules": [
-
{
"name": "packageInSittingRule",
"conditions": [
@@ -131,8 +130,10 @@
"evaluator": "cPackageInSitting"
}
],
- "actionFunction": "aPackageInSitting",
- "priority":1
+ "actionService": {
+ "service": "FunctionService"
+ },
+ "priority": 1
},
{
"name": "packageInDelayedRule",
@@ -145,8 +146,10 @@
"evaluator": "cPackageInDelayed"
}
],
- "actionFunction": "aPackageInDelayed",
- "priority":1
+ "actionService": {
+ "service": "FunctionService1"
+ },
+ "priority": 1
},
{
"name": "packageInMovingRule",
@@ -159,8 +162,10 @@
"evaluator": "cPackageInMoving"
}
],
- "actionFunction": "aPackageInMoving",
- "priority":1
+ "actionService": {
+ "service": "FunctionService2"
+ },
+ "priority": 1
},
{
"name": "packageInDroppedRule",
@@ -173,8 +178,10 @@
"evaluator": "cPackageInDropped"
}
],
- "actionFunction": "aPackageInDropped",
- "priority":1
+ "actionService": {
+ "service": "FunctionService3"
+ },
+ "priority": 1
},
{
"name": "printPackageRule",
@@ -187,8 +194,10 @@
"evaluator": "cPackageEvent"
}
],
- "actionFunction": "aPrintPackage",
- "priority":2
+ "actionService": {
+ "service": "FunctionService4"
+ },
+ "priority": 2
},
{
"name": "printMoveEventRule",
@@ -201,8 +210,10 @@
"evaluator": "cMoveEvent"
}
],
- "actionFunction": "aPrintMoveEvent",
- "priority":3
+ "actionService": {
+ "service": "FunctionService5"
+ },
+ "priority": 3
},
{
"name": "joinMoveEventAndPackageEventRule",
@@ -216,8 +227,10 @@
"evaluator": "cJoinMoveEventAndPackage"
}
],
- "actionFunction": "aJoinMoveEventAndPackage",
- "priority":4
+ "actionService": {
+ "service": "FunctionService6"
+ },
+ "priority": 4
},
{
"name": "aMoveTimeoutEventRule",
@@ -230,8 +243,10 @@
"evaluator": "cMoveTimeoutEvent"
}
],
- "actionFunction": "aMoveTimeoutEvent",
- "priority":5
+ "actionService": {
+ "service": "FunctionService7"
+ },
+ "priority": 5
},
{
"name": "joinMoveTimeoutEventAndPackage",
@@ -245,8 +260,66 @@
"evaluator": "cJoinMoveTimeoutEventAndPackage"
}
],
- "actionFunction": "aJoinMoveTimeoutEventAndPackage",
- "priority":6
+ "actionService": {
+ "service": "FunctionService8"
+ },
+ "priority": 6
+ }
+ ],
+ "services": [
+ {
+ "name": "FunctionService",
+ "description": "function service for aPackageInSitting",
+ "type": "function",
+ "function": "aPackageInSitting"
+ },
+ {
+ "name": "FunctionService1",
+ "description": "function service for aPackageInDelayed",
+ "type": "function",
+ "function": "aPackageInDelayed"
+ },
+ {
+ "name": "FunctionService2",
+ "description": "function service for aPackageInMoving",
+ "type": "function",
+ "function": "aPackageInMoving"
+ },
+ {
+ "name": "FunctionService3",
+ "description": "function service for aPackageInDropped",
+ "type": "function",
+ "function": "aPackageInDropped"
+ },
+ {
+ "name": "FunctionService4",
+ "description": "function service for aPrintPackage",
+ "type": "function",
+ "function": "aPrintPackage"
+ },
+ {
+ "name": "FunctionService5",
+ "description": "function service for aPrintMoveEvent",
+ "type": "function",
+ "function": "aPrintMoveEvent"
+ },
+ {
+ "name": "FunctionService6",
+ "description": "function service for aJoinMoveEventAndPackage",
+ "type": "function",
+ "function": "aJoinMoveEventAndPackage"
+ },
+ {
+ "name": "FunctionService7",
+ "description": "function service for aMoveTimeoutEvent",
+ "type": "function",
+ "function": "aMoveTimeoutEvent"
+ },
+ {
+ "name": "FunctionService8",
+ "description": "function service for aJoinMoveTimeoutEventAndPackage",
+ "type": "function",
+ "function": "aJoinMoveTimeoutEventAndPackage"
}
]
}
diff --git a/examples/flogo/trackntrace/trackntrace_test.go b/examples/flogo/trackntrace/trackntrace_test.go
new file mode 100644
index 0000000..bd1df9c
--- /dev/null
+++ b/examples/flogo/trackntrace/trackntrace_test.go
@@ -0,0 +1,57 @@
+package main
+
+import (
+ "io/ioutil"
+ "net/http"
+ "path/filepath"
+ "testing"
+
+ "github.com/project-flogo/core/engine"
+ "github.com/project-flogo/rules/ruleapi/tests"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestInvokeService(t *testing.T) {
+
+ data, err := ioutil.ReadFile(filepath.FromSlash("flogo.json"))
+ assert.Nil(t, err)
+ cfg, err := engine.LoadAppConfig(string(data), false)
+ assert.Nil(t, err)
+ e, err := engine.New(cfg)
+ assert.Nil(t, err)
+ tests.Drain("7777")
+ err = e.Start()
+ assert.Nil(t, err)
+ defer func() {
+ err := e.Stop()
+ assert.Nil(t, err)
+ }()
+ tests.Pour("7777")
+
+ client := &http.Client{}
+ request := func() {
+ response, err := client.Get("http://localhost:7777/moveevent?packageid=PACKAGE1&targetstate=sitting")
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output := tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "PACKAGE [PACKAGE1] is Sitting")
+
+ request = func() {
+ response, err := client.Get("http://localhost:7777/moveevent?packageid=PACKAGE1&targetstate=moving")
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output = tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "PACKAGE [PACKAGE1] is Moving")
+
+ request = func() {
+ response, err := client.Get("http://localhost:7777/moveevent?packageid=PACKAGE2&targetstate=normal")
+ assert.Nil(t, err)
+ assert.Equal(t, http.StatusOK, response.StatusCode)
+ }
+ output = tests.CaptureStdOutput(request)
+ assert.Contains(t, output, "Received package [PACKAGE2]")
+
+}
diff --git a/examples/rulesapp/main.go b/examples/rulesapp/main.go
index c544c61..2f4f4ff 100644
--- a/examples/rulesapp/main.go
+++ b/examples/rulesapp/main.go
@@ -6,120 +6,251 @@ import (
"github.com/project-flogo/rules/common"
"github.com/project-flogo/rules/common/model"
+ "github.com/project-flogo/rules/config"
"github.com/project-flogo/rules/ruleapi"
)
func main() {
+ err := example()
+ if err != nil {
+ panic(err)
+ }
+}
- fmt.Println("** rulesapp: Example usage of the Rules module/API **")
-
+func example() error {
//Load the tuple descriptor file (relative to GOPATH)
tupleDescAbsFileNm := common.GetAbsPathForResource("src/github.com/project-flogo/rules/examples/rulesapp/rulesapp.json")
tupleDescriptor := common.FileToString(tupleDescAbsFileNm)
- fmt.Printf("Loaded tuple descriptor: \n%s\n", tupleDescriptor)
//First register the tuple descriptors
err := model.RegisterTupleDescriptors(tupleDescriptor)
if err != nil {
- fmt.Printf("Error [%s]\n", err)
- return
+ return err
}
//Create a RuleSession
- rs, _ := ruleapi.GetOrCreateRuleSession("asession")
+ rs, err := ruleapi.GetOrCreateRuleSession("asession")
+ if err != nil {
+ return err
+ }
+ events := make(map[string]int, 8)
//// check for name "Bob" in n1
rule := ruleapi.NewRule("n1.name == Bob")
- rule.AddCondition("c1", []string{"n1"}, checkForBob, nil)
- rule.SetAction(checkForBobAction)
- rule.SetContext("This is a test of context")
- rs.AddRule(rule)
- fmt.Printf("Rule added: [%s]\n", rule.GetName())
+ err = rule.AddCondition("c1", []string{"n1"}, checkForBob, events)
+ if err != nil {
+ return err
+ }
+ serviceCfg := &config.ServiceDescriptor{
+ Name: "checkForBobAction",
+ Function: checkForBobAction,
+ Type: "function",
+ }
+ aService, err := ruleapi.NewActionService(serviceCfg)
+ if err != nil {
+ return err
+ }
+ rule.SetActionService(aService)
+ rule.SetContext(events)
+ err = rs.AddRule(rule)
+ if err != nil {
+ return err
+ }
// check for name "Bob" in n1, match the "name" field in n2,
// in effect, fire the rule when name field in both tuples is "Bob"
rule2 := ruleapi.NewRule("n1.name == Bob && n1.name == n2.name")
- rule2.AddCondition("c1", []string{"n1"}, checkForBob, nil)
- rule2.AddCondition("c2", []string{"n1", "n2"}, checkSameNamesCondition, nil)
- rule2.SetAction(checkSameNamesAction)
- rs.AddRule(rule2)
- fmt.Printf("Rule added: [%s]\n", rule2.GetName())
+ err = rule2.AddCondition("c1", []string{"n1"}, checkForBob, events)
+ if err != nil {
+ return err
+ }
+ err = rule2.AddCondition("c2", []string{"n1", "n2"}, checkSameNamesCondition, events)
+ if err != nil {
+ return err
+ }
+ serviceCfg2 := &config.ServiceDescriptor{
+ Name: "checkSameNamesAction",
+ Function: checkSameNamesAction,
+ Type: "function",
+ }
+ aService2, err := ruleapi.NewActionService(serviceCfg2)
+ if err != nil {
+ return err
+ }
+ rule2.SetActionService(aService2)
+ rule2.SetContext(events)
+ err = rs.AddRule(rule2)
+ if err != nil {
+ return err
+ }
//Start the rule session
- rs.Start(nil)
+ err = rs.Start(nil)
+ if err != nil {
+ return err
+ }
//Now assert a "n1" tuple
- fmt.Println("Asserting n1 tuple with name=Tom")
- t1, _ := model.NewTupleWithKeyValues("n1", "Tom")
- t1.SetString(context.TODO(), "name", "Tom")
- rs.Assert(context.TODO(), t1)
+ t1, err := model.NewTupleWithKeyValues("n1", "Tom")
+ if err != nil {
+ return err
+ }
+ t1.SetString(nil, "name", "Tom")
+ err = rs.Assert(nil, t1)
+ if err != nil {
+ return err
+ }
//Now assert a "n1" tuple
- fmt.Println("Asserting n1 tuple with name=Bob")
- t2, _ := model.NewTupleWithKeyValues("n1", "Bob")
- t2.SetString(context.TODO(), "name", "Bob")
- rs.Assert(context.TODO(), t2)
+ t2, err := model.NewTupleWithKeyValues("n1", "Bob")
+ if err != nil {
+ return err
+ }
+ t2.SetString(nil, "name", "Bob")
+ err = rs.Assert(nil, t2)
+ if err != nil {
+ return err
+ }
//Now assert a "n2" tuple
- fmt.Println("Asserting n2 tuple with name=Bob")
- t3, _ := model.NewTupleWithKeyValues("n2", "Bob")
+ t3, err := model.NewTupleWithKeyValues("n2", "Bob")
+ if err != nil {
+ return err
+ }
t3.SetString(nil, "name", "Bob")
- rs.Assert(context.TODO(), t3)
+ err = rs.Assert(nil, t3)
+ if err != nil {
+ return err
+ }
+
+ //Now assert a "n1" tuple
+ t4, err := model.NewTupleWithKeyValues("n1", "Smith")
+ if err != nil {
+ return err
+ }
+ t4.SetString(nil, "name", "Smith")
+ err = rs.Assert(nil, t4)
+ if err != nil {
+ return err
+ }
//Retract tuples
- rs.Retract(context.TODO(), t1)
- rs.Retract(context.TODO(), t2)
- rs.Retract(context.TODO(), t3)
+ rs.Retract(nil, t1)
+ rs.Retract(nil, t2)
+ rs.Retract(nil, t3)
+ rs.Retract(nil, t4)
//delete the rule
- rs.DeleteRule(rule.GetName())
+ rs.DeleteRule(rule2.GetName())
//unregister the session, i.e; cleanup
rs.Unregister()
+
+ if events["checkForBob"] != 6 {
+ return fmt.Errorf("checkForBob should have been called 6 times")
+ }
+ if events["checkForBobAction"] != 1 {
+ return fmt.Errorf("checkForBobAction should have been called once")
+ }
+ if events["checkSameNamesCondition"] != 1 {
+ return fmt.Errorf("checkSameNamesCondition should have been called once")
+ }
+ if events["checkSameNamesAction"] != 1 {
+ return fmt.Errorf("checkSameNamesAction should have been called once")
+ }
+
+ return nil
}
func checkForBob(ruleName string, condName string, tuples map[model.TupleType]model.Tuple, ctx model.RuleContext) bool {
//This conditions filters on name="Bob"
+ //fmt.Println("checkForBob")
t1 := tuples["n1"]
if t1 == nil {
- fmt.Println("Should not get a nil tuple in FilterCondition! This is an error")
return false
}
- name, _ := t1.GetString("name")
+ name, err := t1.GetString("name")
+ if err != nil {
+ return false
+ }
+ if name == "" {
+ return false
+ }
+ events := ctx.(map[string]int)
+ count := events["checkForBob"]
+ events["checkForBob"] = count + 1
return name == "Bob"
}
func checkForBobAction(ctx context.Context, rs model.RuleSession, ruleName string, tuples map[model.TupleType]model.Tuple, ruleCtx model.RuleContext) {
- fmt.Printf("Rule fired: [%s]\n", ruleName)
- fmt.Printf("Context is [%s]\n", ruleCtx)
+ //fmt.Println("checkForBobAction")
t1 := tuples["n1"]
if t1 == nil {
- fmt.Println("Should not get nil tuples here in JoinCondition! This is an error")
return
}
+ name, err := t1.GetString("name")
+ if err != nil {
+ return
+ }
+ if name == "" {
+ return
+ }
+ fmt.Println("Rule checkForBobAction is fired")
+ events := ruleCtx.(map[string]int)
+ count := events["checkForBobAction"]
+ events["checkForBobAction"] = count + 1
}
func checkSameNamesCondition(ruleName string, condName string, tuples map[model.TupleType]model.Tuple, ctx model.RuleContext) bool {
+ //fmt.Println("checkSameNamesCondition")
t1 := tuples["n1"]
t2 := tuples["n2"]
if t1 == nil || t2 == nil {
- fmt.Println("Should not get nil tuples here in JoinCondition! This is an error")
return false
}
- name1, _ := t1.GetString("name")
- name2, _ := t2.GetString("name")
+ name1, err := t1.GetString("name")
+ if err != nil {
+ return false
+ }
+ if name1 == "" {
+ return false
+ }
+ name2, err := t2.GetString("name")
+ if err != nil {
+ return false
+ }
+ if name2 == "" {
+ return false
+ }
+ events := ctx.(map[string]int)
+ count := events["checkSameNamesCondition"]
+ events["checkSameNamesCondition"] = count + 1
return name1 == name2
}
func checkSameNamesAction(ctx context.Context, rs model.RuleSession, ruleName string, tuples map[model.TupleType]model.Tuple, ruleCtx model.RuleContext) {
- fmt.Printf("Rule fired: [%s]\n", ruleName)
+ //fmt.Println("checkSameNamesAction")
t1 := tuples["n1"]
t2 := tuples["n2"]
if t1 == nil || t2 == nil {
- fmt.Println("Should not get nil tuples here in Action! This is an error")
return
}
- name1, _ := t1.GetString("name")
- name2, _ := t2.GetString("name")
- fmt.Printf("n1.name = [%s], n2.name = [%s]\n", name1, name2)
+ name1, err := t1.GetString("name")
+ if err != nil {
+ return
+ }
+ if name1 == "" {
+ return
+ }
+ name2, err := t2.GetString("name")
+ if err != nil {
+ return
+ }
+ if name2 == "" {
+ return
+ }
+ fmt.Println("Rule checkSameNamesAction is fired")
+ events := ruleCtx.(map[string]int)
+ count := events["checkSameNamesAction"]
+ events["checkSameNamesAction"] = count + 1
}
diff --git a/examples/rulesapp/rulesapp_test.go b/examples/rulesapp/rulesapp_test.go
new file mode 100644
index 0000000..612f800
--- /dev/null
+++ b/examples/rulesapp/rulesapp_test.go
@@ -0,0 +1,12 @@
+package main
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestRuleApp(t *testing.T) {
+ err := example()
+ assert.Nil(t, err)
+}
diff --git a/examples/rulesapp/sanity.sh b/examples/rulesapp/sanity.sh
deleted file mode 100644
index aff0c8a..0000000
--- a/examples/rulesapp/sanity.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-function get_test_cases {
- local my_list=( testcase1 )
- echo "${my_list[@]}"
-}
-
-# This testcase checks for name bob
-function testcase1 {
-pushd $GOPATH/src/github.com/project-flogo/rules/examples/rulesapp
-rm -rf /tmp/testcase1.log
-go run main.go > /tmp/testcase1.log 2>&1
-
-if [[ "echo $(cat /tmp/testcase1.log)" =~ "Rule fired" ]]
- then
- echo "PASS"
- else
- echo "FAIL"
-fi
-popd
-}
\ No newline at end of file
diff --git a/examples/trackntrace/trackntrace_test.go b/examples/trackntrace/trackntrace_test.go
index 590be1b..68dc871 100644
--- a/examples/trackntrace/trackntrace_test.go
+++ b/examples/trackntrace/trackntrace_test.go
@@ -1,9 +1,14 @@
package trackntrace
import (
+ "reflect"
+ "runtime"
+
"github.com/project-flogo/rules/common"
"github.com/project-flogo/rules/common/model"
+ "github.com/project-flogo/rules/config"
"github.com/project-flogo/rules/ruleapi"
+ "github.com/stretchr/testify/assert"
"context"
"fmt"
@@ -218,7 +223,7 @@ func loadPkgRulesWithDeps(t *testing.T, rs model.RuleSession) {
//handle a package event, create a package in the packageAction
rule := ruleapi.NewRule("packageevent")
rule.AddCondition("truecondition", []string{"packageevent.none"}, truecondition, nil)
- rule.SetAction(packageeventAction)
+ rule.SetActionService(createActionServiceFromFunction(t, packageeventAction))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
@@ -226,7 +231,7 @@ func loadPkgRulesWithDeps(t *testing.T, rs model.RuleSession) {
//handle a package, print package details in the packageAction
rule1 := ruleapi.NewRule("package")
rule1.AddCondition("packageCondition", []string{"package.none"}, packageCondition, nil)
- rule1.SetAction(packageAction)
+ rule1.SetActionService(createActionServiceFromFunction(t, packageAction))
rule1.SetPriority(2)
rs.AddRule(rule1)
t.Logf("Rule added: [%s]\n", rule1.GetName())
@@ -235,7 +240,7 @@ func loadPkgRulesWithDeps(t *testing.T, rs model.RuleSession) {
//for the next destination, etc in the scaneventAction
rule2 := ruleapi.NewRule("scanevent")
rule2.AddCondition("scaneventCondition", []string{"package.packageid", "scanevent.packageid", "package.curr", "package.next"}, scaneventCondition, nil)
- rule2.SetAction(scaneventAction)
+ rule2.SetActionService(createActionServiceFromFunction(t, scaneventAction))
rule2.SetPriority(2)
rs.AddRule(rule2)
t.Logf("Rule added: [%s]\n", rule2.GetName())
@@ -243,7 +248,7 @@ func loadPkgRulesWithDeps(t *testing.T, rs model.RuleSession) {
//handle a timeout event, triggered by scaneventAction, mark the package as delayed in scantimeoutAction
rule3 := ruleapi.NewRule("scantimeout")
rule3.AddCondition("scantimeoutCondition", []string{"package.packageid", "scantimeout.packageid"}, scantimeoutCondition, nil)
- rule3.SetAction(scantimeoutAction)
+ rule3.SetActionService(createActionServiceFromFunction(t, scantimeoutAction))
rule3.SetPriority(1)
rs.AddRule(rule3)
t.Logf("Rule added: [%s]\n", rule3.GetName())
@@ -251,7 +256,7 @@ func loadPkgRulesWithDeps(t *testing.T, rs model.RuleSession) {
//notify when a package is marked as delayed, print as such in the packagedelayedAction
rule4 := ruleapi.NewRule("packagedelayed")
rule4.AddCondition("packageDelayedCheck", []string{"package.status"}, packageDelayedCheck, nil)
- rule4.SetAction(packagedelayedAction)
+ rule4.SetActionService(createActionServiceFromFunction(t, packagedelayedAction))
rule4.SetPriority(1)
rs.AddRule(rule4)
t.Logf("Rule added: [%s]\n", rule4.GetName())
@@ -391,3 +396,17 @@ func packagedelayedAction(ctx context.Context, rs model.RuleSession, ruleName st
}
type TestKey struct{}
+
+func createActionServiceFromFunction(t *testing.T, actionFunction model.ActionFunction) model.ActionService {
+ fname := runtime.FuncForPC(reflect.ValueOf(actionFunction).Pointer()).Name()
+ cfg := &config.ServiceDescriptor{
+ Name: fname,
+ Description: fname,
+ Type: config.TypeServiceFunction,
+ Function: actionFunction,
+ }
+ aService, err := ruleapi.NewActionService(cfg)
+ assert.Nil(t, err)
+ assert.NotNil(t, aService)
+ return aService
+}
diff --git a/rete/conflict.go b/rete/conflict.go
index a277679..3ad8e1d 100644
--- a/rete/conflict.go
+++ b/rete/conflict.go
@@ -53,10 +53,11 @@ func (cr *conflictResImpl) resolveConflict(ctx context.Context) {
if val != nil {
item = val.(agendaItem)
actionTuples := item.getTuples()
- actionFn := item.getRule().GetActionFn()
- if actionFn != nil {
+ // execute rule action service
+ aService := item.getRule().GetActionService()
+ if aService != nil {
reteCtxV := getReteCtx(ctx)
- actionFn(ctx, reteCtxV.getRuleSession(), item.getRule().GetName(), actionTuples, item.getRule().GetContext())
+ aService.Execute(ctx, reteCtxV.getRuleSession(), item.getRule().GetName(), actionTuples, item.getRule().GetContext())
}
}
diff --git a/rete/debug.test b/rete/debug.test
deleted file mode 100755
index 2eca2fb..0000000
Binary files a/rete/debug.test and /dev/null differ
diff --git a/ruleaction/action.go b/ruleaction/action.go
index d35cd27..b6ac0ee 100644
--- a/ruleaction/action.go
+++ b/ruleaction/action.go
@@ -96,6 +96,8 @@ func (f *ActionFactory) New(cfg *action.Config) (action.Action, error) {
}
ruleAction := &RuleAction{}
+
+ // create rule session
ruleSessionDescriptor, err := manager.GetRuleSessionDescriptor(settings.RuleSessionURI)
if err != nil {
return nil, fmt.Errorf("failed to get RuleSessionDescriptor for %s\n%s", settings.RuleSessionURI, err.Error())
diff --git a/ruleapi/actionservice.go b/ruleapi/actionservice.go
new file mode 100644
index 0000000..9bf55c9
--- /dev/null
+++ b/ruleapi/actionservice.go
@@ -0,0 +1,135 @@
+package ruleapi
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/project-flogo/core/activity"
+ "github.com/project-flogo/core/data"
+ "github.com/project-flogo/core/data/mapper"
+ "github.com/project-flogo/core/data/resolve"
+ "github.com/project-flogo/core/support"
+ "github.com/project-flogo/core/support/log"
+ "github.com/project-flogo/rules/common/model"
+ "github.com/project-flogo/rules/config"
+)
+
+var logger = log.ChildLogger(log.RootLogger(), "rules")
+
+// rule action service
+type ruleActionService struct {
+ Name string
+ Type string
+ Function model.ActionFunction
+ Act activity.Activity
+ Input map[string]interface{}
+}
+
+// NewActionService creates new rule action service
+func NewActionService(serviceCfg *config.ServiceDescriptor) (model.ActionService, error) {
+
+ raService := &ruleActionService{
+ Name: serviceCfg.Name,
+ Type: serviceCfg.Type,
+ Input: make(map[string]interface{}),
+ }
+
+ switch serviceCfg.Type {
+ default:
+ return nil, fmt.Errorf("service type - '%s' is not supported", serviceCfg.Type)
+ case "":
+ return nil, fmt.Errorf("service type can't be empty")
+ case config.TypeServiceFunction:
+ if serviceCfg.Function == nil {
+ return nil, fmt.Errorf("service function can't empty")
+ }
+ raService.Function = serviceCfg.Function
+ case config.TypeServiceActivity:
+ // inflate activity from ref
+ if serviceCfg.Ref[0] == '#' {
+ var ok bool
+ activityRef := serviceCfg.Ref
+ serviceCfg.Ref, ok = support.GetAliasRef("activity", activityRef)
+ if !ok {
+ return nil, fmt.Errorf("activity '%s' not imported", activityRef)
+ }
+ }
+
+ act := activity.Get(serviceCfg.Ref)
+ if act == nil {
+ return nil, fmt.Errorf("unsupported Activity:" + serviceCfg.Ref)
+ }
+
+ f := activity.GetFactory(serviceCfg.Ref)
+
+ if f != nil {
+ initCtx := newInitContext(serviceCfg.Name, serviceCfg.Settings, log.ChildLogger(log.RootLogger(), "ruleaction"))
+ pa, err := f(initCtx)
+ if err != nil {
+ return nil, fmt.Errorf("unable to create rule action service '%s' : %s", serviceCfg.Name, err.Error())
+ }
+ act = pa
+ }
+
+ raService.Act = act
+ }
+
+ return raService, nil
+}
+
+// SetInput sets input
+func (raService *ruleActionService) SetInput(input map[string]interface{}) {
+ for k, v := range input {
+ raService.Input[k] = v
+ }
+}
+
+func resolveExpFromTupleScope(tuples map[model.TupleType]model.Tuple, exprs map[string]interface{}) (map[string]interface{}, error) {
+ // resolve inputs from tuple scope
+ mFactory := mapper.NewFactory(resolve.GetBasicResolver())
+ mapper, err := mFactory.NewMapper(exprs)
+ if err != nil {
+ return nil, err
+ }
+
+ tupleScope := make(map[string]interface{})
+ for tk, t := range tuples {
+ tupleScope[string(tk)] = t.GetMap()
+ }
+
+ scope := data.NewSimpleScope(tupleScope, nil)
+ return mapper.Apply(scope)
+}
+
+// Execute execute rule action service
+func (raService *ruleActionService) Execute(ctx context.Context, rs model.RuleSession, rName string, tuples map[model.TupleType]model.Tuple, rCtx model.RuleContext) (done bool, err error) {
+
+ switch raService.Type {
+
+ default:
+ return false, fmt.Errorf("unsupported service type - '%s'", raService.Type)
+
+ case config.TypeServiceFunction:
+ // invoke function and return, if available
+ if raService.Function != nil {
+ raService.Function(ctx, rs, rName, tuples, rCtx)
+ return true, nil
+ }
+
+ case config.TypeServiceActivity:
+ // resolve inputs from tuple scope
+ resolvedInputs, err := resolveExpFromTupleScope(tuples, raService.Input)
+ if err != nil {
+ return false, err
+ }
+ // create activity context and set resolved inputs
+ sContext := newServiceContext(raService.Act.Metadata())
+ for k, v := range resolvedInputs {
+ sContext.SetInput(k, v)
+ }
+ // run activities Eval
+ return raService.Act.Eval(sContext)
+ }
+
+ return false, fmt.Errorf("service not executed, something went wrong")
+}
diff --git a/ruleapi/actionservice_test.go b/ruleapi/actionservice_test.go
new file mode 100644
index 0000000..57a0dcb
--- /dev/null
+++ b/ruleapi/actionservice_test.go
@@ -0,0 +1,52 @@
+package ruleapi
+
+import (
+ "context"
+ "testing"
+
+ _ "github.com/project-flogo/contrib/activity/log"
+ "github.com/project-flogo/rules/common/model"
+ "github.com/project-flogo/rules/config"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestNewActionService(t *testing.T) {
+ cfg := &config.ServiceDescriptor{
+ Name: "TestActionService",
+ Description: "test action service",
+ }
+ aService, err := NewActionService(cfg)
+ assert.NotNil(t, err)
+ assert.Equal(t, "service type can't be empty", err.Error())
+ assert.Nil(t, aService)
+
+ // unsupported service type
+ cfg.Type = "unknowntype"
+ _, err = NewActionService(cfg)
+ assert.NotNil(t, err)
+ assert.Equal(t, "service type - 'unknowntype' is not supported", err.Error())
+
+ // action service with function
+ cfg.Function = emptyAction
+ cfg.Type = config.TypeServiceFunction
+ aService, err = NewActionService(cfg)
+ assert.Nil(t, err)
+ assert.NotNil(t, aService)
+ cfg.Function = nil //clear for next test scenario
+
+ // action service with activity
+ cfg.Ref = "github.com/project-flogo/contrib/activity/log"
+ cfg.Type = config.TypeServiceActivity
+ aService, err = NewActionService(cfg)
+ assert.Nil(t, err)
+ assert.NotNil(t, aService)
+
+ // set input
+ input := map[string]interface{}{"message": "=$.n1.name"}
+ aService.SetInput(input)
+
+ // TODO: test aService.Execute()
+}
+
+func emptyAction(ctx context.Context, rs model.RuleSession, ruleName string, tuples map[model.TupleType]model.Tuple, ruleCtx model.RuleContext) {
+}
diff --git a/ruleapi/rule.go b/ruleapi/rule.go
index 8a5fd69..f0b3c78 100644
--- a/ruleapi/rule.go
+++ b/ruleapi/rule.go
@@ -9,13 +9,13 @@ import (
)
type ruleImpl struct {
- name string
- identifiers []model.TupleType
- conditions []model.Condition
- actionFn model.ActionFunction
- priority int
- deps map[model.TupleType]map[string]bool
- ctx model.RuleContext
+ name string
+ identifiers []model.TupleType
+ conditions []model.Condition
+ actionService model.ActionService
+ priority int
+ deps map[model.TupleType]map[string]bool
+ ctx model.RuleContext
}
func (rule *ruleImpl) GetContext() model.RuleContext {
@@ -44,16 +44,16 @@ func (rule *ruleImpl) GetName() string {
return rule.name
}
-func (rule *ruleImpl) GetActionFn() model.ActionFunction {
- return rule.actionFn
+func (rule *ruleImpl) GetActionService() model.ActionService {
+ return rule.actionService
}
func (rule *ruleImpl) GetConditions() []model.Condition {
return rule.conditions
}
-func (rule *ruleImpl) SetActionFn(actionFn model.ActionFunction) {
- rule.actionFn = actionFn
+func (rule *ruleImpl) SetActionService(actionService model.ActionService) {
+ rule.actionService = actionService
}
func (rule *ruleImpl) addCond(conditionName string, idrs []model.TupleType, cfn model.ConditionEvaluator, ctx model.RuleContext, setIdr bool) {
@@ -141,10 +141,6 @@ func (rule *ruleImpl) GetIdentifiers() []model.TupleType {
return rule.identifiers
}
-func (rule *ruleImpl) SetAction(actionFn model.ActionFunction) {
- rule.actionFn = actionFn
-}
-
func (rule *ruleImpl) AddCondition2(conditionName string, idrs []string, cFn model.ConditionEvaluator, ctx model.RuleContext) (err error) {
typeDeps := []model.TupleType{}
for _, idr := range idrs {
diff --git a/ruleapi/rulesession.go b/ruleapi/rulesession.go
index 33cbdfc..678974c 100644
--- a/ruleapi/rulesession.go
+++ b/ruleapi/rulesession.go
@@ -49,10 +49,28 @@ func GetOrCreateRuleSessionFromConfig(name string, jsonConfig string) (model.Rul
return nil, err
}
+ // inflate action services
+ aServices := make(map[string]model.ActionService)
+ for _, s := range ruleSessionDescriptor.Services {
+ aService, err := NewActionService(s)
+ if err != nil {
+ return nil, err
+ }
+ aServices[s.Name] = aService
+ }
+
for _, ruleCfg := range ruleSessionDescriptor.Rules {
rule := NewRule(ruleCfg.Name)
rule.SetContext("This is a test of context")
- rule.SetAction(ruleCfg.ActionFunc)
+ // set action service to rule, if exist
+ if ruleCfg.ActionService != nil {
+ aService, found := aServices[ruleCfg.ActionService.Service]
+ if !found {
+ return nil, fmt.Errorf("rule action service[%s] not found", ruleCfg.ActionService.Service)
+ }
+ aService.SetInput(ruleCfg.ActionService.Input)
+ rule.SetActionService(aService)
+ }
rule.SetPriority(ruleCfg.Priority)
for _, condCfg := range ruleCfg.Conditions {
diff --git a/ruleapi/servicecontext.go b/ruleapi/servicecontext.go
new file mode 100644
index 0000000..23fadec
--- /dev/null
+++ b/ruleapi/servicecontext.go
@@ -0,0 +1,185 @@
+package ruleapi
+
+import (
+ "github.com/project-flogo/core/activity"
+ "github.com/project-flogo/core/data"
+ "github.com/project-flogo/core/data/mapper"
+ "github.com/project-flogo/core/data/metadata"
+ "github.com/project-flogo/core/data/resolve"
+ "github.com/project-flogo/core/support/log"
+ "github.com/project-flogo/core/support/trace"
+)
+
+// activity init context
+type initContext struct {
+ settings map[string]interface{}
+ mapperFactory mapper.Factory
+ logger log.Logger
+}
+
+func newInitContext(name string, settings map[string]interface{}, l log.Logger) *initContext {
+ return &initContext{
+ settings: settings,
+ mapperFactory: mapper.NewFactory(resolve.GetBasicResolver()),
+ logger: log.ChildLogger(l, name),
+ }
+}
+
+func (i *initContext) Settings() map[string]interface{} {
+ return i.settings
+}
+
+func (i *initContext) MapperFactory() mapper.Factory {
+ return i.mapperFactory
+}
+
+func (i *initContext) Logger() log.Logger {
+ return i.logger
+}
+
+// ServiceContext context
+type ServiceContext struct {
+ TaskName string
+ activityHost activity.Host
+
+ metadata *activity.Metadata
+ settings map[string]interface{}
+ inputs map[string]interface{}
+ outputs map[string]interface{}
+
+ shared map[string]interface{}
+}
+
+func newServiceContext(md *activity.Metadata) *ServiceContext {
+ input := map[string]data.TypedValue{"Input1": data.NewTypedValue(data.TypeString, "")}
+ output := map[string]data.TypedValue{"Output1": data.NewTypedValue(data.TypeString, "")}
+
+ // TBD: rule action's details (like: metadata, name, etc) to be used here
+ sHost := &ServiceHost{
+ HostId: "1",
+ HostRef: "github.com/project-flogo/rules",
+ IoMetadata: &metadata.IOMetadata{Input: input, Output: output},
+ HostData: data.NewSimpleScope(nil, nil),
+ }
+ sContext := &ServiceContext{
+ metadata: md,
+ activityHost: sHost,
+ TaskName: "Rule action service",
+ inputs: make(map[string]interface{}, len(md.Input)),
+ outputs: make(map[string]interface{}, len(md.Output)),
+ settings: make(map[string]interface{}, len(md.Settings)),
+ }
+
+ for name, tv := range md.Input {
+ sContext.inputs[name] = tv.Value()
+ }
+ for name, tv := range md.Output {
+ sContext.outputs[name] = tv.Value()
+ }
+
+ return sContext
+}
+
+// ActivityHost gets the "host" under with the activity is executing
+func (sc *ServiceContext) ActivityHost() activity.Host {
+ return sc.activityHost
+}
+
+//Name the name of the activity that is currently executing
+func (sc *ServiceContext) Name() string {
+ return sc.TaskName
+}
+
+// GetInput gets the value of the specified input attribute
+func (sc *ServiceContext) GetInput(name string) interface{} {
+ val, found := sc.inputs[name]
+ if found {
+ return val
+ }
+ return nil
+}
+
+// SetOutput sets the value of the specified output attribute
+func (sc *ServiceContext) SetOutput(name string, value interface{}) error {
+ sc.outputs[name] = value
+ return nil
+}
+
+// GetInputObject gets all the activity input as the specified object.
+func (sc *ServiceContext) GetInputObject(input data.StructValue) error {
+ err := input.FromMap(sc.inputs)
+ return err
+}
+
+// SetOutputObject sets the activity output as the specified object.
+func (sc *ServiceContext) SetOutputObject(output data.StructValue) error {
+ sc.outputs = output.ToMap()
+ return nil
+}
+
+// GetSharedTempData get shared temporary data for activity, lifespan
+// of the data dependent on the activity host implementation
+func (sc *ServiceContext) GetSharedTempData() map[string]interface{} {
+ if sc.shared == nil {
+ sc.shared = make(map[string]interface{})
+ }
+ return sc.shared
+}
+
+// Logger the logger for the activity
+func (sc *ServiceContext) Logger() log.Logger {
+ return logger
+}
+
+// SetInput sets input
+func (sc *ServiceContext) SetInput(name string, value interface{}) {
+ sc.inputs[name] = value
+}
+
+// GetTracingContext returns tracing context
+func (sc *ServiceContext) GetTracingContext() trace.TracingContext {
+ return nil
+}
+
+// ServiceHost hosts service
+type ServiceHost struct {
+ HostId string
+ HostRef string
+
+ IoMetadata *metadata.IOMetadata
+ HostData data.Scope
+ ReplyData map[string]interface{}
+ ReplyErr error
+}
+
+// ID returns the ID of the Activity Host
+func (ac *ServiceHost) ID() string {
+ return ac.HostId
+}
+
+// Name the name of the Activity Host
+func (ac *ServiceHost) Name() string {
+ return ""
+}
+
+// IOMetadata get the input/output metadata of the activity host
+func (ac *ServiceHost) IOMetadata() *metadata.IOMetadata {
+ return ac.IoMetadata
+}
+
+// Reply is used to reply to the activity Host with the results of the execution
+func (ac *ServiceHost) Reply(replyData map[string]interface{}, err error) {
+ ac.ReplyData = replyData
+ ac.ReplyErr = err
+}
+
+// Return is used to indicate to the activity Host that it should complete and return the results of the execution
+func (ac *ServiceHost) Return(returnData map[string]interface{}, err error) {
+ ac.ReplyData = returnData
+ ac.ReplyErr = err
+}
+
+// Scope returns the scope for the Host's data
+func (ac *ServiceHost) Scope() data.Scope {
+ return ac.HostData
+}
diff --git a/ruleapi/tests/common.go b/ruleapi/tests/common.go
index 30add5d..90a2632 100644
--- a/ruleapi/tests/common.go
+++ b/ruleapi/tests/common.go
@@ -1,14 +1,26 @@
package tests
import (
+ "bytes"
"context"
+ "io"
"io/ioutil"
"log"
+ "net"
+ "os"
+ "os/exec"
+ "reflect"
+ "runtime"
+ "strings"
+ "sync"
"testing"
+ "time"
"github.com/project-flogo/rules/common"
"github.com/project-flogo/rules/common/model"
+ "github.com/project-flogo/rules/config"
"github.com/project-flogo/rules/ruleapi"
+ "github.com/stretchr/testify/assert"
)
func createRuleSession() (model.RuleSession, error) {
@@ -62,4 +74,77 @@ type txnCtx struct {
TxnCnt int
}
+func createActionServiceFromFunction(t *testing.T, actionFunction model.ActionFunction) model.ActionService {
+ fname := runtime.FuncForPC(reflect.ValueOf(actionFunction).Pointer()).Name()
+ cfg := &config.ServiceDescriptor{
+ Name: fname,
+ Description: fname,
+ Type: config.TypeServiceFunction,
+ Function: actionFunction,
+ }
+ aService, err := ruleapi.NewActionService(cfg)
+ assert.Nil(t, err)
+ assert.NotNil(t, aService)
+ return aService
+}
+
type TestKey struct{}
+
+func Drain(port string) {
+ for {
+ conn, err := net.DialTimeout("tcp", net.JoinHostPort("", port), time.Second)
+ if conn != nil {
+ conn.Close()
+ }
+ if err != nil && strings.Contains(err.Error(), "connect: connection refused") {
+ break
+ }
+ }
+}
+
+func Pour(port string) {
+ for {
+ conn, _ := net.Dial("tcp", net.JoinHostPort("", port))
+ if conn != nil {
+ conn.Close()
+ break
+ }
+ }
+}
+
+func CaptureStdOutput(f func()) string {
+ reader, writer, err := os.Pipe()
+ if err != nil {
+ panic(err)
+ }
+ stdout := os.Stdout
+ stderr := os.Stderr
+ defer func() {
+ os.Stdout = stdout
+ os.Stderr = stderr
+ log.SetOutput(os.Stderr)
+ }()
+ os.Stdout = writer
+ os.Stderr = writer
+ log.SetOutput(writer)
+ out := make(chan string)
+ wg := new(sync.WaitGroup)
+ wg.Add(1)
+ go func() {
+ var buf bytes.Buffer
+ wg.Done()
+ io.Copy(&buf, reader)
+ out <- buf.String()
+ }()
+ wg.Wait()
+ f()
+ writer.Close()
+ return <-out
+}
+
+func Command(name string, arg ...string) {
+ _, err := exec.Command(name, arg...).CombinedOutput()
+ if err != nil {
+ os.Stderr.WriteString(err.Error())
+ }
+}
diff --git a/ruleapi/tests/expr_1_test.go b/ruleapi/tests/expr_1_test.go
index f48dca9..611fd65 100644
--- a/ruleapi/tests/expr_1_test.go
+++ b/ruleapi/tests/expr_1_test.go
@@ -15,7 +15,7 @@ func Test_1_Expr(t *testing.T) {
rs, _ := createRuleSession()
r1 := ruleapi.NewRule("r1")
r1.AddExprCondition("c1", "$.t2.p2 > $.t1.p1", nil)
- r1.SetAction(a1)
+ r1.SetActionService(createActionServiceFromFunction(t, a1))
r1.SetContext(actionCount)
rs.AddRule(r1)
diff --git a/ruleapi/tests/expr_2_test.go b/ruleapi/tests/expr_2_test.go
index 2fdaebe..150746a 100644
--- a/ruleapi/tests/expr_2_test.go
+++ b/ruleapi/tests/expr_2_test.go
@@ -16,7 +16,7 @@ func Test_2_Expr(t *testing.T) {
r1 := ruleapi.NewRule("r1")
r1.AddExprCondition("c1", "$.t1.p1 > $.t2.p1", nil)
r1.AddExprCondition("c2", "$.t1.p1 == 2", nil)
- r1.SetAction(a2)
+ r1.SetActionService(createActionServiceFromFunction(t, a2))
r1.SetContext(actionCount)
rs.AddRule(r1)
diff --git a/ruleapi/tests/expr_3_test.go b/ruleapi/tests/expr_3_test.go
index e5406bd..628a3aa 100644
--- a/ruleapi/tests/expr_3_test.go
+++ b/ruleapi/tests/expr_3_test.go
@@ -15,7 +15,7 @@ func Test_3_Expr(t *testing.T) {
rs, _ := createRuleSession()
r1 := ruleapi.NewRule("r1")
r1.AddExprCondition("c1", "($.t1.p1 > $.t2.p1) && ($.t1.p2 > $.t2.p2)", nil)
- r1.SetAction(a3)
+ r1.SetActionService(createActionServiceFromFunction(t, a3))
r1.SetContext(actionCount)
rs.AddRule(r1)
diff --git a/ruleapi/tests/expr_4_test.go b/ruleapi/tests/expr_4_test.go
index 13d76bd..60b9f46 100644
--- a/ruleapi/tests/expr_4_test.go
+++ b/ruleapi/tests/expr_4_test.go
@@ -15,7 +15,7 @@ func Test_4_Expr(t *testing.T) {
rs, _ := createRuleSession()
r1 := ruleapi.NewRule("r1")
r1.AddExprCondition("c1", "($.t1.p1 > $.t2.p1) && (($.t1.p2 > $.t2.p2) && ($.t1.p3 == $.t2.p3))", nil)
- r1.SetAction(a4)
+ r1.SetActionService(createActionServiceFromFunction(t, a4))
r1.SetContext(actionCount)
rs.AddRule(r1)
diff --git a/ruleapi/tests/expr_5_test.go b/ruleapi/tests/expr_5_test.go
index f05ae32..3580beb 100644
--- a/ruleapi/tests/expr_5_test.go
+++ b/ruleapi/tests/expr_5_test.go
@@ -15,7 +15,7 @@ func Test_5_Expr(t *testing.T) {
rs, _ := createRuleSession()
r1 := ruleapi.NewRule("r1")
r1.AddExprCondition("c1", "(($.t1.p1 + $.t2.p1) == 5) && (($.t1.p2 > $.t2.p2) && ($.t1.p3 == $.t2.p3))", nil)
- r1.SetAction(a5)
+ r1.SetActionService(createActionServiceFromFunction(t, a5))
r1.SetContext(actionCount)
rs.AddRule(r1)
diff --git a/ruleapi/tests/expr_6_test.go b/ruleapi/tests/expr_6_test.go
index 680e1ad..cf3a9f0 100644
--- a/ruleapi/tests/expr_6_test.go
+++ b/ruleapi/tests/expr_6_test.go
@@ -22,7 +22,7 @@ func Test_6_Expr(t *testing.T) {
rs, _ := createRuleSession()
r1 := ruleapi.NewRule("r1")
r1.AddExprCondition("c1", "($.t1.p3 == $env['name_rules_test_6'])", nil)
- r1.SetAction(a6)
+ r1.SetActionService(createActionServiceFromFunction(t, a6))
r1.SetContext(actionCount)
rs.AddRule(r1)
diff --git a/ruleapi/tests/expr_7_test.go b/ruleapi/tests/expr_7_test.go
index a95089f..ded0e5c 100644
--- a/ruleapi/tests/expr_7_test.go
+++ b/ruleapi/tests/expr_7_test.go
@@ -24,7 +24,7 @@ func Test_7_Expr(t *testing.T) {
r1 := ruleapi.NewRule("r1")
r1.AddExprCondition("c1", "($.t1.p3 == $property['name'])", nil)
r1.AddExprCondition("c2", "($.t1.p1 == $property['age'])", nil)
- r1.SetAction(a7)
+ r1.SetActionService(createActionServiceFromFunction(t, a7))
r1.SetContext(actionCount)
rs.AddRule(r1)
diff --git a/ruleapi/tests/identifier_1_test.go b/ruleapi/tests/identifier_1_test.go
index 7dfc736..937f0e3 100644
--- a/ruleapi/tests/identifier_1_test.go
+++ b/ruleapi/tests/identifier_1_test.go
@@ -17,7 +17,8 @@ func Test_I1(t *testing.T) {
rule := ruleapi.NewRule("I1")
rule.AddCondition("I1_c1", []string{"t1.none", "t3.none"}, trueCondition, nil)
- rule.SetAction(i1_action)
+ rule.SetActionService(createActionServiceFromFunction(t, i1_action))
+
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/identifier_2_test.go b/ruleapi/tests/identifier_2_test.go
index 7e82a51..e823fdf 100644
--- a/ruleapi/tests/identifier_2_test.go
+++ b/ruleapi/tests/identifier_2_test.go
@@ -19,7 +19,7 @@ func Test_I2(t *testing.T) {
rule := ruleapi.NewRule("I21")
rule.AddCondition("I2_c1", []string{"t1.none", "t2.none"}, trueCondition, nil)
- rule.SetAction(i21_action)
+ rule.SetActionService(createActionServiceFromFunction(t, i21_action))
rule.SetPriority(1)
//rule.SetContext(actionMap)
rs.AddRule(rule)
@@ -27,7 +27,7 @@ func Test_I2(t *testing.T) {
rule1 := ruleapi.NewRule("I22")
rule1.AddCondition("I2_c2", []string{"t1.none", "t3.none"}, trueCondition, nil)
- rule1.SetAction(i22_action)
+ rule1.SetActionService(createActionServiceFromFunction(t, i22_action))
rule1.SetPriority(1)
//rule.SetContext(actionMap)
rs.AddRule(rule1)
@@ -35,7 +35,7 @@ func Test_I2(t *testing.T) {
rule2 := ruleapi.NewRule("I23")
rule2.AddCondition("I2_c3", []string{"t2.none", "t3.none"}, trueCondition, nil)
- rule2.SetAction(i23_action)
+ rule2.SetActionService(createActionServiceFromFunction(t, i23_action))
rule2.SetPriority(1)
//rule.SetContext(actionMap)
rs.AddRule(rule2)
@@ -43,7 +43,7 @@ func Test_I2(t *testing.T) {
rule3 := ruleapi.NewRule("I24")
rule3.AddCondition("I2_c4", []string{"t1.none", "t2.none", "t3.none"}, trueCondition, nil)
- rule3.SetAction(i24_action)
+ rule3.SetActionService(createActionServiceFromFunction(t, i24_action))
rule3.SetPriority(1)
//rule.SetContext(actionMap)
rs.AddRule(rule3)
diff --git a/ruleapi/tests/retract_1_test.go b/ruleapi/tests/retract_1_test.go
index 43d3f61..f83c762 100644
--- a/ruleapi/tests/retract_1_test.go
+++ b/ruleapi/tests/retract_1_test.go
@@ -22,7 +22,7 @@ func Test_Retract_1(t *testing.T) {
}
ruleActionCtx := make(map[string]string)
rule.SetContext(ruleActionCtx)
- rule.SetAction(assertAction)
+ rule.SetActionService(createActionServiceFromFunction(t, assertAction))
rule.SetPriority(1)
err = rs.AddRule(rule)
if err != nil {
diff --git a/ruleapi/tests/rtctxn_10_test.go b/ruleapi/tests/rtctxn_10_test.go
index 3b416ba..8b5e870 100644
--- a/ruleapi/tests/rtctxn_10_test.go
+++ b/ruleapi/tests/rtctxn_10_test.go
@@ -15,7 +15,7 @@ func Test_T10(t *testing.T) {
rule := ruleapi.NewRule("R10")
rule.AddCondition("R10_c1", []string{"t1.none", "t3.none"}, trueCondition, nil)
- rule.SetAction(r10_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r10_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_11_test.go b/ruleapi/tests/rtctxn_11_test.go
index 8d55c5f..fc1b69b 100644
--- a/ruleapi/tests/rtctxn_11_test.go
+++ b/ruleapi/tests/rtctxn_11_test.go
@@ -15,14 +15,14 @@ func Test_T11(t *testing.T) {
rule := ruleapi.NewRule("R11")
rule.AddCondition("R11_c1", []string{"t1.none"}, trueCondition, nil)
- rule.SetAction(r11_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r11_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
rule1 := ruleapi.NewRule("R112")
rule1.AddCondition("R112_c1", []string{"t1.none"}, trueCondition, nil)
- rule1.SetAction(r112_action)
+ rule1.SetActionService(createActionServiceFromFunction(t, r112_action))
rule1.SetPriority(1)
rs.AddRule(rule1)
t.Logf("Rule added: [%s]\n", rule1.GetName())
diff --git a/ruleapi/tests/rtctxn_12_test.go b/ruleapi/tests/rtctxn_12_test.go
index 111c149..0d41486 100644
--- a/ruleapi/tests/rtctxn_12_test.go
+++ b/ruleapi/tests/rtctxn_12_test.go
@@ -15,14 +15,14 @@ func Test_T12(t *testing.T) {
rule := ruleapi.NewRule("R12")
rule.AddCondition("R12_c1", []string{"t1.none", "t3.none"}, trueCondition, nil)
- rule.SetAction(r122_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r122_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
rule1 := ruleapi.NewRule("R122")
rule1.AddCondition("R122_c1", []string{"t1.none", "t3.none"}, trueCondition, nil)
- rule1.SetAction(r12_action)
+ rule1.SetActionService(createActionServiceFromFunction(t, r12_action))
rule1.SetPriority(1)
rs.AddRule(rule1)
t.Logf("Rule added: [%s]\n", rule1.GetName())
diff --git a/ruleapi/tests/rtctxn_13_test.go b/ruleapi/tests/rtctxn_13_test.go
index a09d402..5d5cf15 100644
--- a/ruleapi/tests/rtctxn_13_test.go
+++ b/ruleapi/tests/rtctxn_13_test.go
@@ -15,14 +15,14 @@ func Test_T13(t *testing.T) {
rule := ruleapi.NewRule("R13")
rule.AddCondition("R13_c1", []string{"t1.none", "t3.none"}, trueCondition, nil)
- rule.SetAction(r13_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r13_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
rule1 := ruleapi.NewRule("R132")
rule1.AddCondition("R132_c1", []string{"t3.none"}, trueCondition, nil)
- rule1.SetAction(r132_action)
+ rule1.SetActionService(createActionServiceFromFunction(t, r132_action))
rule1.SetPriority(2)
rs.AddRule(rule1)
t.Logf("Rule added: [%s]\n", rule1.GetName())
diff --git a/ruleapi/tests/rtctxn_14_test.go b/ruleapi/tests/rtctxn_14_test.go
index ae999a9..17ca089 100644
--- a/ruleapi/tests/rtctxn_14_test.go
+++ b/ruleapi/tests/rtctxn_14_test.go
@@ -15,14 +15,14 @@ func Test_T14(t *testing.T) {
rule := ruleapi.NewRule("R14")
rule.AddCondition("R14_c1", []string{"t1.none"}, trueCondition, nil)
- rule.SetAction(r14_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r14_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
rule1 := ruleapi.NewRule("R142")
rule1.AddCondition("R142_c1", []string{"t3.none"}, trueCondition, nil)
- rule1.SetAction(r142_action)
+ rule1.SetActionService(createActionServiceFromFunction(t, r142_action))
rule1.SetPriority(2)
rs.AddRule(rule1)
t.Logf("Rule added: [%s]\n", rule1.GetName())
diff --git a/ruleapi/tests/rtctxn_15_test.go b/ruleapi/tests/rtctxn_15_test.go
index 86e5aff..87031e5 100644
--- a/ruleapi/tests/rtctxn_15_test.go
+++ b/ruleapi/tests/rtctxn_15_test.go
@@ -18,7 +18,7 @@ func Test_T15(t *testing.T) {
rule := ruleapi.NewRule("R15")
rule.AddCondition("R15_c1", []string{"t1.none"}, trueCondition, nil)
- rule.SetAction(r15_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r15_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_16_test.go b/ruleapi/tests/rtctxn_16_test.go
index b89dac7..6278fe0 100644
--- a/ruleapi/tests/rtctxn_16_test.go
+++ b/ruleapi/tests/rtctxn_16_test.go
@@ -18,7 +18,7 @@ func Test_T16(t *testing.T) {
rule := ruleapi.NewRule("R16")
rule.AddCondition("R16_c1", []string{"t1.none"}, trueCondition, nil)
- rule.SetAction(r16_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r16_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_1_test.go b/ruleapi/tests/rtctxn_1_test.go
index 5ef571c..efca7a5 100644
--- a/ruleapi/tests/rtctxn_1_test.go
+++ b/ruleapi/tests/rtctxn_1_test.go
@@ -14,8 +14,8 @@ func Test_T1(t *testing.T) {
rs, _ := createRuleSession()
rule := ruleapi.NewRule("R1")
- rule.AddCondition("R1_c1", []string{"t1.none"}, trueCondition, t)
- rule.SetAction(emptyAction)
+ rule.AddCondition("R1_c1", []string{"t1.none"}, trueCondition, nil)
+ rule.SetActionService(createActionServiceFromFunction(t, emptyAction))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_2_test.go b/ruleapi/tests/rtctxn_2_test.go
index 3eafa24..af9891e 100644
--- a/ruleapi/tests/rtctxn_2_test.go
+++ b/ruleapi/tests/rtctxn_2_test.go
@@ -15,7 +15,7 @@ func Test_T2(t *testing.T) {
rule := ruleapi.NewRule("R2")
rule.AddCondition("R2_c1", []string{"t2.none"}, trueCondition, nil)
- rule.SetAction(emptyAction)
+ rule.SetActionService(createActionServiceFromFunction(t, emptyAction))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_3_test.go b/ruleapi/tests/rtctxn_3_test.go
index f0f22dc..38f3967 100644
--- a/ruleapi/tests/rtctxn_3_test.go
+++ b/ruleapi/tests/rtctxn_3_test.go
@@ -15,7 +15,7 @@ func Test_T3(t *testing.T) {
rule := ruleapi.NewRule("R3")
rule.AddCondition("R3_c1", []string{"t1.none"}, trueCondition, nil)
- rule.SetAction(R3_action)
+ rule.SetActionService(createActionServiceFromFunction(t, R3_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_4_test.go b/ruleapi/tests/rtctxn_4_test.go
index 64fca8c..fe58fcd 100644
--- a/ruleapi/tests/rtctxn_4_test.go
+++ b/ruleapi/tests/rtctxn_4_test.go
@@ -15,7 +15,7 @@ func Test_T4(t *testing.T) {
rule := ruleapi.NewRule("R4")
rule.AddCondition("R4_c1", []string{"t1.none"}, trueCondition, nil)
- rule.SetAction(r4_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r4_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_5_test.go b/ruleapi/tests/rtctxn_5_test.go
index b8b5981..718ad24 100644
--- a/ruleapi/tests/rtctxn_5_test.go
+++ b/ruleapi/tests/rtctxn_5_test.go
@@ -15,7 +15,7 @@ func Test_T5(t *testing.T) {
rule := ruleapi.NewRule("R5")
rule.AddCondition("R5_c1", []string{"t1.none"}, trueCondition, nil)
- rule.SetAction(r5_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r5_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_6_test.go b/ruleapi/tests/rtctxn_6_test.go
index 5de8501..66d5880 100644
--- a/ruleapi/tests/rtctxn_6_test.go
+++ b/ruleapi/tests/rtctxn_6_test.go
@@ -15,7 +15,7 @@ func Test_T6(t *testing.T) {
rule := ruleapi.NewRule("R6")
rule.AddCondition("R6_c1", []string{"t1.none"}, trueCondition, nil)
- rule.SetAction(r6_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r6_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_7_test.go b/ruleapi/tests/rtctxn_7_test.go
index 3d6c9ef..61b260b 100644
--- a/ruleapi/tests/rtctxn_7_test.go
+++ b/ruleapi/tests/rtctxn_7_test.go
@@ -15,7 +15,7 @@ func Test_T7(t *testing.T) {
rule := ruleapi.NewRule("R7")
rule.AddCondition("R7_c1", []string{"t1.none"}, trueCondition, nil)
- rule.SetAction(r7_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r7_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_8_test.go b/ruleapi/tests/rtctxn_8_test.go
index c8ec59b..48c9f81 100644
--- a/ruleapi/tests/rtctxn_8_test.go
+++ b/ruleapi/tests/rtctxn_8_test.go
@@ -16,7 +16,7 @@ func Test_T8(t *testing.T) {
rule := ruleapi.NewRule("R1")
rule.AddCondition("R1_c1", []string{"t1.none"}, trueCondition, nil)
rule.AddCondition("R1_c2", []string{}, falseCondition, nil)
- rule.SetAction(assertTuple)
+ rule.SetActionService(createActionServiceFromFunction(t, assertTuple))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rtctxn_9_test.go b/ruleapi/tests/rtctxn_9_test.go
index 6ca9be4..d51129b 100644
--- a/ruleapi/tests/rtctxn_9_test.go
+++ b/ruleapi/tests/rtctxn_9_test.go
@@ -15,7 +15,7 @@ func Test_T9(t *testing.T) {
rule := ruleapi.NewRule("R9")
rule.AddCondition("R9_c1", []string{"t1.none", "t3.none"}, trueCondition, nil)
- rule.SetAction(r9_action)
+ rule.SetActionService(createActionServiceFromFunction(t, r9_action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rules_1_test.go b/ruleapi/tests/rules_1_test.go
index b98c4fd..312a7fe 100644
--- a/ruleapi/tests/rules_1_test.go
+++ b/ruleapi/tests/rules_1_test.go
@@ -24,7 +24,7 @@ func Test_One(t *testing.T) {
//// rule 1
r1 := ruleapi.NewRule("R1")
r1.AddCondition("C1", []string{"t1"}, checkC1, nil)
- r1.SetAction(actionA1)
+ r1.SetActionService(createActionServiceFromFunction(t, actionA1))
r1.SetPriority(1)
r1.SetContext(actionMap)
@@ -33,7 +33,7 @@ func Test_One(t *testing.T) {
// rule 2
r2 := ruleapi.NewRule("R2")
r2.AddCondition("C2", []string{"t1"}, checkC2, nil)
- r2.SetAction(actionA2)
+ r2.SetActionService(createActionServiceFromFunction(t, actionA2))
r2.SetPriority(2)
r2.SetContext(actionMap)
@@ -42,7 +42,7 @@ func Test_One(t *testing.T) {
// rule 3
r3 := ruleapi.NewRule("R3")
r3.AddCondition("C3", []string{"t1"}, checkC3, nil)
- r3.SetAction(actionA3)
+ r3.SetActionService(createActionServiceFromFunction(t, actionA3))
r3.SetPriority(3)
r3.SetContext(actionMap)
diff --git a/ruleapi/tests/rules_2_test.go b/ruleapi/tests/rules_2_test.go
index 52dbfde..22c5136 100644
--- a/ruleapi/tests/rules_2_test.go
+++ b/ruleapi/tests/rules_2_test.go
@@ -35,7 +35,7 @@ func Test_Two(t *testing.T) {
rule.AddCondition("c1", []string{"n1"}, checkForBob, nil)
rule.AddCondition("c2", []string{"n1"}, checkForName, nil)
- rule.SetAction(checkForBobAction)
+ rule.SetActionService(createActionServiceFromFunction(t, checkForBobAction))
rule.SetContext(actionFireCount)
rs.AddRule(rule)
fmt.Printf("Rule added: [%s]\n", rule.GetName())
diff --git a/ruleapi/tests/rules_3_test.go b/ruleapi/tests/rules_3_test.go
index 0b54fe6..4ed5417 100644
--- a/ruleapi/tests/rules_3_test.go
+++ b/ruleapi/tests/rules_3_test.go
@@ -19,14 +19,14 @@ func Test_Three(t *testing.T) {
rule := ruleapi.NewRule("R3")
rule.AddCondition("R3c1", []string{"t1.id"}, trueCondition, nil)
- rule.SetAction(r3action)
+ rule.SetActionService(createActionServiceFromFunction(t, r3action))
rule.SetPriority(1)
rs.AddRule(rule)
t.Logf("Rule added: [%s]\n", rule.GetName())
rule1 := ruleapi.NewRule("R32")
rule1.AddCondition("R32c1", []string{"t1.p1"}, r3Condition, nil)
- rule1.SetAction(r32action)
+ rule1.SetActionService(createActionServiceFromFunction(t, r32action))
rule1.SetPriority(1)
rule1.SetContext(actionMap)
rs.AddRule(rule1)
diff --git a/ruleapi/tests/rules_4_test.go b/ruleapi/tests/rules_4_test.go
index fc1eeb2..4e9c4ac 100644
--- a/ruleapi/tests/rules_4_test.go
+++ b/ruleapi/tests/rules_4_test.go
@@ -16,7 +16,7 @@ func Test_Four(t *testing.T) {
// create rule
r1 := ruleapi.NewRule("Rule1")
r1.AddCondition("r1c1", []string{"t1.none", "t2.none"}, trueCondition, nil)
- r1.SetAction(r1Action)
+ r1.SetActionService(createActionServiceFromFunction(t, r1Action))
// create tuples
t1, _ := model.NewTupleWithKeyValues("t1", "one") // No TTL
t2, _ := model.NewTupleWithKeyValues("t2", "two") // TTL is 0
@@ -31,8 +31,8 @@ func Test_Four(t *testing.T) {
// Test1: add r1 and assert t1 & t2; rule action SHOULD be fired
addRule(t, rs, r1)
- assert(assertCtx, rs, t1)
- assert(assertCtx, rs, t2)
+ assertWithCtx(assertCtx, rs, t1)
+ assertWithCtx(assertCtx, rs, t2)
actionFired, _ := assertCtxValues["actionFired"].(string)
if actionFired != "FIRED" {
t.Log("rule action SHOULD be fired")
@@ -42,7 +42,7 @@ func Test_Four(t *testing.T) {
// Test2: remove r1 and assert t2; rule action SHOULD NOT be fired
deleteRule(t, rs, r1)
assertCtxValues["actionFired"] = "NOTFIRED"
- assert(assertCtx, rs, t2)
+ assertWithCtx(assertCtx, rs, t2)
actionFired, _ = assertCtxValues["actionFired"].(string)
if actionFired != "NOTFIRED" {
t.Log("rule action SHOULD NOT be fired")
@@ -53,7 +53,7 @@ func Test_Four(t *testing.T) {
addRule(t, rs, r1)
rs.ReplayTuplesForRule(r1.GetName())
assertCtxValues["actionFired"] = "NOTFIRED"
- assert(assertCtx, rs, t2)
+ assertWithCtx(assertCtx, rs, t2)
actionFired, _ = assertCtxValues["actionFired"].(string)
if actionFired != "FIRED" {
t.Log("rule action SHOULD be fired")
@@ -77,7 +77,7 @@ func deleteRule(t *testing.T, rs model.RuleSession, rule model.Rule) {
t.Logf("[%s] Rule[%s] deleted. \n", time.Now().Format("15:04:05.999999"), rule.GetName())
}
-func assert(ctx context.Context, rs model.RuleSession, tuple model.Tuple) {
+func assertWithCtx(ctx context.Context, rs model.RuleSession, tuple model.Tuple) {
assertCtxValues := ctx.Value("values").(map[string]interface{})
t, _ := assertCtxValues["test"].(*testing.T)
err := rs.Assert(ctx, tuple)
diff --git a/scripts/README.md b/scripts/README.md
deleted file mode 100755
index 6cdeff0..0000000
--- a/scripts/README.md
+++ /dev/null
@@ -1,37 +0,0 @@
-## Sanity Testing
-
-* There is a shell script file `run_sanitytest.sh` that performs sanity testing against rules/examples and generates html report.
-
-* This script file checks for all available `sanity.sh` files inside rules/examples and run tests against individual `sanity.sh` file
-
-
-* To run sanity tests
-
-```
-cd $GOPATH/src/github.com/project-flogo/rules/scripts
-./run_sanitytest.sh
-```
-
-* Testcase status of each example is updated in the html report and test report is made available in scripts folder.
-
-
-### Contributing
-
-If you're adding a new rules example, optionally you can add sanity test file with name `sanity.sh`. Below is the template used for creating test file.
-
-```
-#!/bin/bash
-
-function get_test_cases {
- local my_list=( testcase1 )
- echo "${my_list[@]}"
-}
-
-function testcase1 {
-# Add detailed steps to execute the test case
-}
-```
-Sample sanity test file can be found at
-```
-$GOPATH/src/github.com/project-flogo/rules/examples/flogo/simple/sanity.sh
-```
\ No newline at end of file
diff --git a/scripts/run_sanitytest.sh b/scripts/run_sanitytest.sh
deleted file mode 100755
index f10de76..0000000
--- a/scripts/run_sanitytest.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/bash
-
-RULESPATH=$GOPATH/src/github.com/project-flogo/rules
-export FILENAME="RulesSanityReport.html"
-HTML="
-
Summary
Number of test cases passed | |
Number of test cases failed | |
Total test cases | |
"
-
-echo $HTML >> $RULESPATH/scripts/$FILENAME
-PASS_COUNT=0 FAIL_COUNT=0
-
-# Fetch list of sanity.sh files in examples folder
-function get_sanitylist()
-{
- cd $RULESPATH/examples
- find | grep sanity.sh > file.txt
- readarray -t array < file.txt
- for EXAMPLE in "${array[@]}"
- do
- echo "$EXAMPLE"
- RECIPE=$(echo $EXAMPLE | sed -e 's/\/sanity.sh//g' | sed -e 's/\.\///g' | sed -e 's/\//-/g')
- execute_testcase
- done
-}
-
-# Execute and obtain testcase status (pass/fail)
-function execute_testcase()
-{
- echo $RECIPE
- source $EXAMPLE
- TESTCASE_LIST=($(get_test_cases))
- sleep 10
- for ((i=0;i < ${#TESTCASE_LIST[@]};i++))
- do
- TESTCASE=$(${TESTCASE_LIST[i]})
- sleep 10
- if [[ $TESTCASE == *"PASS"* ]]; then
- echo "$RECIPE":"Passed"
- PASS_COUNT=$((PASS_COUNT+1))
- sed -i "s/<\/tr> <\/table>/$RECIPE<\/td> | ${TESTCASE_LIST[i]}<\/td> | PASS<\/td><\/tr><\/tr> <\/table>/g" $RULESPATH/scripts/$FILENAME
- else
- echo "$RECIPE":"Failed"
- FAIL_COUNT=$((FAIL_COUNT+1))
- sed -i "s/<\/tr> <\/table>/ |
$RECIPE<\/td> | ${TESTCASE_LIST[i]}<\/td> | FAIL<\/td><\/tr><\/tr> <\/table>/g" $RULESPATH/scripts/$FILENAME
- fi
- done
-}
-
-get_sanitylist
-
-# Update testcase count in html report
-sed -i s/"passed <\/td> | "/"passed <\/td> | $PASS_COUNT"/g $RULESPATH/scripts/$FILENAME
-sed -i s/"failed <\/td> | "/"failed <\/td> | $FAIL_COUNT"/g $RULESPATH/scripts/$FILENAME
-sed -i s/"cases<\/td> | "/"cases<\/td> | $((PASS_COUNT+FAIL_COUNT))"/g $RULESPATH/scripts/$FILENAME
\ No newline at end of file
|