/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// Assertion models an assertion on a test <see cref="Circuit"/>.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Indicate whether or not the assertion passes when applied.
    /// </table>
    /// </summary>
    public interface Assertion
    {
        /// <summary>
        /// Applies the assertion.
        /// </summary>
        /// <return> <tt>true</tt> if the assertion passes, <tt>false</tt> if it fails. </return>
        public bool apply();
    }
}
/*
 *
 * 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.
 *
 */
using System.Collections.Generic.LinkedList;
using System.Collections.Generic.IList;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// AssertionBase is a base class for implenmenting assertions. It provides a mechanism to store error messages, and
    /// report all error messages when its <see cref="#ToString()"/> method is called.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Collect error messages.
    /// </table>
    /// </summary>
    public abstract class AssertionBase : Assertion
    {
        /// <summary> Holds the error messages. </summary>
        IList<String> errors = new LinkedList<String>();

        /// <summary>
        /// Adds an error message to the assertion.
        /// </summary>
        /// <param name="error"> An error message to add to the assertion. </param>
        public void addError(string error)
        {
            errors.add(error);
        }

        /// <summary>
        /// Prints all of the error messages in the assertion into a string.
        /// </summary>
        /// <return> All of the error messages in the assertion as a string. </return>
        public string ToString()
        {
            string result = "";

            for (string error : errors)
            {
                result += error;
            }

            return result;
        }
    }
}
/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// BrokerLifecycleAware is an awareness interface implemented by test cases that can run control the life-cycle of
    /// the brokers on which they run. Its purpose is to expose additional instrumentation of brokers during testing, that
    /// enables tests to use an automated failure mechanism to simulate broker failures, and to re-start failed brokers.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Indicate whether or not a test case is using an in-vm broker.
    /// <tr><td> Track which in-vm broker is currently in use.
    /// <tr><td> Accept setting of a failure mechanism. <td> <see cref="CauseFailure"/>.
    /// </table>
    /// </summary>
    ///
    /// <remarks> Need to think about how to present the brokers through this interface. Thinking numbering the available
    ///       brokers from 1 will do. Then can kill 1 and assume failing onto 2. Restart 1 and kill 2 and fail back onto
    ///       1 again? </remarks>
    public interface BrokerLifecycleAware
    {
        public void setInVmBrokers();

        /// <summary>
        /// Indicates whether or not a test case is using in-vm brokers.
        /// </summary>
        /// <return> <tt>true</tt> if the test is using in-vm brokers, <tt>false</tt> otherwise. </return>
        public bool usingInVmBroker();

        /// <summary>
        /// Sets the currently live in-vm broker.
        /// </summary>
        /// <param name="i"> The currently live in-vm broker. </param>
        public void setLiveBroker(int i);

        /// <summary>
        /// Reports the currently live in-vm broker.
        /// </summary>
        /// <return> The currently live in-vm broker. </return>
        public int getLiveBroker();

        /// <summary>
        /// Accepts a failure mechanism.
        /// </summary>
        /// <param name="failureMechanism"> The failure mechanism. </param>
        public void setFailureMechanism(CauseFailure failureMechanism);
    }
}
/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// CauseFailure provides a method to cause a failure in a messaging broker, usually used in conjunction with fail-over
    /// or other failure mode testing. In some cases failures may be automated, for example by shutting down an in-vm broker,
    /// or by sending a special control signal to a broker over a network connection. In other cases, it may be preferable
    /// to ask a user interactively to cause a failure scenario, in which case an implementation may display a prompt or
    /// dialog box asking for notification once the failure has been caused. The purpose of this interface is to abstract
    /// the exact cause and nature of a failure out of failure test cases.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Cause messaging broker failure.
    /// </table>
    /// </summary>
    public interface CauseFailure
    {
        /// <summary> Causes the active message broker to fail. </summary>
        void causeFailure();
    }
}
/*
 *
 * 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.
 *
 */
using Apache.Qpid.Integration.Tests.framework.CauseFailure;

using java.io.IOException;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// Causes a message broker failure by interactively prompting the user to cause it.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Cause messaging broker failure.
    /// </table>
    /// </summary>
    public class CauseFailureUserPrompt : CauseFailure
    {
        /// <summary> Causes the active message broker to fail.</summary>
        public void causeFailure()
        {
            waitForUser("Cause a broker failure now, then press Return.");
        }

        /// <summary>
        /// Outputs a prompt to the console and waits for the user to press return.
        /// </summary>
        /// <param name="prompt"> The prompt to display on the console. </param>
        private void waitForUser(string prompt)
        {
            System.out.println(prompt);

            try
            {
                System.in.read();
            }
            catch (IOException e)
            {
                // Ignored.
            }

            System.out.println("Continuing.");
        }
    }
}
/*
 *
 * 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.
 *
 */
using System.Collections.Generic.IList;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// A Circuit is the basic test unit against which test cases are to be written. A circuit consists of two 'ends', an
    /// instigating 'publisher' end and a more passive 'receivers' end.
    ///
    /// <p/>Once created, the life-cycle of a circuit may be controlled by <see cref="#start()"/>ing it, or <see cref="#close()"/>ing it.
    /// Once started, the circuit is ready to send messages over. Once closed the circuit can no longer be used.
    ///
    /// <p/>The state of the circuit may be taken with the <see cref="#check()"/> method, and asserted against by the
    /// <see cref="#applyAssertions(System.Collections.Generic.IList)"/> method.
    ///
    /// <p/>There is a default test procedure which may be performed against the circuit. The outline of this procedure is:
    ///
    /// <p/><pre>
    /// Start the circuit.
    /// Send test messages.
    /// Request a status report.
    /// Assert conditions on the publishing end of the circuit.
    /// Assert conditions on the receiving end of the circuit.
    /// Close the circuit.
    /// Pass with no failed assertions or fail with a list of failed assertions.
    /// </pre>
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
    /// <tr><td> Start the circuit running.
    /// <tr><td> Close the circuit down.
    /// <tr><td> Take a reading of the circuits state.
    /// <tr><td> Apply assertions against the circuits state.
    /// <tr><td> Send test messages over the circuit.
    /// <tr><td> Perform the default test procedue on the circuit.
    /// </table>
    /// </summary>
    public interface Circuit
    {
        /// <summary>
        /// Gets the interface on the publishing end of the circuit.
        /// </summary>
        /// <return> The publishing end of the circuit. </return>
        public Publisher getPublisher();

        /// <summary>
        /// Gets the interface on the receiving end of the circuit.
        /// </summary>
        /// <return> The receiving end of the circuit. </return>
        public Receiver getReceiver();

        /// <summary>
        /// Connects and starts the circuit. After this method is called the circuit is ready to send messages.
        public void start();

        /// <summary>
        /// Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
        /// into a report, against which assertions may be checked.
        public void check();

        /// <summary>
        /// Closes the circuit. All associated resources are closed.
        public void close();

        /// <summary>
        /// Applied a list of assertions against the test circuit. The <see cref="#check()"/> method should be called before doing
        /// this, to ensure that the circuit has gathered its state into a report to assert against.
        /// </summary>
        /// <param name="assertions"> The list of assertions to apply to the circuit. </param>
        ///
        /// <return> Any assertions that failed. </return>
        public IList<Assertion> applyAssertions(List<Assertion> assertions);

        /// <summary>
        /// Runs the default test procedure against the circuit, and checks that all of the specified assertions hold.
        /// </summary>
        /// <param name="numMessages"> The number of messages to send using the default test procedure. </param>
        /// <param name="assertions">  The list of assertions to apply. </param>
        ///
        /// <return> Any assertions that failed. </return>
        public IList<Assertion> test(int numMessages, List<Assertion> assertions);
    }
}
/*
 *
 * 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.
 *
 */
using javax.jms.*;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// A CircuitEnd is a pair consisting of one message producer and one message consumer, that represents one end of a
    /// test circuit. It is a standard unit of connectivity allowing a full-duplex conversation to be held, provided both
    /// the consumer and producer are instantiated and configured.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Provide a message producer for sending messages.
    /// <tr><td> Provide a message consumer for receiving messages.
    /// </table>
    /// </summary>
    ///
    /// <remarks> Update the <see cref="org.apache.qpid.util.ConversationFactory"/> so that it accepts these as the basic conversation
    /// connection units.</remarks>
    public interface CircuitEnd
    {
        /// <summary>
        /// Gets the message producer at this circuit end point.
        /// </summary>
        /// <return> The message producer at with this circuit end point. </return>
        public MessageProducer getProducer();

        /// <summary>
        /// Gets the message consumer at this circuit end point.
        /// </summary>
        /// <return> The message consumer at this circuit end point. </return>
        public MessageConsumer getConsumer();

        /// <summary>
        /// Send the specified message over the producer at this end point.
        /// </summary>
        /// <param name="message"> The message to send. </param>
        ///
        /// <exception cref="JMSException"> Any JMS exception occuring during the send is allowed to fall through. </exception>
        public void send(Message message) throws JMSException;

        /// <summary>
        /// Gets the JMS Session associated with this circuit end point.
        /// </summary>
        /// <return> The JMS Session associated with this circuit end point. </return>
        public Session getSession();

        /// <summary>
        /// Closes the message producers and consumers and the sessions, associated with this circuit end point.
        /// </summary>
        /// <exception cref="JMSException"> Any JMSExceptions occurring during the close are allowed to fall through. </exception>
        public void close() throws JMSException;

        /// <summary>
        /// Returns the message monitor for reporting on received messages on this circuit end.
        /// </summary>
        /// <return> The message monitor for this circuit end. </return>
        public MessageMonitor getMessageMonitor();

        /// <summary>
        /// Returns the exception monitor for reporting on exceptions received on this circuit end.
        /// </summary>
        /// <return> The exception monitor for this circuit end. </return>
        public ExceptionMonitor getExceptionMonitor();
    }
}
/*
 *
 * 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.
 *
 */
