/*
* Copyright (c) 2010 Lockheed Martin Corporation
*
* 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.
*/
package org.eurekastreams.server.action.execution.profile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eurekastreams.commons.actions.context.ActionContext;
import org.eurekastreams.commons.actions.context.Principal;
import org.eurekastreams.commons.actions.context.PrincipalActionContext;
import org.eurekastreams.commons.actions.context.TaskHandlerActionContext;
import org.eurekastreams.commons.server.UserActionRequest;
import org.eurekastreams.server.AnonymousClassInterceptor;
import org.eurekastreams.server.action.execution.notification.Notifier;
import org.eurekastreams.server.action.request.profile.ReviewPendingGroupRequest;
import org.eurekastreams.server.domain.DomainGroup;
import org.eurekastreams.server.domain.NotificationDTO;
import org.eurekastreams.server.domain.Organization;
import org.eurekastreams.server.domain.Person;
import org.eurekastreams.server.domain.strategies.OrganizationHierarchyTraverser;
import org.eurekastreams.server.domain.strategies.OrganizationHierarchyTraverserBuilder;
import org.eurekastreams.server.persistence.DomainGroupMapper;
import org.eurekastreams.server.persistence.OrganizationMapper;
import org.eurekastreams.server.persistence.mappers.cache.AddPrivateGroupIdToCachedCoordinatorAccessList;
import org.eurekastreams.server.search.modelview.PersonModelView;
import org.eurekastreams.server.service.security.userdetails.ExtendedUserDetails;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Before;
import org.junit.Test;
/**
* Test fixture for ReviewPendingGroupExecution.
*/
public class ReviewPendingGroupExecutionTest
{
/**
* A shortname to pass into the params.
*/
private static final String GROUP_SHORTNAME = "shortname";
/** Test data. */
private static final String GROUP_NAME = "Group Name";
/** Test data. */
private static final long GROUP_ID = 3425L;
/**
* System under test.
*/
private ReviewPendingGroupExecution sut;
/**
* Context for building mock objects.
*/
private final Mockery context = new JUnit4Mockery()
{
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
/**
* User info in the session.
*/
private ExtendedUserDetails user = context.mock(ExtendedUserDetails.class);
/**
* Mocked group cache.
*/
private DomainGroupMapper groupMapper = context.mock(DomainGroupMapper.class);
/**
* Mocked group.
*/
private DomainGroup group = context.mock(DomainGroup.class);
/**
* Mock used to update privategroupcoordinatorcache.
*/
private AddPrivateGroupIdToCachedCoordinatorAccessList addPrivateGroupIdToCachedListMock = context
.mock(AddPrivateGroupIdToCachedCoordinatorAccessList.class);
/**
* A username for tests.
*/
private String username = "username";
/**
* User's email address.
*/
private String userEmailAddress = "username@example.com";
/**
* PersonModelView returned for the user.
*/
private PersonModelView userModelView;
/**
* Mocked principal.
*/
private Principal mockedPrincipal = context.mock(Principal.class);
/** Fixture: email notifier. */
private Notifier emailNotifier = context.mock(Notifier.class);
/** Fixture: async request to send notification. */
private UserActionRequest notifAsyncRequest = context.mock(UserActionRequest.class);
/**
* Mocked instance of the {@link OrganizationMapper}.
*/
private final OrganizationMapper orgMapperMock = context.mock(OrganizationMapper.class);
/**
* Mocked instance of the {@link Organization}.
*/
private final Organization orgMock = context.mock(Organization.class);
/**
* The organization hierarchy traverser builder.
*/
private final OrganizationHierarchyTraverserBuilder orgTraverserBuilder = context
.mock(OrganizationHierarchyTraverserBuilder.class);
/**
* Org traverser built by the org traverser builder.
*/
private final OrganizationHierarchyTraverser orgTraverser = context.mock(OrganizationHierarchyTraverser.class);
/** Fixture: Execution strategy for deleting a group. */
private DeleteGroupFromDBExecution deleteGroupExecution = context.mock(DeleteGroupFromDBExecution.class);
/**
* Set up the SUT.
*
* @throws MalformedURLException
* won't happen
*/
@Before
public void setup() throws MalformedURLException
{
sut = new ReviewPendingGroupExecution(groupMapper, emailNotifier, addPrivateGroupIdToCachedListMock,
orgMapperMock, orgTraverserBuilder, deleteGroupExecution);
}
/**
* Test a valid case where the coordinator approves.
*
* @throws Exception
* not expected
*/
@SuppressWarnings("deprecation")
@Test
public void performActionApprovePublicGroupTest() throws Exception
{
final ReviewPendingGroupRequest request = new ReviewPendingGroupRequest(GROUP_SHORTNAME, true);
setupCommonExpectations();
context.checking(new Expectations()
{
{
oneOf(group).setPending(false);
oneOf(groupMapper).flush();
oneOf(group).isPublicGroup();
will(returnValue(true));
allowing(group).getParentOrganization();
will(returnValue(orgMock));
one(orgTraverserBuilder).getOrganizationHierarchyTraverser();
will(returnValue(orgTraverser));
one(orgTraverser).traverseHierarchy(orgMock);
allowing(orgMapperMock).updateOrganizationStatistics(orgTraverser);
}
});
List<UserActionRequest> asyncRequests = callExecute(request);
context.assertIsSatisfied();
assertEquals(1, asyncRequests.size());
assertSame(notifAsyncRequest, asyncRequests.get(0));
}
/**
* Test a valid case where the coordinator approves.
*
* @throws Exception
* not expected
*/
@SuppressWarnings("deprecation")
@Test
public void performActionApprovePrivateGroupTest() throws Exception
{
final ReviewPendingGroupRequest request = new ReviewPendingGroupRequest(GROUP_SHORTNAME, true);
setupCommonExpectations();
context.checking(new Expectations()
{
{
oneOf(group).setPending(false);
oneOf(groupMapper).flush();
oneOf(group).isPublicGroup();
will(returnValue(false));
oneOf(addPrivateGroupIdToCachedListMock).execute(GROUP_ID);
allowing(group).getParentOrganization();
will(returnValue(orgMock));
one(orgTraverserBuilder).getOrganizationHierarchyTraverser();
will(returnValue(orgTraverser));
one(orgTraverser).traverseHierarchy(orgMock);
allowing(orgMapperMock).updateOrganizationStatistics(orgTraverser);
}
});
List<UserActionRequest> asyncRequests = callExecute(request);
context.assertIsSatisfied();
assertEquals(1, asyncRequests.size());
assertSame(notifAsyncRequest, asyncRequests.get(0));
}
/**
* Test a valid case where the coordinator denies the new group.
*
* @throws Exception
* not expected
*/
@Test
public void performActionDenyPrivateGroupTest() throws Exception
{
final ReviewPendingGroupRequest request = new ReviewPendingGroupRequest(GROUP_SHORTNAME, false);
setupCommonExpectations();
final AnonymousClassInterceptor<TaskHandlerActionContext<ActionContext>> intCtx = // \n
new AnonymousClassInterceptor<TaskHandlerActionContext<ActionContext>>();
context.checking(new Expectations()
{
{
oneOf(deleteGroupExecution).execute(with(any(TaskHandlerActionContext.class)));
will(intCtx);
}
});
List<UserActionRequest> asyncRequests = callExecute(request);
context.assertIsSatisfied();
assertTrue(asyncRequests.size() >= 1);
assertSame(notifAsyncRequest, asyncRequests.get(0));
TaskHandlerActionContext<ActionContext> thac = intCtx.getObject();
assertSame(asyncRequests, thac.getUserActionRequests());
assertEquals(GROUP_ID, thac.getActionContext().getParams());
}
/**
* Executes the SUT with the proper action context setup.
*
* @param request
* The request to pass.
* @return List with any async requests made by the SUT.
*/
private List<UserActionRequest> callExecute(final ReviewPendingGroupRequest request)
{
List<UserActionRequest> asyncRequests = new ArrayList<UserActionRequest>();
sut.execute(new TaskHandlerActionContext<PrincipalActionContext>(new PrincipalActionContext()
{
/**
* Serial version uid.
*/
private static final long serialVersionUID = -1644049510102329123L;
@Override
public Map<String, Object> getState()
{
return null;
}
@Override
public Serializable getParams()
{
return request;
}
@Override
public Principal getPrincipal()
{
return mockedPrincipal;
}
@Override
public String getActionId()
{
return null;
}
@Override
public void setActionId(final String inActionId)
{
}
}, asyncRequests));
return asyncRequests;
}
/**
* Set up expectations that are common to multiple tests.
*
* @throws Exception
* Shouldn't.
*/
private void setupCommonExpectations() throws Exception
{
final Set<Person> coordinators = new HashSet<Person>();
final Person coordinator1 = context.mock(Person.class, "coord1");
final Person coordinator2 = context.mock(Person.class, "coord2");
coordinators.add(coordinator1);
coordinators.add(coordinator2);
userModelView = new PersonModelView();
userModelView.setEmail(userEmailAddress);
context.checking(new Expectations()
{
{
allowing(mockedPrincipal).getAccountId();
will(returnValue(username));
allowing(groupMapper).findByShortName(GROUP_SHORTNAME);
will(returnValue(group));
allowing(group).getId();
will(returnValue(GROUP_ID));
allowing(group).getName();
will(returnValue(GROUP_NAME));
allowing(group).getShortName();
will(returnValue(GROUP_SHORTNAME));
allowing(group).getCoordinators();
will(returnValue(coordinators));
allowing(coordinator1).getId();
will(returnValue(7L));
allowing(coordinator2).getId();
will(returnValue(8L));
allowing(user).getPerson();
oneOf(emailNotifier).notify(with(aNonNull(NotificationDTO.class)));
will(returnValue(notifAsyncRequest));
}
});
}
}