Expand my Community achievements bar.

Guidelines for the Responsible Use of Generative AI in the Experience Cloud Community.
SOLVED

Unit test Sling Event Handler

Avatar

Level 4

 

Hi,

I would like to test the "event_filter" path behavior , specific to if allowed path replication event fired then event handler gets executed vs replication event fired on non-allowed path, event handler does not get executed. This question is more of how I test event handler getting executed only on specific path defined by EVENT_FITLER.

 

I appreciate any help!

 

Thanks,

Sri

 

 



import com.day.cq.replication.ReplicationAction;
import com.day.cq.replication.ReplicationActionType;
import com.day.cq.wcm.api.Page;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.settings.SlingSettingsService;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Event handler for handling the replication of disclaimer content.
 * setting configuration policy to REQUIRE to ensure that the configuration is available only in author instance
 * (runmodes) and code executed in author instance not on publish instances.
 *
 */
@Component(service = EventHandler.class,
        immediate = true,
        property = {
                EventConstants.EVENT_TOPIC +"=" + ReplicationAction.EVENT_TOPIC,
                EventConstants.EVENT_FILTER +"=(paths=/content/siteallowed/*)"
        },
       configurationPolicy = ConfigurationPolicy.REQUIRE)
public class PublicationEventHandler implements EventHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(PublicationEventHandler.class);

 

    public static final String CONTENT_JOB_TOPIC = "CONTENT-JOB-TOPIC";

    @reference
    private ResourceResolverFactory resourceResolverFactory;

    @reference
    private JobManager jobManager;

    /**
     * Handles the event of clearing the cache whenever a page replication event occurs.
     */
    public void handleEvent(Event event) {
        try {
            ReplicationAction action = ReplicationAction.fromEvent(event);

            if (action != null) {

                final Map<String, Object> props = new HashMap<>();
                props.put("path", action.getPath());

                jobManager.addJob(CONTENT_JOB_TOPIC, props);


                 LOGGER.info("Replication action {} occured on {} ", action.getType().getName(), action.getPath());
            }
        } catch(Exception e) {
            LOGGER.error("Error occurred while handling the event PublicationEventHandler", e);
        }
    }

}

 

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

1 Accepted Solution

Avatar

Correct answer by
Employee Advisor

If I understand the OP correct, they want to test the FILTER_PATH behavior, that the filter is invoked correctly when a matching path is provided; and that the code is not invoked when a non-matching path is provided.

 

Your sample code hardwires that decision; if I change the FILTER_PATH parameter in the production code to something else, the unit test still passes.

View solution in original post

4 Replies

Avatar

Community Advisor

Hi @sreedobe 

Here you can check sample setup Generated by ChatGPT

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------

 

To write a JUnit test for the PublicationEventHandler class in AEM, you can use JUnit 4, Mockito, and AEM Mocks provided by the wcm.io AEM Mocks library. Here's a step-by-step guide to set up and write the test:

 

Dependencies

Make sure you have the following dependencies in your pom.xml:

<dependencies>
    <!-- JUnit and Mockito -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>3.11.2</version>
        <scope>test</scope>
    </dependency>
    <!-- AEM Mocks -->
    <dependency>
        <groupId>io.wcm.testing.aem-mock</groupId>
        <artifactId>aem-mock-core</artifactId>
        <version>2.8.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

 

JUnit Test Class

Here is the JUnit test class for PublicationEventHandler:

import com.day.cq.replication.ReplicationAction;
import com.day.cq.replication.ReplicationActionType;
import io.wcm.testing.mock.aem.junit.AemContext;
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.event.jobs.JobManager;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.osgi.service.event.Event;

import java.util.HashMap;
import java.util.Map;

import static org.mockito.Mockito.*;

public class PublicationEventHandlerTest {

    @Rule
    public final AemContext context = new AemContext();

    @Mock
    private JobManager jobManager;

    private PublicationEventHandler eventHandler;

