/*
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2017 Adobe
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.adobe.acs.commons.wcm.notifications.impl;
import com.day.cq.wcm.api.NameConstants;
import io.wcm.testing.mock.aem.junit.AemContext;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.settings.SlingSettingsService;
import org.apache.sling.testing.mock.osgi.MockEventAdmin;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.junit.SlingContext;
import org.apache.sling.testing.mock.sling.services.MockSlingSettingService;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import static org.junit.Assert.*;
import static com.day.cq.wcm.api.NameConstants.NT_PAGE;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
import static org.hamcrest.text.StringContainsInOrder.stringContainsInOrder;
public class SystemNotificationsImplTest {
@Rule
public AemContext aemContext = new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);
private SystemNotificationsImpl notifications = new SystemNotificationsImpl();
private ResourceResolver resourceResolver;
private Calendar zeroHour;
@Before
public void setup() {
resourceResolver = aemContext.resourceResolver();
zeroHour = Calendar.getInstance();
zeroHour.setTime(new Date(0));
}
@Test
public void testOnPublish() {
aemContext.registerInjectActivateService(notifications);
assertEquals(0, aemContext.getServices(EventHandler.class, null).length);
assertEquals(0, aemContext.getServices(Filter.class, null).length);
}
@Test
public void testOnAuthorNoNotifications() {
setAuthorRunmode();
aemContext.registerInjectActivateService(notifications);
assertEquals(1, aemContext.getServices(EventHandler.class, null).length);
assertEquals(0, aemContext.getServices(Filter.class, null).length);
}
@Test
public void testOnAuthorEmptyNotificationsFolder() throws Exception {
setAuthorRunmode();
aemContext.build().
resource("/etc/acs-commons/notifications", JCR_PRIMARYTYPE, NT_PAGE).
resource("jcr:content", JCR_PRIMARYTYPE, NT_UNSTRUCTURED);
commit();
aemContext.registerInjectActivateService(notifications);
assertEquals(1, aemContext.getServices(EventHandler.class, null).length);
assertEquals(0, aemContext.getServices(Filter.class, null).length);
aemContext.create().resource("/etc/acs-commons/notifications/first");
commit();
sendEvent();
assertEquals(1, aemContext.getServices(Filter.class, null).length);
notifications.deactivate(aemContext.componentContext());
assertEquals(0, aemContext.getServices(Filter.class, null).length);
assertEquals(0, aemContext.getServices(EventHandler.class, null).length);
}
@Test
public void testOnAuthorPopulatedNotificationsFolder() throws Exception {
setAuthorRunmode();
createEnabledNotification();
aemContext.registerInjectActivateService(notifications);
assertEquals(1, aemContext.getServices(EventHandler.class, null).length);
assertEquals(1, aemContext.getServices(Filter.class, null).length);
// then remove the resource
delete("/etc/acs-commons/notifications/enabled");
commit();
sendEvent();
assertEquals(0, aemContext.getServices(Filter.class, null).length);
notifications.deactivate(aemContext.componentContext());
assertEquals(0, aemContext.getServices(Filter.class, null).length);
assertEquals(0, aemContext.getServices(EventHandler.class, null).length);
}
@Test
public void testFilter() throws Exception {
setAuthorRunmode();
createEnabledNotification();
aemContext.registerInjectActivateService(notifications);
aemContext.request().setResource(aemContext.resourceResolver().getResource("/"));
notifications.doFilter(aemContext.request(), aemContext.response(), outputChain);
String output = aemContext.response().getOutputAsString();
assertThat(output, stringContainsInOrder(Arrays.asList("<html><body>", "<script>", "</script>", "</body></html>")));
}
@Test
public void testFilterOnNotificationPage() throws Exception {
setAuthorRunmode();
createEnabledNotification();
aemContext.registerInjectActivateService(notifications);
aemContext.request().setResource(aemContext.resourceResolver().getResource("/etc/acs-commons/notifications"));
notifications.doFilter(aemContext.request(), aemContext.response(), outputChain);
String output = aemContext.response().getOutputAsString();
assertEquals(output.trim(), "<html><body></body></html>");
}
@Test
public void testFilterWhenDismissed() throws Exception {
setAuthorRunmode();
createEnabledNotification();
aemContext.registerInjectActivateService(notifications);
aemContext.request().setResource(aemContext.resourceResolver().getResource("/"));
aemContext.request().addCookie(new Cookie("acs-commons-system-notifications", "uid-" + DigestUtils.shaHex("/etc/acs-commons/notifications/enabled0")));
notifications.doFilter(aemContext.request(), aemContext.response(), outputChain);
String output = aemContext.response().getOutputAsString();
assertEquals(output.trim(), "<html><body></body></html>");
}
@Test
public void testFilterWhenDisabled() throws Exception {
setAuthorRunmode();
createDisabledNotification();
aemContext.registerInjectActivateService(notifications);
aemContext.request().setResource(aemContext.resourceResolver().getResource("/"));
notifications.doFilter(aemContext.request(), aemContext.response(), outputChain);
String output = aemContext.response().getOutputAsString();
assertEquals(output.trim(), "<html><body></body></html>");
}
private FilterChain outputChain = (req, res) -> {
res.setContentType("text/html");
res.getWriter().println("<html><body></body></html>");
};
private void createEnabledNotification() throws PersistenceException {
aemContext.build().
resource("/etc/acs-commons/notifications", JCR_PRIMARYTYPE, NT_PAGE).
siblingsMode().
resource("jcr:content", JCR_PRIMARYTYPE, NT_UNSTRUCTURED).
hierarchyMode().
resource("enabled", JCR_PRIMARYTYPE, NT_PAGE).
resource("jcr:content", JCR_PRIMARYTYPE, NT_UNSTRUCTURED, "enabled", true, "cq:lastModified", zeroHour);
commit();
}
private void createDisabledNotification() throws PersistenceException {
aemContext.build().
resource("/etc/acs-commons/notifications", JCR_PRIMARYTYPE, NT_PAGE).
siblingsMode().
resource("jcr:content", JCR_PRIMARYTYPE, NT_UNSTRUCTURED).
hierarchyMode().
resource("disabled", JCR_PRIMARYTYPE, NT_PAGE).
resource("jcr:content", JCR_PRIMARYTYPE, NT_UNSTRUCTURED, "enabled", false, "cq:lastModified", zeroHour);
commit();
}
private void sendEvent() {
notifications.handleEvent(new Event("dummy", Collections.singletonMap(SlingConstants.PROPERTY_PATH, "/etc/acs-commons/notifications")));
}
private void delete(String path) throws PersistenceException {
resourceResolver.delete(aemContext.resourceResolver().getResource(path));
}
private void commit() throws PersistenceException {
resourceResolver.commit();
}
private void setAuthorRunmode() {
MockSlingSettingService settingService = (MockSlingSettingService) aemContext.getService(SlingSettingsService.class);
settingService.setRunModes(Collections.singleton("author"));
}
}