Write your first custom Rule using the Fluent Rules SDK (Hello World)
Author:
Lesley Dean
Changed on:
1 July 2024
Key Points
- A step-by-Step guide to creating your first custom Rule to log "Hello World"
Prerequisites
Steps
Overview
`LogAction`.A `LogAction` creates an `ORCHESTRATION_AUDIT` Event which can be retrieved using the Event API.
Prerequisites
- A fully setup and functioning Fluent Account
- Setup your Development Environment
- Create a new Rules Plugin Project
- If you are using a JDK version higher than JDK 8 (e.g: JDK 17), (Optional) Update your Plugin Project for JDK 17+
Step 1: Create a new Rule class
- SendEventAction, which produces events to be executed either inline to the current execution, separately in another workflow, or on a scheduled date and time.
- MutateAction, which creates or updates entities within the platform.
- WebhookAction, which sends an Event payload to an external endpoint.
- LogAction, which creates custom orchestration audit event.
Read more about Rule Actions here.
For this example, we will use the simplest action for our rule - LogAction.
- Create a new Java class in the
`rule`folder of your Plugin Project.
For example:`src/main/java/com/acme/rule` - Name the class
`LogHelloWorld.java` - Implement the
`com.fluentretail.rubix.v2.rule.Rule`interface, and implement the`run`method.
Note: Make sure to fully qualify the name of the context parameter:`run(C context)` - Annotate the Rule class with the
`@RuleInfo`annotation.
You will need to import`com.fluentretail.rubix.rule.meta.RuleInfo`- Set the
`name`field of the`@RuleInfo`to "LogHelloWorld" - Set the
`description`field to "Say Hello to the World"
- Set the
- Inside the
`run`method, produce a`LogAction`by accessing the`ActionFactory`on the incoming`context`:`context.action().log();`- Set the
`message`parameter to "Hello World" - Set the
`detailedMessage`parameter to "This is a log message that says Hello World" - Set the
`attributes`parameter to an empty ArrayList:`new ArrayList<>()`
- Set the
Step 2: Create a Unit Test
- Create a new JUnit Test class in the
`rule`folder under your`src/test/java`.
For example:`src/test/java/com/acme/rule` - Name the class
`LogHelloWorldTest.java` - Add the following private fields to the Test class:
- Add a new private final instance of the rule under test:
`private final LogHelloWorld rule = new LogHelloWorld();` - Add an AutoClosable to manage the mock object lifecycle:
`private AutoCloseable mocks;` - Add a Mock for the Rule Context:
`private Context context;` - Add a Mock for the ActionFactory:
`private ActionFactory actionFactory;`
- Add a new private final instance of the rule under test:
- Add a Test
`setUp`method, annotated with`@Before`:- Initialise the mocks:
`mocks = MockitoAnnotations.openMocks(this);` - Setup the Context ActionFactory stub:
`when(context.action()).thenReturn(actionFactory);`
- Initialise the mocks:
- Add a Test
`tearDown`method, annotated with`@After`:- Close the mocks:
`mocks.close();`
- Close the mocks:
- Create a new Test method called
`run_producesHelloWorldLog`:`@Test public void run_producesHelloWorldLog()`- Call the Rule's
`run`method:`rule.run(context);` - Verify that a single
`LogAction`was produced with a message equal to "Hello World":`verify(actionFactory, times(1)).log(eq("Hello World"), anyString(), anyList());`
- Call the Rule's
Step 3: Create an Executor Test
- Create another new JUnit Test class in the
`rule`folder under your`src/test/java`.
For example:`src/test/java/com/acme/rule` - Name the class
`LogHelloWorldExecutorTest.java` - Add the following private fields to the Test class:
- Add a new constant field to hold the Order Id:
`private static final String ORDER_ID = "123";` - Add a new constant field to hold the Order Ref:
`private static final String ORDER_REF = "HD_123";` - Add a private TestExecutor field:
`private TestExecutor executor;` - Add a private Event field:
`private Event event;`
- Add a new constant field to hold the Order Id:
- Add a Test
`setUp`method, annotated with`@Before`:- Use the RubixEntity builder to create an instance of an Entity to simulate an Order record:
`RubixEntity entity = RubixEntity.builder()`:- Set the entityType:
`.entityType("ORDER")` - Set the id:
`.id(ORDER_ID)` - Set the ref:
`.ref(ORDER_REF)` - Set the status:
`.status("BOOKED")` - Set the type:
`.type("HD")` - Set the flexType:
`.flexType("ORDER::HD")` - Set the flexVersion:
`.flexVersion(1)` - Build the instance:
`.build();`
- Set the entityType:
- Use the Event builder to create an instance of an Event to trigger the Workflow:
`event = Event.builder()`- Set the retailerId:
`.retailerId("1")` - Set the entityId:
`.entityId(entity.getId())` - Set the entityRef:
`.entityRef(entity.getRef())` - Set the entityType:
`.entityType(entity.getEntityType())` - Set the name:
`.name("test-event")` - Build the instance:
`.build();`
- Set the retailerId:
- Create an instance of a Ruleset, passing in the Event and the Rule name:
`RuleSet ruleSet = ruleSet(event, ruleInstance(LogHelloWorld.class.getSimpleName()));` - Use the TestExecutor builder to create an instance of the TextExecutor:
`executor = TestExecutor.builder()`- Set the rule:
`.rule(LogHelloWorld.class)` - Set the ruleset:
`.ruleset(ruleSet)` - Set the entity:
`.entity(entity)` - Build the instance:
`.build();`
- Set the rule:
- Use the RubixEntity builder to create an instance of an Entity to simulate an Order record:
- Create a new Test method called
`run_producesLogEvent`:`@Test public void run_producesLogEvent()`- Call the Executor's
`execute`method:`TestContext testContext = executor.execute(event);` - Assert a single LogAction was produced:
`assertEquals(1, testContext.countActionsOfType(TestContext.LogAction.class));`
- Call the Executor's
