Expand my Community achievements bar.

How write unit test case for sling servlet which have sql query code

Avatar

Level 1

Hi, 

How I can write unit test case for sling servlet which have sql query code. I have tried to write unit test but that is not working kindly look below is the sling servlet code and unit test code share what's wrong I am doing

# Servlet


import java.io.IOException;
import java.util.Iterator;
import java.util.Objects;

import javax.servlet.Servlet;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.wcm.api.Page;

@component(service = Servlet.class, property = { Constants.SERVICE_DESCRIPTION + "= Global Search Servlet",
"sling.servlet.methods=" + HttpConstants.METHOD_GET, "sling.servlet.paths=" + "/bin/mysite/globalsearch" })
public class GlobalSearchServlet extends SlingAllMethodsServlet {

private static final long serialVersionUID = 1L;
private static final transient Logger LOG = LoggerFactory.getLogger(GlobalSearchServlet.class);

@Override
public void doGet(SlingHttpServletRequest req, SlingHttpServletResponse res) {
ResourceResolver resourceResolver = req.getResourceResolver();
String keyword = null;
res.setContentType("application/json");
res.setCharacterEncoding("UTF-8");
JSONArray jsonArray = new JSONArray();
try {
keyword = req.getParameter("q");
if (Objects.nonNull(keyword)) {
String query = "select * from [cq:Page] as a where contains(*, '"+keyword+"') and isdescendantnode(a, '/content/mysite')";
Iterator<Resource> results = resourceResolver.findResources(query, "sql");
while (results.hasNext()) {
JSONObject object = new JSONObject();
Resource resource = results.next();
Page page =resource.adaptTo(Page.class);
object.put("path", page.getPath());
object.put("title", page.getTitle());
jsonArray.put(object);
}
} else {
LOG.info("Query Parameter is missing in request.");
}
res.getWriter().print(jsonArray);
} catch (IOException | JSONException ioe) {
LOG.error("Error occurred. Error ", ioe);
}
}
}

 

 

#Unit Test

 


import static org.junit.Assert.assertEquals;
import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.wcm.testing.mock.aem.junit.AemContext;

public class GlobalSearchServletTest {

private static final String MOCK_JSON = "/globalsearch/globalsearch.json";

@Deleted Account
public final AemContext context = new AemContext(ResourceResolverType.JCR_OAK);

static final Logger LOG = LoggerFactory.getLogger(GlobalSearchServletTest.class);


@Before
public void setup() {
context.load().json(MOCK_JSON, "/content");
}


@test
public void testDoGet() throws ServletException, IOException, JSONException {
GlobalSearchServlet servlet = new GlobalSearchServlet();

context.currentPage(context.pageManager().getPage("/content/mysite"));
context.currentResource(context.resourceResolver().getResource("/content/mysite"));
context.requestPathInfo().setResourcePath("/content/mysite");

MockSlingHttpServletRequest request = context.request();
request.setQueryString("q=the");

MockSlingHttpServletResponse reponse = context.response();

servlet.doGet(request, reponse);

System.out.println("RESPONSE=="+context.response().getOutputAsString());


LOG.info("output = {}", context.response().getOutputAsString());
assertEquals("[{\"message\":\"0 results found\",\"status\":false}]",context.response().getOutputAsString());
}

}

11 Replies

Avatar

Employee Advisor

Can you share details what's not working? Do you get an exception? Is the testcase failing on an assert?

Avatar

Level 1

I am not getting any exception But while running the unit test case I am not getting any response or to be more precise not getting any result from query execution

String query = "select * from [cq:Page] as a where contains(*, '"+keyword+"') and isdescendantnode(a, '/content/mysite')";
Iterator<Resource> results = resourceResolver.findResources(query, "sql");

 

Below is the page json. Can you share what's wrong I am doing here or it not possible? 

 

{
"jcr:content": "nt:unstructured",
"mysite": {
"jcr:primaryType": "cq:Page",
"jcr:content": {
"jcr:primaryType": "cq:PageContent",
"jcr:title": "the mysite page"
},
"dashboard": {
"jcr:primaryType": "cq:Page",
"jcr:content": {
"jcr:primaryType": "cq:PageContent",
"jcr:title": "the dashboard page"
},
"homepage": {
"jcr:primaryType": "cq:Page",
"jcr:content": {
"jcr:primaryType": "cq:PageContent",
"jcr:title": "the home page"
},
"userpage": {
"jcr:primaryType": "cq:Page",
"jcr:content": {
"jcr:primaryType": "cq:PageContent",
"jcr:title": "the user page"
}
},
"productpage": {
"jcr:primaryType": "cq:Page",
"jcr:content": {
"jcr:primaryType": "cq:PageContent",
"jcr:title": "the product page"
}
}
}
}
}
}

 

Avatar

Employee Advisor
Both the testcase and the test data look reasonable, and i don't understand what could be wrong here. Can you execute that testcase in an IDE, set a breakpoint and inspect in the debugger the loaded repository structure?

Avatar

Level 1
Can you advice where i can put logger to check what the content repository loaded?

Avatar

Employee Advisor
In eclipse when I set a breakpoint in the testcase and I can drill down into all available objects in the current scope, and if you are going down in the AemContext object you can find the content of the repo. A bit cumbersome, but works. I am not aware of any convenience method to dump the content of the repository of the AemContext.

Avatar

Community Advisor

I have the same issue -

while I can see the resource created with context.load().json(inputStream, "/content");

 

Issue is when executing Iterator<Resource> resources = resolver.findResources(query, "JCR-SQL2")
I am not getting the resource in iterator.

@Jörg_Hoh

Avatar

Level 1

@Kamal_Kishor were you able to resolve this? I am facing similar issue.

Avatar

Level 1

I've found that when using JCR_OAK and the findResources() method, it works once you've committed the loaded data from the JSON:

@Before
public void setup() {
    context.load().json(MOCK_JSON, "/content");
    context.resourceResolver().commit();
}

Avatar

Level 1

1. Create AemContext object by setting the ResourceResolverType to JCR_OAK

public AemContext context = new AemContext(ResourceResolverType.JCR_OAK);

2. On loading the JSON, commit the resource resolver

context.load().json(PAGE_JSON, PAGE);
context.resourceResolver().commit();

 

Avatar

Employee

For future folks, here is the solution that worked for me

 

Add an inner class like below in your test class

 

public class MockFindResourcesHandlerImpl implements MockFindResourcesHandler {

@Nullable
@Override
public Iterator<Resource> findResources(@NotNull String query, String language) {
// NOTE: In my case I only need one mockedResource,
return Collections.singletonList(mockedResource).iterator();
}
}

How I mocked the resource

// NOTE: Before this line I have loaded the pages to context object through load().json(K,T)
mockedResource
= context.resourceResolver().getResource(ROOT_PATH);

 

Finally, How to use it

// Add below to the BeforeEach method at end (once all context initialization is done)
MockFindQueryResources.addFindResourceHandler(context.resourceResolver(), new MockFindResourcesHandlerImpl());
I Used => ResourceResolverType.RESOURCERESOLVER_MOCK

 

Packages are here:

import org.apache.sling.testing.resourceresolver.MockFindQueryResources;
import org.apache.sling.testing.resourceresolver.MockFindResourcesHandler;



Thank you

- Harish Malineni