/*
* JBoss, a division of Red Hat
* Copyright 2011, Red Hat Middleware, LLC, and individual
* contributors as indicated by the @authors tag. See the
* copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.gatein.integration.wsrp.structure;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.exoplatform.portal.config.DataStorage;
import org.exoplatform.portal.mop.Described;
import org.exoplatform.portal.mop.EventType;
import org.exoplatform.portal.mop.page.PageContext;
import org.exoplatform.portal.mop.page.PageKey;
import org.exoplatform.portal.mop.page.PageService;
import org.exoplatform.portal.mop.page.PageState;
import org.exoplatform.portal.pom.spi.wsrp.WSRP;
import org.exoplatform.services.listener.Event;
import org.gatein.mop.api.content.Customization;
import org.gatein.mop.api.workspace.ObjectType;
import org.gatein.mop.api.workspace.Page;
import org.gatein.mop.api.workspace.Site;
import org.gatein.mop.api.workspace.ui.UIComponent;
import org.gatein.mop.api.workspace.ui.UIContainer;
import org.gatein.mop.api.workspace.ui.UIWindow;
import org.gatein.pc.api.PortletContext;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/**
* @author <a href="mailto:chris.laprun@jboss.com">Chris Laprun</a>
* @version $Revision$
*/
public class MOPConsumerStructureProviderTestCase extends TestCase {
public static final String SITE_NAME = "site";
private MOPConsumerStructureProvider provider;
private PortalStructureAccess structureAccess;
private Page page1;
public void testGetPageIdentifiers() {
List<String> pageIdentifiers = provider.getPageIdentifiers();
assertEquals(5, pageIdentifiers.size());
assertTrue(pageIdentifiers.contains(getPageIdFor("page1")));
assertTrue(pageIdentifiers.contains(getPageIdFor("page11")));
assertTrue(pageIdentifiers.contains(getPageIdFor("page12")));
assertTrue(pageIdentifiers.contains(getPageIdFor("page2")));
assertTrue(pageIdentifiers.contains(getPageIdFor("page21")));
}
private String getPageIdFor(String pageName) {
return MOPConsumerStructureProvider.PageInfo.getPageIdFor(SITE_NAME, pageName);
}
public void testGetWindowIdentifiersForInexistingPage() {
try {
provider.getWindowIdentifiersFor("inexisting");
fail("Cannot retrieve windows for an inexistent page");
} catch (IllegalArgumentException e) {
// expected
}
}
public void testGetWindowIdentifiersFor() {
checkWindows("page1", "window11", "window12");
checkWindows("page2");
checkWindows("page11", "window111", "window112");
checkWindows("page12", "window121");
checkWindows("page21", "window211");
}
public void testAssignPortletToWindow() {
String newCustomizationId = "/app.new";
String newWindowName = "portlet";
provider.assignPortletToWindow(PortletContext.createPortletContext(newCustomizationId), "window11", getPageIdFor("page1"),
newWindowName);
verify(structureAccess).getWindowFrom(getIdFor("window11"));
UIWindow window11 = structureAccess.getWindowFrom(getIdFor("window11"));
verify(structureAccess).saveChangesTo(window11);
Described described = window11.adapt(Described.class);
verify(described).setName(newWindowName + " (remote)");
WSRP state = new WSRP();
state.setPortletId(newCustomizationId);
verify(window11).customize(WSRP.CONTENT_TYPE, newCustomizationId, state);
Customization<?> customization = window11.getCustomization();
assertEquals(WSRP.CONTENT_TYPE, customization.getType());
}
public void testPageCreationEvent() throws Exception {
Page foo = createPage("foo", new String[] { "foo1" }, new String[] { "windowfoo1" });
Page foo1 = foo.getChild("foo1");
addWindows(foo1, "windowfoo11");
org.exoplatform.portal.config.model.Page portalPage = mock(org.exoplatform.portal.config.model.Page.class);
PageKey pageKey = mock(PageKey.class);
when(structureAccess.getPageFrom(portalPage)).thenReturn(foo);
when(structureAccess.getPageFrom(pageKey)).thenReturn(foo);
int pageNumber = provider.getPageIdentifiers().size();
// when a page is created, the events being sent are now EventType.PAGE_CREATED and DataStorage.PAGE_UPDATED in that
// order
provider.onEvent(new Event<PageService, PageKey>(EventType.PAGE_CREATED, null, pageKey));
provider.onEvent(new Event<DataStorage, org.exoplatform.portal.config.model.Page>(DataStorage.PAGE_UPDATED, null,
portalPage));
List<String> identifiers = provider.getPageIdentifiers();
assertEquals(pageNumber + 2, identifiers.size());
assertTrue(identifiers.contains(getPageIdFor("foo")));
assertTrue(identifiers.contains(getPageIdFor("foo1")));
checkWindows("foo", "windowfoo1");
checkWindows("foo1", "windowfoo11");
assertEquals(foo1.getRootComponent().get("windowfoo11"), structureAccess.getWindowFrom(getIdFor("windowfoo11")));
}
public void testPageDeletionEvent() throws Exception {
String pageToRemove = "page1";
// mocking internal behavior
PageKey pageKey = mock(PageKey.class);
when(pageKey.getName()).thenReturn(createInternalNameFrom(pageToRemove));
PageState pageState = mock(PageState.class);
when(pageState.getDisplayName()).thenReturn(pageToRemove);
PageContext pageContext = mock(PageContext.class);
when(pageContext.getState()).thenReturn(pageState);
PageService pageService = mock(PageService.class);
when(pageService.loadPage(pageKey)).thenReturn(pageContext);
// on delete, we actually get the event after the page has been removed from JCR so we don't have an actual page
when(structureAccess.getPageFrom(pageKey)).thenReturn(null);
int pageNumber = provider.getPageIdentifiers().size();
// when a page is deleted the event being sent is now EventType.PAGE_DESTROYED
provider.onEvent(new Event<PageService, PageKey>(EventType.PAGE_DESTROYED, pageService, pageKey));
List<String> identifiers = provider.getPageIdentifiers();
assertEquals(pageNumber - 1, identifiers.size());
// deleting a page doesn't delete its children, see GTNPORTAL-1630
assertFalse(identifiers.contains(getPageIdFor(pageToRemove)));
assertTrue(identifiers.contains(getPageIdFor("page11")));
assertTrue(identifiers.contains(getPageIdFor("page12")));
}
public void testPageUpdatedEvent() throws Exception {
// todo!
}
@Override
protected void setUp() throws Exception {
structureAccess = mock(PortalStructureAccess.class);
page1 = createPage("page1", new String[] { "page11", "page12" }, new String[] { "window11", "window12" });
Page page2 = createPage("page2", new String[] { "page21" }, null);
Page page11 = page1.getChild("page11");
addWindows(page11, "window111", "window112");
Page page12 = page1.getChild("page12");
addWindows(page12, "window121");
Page page21 = page2.getChild("page21");
addWindows(page21, "window211");
ArrayList<Page> pages = new ArrayList<Page>();
pages.add(page1);
pages.add(page11);
pages.add(page12);
pages.add(page2);
pages.add(page21);
when(structureAccess.getPages()).thenReturn(pages);
provider = new MOPConsumerStructureProvider(structureAccess);
// needed to initialize state
provider.getPageIdentifiers();
}
private void checkWindows(final String pageName, String... windowNames) {
List<String> windows = provider.getWindowIdentifiersFor(getPageIdFor(pageName));
if (windowNames != null) {
assertEquals(windowNames.length, windows.size());
for (String windowName : windowNames) {
assertTrue(windows.contains(windowName));
}
}
}
private Page createPage(String name, String[] childrenPages, String[] windowNames) {
Site site = mock(Site.class);
when(site.getName()).thenReturn(SITE_NAME);
Page page = mock(Page.class);
when(page.getName()).thenReturn(createInternalNameFrom(name));
when(page.getSite()).thenReturn(site);
// mock call to adapt
Described described = mock(Described.class);
when(described.getName()).thenReturn(name);
when(page.adapt(Described.class)).thenReturn(described);
if (childrenPages != null) {
List<Page> children = new ArrayList<Page>(childrenPages.length);
for (String pageId : childrenPages) {
Page childPage = createPage(pageId, null, null);
when(page.getChild(pageId)).thenReturn(childPage);
children.add(childPage);
}
when(page.getChildren()).thenReturn(children);
}
addWindows(page, windowNames);
return page;
}
private String createInternalNameFrom(String name) {
return name + "internal";
}
private void addWindows(Page page, String... windowNames) {
if (windowNames != null) {
// mock page container
UIContainer root = mock(UIContainer.class);
when(page.getRootComponent()).thenReturn(root);
// for each provided window name, create a mock UIWindow...
List<UIComponent> children = new ArrayList<UIComponent>(windowNames.length);
for (String windowName : windowNames) {
UIWindow window = mock(UIWindow.class);
when(window.getName()).thenThrow(
new RuntimeException("Window.getName returns the internal name, not the human readable one"));
when(window.getObjectId()).thenReturn(getIdFor(windowName));
// need to use thenAnswer instead of thenReturn here because it doesn't play well with generics
when(window.getObjectType()).thenAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
return ObjectType.WINDOW;
}
});
// mock call to adapt
Described described = mock(Described.class);
when(described.getName()).thenReturn(windowName);
when(window.adapt(Described.class)).thenReturn(described);
// mock Customization
final Customization<WSRP> customization = mock(Customization.class);
when(customization.getType()).thenReturn(WSRP.CONTENT_TYPE);
when(window.getCustomization()).thenAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
return customization;
}
});
// add it to the list of windows for this page
children.add(window);
// make sure that we return the window when we ask for it from its uuid
when(structureAccess.getWindowFrom(getIdFor(windowName))).thenReturn(window);
// make sure that we return the window if we ask the root component for it
when(root.get(windowName)).thenReturn(window);
}
// the container should return the list of windows when asked for its components
when(root.getComponents()).thenReturn(children);
}
}
private String getIdFor(String windowName) {
return windowName + "Id";
}
}