You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ru...@apache.org on 2008/01/17 18:13:23 UTC
svn commit: r612874 [3/5] - in /incubator/qpid/branches/M2.1/dotnet:
Qpid.Buffer.Tests/Properties/ Qpid.Buffer/Properties/
Qpid.Client.Tests/Properties/
Qpid.Client.Transport.Socket.Blocking/Properties/ Qpid.Client/Properties/
Qpid.Codec/Properties/ Qp...
Added: incubator/qpid/branches/M2.1/dotnet/Qpid.Integration.Tests/framework/alljava.csx
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2.1/dotnet/Qpid.Integration.Tests/framework/alljava.csx?rev=612874&view=auto
==============================================================================
--- incubator/qpid/branches/M2.1/dotnet/Qpid.Integration.Tests/framework/alljava.csx (added)
+++ incubator/qpid/branches/M2.1/dotnet/Qpid.Integration.Tests/framework/alljava.csx Thu Jan 17 09:13:11 2008
@@ -0,0 +1,7851 @@
+/*
+ *
+ * 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>
[... 5804 lines stripped ...]