using javax.jms.*;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// A CircuitEndBase is a pair consisting of one message producer and one message consumer, that represents one end of a
    /// test circuit. It is a standard unit of connectivity allowing a full-duplex conversation to be held, provided both
    /// the consumer and producer are instantiated and configured.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Provide a message producer for sending messages.
    /// <tr><td> Provide a message consumer for receiving messages.
    /// </table>
    /// </summary>
    public class CircuitEndBase : CircuitEnd
    {
        /// <summary> Holds the single message producer. </summary>
        MessageProducer producer;

        /// <summary> Holds the single message consumer. </summary>
        MessageConsumer consumer;

        /// <summary> Holds the controlSession for the circuit end. </summary>
        Session session;

        /// <summary> Holds the message monitor for the circuit end. </summary>
        MessageMonitor messageMonitor;

        /// <summary> Holds the exception monitor for the circuit end. </summary>
        ExceptionMonitor exceptionMonitor;

        /// <summary>
        /// Creates a circuit end point on the specified producer, consumer and controlSession. Monitors are also configured
        /// for messages and exceptions received by the circuit end.
        /// </summary>
        /// <param name="producer">         The message producer for the circuit end point. </param>
        /// <param name="consumer">         The message consumer for the circuit end point. </param>
        /// <param name="session">          The controlSession for the circuit end point. </param>
        /// <param name="messageMonitor">   The monitor to notify of all messages received by the circuit end. </param>
        /// <param name="exceptionMonitor"> The monitor to notify of all exceptions received by the circuit end. </param>
        public CircuitEndBase(MessageProducer producer, MessageConsumer consumer, Session session, MessageMonitor messageMonitor,
                              ExceptionMonitor exceptionMonitor)
        {
            this.producer = producer;
            this.consumer = consumer;
            this.session = session;

            this.messageMonitor = messageMonitor;
            this.exceptionMonitor = exceptionMonitor;
        }

        /// <summary>
        /// Gets the message producer at this circuit end point.
        /// </summary>
        /// <return> The message producer at with this circuit end point. </return>
        public MessageProducer getProducer()
        {
            return producer;
        }

        /// <summary>
        /// Gets the message consumer at this circuit end point.
        /// </summary>
        /// <return> The message consumer at this circuit end point. </return>
        public MessageConsumer getConsumer()
        {
            return consumer;
        }

        /// <summary>
        /// Send the specified message over the producer at this end point.
        /// </summary>
        /// <param name="message"> The message to send. </param>
        /// <exception cref="javax.jms.JMSException"> Any JMS exception occuring during the send is allowed to fall through. </exception>
        public void send(Message message) throws JMSException
        {
            producer.send(message);
        }

        /// <summary>
        /// Gets the JMS Session associated with this circuit end point.
        /// </summary>
        /// <return> The JMS Session associated with this circuit end point. </return>
        public Session getSession()
        {
            return session;
        }

        /// <summary>
        /// Closes the message producers and consumers and the sessions, associated with this circuit end point.
        /// </summary>
        /// <exception cref="javax.jms.JMSException"> Any JMSExceptions occurring during the close are allowed to fall through. </exception>
        public void close() throws JMSException
        {
            if (producer != null)
            {
                producer.close();
            }

            if (consumer != null)
            {
                consumer.close();
            }
        }

        /// <summary>
        /// Returns the message monitor for reporting on received messages on this circuit end.
        /// </summary>
        /// <return> The message monitor for this circuit end. </return>
        public MessageMonitor getMessageMonitor()
        {
            return messageMonitor;
        }

        /// <summary>
        /// Returns the exception monitor for reporting on exceptions received on this circuit end.
        /// </summary>
        /// <return> The exception monitor for this circuit end. </return>
        public ExceptionMonitor getExceptionMonitor()
        {
            return exceptionMonitor;
        }
    }
}
/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework.clocksynch
{
    /// <summary>
    /// ClockSynchFailureException represents failure of a <see cref="ClockSynchronizer"/> to achieve synchronization. For example,
    /// this could be because a reference signal is not available, or because a desired accurracy cannot be attained.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Represent failure to achieve synchronization.
    /// </table>
    /// </summary>
    public class ClockSynchFailureException extends Exception
    {
        /// <summary>
        /// Creates a clock synch failure exception.
        /// </summary>
        /// <param name="message"> The detail message (which is saved for later retrieval by the <see cref="#getMessage()"/> method). </param>
        /// <param name="cause">   The cause (which is saved for later retrieval by the <see cref="#getCause()"/> method).  (A <tt>null</tt>
        ///                        value is permitted, and indicates that the cause is nonexistent or unknown.)</param>
        public ClockSynchFailureException(string message, Throwable cause)
        {
            super(message, cause);
        }
    }
}
/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework.clocksynch
{
    /// <summary>
    /// ClockSynchronizer provides an interface through which two nodes may synchronize their clocks. It is expected that one
    /// node will act as the reference clock, to which no delta need be applied, and the other node will act as the slave,
    /// and which must apply a delta to its local clock to get a clock synchronized with the reference.
    ///
    /// <p/>The slave side will initiate the computation of a clock delta by calling the <see cref="#synch"/> method. This method
    /// will not return until the delta has been computed, at which point there is a method to return its value, as well as
    /// an estimate of the likely error (usually one standard deviation), in the synchronization. For convenience there is a
    /// <see cref="#nanoTime"/> method to return the value of System.nanoTime() with the delta added in.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Trigger a clock synchronization.
    /// <tr><td> Compute a clock delta to apply to the local clock.
    /// <tr><td> Estimate the error in the synchronzation.
    /// </table>
    /// </summary>
    public interface ClockSynchronizer
    {
        /// <summary>
        /// The slave side should call this to copute a clock delta with the reference.
        /// </summary>
        /// <exception cref="ClockSynchFailureException"> If synchronization cannot be achieved. </exception>
        public void synch() throws ClockSynchFailureException;

        /// <summary>
        /// Gets the clock delta in nano seconds.
        /// </summary>
        /// <return> The clock delta in nano seconds. </return>
        public long getDelta();

        /// <summary>
        /// Gets an estimate of the clock error in nan seconds.
        /// </summary>
        /// <return> An estimate of the clock error in nan seconds. </return>
        public long getEpsilon();

        /// <summary>
        /// Gets the local clock time with any computed delta added in.
        /// </summary>
        /// <return> The local clock time with any computed delta added in. </return>
        public long nanoTime();
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using uk.co.thebadgerset.junit.extensions.ShutdownHookable;
using uk.co.thebadgerset.junit.extensions.Throttle;

namespace Apache.Qpid.Integration.Tests.framework.clocksynch
{
    /// <summary>
    /// ClockSynchThread is a convenient utility for running a thread that periodically synchronizes the clock against
    /// a reference. Supply it with a <see cref="ClockSynchronizer"/> and a <see cref="Throttle"/> and it will continually keep the
    /// clock up-to-date at a rate determined by the throttle.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Continually sychronize the clock at a throttled rate.
    /// </table>
    /// </summary>
    public class ClockSynchThread extends Thread : ShutdownHookable
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(ClockSynchThread));

        /// <summary> Holds the clock syncher for the synch thread. </summary>
        private ClockSynchronizer clockSyncher;

        /// <summary> Holds the throttle to limit the synch rate. </summary>
        private Throttle throttle;

        /// <summary> Flag to indicate that the periodic clock syncher should keep running. </summary>
        bool doSynch = true;

        /// <summary>
        /// Creates a clock synchronizer thread from a clock synchronizer and a throttle.
        /// </summary>
        /// <param name="syncher">  The clock synchronizer. </param>
        /// <param name="throttle"> The throttle. </param>
        public ClockSynchThread(ClockSynchronizer syncher, Throttle throttle)
        {
            this.clockSyncher = syncher;
            this.throttle = throttle;
        }

        /// <summary> Terminates the synchronization thread. </summary>
        public void terminate()
        {
            doSynch = false;
        }

        /// <summary> Continually updates the clock, until <see cref="#terminate()"/> is called. </summary>
        public void run()
        {
            while (doSynch)
            {
                // Perform a clock clockSynch.
                try
                {
                    // Wait controlled by the throttle before doing the next synch.
                    throttle.throttle();

                    clockSyncher.synch();
                    log.debug("Clock synched, delta = " + clockSyncher.getDelta() + ", epsilon = " + clockSyncher.getEpsilon()
                              + ".");
                }
                // Terminate the synch thread if the synchronization cannot be achieved.
                catch (ClockSynchFailureException e)
                {
                    log.debug("Cannot synchronize the clock (reference service may be down). Terminating the synch thread.");
                    doSynch = false;
                }
            }
        }

        /// <summary>
        /// Gets the clock synchronizer that is kept continually up to date.
        /// </summary>
        /// <return> The clock synchronizer that is kept continually up to date. </return>
        public ClockSynchronizer getClockSyncher()
        {
            return clockSyncher;
        }

        /// <summary>
        /// Supplies a shutdown hook, that terminates the synching thread.
        /// </summary>
        /// <return> The shut down hook. </return>
        public Thread getShutdownHook()
        {
            return new Thread(new Runnable()
                {
                    public void run()
                    {
                        doSynch = false;
                    }
                });
        }
    }
}
/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework.clocksynch
{

    /// <summary>
    /// LocalClockSynchronizer is a fake <see cref="ClockSynchronizer"/> that simply calls System.nanoTime(). It exists so that
    /// the same tests can be run distributed or locally, taking timings against the ClockSynchronizer interface without
    /// being aware of how they are being run.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Supply the local clock with no delta.
    /// </table>
    /// </summary>
    public class LocalClockSynchronizer : ClockSynchronizer
    {
        /// <summary>
        /// The slave side should call this to copute a clock delta with the reference.
        /// </summary>
        /// <exception cref="Apache.Qpid.Integration.Tests.framework.clocksynch.ClockSynchFailureException"> If synchronization cannot be achieved. </exception>
        public void synch() throws ClockSynchFailureException
        { }

        /// <summary>
        /// Gets the clock delta in nano seconds.
        /// </summary>
        /// <return> The clock delta in nano seconds. </return>
        public long getDelta()
        {
            return 0L;
        }

        /// <summary>
        /// Gets an estimate of the clock error in nan seconds.
        /// </summary>
        /// <return> An estimate of the clock error in nan seconds. </return>
        public long getEpsilon()
        {
            return 0L;
        }

        /// <summary>
        /// Gets the local clock time with any computed delta added in.
        /// </summary>
        /// <return> The local clock time with any computed delta added in. </return>
        public long nanoTime()
        {
            return System.nanoTime();
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using uk.co.thebadgerset.junit.extensions.ShutdownHookable;

using java.io.IOException;
using java.net.*;
using java.nio.ByteBuffer;

namespace Apache.Qpid.Integration.Tests.framework.clocksynch
{
    /// <summary>
    /// UDPClockReference supplies a refernce clock signal (generated from System.nanoTime()).
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Supply a reference clock signal.
    /// </table>
    /// </summary>
    ///
    /// <remarks> Port hard coded. Make configurable.</remarks>
    ///
    /// <remarks> Errors rethrown as runtimes, or silently terminate the service. Could add better error handling if needed.</remarks>
    public class UDPClockReference : Runnable, ShutdownHookable
    {
        /// <summary> Used for debugging. </summary>
        // private static ILog log = LogManager.GetLogger(typeof(UDPClockReference));

        /// <summary> Defines the timeout to use when polling the socket for time requests. </summary>
        private static final int TIMEOUT = 200;

        /// <summary> Defines the port to run the clock reference on. </summary>
        public static final int REFERENCE_PORT = 4444;

        /// <summary> Holds the socket to receive clock reference requests on. </summary>
        protected DatagramSocket socket = null;

        /// <summary> Flag used to indicate that the time server should keep running. Set to false to terminate. </summary>
        protected bool publish = true;

        /// <summary> Creates a clock reference service on the standard port. </summary>
        public UDPClockReference()
        {
            try
            {
                socket = new DatagramSocket(REFERENCE_PORT);
                socket.setSoTimeout(TIMEOUT);
            }
            catch (SocketException e)
            {
                throw new RuntimeException(e);
            }
        }

        /// <summary>
        /// Implements the run loop for this reference time server. This waits for incoming time requests, and replies to
        /// any, with a message with the local time stamp in it. Periodically (controlled by <see cref="#TIMEOUT"/>), the run
        /// loop will check if the <see cref="#publish"/> flag has been cleared, and terminate the reference time service if so.
        /// </summary>
        public void run()
        {
            byte[] buf = new byte[256];
            ByteBuffer bbuf = ByteBuffer.wrap(buf);

            while (publish)
            {
                try
                {
                    // Wait for a reference time request.
                    DatagramPacket packet = new DatagramPacket(buf, buf.length);
                    bool timedOut = false;

                    try
                    {
                        socket.receive(packet);
                    }
                    catch (SocketTimeoutException e)
                    {
                        timedOut = true;
                    }

                    if (!timedOut)
                    {
                        // Work out from the received packet, where to reply to.
                        InetAddress address = packet.getAddress();
                        int port = packet.getPort();

                        // Respond to the time request by sending back the local clock as the reference time.
                        bbuf.putLong(System.nanoTime());
                        bbuf.flip();
                        packet = new DatagramPacket(bbuf.array(), bbuf.capacity(), address, port);

                        socket.send(packet);
                    }
                }
                catch (IOException e)
                {
                    publish = false;
                }
            }

            socket.close();
        }

        /// <summary>
        /// Supplies a shutdown hook.
        /// </summary>
        /// <return> The shut down hook. </return>
        public Thread getShutdownHook()
        {
            return new Thread(new Runnable()
                {
                    public void run()
                    {
                        publish = false;
                    }
                });
        }

        /// <summary>
        /// For testing purposes. Runs a reference clock on the default port.
        /// </summary>
        /// <param name="args"> None. </param>
        public static void main(String[] args)
        {
            try
            {
                // Create the clock reference service.
                UDPClockReference clock = new UDPClockReference();

                // Set up a shutdown hook for it.
                Runtime.getRuntime().addShutdownHook(clock.getShutdownHook());

                // Start the service.
                clock.run();
            }
            catch (Exception e)
            {
                e.printStackTrace();
                System.exit(1);
            }
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using uk.co.thebadgerset.junit.extensions.util.CommandLineParser;
using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using java.io.IOException;
using java.net.*;
using java.nio.ByteBuffer;
using java.util.Arrays;

namespace Apache.Qpid.Integration.Tests.framework.clocksynch
{
    /// <summary>
    /// UDPClockSynchronizer is a <see cref="ClockSynchronizer"/> that sends pings as UDP datagrams, and uses the following simple
    /// algorithm to perform clock synchronization:
    ///
    /// <ol>
    /// <li>Slave initiates synchronization with a Reference clock.</li>
    /// <li>Slave stamps current local time on a "time request" message and sends to the Reference.</li>
    /// <li>Upon receipt by Reference, Reference stamps Reference-time and returns.</li>
    /// <li>Upon receipt by Slave, Slave subtracts current time from sent time and divides by two to compute latency. It
    ///     subtracts current time from Reference time to determine Slave-Reference time delta and adds in the
    ///     half-latency to get the correct clock delta.</li>
    /// <li>The first result is immediately used to update the clock since it will get the local clock into at least
    ///     the right ballpark.</li>
    /// <li>The Slave repeats steps 2 through 4, 15 more times.</li>
    /// <li>The results of the packet receipts are accumulated and sorted in lowest-latency to highest-latency order. The
    ///     median latency is determined by picking the mid-point sample from this ordered list.</li>
    /// <li>All samples outside 1 standard-deviation from the median are discarded and the remaining samples
    ///     are averaged using an arithmetic mean.</li>
    /// </ol>
    ///
    /// <p/>The use of UDP datagrams, instead of TCP based communication eliminates the hidden delays that TCP can introduce,
    /// as it can transparently re-order or re-send packets, or introduce delays as packets are naggled.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Trigger a clock synchronziation.
    /// <tr><td> Compute a clock delta to apply to the local clock.
    /// <tr><td> Estimate the error in the synchronzation.
    /// </table>
    /// </summary>
    public class UDPClockSynchronizer : ClockSynchronizer
    {
        /// <summary> Used for debugging. </summary>
        // private static ILog log = LogManager.GetLogger(typeof(UDPClockSynchronizer));

        /// <summary> Defines the timeout to use when waiting for responses to time requests. </summary>
        private static final int TIMEOUT = 50;

        /// <summary> The clock delta. </summary>
        private long delta = 0L;

        /// <summary> Holds an estimate of the clock error relative to the reference clock. </summary>
        private long epsilon = 0L;

        /// <summary> Holds the address of the reference clock. </summary>
        private InetAddress referenceAddress;

        /// <summary> Holds the socket to communicate with the reference service over. </summary>
        private DatagramSocket socket;

        /// <summary> Used to control the shutdown in the main test loop. </summary>
        private static bool doSynch = true;

        /// <summary>
        /// Creates a clock synchronizer against the specified address for the reference.
        /// </summary>
        /// <param name="address"> The address of the reference service. </param>
        public UDPClockSynchronizer(string address)
        {
            try
            {
                referenceAddress = InetAddress.getByName(address);
            }
            catch (UnknownHostException e)
            {
                throw new RuntimeException(e);
            }
        }

        /// <summary>
        /// The slave side should call this to compute a clock delta with the reference.
        /// </summary>
        /// <exception cref="ClockSynchFailureException"> If synchronization cannot be achieved, due to unavailability of the reference
        /// time service. </exception>
        public void synch() throws ClockSynchFailureException
        {
            try
            {
                socket = new DatagramSocket();
                socket.setSoTimeout(TIMEOUT);

                // Synchronize on a single ping, to get the clock into the right ball-park.
                synch(1);

                // Synchronize on 15 pings.
                synch(15);

                // And again, for greater accuracy, on 31.
                synch(31);

                socket.close();
            }
            catch (SocketException e)
            {
                throw new RuntimeException(e);
            }
        }

        /// <summary>
        /// Updates the synchronization delta by performing the specified number of reference clock requests.
        /// </summary>
        /// <param name="n"> The number of reference clock request cycles to perform. </param>
        ///
        /// <exception cref="ClockSynchFailureException"> If synchronization cannot be achieved, due to unavailability of the reference 
        ///                                               time service. </exception>
        protected void synch(int n) throws ClockSynchFailureException
        {
            // log.debug("protected void synch(int n = " + n + "): called");

            // Create an array of deltas by performing n reference pings.
            long[] delta = new long[n];

            for (int i = 0; i < n; i++)
            {
                delta[i] = ping();
            }

            // Reject any deltas that are larger than 1 s.d. above the median.
            long median = median(delta);
            long sd = standardDeviation(delta);

            // log.debug("median = " + median);
            // log.debug("sd = " + sd);

            long[] tempDeltas = new long[n];
            int count = 0;

            for (int i = 0; i < n; i++)
            {
                if ((delta[i] <= (median + sd)) && (delta[i] >= (median - sd)))
                {
                    tempDeltas[count] = delta[i];
                    count++;
                }
                else
                {
                    // log.debug("Rejected: " + delta[i]);
                }
            }

            System.arraycopy(tempDeltas, 0, delta, 0, count);

            // Estimate the delta as the mean of the remaining deltas.
            this.delta += mean(delta);

            // Estimate the error as the standard deviation of the remaining deltas.
            this.epsilon = standardDeviation(delta);

            // log.debug("this.delta = " + this.delta);
            // log.debug("this.epsilon = " + this.epsilon);
        }

        /// <summary>
        /// Performs a single reference clock request cycle and returns the estimated delta relative to the local clock.
        /// This is computed as the half-latency of the requst cycle, plus the reference clock, minus the local clock.
        /// </summary>
        /// <return> The estimated clock delta. </return>
        ///
        /// <exception cref="ClockSynchFailureException"> If the reference service is not responding. </exception>
        protected long ping() throws ClockSynchFailureException
        {
            // log.debug("protected long ping(): called");

            try
            {
                byte[] buf = new byte[256];

                bool timedOut = false;
                long start = 0L;
                long refTime = 0L;
                long localTime = 0L;
                long latency = 0L;
                int failCount = 0;

                // Keep trying the ping until it gets a response, or 10 tries in a row all time out.
                do
                {
                    // Start timing the request latency.
                    start = nanoTime();

                    // Get the reference time.
                    DatagramPacket packet =
                        new DatagramPacket(buf, buf.length, referenceAddress, UDPClockReference.REFERENCE_PORT);
                    socket.send(packet);
                    packet = new DatagramPacket(buf, buf.length);

                    timedOut = false;

                    try
                    {
                        socket.receive(packet);
                    }
                    catch (SocketTimeoutException e)
                    {
                        timedOut = true;
                        failCount++;

                        continue;
                    }

                    ByteBuffer bbuf = ByteBuffer.wrap(packet.getData());
                    refTime = bbuf.getLong();

                    // Stop timing the request latency.
                    localTime = nanoTime();
                    latency = localTime - start;

                    // log.debug("refTime = " + refTime);
                    // log.debug("localTime = " + localTime);
                    // log.debug("start = " + start);
                    // log.debug("latency = " + latency);
                    // log.debug("delta = " + ((latency / 2) + (refTime - localTime)));

                }
                while (timedOut && (failCount < 10));

                // Fail completely if the fail count is too high.
                if (failCount >= 10)
                {
                    throw new ClockSynchFailureException("Clock reference not responding.", null);
                }

                // Estimate delta as (ref clock + half-latency) - local clock.
                return (latency / 2) + (refTime - localTime);
            }
            catch (IOException e)
            {
                throw new RuntimeException(e);
            }
        }

        /// <summary>
        /// Gets the clock delta in nano seconds.
        /// </summary>
        /// <return> The clock delta in nano seconds. </return>
        public long getDelta()
        {
            return delta;
        }

        /// <summary>
        /// Gets an estimate of the clock error in nan seconds.
        /// </summary>
        /// <return> An estimate of the clock error in nan seconds. </return>
        public long getEpsilon()
        {
            return epsilon;
        }

        /// <summary>
        /// Gets the local clock time with any computed delta added in.
        /// </summary>
        /// <return> The local clock time with any computed delta added in. </return>
        public long nanoTime()
        {
            return System.nanoTime() + delta;
        }

        /// <summary>
        /// Computes the median of a series of values.
        /// </summary>
        /// <param name="values"> The values. </param>
        ///
        /// <return> The median. </return>
        public static long median(long[] values)
        {
            // log.debug("public static long median(long[] values = " + Arrays.ToString(values) + "): called");

            long median;

            // Order the list of values.
            long[] orderedValues = new long[values.length];
            System.arraycopy(values, 0, orderedValues, 0, values.length);
            Arrays.sort(orderedValues);

            // Check if the median is computed from a pair of middle value.
            if ((orderedValues.length % 2) == 0)
            {
                int middle = orderedValues.length / 2;

                median = (orderedValues[middle] + orderedValues[middle - 1]) / 2;
            }
            // The median is computed from a single middle value.
            else
            {
                median = orderedValues[orderedValues.length / 2];
            }

            // log.debug("median = " + median);

            return median;
        }

        /// <summary>
        /// Computes the mean of a series of values.
        /// </summary>
        /// <param name="values"> The values. </param>
        ///
        /// <return> The mean. </return>
        public static long mean(long[] values)
        {
            // log.debug("public static long mean(long[] values = " + Arrays.ToString(values) + "): called");

            long total = 0L;

            for (long value : values)
            {
                total += value;
            }

            long mean = total / values.length;

            // log.debug("mean = " + mean);

            return mean;
        }

        /// <summary>
        /// Computes the variance of series of values.
        /// </summary>
        /// <param name="values"> The values. </param>
        ///
        /// <return> The variance of the values. </return>
        public static long variance(long[] values)
        {
            // log.debug("public static long variance(long[] values = " + Arrays.ToString(values) + "): called");

            long mean = mean(values);

            long totalVariance = 0;

            for (long value : values)
            {
                long diff = (value - mean);
                totalVariance += diff/// diff;
                    }

            long variance = totalVariance / values.length;

            // log.debug("variance = " + variance);

            return variance;
        }

        /// <summary>
        /// Computes the standard deviation of a series of values.
        /// </summary>
        /// <param name="values"> The values. </param>
        ///
        /// <return> The standard deviation. </return>
        public static long standardDeviation(long[] values)
        {
            // log.debug("public static long standardDeviation(long[] values = " + Arrays.ToString(values) + "): called");

            long sd = Double.valueOf(Math.sqrt(variance(values))).longValue();

            // log.debug("sd = " + sd);

            return sd;
        }

        /// <summary>
        /// For testing purposes. Supply address of reference clock as arg 1.
        /// </summary>
        /// <param name="args"> Address of reference clock as arg 1. </param>
        public static void main(String[] args)
        {
            ParsedProperties options =
                new ParsedProperties(CommandLineParser.processCommandLine(args,
                                                                          new CommandLineParser(
                                                                                                new String[][]
                                                                                                {
                                                                                                    { "1", "Address of clock reference service.", "address", "true" }
                                                                                                }), System.getProperties()));

            string address = options.getProperty("1");

            // Create a clock synchronizer.
            UDPClockSynchronizer clockSyncher = new UDPClockSynchronizer(address);

            // Set up a shutdown hook for it.
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable()
                {
                    public void run()
                    {
                        doSynch = false;
                    }
                }));

            // Repeat the clock synching until the user kills the progam.
            while (doSynch)
            {
                // Perform a clock clockSynch.
                try
                {
                    clockSyncher.synch();

                    // Print out the clock delta and estimate of the error.
                    System.out.println("Delta = " + clockSyncher.getDelta());
                    System.out.println("Epsilon = " + clockSyncher.getEpsilon());

                    try
                    {
                        Thread.sleep(250);
                    }
                    catch (InterruptedException e)
                    {
                        // Restore the interrupted status and terminate the loop.
                        Thread.currentThread().interrupt();
                        doSynch = false;
                    }
                }
                // Terminate if the reference time service is unavailable.
                catch (ClockSynchFailureException e)
                {
                    doSynch = false;
                }
            }
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using Apache.Qpid.Integration.Tests.framework.*;
using org.apache.qpid.util.ConversationFactory;

using uk.co.thebadgerset.junit.extensions.TimingController;
using uk.co.thebadgerset.junit.extensions.TimingControllerAware;
using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.Destination;
using javax.jms.JMSException;
using javax.jms.Message;
using javax.jms.Session;

using System.Collections.Generic.LinkedList;
using System.Collections.Generic.IList;

namespace Apache.Qpid.Integration.Tests.framework.distributedcircuit
{
    /// <summary>
    /// DistributedCircuitImpl is a distributed implementation of the test <see cref="Circuit"/>. Many publishers and receivers
    /// accross multiple machines may be combined to form a single test circuit. The test circuit extracts reports from
    /// all of its publishers and receivers, and applies its assertions to these reports.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
    /// <tr><td> Start the circuit running.
    /// <tr><td> Close the circuit down.
    /// <tr><td> Take a reading of the circuits state.
    /// <tr><td> Apply assertions against the circuits state.
    /// <tr><td> Send test messages over the circuit.
    /// <tr><td> Perform the default test procedue on the circuit.
    /// </table>
    /// </summary>
    ///
    /// <remarks> There is a short pause after receiving sender reports before asking for receiver reports, because receivers may
    ///       not have finished receiving all their test messages before the report request arrives. This is going to be a
    ///       problem for taking test timings and needs to be eliminiated. Suggested solution: have receiver send back reports
    ///       asynchronously, on test batch size boundaries, and do so automatically rather than having to have the report
    ///       request sent to them. Number each test run, or otherwise uniquely identify it, when a receiver does not get
    ///       any more messages on a test run for more than a timeout, it can assume the test is complete and send a final
    ///       report. On the coordinator end a future will need to be created to wait for all final reports to come in, and
    ///       to register results and timings for the test. This must work in such a way that a new test cycle can be started
    ///       without waiting for the results of the old one to come in.</remarks>
    ///
    /// <remarks> Add in setting of timing controller, from timing aware test cases.</remarks>
    public class DistributedCircuitImpl : Circuit, TimingControllerAware
    {
        /// <summary> Used for debugging purposes. </summary>
        private static ILog log = LogManager.GetLogger(typeof(DistributedCircuitImpl));

        /// <summary> Holds the conversation factory over which to coordinate the test. </summary>
        protected ConversationFactory conversationFactory;

        /// <summary> Holds the controlSession over which to hold the control conversation. </summary>
        protected Session controlSession;

        /// <summary> Holds the sender nodes in the test circuit. </summary>
        protected IList<TestClientDetails> senders;

        /// <summary> Holds the receiver nodes in the test circuit. </summary>
        protected IList<TestClientDetails> receivers;

        /// <summary> Holds the sender control conversations. </summary>
        protected ConversationFactory.Conversation[] senderConversation;

        /// <summary> Holds the receiver control conversations. </summary>
        protected ConversationFactory.Conversation[] receiverConversation;

        /// <summary> Holds the control topics for the senders in the test circuit. </summary>
        protected Destination[] senderControlTopic;

        /// <summary> Holds the control topics for the receivers in the test circuit. </summary>
        protected Destination[] receiverControlTopic;

        /// <summary> Holds the number of messages to send per test run. </summary>
        protected int numMessages;

        /// <summary>
        /// Holds the timing controller for the circuit. This is used to log test times asynchronously, when reciever nodes
        /// return their reports after senders have completed a test case.
        TimingController timingController;

        /// <summary>
        /// Creates a distributed test circuit on the specified senders and receivers.
        /// </summary>
        /// <param name="session">              The controlSession for all control conversations. </param>
        /// <param name="senders">              The senders. </param>
        /// <param name="receivers">            The receivers. </param>
        /// <param name="senderConversation">   A control conversation with the senders. </param>
        /// <param name="receiverConversation"> A control conversation with the receivers. </param>
        /// <param name="senderControlTopic">   The senders control topic. </param>
        /// <param name="receiverControlTopic"> The receivers control topic. </param>
        protected DistributedCircuitImpl(Session session, IList<TestClientDetails> senders, List<TestClientDetails> receivers,
                                         ConversationFactory.Conversation[] senderConversation, ConversationFactory.Conversation[] receiverConversation,
                                         Destination[] senderControlTopic, Destination[] receiverControlTopic)
        {
            this.controlSession = session;
            this.senders = senders;
            this.receivers = receivers;
            this.senderConversation = senderConversation;
            this.receiverConversation = receiverConversation;
            this.senderControlTopic = senderControlTopic;
            this.receiverControlTopic = receiverControlTopic;
        }

        /// <summary>
        /// Creates a distributed test circuit from the specified test parameters, on the senders and receivers
        /// given.
        /// </summary>
        /// <param name="testProps">           The test parameters. </param>
        /// <param name="senders">             The sender ends in the test circuit. </param>
        /// <param name="receivers">           The receiver ends in the test circuit. </param>
        /// <param name="conversationFactory"> A conversation factory for creating the control conversations with senders and receivers. </param>
        ///
        /// <return> A connected and ready to start, test circuit. </return>
        public static Circuit createCircuit(ParsedProperties testProps, IList<TestClientDetails> senders,
                                            IList<TestClientDetails> receivers, ConversationFactory conversationFactory)
        {
            log.debug("public static Circuit createCircuit(ParsedProperties testProps, IList<TestClientDetails> senders, "
                      + " IList<TestClientDetails> receivers, ConversationFactory conversationFactory)");

            try
            {
                Session session = conversationFactory.getSession();

                // Create control conversations with each of the senders.
                ConversationFactory.Conversation[] senderConversation = new ConversationFactory.Conversation[senders.size()];
                Destination[] senderControlTopic = new Destination[senders.size()];

                for (int i = 0; i < senders.size(); i++)
                {
                    TestClientDetails sender = senders.get(i);

                    senderControlTopic[i] = session.createTopic(sender.privateControlKey);
                    senderConversation[i] = conversationFactory.startConversation();
                }

                log.debug("Sender conversations created.");

                // Create control conversations with each of the receivers.
                ConversationFactory.Conversation[] receiverConversation = new ConversationFactory.Conversation[receivers.size()];
                Destination[] receiverControlTopic = new Destination[receivers.size()];

                for (int i = 0; i < receivers.size(); i++)
                {
                    TestClientDetails receiver = receivers.get(i);

                    receiverControlTopic[i] = session.createTopic(receiver.privateControlKey);
                    receiverConversation[i] = conversationFactory.startConversation();
                }

                log.debug("Receiver conversations created.");

                // Assign the sender role to each of the sending test clients.
                for (int i = 0; i < senders.size(); i++)
                {
                    TestClientDetails sender = senders.get(i);

                    Message assignSender = conversationFactory.getSession().createMessage();
                    TestUtils.setPropertiesOnMessage(assignSender, testProps);
                    assignSender.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
                    assignSender.setStringProperty("ROLE", "SENDER");

                    senderConversation[i].send(senderControlTopic[i], assignSender);
                }

                log.debug("Sender role assignments sent.");

                // Assign the receivers role to each of the receiving test clients.
                for (int i = 0; i < receivers.size(); i++)
                {
                    TestClientDetails receiver = receivers.get(i);

                    Message assignReceiver = session.createMessage();
                    TestUtils.setPropertiesOnMessage(assignReceiver, testProps);
                    assignReceiver.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
                    assignReceiver.setStringProperty("ROLE", "RECEIVER");

                    receiverConversation[i].send(receiverControlTopic[i], assignReceiver);
                }

                log.debug("Receiver role assignments sent.");

                // Wait for the senders and receivers to confirm their roles.
                for (int i = 0; i < senders.size(); i++)
                {
                    senderConversation[i].receive();
                }

                log.debug("Got all sender role confirmations");

                for (int i = 0; i < receivers.size(); i++)
                {
                    receiverConversation[i].receive();
                }

                log.debug("Got all receiver role confirmations");

                // Package everything up as a circuit.
                return new DistributedCircuitImpl(session, senders, receivers, senderConversation, receiverConversation,
                                                  senderControlTopic, receiverControlTopic);
            }
            catch (JMSException e)
            {
                throw new RuntimeException("JMSException not handled.");
            }
        }

        /// <summary>
        /// Used by tests cases that can supply a <see cref="uk.co.thebadgerset.junit.extensions.TimingController"/> to set the
        /// controller on an aware test.
        /// </summary>
        /// <param name="controller"> The timing controller. </param>
        public void setTimingController(TimingController controller)
        {
            this.timingController = controller;
        }

        /// <summary>
        /// Gets the interface on the publishing end of the circuit.
        /// </summary>
        /// <return> The publishing end of the circuit. </return>
        public Publisher getPublisher()
        {
            throw new RuntimeException("Not Implemented.");
        }

        /// <summary>
        /// Gets the interface on the receiving end of the circuit.
        /// </summary>
        /// <return> The receiving end of the circuit. </return>
        public Receiver getReceiver()
        {
            throw new RuntimeException("Not Implemented.");
        }

        /// <summary>
        /// Connects and starts the circuit. After this method is called the circuit is ready to send messages.
        public void start()
        {
            log.debug("public void start(): called");

            try
            {
                // Start the test on each of the senders.
                Message start = controlSession.createMessage();
                start.setStringProperty("CONTROL_TYPE", "START");
                start.setIntProperty("MESSAGE_COUNT", numMessages);

                for (int i = 0; i < senders.size(); i++)
                {
                    senderConversation[i].send(senderControlTopic[i], start);
                }

                log.debug("All senders told to start their tests.");
            }
            catch (JMSException e)
            {
                throw new RuntimeException("Unhandled JMSException.", e);
            }
        }

        /// <summary>
        /// Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
        /// into a report, against which assertions may be checked.
        /// </summary>
        /// <remarks> Replace the asynch receiver report thread with a choice of direct or asynch executor, so that asynch
        ///       or synch logging of test timings is optional. Also need to provide an onMessage method that is capable
        ///       of receiving timing reports that receivers will generate during an ongoing test, on the test sample
        ///       size boundaries. The message timing logging code should be factored out as a common method that can
        ///       be called in response to the final report responses, or the onMessage method. Another alternative is
        ///       to abandon the final report request altogether and just use the onMessage method? I think the two
        ///       differ though, as the final report is used to apply assertions, and the ongoing report is just for
        ///       periodic timing results... In which case, maybe there needs to be a way for the onMessage method
        ///       to process just some of the incoming messages, and forward the rest on to the conversion helper, as
        ///       a sort of pre-conversation helper filter? Make conversation expose its onMessage method (it should
        ///       already) and allow another delivery thread to filter the incoming messages to the conversation.</remarks>
        public void check()
        {
            log.debug("public void check(): called");

            try
            {
                // Wait for all the test senders to return their reports.
                for (int i = 0; i < senders.size(); i++)
                {
                    Message senderReport = senderConversation[i].receive();
                    log.debug("Sender " + senderReport.getStringProperty("CLIENT_NAME") + " reports message count: "
                              + senderReport.getIntProperty("MESSAGE_COUNT"));
                    log.debug("Sender " + senderReport.getStringProperty("CLIENT_NAME") + " reports message time: "
                              + senderReport.getLongProperty("TEST_TIME"));
                }

                log.debug("Got all sender test reports.");

                // Apply sender assertions to pass/fail the tests.

                // Inject a short pause to give the receivers time to finish receiving their test messages.
                TestUtils.pause(500);

                // Ask the receivers for their reports.
                Message statusRequest = controlSession.createMessage();
                statusRequest.setStringProperty("CONTROL_TYPE", "STATUS_REQUEST");

                for (int i = 0; i < receivers.size(); i++)
                {
                    receiverConversation[i].send(receiverControlTopic[i], statusRequest);
                }

                log.debug("All receiver test reports requested.");

                // Wait for all receiver reports to come in, but do so asynchronously.
                Runnable gatherAllReceiverReports =
                    new Runnable()
                    {
                        public void run()
                        {
                            try
                            {
                                // Wait for all the receivers to send their reports.
                                for (int i = 0; i < receivers.size(); i++)
                                {
                                    Message receiverReport = receiverConversation[i].receive();

                                    string clientName = receiverReport.getStringProperty("CLIENT_NAME");
                                    int messageCount = receiverReport.getIntProperty("MESSAGE_COUNT");
                                    long testTime = receiverReport.getLongProperty("TEST_TIME");

                                    log.debug("Receiver " + clientName + " reports message count: " + messageCount);
                                    log.debug("Receiver " + receiverReport.getStringProperty("CLIENT_NAME")
                                              + " reports message time: " + testTime);

                                    // Apply receiver assertions to pass/fail the tests.

                                    // Log the test timings on the asynchronous test timing controller.
                                    /*try
                                      {
                                      timingController.completeTest(true, messageCount, testTime);
                                      }
                                      // The timing controll can throw InterruptedException is the current test is to be
                                      // interrupted.
                                      catch (InterruptedException e)
                                      {
                                      e.printStackTrace();
                                      }*/
                                }

                                log.debug("All receiver test reports received.");
                            }
                            catch (JMSException e)
                            {
                                throw new RuntimeException(e);
                            }
                        }
                    };

                Thread receiverReportsThread = new Thread(gatherAllReceiverReports);
                receiverReportsThread.start();

                // return new Message[] { senderReport, receiverReport };

            }
            catch (JMSException e)
            {
                throw new RuntimeException("Unhandled JMSException.", e);
            }
        }

        /// <summary> Closes the circuit. All associated resources are closed. </summary>
        public void close()
        {
            log.debug("public void close(): called");

            // End the current test on all senders and receivers.
        }

        /// <summary>
        /// Applies a list of assertions against the test circuit. The <see cref="#check()"/> method should be called before doing
        /// this, to ensure that the circuit has gathered its state into a report to assert against.
        /// </summary>
        /// <param name="assertions"> The list of assertions to apply. </param>
        ///
        /// <return> Any assertions that failed. </return>
        public IList<Assertion> applyAssertions(List<Assertion> assertions)
        {
            log.debug("public IList<Assertion> applyAssertions(List<Assertion> assertions = " + assertions + "): called");

            IList<Assertion> failures = new LinkedList<Assertion>();

            for (Assertion assertion : assertions)
            {
                if (!assertion.apply())
                {
                    failures.add(assertion);
                }
            }

            return failures;
        }

        /// <summary>
        /// Runs the default test procedure against the circuit, and checks that all of the specified assertions hold.
        /// </summary>
        /// <param name="numMessages"> The number of messages to send using the default test procedure. </param>
        /// <param name="assertions">  The list of assertions to apply. </param>
        ///
        /// <return> Any assertions that failed. </return>
        ///
        /// <remarks> From check onwards needs to be handled as a future. The future must call back onto the test case to
        ///       report results asynchronously.</remarks>
        public IList<Assertion> test(int numMessages, List<Assertion> assertions)
        {
            log.debug("public IList<Assertion> test(int numMessages = " + numMessages + ", List<Assertion> assertions = "
                      + assertions + "): called");

            // Keep the number of messages to send per test run, where the send method can reference it.
            this.numMessages = numMessages;

            // Start the test running on all sender circuit ends.
            start();

            // Request status reports to be handed in.
            check();

            // Assert conditions on the publishing end of the circuit.
            // Assert conditions on the receiving end of the circuit.
            IList<Assertion> failures = applyAssertions(assertions);

            // Close the circuit ending the current test case.
            close();

            // Pass with no failed assertions or fail with a list of failed assertions.
            return failures;
        }
    }
}
/*
 *
 * 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.
 *
 */
using Apache.Qpid.Integration.Tests.framework.Assertion;
using Apache.Qpid.Integration.Tests.framework.Publisher;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

namespace Apache.Qpid.Integration.Tests.framework.distributedcircuit
{
    /// <summary>
    /// DistributedPublisherImpl represents the status of the publishing side of a test circuit. Its main purpose is to
    /// provide assertions that can be applied to verify the behaviour of a non-local publisher.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Provide assertion that the publishers received no exceptions.
    /// <tr><td> Provide assertion that the publishers received a no consumers error code on every message.
    /// <tr><td> Provide assertion that the publishers received a no route error code on every message.
    /// </table>
    /// </summary>
    public class DistributedPublisherImpl : Publisher
    {
        /// <summary>
        /// Provides an assertion that the publisher encountered no exceptions.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        /// <return> An assertion that the publisher encountered no exceptions. </return>
        public Assertion noExceptionsAssertion(ParsedProperties testProps)
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Provides an assertion that the publisher got a no consumers exception on every message.
        /// </summary>
        /// <return> An assertion that the publisher got a no consumers exception on every message. </return>
        public Assertion noConsumersAssertion()
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Provides an assertion that the publisher got a no rout exception on every message.
        /// </summary>
        /// <return> An assertion that the publisher got a no rout exception on every message. </return>
        public Assertion noRouteAssertion()
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
        public Assertion channelClosedAssertion(ParsedProperties testProps)
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Provides an assertion that the publisher got a given exception during the test.
        /// </summary>
        /// <param name="testProps">      The test configuration properties. </param>
        /// <param name="exceptionClass"> The exception class to check for. </param>
        /// <return> An assertion that the publisher got a given exception during the test. </return>
        public Assertion exceptionAssertion(ParsedProperties testProps, Class<? extends Exception> exceptionClass)
        {
            throw new RuntimeException("Not implemented.");
        }
    }
}
/*
 *
 * 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.
 *
 */
using Apache.Qpid.Integration.Tests.framework.Assertion;
using Apache.Qpid.Integration.Tests.framework.Receiver;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

namespace Apache.Qpid.Integration.Tests.framework.distributedcircuit
{
    /// <summary>
    /// DistributedReceiverImpl represents the status of the receiving side of a test circuit. Its main purpose is to
    /// provide assertions that can be applied to verify the behaviour of a non-local receiver.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Provide assertion that the receivers received no exceptions.
    /// <tr><td> Provide assertion that the receivers received all test messages sent to it.
    /// </table>
    /// </summary>
    public class DistributedReceiverImpl : Receiver
    {
        /// <summary>
        /// Provides an assertion that the receivers encountered no exceptions.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        /// <return> An assertion that the receivers encountered no exceptions. </return>
        public Assertion noExceptionsAssertion(ParsedProperties testProps)
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Provides an assertion that the receivers got all messages that were sent to it.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        /// <return> An assertion that the receivers got all messages that were sent to it. </return>
        public Assertion allMessagesReceivedAssertion(ParsedProperties testProps)
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Provides an assertion that the receivers got none of the messages that were sent to it.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        /// <return> An assertion that the receivers got none of the messages that were sent to it. </return>
        public Assertion noMessagesReceivedAssertion(ParsedProperties testProps)
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
        public Assertion channelClosedAssertion(ParsedProperties testProps)
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Provides an assertion that the receiver got a given exception during the test.
        ///
        /// <param name="testProps"> The test configuration properties. </param>
        /// <param name="exceptionClass"> The exception class to check for. <return> An assertion that the receiver got a given exception during the test. </return> </param>
        public Assertion exceptionAssertion(ParsedProperties testProps, Class<? extends Exception> exceptionClass)
        {
            throw new RuntimeException("Not implemented.");
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using Apache.Qpid.Integration.Tests.framework.*;
using Apache.Qpid.Integration.Tests.framework.distributedtesting.TestClientControlledTest;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
using uk.co.thebadgerset.junit.extensions.util.TestContextProperties;

using javax.jms.*;

namespace Apache.Qpid.Integration.Tests.framework.distributedcircuit
{
    /// <summary>
    /// A TestClientCircuitEnd is a <see cref="CircuitEnd"/> that may be controlled from a
    /// <see cref="Apache.Qpid.Integration.Tests.framework.distributedtesting.TestClient"/>, and that forms a single publishing or
    /// receiving end point in a distributed test <see cref="Apache.Qpid.Integration.Tests.framework.Circuit"/>.
    ///
    /// <p/>When operating in the SENDER role, this circuit end is capable of acting as part of the default circuit test
    /// procedure (described in the class comment for <see cref="Apache.Qpid.Integration.Tests.framework.Circuit"/>). That is, it will
    /// send the number of test messages required, using the test configuration parameters given in the test invite, and
    /// return a report on its activities to the circuit controller.
    ///
    /// <p/>When operation in the RECEIVER role, this circuit end acts as part of the default circuit test procedure. It will
    /// receive test messages, on the setup specified in the test configuration parameters, and keep count of the messages
    /// received, and time taken to receive them. When requested by the circuit controller to provide a report, it will
    /// return this report of its activities.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Provide a message producer for sending messages.
    ///     <td> <see cref="CircuitEnd"/>, <see cref="LocalCircuitFactory"/>, <see cref="TestUtils"/>
    /// <tr><td> Provide a message consumer for receiving messages.
    ///     <td> <see cref="CircuitEnd"/>, <see cref="LocalCircuitFactory"/>, <see cref="TestUtils"/>
    /// <tr><td> Supply the name of the test case that this implements.
    /// <tr><td> Accept/Reject invites based on test parameters. <td> <see cref="MessagingTestConfigProperties"/>
    /// <tr><td> Adapt to assigned roles. <td> <see cref="TestClientControlledTest.Roles"/>
    /// <tr><td> Perform test case actions. <td> <see cref="MessageMonitor"/>
    /// <tr><td> Generate test reports. <td> <see cref="MessageMonitor"/>
    /// </table>
    /// </summary>
    public class TestClientCircuitEnd : CircuitEnd, TestClientControlledTest
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(TestClientCircuitEnd));

        /// <summary> Holds the test parameters. </summary>
        ParsedProperties testProps;

        /// <summary> The number of test messages to send. </summary>
        private int numMessages;

        /// <summary> The role to be played by the test. </summary>
        private Roles role;

        /// <summary> The connection to send the test messages on. </summary>
        private Connection connection;

        /// <summary> Holds the circuit end for this test. </summary>
        CircuitEnd circuitEnd;

        /// <summary>
        /// Holds a message monitor for this circuit end, either the monitor on the consumer when in RECEIVER more, or
        /// a monitor updated on every message sent, when acting as a SENDER.
        MessageMonitor messageMonitor;

        /// <summary>
        /// Should provide the name of the test case that this class implements. The exact names are defined in the
        /// interop testing spec.
        /// </summary>
        /// <return> The name of the test case that this implements. </return>
        public string getName()
        {
            return "DEFAULT_CIRCUIT_TEST";
        }

        /// <summary>
        /// Determines whether the test invite that matched this test case is acceptable.
        /// </summary>
        /// <param name="inviteMessage"> The invitation to accept or reject. </param>
        /// <return> <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it. </return>
        /// </summary>
        /// <exception cref="JMSException"> Any JMSException resulting from reading the message are allowed to fall through. </exception>
        public bool acceptInvite(Message inviteMessage) throws JMSException
        {
            log.debug("public bool acceptInvite(Message inviteMessage): called");

            // Populate the test parameters from the invitation.
            testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);

            for (Object key : testProps.keySet())
            {
                string propName = (String) key;

                // If the test parameters is overridden by the invitation, use it instead.
                string inviteValue = inviteMessage.getStringProperty(propName);

                if (inviteValue != null)
                {
                    testProps.setProperty(propName, inviteValue);
                    log.debug("Test invite supplied override to " + propName + " of " + inviteValue);
                }

            }

            // Accept the invitation.
            return true;
        }

        /// <summary>
        /// Assigns the role to be played by this test case. The test parameters are fully specified in the
        /// assignment message. When this method return the test case will be ready to execute.
        /// </summary>
        /// <param name="role">              The role to be played; sender or receivers. </param>
        /// <param name="assignRoleMessage"> The role assingment message, contains the full test parameters. </param>
        ///
        /// <exception cref="JMSException"> Any JMSException resulting from reading the message are allowed to fall through. </exception>
        public void assignRole(Roles role, Message assignRoleMessage) throws JMSException
        {
            log.debug("public void assignRole(Roles role, Message assignRoleMessage): called");

            // Take note of the role to be played.
            this.role = role;

            // Extract and retain the test parameters.
            numMessages = 1; // assignRoleMessage.getIntProperty("NUM_MESSAGES");

            // Connect using the test parameters.
            connection = TestUtils.createConnection(testProps);

            // Create a circuit end that matches the assigned role and test parameters.
            LocalCircuitFactory circuitFactory = new LocalCircuitFactory();

            switch (role)
            {
                // Check if the sender role is being assigned, and set up a message producer if so.
            case SENDER:

                // Set up the publisher.
                circuitEnd = circuitFactory.createPublisherCircuitEnd(connection, testProps, 0L);

                // Create a custom message monitor that will be updated on every message sent.
                messageMonitor = new MessageMonitor();

                break;

                // Otherwise the receivers role is being assigned, so set this up to listen for messages.
            case RECEIVER:

                // Set up the receiver.
                circuitEnd = circuitFactory.createReceiverCircuitEnd(connection, testProps, 0L);

                // Use the message monitor from the consumer for stats.
                messageMonitor = getMessageMonitor();

                break;
            }

            // Reset all messaging stats for the report.
            messageMonitor.reset();

            connection.start();
        }

        /// <summary>
        /// Performs the test case actions. Returning from here, indicates that the sending role has completed its test.
        /// </summary>
        /// <param name="numMessages"> The number of test messages to send. </param>
        ///
        /// <exception cref="JMSException"> Any JMSException resulting from reading the message are allowed to fall through. </exception>
        ///
        /// <remarks> Add round robin on destinations where multiple destinations being used.</remarks>
        ///
        /// <remarks> Add rate limiting when rate limit specified on publishers.</remarks>
        ///
        /// <remarks> Add Max pending message size protection. The receiver will have to send back some acks once in a while,
        ///       to notify the publisher that its messages are being consumed. This makes the safety valve harder to
        ///       implement than in the single VM case. For example, if the limit is 1000 messages, might want to get back
        ///       an ack every 500, to notify the publisher that it can keep sending. What about pub/sub tests? Will it be
        ///       necessary to wait for an ack from every receiver? This will have the effect of rate limiting to slow
        ///       consumers too.</remarks>
        ///
        /// <remarks> Add commits on every commit batch size boundary.</remarks>
        public void start(int numMessages) throws JMSException
        {
            log.debug("public void start(): called");

            // If in the SENDER role, send the specified number of test messages to the circuit destinations.
            if (role.equals(Roles.SENDER))
            {
                Message testMessage = getSession().createMessage();

                for (int i = 0; i < numMessages; i++)
                {
                    getProducer().send(testMessage);

                    // Increment the message count and timings.
                    messageMonitor.onMessage(testMessage);
                }
            }
        }

        /// <summary>
        /// Gets a report on the actions performed by the test case in its assigned role.
        /// </summary>
        /// <param name="session"> The controlSession to create the report message in. </param>
        /// <return> The report message. </return>
        ///
        /// <exception cref="JMSException"> Any JMSExceptions resulting from creating the report are allowed to fall through. </exception>
        public Message getReport(Session session) throws JMSException
        {
            Message report = session.createMessage();
            report.setStringProperty("CONTROL_TYPE", "REPORT");

            // Add the count of messages sent/received to the report.
            report.setIntProperty("MESSAGE_COUNT", messageMonitor.getNumMessage());

            // Add the time to send/receive messages to the report.
            report.setLongProperty("TEST_TIME", messageMonitor.getTime());

            // Add any exceptions detected to the report.

            return report;
        }

        /// <summary>
        /// Gets the message producer at this circuit end point.
        /// </summary>
        /// <return> The message producer at with this circuit end point. </return>
        public MessageProducer getProducer()
        {
            return circuitEnd.getProducer();
        }

        /// <summary>
        /// Gets the message consumer at this circuit end point.
        /// </summary>
        /// <return> The message consumer at this circuit end point. </return>
        public MessageConsumer getConsumer()
        {
            return circuitEnd.getConsumer();
        }

        /// <summary>
        /// Send the specified message over the producer at this end point.
        /// </summary>
        /// <param name="message"> The message to send. </param>
        ///
        /// <exception cref="JMSException"> Any JMS exception occuring during the send is allowed to fall through. </exception>
        public void send(Message message) throws JMSException
        {
            // Send the message on the circuit ends producer.
            circuitEnd.send(message);
        }

        /// <summary>
        /// Gets the JMS Session associated with this circuit end point.
        /// </summary>
        /// <return> The JMS Session associated with this circuit end point. </return>
        public Session getSession()
        {
            return circuitEnd.getSession();
        }

        /// <summary>
        /// Closes the message producers and consumers and the sessions, associated with this circuit end point.
        ///
        /// <exception cref="JMSException"> Any JMSExceptions occurring during the close are allowed to fall through. </exception>
        public void close() throws JMSException
        {
            // Close the producer and consumer.
            circuitEnd.close();
        }

        /// <summary>
        /// Returns the message monitor for reporting on received messages on this circuit end.
        /// </summary>
        /// <return> The message monitor for this circuit end. </return>
        public MessageMonitor getMessageMonitor()
        {
            return circuitEnd.getMessageMonitor();
        }

        /// <summary>
        /// Returns the exception monitor for reporting on exceptions received on this circuit end.
        /// </summary>
        /// <return> The exception monitor for this circuit end. </return>
        public ExceptionMonitor getExceptionMonitor()
        {
            return circuitEnd.getExceptionMonitor();
        }
    }
}
/*
 *
 * 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.
 *
 */
using junit.framework.Test;
using junit.framework.TestResult;
using junit.framework.TestSuite;

using log4net;
using org.apache.log4j.NDC;

using Apache.Qpid.Integration.Tests.framework.FrameworkBaseCase;
using Apache.Qpid.Integration.Tests.framework.MessagingTestConfigProperties;
using Apache.Qpid.Integration.Tests.framework.TestClientDetails;
using Apache.Qpid.Integration.Tests.framework.TestUtils;
using Apache.Qpid.Integration.Tests.framework.clocksynch.UDPClockReference;
using org.apache.qpid.util.ConversationFactory;

using uk.co.thebadgerset.junit.extensions.TKTestRunner;
using uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;
using uk.co.thebadgerset.junit.extensions.util.CommandLineParser;
using uk.co.thebadgerset.junit.extensions.util.MathUtils;
using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
using uk.co.thebadgerset.junit.extensions.util.TestContextProperties;

using javax.jms.*;

using java.net.InetAddress;
using java.util.*;
using java.util.concurrent.LinkedBlockingQueue;

namespace Apache.Qpid.Integration.Tests.framework.distributedtesting
{
    /// <summary>
    /// <p/>Implements the coordinator client described in the interop testing specification
    /// (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification). This coordinator is built on
    /// top of the JUnit testing framework.
    ///
    /// <p><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Find out what test clients are available. <td> <see cref="ConversationFactory"/>
    /// <tr><td> Decorate available tests to run on all available clients. <td> <see cref="DistributedTestDecorator"/>
    /// <tr><td> Attach XML test result logger.
    /// <tr><td> Terminate the interop testing framework.
    /// </table>
    /// </summary>
    ///
    /// <remarks> Should accumulate failures over all tests, and return with success or fail code based on all results. May need
    ///       to write a special TestResult to do this properly. At the moment only the last one used will be tested for
    ///       errors, as the start method creates a fresh one for each test case run.</remarks>
    public class Coordinator extends TKTestRunner
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(Coordinator));

        /// <summary> Used for reporting to the console. </summary>
        private static ILog console = LogManager.GetLogger("CONSOLE");

        /// <summary> Defines the possible distributed test engines available to run coordinated test cases with. </summary>
        public enum TestEngine
        {
            /// <summary> Specifies the interop test engine. This tests all available clients in pairs. </summary>
            INTEROP,

            /// <summary> Specifies the fanout test engine. This sets up one publisher role, and many reciever roles. </summary>
            FANOUT
        }

        /// <summary>
        /// Holds the test context properties that provides the default test parameters, plus command line overrides.
        /// This is initialized with the default test parameters, to which command line overrides may be applied.
        protected static ParsedProperties testContextProperties =
            TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);

        /// <summary> Holds the URL of the broker to coordinate the tests on. </summary>
        protected string brokerUrl;

        /// <summary> Holds the virtual host to coordinate the tests on. If <tt>null</tt>, then the default virtual host is used. </summary>
        protected string virtualHost;

        /// <summary> Holds the list of all clients that enlisted, when the compulsory invite was issued. </summary>
        protected Set<TestClientDetails> enlistedClients = new HashSet<TestClientDetails>();

        /// <summary> Holds the conversation helper for the control conversation. </summary>
        protected ConversationFactory conversationFactory;

        /// <summary> Holds the connection that the coordinating messages are sent over. </summary>
        protected Connection connection;

        /// <summary> Holds the path of the directory to output test results too, if one is defined. </summary>
        protected string reportDir;

        /// <summary> Holds the coordinating test engine type to run the tests through. </summary>
        protected TestEngine engine;

        /// <summary> Flag that indicates that all test clients should be terminated upon completion of the test cases. </summary>
        protected bool terminate;

        /// <summary>
        /// Creates an interop test coordinator on the specified broker and virtual host.
        /// </summary>
        /// <param name="repetitions">        The number of times to repeat the test, or test batch size. </param>
        /// <param name="duration">           The length of time to run the tests for. -1 means no duration has been set. </param>
        /// <param name="threads">            The concurrency levels to ramp up to. </param>
        /// <param name="delay">              A delay in milliseconds between test runs. </param>
        /// <param name="params">             The sets of 'size' parameters to pass to test. </param>
        /// <param name="testCaseName">       The name of the test case to run. </param>
        /// <param name="reportDir">          The directory to output the test results to. </param>
        /// <param name="runName">            The name of the test run; used to name the output file. </param>
        /// <param name="verbose">            Whether to print comments during test run. </param>
        /// <param name="brokerUrl">          The URL of the broker to connect to. </param>
        /// <param name="virtualHost">        The virtual host to run all tests on. Optional, may be <tt>null</tt>. </param>
        /// <param name="engine">             The distributed test engine type to run the tests with. </param>
        /// <param name="terminate">          <tt>true</tt> if test client nodes should be terminated at the end of the tests. </param>
        /// <param name="csv">                <tt>true</tt> if the CSV results listener should be attached. </param>
        /// <param name="xml">                <tt>true</tt> if the XML results listener should be attached. </param>
        /// <param name="decoratorFactories"> List of factories for user specified decorators. </param>
        public Coordinator(Integer repetitions, Long duration, int[] threads, int delay, int[] params, string testCaseName,
                           string reportDir, string runName, bool verbose, string brokerUrl, string virtualHost, TestEngine engine,
                           bool terminate, bool csv, bool xml, IList<TestDecoratorFactory> decoratorFactories)
        {
            super(repetitions, duration, threads, delay, params, testCaseName, reportDir, runName, csv, xml, verbose,
                  decoratorFactories);

            log.debug("public Coordinator(Integer repetitions = " + repetitions + " , Long duration = " + duration
                      + ", int[] threads = " + Arrays.ToString(threads) + ", int delay = " + delay + ", int[] params = "
                      + Arrays.ToString(params) + ", string testCaseName = " + testCaseName + ", string reportDir = " + reportDir
                      + ", string runName = " + runName + ", bool verbose = " + verbose + ", string brokerUrl = " + brokerUrl
                      + ", string virtualHost =" + virtualHost + ", TestEngine engine = " + engine + ", bool terminate = "
                      + terminate + ", bool csv = " + csv + ", bool xml = " + xml + "): called");

            // Retain the connection parameters.
            this.brokerUrl = brokerUrl;
            this.virtualHost = virtualHost;
            this.reportDir = reportDir;
            this.engine = engine;
            this.terminate = terminate;
        }

        /// <summary>
        /// The entry point for the interop test coordinator. This client accepts the following command line arguments:
        ///
        /// <p/><table>
        /// <tr><td> -b         <td> The broker URL.   <td> Mandatory.
        /// <tr><td> -h         <td> The virtual host. <td> Optional.
        /// <tr><td> -o         <td> The directory to output test results to. <td> Optional.
        /// <tr><td> -e         <td> The type of test distribution engine to use. <td> Optional. One of: interop, fanout.
        /// <tr><td> ...        <td> Free arguments. The distributed test cases to run.
        ///                     <td> Mandatory. At least one must be defined.
        /// <tr><td> name=value <td> Trailing argument define name/value pairs. Added to the test contenxt properties.
        ///                     <td> Optional.
        /// </table>
        /// </summary>
        /// <param name="args"> The command line arguments. </param>
        public static void main(String[] args)
        {
            NDC.push("coordinator");
            log.debug("public static void main(String[] args = " + Arrays.ToString(args) + "): called");
            console.info("Qpid Distributed Test Coordinator.");

            // Override the default broker url to be localhost:5672.
            testContextProperties.setProperty(MessagingTestConfigProperties.BROKER_PROPNAME, "tcp://localhost:5672");

            try
            {
                // Use the command line parser to evaluate the command line with standard handling behaviour (print errors
                // and usage then exist if there are errors).
                // Any options and trailing name=value pairs are also injected into the test context properties object,
                // to override any defaults that may have been set up.
                ParsedProperties options =
                    new ParsedProperties(CommandLineParser.processCommandLine(args,
                                                                              new CommandLineParser(
                                                                                                    new String[][]
                                                                                                    {
                                                                                                        { "b", "The broker URL.", "broker", "false" },
                                                                                                        { "h", "The virtual host to use.", "virtual host", "false" },
                                                                                                        { "o", "The name of the directory to output test timings to.", "dir", "false" },
                                                                                                        {
                                                                                                            "e", "The test execution engine to use. Default is interop.", "engine", "interop",
                                                                                                            "^interop$|^fanout$", "true"
                                                                                                        },
                                                                                                        { "t", "Terminate test clients on completion of tests.", null, "false" },
                                                                                                        { "-csv", "Output test results in CSV format.", null, "false" },
                                                                                                        { "-xml", "Output test results in XML format.", null, "false" },
                                                                                                        {
                                                                                                            "-trefaddr", "To specify an alternative to hostname for time singal reference.",
                                                                                                            "address", "false"
                                                                                                        },
                                                                                                        {
                                                                                                            "c", "The number of tests to run concurrently.", "num", "false",
                                                                                                            MathUtils.SEQUENCE_REGEXP
                                                                                                        },
                                                                                                        { "r", "The number of times to repeat each test.", "num", "false" },
                                                                                                        {
                                                                                                            "d", "The length of time to run the tests for.", "duration", "false",
                                                                                                            MathUtils.DURATION_REGEXP
                                                                                                        },
                                                                                                        {
                                                                                                            "f", "The maximum rate to call the tests at.", "frequency", "false",
                                                                                                            "^([1-9][0-9]*)/([1-9][0-9]*)$"
                                                                                                        },
                                                                                                        { "s", "The size parameter to run tests with.", "size", "false", MathUtils.SEQUENCE_REGEXP },
                                                                                                        { "v", "Verbose mode.", null, "false" },
                                                                                                        { "n", "A name for this test run, used to name the output file.", "name", "true" },
                                                                                                        {
                                                                                                            "X:decorators", "A list of additional test decorators to wrap the tests in.",
                                                                                                            "\"class.name[:class.name]*\"", "false"
                                                                                                        }
                                                                                                    }), testContextProperties));

                // Extract the command line options.
                string brokerUrl = options.getProperty("b");
                string virtualHost = options.getProperty("h");
                string reportDir = options.getProperty("o");
                reportDir = (reportDir == null) ? "." : reportDir;
                string testEngine = options.getProperty("e");
                TestEngine engine = "fanout".equals(testEngine) ? TestEngine.FANOUT : TestEngine.INTEROP;
                bool terminate = options.getPropertyAsBoolean("t");
                bool csvResults = options.getPropertyAsBoolean("-csv");
                bool xmlResults = options.getPropertyAsBoolean("-xml");
                string threadsstring = options.getProperty("c");
                Integer repetitions = options.getPropertyAsInteger("r");
                string durationstring = options.getProperty("d");
                string paramsstring = options.getProperty("s");
                bool verbose = options.getPropertyAsBoolean("v");
                string testRunName = options.getProperty("n");
                string decorators = options.getProperty("X:decorators");

                int[] threads = (threadsstring == null) ? null : MathUtils.parseSequence(threadsString);
                int[] params = (paramsstring == null) ? null : MathUtils.parseSequence(paramsString);
                Long duration = (durationstring == null) ? null : MathUtils.parseDuration(durationString);

                // If broker or virtual host settings were specified as command line options, override the defaults in the
                // test context properties with them.

                // Collection all of the test cases to be run.
                Collection<Class<? extends FrameworkBaseCase>> testCaseClasses =
                    new ArrayList<Class<? extends FrameworkBaseCase>>();

                // Create a list of test decorator factories for use specified decorators to be applied.
                IList<TestDecoratorFactory> decoratorFactories = parseDecorators(decorators);

                // Scan for available test cases using a classpath scanner.
                // ClasspathScanner.getMatches(DistributedTestCase.class, "^Test.*", true);

                // Hard code the test classes till the classpath scanner is fixed.
                // Collections.addAll(testCaseClasses, InteropTestCase1DummyRun.class, InteropTestCase2BasicP2P.class,
                // InteropTestCase3BasicPubSub.class);

                // Parse all of the free arguments as test cases to run.
                for (int i = 1; true; i++)
                {
                    string nextFreeArg = options.getProperty(Integer.ToString(i));

                    // Terminate the loop once all free arguments have been consumed.
                    if (nextFreeArg == null)
                    {
                        break;
                    }

                    try
                    {
                        Class nextClass = Class.forName(nextFreeArg);

                        if (FrameworkBaseCase.class.isAssignableFrom(nextClass))
                        {
                            testCaseClasses.add(nextClass);
                            console.info("Found distributed test case: " + nextFreeArg);
                        }
                    }
                    catch (ClassNotFoundException e)
                    {
                        console.info("Unable to instantiate the test case: " + nextFreeArg + ".");
                    }
                }

                // Check that some test classes were actually found.
                if (testCaseClasses.isEmpty())
                {
                    throw new RuntimeException(
                                               "No test cases implementing FrameworkBaseCase were specified on the command line.");
                }

                // Extract the names of all the test classes, to pass to the start method.
                int i = 0;
                String[] testClassNames = new String[testCaseClasses.size()];

                for (Class testClass : testCaseClasses)
                {
                    testClassNames[i++] = testClass.getName();
                }

                // Create a coordinator and begin its test procedure.
                Coordinator coordinator =
                    new Coordinator(repetitions, duration, threads, 0, params, null, reportDir, testRunName, verbose, brokerUrl,
                                    virtualHost, engine, terminate, csvResults, xmlResults, decoratorFactories);

                TestResult testResult = coordinator.start(testClassNames);

                // Return different error codes, depending on whether or not there were test failures.
                if (testResult.failureCount() > 0)
                {
                    System.exit(FAILURE_EXIT);
                }
                else
                {
                    System.exit(SUCCESS_EXIT);
                }
            }
            catch (Exception e)
            {
                log.debug("Top level handler caught execption.", e);
                console.info(e.getMessage());
                e.printStackTrace();
                System.exit(EXCEPTION_EXIT);
            }
        }

        /// <summary>
        /// Starts all of the test classes to be run by this coordinator.
        /// </summary>
        /// <param name="testClassNames"> An array of all the coordinating test case implementations. </param>
        ///
        /// <return> A JUnit TestResult to run the tests with. </return>
        ///
        /// <exception cref="Exception"> Any underlying exceptions are allowed to fall through, and fail the test process. </exception>
        public TestResult start(String[] testClassNames) throws Exception
        {
            log.debug("public TestResult start(String[] testClassNames = " + Arrays.ToString(testClassNames) + ": called");

            // Connect to the broker.
            connection = TestUtils.createConnection(TestContextProperties.getInstance());
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

            Destination controlTopic = session.createTopic("iop.control");
            Destination responseQueue = session.createQueue("coordinator");

            conversationFactory = new ConversationFactory(connection, responseQueue, LinkedBlockingQueue.class);
            ConversationFactory.Conversation conversation = conversationFactory.startConversation();

            connection.start();

            // Broadcast the compulsory invitation to find out what clients are available to test.
            Message invite = session.createMessage();
            invite.setStringProperty("CONTROL_TYPE", "INVITE");
            invite.setJMSReplyTo(responseQueue);

            conversation.send(controlTopic, invite);

            // Wait for a short time, to give test clients an opportunity to reply to the invitation.
            Collection<Message> enlists = conversation.receiveAll(0, 500);
            enlistedClients = extractEnlists(enlists);

            for (TestClientDetails client : enlistedClients)
            {
                log.debug("Got enlisted test client: " + client);
                console.info("Test node " + client.clientName + " available.");
            }

            // Start the clock reference service running.
            UDPClockReference clockReference = new UDPClockReference();
            Thread clockRefThread = new Thread(clockReference);
            registerShutdownHook(clockReference);
            clockRefThread.start();

            // Broadcast to all clients to synchronize their clocks against the coordinators clock reference.
            Message clockSynchRequest = session.createMessage();
            clockSynchRequest.setStringProperty("CONTROL_TYPE", "CLOCK_SYNCH");

            string localAddress = InetAddress.getByName(InetAddress.getLocalHost().getHostName()).getHostAddress();
            clockSynchRequest.setStringProperty("ADDRESS", localAddress);

            conversation.send(controlTopic, clockSynchRequest);

            // Run the test in the suite using JUnit.
            TestResult result = null;

            for (string testClassName : testClassNames)
            {
                // Record the current test class, so that the test results can be output to a file incorporating this name.
                this.currentTestClassName = testClassName;

                result = super.start(new String[] { testClassName });
            }

            // At this point in time, all tests have completed. Broadcast the shutdown message, if the termination option
            // was set on the command line.
            if (terminate)
            {
                Message terminate = session.createMessage();
                terminate.setStringProperty("CONTROL_TYPE", "TERMINATE");

                conversation.send(controlTopic, terminate);
            }

            return result;
        }

        /// <summary>
        /// For a collection of enlist messages, this method pulls out of the client details for the enlisting clients.
        /// </summary>
        /// <param name="enlists"> The enlist messages. </param>
        ///
        /// <return> A set of enlisting clients, extracted from the enlist messages. </return>
        ///
        /// <exception cref="JMSException"> Any underlying JMSException is allowed to fall through. </exception>
        public static Set<TestClientDetails> extractEnlists(Collection<Message> enlists) throws JMSException
        {
            log.debug("public static Set<TestClientDetails> extractEnlists(Collection<Message> enlists = " + enlists
                      + "): called");

            Set<TestClientDetails> enlistedClients = new HashSet<TestClientDetails>();

            // Retain the list of all available clients.
            for (Message enlist : enlists)
            {
                TestClientDetails clientDetails = new TestClientDetails();
                clientDetails.clientName = enlist.getStringProperty("CLIENT_NAME");
                clientDetails.privateControlKey = enlist.getStringProperty("CLIENT_PRIVATE_CONTROL_KEY");

                string replyType = enlist.getStringProperty("CONTROL_TYPE");

                if ("ENLIST".equals(replyType))
                {
                    enlistedClients.add(clientDetails);
                }
                else if ("DECLINE".equals(replyType))
                {
                    log.debug("Test client " + clientDetails.clientName + " declined the invite.");
                }
                else
                {
                    log.warn("Got an unknown reply type, " + replyType + ", to the invite.");
                }
            }

            return enlistedClients;
        }

        /// <summary>
        /// Runs a test or suite of tests, using the super class implemenation. This method wraps the test to be run
        /// in any test decorators needed to add in the coordinators ability to invite test clients to participate in
        /// tests.
        /// </summary>
        /// <param name="test"> The test to run. </param>
        /// <param name="wait"> Undocumented. Nothing in the JUnit javadocs to say what this is for. </param>
        ///
        /// <return> The results of the test run. </return>
        public TestResult doRun(Test test, bool wait)
        {
            log.debug("public TestResult doRun(Test \"" + test + "\", bool " + wait + "): called");

            // Wrap all tests in the test suite with WrappedSuiteTestDecorators. This is quite ugly and a bit baffling,
            // but the reason it is done is because the JUnit implementation of TestDecorator has some bugs in it.
            WrappedSuiteTestDecorator targetTest = null;

            if (test instanceof TestSuite)
            {
                log.debug("targetTest is a TestSuite");

                TestSuite suite = (TestSuite) test;

                int numTests = suite.countTestCases();
                log.debug("There are " + numTests + " in the suite.");

                for (int i = 0; i < numTests; i++)
                {
                    Test nextTest = suite.testAt(i);
                    log.debug("suite.testAt(" + i + ") = " + nextTest);

                    if (nextTest instanceof FrameworkBaseCase)
                    {
                        log.debug("nextTest is a FrameworkBaseCase");
                    }
                }

                targetTest = new WrappedSuiteTestDecorator(suite);
                log.debug("Wrapped with a WrappedSuiteTestDecorator.");
            }

            // Apply any optional user specified decorators.
            targetTest = applyOptionalUserDecorators(targetTest);

            // Wrap the tests in a suitable distributed test decorator, to perform the invite/test cycle.
            targetTest = newTestDecorator(targetTest, enlistedClients, conversationFactory, connection);

            // TestSuite suite = new TestSuite();
            // suite.addTest(targetTest);

            // Wrap the tests in a scaled test decorator to them them as a 'batch' in one thread.
            // targetTest = new ScaledTestDecorator(targetTest, new int[] { 1 });

            return super.doRun(targetTest, wait);
        }

        /// <summary>
        /// Creates a wrapped test decorator, that is capable of inviting enlisted clients to participate in a specified
        /// test. This is the test engine that sets up the roles and sequences a distributed test case.
        /// </summary>
        /// <param name="targetTest">          The test decorator to wrap. </param>
        /// <param name="enlistedClients">     The enlisted clients available to run the test. </param>
        /// <param name="conversationFactory"> The conversation factory used to build conversation helper over the specified connection. </param>
        /// <param name="connection">          The connection to talk to the enlisted clients over. </param>
        ///
        /// <return> An invititing test decorator, that invites all the enlisted clients to participate in tests, in pairs. </return>
        protected DistributedTestDecorator newTestDecorator(WrappedSuiteTestDecorator targetTest,
                                                            Set<TestClientDetails> enlistedClients, ConversationFactory conversationFactory, Connection connection)
        {
            switch (engine)
            {
            case FANOUT:
                return new FanOutTestDecorator(targetTest, enlistedClients, conversationFactory, connection);
            case INTEROP:
            default:
                return new InteropTestDecorator(targetTest, enlistedClients, conversationFactory, connection);
            }
        }
    }
}
/*
 *
 * 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.
 *
 */
using junit.framework.TestResult;

using log4net;

using Apache.Qpid.Integration.Tests.framework.FrameworkBaseCase;
using Apache.Qpid.Integration.Tests.framework.TestClientDetails;
using Apache.Qpid.Integration.Tests.framework.sequencers.CircuitFactory;
using org.apache.qpid.util.ConversationFactory;

using uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;

using javax.jms.Connection;
using javax.jms.Destination;
using javax.jms.JMSException;
using javax.jms.Message;

using java.util.*;

namespace Apache.Qpid.Integration.Tests.framework.distributedtesting
{
    /// <summary>
    /// DistributedTestDecorator is a base class for writing test decorators that invite test clients to participate in
    /// distributed test cases. It provides a helper method, <see cref="#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 <see cref="FrameworkBaseCase"/> test, it replaces the default <see cref="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> <see cref="ConversationFactory"/>.
    /// </table>
    /// </summary>
    public abstract class DistributedTestDecorator extends WrappedSuiteTestDecorator
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(DistributedTestDecorator));

        /// <summary> Holds the contact information for all test clients that are available and that may take part in the test. </summary>
        Set<TestClientDetails> allClients;

        /// <summary> Holds the conversation helper for the control level conversation for coordinating the test through. </summary>
        ConversationFactory conversationFactory;

        /// <summary> Holds the connection that the control conversation is held over. </summary>
        Connection connection;

        /// <summary> Holds the underlying test suite that this decorator wraps. </summary>
        WrappedSuiteTestDecorator testSuite;

        /// <summary> Holds the control topic, on which test invitations are broadcast. </summary>
        protected Destination controlTopic;

        /// <summary>
        /// Creates a wrapped suite test decorator from another one.
        /// </summary>
        /// <param name="suite">               The test suite. </param>
        /// <param name="availableClients">    The list of all clients that responded to the compulsory invite. </param>
        /// <param name="controlConversation"> The conversation helper for the control level, test coordination conversation. </param>
        /// <param name="controlConnection">   The connection that the coordination messages are sent over. </param>
        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);
            }
        }

        /// <summary>
        /// Should run all of the tests in the wrapped test suite.
        /// </summary>
        /// <param name="testResult"> The the results object to monitor the test results with. </param>
        public abstract void run(TestResult testResult);

        /// <summary>
        /// Should provide the distributed test sequencer to pass to <see cref="Apache.Qpid.Integration.Tests.framework.FrameworkBaseCase"/>
        /// tests.
        /// </summary>
        /// <return> A distributed test sequencer. </return>
        public abstract CircuitFactory getTestSequencer();

        /// <summary>
        /// Broadcasts an invitation to participate in a coordinating test case to find out what clients are available to
        /// run the test case.
        /// </summary>
        /// <param name="coordTest"> The coordinating test case to broadcast an inviate for. </param>
        ///
        /// <return> A set of test clients that accepted the invitation. </return>
        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;
        }

        /// <summary>
        /// Prints a string summarizing this test decorator, mainly for debugging purposes.
        /// </summary>
        /// <return> string representation for debugging purposes. </return>
        public string ToString()
        {
            return "DistributedTestDecorator: [ testSuite = " + testSuite + " ]";
        }
    }
}
/*
 *
 * 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.
 *
 */