    @Before
    public void setUp() {
        MockitoAnnotations.openMocks(this);
        eventHandler = new PublicationEventHandler();
        context.registerService(JobManager.class, jobManager);
        context.registerInjectActivateService(eventHandler);
    }

    @Test
    public void testHandleEvent() {
        // Prepare mock event
        String path = "/content/siteallowed/test-page";
        Map<String, Object> eventProps = new HashMap<>();
        eventProps.put("path", path);
        Event mockEvent = new Event(ReplicationAction.EVENT_TOPIC, eventProps);

        ReplicationAction mockAction = mock(ReplicationAction.class);
        when(mockAction.getType()).thenReturn(ReplicationActionType.ACTIVATE);
        when(mockAction.getPath()).thenReturn(path);

        // Mock static method ReplicationAction.fromEvent
        mockStatic(ReplicationAction.class);
        when(ReplicationAction.fromEvent(mockEvent)).thenReturn(mockAction);

        // Call the handleEvent method
        eventHandler.handleEvent(mockEvent);

        // Verify that jobManager.addJob was called with the correct parameters
        Map<String, Object> jobProps = new HashMap<>();
        jobProps.put("path", path);
        verify(jobManager, times(1)).addJob(PublicationEventHandler.CONTENT_JOB_TOPIC, jobProps);

        // Verify that the static method was called
        verifyStatic(ReplicationAction.class, times(1));
        ReplicationAction.fromEvent(mockEvent);
    }

    @Test
    public void testHandleEvent_NullAction() {
        // Prepare mock event
        Event mockEvent = new Event(ReplicationAction.EVENT_TOPIC, new HashMap<>());

        // Mock static method ReplicationAction.fromEvent to return null
        mockStatic(ReplicationAction.class);
        when(ReplicationAction.fromEvent(mockEvent)).thenReturn(null);

        // Call the handleEvent method
        eventHandler.handleEvent(mockEvent);

        // Verify that jobManager.addJob was not called
        verify(jobManager, times(0)).addJob(anyString(), anyMap());

        // Verify that the static method was called
        verifyStatic(ReplicationAction.class, times(1));
        ReplicationAction.fromEvent(mockEvent);
    }
}

 

Explanation

  1. Dependencies: Ensure you have the required dependencies for JUnit, Mockito, and AEM Mocks.

  2. Test Setup:

    • @Rule: Sets up the AEM context for testing.
    • @Mock: Mocks the JobManager service.
    • setUp(): Initializes the mocks and registers the services and the event handler.
  3. Tests:

    • testHandleEvent(): Tests the handleEvent method for a valid event. It mocks the ReplicationAction.fromEvent method to return a mock ReplicationAction and verifies that jobManager.addJob is called with the correct parameters.
    • testHandleEvent_NullAction(): Tests the handleEvent method for a case where ReplicationAction.fromEvent returns null. It verifies that jobManager.addJob is not called.

Mocking Static Methods

Note that mocking static methods with Mockito requires using the mockito-inline dependency or PowerMockito. In this example, I've used the standard approach. If you need to mock static methods, add the following dependency:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.11.2</version>
    <scope>test</scope>
</dependency>

And replace the mockStatic and verifyStatic methods with appropriate usage as per mockito-inline documentation.

 

 

 



Arun Patidar

Avatar

Correct answer by
Employee Advisor

If I understand the OP correct, they want to test the FILTER_PATH behavior, that the filter is invoked correctly when a matching path is provided; and that the code is not invoked when a non-matching path is provided.

 

Your sample code hardwires that decision; if I change the FILTER_PATH parameter in the production code to something else, the unit test still passes.

Avatar

Employee Advisor

 

This parameter is used by the runtime (OSGI events) to decide if your code is going to be invoked. That means if you want to test that you have the correct parameters provided to the service you have to have a OSGI runtime running. 

That's rather a task for an integration test; unit tests are less suitable, as you would need to startup a OSGI runtime for it. Possible, but I don't know of any unittest framework which does that for you.

 

On the other hand side: Isn't this a functionality of the framework and you are testing that the framework does the right job?