Search code examples
mockingosgiadobeaemsling

AEM 6.3, wcm.io: sling MockResource null in @Activate method


I have an OSGI service that has an @Activate method. In the activate method I call a method called 'buildTitleList' where I query some resources (pages) and gather their titles in a list. This code is working in a running environment but not in my unit tests.

I create the page in my context the following way:

aemContext.create().page("/content/test-page', "/apps/platform-company/templates/home-page", "test-tile");

If I debug my unit test I can see that the resources I query in the 'buildTitleList' are empty (note: I am sure that my path is correct)

When I call the 'buildTitleList' directly in my unit test it DOES work. Is this normal behaviour, is there a way to make sure the @Activate method also can see the newly created page in the context?

Test:

@Test
public void checkTitles() {
    TitleService titleService = context.getService(TitleService.class);
    System.out.println(); //If I set a breakpoint here and look into the TitleService instance the list of titles is still 0
}

TitleService:

public class TitleService {

    private List<String> titles;

    public TitleService() {
        this.titles = new CopyOnWriteArrayList<>();
    }

    ...
    public void buildTitleList() throws RepositoryException, LoginException, WCMException {

        // Gather title code here (incl. newlist). This works on a running instance but the resoure is always null when calle from within an @Activa method

        this.titles.addAll(newlist);

    }
    ...

    @Activate
    protected void Activate() {
        buildTitleList();       
    }
}

Setup code:

...

public static AemContext getAemContext(RunMode runMode) {
    if (aemContext != null) {
        aemContext.runMode(runMode.getValue());
        return aemContext;
    } else {
        aemContext = newAemContext();
        aemContext.runMode(runMode.getValue());
        return aemContext;
    }
}

public static AemContext newAemContext() {
    return new AemContextBuilder()
            .resourceResolverType(ResourceResolverType.JCR_MOCK)
            .afterSetUp(SETUP_CALLBACK)
            .build();
}

private static final AemContextCallback SETUP_CALLBACK = aemContext -> {

    // context path strategy
    MockCAConfig.contextPathStrategyRootTemplate(aemContext, Template.HOME_PAGE.getValue());

    // register sling models
    ...

    aemContext.registerInjectActivateService(new AutoClosableResourceResolverFactory());
    aemContext.registerInjectActivateService(new TitleService());

    createBlueprintPages(aemContext);

    TestInformation testInformation = TestInformation.getInstance();

    for (TestLiveCopyInformation info : testInformation.getLiveCopyInformationList()) {
        aemContext.load().json(info.getResourcePath(), info.getContentRoot() + "/" + info.getLanguage().getIsoCode());
    }

    // set default current page
    aemContext.currentPage(CONTENT_ROOT);

};

...

Rule in test:

@Rule
public final AemContext context = AppAemContext.getAemContext(RunMode.AUTHOR);

Solution

  • Thanks to @Jens I found out that ResourceResolver now implement the AutoClosable interface (since 6.2, we are using 6.3.1.2) so I could remove our custom factory and use the default ResourceResolverFactory, everything is working fine now.