using junit.framework.Test;
using junit.framework.TestResult;

using log4net;

using Apache.Qpid.Integration.Tests.framework.DropInTest;
using Apache.Qpid.Integration.Tests.framework.FrameworkBaseCase;
using Apache.Qpid.Integration.Tests.framework.TestClientDetails;
using Apache.Qpid.Integration.Tests.framework.sequencers.CircuitFactory;
using Apache.Qpid.Integration.Tests.framework.sequencers.FanOutCircuitFactory;
using org.apache.qpid.util.ConversationFactory;

using uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;

using javax.jms.Connection;
using javax.jms.JMSException;
using javax.jms.Message;
using javax.jms.MessageListener;

using System.Collections.Generic.Collection;
using java.util.Iterator;
using java.util.Set;

namespace Apache.Qpid.Integration.Tests.framework.distributedtesting
{
    /// <summary>
    /// FanOutTestDecorator is an <see cref="DistributedTestDecorator"/> that runs one test client in the sender role, and the remainder
    /// in the receivers role. It also has the capability to listen for new test cases joining the test beyond the initial start
    /// point. This feature can be usefull when experimenting with adding more load, in the form of more test clients, to assess
    /// its impact on a running test.
    ///
    /// <p><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Execute coordinated test cases. <td> <see cref="FrameworkBaseCase"/>
    /// <tr><td> Accept test clients joining a running test.
    /// </table>
    /// </summary>
    public class FanOutTestDecorator extends DistributedTestDecorator : MessageListener
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(FanOutTestDecorator));

        /// <summary> Holds the currently running test case. </summary>
        FrameworkBaseCase currentTest = null;

        /// <summary>
        /// Creates a wrapped suite test decorator from another one.
        /// </summary>
        /// <param name="suite">               The test suite. </param>
        /// <param name="availableClients">    The list of all clients that responded to the compulsory invite. </param>
        /// <param name="controlConversation"> The conversation helper for the control level, test coordination conversation. </param>
        /// <param name="controlConnection">   The connection that the coordination messages are sent over. </param>
        public FanOutTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> availableClients,
                                   ConversationFactory controlConversation, Connection controlConnection)
        {
            super(suite, availableClients, controlConversation, controlConnection);

            log.debug("public DistributedTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> allClients = "
                      + availableClients + ", ConversationHelper controlConversation = " + controlConversation + "): called");

            testSuite = suite;
            allClients = availableClients;
            conversationFactory = controlConversation;
            connection = controlConnection;

            // Sign available clients up to the test.
            for (Test test : getAllUnderlyingTests())
            {
                FrameworkBaseCase coordTest = (FrameworkBaseCase) test;

                // Get all of the clients able to participate in the test.
                Set<TestClientDetails> enlists = signupClients(coordTest);

                // Check that there were some clients available.
                if (enlists.size() == 0)
                {
                    throw new RuntimeException("No clients to test with");
                }

                // Create a distributed test circuit factory for the test.
                CircuitFactory circuitFactory = getTestSequencer();

                // Set up the first client in the sender role, and the remainder in the receivers role.
                Iterator<TestClientDetails> clients = enlists.iterator();
                circuitFactory.setSender(clients.next());

                while (clients.hasNext())
                {
                    // Set the sending and receiving client details on the test case.
                    circuitFactory.setReceiver(clients.next());
                }

                // Pass down the connection to hold the coordinating conversation over.
                circuitFactory.setConversationFactory(conversationFactory);

                // If the current test case is a drop-in test, set it up as the currently running test for late joiners to
                // add in to. Otherwise the current test field is set to null, to indicate that late joiners are not allowed.
                currentTest = (coordTest instanceof DropInTest) ? coordTest : null;

                // Execute the test case.
                coordTest.setCircuitFactory(circuitFactory);
            }
        }

        /// <summary>
        /// Broadcasts a test invitation and accepts enlists from participating clients. The wrapped test cases are run
        /// with one test client in the sender role, and the remaining test clients in the receiving role.
        ///
        /// <p/>Any JMSExceptions during the invite/enlist conversation will be allowed to fall through as runtime
        /// exceptions, resulting in the non-completion of the test run.
        /// </summary>
        /// <param name="testResult"> The the results object to monitor the test results with. </param>
        ///
        /// <remarks> Better error recovery for failure of the invite/enlist conversation could be added.</remarks>
        public void run(TestResult testResult)
        {
            log.debug("public void run(TestResult testResult): called");

            // Listen for late joiners on the control topic.
            try
            {
                conversationFactory.getSession().createConsumer(controlTopic).setMessageListener(this);
            }
            catch (JMSException e)
            {
                throw new RuntimeException("Unable to set up the message listener on the control topic.", e);
            }

            // Run all of the test cases in the test suite.
            /*for (Test test : getAllUnderlyingTests())
              {
              FrameworkBaseCase coordTest = (FrameworkBaseCase) test;

              // Get all of the clients able to participate in the test.
              Set<TestClientDetails> enlists = signupClients(coordTest);

              // Check that there were some clients available.
              if (enlists.size() == 0)
              {
              throw new RuntimeException("No clients to test with");
              }

              // Create a distributed test circuit factory for the test.
              CircuitFactory circuitFactory = getTestSequencer();

              // Set up the first client in the sender role, and the remainder in the receivers role.
              Iterator<TestClientDetails> clients = enlists.iterator();
              circuitFactory.setSender(clients.next());

              while (clients.hasNext())
              {
              // Set the sending and receiving client details on the test case.
              circuitFactory.setReceiver(clients.next());
              }

              // Pass down the connection to hold the coordinating conversation over.
              circuitFactory.setConversationFactory(conversationFactory);

              // If the current test case is a drop-in test, set it up as the currently running test for late joiners to
              // add in to. Otherwise the current test field is set to null, to indicate that late joiners are not allowed.
              currentTest = (coordTest instanceof DropInTest) ? coordTest : null;

              // Execute the test case.
              coordTest.setCircuitFactory(circuitFactory);
              }*/

            // Run all of the test cases in the test suite.
            for (Test test : getAllUnderlyingTests())
            {
                FrameworkBaseCase coordTest = (FrameworkBaseCase) test;

                coordTest.run(testResult);

                currentTest = null;
            }
        }

        /// <summary>
        /// Should provide the distributed test sequencer to pass to <see cref="Apache.Qpid.Integration.Tests.framework.FrameworkBaseCase"/>
        /// tests.
        /// </summary>
        /// <return> A distributed test sequencer. </return>
        public CircuitFactory getTestSequencer()
        {
            return new FanOutCircuitFactory();
        }

        /// <summary>
        /// Listens to incoming messages on the control topic. If the messages are 'join' messages, signalling a new
        /// test client wishing to join the current test, then the new client will be added to the current test in the
        /// receivers role.
        /// </summary>
        /// <param name="message"> The incoming control message. </param>
        public void onMessage(Message message)
        {
            try
            {
                // Check if the message is from a test client attempting to join a running test, and join it to the current
                // test case if so.
                if (message.getStringProperty("CONTROL_TYPE").equals("JOIN") && (currentTest != null))
                {
                    ((DropInTest) currentTest).lateJoin(message);
                }
            }
            // There is not a lot can be done with this error, so it is deliberately ignored.
            catch (JMSException e)
            {
                log.debug("Unable to process message:" + message);
            }
        }

        /// <summary>
        /// Prints a string summarizing this test decorator, mainly for debugging purposes.
        /// </summary>
        /// <return> string representation for debugging purposes. </return>
        public string ToString()
        {
            return "FanOutTestDecorator: [ testSuite = " + testSuite + " ]";
        }
    }
}
/*
 *
 * 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.
 *
 */
