package org.sakaiproject.tool.impl;
import java.lang.reflect.Field;
import java.util.HashSet;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.jmock.Expectations;
import org.jmock.integration.junit3.MockObjectTestCase;
import org.sakaiproject.component.api.ComponentManager;
import org.sakaiproject.id.api.IdManager;
import org.sakaiproject.thread_local.api.ThreadLocalManager;
import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.api.Tool;
import org.sakaiproject.tool.api.ToolManager;
import org.sakaiproject.tool.api.SessionAttributeListener;
/**
* Provides common fixture set-up operations. This is necessary
* so long as the Sessions domain is implemented as inner classes
* on {@link SessionComponent}.
*
* @author dmccallum@unicon.net
*
*/
public abstract class BaseSessionComponentTest extends MockObjectTestCase {
protected SessionComponent sessionComponent;
protected IdManager idManager;
protected ComponentManager componentManager;
protected ThreadLocalManager threadLocalManager;
protected ToolManager toolManager;
private int uuidDiscriminator;
// not used - test passes null value to MySession() constructor
protected SessionAttributeListener sessionListener;
protected void setUp() throws Exception {
this.idManager = mock(IdManager.class);
this.threadLocalManager = mock(ThreadLocalManager.class);
this.toolManager = mock(ToolManager.class);
setUpComponentManager();
this.sessionComponent = new SessionComponent() {
@Override
protected IdManager idManager() {
return idManager;
}
@Override
protected ThreadLocalManager threadLocalManager() {
return threadLocalManager;
}
@Override
protected ToolManager toolManager() {
return toolManager;
}
};
//commenting out this next line, because it doesn't seem to be needed
//this.sessionComponent.setClusterableTools("");
this.sessionComponent.init();
// it's up to individual tests to start or stop maintenance
stopMaintenance();
super.setUp();
}
/**
* Initializes the {@link org.sakaiproject.component.cover.ComponentManager}} cover
* referenced during {@link SessionComponent#init()}. This implementation
* effectively short-circuits the internal initialization that would normally
* occur in the CM cover when <code>SessionComponent</code>
* starts an internal thread which invokes the static
* {@link org.sakaiproject.component.cover.ComponentManager#waitTillConfigured()}.
*
*
* @throws NoSuchFieldException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
protected void setUpComponentManager()
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
this.componentManager = mock(ComponentManager.class);
//
Field componentManagerField =
org.sakaiproject.component.cover.ComponentManager.
class.getDeclaredField("m_componentManager");
componentManagerField.setAccessible(true);
componentManagerField.set(null, componentManager);
}
/**
* Destroys and recreates the current {@link SessionComponent}, setting
* <code>checkEvery</code> and <code>inactiveInterval</code> values to
* the received arguments. This is overkill in many cases for this class,
* but is our only "blackbox" means of "knowing" what <code>checkEvery</code>
* and <code>inactiveInterval</code> are set to.
*
* @param checkEvery
* @param inactiveInterval
*/
protected void resetMaintenance(String checkEvery, String inactiveInterval) {
stopMaintenance();
sessionComponent.setCheckEvery(checkEvery);
sessionComponent.setInactiveInterval(inactiveInterval);
startMaintenance();
}
protected void stopMaintenance() {
// Basically copied directly from SessionComponent.destroy().
// Didn't want to use the latter since its semantics could be
// more broad than simply stopping the maintenance thread.
if (sessionComponent.m_maintenance != null)
{
sessionComponent.m_maintenance.stop();
sessionComponent.m_maintenance = null;
}
}
protected void startMaintenance() {
// Basically copied directly from SessionComponent.init().
// Didn't want to use the latter since its semantics could be
// more broad than simply starting the maintenance thread.
if (sessionComponent.m_checkEvery > 0)
{
sessionComponent.m_maintenance = sessionComponent.new Maintenance();
sessionComponent.m_maintenance.start();
}
}
protected void expectCreateUuidRequest(final String nextUuid) {
checking(new Expectations() {{
one(idManager).createUuid(); will(returnValue(nextUuid));
}});
}
protected void expectCreateUuidRequest() {
expectCreateUuidRequest(nextUuid());
}
protected void allowCreateUuidRequest(final String nextUuid) {
checking(new Expectations() {{
allowing(idManager).createUuid(); will(returnValue(nextUuid));
}});
}
protected void allowCreateUuidRequest() {
allowCreateUuidRequest(nextUuid());
}
/**
* Doesn't actually return a UUID, but a String that should be "unique enough"
* for testing purposes.
*
* @return
*/
protected String nextUuid() {
return "" + System.currentTimeMillis() + uuidDiscriminator++;
}
protected void expectGetAndUnsetCurrentSession(final Session session) {
expectGetSession(session);
checking(new Expectations() {{
one(threadLocalManager).set(SessionComponent.CURRENT_SESSION, null);
}});
}
protected void expectGetSession(final Session session) {
checking(new Expectations() {{
one(threadLocalManager).get(SessionComponent.CURRENT_SESSION);
will(returnValue(session));
}});
}
protected void allowGetAndUnsetCurrentSession(final Session session) {
checking(new Expectations() {{
allowing(threadLocalManager).get(SessionComponent.CURRENT_SESSION);
will(returnValue(session));
allowing(threadLocalManager).set(SessionComponent.CURRENT_SESSION, null);
}});
}
protected void expectToolCheck(final String toolId) {
checking(new Expectations() {{
Tool mockTool = mock(Tool.class);
one(toolManager).getCurrentTool();
will(returnValue(mockTool));
one(mockTool).getId();
will(returnValue(toolId));
}});
}
protected void allowToolCheck(final String toolId) {
checking(new Expectations() {{
Tool mockTool = mock(Tool.class);
allowing(toolManager).getCurrentTool();
will(returnValue(mockTool));
allowing(mockTool).getId();
will(returnValue(toolId));
}});
}
protected Matcher<Session> sessionHavingId(final String toMatch, final SessionHolder matchedSessionHolder) {
return new TypeSafeMatcher<Session>() {
@Override
public boolean matchesSafely(Session item) {
if (matchedSessionHolder != null) matchedSessionHolder.setSession(item);
return toMatch.equals(item.getId());
}
public void describeTo(Description description) {
description.appendText("a session having ID ").appendValue(toMatch);
}
};
}
protected static final class SessionHolder {
private Session session;
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
}
protected void tearDown() throws Exception {
sessionComponent.destroy();
// TODO try to verify Maintenance shutdown? prob overkill.
super.tearDown();
}
}