blob: bdcfc996d65087182c18ab1e9cb125c35b5734f0 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.qpid.test.framework.distributedtesting;
import junit.framework.TestResult;
import org.apache.log4j.Logger;
import org.apache.qpid.test.framework.FrameworkBaseCase;
import org.apache.qpid.test.framework.TestClientDetails;
import org.apache.qpid.test.framework.sequencers.CircuitFactory;
import org.apache.qpid.test.utils.ConversationFactory;
import org.apache.qpid.junit.extensions.WrappedSuiteTestDecorator;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import java.util.*;
/**
* DistributedTestDecorator is a base class for writing test decorators that invite test clients to participate in
* distributed test cases. It provides a helper method, {@link #signupClients}, that broadcasts an invitation and
* returns the set of test clients that are available to particiapte in the test.
*
* <p/>When used to wrap a {@link FrameworkBaseCase} test, it replaces the default {@link CircuitFactory} implementations
* with a suitable circuit factory for distributed tests. Concrete implementations can use this to configure the sending
* and receiving roles on the test.
*
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
* <tr><td> Broadcast test invitations and collect enlists. <td> {@link ConversationFactory}.
* </table>
*/
public abstract class DistributedTestDecorator extends WrappedSuiteTestDecorator
{
/** Used for debugging. */
private static final Logger log = Logger.getLogger(DistributedTestDecorator.class);
/** Holds the contact information for all test clients that are available and that may take part in the test. */
Set<TestClientDetails> allClients;
/** Holds the conversation helper for the control level conversation for coordinating the test through. */
ConversationFactory conversationFactory;
/** Holds the connection that the control conversation is held over. */
Connection connection;
/** Holds the underlying test suite that this decorator wraps. */
WrappedSuiteTestDecorator testSuite;
/** Holds the control topic, on which test invitations are broadcast. */
protected Destination controlTopic;
/**
* Creates a wrapped suite test decorator from another one.
*
* @param suite The test suite.
* @param availableClients The list of all clients that responded to the compulsory invite.
* @param controlConversation The conversation helper for the control level, test coordination conversation.
* @param controlConnection The connection that the coordination messages are sent over.
*/
public DistributedTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> availableClients,
ConversationFactory controlConversation, Connection controlConnection)
{
super(suite);
log.debug("public DistributedTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> allClients = "
+ availableClients + ", ConversationHelper controlConversation = " + controlConversation + "): called");
testSuite = suite;
allClients = availableClients;
conversationFactory = controlConversation;
connection = controlConnection;
// Set up the test control topic.
try
{
controlTopic = conversationFactory.getSession().createTopic("iop.control");
}
catch (JMSException e)
{
throw new RuntimeException("Unable to create the coordinating control topic to broadcast test invites on.", e);
}
}
/**
* Should run all of the tests in the wrapped test suite.
*
* @param testResult The the results object to monitor the test results with.
*/
public abstract void run(TestResult testResult);
/**
* Should provide the distributed test sequencer to pass to {@link org.apache.qpid.test.framework.FrameworkBaseCase}
* tests.
*
* @return A distributed test sequencer.
*/
public abstract CircuitFactory getTestSequencer();
/**
* Broadcasts an invitation to participate in a coordinating test case to find out what clients are available to
* run the test case.
*
* @param coordTest The coordinating test case to broadcast an inviate for.
*
* @return A set of test clients that accepted the invitation.
*/
protected Set<TestClientDetails> signupClients(FrameworkBaseCase coordTest)
{
// Broadcast the invitation to find out what clients are available to test.
Set<TestClientDetails> enlists;
try
{
Message invite = conversationFactory.getSession().createMessage();
ConversationFactory.Conversation conversation = conversationFactory.startConversation();
invite.setStringProperty("CONTROL_TYPE", "INVITE");
invite.setStringProperty("TEST_NAME", coordTest.getTestCaseNameForTestMethod(coordTest.getName()));
conversation.send(controlTopic, invite);
// Wait for a short time, to give test clients an opportunity to reply to the invitation.
Collection<Message> replies = conversation.receiveAll(allClients.size(), 500);
enlists = Coordinator.extractEnlists(replies);
}
catch (JMSException e)
{
throw new RuntimeException("There was a JMSException during the invite/enlist conversation.", e);
}
return enlists;
}
/**
* Prints a string summarizing this test decorator, mainly for debugging purposes.
*
* @return String representation for debugging purposes.
*/
public String toString()
{
return "DistributedTestDecorator: [ testSuite = " + testSuite + " ]";
}
}