using junit.framework.Test;
using junit.framework.TestResult;

using log4net;

using Apache.Qpid.Integration.Tests.framework.FrameworkBaseCase;
using Apache.Qpid.Integration.Tests.framework.TestClientDetails;
using Apache.Qpid.Integration.Tests.framework.sequencers.CircuitFactory;
using Apache.Qpid.Integration.Tests.framework.sequencers.InteropCircuitFactory;
using org.apache.qpid.util.ConversationFactory;

using uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;

using javax.jms.Connection;

using java.util.*;

namespace Apache.Qpid.Integration.Tests.framework.distributedtesting
{
    /// <summary>
    /// DistributedTestDecorator is a test decorator, written to implement the interop test specification. Given a list
    /// of enlisted test clients, that are available to run interop tests, this decorator invites them to participate
    /// in each test in the wrapped test suite. Amongst all the clients that respond to the invite, all pairs are formed,
    /// and each pairing (in both directions, but excluding the reflexive pairings) is split into a sender and receivers
    /// role and a test case run between them. Any enlisted combinations that do not accept a test invite are automatically
    /// failed.
    ///
    /// <p><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Broadcast test invitations and collect enlists. <td> <see cref="org.apache.qpid.util.ConversationFactory"/>.
    /// <tr><td> Output test failures for clients unwilling to run the test case. <td> <see cref="Coordinator"/>
    /// <tr><td> Execute distributed test cases. <td> <see cref="FrameworkBaseCase"/>
    /// <tr><td> Fail non-participating pairings. <td> <see cref="OptOutTestCase"/>
    /// </table>
    /// </summary>
    public class InteropTestDecorator extends DistributedTestDecorator
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(InteropTestDecorator));

        /// <summary>
        /// Creates a wrapped suite test decorator from another one.
        /// </summary>
        /// <param name="suite">               The test suite. </param>
        /// <param name="availableClients">    The list of all clients that responded to the compulsory invite. </param>
        /// <param name="controlConversation"> The conversation helper for the control level, test coordination conversation. </param>
        /// <param name="controlConnection">   The connection that the coordination messages are sent over. </param>
        public InteropTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> availableClients,
                                    ConversationFactory controlConversation, Connection controlConnection)
        {
            super(suite, availableClients, controlConversation, controlConnection);
        }

        /// <summary>
        /// Broadcasts a test invitation and accetps enlisting from participating clients. The wrapped test case is
        /// then repeated for every combination of test clients (provided the wrapped test case extends
        /// <see cref="FrameworkBaseCase"/>.
        ///
        /// <p/>Any JMSExceptions during the invite/enlist conversation will be allowed to fall through as runtime exceptions,
        /// resulting in the non-completion of the test run.
        /// </summary>
        /// <remarks> Better error recovery for failure of the invite/enlist conversation could be added.</remarks>
        /// <param name="testResult"> The the results object to monitor the test results with. </param>
        public void run(TestResult testResult)
        {
            log.debug("public void run(TestResult testResult): called");

            Collection<Test> tests = testSuite.getAllUnderlyingTests();

            for (Test test : getAllUnderlyingTests())
            {
                FrameworkBaseCase coordTest = (FrameworkBaseCase) test;

                // Broadcast the invitation to find out what clients are available to test.
                Set<TestClientDetails> enlists = signupClients(coordTest);

                // Compare the list of willing clients to the list of all available.
                Set<TestClientDetails> optOuts = new HashSet<TestClientDetails>(allClients);
                optOuts.removeAll(enlists);

                // Output test failures for clients that will not particpate in the test.
                Set<List<TestClientDetails>> failPairs = allPairs(optOuts, allClients);

                for (List<TestClientDetails> failPair : failPairs)
                {
                    // Create a distributed test circuit factory for the test.
                    CircuitFactory circuitFactory = getTestSequencer();

                    // Create an automatic failure test for the opted out test pair.
                    FrameworkBaseCase failTest = new OptOutTestCase("testOptOut");
                    circuitFactory.setSender(failPair.get(0));
                    circuitFactory.setReceiver(failPair.get(1));
                    failTest.setCircuitFactory(circuitFactory);

                    failTest.run(testResult);
                }

                // Loop over all combinations of clients, willing to run the test.
                Set<List<TestClientDetails>> enlistedPairs = allPairs(enlists, enlists);

                for (List<TestClientDetails> enlistedPair : enlistedPairs)
                {
                    // Create a distributed test circuit factory for the test.
                    CircuitFactory circuitFactory = getTestSequencer();

                    // Set the sending and receiving client details on the test circuitFactory.
                    circuitFactory.setSender(enlistedPair.get(0));
                    circuitFactory.setReceiver(enlistedPair.get(1));

                    // Pass down the connection to hold the coordination conversation over.
                    circuitFactory.setConversationFactory(conversationFactory);

                    // Execute the test case.
                    coordTest.setCircuitFactory(circuitFactory);
                    coordTest.run(testResult);
                }
            }
        }

        /// <summary>
        /// Should provide the distributed test sequencer to pass to <see cref="Apache.Qpid.Integration.Tests.framework.FrameworkBaseCase"/>
        /// tests.
        /// </summary>
        /// <return> A distributed test sequencer. </return>
        public CircuitFactory getTestSequencer()
        {
            return new InteropCircuitFactory();
        }

        /// <summary>
        /// Produces all pairs of combinations of elements from two sets. The ordering of the elements in the pair is
        /// important, that is the pair <l, r> is distinct from <r, l>; both pairs are generated. For any element, i, in
        /// both the left and right sets, the reflexive pair <i, i> is not generated.
        /// </summary>
        /// <param name="left">  The left set. </param>
        /// <param name="right"> The right set. </param>
        /// @param <E>   The type of the content of the pairs.
        /// </summary>
        /// <return> All pairs formed from the permutations of all elements of the left and right sets. </return>
        private <E> Set<List<E>> allPairs(Set<E> left, Set<E> right)
        {
            log.debug("private <E> Set<List<E>> allPairs(Set<E> left = " + left + ", Set<E> right = " + right + "): called");

            Set<List<E>> results = new HashSet<List<E>>();

            // Form all pairs from left to right.
            // Form all pairs from right to left.
            for (E le : left)
            {
                for (E re : right)
                {
                    if (!le.equals(re))
                    {
                        results.add(new Pair<E>(le, re));
                        results.add(new Pair<E>(re, le));
                    }
                }
            }

            log.debug("results = " + results);

            return results;
        }

        /// <summary> A simple implementation of a pair, using a list. </summary>
        private class Pair<T> extends ArrayList<T>
        {
            /// <summary>
            /// Creates a new pair of elements.
            /// </summary>
            /// <param name="first">  The first element. </param>
            /// <param name="second"> The second element. </param>
            public Pair(T first, T second)
            {
                super();
                super.add(first);
                super.add(second);
            }
        }
    }
}
/*
 *
 * 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.
 *
 */
using Apache.Qpid.Integration.Tests.framework.sequencers.CircuitFactory;
using Apache.Qpid.Integration.Tests.framework.FrameworkBaseCase;

namespace Apache.Qpid.Integration.Tests.framework.distributedtesting
{
    /// <summary>
    /// An OptOutTestCase is a test case that automatically fails. It is used when a list of test clients has been generated
    /// from a compulsory invite, but only some of those clients have responded to a specific test case invite. The clients
    /// that did not respond, may automatically be given a fail for some tests.
    ///
    /// <p><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Fail the test with a suitable reason.
    /// </table>
    /// </summary>
    public class OptOutTestCase extends FrameworkBaseCase
    {
        /// <summary>
        /// Creates a new coordinating test case with the specified name.
        /// </summary>
        /// <param name="name"> The test case name. </param>
        public OptOutTestCase(string name)
        {
            super(name);
        }

        /// <summary> Generates an appropriate test failure assertion. </summary>
        public void testOptOut()
        {
            CircuitFactory circuitFactory = getCircuitFactory();

            fail("One of " + circuitFactory.getSender() + " and " + getCircuitFactory().getReceivers()
                 + " opted out of the test.");
        }

        /// <summary>
        /// Should provide a translation from the junit method name of a test to its test case name as defined in the
        /// interop testing specification. For example the method "testP2P" might map onto the interop test case name
        /// "TC2_BasicP2P".
        /// </summary>
        /// <param name="methodName"> The name of the JUnit test method. </param>
        /// <return> The name of the corresponding interop test case. </return>
        public string getTestCaseNameForTestMethod(string methodName)
        {
            return "OptOutTest";
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;
using org.apache.log4j.NDC;

using Apache.Qpid.Integration.Tests.framework.MessagingTestConfigProperties;
using Apache.Qpid.Integration.Tests.framework.TestUtils;
using Apache.Qpid.Integration.Tests.framework.clocksynch.ClockSynchThread;
using Apache.Qpid.Integration.Tests.framework.clocksynch.UDPClockSynchronizer;
using org.apache.qpid.util.ReflectionUtils;
using org.apache.qpid.util.ReflectionUtilsException;

using uk.co.thebadgerset.junit.extensions.SleepThrottle;
using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
using uk.co.thebadgerset.junit.extensions.util.TestContextProperties;

using javax.jms.*;

using java.util.*;

namespace Apache.Qpid.Integration.Tests.framework.distributedtesting
{
    /// <summary>
    /// Implements a test client as described in the interop testing spec
    /// (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification). A test client is an agent that
    /// reacts to control message sequences send by the test <see cref="Coordinator"/>.
    ///
    /// <p/><table><caption>Messages Handled by TestClient</caption>
    /// <tr><th> Message               <th> Action
    /// <tr><td> Invite(compulsory)    <td> Reply with Enlist.
    /// <tr><td> Invite(test case)     <td> Reply with Enlist if test case available.
    /// <tr><td> AssignRole(test case) <td> Reply with Accept Role if matches an enlisted test. Keep test parameters.
    /// <tr><td> Start                 <td> Send test messages defined by test parameters. Send report on messages sent.
    /// <tr><td> Status Request        <td> Send report on messages received.
    /// <tr><td> Terminate             <td> Terminate the test client.
    /// <tr><td> ClockSynch            <td> Synch clock against the supplied UDP address.
    /// </table>
    ///
    /// <p><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Handle all incoming control messages. <td> <see cref="TestClientControlledTest"/>
    /// <tr><td> Configure and look up test cases by name. <td> <see cref="TestClientControlledTest"/>
    /// </table>
    /// </summary>
    public class TestClient : MessageListener
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(TestClient));

        /// <summary> Used for reporting to the console. </summary>
        private static ILog console = LogManager.GetLogger("CONSOLE");

        /// <summary> Holds the default identifying name of the test client. </summary>
        public static final string CLIENT_NAME = "java";

        /// <summary> Holds the URL of the broker to run the tests on. </summary>
        public static string brokerUrl;

        /// <summary> Holds the virtual host to run the tests on. If <tt>null</tt>, then the default virtual host is used. </summary>
        public static string virtualHost;

        /// <summary>
        /// Holds the test context properties that provides the default test parameters, plus command line overrides.
        /// This is initialized with the default test parameters, to which command line overrides may be applied.
        /// </summary>
        public static ParsedProperties testContextProperties =
            TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);

        /// <summary> Holds all the test cases loaded from the classpath. </summary>
        Map<String, TestClientControlledTest> testCases = new HashMap<String, TestClientControlledTest>();

        /// <summary> Holds the test case currently being run by this client. </summary>
        protected TestClientControlledTest currentTestCase;

        /// <summary> Holds the connection to the broker that the test is being coordinated on. </summary>
        protected Connection connection;

        /// <summary> Holds the message producer to hold the test coordination over. </summary>
        protected MessageProducer producer;

        /// <summary> Holds the JMS controlSession for the test coordination. </summary>
        protected Session session;

        /// <summary> Holds the name of this client, with a default value. </summary>
        protected string clientName = CLIENT_NAME;

        /// <summary> This flag indicates that the test client should attempt to join the currently running test case on start up. </summary>
        protected bool join;

        /// <summary> Holds the clock synchronizer for the test node. </summary>
        ClockSynchThread clockSynchThread;

        /// <summary>
        /// Creates a new interop test client, listenting to the specified broker and virtual host, with the specified client
        /// identifying name.
        /// </summary>
        /// <param name="pBrokerUrl">   The url of the broker to connect to. </param>
        /// <param name="pVirtualHost"> The virtual host to conect to. </param>
        /// <param name="clientName">  The client name to use. </param>
        /// <param name="join">        Flag to indicate that this client should attempt to join running tests. </param>
        public TestClient(string pBrokerUrl, string pVirtualHost, string clientName, bool join)
        {
            log.debug("public TestClient(string pBrokerUrl = " + pBrokerUrl + ", string pVirtualHost = " + pVirtualHost
                      + ", string clientName = " + clientName + ", bool join = " + join + "): called");

            // Retain the connection parameters.
            brokerUrl = pBrokerUrl;
            virtualHost = pVirtualHost;
            this.clientName = clientName;
            this.join = join;
        }

        /// <summary>
        /// The entry point for the interop test coordinator. This client accepts the following command line arguments:
        ///
        /// <p/><table>
        /// <tr><td> -b         <td> The broker URL.       <td> Optional.
        /// <tr><td> -h         <td> The virtual host.     <td> Optional.
        /// <tr><td> -n         <td> The test client name. <td> Optional.
        /// <tr><td> name=value <td> Trailing argument define name/value pairs. Added to system properties. <td> Optional.
        /// </table>
        /// </summary>
        /// <param name="args"> The command line arguments. </param>
        public static void main(String[] args)
        {
            log.debug("public static void main(String[] args = " + Arrays.ToString(args) + "): called");
            console.info("Qpid Distributed Test Client.");

            // Override the default broker url to be localhost:5672.
            testContextProperties.setProperty(MessagingTestConfigProperties.BROKER_PROPNAME, "tcp://localhost:5672");

            // Use the command line parser to evaluate the command line with standard handling behaviour (print errors
            // and usage then exist if there are errors).
            // Any options and trailing name=value pairs are also injected into the test context properties object,
            // to override any defaults that may have been set up.
            ParsedProperties options =
                new ParsedProperties(uk.co.thebadgerset.junit.extensions.util.CommandLineParser.processCommandLine(args,
                                                                                                                   new uk.co.thebadgerset.junit.extensions.util.CommandLineParser(
                                                                                                                                                                                  new String[][]
                                                                                                                                                                                  {
                                                                                                                                                                                      { "b", "The broker URL.", "broker", "false" },
                                                                                                                                                                                      { "h", "The virtual host to use.", "virtual host", "false" },
                                                                                                                                                                                      { "o", "The name of the directory to output test timings to.", "dir", "false" },
                                                                                                                                                                                      { "n", "The name of the test client.", "name", "false" },
                                                                                                                                                                                      { "j", "Join this test client to running test.", "false" }
                                                                                                                                                                                  }), testContextProperties));

            // Extract the command line options.
            string brokerUrl = options.getProperty("b");
            string virtualHost = options.getProperty("h");
            string clientName = options.getProperty("n");
            clientName = (clientName == null) ? CLIENT_NAME : clientName;
            bool join = options.getPropertyAsBoolean("j");

            // To distinguish logging output set up an NDC on the client name.
            NDC.push(clientName);

            // Create a test client and start it running.
            TestClient client = new TestClient(brokerUrl, virtualHost, clientName, join);

            // Use a class path scanner to find all the interop test case implementations.
            // Hard code the test classes till the classpath scanner is fixed.
            Collection<Class<? extends TestClientControlledTest>> testCaseClasses =
                new ArrayList<Class<? extends TestClientControlledTest>>();
            // ClasspathScanner.getMatches(TestClientControlledTest.class, "^TestCase.*", true);
            testCaseClasses.addAll(loadTestCases("org.apache.qpid.interop.clienttestcases.TestCase1DummyRun",
                                                 "org.apache.qpid.interop.clienttestcases.TestCase2BasicP2P",
                                                 "org.apache.qpid.interop.clienttestcases.TestCase3BasicPubSub",
                                                 "org.apache.qpid.interop.clienttestcases.TestCase4P2PMessageSize",
                                                 "org.apache.qpid.interop.clienttestcases.TestCase5PubSubMessageSize",
                                                 "Apache.Qpid.Integration.Tests.framework.distributedcircuit.TestClientCircuitEnd"));

            try
            {
                client.start(testCaseClasses);
            }
            catch (Exception e)
            {
                log.error("The test client was unable to start.", e);
                console.info(e.getMessage());
                System.exit(1);
            }
        }

        /// <summary>
        /// Parses a list of class names, and loads them if they are available on the class path.
        /// </summary>
        /// <param name="classNames"> The names of the classes to load. </param>
        ///
        /// <return> A list of the loaded test case classes. </return>
        public static IList<Class<? extends TestClientControlledTest>> loadTestCases(String... classNames)
        {
            IList<Class<? extends TestClientControlledTest>> testCases =
                new LinkedList<Class<? extends TestClientControlledTest>>();

            for (string className : classNames)
            {
                try
                {
                    Class<?> cls = ReflectionUtils.forName(className);
                    testCases.add((Class<? extends TestClientControlledTest>) cls);
                }
                catch (ReflectionUtilsException e)
                {
                    // Ignore, class could not be found, so test not available.
                    console.warn("Requested class " + className + " cannot be found, ignoring it.");
                }
                catch (ClassCastException e)
                {
                    // Ignore, class was not of correct type to be a test case.
                    console.warn("Requested class " + className + " is not an instance of TestClientControlledTest.");
                }
            }

            return testCases;
        }

        /// <summary>
        /// Starts the interop test client running. This causes it to start listening for incoming test invites.
        /// </summary>
        /// <param name="testCaseClasses"> The classes of the available test cases. The test case names from these are used to </param>
        ///                        matchin incoming test invites against.
        ///
        /// <exception cref="JMSException"> Any underlying JMSExceptions are allowed to fall through. </exception>
        protected void start(Collection<Class<? extends TestClientControlledTest>> testCaseClasses) throws JMSException
        {
            log.debug("protected void start(Collection<Class<? extends TestClientControlledTest>> testCaseClasses = "
                      + testCaseClasses + "): called");

            // Create all the test case implementations and index them by the test names.
            for (Class<? extends TestClientControlledTest> nextClass : testCaseClasses)
            {
                try
                {
                    TestClientControlledTest testCase = nextClass.newInstance();
                    testCases.put(testCase.getName(), testCase);
                }
                catch (InstantiationException e)
                {
                    log.warn("Could not instantiate test case class: " + nextClass.getName(), e);
                    // Ignored.
                }
                catch (IllegalAccessException e)
                {
                    log.warn("Could not instantiate test case class due to illegal access: " + nextClass.getName(), e);
                    // Ignored.
                }
            }

            // Open a connection to communicate with the coordinator on.
            connection = TestUtils.createConnection(testContextProperties);
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

            // Set this up to listen for control messages.
            Topic privateControlTopic = session.createTopic("iop.control." + clientName);
            MessageConsumer consumer = session.createConsumer(privateControlTopic);
            consumer.setMessageListener(this);

            Topic controlTopic = session.createTopic("iop.control");
            MessageConsumer consumer2 = session.createConsumer(controlTopic);
            consumer2.setMessageListener(this);

            // Create a producer to send replies with.
            producer = session.createProducer(null);

            // If the join flag was set, then broadcast a join message to notify the coordinator that a new test client
            // is available to join the current test case, if it supports it. This message may be ignored, or it may result
            // in this test client receiving a test invite.
            if (join)
            {
                Message joinMessage = session.createMessage();

                joinMessage.setStringProperty("CONTROL_TYPE", "JOIN");
                joinMessage.setStringProperty("CLIENT_NAME", clientName);
                joinMessage.setStringProperty("CLIENT_PRIVATE_CONTROL_KEY", "iop.control." + clientName);
                producer.send(controlTopic, joinMessage);
            }

            // Start listening for incoming control messages.
            connection.start();
        }

        /// <summary>
        /// Handles all incoming control messages.
        /// </summary>
        /// <param name="message"> The incoming message. </param>
        public void onMessage(Message message)
        {
            NDC.push(clientName);
            log.debug("public void onMessage(Message message = " + message + "): called");

            try
            {
                string controlType = message.getStringProperty("CONTROL_TYPE");
                string testName = message.getStringProperty("TEST_NAME");

                log.debug("Received control of type '" + controlType + "' for the test '" + testName + "'");

                // Check if the message is a test invite.
                if ("INVITE".equals(controlType))
                {
                    // Flag used to indicate that an enlist should be sent. Only enlist to compulsory invites or invites
                    // for which test cases exist.
                    bool enlist = false;

                    if (testName != null)
                    {
                        log.debug("Got an invite to test: " + testName);

                        // Check if the requested test case is available.
                        TestClientControlledTest testCase = testCases.get(testName);

                        if (testCase != null)
                        {
                            log.debug("Found implementing class for test '" + testName + "', enlisting for it.");

                            // Check if the test case will accept the invitation.
                            enlist = testCase.acceptInvite(message);

                            log.debug("The test case "
                                      + (enlist ? " accepted the invite, enlisting for it."
                                         : " did not accept the invite, not enlisting."));

                            // Make the requested test case the current test case.
                            currentTestCase = testCase;
                        }
                        else
                        {
                            log.debug("Received an invite to the test '" + testName + "' but this test is not known.");
                        }
                    }
                    else
                    {
                        log.debug("Got a compulsory invite, enlisting for it.");

                        enlist = true;
                    }

                    if (enlist)
                    {
                        // Reply with the client name in an Enlist message.
                        Message enlistMessage = session.createMessage();
                        enlistMessage.setStringProperty("CONTROL_TYPE", "ENLIST");
                        enlistMessage.setStringProperty("CLIENT_NAME", clientName);
                        enlistMessage.setStringProperty("CLIENT_PRIVATE_CONTROL_KEY", "iop.control." + clientName);
                        enlistMessage.setJMSCorrelationID(message.getJMSCorrelationID());

                        log.debug("Sending enlist message '" + enlistMessage + "' to " + message.getJMSReplyTo());

                        producer.send(message.getJMSReplyTo(), enlistMessage);
                    }
                    else
                    {
                        // Reply with the client name in an Decline message.
                        Message enlistMessage = session.createMessage();
                        enlistMessage.setStringProperty("CONTROL_TYPE", "DECLINE");
                        enlistMessage.setStringProperty("CLIENT_NAME", clientName);
                        enlistMessage.setStringProperty("CLIENT_PRIVATE_CONTROL_KEY", "iop.control." + clientName);
                        enlistMessage.setJMSCorrelationID(message.getJMSCorrelationID());

                        log.debug("Sending decline message '" + enlistMessage + "' to " + message.getJMSReplyTo());

                        producer.send(message.getJMSReplyTo(), enlistMessage);
                    }
                }
                else if ("ASSIGN_ROLE".equals(controlType))
                {
                    // Assign the role to the current test case.
                    string roleName = message.getStringProperty("ROLE");

                    log.debug("Got a role assignment to role: " + roleName);

                    TestClientControlledTest.Roles role = Enum.valueOf(TestClientControlledTest.Roles.class, roleName);

                    currentTestCase.assignRole(role, message);

                    // Reply by accepting the role in an Accept Role message.
                    Message acceptRoleMessage = session.createMessage();
                    acceptRoleMessage.setStringProperty("CLIENT_NAME", clientName);
                    acceptRoleMessage.setStringProperty("CONTROL_TYPE", "ACCEPT_ROLE");
                    acceptRoleMessage.setJMSCorrelationID(message.getJMSCorrelationID());

                    log.debug("Sending accept role message '" + acceptRoleMessage + "' to " + message.getJMSReplyTo());

                    producer.send(message.getJMSReplyTo(), acceptRoleMessage);
                }
                else if ("START".equals(controlType) || "STATUS_REQUEST".equals(controlType))
                {
                    if ("START".equals(controlType))
                    {
                        log.debug("Got a start notification.");

                        // Extract the number of test messages to send from the start notification.
                        int numMessages;

                        try
                        {
                            numMessages = message.getIntProperty("MESSAGE_COUNT");
                        }
                        catch (NumberFormatException e)
                        {
                            // If the number of messages is not specified, use the default of one.
                            numMessages = 1;
                        }

                        // Start the current test case.
                        currentTestCase.start(numMessages);
                    }
                    else
                    {
                        log.debug("Got a status request.");
                    }

                    // Generate the report from the test case and reply with it as a Report message.
                    Message reportMessage = currentTestCase.getReport(session);
                    reportMessage.setStringProperty("CLIENT_NAME", clientName);
                    reportMessage.setStringProperty("CONTROL_TYPE", "REPORT");
                    reportMessage.setJMSCorrelationID(message.getJMSCorrelationID());

                    log.debug("Sending report message '" + reportMessage + "' to " + message.getJMSReplyTo());

                    producer.send(message.getJMSReplyTo(), reportMessage);
                }
                else if ("TERMINATE".equals(controlType))
                {
                    console.info("Received termination instruction from coordinator.");

                    // Is a cleaner shutdown needed?
                    connection.close();
                    System.exit(0);
                }
                else if ("CLOCK_SYNCH".equals(controlType))
                {
                    log.debug("Received clock synch command.");
                    string address = message.getStringProperty("ADDRESS");

                    log.debug("address = " + address);

                    // Re-create (if necessary) and start the clock synch thread to synch the clock every ten seconds.
                    if (clockSynchThread != null)
                    {
                        clockSynchThread.terminate();
                    }

                    SleepThrottle throttle = new SleepThrottle();
                    throttle.setRate(0.1f);

                    clockSynchThread = new ClockSynchThread(new UDPClockSynchronizer(address), throttle);
                    clockSynchThread.start();
                }
                else
                {
                    // Log a warning about this but otherwise ignore it.
                    log.warn("Got an unknown control message, controlType = " + controlType + ", message = " + message);
                }
            }
            catch (JMSException e)
            {
                // Log a warning about this, but otherwise ignore it.
                log.warn("Got JMSException whilst handling message: " + message, e);
            }
            // Log any runtimes that fall through this message handler. These are fatal errors for the test client.
            catch (RuntimeException e)
            {
                log.error("The test client message handler got an unhandled exception: ", e);
                console.info("The message handler got an unhandled exception, terminating the test client.");
                System.exit(1);
            }
            finally
            {
                NDC.pop();
            }
        }
    }
}
/*
 *
 * 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.
 *
 */
using javax.jms.JMSException;
using javax.jms.Message;
using javax.jms.MessageListener;
using javax.jms.Session;

namespace Apache.Qpid.Integration.Tests.framework.distributedtesting
{
    /// <summary>
    /// TestClientControlledTest provides an interface that classes implementing test cases to run on a <see cref="TestClient"/>
    /// node can use. Implementations must be Java beans, that is, to provide a default constructor and to implement the
    /// <see cref="#getName"/> method.
    ///
    /// <p/>The methods specified in this interface are called when the <see cref="TestClient"/> receives control instructions to
    /// apply to the test. There are control instructions to present the test case with the test invite, so that it may
    /// choose whether or not to participate in the test, assign the test to play the sender or receiver role, start the
    /// test and obtain the test status report.
    ///
    /// <p><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Supply the name of the test case that this implements.
    /// <tr><td> Accept/Reject invites based on test parameters.
    /// <tr><td> Adapt to assigned roles.
    /// <tr><td> Perform test case actions.
    /// <tr><td> Generate test reports.
    /// </table>
    /// </summary>
    public interface TestClientControlledTest
    {
        /// <summary> Defines the possible test case roles that an interop test case can take on. </summary>
        public enum Roles
        {
            /// <summary> Specifies the sender role. </summary>
            SENDER,

            /// <summary> Specifies the receivers role. </summary>
            RECEIVER
        }

        /// <summary>
        /// Should provide the name of the test case that this class implements. The exact names are defined in the
        /// interop testing spec.
        /// </summary>
        /// <return> The name of the test case that this implements. </return>
        public string getName();

        /// <summary>
        /// Determines whether the test invite that matched this test case is acceptable.
        /// </summary>
        /// <param name="inviteMessage"> The invitation to accept or reject. </param>
        ///
        /// <return> <tt>true</tt> to accept the invitation, <tt>false</tt> to reject it. </return>
        ///
        /// <exception cref="JMSException"> Any JMSException resulting from reading the message are allowed to fall through. </exception>
        public bool acceptInvite(Message inviteMessage) throws JMSException;

        /// <summary>
        /// Assigns the role to be played by this test case. The test parameters are fully specified in the
        /// assignment message. When this method return the test case will be ready to execute.
        /// </summary>
        /// <param name="role">              The role to be played; sender or receivers. </param>
        /// <param name="assignRoleMessage"> The role assingment message, contains the full test parameters. </param>
        ///
        /// <exception cref="JMSException"> Any JMSException resulting from reading the message are allowed to fall through. </exception>
        public void assignRole(Roles role, Message assignRoleMessage) throws JMSException;

        /// <summary>
        /// Performs the test case actions. Returning from here, indicates that the sending role has completed its test.
        /// </summary>
        /// <param name="numMessages"> The number of test messages to send. </param>
        ///
        /// <exception cref="JMSException"> Any JMSException resulting from reading the message are allowed to fall through. </exception>
        public void start(int numMessages) throws JMSException;

        /// <summary>
        /// Gets a report on the actions performed by the test case in its assigned role.
        /// </summary>
        /// <param name="session"> The controlSession to create the report message in. </param>
        ///
        /// <return> The report message. </return>
        ///
        /// <exception cref="JMSException"> Any JMSExceptions resulting from creating the report are allowed to fall through. </exception>
        public Message getReport(Session session) throws JMSException;
    }
}
/*
 *
 * 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.
 *
 */
using javax.jms.JMSException;
using javax.jms.Message;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// A DropIn test is a test case that can accept late joining test clients into a running test. This can be usefull,
    /// for interactive experimentation.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Accept late joining test clients.
    /// </table>
    /// </summary>
    public interface DropInTest
    {
        /// <summary>
        /// Should accept a late joining client into a running test case. The client will be enlisted with a control message
        /// with the 'CONTROL_TYPE' field set to the value 'LATEJOIN'. It should also provide values for the fields:
        ///
        /// <p/><table>
        /// <tr><td> CLIENT_NAME <td> A unique name for the new client.
        /// <tr><td> CLIENT_PRIVATE_CONTROL_KEY <td> The key for the route on which the client receives its control messages.
        /// </table>
        /// </summary>
        /// <param name="message"> The late joiners join message. </param>
        ///
        /// <exception cref="JMSException"> Any JMS Exception are allowed to fall through, indicating that the join failed. </exception>
        public void lateJoin(Message message) throws JMSException;
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using javax.jms.ExceptionListener;
using javax.jms.JMSException;

using java.io.PrintWriter;
using java.io.StringWriter;
using java.util.ArrayList;
using System.Collections.Generic.IList;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// An exception monitor, listens for JMS exception on a connection or consumer. It record all exceptions that it receives
    /// and provides methods to test the number and type of exceptions received.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Record all exceptions received.
    /// </table>
    /// </summary>
    public class ExceptionMonitor : ExceptionListener
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(ExceptionMonitor));

        /// <summary> Holds the received exceptions. </summary>
        IList<Exception> exceptions = new ArrayList<Exception>();

        /// <summary>
        /// Receives incoming exceptions.
        /// </summary>
        /// <param name="e"> The exception to record. </param>
        public synchronized void onException(JMSException e)
        {
            log.debug("public void onException(JMSException e): called", e);

            exceptions.add(e);
        }

        /// <summary>
        /// Checks that no exceptions have been received.
        /// </summary>
        /// <return> <tt>true</tt> if no exceptions have been received, <tt>false</tt> otherwise. </return>
        public synchronized bool assertNoExceptions()
        {
            return exceptions.isEmpty();
        }

        /// <summary>
        /// Checks that exactly one exception has been received.
        /// </summary>
        /// <return> <tt>true</tt> if exactly one exception been received, <tt>false</tt> otherwise. </return>
        public synchronized bool assertOneJMSException()
        {
            return exceptions.size() == 1;
        }

        /// <summary>
        /// Checks that exactly one exception, with a linked cause of the specified type, has been received.
        /// </summary>
        /// <param name="aClass"> The type of the linked cause. </param>
        ///
        /// <return> <tt>true</tt> if exactly one exception, with a linked cause of the specified type, been received, </return>
        ///         <tt>false</tt> otherwise.
        public synchronized bool assertOneJMSExceptionWithLinkedCause(Class aClass)
        {
            if (exceptions.size() == 1)
            {
                Exception e = exceptions.get(0);

                if (e instanceof JMSException)
                {
                    JMSException jmse = (JMSException) e;

                    Exception linkedCause = jmse.getLinkedException();

                    if ((linkedCause != null) && aClass.isInstance(linkedCause))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Checks that at least one exception of the the specified type, has been received.
        /// </summary>
        /// <param name="exceptionClass"> The type of the exception. </param>
        ///
        /// <return> <tt>true</tt> if at least one exception of the specified type has been received, <tt>false</tt> otherwise. </return>
        public synchronized bool assertExceptionOfType(Class exceptionClass)
        {
            // Start by assuming that the exception has no been received.
            bool passed = false;

            // Scan all the exceptions for a match.
            for (Exception e : exceptions)
            {
                if (exceptionClass.isInstance(e))
                {
                    passed = true;

                    break;
                }
            }

            return passed;
        }

        /// <summary>
        /// Reports the number of exceptions held by this monitor.
        /// </summary>
        /// <return> The number of exceptions held by this monitor. </return>
        public synchronized int size()
        {
            return exceptions.size();
        }

        /// <summary>
        /// Clears the record of received exceptions.
        /// </summary>
        public synchronized void reset()
        {
            exceptions = new ArrayList<Exception>();
        }

        /// <summary>
        /// Provides a dump of the stack traces of all exceptions that this exception monitor was notified of. Mainly
        /// use for debugging/test failure reporting purposes.
        /// </summary>
        /// <return> A string containing a dump of the stack traces of all exceptions. </return>
        public synchronized string ToString()
        {
            string result = "ExceptionMonitor: holds " + exceptions.size() + " exceptions.\n\n";

            for (Exception ex : exceptions)
            {
                result += getStackTrace(ex) + "\n";
            }

            return result;
        }

        /// <summary>
        /// Prints an exception stack trace into a string.
        /// </summary>
        /// <param name="t"> The throwable to get the stack trace from. </param>
        ///
        /// <return> A string containing the throwables stack trace. </return>
        public static string getStackTrace(Throwable t)
        {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw, true);
            t.printStackTrace(pw);
            pw.flush();
            sw.flush();

            return sw.ToString();
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;
using org.apache.log4j.NDC;

using Apache.Qpid.Integration.Tests.framework.BrokerLifecycleAware;
using Apache.Qpid.Integration.Tests.framework.sequencers.CircuitFactory;

using uk.co.thebadgerset.junit.extensions.AsymptoticTestCase;
using uk.co.thebadgerset.junit.extensions.SetupTaskAware;
using uk.co.thebadgerset.junit.extensions.SetupTaskHandler;
using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
using uk.co.thebadgerset.junit.extensions.util.TestContextProperties;

using java.util.ArrayList;
using System.Collections.Generic.IList;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// FrameworkBaseCase provides a starting point for writing test cases against the test framework. Its main purpose is
    /// to provide some convenience methods for testing.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Create and clean up in-vm brokers on every test case.
    /// <tr><td> Produce lists of assertions from assertion creation calls.
    /// <tr><td> Produce JUnit failures from assertion failures.
    /// <tr><td> Convert failed assertions to error messages.
    /// </table>
    /// </summary>
    public class FrameworkBaseCase extends AsymptoticTestCase : FrameworkTestContext, SetupTaskAware,
        BrokerLifecycleAware
    {
        /// <summary> Used for debugging purposes. </summary>
        private static ILog log = LogManager.GetLogger(typeof(FrameworkBaseCase));

        /// <summary> Holds the test sequencer to create and run test circuits with. </summary>
        protected CircuitFactory circuitFactory = new LocalCircuitFactory();

        /// <summary> Used to read the tests configurable properties through. </summary>
        protected ParsedProperties testProps;

        /// <summary> A default setup task processor to delegate setup tasks to. </summary>
        protected SetupTaskHandler taskHandler = new SetupTaskHandler();

        /// <summary> Flag used to track whether the test is in-vm or not. </summary>
        protected bool isUsingInVM;

        /// <summary> Holds the failure mechanism. </summary>
        protected CauseFailure failureMechanism = new CauseFailureUserPrompt();

        /// <summary>
        /// Creates a new test case with the specified name.
        /// </summary>
        /// <param name="name"> The test case name. </param>
        public FrameworkBaseCase(string name)
        {
            super(name);
        }

        /// <summary>
        /// Returns the test case sequencer that provides test circuit, and test sequence implementations. The sequencer
        /// that this base case returns by default is suitable for running a test circuit with both circuit ends colocated
        /// on the same JVM.
        /// </summary>
        /// <return> The test case sequencer. </return>
        protected CircuitFactory getCircuitFactory()
        {
            return circuitFactory;
        }

        /// <summary>
        /// Overrides the default test circuit factory. Test decorators can use this to supply distributed test sequencers or
        /// other test circuit factory specializations.
        /// </summary>
        /// <param name="circuitFactory"> The new test circuit factory. </param>
        public void setCircuitFactory(CircuitFactory circuitFactory)
        {
            this.circuitFactory = circuitFactory;
        }

        /// <summary>
        /// Reports the current test case name.
        /// </summary>
        /// <return> The current test case name. </return>
        public TestCaseVector getTestCaseVector()
        {
            return new TestCaseVector(this.getName(), 0);
        }

        /// <summary>
        /// Reports the current test case parameters.
        /// </summary>
        /// <return> The current test case parameters. </return>
        public MessagingTestConfigProperties getTestParameters()
        {
            return new MessagingTestConfigProperties(testProps);
        }

        /// <summary>
        /// Creates a list of assertions.
        /// </summary>
        /// <param name="asserts"> The assertions to compile in a list. </param>
        ///
        /// <return> A list of assertions. </return>
        protected IList<Assertion> assertionList(Assertion... asserts)
        {
            IList<Assertion> result = new ArrayList<Assertion>();

            for (Assertion assertion : asserts)
            {
                result.add(assertion);
            }

            return result;
        }

        /// <summary>
        /// Generates a JUnit assertion exception (failure) if any assertions are passed into this method, also concatenating
        /// all of the error messages in the assertions together to form an error message to diagnose the test failure with.
        /// </summary>
        /// <param name="asserts"> The list of failed assertions. </param>
        protected static void assertNoFailures(List<Assertion> asserts)
        {
            log.debug("protected void assertNoFailures(List<Assertion> asserts = " + asserts + "): called");

            // Check if there are no assertion failures, and return without doing anything if so.
            if ((asserts == null) || asserts.isEmpty())
            {
                return;
            }

            // Compile all of the assertion failure messages together.
            string errorMessage = assertionsToString(asserts);

            // Fail with the error message from all of the assertions.
            fail(errorMessage);
        }

        /// <summary>
        /// Converts a list of failed assertions into an error message.
        /// </summary>
        /// <param name="asserts"> The failed assertions. </param>
        ///
        /// <return> The error message. </return>
        protected static string assertionsToString(List<Assertion> asserts)
        {
            string errorMessage = "";

            for (Assertion assertion : asserts)
            {
                errorMessage += assertion.ToString() + "\n";
            }

            return errorMessage;
        }

        /// <summary>
        /// Ensures that the in-vm broker is created and initialized.
        /// </summary>
        ///
        /// <exception cref="Exception"> Any exceptions allowed to fall through and fail the test. </exception>
        protected void setUp() throws Exception
        {
            NDC.push(getName());

            testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);

            // Process all optional setup tasks. This may include in-vm broker creation, if a decorator has added it.
            taskHandler.runSetupTasks();
        }

        /// <summary> Ensures that the in-vm broker is cleaned up after each test run. </summary>
        protected void tearDown()
        {
            NDC.pop();

            // Process all optional tear down tasks. This may include in-vm broker clean up, if a decorator has added it.
            taskHandler.runTearDownTasks();
        }

        /// <summary>
        /// Adds the specified task to the tests setup.
        /// </summary>
        /// <param name="task"> The task to add to the tests setup. </param>
        public void chainSetupTask(Runnable task)
        {
            taskHandler.chainSetupTask(task);
        }

        /// <summary>
        /// Adds the specified task to the tests tear down.
        /// </summary>
        /// <param name="task"> The task to add to the tests tear down. </param>
        public void chainTearDownTask(Runnable task)
        {
            taskHandler.chainTearDownTask(task);
        }

        /// <summary>
        /// Should provide a translation from the junit method name of a test to its test case name as known to the test
        /// clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test
        /// case name to place into the test invite. For example the method "testP2P" might map onto the interop test case
        /// name "TC2_BasicP2P".
        /// </summary>
        /// <param name="methodName"> The name of the JUnit test method. </param>
        ///
        /// <return> The name of the corresponding interop test case. </return>
        public string getTestCaseNameForTestMethod(string methodName)
        {
            return methodName;
        }

        public void setInVmBrokers()
        {
            isUsingInVM = true;
        }

        /// <summary>
        /// Indicates whether or not a test case is using in-vm brokers.
        /// </summary>
        /// <return> <tt>true</tt> if the test is using in-vm brokers, <tt>false</tt> otherwise. </return>
        public bool usingInVmBroker()
        {
            return isUsingInVM;
        }

        /// <summary>
        /// Sets the currently live in-vm broker.
        /// </summary>
        /// <param name="i"> The currently live in-vm broker. </param>
        public void setLiveBroker(int i)
        { }

        /// <summary>
        /// Reports the currently live in-vm broker.
        /// </summary>
        /// <return> The currently live in-vm broker. </return>
        public int getLiveBroker()
        {
            return 0;
        }

        /// <summary>
        /// Accepts a failure mechanism.
        /// </summary>
        /// <param name="failureMechanism"> The failure mechanism. </param>
        public void setFailureMechanism(CauseFailure failureMechanism)
        {
            this.failureMechanism = failureMechanism;
        }
    }
}
/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework
{

    /// <summary>
    /// A FrameworkTestContext provides context information to test code about the current test case being run; its name, its
    /// parameters.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Provide the name of the current test case.
    /// <tr><td> Provide the test parameters.
    /// </table>
    /// </summary>
    public interface FrameworkTestContext
    {
        /// <summary>
        /// Reports the current test case name.
        /// </summary>
        /// <return> The current test case name. </return>
        TestCaseVector getTestCaseVector();

        /// <summary>
        /// Reports the current test case parameters.
        /// </summary>
        /// <return> The current test case parameters. </return>
        MessagingTestConfigProperties getTestParameters();
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using Apache.Qpid.Integration.Tests.framework.*;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.*;

using System.Collections.Generic.LinkedList;
using System.Collections.Generic.IList;

namespace Apache.Qpid.Integration.Tests.framework.localcircuit
{
    /// <summary>
    /// LocalCircuitImpl provides an implementation of the test circuit. This is a local only circuit implementation that
    /// supports a single producer/consumer on each end of the circuit, with both ends of the circuit on the same JVM.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
    ///     <td> <see cref="LocalPublisherImpl"/>, <see cref="LocalReceiverImpl"/>
    /// <tr><td> Start the circuit running.
    /// <tr><td> Close the circuit down.
    /// <tr><td> Take a reading of the circuits state.
    /// <tr><td> Apply assertions against the circuits state. <td> <see cref="Assertion"/>
    /// <tr><td> Send test messages over the circuit.
    /// <tr><td> Perform the default test procedure on the circuit.
    /// <tr><td> Provide access to connection and controlSession exception monitors. <td> <see cref="ExceptionMonitor"/>
    /// </table>
    /// </summary>
    public class LocalCircuitImpl : Circuit
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(LocalCircuitImpl));

        /// <summary> Holds the test configuration for the circuit. </summary>
        private ParsedProperties testProps;

        /// <summary> Holds the publishing end of the circuit. </summary>
        private LocalPublisherImpl publisher;

        /// <summary> Holds the receiving end of the circuit. </summary>
        private LocalReceiverImpl receiver;

        /// <summary> Holds the connection for the publishing end of the circuit. </summary>
        private Connection connection;

        /// <summary> Holds the exception listener for the connection on the publishing end of the circuit. </summary>
        private ExceptionMonitor connectionExceptionMonitor;

        /// <summary> Holds the exception listener for the controlSession on the publishing end of the circuit. </summary>
        private ExceptionMonitor exceptionMonitor;

        /// <summary>
        /// Creates a test circuit using the specified test parameters. The publisher, receivers, connection and
        /// connection monitor must already have been created, to assemble the circuit.
        /// </summary>
        /// <param name="testProps">                  The test parameters. </param>
        /// <param name="publisher">                  The test publisher. </param>
        /// <param name="receiver">                   The test receivers. </param>
        /// <param name="connection">                 The connection. </param>
        /// <param name="connectionExceptionMonitor"> The connection exception monitor. </param>
        public LocalCircuitImpl(ParsedProperties testProps, LocalPublisherImpl publisher, LocalReceiverImpl receiver,
                                Connection connection, ExceptionMonitor connectionExceptionMonitor)
        {
            this.testProps = testProps;
            this.publisher = publisher;
            this.receiver = receiver;
            this.connection = connection;
            this.connectionExceptionMonitor = connectionExceptionMonitor;
            this.exceptionMonitor = new ExceptionMonitor();

            // Set this as the parent circuit on the publisher and receivers.
            publisher.setCircuit(this);
            receiver.setCircuit(this);
        }

        /// <summary>
        /// Gets the interface on the publishing end of the circuit.
        /// </summary>
        /// <return> The publishing end of the circuit. </return>
        public Publisher getPublisher()
        {
            return publisher;
        }

        /// <summary>
        /// Gets the local publishing circuit end, for direct manipulation.
        /// </summary>
        /// <return> The local publishing circuit end. </return>
        public CircuitEnd getLocalPublisherCircuitEnd()
        {
            return publisher;
        }

        /// <summary>
        /// Gets the interface on the receiving end of the circuit.
        /// </summary>
        /// <return> The receiving end of the circuit. </return>
        public Receiver getReceiver()
        {
            return receiver;
        }

        /// <summary>
        /// Gets the local receiving circuit end, for direct manipulation.
        /// </summary>
        /// <return> The local receiving circuit end. </return>
        public CircuitEnd getLocalReceiverCircuitEnd()
        {
            return receiver;
        }

        /// <summary>
        /// Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
        /// into a report, against which assertions may be checked.
        /// </summary>
        public void check()
        { }

        /// <summary>
        /// Applied a list of assertions against the test circuit. The <see cref="#check()"/> method should be called before doing
        /// this, to ensure that the circuit has gathered its state into a report to assert against.
        /// </summary>
        /// <param name="assertions"> The list of assertions to apply. </param>
        /// <return> Any assertions that failed. </return>
        public IList<Assertion> applyAssertions(List<Assertion> assertions)
        {
            IList<Assertion> failures = new LinkedList<Assertion>();

            for (Assertion assertion : assertions)
            {
                if (!assertion.apply())
                {
                    failures.add(assertion);
                }
            }

            return failures;
        }

        /// <summary> Connects and starts the circuit. After this method is called the circuit is ready to send messages. </summary>
        public void start()
        { }

        /// <summary> Closes the circuit. All associated resources are closed. </summary>
        public void close()
        {
            try
            {
                publisher.close();
                receiver.close();
                connection.close();
            }
            catch (JMSException e)
            {
                throw new RuntimeException("Got JMSException during close:" + e.getMessage(), e);
            }
        }

        /// <summary> Sends a message on the test circuit. The exact nature of the message sent is controlled by the test parameters. </summary>
        protected void send()
        {
            // Cast the test properties into a typed interface for convenience.
            MessagingTestConfigProperties props = new MessagingTestConfigProperties(testProps);

            bool transactional = props.getPublisherTransacted();
            bool rollback = props.getRollbackPublisher();

            // Send a message through the publisher and log any exceptions raised.
            try
            {
                CircuitEnd end = getLocalPublisherCircuitEnd();

                end.send(createTestMessage(end));

                if (rollback)
                {
                    end.getSession().rollback();
                }
                else if (transactional)
                {
                    end.getSession().commit();
                }
            }
            catch (JMSException e)
            {
                exceptionMonitor.onException(e);
            }
        }

        /// <summary>
        /// Runs the default test procedure against the circuit, and checks that all of the specified assertions hold. The
        /// outline of the default test procedure is:
        ///
        /// <p/><pre>
        /// Start the circuit.
        /// Send test messages.
        /// Request a status report.
        /// Assert conditions on the publishing end of the circuit.
        /// Assert conditions on the receiving end of the circuit.
        /// Close the circuit.
        /// Pass with no failed assertions or fail with a list of failed assertions.
        /// </pre>
        /// </summary>
        /// <param name="numMessages"> The number of messages to send using the default test procedure. </param>
        /// <param name="assertions">  The list of assertions to apply. </param>
        /// <return> Any assertions that failed. </return>
        public IList<Assertion> test(int numMessages, List<Assertion> assertions)
        {
            // Start the test circuit.
            start();

            // Send the requested number of test messages.
            for (int i = 0; i < numMessages; i++)
            {
                send();
            }

            // Inject a short pause to allow time for exceptions to come back asynchronously.
            TestUtils.pause(500L);

            // Request a status report.
            check();

            // Clean up the publisher/receivers/controlSession/connections.
            close();

            // Apply all of the requested assertions, keeping record of any that fail.
            IList<Assertion> failures = applyAssertions(assertions);

            // Return any failed assertions to the caller.
            return failures;
        }

        /// <summary>
        /// Creates a message with the properties defined as per the test parameters.
        /// </summary>
        /// <param name="client"> The circuit end to create the message on. </param>
        ///
        /// <return> The test message. </return>
        ///
        /// <exception cref="JMSException"> Any JMSException occurring during creation of the message is allowed to fall through. </exception>
        private Message createTestMessage(CircuitEnd client) throws JMSException
        {
            // Cast the test properties into a typed interface for convenience.
            MessagingTestConfigProperties props = new MessagingTestConfigProperties(testProps);

            return TestUtils.createTestMessageOfSize(client.getSession(), props.getMessageSize());
        }

        /// <summary>
        /// Gets the exception monitor for the publishing ends connection.
        /// </summary>
        /// <return> The exception monitor for the publishing ends connection. </return>
        public ExceptionMonitor getConnectionExceptionMonitor()
        {
            return connectionExceptionMonitor;
        }

        /// <summary>
        /// Gets the exception monitor for the publishing ends controlSession.
        /// </summary>
        /// <return> The exception monitor for the publishing ends controlSession. </return>
        public ExceptionMonitor getExceptionMonitor()
        {
            return exceptionMonitor;
        }
    }
}
/*
 *
 * 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.
 *
 */
using Apache.Qpid.Integration.Tests.framework.*;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.MessageConsumer;
using javax.jms.MessageProducer;
using javax.jms.Session;

namespace Apache.Qpid.Integration.Tests.framework.localcircuit
{
    /// <summary>
    /// Provides an implementation of the <see cref="Publisher"/> interface and wraps a single message producer and consumer on
    /// a single controlSession, as a <see cref="CircuitEnd"/>. A local publisher also acts as a circuit end, because for a locally
    /// located circuit the assertions may be applied directly, there does not need to be any inter-process messaging
    /// between the publisher and its single circuit end, in order to ascertain its status.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Provide a message producer for sending messages.
    /// <tr><td> Provide a message consumer for receiving messages.
    /// <tr><td> Provide assertion that the publisher received no exceptions.
    /// <tr><td> Provide assertion that the publisher received a no consumers error code.
    /// <tr><td> Provide assertion that the publisher received a no route error code.
    /// </table>
    /// </summary>
    public class LocalPublisherImpl extends CircuitEndBase : Publisher
    {
        /// <summary> Holds a reference to the containing circuit. </summary>
        protected LocalCircuitImpl circuit;

        /// <summary>
        /// Creates a circuit end point on the specified producer, consumer and controlSession. Monitors are also configured
        /// for messages and exceptions received by the circuit end.
        /// </summary>
        /// <param name="producer"> The message producer for the circuit end point. </param>
        /// <param name="consumer"> The message consumer for the circuit end point. </param>
        /// <param name="session">  The controlSession for the circuit end point. </param>
        /// <param name="messageMonitor">   The monitor to notify of all messages received by the circuit end. </param>
        /// <param name="exceptionMonitor"> The monitor to notify of all exceptions received by the circuit end. </param>
        public LocalPublisherImpl(MessageProducer producer, MessageConsumer consumer, Session session,
                                  MessageMonitor messageMonitor, ExceptionMonitor exceptionMonitor)
        {
            super(producer, consumer, session, messageMonitor, exceptionMonitor);
        }

        /// <summary>
        /// Creates a circuit end point from the producer, consumer and controlSession in a circuit end base implementation.
        /// </summary>
        /// <param name="end"> The circuit end base implementation to take producers and consumers from. </param>
        public LocalPublisherImpl(CircuitEndBase end)
        {
            super(end.getProducer(), end.getConsumer(), end.getSession(), end.getMessageMonitor(), end.getExceptionMonitor());
        }

        /// <summary> Provides an assertion that the publisher encountered no exceptions. </summary>
        ///
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the publisher encountered no exceptions. </return>
        public Assertion noExceptionsAssertion(ParsedProperties testProps)
        {
            return new AssertionBase()
                {
                    public bool apply()
                    {
                        bool passed = true;
                        ExceptionMonitor sessionExceptionMonitor = circuit.getExceptionMonitor();
                        ExceptionMonitor connectionExceptionMonitor = circuit.getConnectionExceptionMonitor();

                        if (!connectionExceptionMonitor.assertNoExceptions())
                        {
                            passed = false;

                            addError("Was expecting no exceptions.\n");
                            addError("Got the following exceptions on the connection, "
                                     + circuit.getConnectionExceptionMonitor());
                        }

                        if (!sessionExceptionMonitor.assertNoExceptions())
                        {
                            passed = false;

                            addError("Was expecting no exceptions.\n");
                            addError("Got the following exceptions on the producer, " + circuit.getExceptionMonitor());
                        }

                        return passed;
                    }
            };
        }

        /// <summary>
        /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
        public Assertion channelClosedAssertion(ParsedProperties testProps)
        {
            return new NotApplicableAssertion(testProps);
        }

        /// <summary>
        /// Provides an assertion that the publisher got a given exception during the test.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        /// <param name="exceptionClass"> The exception class to check for. </param>
        ///
        /// <return> An assertion that the publisher got a given exception during the test. </return>
        public Assertion exceptionAssertion(ParsedProperties testProps, final Class<? extends Exception> exceptionClass)
        {
            return new AssertionBase()
                {
                    public bool apply()
                    {
                        bool passed = true;
                        ExceptionMonitor connectionExceptionMonitor = circuit.getConnectionExceptionMonitor();

                        if (!connectionExceptionMonitor.assertExceptionOfType(exceptionClass))
                        {
                            passed = false;

                            addError("Was expecting linked exception type " + exceptionClass.getName()
                                     + " on the connection.\n");
                            addError((connectionExceptionMonitor.size() > 0)
                                     ? ("Actually got the following exceptions on the connection, " + connectionExceptionMonitor)
                                     : "Got no exceptions on the connection.");
                        }

                        return passed;
                    }
            };
        }

        /// <summary>
        /// Sets the contianing circuit.
        /// </summary>
        /// <param name="circuit"> The containing circuit. </param>
        public void setCircuit(LocalCircuitImpl circuit)
        {
            this.circuit = circuit;
        }
    }
}
/*
 *
 * 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.
 *
 */
using Apache.Qpid.Integration.Tests.framework.*;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.MessageConsumer;
using javax.jms.MessageProducer;
using javax.jms.Session;

namespace Apache.Qpid.Integration.Tests.framework.localcircuit
{
    /// <summary>
    /// Provides an implementation of the <see cref="Receiver"/> interface that wraps a single message producer and consumer on
    /// a single controlSession, as a <see cref="CircuitEnd"/>. A local receiver also acts as a circuit end, because for a locally
    /// located circuit the assertions may be applied directly, there does not need to be any inter process messaging
    /// between the publisher and its single circuit end, in order to ascertain its status.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Provide a message producer for sending messages.
    /// <tr><td> Provide a message consumer for receiving messages.
    /// <tr><td> Provide assertion that the receivers received no exceptions.
    /// <tr><td> Provide assertion that the receivers received all test messages sent to it.
    /// </table>
    /// </summary>
    public class LocalReceiverImpl extends CircuitEndBase : Receiver
    {
        /// <summary> Holds a reference to the containing circuit. </summary>
        private LocalCircuitImpl circuit;

        /// <summary>
        /// Creates a circuit end point on the specified producer, consumer and controlSession. Monitors are also configured
        /// for messages and exceptions received by the circuit end.
        /// </summary>
        /// <param name="producer"> The message producer for the circuit end point. </param>
        /// <param name="consumer"> The message consumer for the circuit end point. </param>
        /// <param name="session">  The controlSession for the circuit end point. </param>
        /// <param name="messageMonitor">   The monitor to notify of all messages received by the circuit end. </param>
        /// <param name="exceptionMonitor"> The monitor to notify of all exceptions received by the circuit end. </param>
        public LocalReceiverImpl(MessageProducer producer, MessageConsumer consumer, Session session,
                                 MessageMonitor messageMonitor, ExceptionMonitor exceptionMonitor)
        {
            super(producer, consumer, session, messageMonitor, exceptionMonitor);
        }

        /// <summary>
        /// Creates a circuit end point from the producer, consumer and controlSession in a circuit end base implementation.
        /// </summary>
        /// <param name="end"> The circuit end base implementation to take producers and consumers from. </param>
        public LocalReceiverImpl(CircuitEndBase end)
        {
            super(end.getProducer(), end.getConsumer(), end.getSession(), end.getMessageMonitor(), end.getExceptionMonitor());
        }

        /// <summary>
        /// Provides an assertion that the receivers encountered no exceptions.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the receivers encountered no exceptions. </return>
        public Assertion noExceptionsAssertion(ParsedProperties testProps)
        {
            return new NotApplicableAssertion(testProps);
        }

        /// <summary>
        /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
        public Assertion channelClosedAssertion(ParsedProperties testProps)
        {
            return new NotApplicableAssertion(testProps);
        }

        /// <summary>
        /// Provides an assertion that the receivers got all messages that were sent to it.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the receivers got all messages that were sent to it. </return>
        public Assertion allMessagesReceivedAssertion(ParsedProperties testProps)
        {
            return new NotApplicableAssertion(testProps);
        }

        /// <summary>
        /// Provides an assertion that the receivers got none of the messages that were sent to it.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the receivers got none of the messages that were sent to it. </return>
        public Assertion noMessagesReceivedAssertion(ParsedProperties testProps)
        {
            return new NotApplicableAssertion(testProps);
        }

        /// <summary>
        /// Provides an assertion that the receiver got a given exception during the test.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        /// <param name="exceptionClass"> The exception class to check for. <return> An assertion that the receiver got a given exception during the test. </return> </param>
        public Assertion exceptionAssertion(ParsedProperties testProps, Class<? extends Exception> exceptionClass)
        {
            return new NotApplicableAssertion(testProps);
        }

        /// <summary>
        /// Sets the contianing circuit.
        /// </summary>
        /// <param name="circuit"> The containing circuit. </param>
        public void setCircuit(LocalCircuitImpl circuit)
        {
            this.circuit = circuit;
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using Apache.Qpid.Integration.Tests.framework.localcircuit.LocalCircuitImpl;
using Apache.Qpid.Integration.Tests.framework.localcircuit.LocalPublisherImpl;
using Apache.Qpid.Integration.Tests.framework.localcircuit.LocalReceiverImpl;
using Apache.Qpid.Integration.Tests.framework.sequencers.CircuitFactory;
using org.apache.qpid.util.ConversationFactory;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.*;

using System.Collections.Generic.IList;
using java.util.Properties;
using java.util.concurrent.atomic.AtomicLong;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// LocalCircuitFactory is a circuit factory that creates test circuits with publishing and receiving ends rooted
    /// on the same JVM. The ends of the circuit are presented as <see cref="Publisher"/> and <see cref="Receiver"/> interfaces, which
    /// in turn provide methods to apply assertions to the circuit. The creation of the circuit ends, and the presentation
    /// of the ends as publisher/receiver interfaces, are designed to be overriden, so that circuits and assertions that
    /// use messaging features not available in JMS can be written. This provides an extension point for writing tests
    /// against proprietary features of JMS implementations.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Provide a standard test procedure over a test circuit.
    /// <tr><td> Construct test circuits appropriate to a tests context.
    /// </table>
    /// </summary>
    public class LocalCircuitFactory : CircuitFactory
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(LocalCircuitFactory));

        /// <summary> Used to create unique destination names for each test. </summary>
        protected static AtomicLong uniqueDestsId = new AtomicLong();

        /// <summary>
        /// Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
        /// begining the test and gathering the test reports from the participants.
        /// </summary>
        /// <param name="testCircuit">    The test circuit. </param>
        /// <param name="assertions">     The list of assertions to apply to the test circuit. </param>
        /// <param name="testProperties"> The test case definition. </param>
        public void sequenceTest(Circuit testCircuit, IList<Assertion> assertions, Properties testProperties)
        {
            FrameworkBaseCase.assertNoFailures(testCircuit.test(1, assertions));
        }

        /// <summary>
        /// Creates a test circuit for the test, configered by the test parameters specified.
        /// </summary>
        /// <param name="testProperties"> The test parameters. </param>
        ///
        /// <return> A test circuit. </return>
        public Circuit createCircuit(ParsedProperties testProperties)
        {
            Circuit result;

            // Cast the test properties into a typed interface for convenience.
            MessagingTestConfigProperties props = new MessagingTestConfigProperties(testProperties);

            // Create a standard publisher/receivers test client pair on a shared connection, individual sessions.
            try
            {
                // Get a unique offset to append to destination names to make them unique to the connection.
                long uniqueId = uniqueDestsId.incrementAndGet();

                // Set up the connection.
                Connection connection = TestUtils.createConnection(testProperties);

                // Add the connection exception listener to assert on exception conditions with.
                // ExceptionMonitor exceptionMonitor = new ExceptionMonitor();
                // connection.setExceptionListener(exceptionMonitor);

                // Set up the publisher.
                CircuitEndBase publisherEnd = createPublisherCircuitEnd(connection, props, uniqueId);

                // Set up the receiver.
                CircuitEndBase receiverEnd = createReceiverCircuitEnd(connection, props, uniqueId);

                // Start listening for incoming messages.
                connection.start();

                // Namespace everything up.
                LocalPublisherImpl publisher = createPublisherFromCircuitEnd(publisherEnd);
                LocalReceiverImpl receiver = createReceiverFromCircuitEnd(receiverEnd);

                result = new LocalCircuitImpl(testProperties, publisher, receiver, connection, publisher.getExceptionMonitor());
            }
            catch (JMSException e)
            {
                throw new RuntimeException("Could not create publisher/receivers pair due to a JMSException.", e);
            }

            return result;
        }

        /// <summary>
        /// Creates a local <see cref="Receiver"/> from a <see cref="CircuitEnd"/>. Sub-classes may override this to provide more
        /// specialized receivers if necessary.
        /// </summary>
        /// <param name="receiverEnd"> The receiving circuit end. </param>
        ///
        /// <return> A <see cref="Receiver"/>. </return>
        protected LocalReceiverImpl createReceiverFromCircuitEnd(CircuitEndBase receiverEnd)
        {
            return new LocalReceiverImpl(receiverEnd);
        }

        /// <summary>
        /// Creates a local <see cref="Publisher"/> from a <see cref="CircuitEnd"/>. Sub-classes may override this to provide more
        /// specialized receivers if necessary.
        /// </summary>
        /// <param name="publisherEnd"> The publishing circuit end. </param>
        ///
        /// <return> A <see cref="Receiver"/>. </return>
        protected LocalPublisherImpl createPublisherFromCircuitEnd(CircuitEndBase publisherEnd)
        {
            return new LocalPublisherImpl(publisherEnd);
        }

        /// <summary>
        /// Builds a circuit end suitable for the publishing side of a test circuit, from standard test parameters.
        /// </summary>
        /// <param name="connection"> The connection to build the circuit end on. </param>
        /// <param name="testProps">  The test parameters to configure the circuit end construction. </param>
        /// <param name="uniqueId">   A unique number to being numbering destinations from, to make this circuit unique. </param>
        ///
        /// <return> A circuit end suitable for the publishing side of a test circuit. </return>
        ///
        /// <exception cref="JMSException"> Any underlying JMSExceptions are allowed to fall through and fail the creation. </exception>
        public CircuitEndBase createPublisherCircuitEnd(Connection connection, ParsedProperties testProps, long uniqueId)
            throws JMSException
        {
            log.debug(
                      "public CircuitEndBase createPublisherCircuitEnd(Connection connection, ParsedProperties testProps, long uniqueId = "
                      + uniqueId + "): called");

            // Cast the test properties into a typed interface for convenience.
            MessagingTestConfigProperties props = new MessagingTestConfigProperties(testProps);

            // Check that the test properties do not contain AMQP/Qpid specific settings, and fail if they do.
            if (props.getImmediate() || props.getMandatory())
            {
                throw new RuntimeException(
                                           "Cannot create a pure JMS circuit as the test properties require AMQP specific options.");
            }

            Session session = connection.createSession(props.getPublisherTransacted(), props.getAckMode());

            Destination destination =
                props.getPubsub() ? session.createTopic(props.getSendDestinationNameRoot() + "_" + uniqueId)
                : session.createQueue(props.getSendDestinationNameRoot() + "_" + uniqueId);

            MessageProducer producer = props.getPublisherProducerBind() ? session.createProducer(destination) : null;

            MessageConsumer consumer =
                props.getPublisherConsumerBind()
                ? session.createConsumer(session.createQueue(props.getReceiveDestinationNameRoot() + "_" + uniqueId)) : null;

            MessageMonitor messageMonitor = new MessageMonitor();

            if (consumer != null)
            {
                consumer.setMessageListener(messageMonitor);
            }

            ExceptionMonitor exceptionMonitor = new ExceptionMonitor();
            connection.setExceptionListener(exceptionMonitor);

            if (!props.getPublisherConsumerActive() && (consumer != null))
            {
                consumer.close();
            }

            return new CircuitEndBase(producer, consumer, session, messageMonitor, exceptionMonitor);
        }

        /// <summary>
        /// Builds a circuit end suitable for the receiving side of a test circuit, from standard test parameters.
        /// </summary>
        /// <param name="connection"> The connection to build the circuit end on. </param>
        /// <param name="testProps">  The test parameters to configure the circuit end construction. </param>
        /// <param name="uniqueId">   A unique number to being numbering destinations from, to make this circuit unique. </param>
        ///
        /// <return> A circuit end suitable for the receiving side of a test circuit. </return>
        ///
        /// <exception cref="JMSException"> Any underlying JMSExceptions are allowed to fall through and fail the creation. </exception>
        public CircuitEndBase createReceiverCircuitEnd(Connection connection, ParsedProperties testProps, long uniqueId)
            throws JMSException
        {
            log.debug(
                      "public CircuitEndBase createReceiverCircuitEnd(Connection connection, ParsedProperties testProps, long uniqueId = "
                      + uniqueId + "): called");

            // Cast the test properties into a typed interface for convenience.
            MessagingTestConfigProperties props = new MessagingTestConfigProperties(testProps);

            // Check that the test properties do not contain AMQP/Qpid specific settings, and fail if they do.
            if (props.getImmediate() || props.getMandatory())
            {
                throw new RuntimeException(
                                           "Cannot create a pure JMS circuit as the test properties require AMQP specific options.");
            }

            Session session = connection.createSession(props.getPublisherTransacted(), props.getAckMode());

            MessageProducer producer =
                props.getReceiverProducerBind()
                ? session.createProducer(session.createQueue(props.getReceiveDestinationNameRoot() + "_" + uniqueId)) : null;

            Destination destination =
                props.getPubsub() ? session.createTopic(props.getSendDestinationNameRoot() + "_" + uniqueId)
                : session.createQueue(props.getSendDestinationNameRoot() + "_" + uniqueId);

            MessageConsumer consumer =
                props.getReceiverConsumerBind()
                ? ((props.getDurableSubscription() && props.getPubsub())
                   ? session.createDurableSubscriber((Topic) destination, "testsub") : session.createConsumer(destination))
                : null;

            MessageMonitor messageMonitor = new MessageMonitor();

            if (consumer != null)
            {
                consumer.setMessageListener(messageMonitor);
            }

            if (!props.getReceiverConsumerActive() && (consumer != null))
            {
                consumer.close();
            }

            return new CircuitEndBase(producer, consumer, session, messageMonitor, null);
        }

        /// <summary>
        /// Sets the sender test client to coordinate the test with.
        /// </summary>
        /// <param name="sender"> The contact details of the sending client in the test. </param>
        public void setSender(TestClientDetails sender)
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Sets the receiving test client to coordinate the test with.
        /// </summary>
        /// <param name="receiver"> The contact details of the sending client in the test. </param>
        public void setReceiver(TestClientDetails receiver)
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Supplies the sending test client.
        /// </summary>
        /// <return> The sending test client. </return>
        public TestClientDetails getSender()
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Supplies the receiving test client.
        /// </summary>
        /// <return> The receiving test client. </return>
        public IList<TestClientDetails> getReceivers()
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Accepts the conversation factory over which to hold the test coordinating conversation.
        /// </summary>
        /// <param name="conversationFactory"> The conversation factory to coordinate the test over. </param>
        public void setConversationFactory(ConversationFactory conversationFactory)
        {
            throw new RuntimeException("Not implemented.");
        }
    }
}
/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// MessageIdentityVector provides a message identification scheme, that matches individual messages with test cases.
    /// Test messages are being sent by a number of test clients, sending messages over a set of routes, and being received
    /// by another set of test clients. Each test is itself, being run within a test cycle, of which there could be many. It
    /// is the job of the test coordinator to request and receive reports from the available test clients, on what has been
    /// sent, what has been received, and what errors may have occurred, and to reconcile this information against the
    /// assertions being applied by the test case. In order to be able to figure out which messages belong to which test,
    /// there needs to be an identification scheme, that the coordinator can use to correlate messages in senders and
    /// receiver reports. Every message sent in a test can be associated with this information.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Identify a test case, a handling client id, a circuit end within the client, and a test cycle number.
    /// </table>
    /// </summary>
    public class MessageIdentityVector
    {
        /// <summary> Holds the test case vector component of the message identity vector. </summary>
        private TestCaseVector testCaseVector;

        /// <summary> The unique client id. </summary>
        private string clientId;

        /// <summary> The unique circuit end number within the client id. </summary>
        private int circuitEndId;

        /// <summary>
        /// Creates a new identity vector for test messages.
        /// </summary>
        /// <param name="testCase">        The name of the test case generating the messages. </param>
        /// <param name="clientId">        The unique id of the client implementing a circuit end that is handling the messages. </param>
        /// <param name="circuitEndId">    The unique id number of the circuit end within the client. </param>
        /// <param name="testCycleNumber"> The cycle iteration number of the test case. </param>
        public MessageIdentityVector(string testCase, string clientId, int circuitEndId, int testCycleNumber)
        {
            this.testCaseVector = new TestCaseVector(testCase, testCycleNumber);
            this.clientId = clientId;
            this.circuitEndId = circuitEndId;
        }

        /// <summary>
        /// Reports the test case vector component of the message identity vector.
        /// </summary>
        /// <return> The test case vector component of the message identity vector. </return>
        public TestCaseVector getTestCaseVector()
        {
            return testCaseVector;
        }

        /// <summary>
        /// Reports the name of the test case.
        /// </summary>
        /// <return> The name of the test case. </return>
        public string getTestCase()
        {
            return testCaseVector.getTestCase();
        }

        /// <summary>
        /// Reports the test iteration cycle number within the test case.
        /// </summary>
        /// <return> The test iteration cycle number within the test case. </return>
        public int getTestCycleNumber()
        {
            return testCaseVector.getTestCycleNumber();
        }

        /// <summary>
        /// Resports the client id.
        /// </summary>
        /// <return> The client id. </return>
        public string getClientId()
        {
            return clientId;
        }

        /// <summary>
        /// Reports the circuit end number within the test client.
        /// </summary>
        /// <return> The circuit end number within the test client. </return>
        public int getCircuitEndId()
        {
            return circuitEndId;
        }

        /// <summary>
        /// Compares this identity vector with another for equality. All fields must match.
        /// </summary>
        /// <param name="o"> The identity vector to compare with. </param>
        ///
        /// <return> <tt>true</tt> if the identity vector is identical to this one by all fields, <tt>false</tt> otherwise. </return>
        public bool equals(Object o)
        {
            if (this == o)
            {
                return true;
            }

            if ((o == null) || (getClass() != o.getClass()))
            {
                return false;
            }

            MessageIdentityVector that = (MessageIdentityVector) o;

            if (circuitEndId != that.circuitEndId)
            {
                return false;
            }

            if ((clientId != null) ? (!clientId.equals(that.clientId)) : (that.clientId != null))
            {
                return false;
            }

            if ((testCaseVector != null) ? (!testCaseVector.equals(that.testCaseVector)) : (that.testCaseVector != null))
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Computes a hash code for this identity vector based on all fields.
        /// </summary>
        /// <return> A hash code for this identity vector based on all fields. </return>
        public int hashCode()
        {
            int result;
            result = ((testCaseVector != null) ? testCaseVector.hashCode() : 0);
            result = (31 * result) + ((clientId != null) ? clientId.hashCode() : 0);
            result = (31 * result) + circuitEndId;

            return result;
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using javax.jms.Message;
using javax.jms.MessageListener;

using java.util.concurrent.atomic.AtomicInteger;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// MessageMonitor is used to record information about messages received. This will provide methods to check various
    /// properties, such as the type, number and content of messages received in order to verify the correct behaviour of
    /// tests.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Count incoming messages.
    /// <tr><td> Record time ellapsed since the arrival of the first message.
    /// <tr><td> Reset all counts and timings.
    /// </table>
    /// </summary>
    public class MessageMonitor : MessageListener
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(MessageMonitor));

        /// <summary> Holds the count of messages received since the last query. </summary>
        protected AtomicInteger numMessages = new AtomicInteger();

        /// <summary> Holds the time of arrival of the first message. </summary>
        protected Long firstMessageTime = null;

        /// <summary>
        /// Handles received messages. Does Nothing.
        /// </summary>
        /// <param name="message"> The message. Ignored. </param>
        public void onMessage(Message message)
        {
            // log.debug("public void onMessage(Message message): called");

            numMessages.getAndIncrement();
        }

        /// <summary>
        /// Gets the count of messages.
        /// </summary>
        /// <return> The count of messages. </return>
        public int getNumMessage()
        {
            if (firstMessageTime == null)
            {
                firstMessageTime = System.nanoTime();
            }

            return numMessages.get();
        }

        /// <summary>
        /// Gets the time elapsed since the first message arrived, in nanos, or zero if no messages have arrived yet.
        /// </summary>
        /// <return> The time elapsed since the first message arrived, in nanos, or zero if no messages have arrived yet. </return>
        public long getTime()
        {
            if (firstMessageTime != null)
            {
                return System.nanoTime() - firstMessageTime;
            }
            else
            {
                return 0L;
            }
        }

        /// <summary> Resets the message count and timer to zero. </summary>
        public void reset()
        {
            numMessages.set(0);
            firstMessageTime = null;
        }
    }
}
/*
 *
 * 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.
 *
 */
using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.Session;

using java.util.Properties;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// MessagingTestConfigProperties defines a set of property names and default values for specifying a messaging topology,
    /// and test parameters for running a messaging test over that topology. A Properties object holding some of these
    /// properties, superimposed onto the defaults, is used to establish test topologies and control test behaviour.
    ///
    /// <p/>A complete list of the parameters, default values and comments on their usage is provided here:
    ///
    /// <p/><table><caption>Parameters</caption>
    /// <tr><th> Parameter        <th> Default  <th> Comments
    /// <tr><td> messageSize      <td> 0        <td> Message size in bytes. Not including any headers.
    /// <tr><td> destinationName  <td> ping     <td> The root name to use to generate destination names to ping.
    /// <tr><td> persistent       <td> false    <td> Determines whether peristent delivery is used.
    /// <tr><td> transacted       <td> false    <td> Determines whether messages are sent/received in transactions.
    /// <tr><td> broker           <td> tcp://localhost:5672 <td> Determines the broker to connect to.
    /// <tr><td> virtualHost      <td> test     <td> Determines the virtual host to send all ping over.
    /// <tr><td> rate             <td> 0        <td> The maximum rate (in hertz) to send messages at. 0 means no limit.
    /// <tr><td> verbose          <td> false    <td> The verbose flag for debugging. Prints to console on every message.
    /// <tr><td> pubsub           <td> false    <td> Whether to ping topics or queues. Uses p2p by default.
    /// <tr><td> username         <td> guest    <td> The username to access the broker with.
    /// <tr><td> password         <td> guest    <td> The password to access the broker with.
    /// <tr><td> selector         <td> null     <td> Not used. Defines a message selector to filter pings with.
    /// <tr><td> destinationCount <td> 1        <td> The number of receivers listening to the pings.
    /// <tr><td> timeout          <td> 30000    <td> In milliseconds. The timeout to stop waiting for replies.
    /// <tr><td> commitBatchSize  <td> 1        <td> The number of messages per transaction in transactional mode.
    /// <tr><td> uniqueDests      <td> true     <td> Whether each receivers only listens to one ping destination or all.
    /// <tr><td> durableDests     <td> false    <td> Whether or not durable destinations are used.
    /// <tr><td> ackMode          <td> AUTO_ACK <td> The message acknowledgement mode. Possible values are:
    ///                                               0 - SESSION_TRANSACTED
    ///                                               1 - AUTO_ACKNOWLEDGE
    ///                                               2 - CLIENT_ACKNOWLEDGE
    ///                                               3 - DUPS_OK_ACKNOWLEDGE
    ///                                               257 - NO_ACKNOWLEDGE
    ///                                               258 - PRE_ACKNOWLEDGE
    /// <tr><td> maxPending       <td> 0        <td> The maximum size in bytes, of messages sent but not yet received.
    ///                                              Limits the volume of messages currently buffered on the client
    ///                                              or broker. Can help scale test clients by limiting amount of buffered
    ///                                              data to avoid out of memory errors.
    /// </table>
    ///
    /// <p><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Provide the names and defaults of all test parameters.
    /// </table>
    /// </summary>
    ///
    /// <remarks> Put a type-safe wrapper around these properties, but continue to store the parameters as properties. This is
    ///       simply to ensure that it is a simple matter to serialize/deserialize string/string pairs onto messages.</remarks>
    public class MessagingTestConfigProperties extends ParsedProperties
    {
        // ====================== Connection Properties ==================================

        /// <summary> Holds the name of the default connection configuration. </summary>
        public static final string CONNECTION_NAME = "broker";

        /// <summary> Holds the name of the property to get the initial context factory name from. </summary>
        public static final string INITIAL_CONTEXT_FACTORY_PROPNAME = "java.naming.factory.initial";

        /// <summary> Defines the class to use as the initial context factory by default. </summary>
        public static final string INITIAL_CONTEXT_FACTORY_DEFAULT = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory";

        /// <summary> Holds the name of the property to get the test broker url from. </summary>
        public static final string BROKER_PROPNAME = "qpid.test.broker";

        /// <summary> Holds the default broker url for the test. </summary>
        public static final string BROKER_DEFAULT = "vm://:1";

        /// <summary> Holds the name of the property to get the test broker virtual path. </summary>
        public static final string VIRTUAL_HOST_PROPNAME = "virtualHost";

        /// <summary> Holds the default virtual path for the test. </summary>
        public static final string VIRTUAL_HOST_DEFAULT = "";

        /// <summary> Holds the name of the property to get the broker access username from. </summary>
        public static final string USERNAME_PROPNAME = "username";

        /// <summary> Holds the default broker log on username. </summary>
        public static final string USERNAME_DEFAULT = "guest";

        /// <summary> Holds the name of the property to get the broker access password from. </summary>
        public static final string PASSWORD_PROPNAME = "password";

        /// <summary> Holds the default broker log on password. </summary>
        public static final string PASSWORD_DEFAULT = "guest";

        // ====================== Messaging Topology Properties ==========================

        /// <summary> Holds the name of the property to get the bind publisher procuder flag from. </summary>
        public static final string PUBLISHER_PRODUCER_BIND_PROPNAME = "publisherProducerBind";

        /// <summary> Holds the default value of the publisher producer flag. </summary>
        public static final bool PUBLISHER_PRODUCER_BIND_DEFAULT = true;

        /// <summary> Holds the name of the property to get the bind publisher procuder flag from. </summary>
        public static final string PUBLISHER_CONSUMER_BIND_PROPNAME = "publisherConsumerBind";

        /// <summary> Holds the default value of the publisher consumer flag. </summary>
        public static final bool PUBLISHER_CONSUMER_BIND_DEFAULT = false;

        /// <summary> Holds the name of the property to get the bind receivers procuder flag from. </summary>
        public static final string RECEIVER_PRODUCER_BIND_PROPNAME = "receiverProducerBind";

        /// <summary> Holds the default value of the receivers producer flag. </summary>
        public static final bool RECEIVER_PRODUCER_BIND_DEFAULT = false;

        /// <summary> Holds the name of the property to get the bind receivers procuder flag from. </summary>
        public static final string RECEIVER_CONSUMER_BIND_PROPNAME = "receiverConsumerBind";

        /// <summary> Holds the default value of the receivers consumer flag. </summary>
        public static final bool RECEIVER_CONSUMER_BIND_DEFAULT = true;

        /// <summary> Holds the name of the property to get the publishers consumer active flag from. </summary>
        public static final string PUBLISHER_CONSUMER_ACTIVE_PROPNAME = "publisherConsumerActive";

        /// <summary> Holds the default value of the publishers consumer active flag. </summary>
        public static final bool PUBLISHER_CONSUMER_ACTIVE_DEFAULT = true;

        /// <summary> Holds the name of the property to get the receivers consumer active flag from. </summary>
        public static final string RECEIVER_CONSUMER_ACTIVE_PROPNAME = "receiverConsumerActive";

        /// <summary> Holds the default value of the receivers consumer active flag. </summary>
        public static final bool RECEIVER_CONSUMER_ACTIVE_DEFAULT = true;

        /// <summary> Holds the name of the property to get the destination name root from. </summary>
        public static final string SEND_DESTINATION_NAME_ROOT_PROPNAME = "sendDestinationRoot";

        /// <summary> Holds the root of the name of the default destination to send to. </summary>
        public static final string SEND_DESTINATION_NAME_ROOT_DEFAULT = "sendTo";

        /// <summary> Holds the name of the property to get the destination name root from. </summary>
        public static final string RECEIVE_DESTINATION_NAME_ROOT_PROPNAME = "receiveDestinationRoot";

        /// <summary> Holds the root of the name of the default destination to send to. </summary>
        public static final string RECEIVE_DESTINATION_NAME_ROOT_DEFAULT = "receiveFrom";

        /// <summary> Holds the name of the proeprty to get the destination count from. </summary>
        public static final string DESTINATION_COUNT_PROPNAME = "destinationCount";

        /// <summary> Defines the default number of destinations to ping. </summary>
        public static final int DESTINATION_COUNT_DEFAULT = 1;

        /// <summary> Holds the name of the property to get the p2p or pub/sub messaging mode from. </summary>
        public static final string PUBSUB_PROPNAME = "pubsub";

        /// <summary> Holds the pub/sub mode default, true means ping a topic, false means ping a queue. </summary>
        public static final bool PUBSUB_DEFAULT = false;

        // ======================  JMS Options and Flags =================================

        /// <summary> Holds the name of the property to get the test delivery mode from. </summary>
        public static final string PERSISTENT_MODE_PROPNAME = "persistent";

        /// <summary> Holds the message delivery mode to use for the test. </summary>
        public static final bool PERSISTENT_MODE_DEFAULT = false;

        /// <summary> Holds the name of the property to get the test transactional mode from. </summary>
        public static final string TRANSACTED_PUBLISHER_PROPNAME = "transactedPublisher";

        /// <summary> Holds the transactional mode to use for the test. </summary>
        public static final bool TRANSACTED_PUBLISHER_DEFAULT = false;

        /// <summary> Holds the name of the property to get the test transactional mode from. </summary>
        public static final string TRANSACTED_RECEIVER_PROPNAME = "transactedReceiver";

        /// <summary> Holds the transactional mode to use for the test. </summary>
        public static final bool TRANSACTED_RECEIVER_DEFAULT = false;

        /// <summary> Holds the name of the property to set the no local flag from. </summary>
        public static final string NO_LOCAL_PROPNAME = "noLocal";

        /// <summary> Defines the default value of the no local flag to use when consuming messages. </summary>
        public static final bool NO_LOCAL_DEFAULT = false;

        /// <summary> Holds the name of the property to get the message acknowledgement mode from. </summary>
        public static final string ACK_MODE_PROPNAME = "ackMode";

        /// <summary> Defines the default message acknowledgement mode. </summary>
        public static final int ACK_MODE_DEFAULT = Session.AUTO_ACKNOWLEDGE;

        /// <summary> Holds the name of the property to get the durable subscriptions flag from, when doing pub/sub messaging. </summary>
        public static final string DURABLE_SUBSCRIPTION_PROPNAME = "durableSubscription";

        /// <summary> Defines the default value of the durable subscriptions flag. </summary>
        public static final bool DURABLE_SUBSCRIPTION_DEFAULT = false;

        // ======================  Qpid/AMQP Options and Flags ================================

        /// <summary> Holds the name of the property to set the exclusive flag from. </summary>
        public static final string EXCLUSIVE_PROPNAME = "exclusive";

        /// <summary> Defines the default value of the exclusive flag to use when consuming messages. </summary>
        public static final bool EXCLUSIVE_DEFAULT = false;

        /// <summary> Holds the name of the property to set the immediate flag from. </summary>
        public static final string IMMEDIATE_PROPNAME = "immediate";

        /// <summary> Defines the default value of the immediate flag to use when sending messages. </summary>
        public static final bool IMMEDIATE_DEFAULT = false;

        /// <summary> Holds the name of the property to set the mandatory flag from. </summary>
        public static final string MANDATORY_PROPNAME = "mandatory";

        /// <summary> Defines the default value of the mandatory flag to use when sending messages. </summary>
        public static final bool MANDATORY_DEFAULT = false;

        /// <summary> Holds the name of the property to get the durable destinations flag from. </summary>
        public static final string DURABLE_DESTS_PROPNAME = "durableDests";

        /// <summary> Default value for the durable destinations flag. </summary>
        public static final bool DURABLE_DESTS_DEFAULT = false;

        /// <summary> Holds the name of the property to set the prefetch size from. </summary>
        public static final string PREFETCH_PROPNAME = "prefetch";

        /// <summary> Defines the default prefetch size to use when consuming messages. </summary>
        public static final int PREFETCH_DEFAULT = 100;

        // ======================  Common Test Parameters ================================

        /// <summary> Holds the name of the property to get the test message size from. </summary>
        public static final string MESSAGE_SIZE_PROPNAME = "messageSize";

        /// <summary> Used to set up a default message size. </summary>
        public static final int MESSAGE_SIZE_DEAFULT = 0;

        /// <summary> Holds the name of the property to get the message rate from. </summary>
        public static final string RATE_PROPNAME = "rate";

        /// <summary> Defines the default rate (in pings per second) to send pings at. 0 means as fast as possible, no restriction. </summary>
        public static final int RATE_DEFAULT = 0;

        /// <summary> Holds the name of the proeprty to get the. </summary>
        public static final string SELECTOR_PROPNAME = "selector";

        /// <summary> Holds the default message selector. </summary>
        public static final string SELECTOR_DEFAULT = "";

        /// <summary> Holds the name of the property to get the waiting timeout for response messages. </summary>
        public static final string TIMEOUT_PROPNAME = "timeout";

        /// <summary> Default time to wait before assuming that a ping has timed out. </summary>
        public static final long TIMEOUT_DEFAULT = 30000;

        /// <summary> Holds the name of the property to get the commit batch size from. </summary>
        public static final string TX_BATCH_SIZE_PROPNAME = "commitBatchSize";

        /// <summary> Defines the default number of pings to send in each transaction when running transactionally. </summary>
        public static final int TX_BATCH_SIZE_DEFAULT = 1;

        /// <summary> Holds the name of the property to set the maximum amount of pending message data for a producer to hold. </summary>
        public static final string MAX_PENDING_PROPNAME = "maxPending";

        /// <summary> Defines the default maximum quantity of pending message data to allow producers to hold. </summary>
        public static final int MAX_PENDING_DEFAULT = 0;

        /// <summary> Holds the name of the property to get the publisher rollback flag from. </summary>
        public static final string ROLLBACK_PUBLISHER_PROPNAME = "rollbackPublisher";

        /// <summary> Holds the default publisher roll back setting. </summary>
        public static final bool ROLLBACK_PUBLISHER_DEFAULT = false;

        /// <summary> Holds the name of the property to get the publisher rollback flag from. </summary>
        public static final string ROLLBACK_RECEIVER_PROPNAME = "rollbackReceiver";

        /// <summary> Holds the default publisher roll back setting. </summary>
        public static final bool ROLLBACK_RECEIVER_DEFAULT = false;

        // ====================== Options that control the bahviour of the test framework. =========================

        /// <summary> Holds the name of the property to get the behavioural mode of not applicable assertions. </summary>
        public static final string NOT_APPLICABLE_ASSERTION_PROPNAME = "notApplicableAssertion";

        /// <summary> Holds the default behavioral mode of not applicable assertions, which is logging them as a warning. </summary>
        public static final string NOT_APPLICABLE_ASSERTION_DEFAULT = "warn";

        /// <summary> Holds the name of the property to get the verbose mode proeprty from. </summary>
        public static final string VERBOSE_PROPNAME = "verbose";

        /// <summary> Holds the default verbose mode. </summary>
        public static final bool VERBOSE_DEFAULT = false;

        /// <summary> Holds the default configuration properties. </summary>
        public static ParsedProperties defaults = new ParsedProperties();

        static
        {
            defaults.setPropertyIfNull(INITIAL_CONTEXT_FACTORY_PROPNAME, INITIAL_CONTEXT_FACTORY_DEFAULT);
            defaults.setPropertyIfNull(BROKER_PROPNAME, BROKER_DEFAULT);
            defaults.setPropertyIfNull(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT);
            defaults.setPropertyIfNull(USERNAME_PROPNAME, USERNAME_DEFAULT);
            defaults.setPropertyIfNull(PASSWORD_PROPNAME, PASSWORD_DEFAULT);

            defaults.setPropertyIfNull(PUBLISHER_PRODUCER_BIND_PROPNAME, PUBLISHER_PRODUCER_BIND_DEFAULT);
            defaults.setPropertyIfNull(PUBLISHER_CONSUMER_BIND_PROPNAME, PUBLISHER_CONSUMER_BIND_DEFAULT);
            defaults.setPropertyIfNull(RECEIVER_PRODUCER_BIND_PROPNAME, RECEIVER_PRODUCER_BIND_DEFAULT);
            defaults.setPropertyIfNull(RECEIVER_CONSUMER_BIND_PROPNAME, RECEIVER_CONSUMER_BIND_DEFAULT);
            defaults.setPropertyIfNull(PUBLISHER_CONSUMER_ACTIVE_PROPNAME, PUBLISHER_CONSUMER_ACTIVE_DEFAULT);
            defaults.setPropertyIfNull(RECEIVER_CONSUMER_ACTIVE_PROPNAME, RECEIVER_CONSUMER_ACTIVE_DEFAULT);
            defaults.setPropertyIfNull(SEND_DESTINATION_NAME_ROOT_PROPNAME, SEND_DESTINATION_NAME_ROOT_DEFAULT);
            defaults.setPropertyIfNull(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME, RECEIVE_DESTINATION_NAME_ROOT_DEFAULT);
            defaults.setPropertyIfNull(DESTINATION_COUNT_PROPNAME, DESTINATION_COUNT_DEFAULT);
            defaults.setPropertyIfNull(PUBSUB_PROPNAME, PUBSUB_DEFAULT);

            defaults.setPropertyIfNull(PERSISTENT_MODE_PROPNAME, PERSISTENT_MODE_DEFAULT);
            defaults.setPropertyIfNull(TRANSACTED_PUBLISHER_PROPNAME, TRANSACTED_PUBLISHER_DEFAULT);
            defaults.setPropertyIfNull(TRANSACTED_RECEIVER_PROPNAME, TRANSACTED_RECEIVER_DEFAULT);
            defaults.setPropertyIfNull(NO_LOCAL_PROPNAME, NO_LOCAL_DEFAULT);
            defaults.setPropertyIfNull(ACK_MODE_PROPNAME, ACK_MODE_DEFAULT);
            defaults.setPropertyIfNull(DURABLE_SUBSCRIPTION_PROPNAME, DURABLE_SUBSCRIPTION_DEFAULT);

            defaults.setPropertyIfNull(EXCLUSIVE_PROPNAME, EXCLUSIVE_DEFAULT);
            defaults.setPropertyIfNull(IMMEDIATE_PROPNAME, IMMEDIATE_DEFAULT);
            defaults.setPropertyIfNull(MANDATORY_PROPNAME, MANDATORY_DEFAULT);
            defaults.setPropertyIfNull(DURABLE_DESTS_PROPNAME, DURABLE_DESTS_DEFAULT);
            defaults.setPropertyIfNull(PREFETCH_PROPNAME, PREFETCH_DEFAULT);

            defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT);
            defaults.setPropertyIfNull(RATE_PROPNAME, RATE_DEFAULT);
            defaults.setPropertyIfNull(SELECTOR_PROPNAME, SELECTOR_DEFAULT);
            defaults.setPropertyIfNull(TIMEOUT_PROPNAME, TIMEOUT_DEFAULT);
            defaults.setPropertyIfNull(TX_BATCH_SIZE_PROPNAME, TX_BATCH_SIZE_DEFAULT);
            defaults.setPropertyIfNull(MAX_PENDING_PROPNAME, MAX_PENDING_DEFAULT);
            defaults.setPropertyIfNull(ROLLBACK_PUBLISHER_PROPNAME, ROLLBACK_PUBLISHER_DEFAULT);
            defaults.setPropertyIfNull(ROLLBACK_RECEIVER_PROPNAME, ROLLBACK_RECEIVER_DEFAULT);

            defaults.setPropertyIfNull(NOT_APPLICABLE_ASSERTION_PROPNAME, NOT_APPLICABLE_ASSERTION_DEFAULT);
            defaults.setPropertyIfNull(VERBOSE_PROPNAME, VERBOSE_DEFAULT);
        }

        /// <summary> Creates a test configuration based on the defaults. </summary>
        public MessagingTestConfigProperties()
        {
            super(defaults);
        }

        /// <summary>
        /// Creates a test configuration based on the supplied properties.
        /// </summary>
        /// <param name="properties"> The test configuration. </param>
        public MessagingTestConfigProperties(Properties properties)
        {
            super(properties);
        }

        /// <summary>
        /// The size of test messages to send.
        /// </summary>
        /// <return> The size of test messages to send. </return>
        public int getMessageSize()
        {
            return getPropertyAsInteger(MESSAGE_SIZE_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that the publishing producer should be set up to publish to a destination.
        /// </summary>
        /// <return> Flag to indicate that the publishing producer should be set up to publish to a destination. </return>
        public bool getPublisherProducerBind()
        {
            return getPropertyAsBoolean(PUBLISHER_PRODUCER_BIND_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that the publishing consumer should be set up to receive from a destination.
        /// </summary>
        /// <return> Flag to indicate that the publishing consumer should be set up to receive from a destination. </return>
        public bool getPublisherConsumerBind()
        {
            return getPropertyAsBoolean(PUBLISHER_CONSUMER_BIND_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that the receiving producer should be set up to publish to a destination.
        /// </summary>
        /// <return> Flag to indicate that the receiving producer should be set up to publish to a destination. </return>
        public bool getReceiverProducerBind()
        {
            return getPropertyAsBoolean(RECEIVER_PRODUCER_BIND_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that the receiving consumer should be set up to receive from a destination.
        /// </summary>
        /// <return> Flag to indicate that the receiving consumer should be set up to receive from a destination. </return>
        public bool getReceiverConsumerBind()
        {
            return getPropertyAsBoolean(RECEIVER_CONSUMER_BIND_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that the publishing consumer should be created and actively listening.
        /// </summary>
        /// <return> Flag to indicate that the publishing consumer should be created. </return>
        public bool getPublisherConsumerActive()
        {
            return getPropertyAsBoolean(PUBLISHER_CONSUMER_ACTIVE_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that the receiving consumers should be created and actively listening.
        /// </summary>
        /// <return> Flag to indicate that the receiving consumers should be created and actively listening. </return>
        public bool getReceiverConsumerActive()
        {
            return getPropertyAsBoolean(RECEIVER_CONSUMER_ACTIVE_PROPNAME);
        }

        /// <summary>
        /// A root to create all test destination names from.
        /// </summary>
        /// <return> A root to create all test destination names from. </return>
        public string getSendDestinationNameRoot()
        {
            return getProperty(SEND_DESTINATION_NAME_ROOT_PROPNAME);
        }

        /// <summary>
        /// A root to create all receiving destination names from.
        /// </summary>
        /// <return> A root to create all receiving destination names from. </return>
        public string getReceiveDestinationNameRoot()
        {
            return getProperty(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that persistent messages should be used.
        /// </summary>
        /// <return> Flag to indicate that persistent messages should be used. </return>
        public bool getPersistentMode()
        {
            return getPropertyAsBoolean(PERSISTENT_MODE_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that transactional messages should be sent by the publisher.
        /// </summary>
        /// <return> Flag to indicate that transactional messages should be sent by the publisher. </return>
        public bool getPublisherTransacted()
        {
            return getPropertyAsBoolean(TRANSACTED_PUBLISHER_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that transactional receives should be used by the receiver.
        /// </summary>
        /// <return> Flag to indicate that transactional receives should be used by the receiver. </return>
        public bool getReceiverTransacted()
        {
            return getPropertyAsBoolean(TRANSACTED_PUBLISHER_PROPNAME);
        }

        /// <summary>
        /// The name of the virtual host to run all tests over.
        /// </summary>
        /// <return> The name of the virtual host to run all tests over. </return>
        public string getVirtualHost()
        {
            return getProperty(VIRTUAL_HOST_PROPNAME);
        }

        /// <summary>
        /// Limiting rate for each sender in messages per second, or zero for unlimited.
        /// </summary>
        /// <return> Limiting rate for each sender in messages per second, or zero for unlimited. </return>
        public string getRate()
        {
            return getProperty(RATE_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that test messages should be received publish/subscribe style by all receivers.
        /// </summary>
        /// <return> Flag to indicate that test messages should be received publish/subscribe style by all receivers. </return>
        public bool getPubsub()
        {
            return getPropertyAsBoolean(PUBSUB_PROPNAME);
        }

        /// <summary>
        /// The username credentials to run tests with.
        /// </summary>
        /// <return> The username credentials to run tests with. </return>
        public string getUsername()
        {
            return getProperty(USERNAME_PROPNAME);
        }

        /// <summary>
        /// The password credentials to run tests with.
        /// </summary>
        /// <return> The password credentials to run tests with. </return>
        public string getPassword()
        {
            return getProperty(PASSWORD_PROPNAME);
        }

        /// <summary>
        /// The timeout duration to fail tests on, should they receive no messages within it.
        /// </summary>
        /// <return> The timeout duration to fail tests on, should they receive no messages within it. </return>
        public long getTimeout()
        {
            return getPropertyAsLong(TIMEOUT_PROPNAME);
        }

        /// <summary>
        /// The number of messages to batch into each transaction in transational tests.
        /// </summary>
        /// <return> The number of messages to batch into each transaction in transational tests. </return>
        public int getTxBatchSize()
        {
            return getPropertyAsInteger(TX_BATCH_SIZE_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that tests should use durable destinations.
        /// </summary>
        /// <return> Flag to indicate that tests should use durable destinations. </return>
        public bool getDurableDests()
        {
            return getPropertyAsBoolean(DURABLE_DESTS_PROPNAME);
        }

        /// <summary>
        /// The ack mode for message receivers to use.
        /// </summary>
        /// <return> The ack mode for message receivers to use. </return>
        public int getAckMode()
        {
            return getPropertyAsInteger(ACK_MODE_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that tests should use durable subscriptions.
        /// </summary>
        /// <return> Flag to indicate that tests should use durable subscriptions. </return>
        public bool getDurableSubscription()
        {
            return getPropertyAsBoolean(DURABLE_SUBSCRIPTION_PROPNAME);
        }

        /// <summary>
        /// The maximum amount of in-flight data, in bytes, that tests should send at any time.
        /// </summary>
        /// <return> The maximum amount of in-flight data, in bytes, that tests should send at any time. </return>
        public int getMaxPending()
        {
            return getPropertyAsInteger(MAX_PENDING_PROPNAME);
        }

        /// <summary>
        /// The size of the prefetch queue to use.
        /// </summary>
        /// <return> The size of the prefetch queue to use. </return>
        public int getPrefetch()
        {
            return getPropertyAsInteger(PREFETCH_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that subscriptions should be no-local.
        /// </summary>
        /// <return> Flag to indicate that subscriptions should be no-local. </return>
        public bool getNoLocal()
        {
            return getPropertyAsBoolean(NO_LOCAL_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that subscriptions should be exclusive.
        /// </summary>
        /// <return> Flag to indicate that subscriptions should be exclusive. </return>
        public bool getExclusive()
        {
            return getPropertyAsBoolean(EXCLUSIVE_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that messages must be delivered immediately.
        /// </summary>
        /// <return> Flag to indicate that messages must be delivered immediately. </return>
        public bool getImmediate()
        {
            return getPropertyAsBoolean(IMMEDIATE_PROPNAME);
        }

        /// <summary>
        /// Flag to indicate that messages must be routable.
        /// </summary>
        /// <return> Flag to indicate that messages must be routable. </return>
        public bool getMandatory()
        {
            return getPropertyAsBoolean(MANDATORY_PROPNAME);
        }

        /// <summary>
        /// Gets the value of a flag to indicate that the publisher should rollback all messages sent.
        /// </summary>
        /// <return> A flag to indicate that the publisher should rollback all messages sent. </return>
        public bool getRollbackPublisher()
        {
            return getPropertyAsBoolean(ROLLBACK_PUBLISHER_PROPNAME);
        }

        /// <summary>
        /// Gets the value of a flag to indicate that the receiver should rollback all messages received, then receive them
        /// again.
        /// </summary>
        /// <return> A flag to indicate that the publisher should rollback all messages received. </return>
        public bool getRollbackReceiver()
        {
            return getPropertyAsBoolean(ROLLBACK_RECEIVER_PROPNAME);
        }

        /// <summary>
        /// Gets the behavioural mode of not applicable assertions. Should be one of 'quiet', 'warn' or 'fail'.
        /// </summary>
        /// <return> The behavioural mode of not applicable assertions. </return>
        public string getNotApplicableAssertionMode()
        {
            return getProperty(NOT_APPLICABLE_ASSERTION_PROPNAME);
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// NotApplicableAssertion is a messaging assertion that can be used when an assertion requested by a test-case is not
    /// applicable to the testing scenario. For example an assertion may relate to AMQP functionality, but a test case may be
    /// being run over a non-AMQP JMS implementation, in which case the request to create the assertion may return this
    /// instead of the proper assertion. The test framework is configurable to quietly drop these assertions, log them
    /// as warnings to the console, or raise them as test failures.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Quitely pass.
    /// <tr><td> Log a warning.
    /// <tr><td> Raise a test failure.
    /// </table>
    /// </summary>
    public class NotApplicableAssertion : Assertion
    {
        /// <summary> Used for logging to the console. </summary>
        private static ILog console = LogManager.GetLogger("CONSOLE." + NotApplicableAssertion.class.getName());

        /// <summary> The possible behavioural modes of this assertion. </summary>
        private enum Mode
        {
            /// <summary> Quietly ignore the assertion by passing. </summary>
            Quiet,

            /// <summary> Ignore the assertion by passing but log a warning about it. </summary>
            Warn,

            /// <summary> Fail the assertion. </summary>
            Fail;
        }

        /// <summary> The behavioural mode of the assertion. </summary>
        private Mode mode;

        /// <summary>
        /// Creates an assertion that is driven by the value of the 'notApplicableAssertion' property of the test
        /// configuration. Its value should match one of 'quiet', 'warn' or 'fail' and if it does not it is automatically
        /// read as 'fail'.
        /// </summary>
        /// <param name="testProperties"> The test configuration properties. </param>
        public NotApplicableAssertion(ParsedProperties testProperties)
        {
            // Cast the test properties into a typed interface for convenience.
            MessagingTestConfigProperties props = new MessagingTestConfigProperties(testProperties);

            string modeName = props.getNotApplicableAssertionMode();

            if ("quiet".equals(modeName))
            {
                mode = Mode.Quiet;
            }
            else if ("warn".equals(modeName))
            {
                mode = Mode.Warn;
            }
            else
            {
                mode = Mode.Fail;
            }
        }

        /// <summary>
        /// Applies the assertion.
        /// </summary>
        /// <return> <tt>true</tt> if the assertion passes, <tt>false</tt> if it fails. </return>
        public bool apply()
        {
            switch (mode)
            {
            case Quiet:
                return true;

            case Warn:
                console.warn("Warning: Not applicable assertion being ignored.");

                return true;

            case Fail:
            default:
                return false;
            }
        }
    }
}
/*
 *
 * 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.
 *
 */
using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// A Publisher represents the status of the publishing side of a test circuit. Its main purpose is to provide assertions
    /// that can be applied to test the behaviour of the publishers.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Provide assertion that the publishers received no exceptions.
    /// </table>
    /// </summary>
    ///
    /// <remarks> There are mixtures of AMQP and JMS assertions in this interface. Either keep them here, but quietly (or with a
    ///       warning or error) drop them from test cases where they are not relevant, or push them down into sub-classes.
    ///       I am tempted to go with the dropping/warning/error approach, that would imply that it makes sense to pull
    ///       the assertions back from AMQPPublisher to here.</remarks>
    public interface Publisher
    {
        // Assertions that are meaningfull to AMQP and to JMS.

        /// <summary>
        /// Provides an assertion that the publisher encountered no exceptions.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the publisher encountered no exceptions. </return>
        public Assertion noExceptionsAssertion(ParsedProperties testProps);

        // Assertions that are meaningfull only to AMQP.

        /// <summary>
        /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
        public Assertion channelClosedAssertion(ParsedProperties testProps);

        // Assertions that are meaningfull only to Java/JMS.

        /// <summary>
        /// Provides an assertion that the publisher got a given exception during the test.
        /// </summary>
        /// <param name="testProps">      The test configuration properties. </param>
        /// <param name="exceptionClass"> The exception class to check for. </param>
        ///
        /// <return> An assertion that the publisher got a given exception during the test. </return>
        public Assertion exceptionAssertion(ParsedProperties testProps, Class<? extends Exception> exceptionClass);
    }
}
/*
 *
 * 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.
 *
 */
using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// A Receiver is a <see cref="CircuitEnd"/> that represents the status of the receiving side of a test circuit. Its main
    /// purpose is to provide assertions that can be applied to check the behaviour of the receivers.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Provide assertion that the receivers received no exceptions.
    /// <tr><td> Provide assertion that the receivers received all test messages sent to it.
    /// </table>
    /// </summary>
    ///
    /// <remarks> There are mixtures of AMQP and JMS assertions in this interface. Either keep them here, but quietly (or with a
    ///       warning or error) drop them from test cases where they are not relevant, or push them down into sub-classes.
    ///       I am tempted to go with the dropping/warning/error approach.</remarks>
    public interface Receiver
    {
        // Assertions that are meaningfull to AMQP and to JMS.

        /// <summary>
        /// Provides an assertion that the receivers encountered no exceptions.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the receivers encountered no exceptions. </return>
        public Assertion noExceptionsAssertion(ParsedProperties testProps);

        /// <summary>
        /// Provides an assertion that the receivers got all messages that were sent to it.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the receivers got all messages that were sent to it. </return>
        public Assertion allMessagesReceivedAssertion(ParsedProperties testProps);

        /// <summary>
        /// Provides an assertion that the receivers got none of the messages that were sent to it.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the receivers got none of the messages that were sent to it. </return>
        public Assertion noMessagesReceivedAssertion(ParsedProperties testProps);

        // Assertions that are meaningfull only to AMQP.

        /// <summary>
        /// Provides an assertion that the AMQP channel was forcibly closed by an error condition.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        ///
        /// <return> An assertion that the AMQP channel was forcibly closed by an error condition. </return>
        public Assertion channelClosedAssertion(ParsedProperties testProps);

        // Assertions that are meaningfull only to Java/JMS.

        /// <summary>
        /// Provides an assertion that the receiver got a given exception during the test.
        /// </summary>
        /// <param name="testProps"> The test configuration properties. </param>
        /// <param name="exceptionClass"> The exception class to check for. </param>
        ///
        /// <return> An assertion that the receiver got a given exception during the test. </return>
        public Assertion exceptionAssertion(ParsedProperties testProps, Class<? extends Exception> exceptionClass);
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using Apache.Qpid.Integration.Tests.framework.Circuit;
using Apache.Qpid.Integration.Tests.framework.TestClientDetails;
using org.apache.qpid.util.ConversationFactory;

using System.Collections.Generic.LinkedList;
using System.Collections.Generic.IList;
using java.util.Properties;

namespace Apache.Qpid.Integration.Tests.framework.sequencers
{
    /// <summary>
    /// BaseCircuitFactory provides some functionality common to all <see cref="CircuitFactory"/>s, such as the details of
    /// all <see cref="Apache.Qpid.Integration.Tests.framework.distributedtesting.TestClient"/>s that make up the end-points of
    /// the circuits that the factory creates, and an active <see cref="ConversationFactory"/> that can be used to generate
    /// control conversations with those circuit end-points.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Hold the details of the sending and receiving end-points to create circuits from.
    /// <tr><td> Provide a conversation factory to create control conversations with the end-points.
    /// </table>
    /// </summary>
    public abstract class BaseCircuitFactory : CircuitFactory
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(BaseCircuitFactory));

        /// <summary> Holds the contact details for the sending test client. </summary>
        protected TestClientDetails sender;

        /// <summary> Holds the contact details for the receving test client. </summary>
        protected IList<TestClientDetails> receivers = new LinkedList<TestClientDetails>();

        /// <summary> Holds the conversation factory over which to coordinate the test. </summary>
        protected ConversationFactory conversationFactory;

        /// <summary>
        /// Creates a test circuit for the test, configered by the test parameters specified.
        /// </summary>
        /// <param name="testProperties"> The test parameters. </param>
        /// <return> A test circuit. </return>
        public Circuit createCircuit(Properties testProperties)
        {
            throw new RuntimeException("Not implemented.");
        }

        /// <summary>
        /// Sets the sender test client to coordinate the test with.
        /// </summary>
        /// <param name="sender"> The contact details of the sending client in the test. </param>
        public void setSender(TestClientDetails sender)
        {
            log.debug("public void setSender(TestClientDetails sender = " + sender + "): called");

            this.sender = sender;
        }

        /// <summary>
        /// Sets the receiving test client to coordinate the test with.
        /// </summary>
        /// <param name="receiver"> The contact details of the sending client in the test. </param>
        public void setReceiver(TestClientDetails receiver)
        {
            log.debug("public void setReceiver(TestClientDetails receivers = " + receiver + "): called");

            this.receivers.add(receiver);
        }

        /// <summary>
        /// Supplies the sending test client.
        /// </summary>
        /// <return> The sending test client. </return>
        public TestClientDetails getSender()
        {
            return sender;
        }

        /// <summary>
        /// Supplies the receiving test client.
        /// </summary>
        /// <return> The receiving test client. </return>
        public IList<TestClientDetails> getReceivers()
        {
            return receivers;
        }

        /// <summary>
        /// Accepts the conversation factory over which to hold the test coordinating conversation.
        /// </summary>
        /// <param name="conversationFactory"> The conversation factory to coordinate the test over. </param>
        public void setConversationFactory(ConversationFactory conversationFactory)
        {
            this.conversationFactory = conversationFactory;
        }

        /// <summary>
        /// Provides the conversation factory for providing the distributed test sequencing conversations over the test
        /// connection.
        /// </summary>
        /// <return> The conversation factory to create test sequencing conversations with. </return>
        public ConversationFactory getConversationFactory()
        {
            return conversationFactory;
        }
    }
}
/*
 *
 * 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.
 *
 */
using Apache.Qpid.Integration.Tests.framework.Assertion;
using Apache.Qpid.Integration.Tests.framework.Circuit;
using Apache.Qpid.Integration.Tests.framework.TestClientDetails;
using org.apache.qpid.util.ConversationFactory;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.JMSException;
using javax.jms.Message;

using System.Collections.Generic.IList;
using System.Collections.Generic.IDictionary;
using java.util.Properties;

namespace Apache.Qpid.Integration.Tests.framework.sequencers
{
    /// <summary>
    /// A CircuitFactory is responsibile for creating test circuits appropriate to the context that a test case is
    /// running in, and providing an implementation of a standard test procedure over a test circuit.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities
    /// <tr><td> Provide a standard test procedure over a test circuit.
    /// <tr><td> Construct test circuits appropriate to a tests context.
    /// </table>
    /// </summary>
    public interface CircuitFactory
    {
        /// <summary>
        /// Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
        /// begining the test, gathering the test reports from the participants, and checking for assertion failures against
        /// the test reports.
        /// </summary>
        /// <param name="testCircuit">    The test circuit. </param>
        /// <param name="assertions">     The list of assertions to apply to the test circuit. </param>
        /// <param name="testProperties"> The test case definition. </param>
        ///
        /// @deprecated Use test circuits and Circuit.test instead.
        public void sequenceTest(Circuit testCircuit, IList<Assertion> assertions, Properties testProperties);

        /// <summary>
        /// Creates a test circuit for the test, configered by the test parameters specified.
        /// </summary>
        /// <param name="testProperties"> The test parameters. </param>
        ///
        /// <return> A test circuit. </return>
        public Circuit createCircuit(ParsedProperties testProperties);

        /// <summary>
        /// Sets the sender test client to coordinate the test with.
        /// </summary>
        /// <param name="sender"> The contact details of the sending client in the test. </param>
        public void setSender(TestClientDetails sender);

        /// <summary>
        /// Sets the receiving test client to coordinate the test with.
        /// </summary>
        /// <param name="receiver"> The contact details of the sending client in the test. </param>
        public void setReceiver(TestClientDetails receiver);

        /// <summary>
        /// Supplies the sending test client.
        /// </summary>
        /// <return> The sending test client. </return>
        public TestClientDetails getSender();

        /// <summary>
        /// Supplies the receiving test client.
        /// </summary>
        /// <return> The receiving test client. </return>
        public IList<TestClientDetails> getReceivers();

        /// <summary>
        /// Accepts the conversation factory over which to hold the test coordinating conversation.
        /// </summary>
        /// <param name="conversationFactory"> The conversation factory to coordinate the test over. </param>
        public void setConversationFactory(ConversationFactory conversationFactory);
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using Apache.Qpid.Integration.Tests.framework.Assertion;
using Apache.Qpid.Integration.Tests.framework.Circuit;
using Apache.Qpid.Integration.Tests.framework.TestClientDetails;
using Apache.Qpid.Integration.Tests.framework.TestUtils;
using Apache.Qpid.Integration.Tests.framework.distributedcircuit.DistributedCircuitImpl;
using org.apache.qpid.util.ConversationFactory;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.Destination;
using javax.jms.JMSException;
using javax.jms.Message;
using javax.jms.Session;

using System.Collections.Generic.LinkedList;
using System.Collections.Generic.IList;
using java.util.Properties;

namespace Apache.Qpid.Integration.Tests.framework.sequencers
{
    /// <summary>
    /// FanOutCircuitFactory is a circuit factory that creates distributed test circuits. Given a set of participating
    /// test client nodes, it assigns one node to the SENDER role and the remainder to the RECEIVER role.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Create distributed circuits from one to many test nodes, for fanout style testing.
    /// </table>
    /// </summary>
    ///
    /// <remarks> Adapt this to be an n*m topology circuit factory. Need to add circuit topology definitions to the test
    ///       parameters. Place n senders onto the available test clients, and m receivers. Where n or m is larger than
    ///       the available nodes, start stacking multiple test clients on each node. There will also be an option that
    ///       indicates whether nodes can play both roles, and how many nodes out of all available may be assigned to
    ///       each role.</remarks>
    ///
    /// <remarks> The createCircuit methods on this and InteropCircuitFactory are going to be identical. This is because the
    ///       partitioning into senders and receivers is already done by the test decorators. Either eliminate these factories
    ///       as unnesesary, or move the partitioning functionality into the factories, in which case the test decorators
    ///       can probably be merged or eliminated. There is confusion over the placement of responsibilities between the
    ///       factories and the test decorators... although the test decorators may well do more than just circuit creation
    ///       in the future. For example, there may have to be a special decorator for test repetition that does one circuit
    ///       creation, but the runs many tests over it, in which case the handling of responsibilities becomes clearer.</remarks>
    public class FanOutCircuitFactory extends BaseCircuitFactory
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(FanOutCircuitFactory));

        /// <summary>
        /// Creates a test circuit for the test, configered by the test parameters specified.
        /// </summary>
        /// <param name="testProperties"> The test parameters. </param>
        /// <return> A test circuit. </return>
        public Circuit createCircuit(ParsedProperties testProperties)
        {
            log.debug("public Circuit createCircuit(ParsedProperties testProperties): called");

            IList<TestClientDetails> senders = new LinkedList<TestClientDetails>();
            senders.add(getSender());
            IList<TestClientDetails> receivers = getReceivers();
            ConversationFactory conversationFactory = getConversationFactory();

            return DistributedCircuitImpl.createCircuit(testProperties, senders, receivers, conversationFactory);
        }

        /// <summary>
        /// Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
        /// begining the test, gathering the test reports from the participants, and checking for assertion failures against
        /// the test reports.
        /// </summary>
        /// <param name="testCircuit">    The test circuit. </param>
        /// <param name="assertions">     The list of assertions to apply to the test circuit. </param>
        /// <param name="testProperties"> The test case definition. </param>
        ///
        /// @deprecated Scheduled for removal once existing tests converted over to use test circuits.
        public void sequenceTest(Circuit testCircuit, IList<Assertion> assertions, Properties testProperties)
        {
            log.debug("protected Message[] sequenceTest(Object... testProperties = " + testProperties + "): called");

            TestClientDetails sender = getSender();
            IList<TestClientDetails> receivers = getReceivers();
            ConversationFactory conversationFactory = getConversationFactory();

            try
            {
                // Create a conversation on the sender clients private control route.
                Session session = conversationFactory.getSession();
                Destination senderControlTopic = session.createTopic(sender.privateControlKey);
                ConversationFactory.Conversation senderConversation = conversationFactory.startConversation();

                // Assign the sender role to the sending test client.
                Message assignSender = conversationFactory.getSession().createMessage();
                TestUtils.setPropertiesOnMessage(assignSender, testProperties);
                assignSender.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
                assignSender.setStringProperty("ROLE", "SENDER");
                assignSender.setStringProperty("CLIENT_NAME", "Sustained_SENDER");

                senderConversation.send(senderControlTopic, assignSender);

                // Wait for the sender to confirm its role.
                senderConversation.receive();

                // Assign the receivers roles.
                for (TestClientDetails receiver : receivers)
                {
                    assignReceiverRole(receiver, testProperties, true);
                }

                // Start the test on the sender.
                Message start = session.createMessage();
                start.setStringProperty("CONTROL_TYPE", "START");

                senderConversation.send(senderControlTopic, start);

                // Wait for the test sender to return its report.
                Message senderReport = senderConversation.receive();
                TestUtils.pause(500);

                // Ask the receivers for their reports.
                Message statusRequest = session.createMessage();
                statusRequest.setStringProperty("CONTROL_TYPE", "STATUS_REQUEST");

                // Gather the reports from all of the receiving clients.

                // Return all of the test reports, the senders report first.
                // return new Message[] { senderReport };
            }
            catch (JMSException e)
            {
                throw new RuntimeException("Unhandled JMSException.");
            }
        }

        /// <summary>
        /// Assigns the receivers role to the specified test client that is to act as a receivers during the test. This method
        /// does not always wait for the receiving clients to confirm their role assignments. This is because this method
        /// may be called from an 'onMessage' method, when a client is joining the test at a later point in time, and it
        /// is not possible to do a synchronous receive during an 'onMessage' method. There is a flag to indicate whether
        /// or not to wait for role confirmations.
        /// </summary>
        /// <param name="receiver">       The test client to assign the receivers role to. </param>
        /// <param name="testProperties"> The test parameters. </param>
        /// <param name="confirm">        Indicates whether role confirmation should be waited for. </param>
        ///
        /// <exception cref="JMSException"> Any JMSExceptions occurring during the conversation are allowed to fall through. </exception>
        ///
        /// @deprecated Scheduled for removal once existing tests converted over to use test circuits.
        protected void assignReceiverRole(TestClientDetails receiver, Properties testProperties, bool confirm)
            throws JMSException
        {
            log.info("assignReceiverRole(TestClientDetails receivers = " + receiver + ", Map<String, Object> testProperties = "
                     + testProperties + "): called");

            ConversationFactory conversationFactory = getConversationFactory();

            // Create a conversation with the receiving test client.
            Session session = conversationFactory.getSession();
            Destination receiverControlTopic = session.createTopic(receiver.privateControlKey);
            ConversationFactory.Conversation receiverConversation = conversationFactory.startConversation();

            // Assign the receivers role to the receiving client.
            Message assignReceiver = session.createMessage();
            TestUtils.setPropertiesOnMessage(assignReceiver, testProperties);
            assignReceiver.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
            assignReceiver.setStringProperty("ROLE", "RECEIVER");
            assignReceiver.setStringProperty("CLIENT_NAME", receiver.clientName);

            receiverConversation.send(receiverControlTopic, assignReceiver);

            // Wait for the role confirmation to come back.
            if (confirm)
            {
                receiverConversation.receive();
            }
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using Apache.Qpid.Integration.Tests.framework.Assertion;
using Apache.Qpid.Integration.Tests.framework.Circuit;
using Apache.Qpid.Integration.Tests.framework.TestClientDetails;
using Apache.Qpid.Integration.Tests.framework.TestUtils;
using Apache.Qpid.Integration.Tests.framework.distributedcircuit.DistributedCircuitImpl;
using org.apache.qpid.util.ConversationFactory;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.Destination;
using javax.jms.JMSException;
using javax.jms.Message;
using javax.jms.Session;

using System.Collections.Generic.LinkedList;
using System.Collections.Generic.IList;
using java.util.Properties;

namespace Apache.Qpid.Integration.Tests.framework.sequencers
{
    /// <summary>
    /// InteropCircuitFactory is a circuit factory that creates distributed test circuits. Given a set of participating
    /// test client nodes, it assigns one node to the SENDER role and one the RECEIVER role.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Create distributed circuits from pairs of test nodes, for interop style testing.
    /// </table>
    /// </summary>
    ///
    /// <remarks> The partitioning of a set of nodes into sender and receiver roles is actually done by the interop test
    ///       decorator. See the todo comment in FanOutCircuitFactory about merging the factories with the decorators, or
    ///       more carefully dividing up responsibilities between them.</remarks>
    ///
    /// <remarks> The squenceTest code is deprecated, but currently still used by the interop tests. It will be removed once it
    ///       have been fully replaced by the default test procedure.</remarks>
    public class InteropCircuitFactory extends BaseCircuitFactory
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(InteropCircuitFactory));

        /// <summary>
        /// Creates a test circuit for the test, configered by the test parameters specified.
        /// </summary>
        /// <param name="testProperties"> The test parameters. </param>
        /// <return> A test circuit. </return>
        public Circuit createCircuit(ParsedProperties testProperties)
        {
            log.debug("public Circuit createCircuit(ParsedProperties testProperties): called");

            IList<TestClientDetails> senders = new LinkedList<TestClientDetails>();
            senders.add(getSender());
            IList<TestClientDetails> receivers = getReceivers();
            ConversationFactory conversationFactory = getConversationFactory();

            return DistributedCircuitImpl.createCircuit(testProperties, senders, receivers, conversationFactory);
        }

        /// <summary>
        /// Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
        /// begining the test, gathering the test reports from the participants, and checking for assertion failures against
        /// the test reports.
        /// </summary>
        /// <param name="testCircuit">    The test circuit. </param>
        /// <param name="assertions">     The list of assertions to apply to the test circuit. </param>
        /// <param name="testProperties"> The test case definition. </param>
        public void sequenceTest(Circuit testCircuit, IList<Assertion> assertions, Properties testProperties)
        {
            log.debug("protected Message[] sequenceTest(Object... testProperties = " + testProperties + "): called");

            TestClientDetails sender = getSender();
            IList<TestClientDetails> receivers = getReceivers();
            ConversationFactory conversationFactory = getConversationFactory();

            try
            {
                Session session = conversationFactory.getSession();
                Destination senderControlTopic = session.createTopic(sender.privateControlKey);
                Destination receiverControlTopic = session.createTopic(receivers.get(0).privateControlKey);

                ConversationFactory.Conversation senderConversation = conversationFactory.startConversation();
                ConversationFactory.Conversation receiverConversation = conversationFactory.startConversation();

                Message assignSender = conversationFactory.getSession().createMessage();
                TestUtils.setPropertiesOnMessage(assignSender, testProperties);
                assignSender.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
                assignSender.setStringProperty("ROLE", "SENDER");

                senderConversation.send(senderControlTopic, assignSender);

                // Assign the receivers role the receiving client.
                Message assignReceiver = session.createMessage();
                TestUtils.setPropertiesOnMessage(assignReceiver, testProperties);
                assignReceiver.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
                assignReceiver.setStringProperty("ROLE", "RECEIVER");

                receiverConversation.send(receiverControlTopic, assignReceiver);

                // Wait for the senders and receivers to confirm their roles.
                senderConversation.receive();
                receiverConversation.receive();

                // Start the test.
                Message start = session.createMessage();
                start.setStringProperty("CONTROL_TYPE", "START");

                senderConversation.send(senderControlTopic, start);

                // Wait for the test sender to return its report.
                Message senderReport = senderConversation.receive();
                TestUtils.pause(500);

                // Ask the receivers for its report.
                Message statusRequest = session.createMessage();
                statusRequest.setStringProperty("CONTROL_TYPE", "STATUS_REQUEST");

                receiverConversation.send(receiverControlTopic, statusRequest);

                // Wait for the receivers to send its report.
                Message receiverReport = receiverConversation.receive();

                // return new Message[] { senderReport, receiverReport };

                // Apply assertions.
            }
            catch (JMSException e)
            {
                throw new RuntimeException("JMSException not handled.");
            }
        }
    }
}
/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td>
    /// </table>
    /// </summary>
    public class TestCaseVector
    {
        /// <summary> The test case name. </summary>
        private string testCase;

        /// <summary> The test cycle number within the test case. </summary>
        private int testCycleNumber;

        public TestCaseVector(string testCase, int testCycleNumber)
        {
            this.testCase = testCase;
            this.testCycleNumber = testCycleNumber;
        }

        public string getTestCase()
        {
            return testCase;
        }

        public int getTestCycleNumber()
        {
            return testCycleNumber;
        }

        public bool equals(Object o)
        {
            if (this == o)
            {
                return true;
            }

            if ((o == null) || (getClass() != o.getClass()))
            {
                return false;
            }

            TestCaseVector that = (TestCaseVector) o;

            if (testCycleNumber != that.testCycleNumber)
            {
                return false;
            }

            if ((testCase != null) ? (!testCase.equals(that.testCase)) : (that.testCase != null))
            {
                return false;
            }

            return true;
        }

        public int hashCode()
        {
            int result;
            result = ((testCase != null) ? testCase.hashCode() : 0);
            result = (31 * result) + testCycleNumber;

            return result;
        }
    }
}
/*
 *
 * 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.
 *
 */
namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// TestClientDetails is used to encapsulate information about an interop test client. It pairs together the unique
    /// name of the client, and the route on which it listens to its control messages.
    ///
    /// <p><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Record test clients control addresses together with their names.
    /// </table>
    /// </summary>
    public class TestClientDetails
    {
        /// <summary> The test clients name. </summary>
        public string clientName;

        /// <summary> The routing key of the test clients control topic. </summary>
        public string privateControlKey;

        /// <summary>
        /// Two TestClientDetails are considered to be equal, iff they have the same client name.
        /// </summary>
        /// <param name="o"> The object to compare to. </param>
        ///
        /// <return> <tt>If the object to compare to is a TestClientDetails equal to this one, <tt>false</tt> otherwise. </return>
        public bool equals(Object o)
        {
            if (this == o)
            {
                return true;
            }

            if (!(o instanceof TestClientDetails))
            {
                return false;
            }

            final TestClientDetails testClientDetails = (TestClientDetails) o;

            return !((clientName != null) ? (!clientName.equals(testClientDetails.clientName))
                     : (testClientDetails.clientName != null));
        }

        /// <summary>
        /// Computes a hash code compatible with the equals method; based on the client name alone.
        /// </summary>
        /// <return> A hash code for this. </return>
        public int hashCode()
        {
            return ((clientName != null) ? clientName.hashCode() : 0);
        }

        /// <summary>
        /// Outputs the client name and address details. Mostly used for debugging purposes.
        /// </summary>
        /// <return> The client name and address. </return>
        public string ToString()
        {
            return "TestClientDetails: [ clientName = " + clientName + ", privateControlKey = " + privateControlKey + " ]";
        }
    }
}
/*
 *
 * 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.
 *
 */
using log4net;

using static Apache.Qpid.Integration.Tests.framework.MessagingTestConfigProperties.*;

using uk.co.thebadgerset.junit.extensions.util.ParsedProperties;

using javax.jms.*;
using javax.naming.Context;
using javax.naming.InitialContext;
using javax.naming.NamingException;

using System.Collections.Generic.IDictionary;

namespace Apache.Qpid.Integration.Tests.framework
{
    /// <summary>
    /// TestUtils provides static helper methods that are usefull for writing tests against QPid.
    ///
    /// <p/><table id="crc"><caption>CRC Card</caption>
    /// <tr><th> Responsibilities <th> Collaborations
    /// <tr><td> Create connections from test properties. <td> <see cref="MessagingTestConfigProperties"/>
    /// <tr><td> Create test messages.
    /// <tr><td> Inject a short pause in a test.
    /// <tr><td> Serialize properties into a message.
    /// </table>
    /// </summary>
    public class TestUtils
    {
        /// <summary> Used for debugging. </summary>
        private static ILog log = LogManager.GetLogger(typeof(TestUtils));

        /// <summary> Some dummy data to stuff all test messages with. </summary>
        private static final byte[] MESSAGE_DATA_BYTES =
            "Test Message -- Test Message -- Test Message -- Test Message -- Test Message -- Test Message -- Test Message -- "
            .getBytes();

        /// <summary>
        /// Establishes a JMS connection using a set of properties and qpids built in JNDI implementation. This is a simple
        /// convenience method for code that does not anticipate handling connection failures. All exceptions that indicate
        /// that the connection has failed, are wrapped as rutime exceptions, presumably handled by a top level failure
        /// handler.
        ///
        /// <p/>This utility makes use of the following test parameters from <see cref="MessagingTestConfigProperties"/> to control
        /// the connection creation:
        ///
        /// <p/><table>
        /// <tr><td> <see cref="MessagingTestConfigProperties#USERNAME_PROPNAME"/> <td> The username.
        /// <tr><td> <see cref="MessagingTestConfigProperties#PASSWORD_PROPNAME"/> <td> The password.
        /// <tr><td> <see cref="MessagingTestConfigProperties#VIRTUAL_HOST_PROPNAME"/> <td> The virtual host name.
        /// <tr><td> <see cref="MessagingTestConfigProperties#BROKER_PROPNAME"/> <td> The broker URL.
        /// <tr><td> <see cref="MessagingTestConfigProperties#CONNECTION_NAME"/> <td> The broker name in the initial context.
        /// </summary>
        /// <param name="messagingProps"> Connection properties as defined in <see cref="MessagingTestConfigProperties"/>. </param>
        ///
        /// <return> A JMS conneciton. </return>
        public static Connection createConnection(ParsedProperties messagingProps)
        {
            log.debug("public static Connection createConnection(ParsedProperties messagingProps = " + messagingProps
                      + "): called");

            try
            {
                // Extract the configured connection properties from the test configuration.
                string conUsername = messagingProps.getProperty(USERNAME_PROPNAME);
                string conPassword = messagingProps.getProperty(PASSWORD_PROPNAME);
                string virtualHost = messagingProps.getProperty(VIRTUAL_HOST_PROPNAME);
                string brokerUrl = messagingProps.getProperty(BROKER_PROPNAME);

                // Create the broker connection url.
                string connectionstring =
                    "amqp://" + conUsername + ":" + conPassword + "@clientid/" + ((virtualHost != null) ? virtualHost : "")
                    + "?brokerlist='" + brokerUrl + "'";

                // Create properties to create the initial context from, and inject the connection factory configuration
                // for the defined connection name into it.
                messagingProps.setProperty("connectionfactory." + CONNECTION_NAME, connectionString);

                Context ctx = new InitialContext(messagingProps);

                ConnectionFactory cf = (ConnectionFactory) ctx.lookup(CONNECTION_NAME);

                return cf.createConnection();
            }
            catch (NamingException e)
            {
                throw new RuntimeException("Got JNDI NamingException whilst looking up the connection factory.", e);
            }
            catch (JMSException e)
            {
                throw new RuntimeException("Could not establish connection due to JMSException.", e);
            }
        }

        /// <summary>
        /// Creates a test message of the specified size, on the given JMS session.
        /// </summary>
        /// <param name="session"> The JMS session. </param>
        /// <param name="size">    The size of the message in bytes. </param>
        ///
        /// <return> A bytes message, of the specified size, filled with dummy data. </return>
        ///
        /// <exception cref="JMSException"> Any underlying JMSExceptions are allowed to fall through. </exception>
        public static Message createTestMessageOfSize(Session session, int size) throws JMSException
        {
            BytesMessage message = session.createBytesMessage();

            if (size > 0)
            {
                int div = MESSAGE_DATA_BYTES.length / size;
                int mod = MESSAGE_DATA_BYTES.length % size;

                for (int i = 0; i < div; i++)
                {
                    message.writeBytes(MESSAGE_DATA_BYTES);
                }

                if (mod != 0)
                {
                    message.writeBytes(MESSAGE_DATA_BYTES, 0, mod);
                }
            }

            return message;
        }

        /// <summary>
        /// Pauses for the specified length of time. In the event of failing to pause for at least that length of time
        /// due to interuption of the thread, a RutimeException is raised to indicate the failure. The interupted status
        /// of the thread is restores in that case. This method should only be used when it is expected that the pause
        /// will be succesfull, for example in test code that relies on inejecting a pause.
        /// </summary>
        /// <param name="t"> The minimum time to pause for in milliseconds. </param>
        public static void pause(long t)
        {
            try
            {
                Thread.sleep(t);
            }
            catch (InterruptedException e)
            {
                // Restore the interrupted status
                Thread.currentThread().interrupt();

                throw new RuntimeException("Failed to generate the requested pause length.", e);
            }
        }

        /// <summary>
        /// Sets properties of different types on a JMS Message.
        /// </summary>
        /// <param name="message">    The message to set properties on. </param>
        /// <param name="properties"> The property name/value pairs to set. </param>
        ///
        /// <exception cref="javax.jms.JMSException"> All underlying JMSExceptions are allowed to fall through. </exception>
        ///
        /// <remarks> Move this helper method somewhere else. For example, TestUtils.</remarks>
        public static void setPropertiesOnMessage(Message message, Map<Object, Object> properties) throws JMSException
        {
            for (Map.Entry<Object, Object> entry : properties.entrySet())
            {
                string name = entry.getKey().ToString();
                Object value = entry.getValue();

                message.setObjectProperty(name, value);
            }
        }
    }
}