summaryrefslogtreecommitdiff
path: root/RC9/qpid/cpp/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'RC9/qpid/cpp/src/tests')
-rw-r--r--RC9/qpid/cpp/src/tests/.valgrind.supp203
-rw-r--r--RC9/qpid/cpp/src/tests/AccumulatedAckTest.cpp232
-rw-r--r--RC9/qpid/cpp/src/tests/Array.cpp79
-rw-r--r--RC9/qpid/cpp/src/tests/AsyncCompletion.cpp100
-rw-r--r--RC9/qpid/cpp/src/tests/AtomicValue.cpp49
-rw-r--r--RC9/qpid/cpp/src/tests/BasicP2PTest.cpp66
-rw-r--r--RC9/qpid/cpp/src/tests/BasicP2PTest.h46
-rw-r--r--RC9/qpid/cpp/src/tests/BasicPubSubTest.cpp121
-rw-r--r--RC9/qpid/cpp/src/tests/BasicPubSubTest.h51
-rw-r--r--RC9/qpid/cpp/src/tests/Blob.cpp128
-rw-r--r--RC9/qpid/cpp/src/tests/BrokerFixture.h130
-rw-r--r--RC9/qpid/cpp/src/tests/ClientSessionTest.cpp452
-rw-r--r--RC9/qpid/cpp/src/tests/ConnectionOptions.h54
-rw-r--r--RC9/qpid/cpp/src/tests/ConsoleTest.cpp43
-rw-r--r--RC9/qpid/cpp/src/tests/DeliveryRecordTest.cpp62
-rw-r--r--RC9/qpid/cpp/src/tests/DispatcherTest.cpp128
-rw-r--r--RC9/qpid/cpp/src/tests/DtxWorkRecordTest.cpp189
-rw-r--r--RC9/qpid/cpp/src/tests/ExchangeTest.cpp284
-rw-r--r--RC9/qpid/cpp/src/tests/FieldTable.cpp178
-rw-r--r--RC9/qpid/cpp/src/tests/FieldValue.cpp90
-rw-r--r--RC9/qpid/cpp/src/tests/ForkedBroker.h122
-rw-r--r--RC9/qpid/cpp/src/tests/Frame.cpp80
-rw-r--r--RC9/qpid/cpp/src/tests/FramingTest.cpp151
-rw-r--r--RC9/qpid/cpp/src/tests/HeaderTest.cpp110
-rw-r--r--RC9/qpid/cpp/src/tests/HeadersExchangeTest.cpp115
-rw-r--r--RC9/qpid/cpp/src/tests/IncompleteMessageList.cpp128
-rw-r--r--RC9/qpid/cpp/src/tests/InlineAllocator.cpp63
-rw-r--r--RC9/qpid/cpp/src/tests/InlineVector.cpp119
-rw-r--r--RC9/qpid/cpp/src/tests/Makefile.am245
-rw-r--r--RC9/qpid/cpp/src/tests/ManagementTest.cpp85
-rw-r--r--RC9/qpid/cpp/src/tests/MessageBuilderTest.cpp224
-rw-r--r--RC9/qpid/cpp/src/tests/MessageReplayTracker.cpp99
-rw-r--r--RC9/qpid/cpp/src/tests/MessageTest.cpp90
-rw-r--r--RC9/qpid/cpp/src/tests/MessageUtils.h55
-rw-r--r--RC9/qpid/cpp/src/tests/PollerTest.cpp164
-rw-r--r--RC9/qpid/cpp/src/tests/QueueOptionsTest.cpp98
-rw-r--r--RC9/qpid/cpp/src/tests/QueuePolicyTest.cpp274
-rw-r--r--RC9/qpid/cpp/src/tests/QueueRegistryTest.cpp94
-rw-r--r--RC9/qpid/cpp/src/tests/QueueTest.cpp501
-rw-r--r--RC9/qpid/cpp/src/tests/README54
-rw-r--r--RC9/qpid/cpp/src/tests/RangeSet.cpp141
-rw-r--r--RC9/qpid/cpp/src/tests/RefCounted.cpp50
-rw-r--r--RC9/qpid/cpp/src/tests/SequenceNumberTest.cpp205
-rw-r--r--RC9/qpid/cpp/src/tests/SequenceSet.cpp140
-rw-r--r--RC9/qpid/cpp/src/tests/SessionState.cpp300
-rw-r--r--RC9/qpid/cpp/src/tests/Shlib.cpp60
-rw-r--r--RC9/qpid/cpp/src/tests/SimpleTestCaseBase.cpp87
-rw-r--r--RC9/qpid/cpp/src/tests/SimpleTestCaseBase.h89
-rw-r--r--RC9/qpid/cpp/src/tests/SocketProxy.h143
-rw-r--r--RC9/qpid/cpp/src/tests/StringUtils.cpp77
-rw-r--r--RC9/qpid/cpp/src/tests/TestCase.h64
-rw-r--r--RC9/qpid/cpp/src/tests/TestMessageStore.h58
-rw-r--r--RC9/qpid/cpp/src/tests/TestOptions.h79
-rw-r--r--RC9/qpid/cpp/src/tests/TimerTest.cpp120
-rw-r--r--RC9/qpid/cpp/src/tests/TopicExchangeTest.cpp167
-rw-r--r--RC9/qpid/cpp/src/tests/TxBufferTest.cpp176
-rw-r--r--RC9/qpid/cpp/src/tests/TxMocks.h229
-rw-r--r--RC9/qpid/cpp/src/tests/TxPublishTest.cpp94
-rw-r--r--RC9/qpid/cpp/src/tests/Url.cpp67
-rw-r--r--RC9/qpid/cpp/src/tests/Uuid.cpp79
-rw-r--r--RC9/qpid/cpp/src/tests/XmlClientSessionTest.cpp221
-rwxr-xr-xRC9/qpid/cpp/src/tests/acl.py459
-rwxr-xr-xRC9/qpid/cpp/src/tests/ais_check56
-rw-r--r--RC9/qpid/cpp/src/tests/ais_test.cpp23
-rw-r--r--RC9/qpid/cpp/src/tests/allSegmentTypes.h128
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/Map.cpp98
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp49
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/apply.cpp99
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/handlers.cpp125
-rw-r--r--RC9/qpid/cpp/src/tests/amqp_0_10/serialize.cpp429
-rwxr-xr-xRC9/qpid/cpp/src/tests/benchmark95
-rw-r--r--RC9/qpid/cpp/src/tests/client_test.cpp149
-rw-r--r--RC9/qpid/cpp/src/tests/cluster.mk41
-rw-r--r--RC9/qpid/cpp/src/tests/cluster_test.cpp648
-rw-r--r--RC9/qpid/cpp/src/tests/config.null1
-rw-r--r--RC9/qpid/cpp/src/tests/consume.cpp119
-rw-r--r--RC9/qpid/cpp/src/tests/declare_queues.cpp69
-rw-r--r--RC9/qpid/cpp/src/tests/dlclose_noop.c30
-rw-r--r--RC9/qpid/cpp/src/tests/echotest.cpp150
-rw-r--r--RC9/qpid/cpp/src/tests/exception_test.cpp121
-rw-r--r--RC9/qpid/cpp/src/tests/failover_soak.cpp654
-rwxr-xr-xRC9/qpid/cpp/src/tests/fanout_perftest22
-rwxr-xr-xRC9/qpid/cpp/src/tests/federated_topic_test130
-rwxr-xr-xRC9/qpid/cpp/src/tests/federation.py505
-rw-r--r--RC9/qpid/cpp/src/tests/header_test.cpp59
-rwxr-xr-xRC9/qpid/cpp/src/tests/header_test.py86
-rw-r--r--RC9/qpid/cpp/src/tests/interop_runner.cpp251
-rw-r--r--RC9/qpid/cpp/src/tests/latencytest.cpp432
-rw-r--r--RC9/qpid/cpp/src/tests/logging.cpp366
-rwxr-xr-xRC9/qpid/cpp/src/tests/multiq_perftest22
-rwxr-xr-xRC9/qpid/cpp/src/tests/perfdist87
-rw-r--r--RC9/qpid/cpp/src/tests/perftest.cpp701
-rw-r--r--RC9/qpid/cpp/src/tests/policy.acl1
-rw-r--r--RC9/qpid/cpp/src/tests/publish.cpp128
-rwxr-xr-xRC9/qpid/cpp/src/tests/python_tests39
-rwxr-xr-xRC9/qpid/cpp/src/tests/quick_perftest22
-rwxr-xr-xRC9/qpid/cpp/src/tests/quick_topictest30
-rwxr-xr-xRC9/qpid/cpp/src/tests/quick_txtest22
-rw-r--r--RC9/qpid/cpp/src/tests/receiver.cpp129
-rw-r--r--RC9/qpid/cpp/src/tests/replaying_sender.cpp131
-rwxr-xr-xRC9/qpid/cpp/src/tests/restart_cluster38
-rw-r--r--RC9/qpid/cpp/src/tests/resuming_receiver.cpp163
-rwxr-xr-xRC9/qpid/cpp/src/tests/run-unit-tests48
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_acl_tests64
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_failover_soak56
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_federation_tests52
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_header_test37
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_perftest28
-rwxr-xr-xRC9/qpid/cpp/src/tests/run_test78
-rw-r--r--RC9/qpid/cpp/src/tests/sender.cpp100
-rwxr-xr-xRC9/qpid/cpp/src/tests/shared_perftest22
-rw-r--r--RC9/qpid/cpp/src/tests/shlibtest.cpp28
-rw-r--r--RC9/qpid/cpp/src/tests/ssl.mk23
-rwxr-xr-xRC9/qpid/cpp/src/tests/ssl_test71
-rwxr-xr-xRC9/qpid/cpp/src/tests/start_broker24
-rwxr-xr-xRC9/qpid/cpp/src/tests/start_cluster46
-rwxr-xr-xRC9/qpid/cpp/src/tests/start_cluster_hosts70
-rwxr-xr-xRC9/qpid/cpp/src/tests/stop_broker41
-rwxr-xr-xRC9/qpid/cpp/src/tests/stop_cluster33
-rw-r--r--RC9/qpid/cpp/src/tests/test_tools.h94
-rw-r--r--RC9/qpid/cpp/src/tests/topic_listener.cpp202
-rwxr-xr-xRC9/qpid/cpp/src/tests/topic_perftest22
-rw-r--r--RC9/qpid/cpp/src/tests/topic_publisher.cpp224
-rwxr-xr-xRC9/qpid/cpp/src/tests/topictest61
-rw-r--r--RC9/qpid/cpp/src/tests/txjob.cpp95
-rw-r--r--RC9/qpid/cpp/src/tests/txshift.cpp185
-rw-r--r--RC9/qpid/cpp/src/tests/txtest.cpp329
-rw-r--r--RC9/qpid/cpp/src/tests/unit_test.cpp23
-rw-r--r--RC9/qpid/cpp/src/tests/unit_test.h86
-rw-r--r--RC9/qpid/cpp/src/tests/vg_check24
130 files changed, 17275 insertions, 0 deletions
diff --git a/RC9/qpid/cpp/src/tests/.valgrind.supp b/RC9/qpid/cpp/src/tests/.valgrind.supp
new file mode 100644
index 0000000000..7ac34fde5d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/.valgrind.supp
@@ -0,0 +1,203 @@
+{
+ Benign error in libcpg.
+ Memcheck:Param
+ socketcall.sendmsg(msg.msg_iov[i])
+ obj:*/libpthread-2.5.so
+ obj:*/libcpg.so.2.0.0
+}
+
+{
+ Uninitialised value problem in _dl_relocate (F7, F8)
+ Memcheck:Cond
+ fun:_dl_relocate_object
+ fun:*dl_*
+}
+
+{
+ False "possibly leaked" in boost program_options - global std::string var.
+ Memcheck:Leak
+ fun:_Znwj
+ fun:_ZNSs4_Rep9_S_createEjjRKSaIcE
+ obj:/usr/lib/libstdc++.so.6.0.8
+ fun:_ZNSsC1EPKcRKSaIcE
+ obj:/usr/lib/libboost_program_options.so.1.33.1
+}
+
+{
+ boost 103200 -- we think Boost is responsible for these leaks.
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZN5boost15program_options??options_description*
+}
+
+{
+ boost 103200 -- we think Boost is responsible for these leaks.
+ Memcheck:Leak
+ fun:_Znwm
+ fun:_ZN5boost9unit_test9test_case*
+}
+
+{
+ boost 103200 -- we think Boost is responsible for these leaks.
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:_ZN4qpid3sys5Shlib4loadEPKc
+ fun:_Z9testShlibv
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv
+ obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0
+ fun:_ZN5boost17execution_monitor7executeEbi
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:_ZN5boost9unit_test10test_suite6do_runEv
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:main
+}
+
+{
+ boost 103200 -- we think Boost is responsible for these leaks.
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid6broker5Timer5startEv
+ fun:_ZN4qpid6broker5TimerC1Ev
+ fun:_ZN4qpid6broker10DtxManagerC1Ev
+ fun:_ZN4qpid6broker6BrokerC1ERKNS1_7OptionsE
+ fun:_ZN4qpid6broker6Broker6createERKNS1_7OptionsE
+ fun:_ZN15SessionFixtureTI15ProxyConnectionEC2Ev
+ fun:_Z14testQueueQueryv
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv
+ obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0
+ fun:_ZN5boost17execution_monitor7executeEbi
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:_ZN5boost9unit_test10test_suite6do_runEv
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:main
+}
+
+{
+ INVESTIGATE
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid6client9Connector4initEv
+ fun:_ZN4qpid6client14ConnectionImpl4openERKSsiS3_S3_S3_
+}
+
+{
+ INVESTIGATE
+ Memcheck:Param
+ write(buf)
+ obj:/lib64/tls/libc-2.3.4.so
+ fun:_ZNK4qpid3sys6Socket5writeEPKvm
+ fun:_ZN4qpid3sys8AsynchIO9writeableERNS0_14DispatchHandleE
+}
+
+{
+ "Conditional jump or move depends on uninitialised value(s)" from Xerces parser
+ Memcheck:Cond
+ fun:_ZN11xercesc_2_717XMLUTF8Transcoder13transcodeFromEPKhjPtjRjPh
+ fun:_ZN11xercesc_2_79XMLReader14xcodeMoreCharsEPtPhj
+ fun:_ZN11xercesc_2_79XMLReader17refreshCharBufferEv
+}
+
+{
+ boost 103200 -- mgoulish -- fix this, sometime
+ Memcheck:Leak
+ fun:*
+ fun:*
+ obj:*
+ fun:*
+ fun:_ZN4qpid34options_description_less_easy_initclEPKcPKN5boost15program_options14value_semanticES2_
+}
+
+{
+ boost 103200 -- mgoulish -- fix this, sometime
+ Memcheck:Leak
+ fun:*
+ fun:*
+ fun:*
+ fun:_ZN4qpid34options_description_less_easy_initclEPKcPKN5boost15program_options14value_semanticES2_
+}
+
+{
+ INVESTIGATE
+ Memcheck:Param
+ socketcall.sendto(msg)
+ fun:send
+ fun:get_mapping
+ fun:__nscd_get_map_ref
+ fun:nscd_gethst_r
+ fun:__nscd_gethostbyname_r
+ fun:gethostbyname_r@@GLIBC_2.2.5
+ fun:gethostbyname
+ fun:_ZNK4qpid3sys6Socket7connectERKSsi
+}
+
+{
+ INVESTIGATE
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid6broker5Timer5startEv
+ fun:_ZN4qpid6broker5TimerC1Ev
+ fun:_ZN4qpid6broker10DtxManagerC1Ev
+ fun:_ZN4qpid6broker6BrokerC1ERKNS1_7OptionsE
+ fun:_ZN4qpid6broker6Broker6createERKNS1_7OptionsE
+ fun:_ZN20ClientSessionFixtureC1Ev
+ fun:_Z14testQueueQueryv
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv
+ obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0
+ fun:_ZN5boost17execution_monitor7executeEbi
+ fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:_ZN5boost9unit_test10test_suite6do_runEv
+ fun:_ZN5boost9unit_test9test_case3runEv
+ fun:main
+}
+
+{
+ INVESTIGATE
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:pthread_create@@GLIBC_2.2.5
+ fun:_ZN4qpid6client9Connector4initEv
+}
+
+{
+ MICK -- FIX
+ Memcheck:Leak
+ fun:_Znam
+ fun:_ZN4qpid7Options5parseEiPPcRKSsb
+}
+
+{
+ MICK -- FIX
+ Memcheck:Leak
+ fun:malloc
+ fun:strdup
+ fun:_ZN4qpid7Options5parseEiPPcRKSsb
+}
+
+{
+ CPG error - seems benign.
+ Memcheck:Param
+ socketcall.sendmsg(msg.msg_iov[i])
+ obj:*
+ obj:*/libcpg.so.2.0.0
+}
+
+{
+ Known leak in boost.thread 1.33.1. Wildcards for 64/32 bit diffs.
+ Memcheck:Leak
+ fun:*
+ obj:/usr/*/libboost_thread.so.1.33.1
+ fun:_ZN5boost6detail3tss3setEPv
+}
+
diff --git a/RC9/qpid/cpp/src/tests/AccumulatedAckTest.cpp b/RC9/qpid/cpp/src/tests/AccumulatedAckTest.cpp
new file mode 100644
index 0000000000..028ce71907
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/AccumulatedAckTest.cpp
@@ -0,0 +1,232 @@
+
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/framing/AccumulatedAck.h"
+#include "unit_test.h"
+#include <iostream>
+#include <list>
+
+using std::list;
+using namespace qpid::framing;
+
+
+bool covers(const AccumulatedAck& ack, int i)
+{
+ return ack.covers(SequenceNumber(i));
+}
+
+void update(AccumulatedAck& ack, int start, int end)
+{
+ ack.update(SequenceNumber(start), SequenceNumber(end));
+}
+
+QPID_AUTO_TEST_SUITE(AccumulatedAckTestSuite)
+
+QPID_AUTO_TEST_CASE(testGeneral)
+{
+ AccumulatedAck ack(0);
+ ack.clear();
+ update(ack, 3,3);
+ update(ack, 7,7);
+ update(ack, 9,9);
+ update(ack, 1,2);
+ update(ack, 4,5);
+ update(ack, 6,6);
+
+ for(int i = 1; i <= 7; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(covers(ack, 9));
+
+ BOOST_CHECK(!covers(ack, 8));
+ BOOST_CHECK(!covers(ack, 10));
+
+ ack.consolidate();
+
+ for(int i = 1; i <= 7; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(covers(ack, 9));
+
+ BOOST_CHECK(!covers(ack, 8));
+ BOOST_CHECK(!covers(ack, 10));
+}
+
+QPID_AUTO_TEST_CASE(testCovers)
+{
+ AccumulatedAck ack(5);
+ update(ack, 7, 7);
+ update(ack, 9, 9);
+
+ BOOST_CHECK(covers(ack, 1));
+ BOOST_CHECK(covers(ack, 2));
+ BOOST_CHECK(covers(ack, 3));
+ BOOST_CHECK(covers(ack, 4));
+ BOOST_CHECK(covers(ack, 5));
+ BOOST_CHECK(covers(ack, 7));
+ BOOST_CHECK(covers(ack, 9));
+
+ BOOST_CHECK(!covers(ack, 6));
+ BOOST_CHECK(!covers(ack, 8));
+ BOOST_CHECK(!covers(ack, 10));
+}
+
+QPID_AUTO_TEST_CASE(testUpdateFromCompletionData)
+{
+ AccumulatedAck ack(0);
+ SequenceNumber mark(2);
+ SequenceNumberSet ranges;
+ ranges.addRange(SequenceNumber(5), SequenceNumber(8));
+ ranges.addRange(SequenceNumber(10), SequenceNumber(15));
+ ranges.addRange(SequenceNumber(9), SequenceNumber(9));
+ ranges.addRange(SequenceNumber(3), SequenceNumber(4));
+
+ ack.update(mark, ranges);
+
+ for(int i = 0; i <= 15; i++) {
+ BOOST_CHECK(covers(ack, i));
+ }
+ BOOST_CHECK(!covers(ack, 16));
+ BOOST_CHECK_EQUAL((uint32_t) 15, ack.mark.getValue());
+}
+
+QPID_AUTO_TEST_CASE(testCase1)
+{
+ AccumulatedAck ack(3);
+ update(ack, 1,2);
+ for(int i = 1; i <= 3; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(!covers(ack, 4));
+}
+
+QPID_AUTO_TEST_CASE(testCase2)
+{
+ AccumulatedAck ack(3);
+ update(ack, 3,6);
+ for(int i = 1; i <= 6; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(!covers(ack, 7));
+}
+
+QPID_AUTO_TEST_CASE(testCase3)
+{
+ AccumulatedAck ack(3);
+ update(ack, 4,6);
+ for(int i = 1; i <= 6; i++) {
+ BOOST_CHECK(covers(ack, i));
+ }
+ BOOST_CHECK(!covers(ack, 7));
+}
+
+QPID_AUTO_TEST_CASE(testCase4)
+{
+ AccumulatedAck ack(3);
+ update(ack, 5,6);
+ for(int i = 1; i <= 6; i++) {
+ if (i == 4) BOOST_CHECK(!covers(ack, i));
+ else BOOST_CHECK(covers(ack, i));
+ }
+ BOOST_CHECK(!covers(ack, 7));
+}
+
+QPID_AUTO_TEST_CASE(testConsolidation1)
+{
+ AccumulatedAck ack(3);
+ update(ack, 7,7);
+ BOOST_CHECK_EQUAL((uint32_t) 3, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 8,9);
+ BOOST_CHECK_EQUAL((uint32_t) 3, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 1,2);
+ BOOST_CHECK_EQUAL((uint32_t) 3, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 4,5);
+ BOOST_CHECK_EQUAL((uint32_t) 5, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 6,6);
+ BOOST_CHECK_EQUAL((uint32_t) 9, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 0, ack.ranges.size());
+
+ for(int i = 1; i <= 9; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(!covers(ack, 10));
+}
+
+QPID_AUTO_TEST_CASE(testConsolidation2)
+{
+ AccumulatedAck ack(0);
+ update(ack, 10,12);
+ BOOST_CHECK_EQUAL((uint32_t) 0, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+
+ update(ack, 7,9);
+ BOOST_CHECK_EQUAL((uint32_t) 0, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+ BOOST_CHECK_EQUAL((uint32_t) 7, ack.ranges.front().start.getValue());
+ BOOST_CHECK_EQUAL((uint32_t) 12, ack.ranges.front().end.getValue());
+
+ update(ack, 5,7);
+ BOOST_CHECK_EQUAL((uint32_t) 0, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+ BOOST_CHECK_EQUAL((uint32_t) 5, ack.ranges.front().start.getValue());
+ BOOST_CHECK_EQUAL((uint32_t) 12, ack.ranges.front().end.getValue());
+
+ update(ack, 3,4);
+ BOOST_CHECK_EQUAL((uint32_t) 0, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 1, ack.ranges.size());
+ BOOST_CHECK_EQUAL((uint32_t) 3, ack.ranges.front().start.getValue());
+ BOOST_CHECK_EQUAL((uint32_t) 12, ack.ranges.front().end.getValue());
+
+ update(ack, 1,2);
+ BOOST_CHECK_EQUAL((uint32_t) 12, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 0, ack.ranges.size());
+
+ for(int i = 1; i <= 12; i++) BOOST_CHECK(covers(ack, i));
+ BOOST_CHECK(!covers(ack, 13));
+}
+
+QPID_AUTO_TEST_CASE(testConsolidation3)
+{
+ AccumulatedAck ack(0);
+ update(ack, 10,12);
+ update(ack, 6,7);
+ update(ack, 3,4);
+ update(ack, 1,15);
+ BOOST_CHECK_EQUAL((uint32_t) 15, ack.mark.getValue());
+ BOOST_CHECK_EQUAL((size_t) 0, ack.ranges.size());
+}
+
+QPID_AUTO_TEST_CASE(testConsolidation4)
+{
+ AccumulatedAck ack(0);
+ ack.update(SequenceNumber(0), SequenceNumber(2));
+ ack.update(SequenceNumber(5), SequenceNumber(8));
+ ack.update(SequenceNumber(10), SequenceNumber(15));
+ ack.update(SequenceNumber(9), SequenceNumber(9));
+ ack.update(SequenceNumber(3), SequenceNumber(4));
+
+ for(int i = 0; i <= 15; i++) {
+ BOOST_CHECK(covers(ack, i));
+ }
+ BOOST_CHECK(!covers(ack, 16));
+ BOOST_CHECK_EQUAL((uint32_t) 15, ack.mark.getValue());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/Array.cpp b/RC9/qpid/cpp/src/tests/Array.cpp
new file mode 100644
index 0000000000..c779cbe901
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Array.cpp
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include <iostream>
+#include <sstream>
+#include "qpid/framing/Array.h"
+#include "qpid/framing/FieldValue.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(ArrayTestSuite)
+
+using namespace qpid::framing;
+
+void populate(std::vector<std::string>& data, int count = 10)
+{
+ for (int i = 0; i < count; i++) {
+ std::stringstream out;
+ out << "item-" << i;
+ data.push_back(out.str());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testEncodeDecode)
+{
+ std::vector<std::string> data;
+ populate(data);
+
+ Array a(data);
+
+ char buff[200];
+ Buffer wbuffer(buff, 200);
+ a.encode(wbuffer);
+
+ Array b;
+ Buffer rbuffer(buff, 200);
+ b.decode(rbuffer);
+ BOOST_CHECK_EQUAL(a, b);
+
+ std::vector<std::string> data2;
+ b.collect(data2);
+ //BOOST_CHECK_EQUAL(data, data2);
+ BOOST_CHECK(data == data2);
+}
+
+QPID_AUTO_TEST_CASE(testArrayAssignment)
+{
+ std::vector<std::string> data;
+ populate(data);
+ Array b;
+ {
+ Array a(data);
+ b = a;
+ BOOST_CHECK_EQUAL(a, b);
+ }
+ std::vector<std::string> data2;
+ b.collect(data2);
+ //BOOST_CHECK_EQUAL(data, data2);
+ BOOST_CHECK(data == data2);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/AsyncCompletion.cpp b/RC9/qpid/cpp/src/tests/AsyncCompletion.cpp
new file mode 100644
index 0000000000..e33b2dc35d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/AsyncCompletion.cpp
@@ -0,0 +1,100 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/sys/BlockingQueue.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/sys/Time.h"
+
+using namespace std;
+using namespace qpid;
+using namespace client;
+using namespace framing;
+
+namespace qpid { namespace broker {
+class TransactionContext;
+class PersistableQueue;
+}}
+
+using broker::PersistableMessage;
+using broker::NullMessageStore;
+using broker::TransactionContext;
+using broker::PersistableQueue;
+using sys::TIME_SEC;
+using boost::intrusive_ptr;
+
+/** @file Unit tests for async completion.
+ * Using a dummy store, verify that the broker indicates async completion of
+ * message enqueues at the correct time.
+ */
+
+class AsyncCompletionMessageStore : public NullMessageStore {
+ public:
+ sys::BlockingQueue<boost::intrusive_ptr<PersistableMessage> > enqueued;
+
+ AsyncCompletionMessageStore() : NullMessageStore() {}
+ ~AsyncCompletionMessageStore(){}
+
+ void enqueue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& )
+ {
+ enqueued.push(msg);
+ }
+};
+
+QPID_AUTO_TEST_SUITE(AsyncCompletionTestSuite)
+
+QPID_AUTO_TEST_CASE(testWaitTillComplete) {
+ AsyncCompletionMessageStore* store = new AsyncCompletionMessageStore;
+ SessionFixture fix;
+ fix.broker->setStore(store); // Broker will delete store.
+ AsyncSession s = fix.session;
+
+ static const int count = 3;
+
+ s.queueDeclare("q", arg::durable=true);
+ Completion transfers[count];
+ for (int i = 0; i < count; ++i) {
+ Message msg(boost::lexical_cast<string>(i), "q");
+ msg.getDeliveryProperties().setDeliveryMode(PERSISTENT);
+ transfers[i] = s.messageTransfer(arg::content=msg);
+ }
+
+ // Get hold of the broker-side messages.
+ typedef vector<intrusive_ptr<PersistableMessage> > BrokerMessages;
+ BrokerMessages enqueued;
+ for (int j = 0; j < count; ++j)
+ enqueued.push_back(store->enqueued.pop(TIME_SEC));
+
+ // Send a sync, make sure it does not complete till all messages are complete.
+ // In reverse order for fun.
+ Completion sync = s.executionSync(arg::sync=true);
+ for (int k = count-1; k >= 0; --k) {
+ BOOST_CHECK(!transfers[k].isComplete()); // Should not be complete yet.
+ BOOST_CHECK(!sync.isComplete()); // Should not be complete yet.
+ enqueued[k]->enqueueComplete();
+ }
+ sync.wait(); // Should complete now, all messages are completed.
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/AtomicValue.cpp b/RC9/qpid/cpp/src/tests/AtomicValue.cpp
new file mode 100644
index 0000000000..05083ad177
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/AtomicValue.cpp
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "qpid/sys/AtomicValue.h"
+
+QPID_AUTO_TEST_SUITE(AtomicValueTestSuite)
+
+QPID_AUTO_TEST_CASE(test) {
+ qpid::sys::AtomicValue<int> x(0);
+ BOOST_CHECK_EQUAL(++x, 1);
+ BOOST_CHECK_EQUAL(--x,0);
+ BOOST_CHECK_EQUAL(x+=5,5);
+ BOOST_CHECK_EQUAL(x-=10,-5);
+ BOOST_CHECK_EQUAL(x.fetchAndAdd(7), -5);
+ BOOST_CHECK_EQUAL(x.get(),2);
+ BOOST_CHECK_EQUAL(x.fetchAndSub(3), 2);
+ BOOST_CHECK_EQUAL(x.get(),-1);
+
+ BOOST_CHECK_EQUAL(x.valueCompareAndSwap(-1,10), -1);
+ BOOST_CHECK_EQUAL(x.get(), 10);
+ BOOST_CHECK_EQUAL(x.valueCompareAndSwap(5, 6), 10);
+ BOOST_CHECK_EQUAL(x.get(), 10);
+
+ BOOST_CHECK(!x.boolCompareAndSwap(5, 6));
+ BOOST_CHECK_EQUAL(x.get(), 10);
+ BOOST_CHECK(x.boolCompareAndSwap(10, 6));
+ BOOST_CHECK_EQUAL(x.get(), 6);
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/BasicP2PTest.cpp b/RC9/qpid/cpp/src/tests/BasicP2PTest.cpp
new file mode 100644
index 0000000000..f4a4cce7f2
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BasicP2PTest.cpp
@@ -0,0 +1,66 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "BasicP2PTest.h"
+
+using namespace qpid;
+using namespace qpid::client;
+
+class BasicP2PTest::Receiver : public Worker, public MessageListener
+{
+ const std::string queue;
+ std::string tag;
+public:
+ Receiver(ConnectionOptions& options, const std::string& _queue, const int _messages)
+ : Worker(options, _messages), queue(_queue){}
+ void init()
+ {
+ Queue q(queue, true);
+ channel.declareQueue(q);
+ framing::FieldTable args;
+ channel.bind(Exchange::STANDARD_DIRECT_EXCHANGE, q, queue, args);
+ channel.consume(q, tag, this);
+ channel.start();
+ }
+
+ void start()
+ {
+ }
+
+ void received(Message&)
+ {
+ count++;
+ }
+};
+
+void BasicP2PTest::assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options)
+{
+ std::string queue = params.getString("P2P_QUEUE_AND_KEY_NAME");
+ int messages = params.getInt("P2P_NUM_MESSAGES");
+ if (role == "SENDER") {
+ worker = std::auto_ptr<Worker>(new Sender(options, Exchange::STANDARD_DIRECT_EXCHANGE, queue, messages));
+ } else if(role == "RECEIVER"){
+ worker = std::auto_ptr<Worker>(new Receiver(options, queue, messages));
+ } else {
+ throw Exception("unrecognised role");
+ }
+ worker->init();
+}
diff --git a/RC9/qpid/cpp/src/tests/BasicP2PTest.h b/RC9/qpid/cpp/src/tests/BasicP2PTest.h
new file mode 100644
index 0000000000..b2611f0301
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BasicP2PTest.h
@@ -0,0 +1,46 @@
+#ifndef _BasicP2PTest_
+#define _BasicP2PTest_
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <memory>
+#include <sstream>
+
+#include "qpid/Exception.h"
+#include "qpid/client/Channel.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/MessageListener.h"
+#include "SimpleTestCaseBase.h"
+
+
+namespace qpid {
+
+class BasicP2PTest : public SimpleTestCaseBase
+{
+ class Receiver;
+public:
+ void assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options);
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/BasicPubSubTest.cpp b/RC9/qpid/cpp/src/tests/BasicPubSubTest.cpp
new file mode 100644
index 0000000000..1e9ff364f1
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BasicPubSubTest.cpp
@@ -0,0 +1,121 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "BasicPubSubTest.h"
+
+using namespace qpid;
+
+class BasicPubSubTest::Receiver : public Worker, public MessageListener
+{
+ const Exchange& exchange;
+ const std::string queue;
+ const std::string key;
+ std::string tag;
+public:
+ Receiver(ConnectionOptions& options, const Exchange& _exchange, const std::string& _queue, const std::string& _key, const int _messages)
+ : Worker(options, _messages), exchange(_exchange), queue(_queue), key(_key){}
+
+ void init()
+ {
+ Queue q(queue, true);
+ channel.declareQueue(q);
+ framing::FieldTable args;
+ channel.bind(exchange, q, key, args);
+ channel.consume(q, tag, this);
+ channel.start();
+ }
+
+ void start(){
+ }
+
+ void received(Message&)
+ {
+ count++;
+ }
+};
+
+class BasicPubSubTest::MultiReceiver : public Worker, public MessageListener
+{
+ typedef boost::ptr_vector<Receiver> ReceiverList;
+ ReceiverList receivers;
+
+public:
+ MultiReceiver(ConnectionOptions& options, const Exchange& exchange, const std::string& key, const int _messages, int receiverCount)
+ : Worker(options, _messages)
+ {
+ for (int i = 0; i != receiverCount; i++) {
+ std::string queue = (boost::format("%1%_%2%") % options.clientid % i).str();
+ receivers.push_back(new Receiver(options, exchange, queue, key, _messages));
+ }
+ }
+
+ void init()
+ {
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ receivers[i].init();
+ }
+ }
+
+ void start()
+ {
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ receivers[i].start();
+ }
+ }
+
+ void received(Message& msg)
+ {
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ receivers[i].received(msg);
+ }
+ }
+
+ virtual int getCount()
+ {
+ count = 0;
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ count += receivers[i].getCount();
+ }
+ return count;
+ }
+ virtual void stop()
+ {
+ for (ReceiverList::size_type i = 0; i != receivers.size(); i++) {
+ receivers[i].stop();
+ }
+ }
+};
+
+void BasicPubSubTest::assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options)
+{
+ std::string key = params.getString("PUBSUB_KEY");
+ int messages = params.getInt("PUBSUB_NUM_MESSAGES");
+ int receivers = params.getInt("PUBSUB_NUM_RECEIVERS");
+ if (role == "SENDER") {
+ worker = std::auto_ptr<Worker>(new Sender(options, Exchange::STANDARD_TOPIC_EXCHANGE, key, messages));
+ } else if(role == "RECEIVER"){
+ worker = std::auto_ptr<Worker>(new MultiReceiver(options, Exchange::STANDARD_TOPIC_EXCHANGE, key, messages, receivers));
+ } else {
+ throw Exception("unrecognised role");
+ }
+ worker->init();
+}
+
diff --git a/RC9/qpid/cpp/src/tests/BasicPubSubTest.h b/RC9/qpid/cpp/src/tests/BasicPubSubTest.h
new file mode 100644
index 0000000000..242d2847d7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BasicPubSubTest.h
@@ -0,0 +1,51 @@
+#ifndef _BasicPubSubTest_
+#define _BasicPubSubTest_
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <memory>
+#include <sstream>
+
+#include "qpid/Exception.h"
+#include "qpid/client/Channel.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/MessageListener.h"
+#include "SimpleTestCaseBase.h"
+#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/format.hpp>
+
+
+namespace qpid {
+
+using namespace qpid::client;
+
+class BasicPubSubTest : public SimpleTestCaseBase
+{
+ class Receiver;
+ class MultiReceiver;
+public:
+ void assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options);
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/Blob.cpp b/RC9/qpid/cpp/src/tests/Blob.cpp
new file mode 100644
index 0000000000..c40e43b96e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Blob.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+#include "qpid/framing/Blob.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(BlobTestSuite)
+
+using namespace std;
+using namespace qpid::framing;
+
+struct Base {
+ int id;
+ int magic;
+
+ Base(int n) : id(n), magic(42) {}
+ Base(const Base& c) : id(c.id), magic(42) {}
+ ~Base() { BOOST_CHECK_EQUAL(42, magic); } // Detect random data.
+};
+
+template <class T> struct Count : public Base {
+ static int instances;
+ bool destroyed;
+
+ Count(int n) : Base(n), destroyed(false) { ++instances; }
+ Count(const Count& c) : Base(c), destroyed(false) { ++instances; }
+ ~Count() {
+ BOOST_CHECK(!destroyed); // Detect double-destructor
+ destroyed=true;
+ BOOST_CHECK(--instances >= 0);
+ }
+};
+
+template <class T> int Count<T>::instances = 0;
+
+struct Foo : public Count<Foo> { Foo(int n) : Count<Foo>(n) {}; };
+struct Bar : public Count<Bar> { Bar(int n) : Count<Bar>(n) {}; };
+
+typedef Blob<sizeof(Foo), Base> TestBlob ;
+
+QPID_AUTO_TEST_CASE(testBlobCtor) {
+ {
+ TestBlob empty;
+ BOOST_CHECK(empty.empty());
+ BOOST_CHECK(empty.get() == 0);
+
+ TestBlob empty2(empty);
+ BOOST_CHECK(empty2.empty());
+
+ TestBlob foo(in_place<Foo>(1));
+ BOOST_CHECK(!foo.empty());
+ BOOST_CHECK_EQUAL(1, foo.get()->id);
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+
+ TestBlob foo2(foo);
+ BOOST_CHECK(!foo2.empty());
+ BOOST_CHECK_EQUAL(1, foo2.get()->id);
+ BOOST_CHECK_EQUAL(2, Foo::instances);
+ }
+
+ BOOST_CHECK_EQUAL(0, Foo::instances);
+ BOOST_CHECK_EQUAL(0, Bar::instances);
+}
+
+
+QPID_AUTO_TEST_CASE(testAssign) {
+ {
+ TestBlob b;
+ b = Foo(2);
+ BOOST_CHECK_EQUAL(2, b.get()->id);
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+
+ TestBlob b2(b);
+ BOOST_CHECK_EQUAL(2, b.get()->id);
+ BOOST_CHECK_EQUAL(2, Foo::instances);
+
+ b2 = Bar(3);
+ BOOST_CHECK_EQUAL(3, b2.get()->id);
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+ BOOST_CHECK_EQUAL(1, Bar::instances);
+
+ b2 = in_place<Foo>(4);
+ BOOST_CHECK_EQUAL(4, b2.get()->id);
+ BOOST_CHECK_EQUAL(2, Foo::instances);
+ BOOST_CHECK_EQUAL(0, Bar::instances);
+
+ b2.clear();
+ BOOST_CHECK(b2.empty());
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+ }
+ BOOST_CHECK_EQUAL(0, Foo::instances);
+ BOOST_CHECK_EQUAL(0, Bar::instances);
+}
+
+
+QPID_AUTO_TEST_CASE(testClear) {
+ TestBlob b(in_place<Foo>(5));
+ TestBlob c(b);
+ BOOST_CHECK(!c.empty());
+ BOOST_CHECK(!b.empty());
+ BOOST_CHECK_EQUAL(2, Foo::instances);
+
+ c.clear();
+ BOOST_CHECK(c.empty());
+ BOOST_CHECK_EQUAL(1, Foo::instances);
+
+ b.clear();
+ BOOST_CHECK(b.empty());
+ BOOST_CHECK_EQUAL(0, Foo::instances);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/BrokerFixture.h b/RC9/qpid/cpp/src/tests/BrokerFixture.h
new file mode 100644
index 0000000000..2a4faa2fd4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/BrokerFixture.h
@@ -0,0 +1,130 @@
+#ifndef TESTS_BROKERFIXTURE_H
+#define TESTS_BROKERFIXTURE_H
+
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "SocketProxy.h"
+
+#include "qpid/broker/Broker.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionImpl.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Options.h"
+#include "qpid/sys/Thread.h"
+#include <boost/noncopyable.hpp>
+
+/**
+ * A fixture with an in-process broker.
+ */
+struct BrokerFixture : private boost::noncopyable {
+ typedef qpid::broker::Broker Broker;
+ typedef boost::intrusive_ptr<Broker> BrokerPtr;
+
+ BrokerPtr broker;
+ qpid::sys::Thread brokerThread;
+
+ BrokerFixture(Broker::Options opts=Broker::Options()) {
+ // Keep the tests quiet unless logging env. vars have been set by user.
+ if (!::getenv("QPID_LOG_ENABLE") && !::getenv("QPID_TRACE")) {
+ qpid::log::Options logOpts;
+ logOpts.selectors.clear();
+ logOpts.selectors.push_back("error+");
+ qpid::log::Logger::instance().configure(logOpts);
+ }
+ opts.port=0;
+ // Management doesn't play well with multiple in-process brokers.
+ opts.enableMgmt=false;
+ opts.workerThreads=1;
+ opts.dataDir="";
+ opts.auth=false;
+ broker = Broker::create(opts);
+ // TODO aconway 2007-12-05: At one point BrokerFixture
+ // tests could hang in Connection ctor if the following
+ // line is removed. This may not be an issue anymore.
+ broker->getPort(qpid::broker::Broker::TCP_TRANSPORT);
+ brokerThread = qpid::sys::Thread(*broker);
+ };
+
+ ~BrokerFixture() {
+ broker->shutdown();
+ brokerThread.join();
+ }
+
+ /** Open a connection to the broker. */
+ void open(qpid::client::Connection& c) {
+ c.open("localhost", broker->getPort(qpid::broker::Broker::TCP_TRANSPORT));
+ }
+
+ uint16_t getPort() { return broker->getPort(qpid::broker::Broker::TCP_TRANSPORT); }
+};
+
+/** Connection that opens in its constructor */
+struct LocalConnection : public qpid::client::Connection {
+ LocalConnection(uint16_t port) { open("localhost", port); }
+};
+
+/** A local client connection via a socket proxy. */
+struct ProxyConnection : public qpid::client::Connection {
+ SocketProxy proxy;
+ ProxyConnection(int brokerPort) : proxy(brokerPort) {
+ open("localhost", proxy.getPort());
+ }
+ ~ProxyConnection() { close(); }
+};
+
+/** Convenience class to create and open a connection and session
+ * and some related useful objects.
+ */
+template <class ConnectionType=LocalConnection, class SessionType=qpid::client::Session>
+struct ClientT {
+ ConnectionType connection;
+ SessionType session;
+ qpid::client::SubscriptionManager subs;
+ qpid::client::LocalQueue lq;
+ ClientT(uint16_t port, const std::string& name=std::string())
+ : connection(port), session(connection.newSession(name)), subs(session) {}
+
+ ~ClientT() { connection.close(); }
+};
+
+typedef ClientT<> Client;
+
+/**
+ * A BrokerFixture and ready-connected BrokerFixture::Client all in one.
+ */
+template <class ConnectionType, class SessionType=qpid::client::Session>
+struct SessionFixtureT : BrokerFixture, ClientT<ConnectionType,SessionType> {
+
+ SessionFixtureT(Broker::Options opts=Broker::Options()) :
+ BrokerFixture(opts),
+ ClientT<ConnectionType,SessionType>(broker->getPort(qpid::broker::Broker::TCP_TRANSPORT))
+ {}
+
+};
+
+typedef SessionFixtureT<LocalConnection> SessionFixture;
+typedef SessionFixtureT<ProxyConnection> ProxySessionFixture;
+
+
+#endif /*!TESTS_BROKERFIXTURE_H*/
diff --git a/RC9/qpid/cpp/src/tests/ClientSessionTest.cpp b/RC9/qpid/cpp/src/tests/ClientSessionTest.cpp
new file mode 100644
index 0000000000..5d047dcd0e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ClientSessionTest.cpp
@@ -0,0 +1,452 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/client/Session.h"
+#include "qpid/framing/TransferContent.h"
+#include "qpid/framing/reply_exceptions.h"
+
+#include <boost/optional.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include <vector>
+
+QPID_AUTO_TEST_SUITE(ClientSessionTest)
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid;
+using qpid::sys::Monitor;
+using qpid::sys::Thread;
+using qpid::sys::TIME_SEC;
+using qpid::broker::Broker;
+using std::string;
+using std::cout;
+using std::endl;
+
+
+struct DummyListener : public sys::Runnable, public MessageListener {
+ std::vector<Message> messages;
+ string name;
+ uint expected;
+ SubscriptionManager submgr;
+
+ DummyListener(Session& session, const string& n, uint ex) :
+ name(n), expected(ex), submgr(session) {}
+
+ void run()
+ {
+ submgr.subscribe(*this, name);
+ submgr.run();
+ }
+
+ void received(Message& msg)
+ {
+ messages.push_back(msg);
+ if (--expected == 0) {
+ submgr.stop();
+ }
+ }
+};
+
+struct SimpleListener : public MessageListener
+{
+ Monitor lock;
+ std::vector<Message> messages;
+
+ void received(Message& msg)
+ {
+ Monitor::ScopedLock l(lock);
+ messages.push_back(msg);
+ lock.notifyAll();
+ }
+
+ void waitFor(const uint n)
+ {
+ Monitor::ScopedLock l(lock);
+ while (messages.size() < n) {
+ lock.wait();
+ }
+ }
+};
+
+struct ClientSessionFixture : public ProxySessionFixture
+{
+ ClientSessionFixture(Broker::Options opts = Broker::Options()) : ProxySessionFixture(opts) {
+ session.queueDeclare(arg::queue="my-queue");
+ }
+};
+
+QPID_AUTO_TEST_CASE(testQueueQuery) {
+ ClientSessionFixture fix;
+ fix.session = fix.connection.newSession();
+ fix.session.queueDeclare(arg::queue="q", arg::alternateExchange="amq.fanout",
+ arg::exclusive=true, arg::autoDelete=true);
+ QueueQueryResult result = fix.session.queueQuery("q");
+ BOOST_CHECK_EQUAL(false, result.getDurable());
+ BOOST_CHECK_EQUAL(true, result.getExclusive());
+ BOOST_CHECK_EQUAL("amq.fanout", result.getAlternateExchange());
+}
+
+QPID_AUTO_TEST_CASE(testDispatcher)
+{
+ ClientSessionFixture fix;
+ fix.session =fix.connection.newSession();
+ size_t count = 100;
+ for (size_t i = 0; i < count; ++i)
+ fix.session.messageTransfer(arg::content=TransferContent(boost::lexical_cast<string>(i), "my-queue"));
+ DummyListener listener(fix.session, "my-queue", count);
+ listener.run();
+ BOOST_CHECK_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(boost::lexical_cast<string>(i), listener.messages[i].getData());
+}
+
+QPID_AUTO_TEST_CASE(testDispatcherThread)
+{
+ ClientSessionFixture fix;
+ fix.session =fix.connection.newSession();
+ size_t count = 10;
+ DummyListener listener(fix.session, "my-queue", count);
+ sys::Thread t(listener);
+ for (size_t i = 0; i < count; ++i) {
+ fix.session.messageTransfer(arg::content=TransferContent(boost::lexical_cast<string>(i), "my-queue"));
+ }
+ t.join();
+ BOOST_CHECK_EQUAL(count, listener.messages.size());
+ for (size_t i = 0; i < count; ++i)
+ BOOST_CHECK_EQUAL(boost::lexical_cast<string>(i), listener.messages[i].getData());
+}
+
+QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(testSuspend0Timeout, 1)
+{
+ ClientSessionFixture fix;
+ fix.session.suspend(); // session has 0 timeout.
+ try {
+ fix.connection.resume(fix.session);
+ BOOST_FAIL("Expected InvalidArgumentException.");
+ } catch(const InternalErrorException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testUseSuspendedError)
+{
+ ClientSessionFixture fix;
+ fix.session.timeout(60);
+ fix.session.suspend();
+ try {
+ fix.session.exchangeQuery(arg::exchange="amq.fanout");
+ BOOST_FAIL("Expected session suspended exception");
+ } catch(const NotAttachedException&) {}
+}
+
+QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(testSuspendResume, 1)
+{
+ ClientSessionFixture fix;
+ fix.session.timeout(60);
+ fix.session.suspend();
+ // Make sure we are still subscribed after resume.
+ fix.connection.resume(fix.session);
+ fix.session.messageTransfer(arg::content=TransferContent("my-message", "my-queue"));
+ FrameSet::shared_ptr msg = fix.session.get();
+ BOOST_CHECK_EQUAL(string("my-message"), msg->getContent());
+}
+
+
+QPID_AUTO_TEST_CASE(testSendToSelf) {
+ ClientSessionFixture fix;
+ SimpleListener mylistener;
+ fix.session.queueDeclare(arg::queue="myq", arg::exclusive=true, arg::autoDelete=true);
+ fix.subs.subscribe(mylistener, "myq");
+ sys::Thread runner(fix.subs);//start dispatcher thread
+ string data("msg");
+ Message msg(data, "myq");
+ const uint count=10;
+ for (uint i = 0; i < count; ++i) {
+ fix.session.messageTransfer(arg::content=msg);
+ }
+ mylistener.waitFor(count);
+ fix.subs.cancel("myq");
+ fix.subs.stop();
+ runner.join();
+ fix.session.close();
+ BOOST_CHECK_EQUAL(mylistener.messages.size(), count);
+ for (uint j = 0; j < count; ++j) {
+ BOOST_CHECK_EQUAL(mylistener.messages[j].getData(), data);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testLocalQueue) {
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="lq", arg::exclusive=true, arg::autoDelete=true);
+ LocalQueue lq;
+ fix.subs.subscribe(lq, "lq", FlowControl(2, FlowControl::UNLIMITED, false));
+ fix.session.messageTransfer(arg::content=Message("foo0", "lq"));
+ fix.session.messageTransfer(arg::content=Message("foo1", "lq"));
+ fix.session.messageTransfer(arg::content=Message("foo2", "lq"));
+ BOOST_CHECK_EQUAL("foo0", lq.pop().getData());
+ BOOST_CHECK_EQUAL("foo1", lq.pop().getData());
+ BOOST_CHECK(lq.empty()); // Credit exhausted.
+ fix.subs.getSubscription("lq").setFlowControl(FlowControl::unlimited());
+ BOOST_CHECK_EQUAL("foo2", lq.pop().getData());
+}
+
+struct DelayedTransfer : sys::Runnable
+{
+ ClientSessionFixture& fixture;
+
+ DelayedTransfer(ClientSessionFixture& f) : fixture(f) {}
+
+ void run()
+ {
+ sleep(1);
+ fixture.session.messageTransfer(arg::content=Message("foo2", "getq"));
+ }
+};
+
+QPID_AUTO_TEST_CASE(testGet) {
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="getq", arg::exclusive=true, arg::autoDelete=true);
+ fix.session.messageTransfer(arg::content=Message("foo0", "getq"));
+ fix.session.messageTransfer(arg::content=Message("foo1", "getq"));
+ Message got;
+ BOOST_CHECK(fix.subs.get(got, "getq", TIME_SEC));
+ BOOST_CHECK_EQUAL("foo0", got.getData());
+ BOOST_CHECK(fix.subs.get(got, "getq", TIME_SEC));
+ BOOST_CHECK_EQUAL("foo1", got.getData());
+ BOOST_CHECK(!fix.subs.get(got, "getq"));
+ DelayedTransfer sender(fix);
+ Thread t(sender);
+ //test timed get where message shows up after a short delay
+ BOOST_CHECK(fix.subs.get(got, "getq", 5*TIME_SEC));
+ BOOST_CHECK_EQUAL("foo2", got.getData());
+ t.join();
+}
+
+QPID_AUTO_TEST_CASE(testOpenFailure) {
+ BrokerFixture b;
+ Connection c;
+ string host("unknowable-host");
+ try {
+ c.open(host);
+ } catch (const Exception&) {
+ BOOST_CHECK(!c.isOpen());
+ }
+ b.open(c);
+ BOOST_CHECK(c.isOpen());
+ c.close();
+ BOOST_CHECK(!c.isOpen());
+}
+
+QPID_AUTO_TEST_CASE(testPeriodicExpiration) {
+ Broker::Options opts;
+ opts.queueCleanInterval = 1;
+ ClientSessionFixture fix(opts);
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ for (uint i = 0; i < 10; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ if (i % 2) m.getDeliveryProperties().setTtl(500);
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ BOOST_CHECK_EQUAL(fix.session.queueQuery(string("my-queue")).getMessageCount(), 10u);
+ sleep(2);
+ BOOST_CHECK_EQUAL(fix.session.queueQuery(string("my-queue")).getMessageCount(), 5u);
+}
+
+QPID_AUTO_TEST_CASE(testExpirationOnPop) {
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ for (uint i = 0; i < 10; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ if (i % 2) m.getDeliveryProperties().setTtl(200);
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ ::usleep(300* 1000);
+
+ for (uint i = 0; i < 10; i++) {
+ if (i % 2) continue;
+ Message m;
+ BOOST_CHECK(fix.subs.get(m, "my-queue", TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testRelease) {
+ ClientSessionFixture fix;
+
+ const uint count=10;
+ for (uint i = 0; i < count; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ fix.subs.setAutoStop(false);
+ fix.subs.start();
+ SubscriptionSettings settings;
+ settings.autoAck = 0;
+
+ SimpleListener l1;
+ Subscription s1 = fix.subs.subscribe(l1, "my-queue", settings);
+ l1.waitFor(count);
+ s1.cancel();
+
+ for (uint i = 0; i < count; i++) {
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), l1.messages[i].getData());
+ }
+ s1.release(s1.getUnaccepted());
+
+ //check that released messages are redelivered
+ settings.autoAck = 1;
+ SimpleListener l2;
+ Subscription s2 = fix.subs.subscribe(l2, "my-queue", settings);
+ l2.waitFor(count);
+ for (uint i = 0; i < count; i++) {
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), l2.messages[i].getData());
+ }
+
+ fix.subs.stop();
+ fix.subs.wait();
+ fix.session.close();
+}
+
+QPID_AUTO_TEST_CASE(testCompleteOnAccept) {
+ ClientSessionFixture fix;
+ const uint count = 8;
+ const uint chunk = 4;
+ for (uint i = 0; i < count; i++) {
+ Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ fix.session.messageTransfer(arg::content=m);
+ }
+
+ SubscriptionSettings settings;
+ settings.autoAck = 0;
+ settings.completionMode = COMPLETE_ON_ACCEPT;
+ settings.flowControl = FlowControl::messageWindow(chunk);
+
+ LocalQueue q;
+ Subscription s = fix.subs.subscribe(q, "my-queue", settings);
+ fix.session.messageFlush(arg::destination=s.getName());
+ SequenceSet accepted;
+ for (uint i = 0; i < chunk; i++) {
+ Message m;
+ BOOST_CHECK(q.get(m));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ accepted.add(m.getId());
+ }
+ Message m;
+ BOOST_CHECK(!q.get(m));
+
+ s.accept(accepted);
+ fix.session.messageFlush(arg::destination=s.getName());
+ accepted.clear();
+
+ for (uint i = chunk; i < count; i++) {
+ Message m;
+ BOOST_CHECK(q.get(m));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ accepted.add(m.getId());
+ }
+ fix.session.messageAccept(accepted);
+}
+
+namespace
+{
+struct Publisher : qpid::sys::Runnable
+{
+ AsyncSession session;
+ Message message;
+ uint count;
+ Thread thread;
+
+ Publisher(Connection& con, Message m, uint c) : session(con.newSession()), message(m), count(c) {}
+
+ void start()
+ {
+ thread = Thread(*this);
+ }
+
+ void join()
+ {
+ thread.join();
+ }
+
+ void run()
+ {
+ for (uint i = 0; i < count; i++) {
+ session.messageTransfer(arg::content=message);
+ }
+ session.sync();
+ session.close();
+ }
+};
+}
+
+QPID_AUTO_TEST_CASE(testConcurrentSenders)
+{
+ //Ensure concurrent publishing sessions on a connection don't
+ //cause assertions, deadlocks or other undesirables:
+ BrokerFixture fix;
+ Connection connection;
+ ConnectionSettings settings;
+ settings.maxFrameSize = 1024;
+ settings.port = fix.broker->getPort(qpid::broker::Broker::TCP_TRANSPORT);
+ connection.open(settings);
+ AsyncSession session = connection.newSession();
+ Message message(string(512, 'X'));
+
+ boost::ptr_vector<Publisher> publishers;
+ for (size_t i = 0; i < 5; i++) {
+ publishers.push_back(new Publisher(connection, message, 100));
+ }
+ for_each(publishers.begin(), publishers.end(), boost::bind(&Publisher::start, _1));
+ for_each(publishers.begin(), publishers.end(), boost::bind(&Publisher::join, _1));
+ connection.close();
+}
+
+
+QPID_AUTO_TEST_CASE(testExclusiveSubscribe)
+{
+ ClientSessionFixture fix;
+ fix.session.queueDeclare(arg::queue="myq", arg::exclusive=true, arg::autoDelete=true);
+ SubscriptionSettings settings;
+ settings.exclusive = true;
+ LocalQueue q;
+ fix.subs.subscribe(q, "myq", settings, "first");
+ //attempt to create new subscriber should fail
+ ScopedSuppressLogging sl;
+ BOOST_CHECK_THROW(fix.subs.subscribe(q, "myq", "second"), ResourceLockedException);
+ ;
+
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/ConnectionOptions.h b/RC9/qpid/cpp/src/tests/ConnectionOptions.h
new file mode 100644
index 0000000000..0130842668
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ConnectionOptions.h
@@ -0,0 +1,54 @@
+#ifndef QPID_CLIENT_CONNECTIONOPTIONS_H
+#define QPID_CLIENT_CONNECTIONOPTIONS_H
+
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/client/ConnectionSettings.h"
+#include "qpid/Options.h"
+
+/**
+ * Options parser for ConnectionOptions.
+ */
+struct ConnectionOptions : public qpid::Options,
+ public qpid::client::ConnectionSettings
+{
+ ConnectionOptions() : qpid::Options("Connection Settings")
+ {
+ using namespace qpid;
+ addOptions()
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("port,p", optValue(port, "PORT"), "Broker port to connect to")
+ ("protocol,P", optValue(protocol, "tcp|rdma"), "Protocol to use for broker connection")
+ ("virtualhost,v", optValue(virtualhost, "VHOST"), "virtual host")
+ ("username", optValue(username, "USER"), "user name for broker log in.")
+ ("password", optValue(password, "PASSWORD"), "password for broker log in.")
+ ("mechanism", optValue(mechanism, "MECH"), "SASL mechanism to use when authenticating.")
+ ("locale", optValue(locale, "LOCALE"), "locale to use.")
+ ("max-channels", optValue(maxChannels, "N"), "the maximum number of channels the client requires.")
+ ("max-frame-size", optValue(maxFrameSize, "N"), "the maximum frame size to request.")
+ ("bounds-multiplier", optValue(bounds, "N"),
+ "bound size of write queue (as a multiple of the max frame size).")
+ ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay");
+ }
+};
+
+#endif /*!QPID_CLIENT_CONNECTIONOPTIONS_H*/
diff --git a/RC9/qpid/cpp/src/tests/ConsoleTest.cpp b/RC9/qpid/cpp/src/tests/ConsoleTest.cpp
new file mode 100644
index 0000000000..1d55b13f3c
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ConsoleTest.cpp
@@ -0,0 +1,43 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/console/Package.h"
+#include "qpid/console/ClassKey.h"
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(ConsoleTestSuite)
+
+using namespace qpid::framing;
+using namespace qpid::console;
+
+QPID_AUTO_TEST_CASE(testClassKey) {
+ uint8_t hash[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ ClassKey k("com.redhat.test", "class", hash);
+
+ BOOST_CHECK_EQUAL(k.getPackageName(), "com.redhat.test");
+ BOOST_CHECK_EQUAL(k.getClassName(), "class");
+ BOOST_CHECK_EQUAL(k.getHashString(), "00010203-04050607-08090a0b-0c0d0e0f");
+ BOOST_CHECK_EQUAL(k.str(), "com.redhat.test:class(00010203-04050607-08090a0b-0c0d0e0f)");
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/DeliveryRecordTest.cpp b/RC9/qpid/cpp/src/tests/DeliveryRecordTest.cpp
new file mode 100644
index 0000000000..47c7157749
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/DeliveryRecordTest.cpp
@@ -0,0 +1,62 @@
+
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/broker/DeliveryRecord.h"
+#include "unit_test.h"
+#include <iostream>
+#include <memory>
+#include <boost/format.hpp>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using boost::dynamic_pointer_cast;
+using std::list;
+
+QPID_AUTO_TEST_SUITE(DeliveryRecordTestSuite)
+
+QPID_AUTO_TEST_CASE(testSort)
+{
+ list<SequenceNumber> ids;
+ ids.push_back(SequenceNumber(6));
+ ids.push_back(SequenceNumber(2));
+ ids.push_back(SequenceNumber(4));
+ ids.push_back(SequenceNumber(5));
+ ids.push_back(SequenceNumber(1));
+ ids.push_back(SequenceNumber(3));
+
+ list<DeliveryRecord> records;
+ for (list<SequenceNumber>::iterator i = ids.begin(); i != ids.end(); i++) {
+ DeliveryRecord r(QueuedMessage(0), Queue::shared_ptr(), "tag", false, false, false);
+ r.setId(*i);
+ records.push_back(r);
+ }
+ records.sort();
+
+ SequenceNumber expected(0);
+ for (list<DeliveryRecord>::iterator i = records.begin(); i != records.end(); i++) {
+ BOOST_CHECK(i->matches(++expected));
+ }
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/DispatcherTest.cpp b/RC9/qpid/cpp/src/tests/DispatcherTest.cpp
new file mode 100644
index 0000000000..7631956acc
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/DispatcherTest.cpp
@@ -0,0 +1,128 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/Dispatcher.h"
+#include "qpid/sys/Thread.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <iostream>
+#include <boost/bind.hpp>
+
+using namespace std;
+using namespace qpid::sys;
+
+int writeALot(int fd, const string& s) {
+ int bytesWritten = 0;
+ do {
+ errno = 0;
+ int lastWrite = ::write(fd, s.c_str(), s.size());
+ if ( lastWrite >= 0) {
+ bytesWritten += lastWrite;
+ }
+ } while (errno != EAGAIN);
+ return bytesWritten;
+}
+
+int readALot(int fd) {
+ int bytesRead = 0;
+ char buf[10240];
+
+ do {
+ errno = 0;
+ int lastRead = ::read(fd, buf, sizeof(buf));
+ if ( lastRead >= 0) {
+ bytesRead += lastRead;
+ }
+ } while (errno != EAGAIN);
+ return bytesRead;
+}
+
+int64_t writtenBytes = 0;
+int64_t readBytes = 0;
+
+void writer(DispatchHandle& h, int fd, const string& s) {
+ writtenBytes += writeALot(fd, s);
+ h.rewatch();
+}
+
+void reader(DispatchHandle& h, int fd) {
+ readBytes += readALot(fd);
+ h.rewatch();
+}
+
+int main(int argc, char** argv)
+{
+ // Create poller
+ Poller::shared_ptr poller(new Poller);
+
+ // Create dispatcher thread
+ Dispatcher d(poller);
+ Dispatcher d1(poller);
+ //Dispatcher d2(poller);
+ //Dispatcher d3(poller);
+ Thread dt(d);
+ Thread dt1(d1);
+ //Thread dt2(d2);
+ //Thread dt3(d3);
+
+ // Setup sender and receiver
+ int sv[2];
+ int rc = ::socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
+ assert(rc >= 0);
+
+ // Set non-blocking
+ rc = ::fcntl(sv[0], F_SETFL, O_NONBLOCK);
+ assert(rc >= 0);
+
+ rc = ::fcntl(sv[1], F_SETFL, O_NONBLOCK);
+ assert(rc >= 0);
+
+ // Make up a large string
+ string testString = "This is only a test ... 1,2,3,4,5,6,7,8,9,10;";
+ for (int i = 0; i < 8; i++)
+ testString += testString;
+
+ DispatchHandle rh(sv[0], boost::bind(reader, _1, sv[0]), 0);
+ DispatchHandle wh(sv[1], 0, boost::bind(writer, _1, sv[1], testString));
+
+ rh.watch(poller);
+ wh.watch(poller);
+
+ // wait 2 minutes then shutdown
+ sleep(60);
+
+ poller->shutdown();
+ dt.join();
+ dt1.join();
+ //dt2.join();
+ //dt3.join();
+
+ cout << "Wrote: " << writtenBytes << "\n";
+ cout << "Read: " << readBytes << "\n";
+
+ return 0;
+}
diff --git a/RC9/qpid/cpp/src/tests/DtxWorkRecordTest.cpp b/RC9/qpid/cpp/src/tests/DtxWorkRecordTest.cpp
new file mode 100644
index 0000000000..c7c1b460ff
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/DtxWorkRecordTest.cpp
@@ -0,0 +1,189 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/broker/DtxWorkRecord.h"
+#include "unit_test.h"
+#include <iostream>
+#include <vector>
+#include "TxMocks.h"
+
+using namespace qpid::broker;
+using boost::static_pointer_cast;
+
+QPID_AUTO_TEST_SUITE(DtxWorkRecordTestSuite)
+
+QPID_AUTO_TEST_CASE(testOnePhaseCommit){
+ MockTransactionalStore store;
+ store.expectBegin().expectCommit();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectCommit();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare().expectCommit();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+
+ work.commit(true);
+
+ store.check();
+ BOOST_CHECK(store.isCommitted());
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_CASE(testFailOnOnePhaseCommit){
+ MockTransactionalStore store;
+ store.expectBegin().expectAbort();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectRollback();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+ DtxBuffer::shared_ptr bufferC(new DtxBuffer());
+ bufferC->enlist(static_pointer_cast<TxOp>(opC));
+ bufferC->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+ work.add(bufferC);
+
+ work.commit(true);
+
+ BOOST_CHECK(store.isAborted());
+ store.check();
+
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testTwoPhaseCommit){
+ MockTransactionalStore store;
+ store.expectBegin2PC().expectPrepare().expectCommit();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectCommit();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare().expectCommit();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+
+ BOOST_CHECK(work.prepare());
+ BOOST_CHECK(store.isPrepared());
+ work.commit(false);
+ store.check();
+ BOOST_CHECK(store.isCommitted());
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_CASE(testFailOnTwoPhaseCommit){
+ MockTransactionalStore store;
+ store.expectBegin2PC().expectAbort();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectRollback();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+ DtxBuffer::shared_ptr bufferC(new DtxBuffer());
+ bufferC->enlist(static_pointer_cast<TxOp>(opC));
+ bufferC->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+ work.add(bufferC);
+
+ BOOST_CHECK(!work.prepare());
+ BOOST_CHECK(store.isAborted());
+ store.check();
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testRollback){
+ MockTransactionalStore store;
+ store.expectBegin2PC().expectPrepare().expectAbort();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare().expectRollback();
+
+ DtxBuffer::shared_ptr bufferA(new DtxBuffer());
+ bufferA->enlist(static_pointer_cast<TxOp>(opA));
+ bufferA->markEnded();
+ DtxBuffer::shared_ptr bufferB(new DtxBuffer());
+ bufferB->enlist(static_pointer_cast<TxOp>(opB));
+ bufferB->markEnded();
+
+ DtxWorkRecord work("my-xid", &store);
+ work.add(bufferA);
+ work.add(bufferB);
+
+ BOOST_CHECK(work.prepare());
+ BOOST_CHECK(store.isPrepared());
+ work.rollback();
+ store.check();
+ BOOST_CHECK(store.isAborted());
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/ExchangeTest.cpp b/RC9/qpid/cpp/src/tests/ExchangeTest.cpp
new file mode 100644
index 0000000000..0946d3115d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ExchangeTest.cpp
@@ -0,0 +1,284 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/broker/Exchange.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/DeliverableMessage.h"
+#include "qpid/broker/DirectExchange.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/FanOutExchange.h"
+#include "qpid/broker/HeadersExchange.h"
+#include "qpid/broker/TopicExchange.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "unit_test.h"
+#include <iostream>
+#include "MessageUtils.h"
+
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace qpid;
+
+QPID_AUTO_TEST_SUITE(ExchangeTestSuite)
+
+QPID_AUTO_TEST_CASE(testMe)
+{
+ Queue::shared_ptr queue(new Queue("queue", true));
+ Queue::shared_ptr queue2(new Queue("queue2", true));
+
+ TopicExchange topic("topic");
+ topic.bind(queue, "abc", 0);
+ topic.bind(queue2, "abc", 0);
+
+ DirectExchange direct("direct");
+ direct.bind(queue, "abc", 0);
+ direct.bind(queue2, "abc", 0);
+
+ queue.reset();
+ queue2.reset();
+
+ intrusive_ptr<Message> msgPtr(MessageUtils::createMessage("exchange", "key", "id"));
+ DeliverableMessage msg(msgPtr);
+ topic.route(msg, "abc", 0);
+ direct.route(msg, "abc", 0);
+
+}
+
+QPID_AUTO_TEST_CASE(testIsBound)
+{
+ Queue::shared_ptr a(new Queue("a", true));
+ Queue::shared_ptr b(new Queue("b", true));
+ Queue::shared_ptr c(new Queue("c", true));
+ Queue::shared_ptr d(new Queue("d", true));
+
+ string k1("abc");
+ string k2("def");
+ string k3("xyz");
+
+ FanOutExchange fanout("fanout");
+ BOOST_CHECK(fanout.bind(a, "", 0));
+ BOOST_CHECK(fanout.bind(b, "", 0));
+ BOOST_CHECK(fanout.bind(c, "", 0));
+
+ BOOST_CHECK(fanout.isBound(a, 0, 0));
+ BOOST_CHECK(fanout.isBound(b, 0, 0));
+ BOOST_CHECK(fanout.isBound(c, 0, 0));
+ BOOST_CHECK(!fanout.isBound(d, 0, 0));
+
+ DirectExchange direct("direct");
+ BOOST_CHECK(direct.bind(a, k1, 0));
+ BOOST_CHECK(direct.bind(a, k3, 0));
+ BOOST_CHECK(direct.bind(b, k2, 0));
+ BOOST_CHECK(direct.bind(c, k1, 0));
+
+ BOOST_CHECK(direct.isBound(a, 0, 0));
+ BOOST_CHECK(direct.isBound(a, &k1, 0));
+ BOOST_CHECK(direct.isBound(a, &k3, 0));
+ BOOST_CHECK(!direct.isBound(a, &k2, 0));
+ BOOST_CHECK(direct.isBound(b, 0, 0));
+ BOOST_CHECK(direct.isBound(b, &k2, 0));
+ BOOST_CHECK(direct.isBound(c, &k1, 0));
+ BOOST_CHECK(!direct.isBound(d, 0, 0));
+ BOOST_CHECK(!direct.isBound(d, &k1, 0));
+ BOOST_CHECK(!direct.isBound(d, &k2, 0));
+ BOOST_CHECK(!direct.isBound(d, &k3, 0));
+
+ TopicExchange topic("topic");
+ BOOST_CHECK(topic.bind(a, k1, 0));
+ BOOST_CHECK(topic.bind(a, k3, 0));
+ BOOST_CHECK(topic.bind(b, k2, 0));
+ BOOST_CHECK(topic.bind(c, k1, 0));
+
+ BOOST_CHECK(topic.isBound(a, 0, 0));
+ BOOST_CHECK(topic.isBound(a, &k1, 0));
+ BOOST_CHECK(topic.isBound(a, &k3, 0));
+ BOOST_CHECK(!topic.isBound(a, &k2, 0));
+ BOOST_CHECK(topic.isBound(b, 0, 0));
+ BOOST_CHECK(topic.isBound(b, &k2, 0));
+ BOOST_CHECK(topic.isBound(c, &k1, 0));
+ BOOST_CHECK(!topic.isBound(d, 0, 0));
+ BOOST_CHECK(!topic.isBound(d, &k1, 0));
+ BOOST_CHECK(!topic.isBound(d, &k2, 0));
+ BOOST_CHECK(!topic.isBound(d, &k3, 0));
+
+ HeadersExchange headers("headers");
+ FieldTable args1;
+ args1.setString("x-match", "all");
+ args1.setString("a", "A");
+ args1.setInt("b", 1);
+ FieldTable args2;
+ args2.setString("x-match", "any");
+ args2.setString("a", "A");
+ args2.setInt("b", 1);
+ FieldTable args3;
+ args3.setString("x-match", "any");
+ args3.setString("c", "C");
+ args3.setInt("b", 6);
+
+ headers.bind(a, "", &args1);
+ headers.bind(a, "", &args3);
+ headers.bind(b, "", &args2);
+ headers.bind(c, "", &args1);
+
+ BOOST_CHECK(headers.isBound(a, 0, 0));
+ BOOST_CHECK(headers.isBound(a, 0, &args1));
+ BOOST_CHECK(headers.isBound(a, 0, &args3));
+ BOOST_CHECK(!headers.isBound(a, 0, &args2));
+ BOOST_CHECK(headers.isBound(b, 0, 0));
+ BOOST_CHECK(headers.isBound(b, 0, &args2));
+ BOOST_CHECK(headers.isBound(c, 0, &args1));
+ BOOST_CHECK(!headers.isBound(d, 0, 0));
+ BOOST_CHECK(!headers.isBound(d, 0, &args1));
+ BOOST_CHECK(!headers.isBound(d, 0, &args2));
+ BOOST_CHECK(!headers.isBound(d, 0, &args3));
+}
+
+QPID_AUTO_TEST_CASE(testDeleteGetAndRedeclare)
+{
+ ExchangeRegistry exchanges;
+ exchanges.declare("my-exchange", "direct", false, FieldTable());
+ exchanges.destroy("my-exchange");
+ try {
+ exchanges.get("my-exchange");
+ } catch (const NotFoundException&) {}
+ std::pair<Exchange::shared_ptr, bool> response = exchanges.declare("my-exchange", "direct", false, FieldTable());
+ BOOST_CHECK_EQUAL(string("direct"), response.first->getType());
+}
+
+intrusive_ptr<Message> cmessage(std::string exchange, std::string routingKey) {
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ return msg;
+}
+
+QPID_AUTO_TEST_CASE(testSequenceOptions)
+{
+ FieldTable args;
+ args.setInt("qpid.msg_sequence",1);
+ char* buff = new char[10000];
+ framing::Buffer buffer(buff,10000);
+ {
+ DirectExchange direct("direct1", false, args);
+
+ intrusive_ptr<Message> msg1 = cmessage("e", "A");
+ intrusive_ptr<Message> msg2 = cmessage("e", "B");
+ intrusive_ptr<Message> msg3 = cmessage("e", "C");
+
+ DeliverableMessage dmsg1(msg1);
+ DeliverableMessage dmsg2(msg2);
+ DeliverableMessage dmsg3(msg3);
+
+ direct.route(dmsg1, "abc", 0);
+ direct.route(dmsg2, "abc", 0);
+ direct.route(dmsg3, "abc", 0);
+
+ BOOST_CHECK_EQUAL(1, msg1->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ BOOST_CHECK_EQUAL(2, msg2->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ BOOST_CHECK_EQUAL(3, msg3->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ FanOutExchange fanout("fanout1", false, args);
+ HeadersExchange header("headers1", false, args);
+ TopicExchange topic ("topic1", false, args);
+
+ // check other exchanges, that they preroute
+ intrusive_ptr<Message> msg4 = cmessage("e", "A");
+ intrusive_ptr<Message> msg5 = cmessage("e", "B");
+ intrusive_ptr<Message> msg6 = cmessage("e", "C");
+
+ DeliverableMessage dmsg4(msg4);
+ DeliverableMessage dmsg5(msg5);
+ DeliverableMessage dmsg6(msg6);
+
+ fanout.route(dmsg4, "abc", 0);
+ BOOST_CHECK_EQUAL(1, msg4->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ FieldTable headers;
+ header.route(dmsg5, "abc", &headers);
+ BOOST_CHECK_EQUAL(1, msg5->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ topic.route(dmsg6, "abc", 0);
+ BOOST_CHECK_EQUAL(1, msg6->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+ direct.encode(buffer);
+ }
+ {
+
+ ExchangeRegistry exchanges;
+ buffer.reset();
+ DirectExchange::shared_ptr exch_dec = Exchange::decode(exchanges, buffer);
+
+ intrusive_ptr<Message> msg1 = cmessage("e", "A");
+ DeliverableMessage dmsg1(msg1);
+ exch_dec->route(dmsg1, "abc", 0);
+
+ BOOST_CHECK_EQUAL(4, msg1->getApplicationHeaders()->getAsInt64("qpid.msg_sequence"));
+
+ }
+ delete [] buff;
+}
+
+QPID_AUTO_TEST_CASE(testIVEOption)
+{
+ FieldTable args;
+ args.setInt("qpid.ive",1);
+ DirectExchange direct("direct1", false, args);
+ FanOutExchange fanout("fanout1", false, args);
+ HeadersExchange header("headers1", false, args);
+ TopicExchange topic ("topic1", false, args);
+
+ intrusive_ptr<Message> msg1 = cmessage("direct1", "abc");
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString("a", "abc");
+ DeliverableMessage dmsg1(msg1);
+
+ FieldTable args2;
+ args2.setString("x-match", "any");
+ args2.setString("a", "abc");
+
+ direct.route(dmsg1, "abc", 0);
+ fanout.route(dmsg1, "abc", 0);
+ header.route(dmsg1, "abc", &args2);
+ topic.route(dmsg1, "abc", 0);
+ Queue::shared_ptr queue(new Queue("queue", true));
+ Queue::shared_ptr queue1(new Queue("queue1", true));
+ Queue::shared_ptr queue2(new Queue("queue2", true));
+ Queue::shared_ptr queue3(new Queue("queue3", true));
+
+ BOOST_CHECK(HeadersExchange::match(args2, msg1->getProperties<MessageProperties>()->getApplicationHeaders()));
+
+ BOOST_CHECK(direct.bind(queue, "abc", 0));
+ BOOST_CHECK(fanout.bind(queue1, "abc", 0));
+ BOOST_CHECK(header.bind(queue2, "", &args2));
+ BOOST_CHECK(topic.bind(queue3, "abc", 0));
+
+ BOOST_CHECK_EQUAL(1u,queue->getMessageCount());
+ BOOST_CHECK_EQUAL(1u,queue1->getMessageCount());
+ BOOST_CHECK_EQUAL(1u,queue2->getMessageCount());
+ BOOST_CHECK_EQUAL(1u,queue3->getMessageCount());
+
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/FieldTable.cpp b/RC9/qpid/cpp/src/tests/FieldTable.cpp
new file mode 100644
index 0000000000..6b364723cf
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/FieldTable.cpp
@@ -0,0 +1,178 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include <iostream>
+#include "qpid/framing/Array.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+#include <alloca.h>
+
+#include "unit_test.h"
+
+using namespace qpid::framing;
+
+QPID_AUTO_TEST_SUITE(FieldTableTestSuite)
+
+QPID_AUTO_TEST_CASE(testMe)
+{
+ FieldTable ft;
+ ft.setString("A", "BCDE");
+ BOOST_CHECK(string("BCDE") == ft.getAsString("A"));
+
+ char buff[100];
+ Buffer wbuffer(buff, 100);
+ wbuffer.put(ft);
+
+ Buffer rbuffer(buff, 100);
+ FieldTable ft2;
+ rbuffer.get(ft2);
+ BOOST_CHECK(string("BCDE") == ft2.getAsString("A"));
+
+}
+
+QPID_AUTO_TEST_CASE(testAssignment)
+{
+ FieldTable a;
+ FieldTable b;
+
+ a.setString("A", "BBBB");
+ a.setInt("B", 1234);
+ b = a;
+ a.setString("A", "CCCC");
+
+ BOOST_CHECK(string("CCCC") == a.getAsString("A"));
+ BOOST_CHECK(string("BBBB") == b.getAsString("A"));
+ BOOST_CHECK_EQUAL(1234, a.getAsInt("B"));
+ BOOST_CHECK_EQUAL(1234, b.getAsInt("B"));
+ BOOST_CHECK(IntegerValue(1234) == *a.get("B"));
+ BOOST_CHECK(IntegerValue(1234) == *b.get("B"));
+
+ FieldTable d;
+ {
+ FieldTable c;
+ c = a;
+
+ char* buff = static_cast<char*>(::alloca(c.encodedSize()));
+ Buffer wbuffer(buff, c.encodedSize());
+ wbuffer.put(c);
+
+ Buffer rbuffer(buff, c.encodedSize());
+ rbuffer.get(d);
+ BOOST_CHECK_EQUAL(c, d);
+ BOOST_CHECK(string("CCCC") == c.getAsString("A"));
+ BOOST_CHECK(IntegerValue(1234) == *c.get("B"));
+ }
+ BOOST_CHECK(string("CCCC") == d.getAsString("A"));
+ BOOST_CHECK(IntegerValue(1234) == *d.get("B"));
+}
+
+
+QPID_AUTO_TEST_CASE(testNestedValues)
+{
+ char buff[100];
+ {
+ FieldTable a;
+ FieldTable b;
+ std::vector<std::string> items;
+ items.push_back("one");
+ items.push_back("two");
+ Array c(items);
+
+ a.setString("id", "A");
+ b.setString("id", "B");
+ a.setTable("B", b);
+ a.setArray("C", c);
+
+
+ Buffer wbuffer(buff, 100);
+ wbuffer.put(a);
+ }
+ {
+ Buffer rbuffer(buff, 100);
+ FieldTable a;
+ FieldTable b;
+ Array c;
+ rbuffer.get(a);
+ BOOST_CHECK(string("A") == a.getAsString("id"));
+ a.getTable("B", b);
+ BOOST_CHECK(string("B") == b.getAsString("id"));
+ a.getArray("C", c);
+ std::vector<std::string> items;
+ c.collect(items);
+ BOOST_CHECK((uint) 2 == items.size());
+ BOOST_CHECK(string("one") == items[0]);
+ BOOST_CHECK(string("two") == items[1]);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testFloatAndDouble)
+{
+ char buff[100];
+ float f = 5.672;
+ double d = 56.720001;
+ {
+ FieldTable a;
+ a.setString("string", "abc");
+ a.setInt("int", 5672);
+ a.setFloat("float", f);
+ a.setDouble("double", d);
+
+ Buffer wbuffer(buff, 100);
+ wbuffer.put(a);
+ }
+ {
+ Buffer rbuffer(buff, 100);
+ FieldTable a;
+ rbuffer.get(a);
+ BOOST_CHECK(string("abc") == a.getAsString("string"));
+ BOOST_CHECK(5672 == a.getAsInt("int"));
+ float f2;
+ BOOST_CHECK(!a.getFloat("string", f2));
+ BOOST_CHECK(!a.getFloat("int", f2));
+ BOOST_CHECK(a.getFloat("float", f2));
+ BOOST_CHECK(f2 == f);
+
+ double d2;
+ BOOST_CHECK(!a.getDouble("string", d2));
+ BOOST_CHECK(!a.getDouble("int", d2));
+ BOOST_CHECK(a.getDouble("double", d2));
+ BOOST_CHECK(d2 == d);
+ }
+}
+
+QPID_AUTO_TEST_CASE(test64GetAndSetConverts)
+{
+ FieldTable args;
+ args.setInt64("a",100);
+ args.setInt64("b",-(int64_t) ((int64_t) 1<<34));
+
+ args.setUInt64("c",1u);
+ args.setUInt64("d",(uint64_t) ((uint64_t) 1<<34));
+ BOOST_CHECK_EQUAL(1u, args.getAsUInt64("c"));
+ BOOST_CHECK_EQUAL(100u, args.getAsUInt64("a"));
+ BOOST_CHECK_EQUAL(1, args.getAsInt64("c"));
+ BOOST_CHECK_EQUAL(100, args.getAsInt64("a"));
+ BOOST_CHECK_EQUAL(-(int64_t) ((int64_t) 1<<34), args.getAsInt64("b"));
+ BOOST_CHECK_EQUAL((uint64_t) ((uint64_t) 1<<34), args.getAsUInt64("d"));
+ BOOST_CHECK_EQUAL((int64_t) ((int64_t) 1<<34), args.getAsInt64("d"));
+
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/FieldValue.cpp b/RC9/qpid/cpp/src/tests/FieldValue.cpp
new file mode 100644
index 0000000000..448f068107
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/FieldValue.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+#include "qpid/framing/FieldValue.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(FieldValueTestSuite)
+
+using namespace qpid::framing;
+
+Str16Value s("abc");
+IntegerValue i(42);
+//DecimalValue d(1234,2);
+//FieldTableValue ft;
+//EmptyValue e;
+
+QPID_AUTO_TEST_CASE(testStr16ValueEquals)
+{
+
+ BOOST_CHECK(Str16Value("abc") == s);
+ BOOST_CHECK(Str16Value("foo") != s);
+ BOOST_CHECK(s != i);
+ BOOST_CHECK(s.convertsTo<std::string>() == true);
+ BOOST_CHECK(s.convertsTo<int>() == false);
+ BOOST_CHECK(s.get<std::string>() == "abc");
+ BOOST_CHECK_THROW(s.get<int>(), InvalidConversionException);
+// BOOST_CHECK(s != ft);
+
+}
+
+QPID_AUTO_TEST_CASE(testIntegerValueEquals)
+{
+ BOOST_CHECK(IntegerValue(42) == i);
+ BOOST_CHECK(IntegerValue(5) != i);
+ BOOST_CHECK(i != s);
+ BOOST_CHECK(i.convertsTo<std::string>() == false);
+ BOOST_CHECK(i.convertsTo<int>() == true);
+ BOOST_CHECK_THROW(i.get<std::string>(), InvalidConversionException);
+ BOOST_CHECK(i.get<int>() == 42);
+// BOOST_CHECK(i != ft);
+}
+
+#if 0
+QPID_AUTO_TEST_CASE(testDecimalValueEquals)
+{
+ BOOST_CHECK(DecimalValue(1234, 2) == d);
+ BOOST_CHECK(DecimalValue(12345, 2) != d);
+ BOOST_CHECK(DecimalValue(1234, 3) != d);
+ BOOST_CHECK(d != s);
+}
+
+QPID_AUTO_TEST_CASE(testFieldTableValueEquals)
+{
+ ft.getValue().setString("foo", "FOO");
+ ft.getValue().setInt("magic", 7);
+
+ BOOST_CHECK_EQUAL(std::string("FOO"),
+ ft.getValue().getString("foo"));
+ BOOST_CHECK_EQUAL(7, ft.getValue().getInt("magic"));
+
+ FieldTableValue f2;
+ BOOST_CHECK(ft != f2);
+ f2.getValue().setString("foo", "FOO");
+ BOOST_CHECK(ft != f2);
+ f2.getValue().setInt("magic", 7);
+ BOOST_CHECK_EQUAL(ft,f2);
+ BOOST_CHECK(ft == f2);
+ f2.getValue().setString("foo", "BAR");
+ BOOST_CHECK(ft != f2);
+ BOOST_CHECK(ft != i);
+}
+#endif
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/ForkedBroker.h b/RC9/qpid/cpp/src/tests/ForkedBroker.h
new file mode 100644
index 0000000000..bf9e9265c4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ForkedBroker.h
@@ -0,0 +1,122 @@
+#ifndef TESTS_FORKEDBROKER_H
+
+
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/log/Statement.h"
+#include "qpid/broker/Broker.h"
+#include <boost/lexical_cast.hpp>
+#include <string>
+#include <stdio.h>
+#include <sys/wait.h>
+
+/**
+ * Class to fork a broker child process.
+ *
+ * For most tests a BrokerFixture may be more convenient as it starts
+ * a broker in the same process which allows you to easily debug into
+ * the broker.
+ *
+ * This useful for tests that need to start multiple brokers where
+ * those brokers can't coexist in the same process (e.g. for cluster
+ * tests where CPG doesn't allow multiple group members in a single
+ * process.)
+ *
+ */
+class ForkedBroker {
+ public:
+ ForkedBroker(std::vector<const char*> argv) { init(argv); }
+
+ ForkedBroker(int argc, const char* const argv[]) {
+ std::vector<const char*> args(argv, argv+argc);
+ init(args);
+ }
+
+ ~ForkedBroker() {
+ try { kill(); } catch(const std::exception& e) {
+ QPID_LOG(error, QPID_MSG("Killing forked broker: " << e.what()));
+ }
+ }
+
+ void kill(int sig=SIGINT) {
+ if (pid == 0) return;
+ int savePid = pid;
+ pid = 0; // Reset pid here in case of an exception.
+ using qpid::ErrnoException;
+ if (::kill(savePid, sig) < 0)
+ throw ErrnoException("kill failed");
+ int status;
+ if (::waitpid(savePid, &status, 0) < 0)
+ throw ErrnoException("wait for forked process failed");
+ if (WEXITSTATUS(status) != 0)
+ throw qpid::Exception(QPID_MSG("Forked broker exited with: " << WEXITSTATUS(status)));
+ }
+
+ uint16_t getPort() { return port; }
+ pid_t getPID() { return pid; }
+
+ private:
+
+ template <class F> struct OnExit {
+ F fn;
+ OnExit(F f) : fn(f) {}
+ ~OnExit() { fn(); }
+ };
+
+ void init(const std::vector<const char*>& args) {
+ using qpid::ErrnoException;
+ port = 0;
+ int pipeFds[2];
+ if(::pipe(pipeFds) < 0) throw ErrnoException("Can't create pipe");
+ pid = ::fork();
+ if (pid < 0) throw ErrnoException("Fork failed");
+ if (pid) { // parent
+ ::close(pipeFds[1]);
+ FILE* f = ::fdopen(pipeFds[0], "r");
+ if (!f) throw ErrnoException("fopen failed");
+ if (::fscanf(f, "%d", &port) != 1) {
+ if (ferror(f)) throw ErrnoException("Error reading port number from child.");
+ else throw qpid::Exception("EOF reading port number from child.");
+ }
+ ::close(pipeFds[0]);
+ }
+ else { // child
+ ::close(pipeFds[0]);
+ int fd = ::dup2(pipeFds[1], 1); // pipe stdout to the parent.
+ if (fd < 0) throw ErrnoException("dup2 failed");
+ const char* prog = "../qpidd";
+ std::vector<const char*> args2(args);
+ args2.push_back("--port=0");
+ args2.push_back("--mgmt-enable=no"); // TODO aconway 2008-07-16: why does mgmt cause problems?
+ args2.push_back("--log-enable=error+"); // Keep quiet except for errors.
+ args2.push_back(0);
+ execv(prog, const_cast<char* const*>(&args2[0]));
+ throw ErrnoException("execv failed");
+ }
+ }
+
+ pid_t pid;
+ int port;
+};
+
+#endif /*!TESTS_FORKEDBROKER_H*/
diff --git a/RC9/qpid/cpp/src/tests/Frame.cpp b/RC9/qpid/cpp/src/tests/Frame.cpp
new file mode 100644
index 0000000000..11905911fa
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Frame.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/framing/Frame.h"
+
+#include <boost/lexical_cast.hpp>
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(FrameTestSuite)
+
+using namespace std;
+using namespace qpid::framing;
+using namespace boost;
+
+QPID_AUTO_TEST_CASE(testContentBody) {
+ Frame f(42, AMQContentBody("foobar"));
+ AMQBody* body=f.getBody();
+ BOOST_CHECK(dynamic_cast<AMQContentBody*>(body));
+ Buffer b(f.encodedSize();
+ f.encode(b);
+ b.flip();
+ Frame g;
+ g.decode(b);
+ AMQContentBody* content=dynamic_cast<AMQContentBody*>(g.getBody());
+ BOOST_REQUIRE(content);
+ BOOST_CHECK_EQUAL(content->getData(), "foobar");
+}
+
+QPID_AUTO_TEST_CASE(testMethodBody) {
+ FieldTable args;
+ args.setString("foo", "bar");
+ Frame f(
+ 42, QueueDeclareBody(ProtocolVersion(), 1, "q", "altex",
+ true, false, true, false, true, args));
+ BOOST_CHECK_EQUAL(f.getChannel(), 42);
+ Buffer b(f.encodedSize();
+ f.encode(b);
+ b.flip();
+ Frame g;
+ g.decode(b);
+ BOOST_CHECK_EQUAL(f.getChannel(), g.getChannel());
+ QueueDeclareBody* declare=dynamic_cast<QueueDeclareBody*>(g.getBody());
+ BOOST_REQUIRE(declare);
+ BOOST_CHECK_EQUAL(declare->getAlternateExchange(), "altex");
+ BOOST_CHECK_EQUAL(lexical_cast<string>(*f.getBody()), lexical_cast<string>(*g.getBody()));
+}
+
+QPID_AUTO_TEST_CASE(testLoop) {
+ // Run in a loop so heap profiler can spot any allocations.
+ Buffer b(1024);
+ for (int i = 0; i < 100; ++i) {
+ Frame ctor(2, AccessRequestOkBody(ProtocolVersion(), 42));
+ Frame assign(3);
+ assign.body = AccessRequestOkBody(ProtocolVersion(), 42);
+ assign.encode(b);
+ b.flip();
+ Frame g;
+ g.decode(b);
+ BOOST_REQUIRE(dynamic_cast<AccessRequestOkBody*>(g.getBody())->getTicket() == 42);
+ }
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/FramingTest.cpp b/RC9/qpid/cpp/src/tests/FramingTest.cpp
new file mode 100644
index 0000000000..f82507c0a7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/FramingTest.cpp
@@ -0,0 +1,151 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/client/Connection.h"
+#include "qpid/client/Connector.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/ProtocolVersion.h"
+#include "qpid/framing/all_method_bodies.h"
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "unit_test.h"
+
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <iostream>
+
+#include <memory>
+#include <sstream>
+#include <typeinfo>
+
+using namespace qpid;
+using namespace qpid::framing;
+using namespace std;
+
+template <class T>
+std::string tostring(const T& x)
+{
+ std::ostringstream out;
+ out << x;
+ return out.str();
+}
+
+QPID_AUTO_TEST_SUITE(FramingTestSuite)
+
+QPID_AUTO_TEST_CASE(testMessageTransferBody)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ MessageTransferBody in(version, "my-exchange", 1, 1);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ MessageTransferBody out(version);
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testConnectionSecureBody)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string s = "security credential";
+ ConnectionSecureBody in(version, s);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ ConnectionSecureBody out(version);
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testConnectionRedirectBody)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string a = "hostA";
+ std::string b = "hostB";
+ Array hosts(0x95);
+ hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(a)));
+ hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(b)));
+
+ ConnectionRedirectBody in(version, a, hosts);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ ConnectionRedirectBody out(version);
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testQueueDeclareBody)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ QueueDeclareBody in(version, "name", "dlq", true, false, true, false, FieldTable());
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ QueueDeclareBody out(version);
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testConnectionRedirectBodyFrame)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ std::string a = "hostA";
+ std::string b = "hostB";
+ Array hosts(0x95);
+ hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(a)));
+ hosts.add(boost::shared_ptr<FieldValue>(new Str16Value(b)));
+
+ AMQFrame in(in_place<ConnectionRedirectBody>(version, a, hosts));
+ in.setChannel(999);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ AMQFrame out;
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_CASE(testMessageCancelBodyFrame)
+{
+ char buffer[1024];
+ ProtocolVersion version(highestProtocolVersion);
+ Buffer wbuff(buffer, sizeof(buffer));
+ AMQFrame in(in_place<MessageCancelBody>(version, "tag"));
+ in.setChannel(999);
+ in.encode(wbuff);
+
+ Buffer rbuff(buffer, sizeof(buffer));
+ AMQFrame out;
+ out.decode(rbuff);
+ BOOST_CHECK_EQUAL(tostring(in), tostring(out));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/HeaderTest.cpp b/RC9/qpid/cpp/src/tests/HeaderTest.cpp
new file mode 100644
index 0000000000..33bf705e65
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/HeaderTest.cpp
@@ -0,0 +1,110 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include <iostream>
+#include "qpid/framing/amqp_framing.h"
+#include "qpid/framing/FieldValue.h"
+#include "unit_test.h"
+
+using namespace qpid::framing;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(HeaderTestSuite)
+
+QPID_AUTO_TEST_CASE(testGenericProperties)
+{
+ AMQHeaderBody body;
+ body.get<MessageProperties>(true)->getApplicationHeaders().setString(
+ "A", "BCDE");
+ char buff[100];
+ Buffer wbuffer(buff, 100);
+ body.encode(wbuffer);
+
+ Buffer rbuffer(buff, 100);
+ AMQHeaderBody body2;
+ body2.decode(rbuffer, body.encodedSize());
+ MessageProperties* props =
+ body2.get<MessageProperties>(true);
+ BOOST_CHECK_EQUAL(
+ string("BCDE"),
+ props->getApplicationHeaders().get("A")->get<string>());
+}
+
+QPID_AUTO_TEST_CASE(testMessageProperties)
+{
+ AMQFrame out(in_place<AMQHeaderBody>());
+ MessageProperties* props1 =
+ out.castBody<AMQHeaderBody>()->get<MessageProperties>(true);
+
+ props1->setContentLength(42);
+ props1->setMessageId(Uuid(true));
+ props1->setCorrelationId("correlationId");
+ props1->setReplyTo(ReplyTo("ex","key"));
+ props1->setContentType("contentType");
+ props1->setContentEncoding("contentEncoding");
+ props1->setUserId("userId");
+ props1->setAppId("appId");
+
+ char buff[10000];
+ Buffer wbuffer(buff, 10000);
+ out.encode(wbuffer);
+
+ Buffer rbuffer(buff, 10000);
+ AMQFrame in;
+ in.decode(rbuffer);
+ MessageProperties* props2 =
+ in.castBody<AMQHeaderBody>()->get<MessageProperties>(true);
+
+ BOOST_CHECK_EQUAL(props1->getContentLength(), props2->getContentLength());
+ BOOST_CHECK_EQUAL(props1->getMessageId(), props2->getMessageId());
+ BOOST_CHECK_EQUAL(props1->getCorrelationId(), props2->getCorrelationId());
+ BOOST_CHECK_EQUAL(props1->getContentType(), props2->getContentType());
+ BOOST_CHECK_EQUAL(props1->getContentEncoding(), props2->getContentEncoding());
+ BOOST_CHECK_EQUAL(props1->getUserId(), props2->getUserId());
+ BOOST_CHECK_EQUAL(props1->getAppId(), props2->getAppId());
+
+}
+
+QPID_AUTO_TEST_CASE(testDeliveryProperies)
+{
+ AMQFrame out(in_place<AMQHeaderBody>());
+ DeliveryProperties* props1 =
+ out.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true);
+
+ props1->setDiscardUnroutable(true);
+ props1->setExchange("foo");
+
+ char buff[10000];
+ Buffer wbuffer(buff, 10000);
+ out.encode(wbuffer);
+
+ Buffer rbuffer(buff, 10000);
+ AMQFrame in;
+ in.decode(rbuffer);
+ DeliveryProperties* props2 =
+ in.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true);
+
+ BOOST_CHECK(props2->getDiscardUnroutable());
+ BOOST_CHECK_EQUAL(string("foo"), props2->getExchange());
+ BOOST_CHECK(!props2->hasTimestamp());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/HeadersExchangeTest.cpp b/RC9/qpid/cpp/src/tests/HeadersExchangeTest.cpp
new file mode 100644
index 0000000000..46933f955a
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/HeadersExchangeTest.cpp
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/Exception.h"
+#include "qpid/broker/HeadersExchange.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/framing/FieldValue.h"
+#include "unit_test.h"
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+QPID_AUTO_TEST_SUITE(HeadersExchangeTestSuite)
+
+QPID_AUTO_TEST_CASE(testMatchAll)
+{
+ FieldTable b, m, n;
+ b.setString("x-match", "all");
+ b.setString("foo", "FOO");
+ b.setInt("n", 42);
+ m.setString("foo", "FOO");
+ m.setInt("n", 42);
+ BOOST_CHECK(HeadersExchange::match(b, m));
+
+ // Ignore extras.
+ m.setString("extra", "x");
+ BOOST_CHECK(HeadersExchange::match(b, m));
+
+ // Fail mismatch, wrong value.
+ m.setString("foo", "NotFoo");
+ BOOST_CHECK(!HeadersExchange::match(b, m));
+
+ // Fail mismatch, missing value
+ n.setInt("n", 42);
+ n.setString("extra", "x");
+ BOOST_CHECK(!HeadersExchange::match(b, n));
+}
+
+QPID_AUTO_TEST_CASE(testMatchAny)
+{
+ FieldTable b, m, n;
+ b.setString("x-match", "any");
+ b.setString("foo", "FOO");
+ b.setInt("n", 42);
+ m.setString("foo", "FOO");
+ BOOST_CHECK(!HeadersExchange::match(b, n));
+ BOOST_CHECK(HeadersExchange::match(b, m));
+ m.setInt("n", 42);
+ BOOST_CHECK(HeadersExchange::match(b, m));
+}
+
+QPID_AUTO_TEST_CASE(testMatchEmptyValue)
+{
+ FieldTable b, m;
+ b.setString("x-match", "all");
+ b.set("foo", FieldTable::ValuePtr());
+ b.set("n", FieldTable::ValuePtr());
+ BOOST_CHECK(!HeadersExchange::match(b, m));
+ m.setString("foo", "blah");
+ m.setInt("n", 123);
+}
+
+QPID_AUTO_TEST_CASE(testMatchEmptyArgs)
+{
+ FieldTable b, m;
+ m.setString("foo", "FOO");
+
+ b.setString("x-match", "all");
+ BOOST_CHECK(HeadersExchange::match(b, m));
+ b.setString("x-match", "any");
+ BOOST_CHECK(!HeadersExchange::match(b, m));
+}
+
+
+QPID_AUTO_TEST_CASE(testMatchNoXMatch)
+{
+ FieldTable b, m;
+ b.setString("foo", "FOO");
+ m.setString("foo", "FOO");
+ BOOST_CHECK(!HeadersExchange::match(b, m));
+}
+
+QPID_AUTO_TEST_CASE(testBindNoXMatch)
+{
+ HeadersExchange exchange("test");
+ Queue::shared_ptr queue;
+ std::string key;
+ FieldTable args;
+ try {
+ //just checking this doesn't cause assertion etc
+ exchange.bind(queue, key, &args);
+ } catch(qpid::Exception&) {
+ //expected
+ }
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/IncompleteMessageList.cpp b/RC9/qpid/cpp/src/tests/IncompleteMessageList.cpp
new file mode 100644
index 0000000000..925cdbf43e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/IncompleteMessageList.cpp
@@ -0,0 +1,128 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include <iostream>
+#include <sstream>
+#include "qpid/broker/Message.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/IncompleteMessageList.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(IncompleteMessageListTestSuite)
+
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+struct Checker
+{
+ std::list<SequenceNumber> ids;
+
+ Checker() { }
+
+ Checker(uint start, uint end) {
+ for (uint i = start; i <= end; i++) {
+ ids.push_back(i);
+ }
+ }
+
+ Checker& expect(const SequenceNumber& id) {
+ ids.push_back(id);
+ return *this;
+ }
+
+ void operator()(boost::intrusive_ptr<Message> msg) {
+ BOOST_CHECK(!ids.empty());
+ BOOST_CHECK_EQUAL(msg->getCommandId(), ids.front());
+ ids.pop_front();
+ }
+};
+
+QPID_AUTO_TEST_CASE(testProcessSimple)
+{
+ IncompleteMessageList list;
+ SequenceNumber counter(1);
+ //fill up list with messages
+ for (int i = 0; i < 5; i++) {
+ boost::intrusive_ptr<Message> msg(new Message(counter++));
+ list.add(msg);
+ }
+ //process and ensure they are all passed to completion listener
+ list.process(Checker(1, 5), false);
+ //process again and ensure none are resent to listener
+ list.process(Checker(), false);
+}
+
+QPID_AUTO_TEST_CASE(testProcessWithIncomplete)
+{
+ IncompleteMessageList list;
+ SequenceNumber counter(1);
+ boost::intrusive_ptr<Message> middle;
+ //fill up list with messages
+ for (int i = 0; i < 5; i++) {
+ boost::intrusive_ptr<Message> msg(new Message(counter++));
+ list.add(msg);
+ if (i == 2) {
+ //mark a message in the middle as incomplete
+ msg->enqueueAsync();
+ middle = msg;
+ }
+ }
+ //process and ensure only message upto incomplete message are passed to listener
+ list.process(Checker(1, 2), false);
+ //mark message complete and re-process to get remaining messages sent to listener
+ middle->enqueueComplete();
+ list.process(Checker(3, 5), false);
+}
+
+
+struct MockStore : public NullMessageStore
+{
+ Queue::shared_ptr queue;
+ boost::intrusive_ptr<Message> msg;
+
+ void flush(const qpid::broker::PersistableQueue& q) {
+ BOOST_CHECK_EQUAL(queue.get(), &q);
+ msg->enqueueComplete();
+ }
+};
+
+QPID_AUTO_TEST_CASE(testSyncProcessWithIncomplete)
+{
+ IncompleteMessageList list;
+ SequenceNumber counter(1);
+ MockStore store;
+ store.queue = Queue::shared_ptr(new Queue("mock-queue"));
+ //fill up list with messages
+ for (int i = 0; i < 5; i++) {
+ boost::intrusive_ptr<Message> msg(new Message(counter++));
+ list.add(msg);
+ if (i == 2) {
+ //mark a message in the middle as incomplete
+ msg->enqueueAsync(store.queue, &store);
+ store.msg = msg;
+ }
+ }
+ //process with sync bit specified and ensure that all messages are passed to listener
+ list.process(Checker(1, 5), true);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/InlineAllocator.cpp b/RC9/qpid/cpp/src/tests/InlineAllocator.cpp
new file mode 100644
index 0000000000..fe6eaefaf4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/InlineAllocator.cpp
@@ -0,0 +1,63 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/InlineAllocator.h"
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(InlineAllocatorTestSuite)
+
+using namespace qpid;
+using namespace std;
+
+QPID_AUTO_TEST_CASE(testAllocate) {
+ InlineAllocator<std::allocator<char>, 2> alloc;
+
+ char* p = alloc.allocate(1);
+ BOOST_CHECK(p == (char*)&alloc);
+ alloc.deallocate(p,1);
+
+ p = alloc.allocate(2);
+ BOOST_CHECK(p == (char*)&alloc);
+ alloc.deallocate(p,2);
+
+ p = alloc.allocate(3);
+ BOOST_CHECK(p != (char*)&alloc);
+ alloc.deallocate(p,3);
+}
+
+QPID_AUTO_TEST_CASE(testAllocateFull) {
+ InlineAllocator<std::allocator<char>, 1> alloc;
+
+ char* p = alloc.allocate(1);
+ BOOST_CHECK(p == (char*)&alloc);
+
+ char* q = alloc.allocate(1);
+ BOOST_CHECK(q != (char*)&alloc);
+
+ alloc.deallocate(p,1);
+ p = alloc.allocate(1);
+ BOOST_CHECK(p == (char*)&alloc);
+
+ alloc.deallocate(p,1);
+ alloc.deallocate(q,1);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/InlineVector.cpp b/RC9/qpid/cpp/src/tests/InlineVector.cpp
new file mode 100644
index 0000000000..bcd36e47b4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/InlineVector.cpp
@@ -0,0 +1,119 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/InlineVector.h"
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(InlineVectorTestSuite)
+
+using namespace qpid;
+using namespace std;
+
+typedef InlineVector<int, 3> Vec;
+
+bool isInline(const Vec& v) {
+ return (const char*)&v <= (const char*)(&v[0]) &&
+ (const char*)(&v[0]) < (const char*)&v+sizeof(v);
+}
+
+QPID_AUTO_TEST_CASE(testCtor) {
+ {
+ Vec v;
+ BOOST_CHECK(isInline(v));
+ BOOST_CHECK(v.empty());
+ }
+ {
+ Vec v(3, 42);
+ BOOST_CHECK(isInline(v));
+ BOOST_CHECK_EQUAL(3u, v.size());
+ BOOST_CHECK_EQUAL(v[0], 42);
+ BOOST_CHECK_EQUAL(v[2], 42);
+
+ Vec u(v);
+ BOOST_CHECK(isInline(u));
+ BOOST_CHECK_EQUAL(3u, u.size());
+ BOOST_CHECK_EQUAL(u[0], 42);
+ BOOST_CHECK_EQUAL(u[2], 42);
+ }
+
+ {
+ Vec v(4, 42);
+
+ BOOST_CHECK_EQUAL(v.size(), 4u);
+ BOOST_CHECK(!isInline(v));
+ Vec u(v);
+ BOOST_CHECK_EQUAL(u.size(), 4u);
+ BOOST_CHECK(!isInline(u));
+ }
+}
+
+QPID_AUTO_TEST_CASE(testInsert) {
+ {
+ Vec v;
+ v.push_back(1);
+ BOOST_CHECK_EQUAL(v.size(), 1u);
+ BOOST_CHECK_EQUAL(v.back(), 1);
+ BOOST_CHECK(isInline(v));
+
+ v.insert(v.begin(), 2);
+ BOOST_CHECK_EQUAL(v.size(), 2u);
+ BOOST_CHECK_EQUAL(v.back(), 1);
+ BOOST_CHECK(isInline(v));
+
+ v.push_back(3);
+ BOOST_CHECK(isInline(v));
+
+ v.push_back(4);
+
+ BOOST_CHECK(!isInline(v));
+ }
+ {
+ Vec v(3,42);
+ v.insert(v.begin(), 9);
+ BOOST_CHECK_EQUAL(v.size(), 4u);
+ BOOST_CHECK(!isInline(v));
+ }
+ {
+ Vec v(3,42);
+ v.insert(v.begin()+1, 9);
+ BOOST_CHECK(!isInline(v));
+ BOOST_CHECK_EQUAL(v.size(), 4u);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testAssign) {
+ Vec v(3,42);
+ Vec u;
+ u = v;
+ BOOST_CHECK(isInline(u));
+ u.push_back(4);
+ BOOST_CHECK(!isInline(u));
+ v = u;
+ BOOST_CHECK(!isInline(v));
+}
+
+QPID_AUTO_TEST_CASE(testResize) {
+ Vec v;
+ v.resize(5);
+ BOOST_CHECK(!isInline(v));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/Makefile.am b/RC9/qpid/cpp/src/tests/Makefile.am
new file mode 100644
index 0000000000..3a608b2bae
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Makefile.am
@@ -0,0 +1,245 @@
+#
+# 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.
+#
+
+AM_CXXFLAGS = $(WARNING_CFLAGS) -DBOOST_TEST_DYN_LINK
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../gen -I$(top_builddir)/src/gen
+
+abs_builddir=@abs_builddir@
+extra_libs =
+lib_client = $(abs_builddir)/../libqpidclient.la
+lib_common = $(abs_builddir)/../libqpidcommon.la
+lib_broker = $(abs_builddir)/../libqpidbroker.la
+lib_console = $(abs_builddir)/../libqmfconsole.la
+# lib_amqp_0_10 = $(abs_builddir)/../libqpidamqp_0_10.la
+
+#
+# Initialize variables that are incremented with +=
+#
+check_PROGRAMS=
+check_LTLIBRARIES=
+TESTS=
+EXTRA_DIST=
+CLEANFILES=
+
+#
+# Unit test program
+#
+# Unit tests are built as a single program to reduce valgrind overhead
+# when running the tests. If you want to build a subset of the tests do
+# rm -f unit_test; make unit_test unit_test_OBJECTS="unit_test.o SelectedTest.o"
+#
+
+TESTS+=unit_test
+check_PROGRAMS+=unit_test
+unit_test_LDADD=-lboost_unit_test_framework -lboost_regex \
+ $(lib_client) $(lib_broker) $(lib_console)
+
+unit_test_SOURCES= unit_test.cpp unit_test.h \
+ BrokerFixture.h SocketProxy.h \
+ exception_test.cpp \
+ RefCounted.cpp \
+ SessionState.cpp Blob.cpp logging.cpp \
+ AsyncCompletion.cpp \
+ Url.cpp Uuid.cpp \
+ Shlib.cpp FieldValue.cpp FieldTable.cpp Array.cpp \
+ QueueOptionsTest.cpp \
+ InlineAllocator.cpp \
+ InlineVector.cpp \
+ ClientSessionTest.cpp \
+ SequenceSet.cpp \
+ StringUtils.cpp \
+ IncompleteMessageList.cpp \
+ RangeSet.cpp \
+ AtomicValue.cpp \
+ QueueTest.cpp \
+ AccumulatedAckTest.cpp \
+ DtxWorkRecordTest.cpp \
+ DeliveryRecordTest.cpp \
+ ExchangeTest.cpp \
+ HeadersExchangeTest.cpp \
+ MessageTest.cpp \
+ QueueRegistryTest.cpp \
+ QueuePolicyTest.cpp \
+ FramingTest.cpp \
+ HeaderTest.cpp \
+ SequenceNumberTest.cpp \
+ TimerTest.cpp \
+ TopicExchangeTest.cpp \
+ TxBufferTest.cpp \
+ TxPublishTest.cpp \
+ MessageBuilderTest.cpp \
+ ConnectionOptions.h \
+ ForkedBroker.h \
+ ManagementTest.cpp \
+ MessageReplayTracker.cpp \
+ ConsoleTest.cpp
+
+if HAVE_XML
+unit_test_SOURCES+= XmlClientSessionTest.cpp
+endif
+
+
+# Disabled till we move to amqp_0_10 codec.
+# amqp_0_10/serialize.cpp allSegmentTypes.h \
+# amqp_0_10/ProxyTemplate.cpp \
+# amqp_0_10/apply.cpp \
+# amqp_0_10/Map.cpp \
+# amqp_0_10/handlers.cpp
+
+
+check_LTLIBRARIES += libshlibtest.la
+libshlibtest_la_LDFLAGS = -module -rpath $(abs_builddir)
+libshlibtest_la_SOURCES = shlibtest.cpp
+
+include cluster.mk
+if SSL
+include ssl.mk
+endif
+
+#
+# Other test programs
+#
+check_PROGRAMS+=perftest
+perftest_SOURCES=perftest.cpp test_tools.h TestOptions.h ConnectionOptions.h
+perftest_LDADD=$(lib_client)
+
+check_PROGRAMS+=txtest
+txtest_SOURCES=txtest.cpp TestOptions.h ConnectionOptions.h
+txtest_LDADD=$(lib_client)
+
+check_PROGRAMS+=latencytest
+latencytest_SOURCES=latencytest.cpp TestOptions.h ConnectionOptions.h
+latencytest_LDADD=$(lib_client)
+
+check_PROGRAMS+=echotest
+echotest_SOURCES=echotest.cpp TestOptions.h ConnectionOptions.h
+echotest_LDADD=$(lib_client)
+
+check_PROGRAMS+=client_test
+client_test_SOURCES=client_test.cpp TestOptions.h ConnectionOptions.h
+client_test_LDADD=$(lib_client)
+
+check_PROGRAMS+=topic_listener
+topic_listener_SOURCES=topic_listener.cpp TestOptions.h ConnectionOptions.h
+topic_listener_LDADD=$(lib_client)
+
+check_PROGRAMS+=topic_publisher
+topic_publisher_SOURCES=topic_publisher.cpp TestOptions.h ConnectionOptions.h
+topic_publisher_LDADD=$(lib_client)
+
+check_PROGRAMS+=publish
+publish_SOURCES=publish.cpp TestOptions.h ConnectionOptions.h
+publish_LDADD=$(lib_client)
+
+check_PROGRAMS+=consume
+consume_SOURCES=consume.cpp TestOptions.h ConnectionOptions.h
+consume_LDADD=$(lib_client)
+
+check_PROGRAMS+=header_test
+header_test_SOURCES=header_test.cpp TestOptions.h ConnectionOptions.h
+header_test_LDADD=$(lib_client)
+
+check_PROGRAMS+=failover_soak
+failover_soak_SOURCES=failover_soak.cpp ForkedBroker.h
+failover_soak_LDADD=$(lib_client)
+
+check_PROGRAMS+=declare_queues
+declare_queues_SOURCES=declare_queues.cpp
+declare_queues_LDADD=$(lib_client)
+
+check_PROGRAMS+=replaying_sender
+replaying_sender_SOURCES=replaying_sender.cpp
+replaying_sender_LDADD=$(lib_client)
+
+check_PROGRAMS+=resuming_receiver
+resuming_receiver_SOURCES=resuming_receiver.cpp
+resuming_receiver_LDADD=$(lib_client)
+
+check_PROGRAMS+=txshift
+txshift_SOURCES=txshift.cpp TestOptions.h ConnectionOptions.h
+txshift_LDADD=$(lib_client)
+
+check_PROGRAMS+=txjob
+txjob_SOURCES=txjob.cpp TestOptions.h ConnectionOptions.h
+txjob_LDADD=$(lib_client)
+
+check_PROGRAMS+=receiver
+receiver_SOURCES=receiver.cpp TestOptions.h ConnectionOptions.h
+receiver_LDADD=$(lib_client)
+
+check_PROGRAMS+=sender
+sender_SOURCES=sender.cpp TestOptions.h ConnectionOptions.h
+sender_LDADD=$(lib_client)
+
+
+TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir) QPID_DATA_DIR= BOOST_TEST_SHOW_PROGRESS=yes $(srcdir)/run_test
+
+system_tests = client_test quick_perftest quick_topictest run_header_test quick_txtest
+TESTS += start_broker $(system_tests) python_tests stop_broker run_federation_tests run_acl_tests
+
+EXTRA_DIST += \
+ run_test vg_check \
+ run-unit-tests start_broker python_tests stop_broker \
+ quick_topictest \
+ quick_perftest \
+ quick_txtest \
+ topictest \
+ run_header_test \
+ header_test.py \
+ ssl_test \
+ config.null \
+ ais_check \
+ run_federation_tests \
+ run_acl_tests \
+ .valgrind.supp \
+ MessageUtils.h \
+ TestMessageStore.h \
+ TxMocks.h \
+ start_cluster stop_cluster restart_cluster
+
+check_LTLIBRARIES += libdlclose_noop.la
+libdlclose_noop_la_LDFLAGS = -module -rpath $(abs_builddir)
+libdlclose_noop_la_SOURCES = dlclose_noop.c
+
+CLEANFILES+=valgrind.out *.log *.vglog* dummy_test $(unit_wrappers)
+
+# FIXME aconway 2008-05-23: Disabled interop_runner because it uses
+# the obsolete Channel class. Convert to Session and re-enable.
+#
+# check_PROGRAMS += interop_runner
+
+# interop_runner_SOURCES = \
+# interop_runner.cpp \
+# SimpleTestCaseBase.cpp \
+# BasicP2PTest.cpp \
+# BasicPubSubTest.cpp \
+# SimpleTestCaseBase.h \
+# BasicP2PTest.h \
+# BasicPubSubTest.h \
+# TestCase.h \
+# TestOptions.h ConnectionOptions.h
+# interop_runner_LDADD = $(lib_client) $(lib_common) $(extra_libs)
+
+
+# Longer running stability tests, not run by default check: target.
+# Not run under valgrind, too slow
+LONG_TESTS=fanout_perftest shared_perftest multiq_perftest topic_perftest run_failover_soak
+EXTRA_DIST+=$(LONG_TESTS) run_perftest
+check-long:
+ $(MAKE) check TESTS="start_broker $(LONG_TESTS) stop_broker" VALGRIND=
diff --git a/RC9/qpid/cpp/src/tests/ManagementTest.cpp b/RC9/qpid/cpp/src/tests/ManagementTest.cpp
new file mode 100644
index 0000000000..a3d29ec22c
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ManagementTest.cpp
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/management/ManagementObject.h"
+#include "qpid/framing/Buffer.h"
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(ManagementTestSuite)
+
+using namespace qpid::framing;
+using namespace qpid::management;
+
+QPID_AUTO_TEST_CASE(testObjectIdSerializeStream) {
+ std::string text("0-10-4-2500-80000000000");
+ std::stringstream input(text);
+
+ ObjectId oid(input);
+
+ std::stringstream output;
+ output << oid;
+
+ BOOST_CHECK_EQUAL(text, output.str());
+}
+
+QPID_AUTO_TEST_CASE(testObjectIdSerializeString) {
+ std::string text("0-10-4-2500-80000000000");
+
+ ObjectId oid(text);
+
+ std::stringstream output;
+ output << oid;
+
+ BOOST_CHECK_EQUAL(text, output.str());
+}
+
+QPID_AUTO_TEST_CASE(testObjectIdEncode) {
+ char buffer[100];
+ Buffer msgBuf(buffer, 100);
+ msgBuf.putLongLong(0x1002000030000004LL);
+ msgBuf.putLongLong(0x0000000000000005LL);
+ msgBuf.reset();
+
+ ObjectId oid(msgBuf);
+
+ std::stringstream out1;
+ out1 << oid;
+
+ BOOST_CHECK_EQUAL(out1.str(), "1-2-3-4-5");
+}
+
+QPID_AUTO_TEST_CASE(testObjectIdAttach) {
+ AgentAttachment agent;
+ ObjectId oid(&agent, 10, 20, 50);
+
+ std::stringstream out1;
+ out1 << oid;
+ BOOST_CHECK_EQUAL(out1.str(), "10-20-0-0-50");
+
+ agent.setBanks(30, 40);
+ std::stringstream out2;
+ out2 << oid;
+ BOOST_CHECK_EQUAL(out2.str(), "10-20-30-40-50");
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/MessageBuilderTest.cpp b/RC9/qpid/cpp/src/tests/MessageBuilderTest.cpp
new file mode 100644
index 0000000000..313a91c053
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/MessageBuilderTest.cpp
@@ -0,0 +1,224 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/broker/Message.h"
+#include "qpid/broker/MessageBuilder.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/framing/frame_functors.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/TypeFilter.h"
+#include "unit_test.h"
+#include <list>
+
+using namespace boost;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+class MockMessageStore : public NullMessageStore
+{
+ enum Op {STAGE=1, APPEND=2};
+
+ uint64_t id;
+ intrusive_ptr<PersistableMessage> expectedMsg;
+ string expectedData;
+ std::list<Op> ops;
+
+ void checkExpectation(Op actual)
+ {
+ BOOST_CHECK_EQUAL(ops.front(), actual);
+ ops.pop_front();
+ }
+
+ public:
+ MockMessageStore() : id(0), expectedMsg(0) {}
+
+ void expectStage(PersistableMessage& msg)
+ {
+ expectedMsg = &msg;
+ ops.push_back(STAGE);
+ }
+
+ void expectAppendContent(PersistableMessage& msg, const string& data)
+ {
+ expectedMsg = &msg;
+ expectedData = data;
+ ops.push_back(APPEND);
+ }
+
+ void stage(const intrusive_ptr<PersistableMessage>& msg)
+ {
+ checkExpectation(STAGE);
+ BOOST_CHECK_EQUAL(expectedMsg, msg);
+ msg->setPersistenceId(++id);
+ }
+
+ void appendContent(const intrusive_ptr<const PersistableMessage>& msg,
+ const string& data)
+ {
+ checkExpectation(APPEND);
+ BOOST_CHECK_EQUAL(static_pointer_cast<const PersistableMessage>(expectedMsg), msg);
+ BOOST_CHECK_EQUAL(expectedData, data);
+ }
+
+ bool expectationsMet()
+ {
+ return ops.empty();
+ }
+
+ //don't treat this store as a null impl
+ bool isNull() const
+ {
+ return false;
+ }
+
+};
+
+QPID_AUTO_TEST_SUITE(MessageBuilderTestSuite)
+
+QPID_AUTO_TEST_CASE(testHeaderOnly)
+{
+ MessageBuilder builder(0, 0);
+ builder.start(SequenceNumber());
+
+ std::string exchange("builder-exchange");
+ std::string key("builder-exchange");
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(0);
+ header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
+
+ builder.handle(method);
+ builder.handle(header);
+
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK_EQUAL(exchange, builder.getMessage()->getExchangeName());
+ BOOST_CHECK_EQUAL(key, builder.getMessage()->getRoutingKey());
+ BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
+}
+
+QPID_AUTO_TEST_CASE(test1ContentFrame)
+{
+ MessageBuilder builder(0, 0);
+ builder.start(SequenceNumber());
+
+ std::string data("abcdefg");
+ std::string exchange("builder-exchange");
+ std::string key("builder-exchange");
+
+ AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame content(in_place<AMQContentBody>(data));
+ method.setEof(false);
+ header.setBof(false);
+ header.setEof(false);
+ content.setBof(false);
+
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data.size());
+ header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
+
+ builder.handle(method);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
+
+ builder.handle(header);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
+
+ builder.handle(content);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
+}
+
+QPID_AUTO_TEST_CASE(test2ContentFrames)
+{
+ MessageBuilder builder(0, 0);
+ builder.start(SequenceNumber());
+
+ std::string data1("abcdefg");
+ std::string data2("hijklmn");
+ std::string exchange("builder-exchange");
+ std::string key("builder-exchange");
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame content1(in_place<AMQContentBody>(data1));
+ AMQFrame content2(in_place<AMQContentBody>(data2));
+ method.setEof(false);
+ header.setBof(false);
+ header.setEof(false);
+ content1.setBof(false);
+ content1.setEof(false);
+ content2.setBof(false);
+
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
+ header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
+
+ builder.handle(method);
+ builder.handle(header);
+ builder.handle(content1);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(!builder.getMessage()->getFrames().isComplete());
+
+ builder.handle(content2);
+ BOOST_CHECK(builder.getMessage());
+ BOOST_CHECK(builder.getMessage()->getFrames().isComplete());
+}
+
+QPID_AUTO_TEST_CASE(testStaging)
+{
+ MockMessageStore store;
+ MessageBuilder builder(&store, 5);
+ builder.start(SequenceNumber());
+
+ std::string data1("abcdefg");
+ std::string data2("hijklmn");
+ std::string exchange("builder-exchange");
+ std::string key("builder-exchange");
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame content1(in_place<AMQContentBody>(data1));
+ AMQFrame content2(in_place<AMQContentBody>(data2));
+
+ header.castBody<AMQHeaderBody>()->get<MessageProperties>(true)->setContentLength(data1.size() + data2.size());
+ header.castBody<AMQHeaderBody>()->get<DeliveryProperties>(true)->setRoutingKey(key);
+
+ builder.handle(method);
+ builder.handle(header);
+
+ store.expectStage(*builder.getMessage());
+ builder.handle(content1);
+ BOOST_CHECK(store.expectationsMet());
+ BOOST_CHECK_EQUAL((uint64_t) 1, builder.getMessage()->getPersistenceId());
+
+ store.expectAppendContent(*builder.getMessage(), data2);
+ builder.handle(content2);
+ BOOST_CHECK(store.expectationsMet());
+ //were the content frames dropped?
+ BOOST_CHECK(!builder.getMessage()->isContentLoaded());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/MessageReplayTracker.cpp b/RC9/qpid/cpp/src/tests/MessageReplayTracker.cpp
new file mode 100644
index 0000000000..a5121cdeb7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/MessageReplayTracker.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "unit_test.h"
+#include "BrokerFixture.h"
+#include "qpid/client/MessageReplayTracker.h"
+#include "qpid/sys/Time.h"
+
+QPID_AUTO_TEST_SUITE(MessageReplayTrackerTests)
+
+using namespace qpid::client;
+using namespace qpid::sys;
+using std::string;
+
+class ReplayBufferChecker
+{
+ public:
+
+ ReplayBufferChecker(uint from, uint to) : end(to), i(from) {}
+
+ void operator()(const Message& m)
+ {
+ if (i > end) BOOST_FAIL("Extra message found: " + m.getData());
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i++)).str(), m.getData());
+ }
+ private:
+ const uint end;
+ uint i;
+
+};
+
+QPID_AUTO_TEST_CASE(testReplay)
+{
+ ProxySessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ MessageReplayTracker tracker(10);
+ tracker.init(fix.session);
+ for (uint i = 0; i < 5; i++) {
+ Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ tracker.send(message);
+ }
+ ReplayBufferChecker checker(1, 10);
+ tracker.foreach(checker);
+
+ tracker.replay(fix.session);
+ for (uint j = 0; j < 2; j++) {//each message should have been sent twice
+ for (uint i = 0; i < 5; i++) {
+ Message m;
+ BOOST_CHECK(fix.subs.get(m, "my-queue", TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), m.getData());
+ }
+ }
+ Message m;
+ BOOST_CHECK(!fix.subs.get(m, "my-queue"));
+}
+
+QPID_AUTO_TEST_CASE(testCheckCompletion)
+{
+ ProxySessionFixture fix;
+ fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true);
+
+ MessageReplayTracker tracker(10);
+ tracker.init(fix.session);
+ for (uint i = 0; i < 5; i++) {
+ Message message((boost::format("Message_%1%") % (i+1)).str(), "my-queue");
+ tracker.send(message);
+ }
+ fix.session.sync();//ensures all messages are complete
+ tracker.checkCompletion();
+ tracker.replay(fix.session);
+ Message received;
+ for (uint i = 0; i < 5; i++) {
+ BOOST_CHECK(fix.subs.get(received, "my-queue"));
+ BOOST_CHECK_EQUAL((boost::format("Message_%1%") % (i+1)).str(), received.getData());
+ }
+ BOOST_CHECK(!fix.subs.get(received, "my-queue"));
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/MessageTest.cpp b/RC9/qpid/cpp/src/tests/MessageTest.cpp
new file mode 100644
index 0000000000..f9292ee53e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/MessageTest.cpp
@@ -0,0 +1,90 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/broker/Message.h"
+#include "qpid/framing/AMQP_HighestVersion.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/FieldValue.h"
+#include "qpid/framing/Uuid.h"
+
+#include "unit_test.h"
+
+#include <iostream>
+#include <alloca.h>
+
+using namespace boost;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+QPID_AUTO_TEST_SUITE(MessageTestSuite)
+
+QPID_AUTO_TEST_CASE(testEncodeDecode)
+{
+ string exchange = "MyExchange";
+ string routingKey = "MyRoutingKey";
+ Uuid messageId(true);
+ string data1("abcdefg");
+ string data2("hijklmn");
+
+ intrusive_ptr<Message> msg(new Message());
+
+ AMQFrame method(in_place<MessageTransferBody>(
+ ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ AMQFrame content1(in_place<AMQContentBody>(data1));
+ AMQFrame content2(in_place<AMQContentBody>(data2));
+
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ msg->getFrames().append(content1);
+ msg->getFrames().append(content2);
+
+ MessageProperties* mProps = msg->getFrames().getHeaders()->get<MessageProperties>(true);
+ mProps->setContentLength(data1.size() + data2.size());
+ mProps->setMessageId(messageId);
+ FieldTable applicationHeaders;
+ applicationHeaders.setString("abc", "xyz");
+ mProps->setApplicationHeaders(applicationHeaders);
+ DeliveryProperties* dProps = msg->getFrames().getHeaders()->get<DeliveryProperties>(true);
+ dProps->setRoutingKey(routingKey);
+ dProps->setDeliveryMode(PERSISTENT);
+ BOOST_CHECK(msg->isPersistent());
+
+ char* buff = static_cast<char*>(::alloca(msg->encodedSize()));
+ Buffer wbuffer(buff, msg->encodedSize());
+ msg->encode(wbuffer);
+
+ Buffer rbuffer(buff, msg->encodedSize());
+ msg = new Message();
+ msg->decodeHeader(rbuffer);
+ msg->decodeContent(rbuffer);
+ BOOST_CHECK_EQUAL(exchange, msg->getExchangeName());
+ BOOST_CHECK_EQUAL(routingKey, msg->getRoutingKey());
+ BOOST_CHECK_EQUAL((uint64_t) data1.size() + data2.size(), msg->contentSize());
+ BOOST_CHECK_EQUAL((uint64_t) data1.size() + data2.size(), msg->getProperties<MessageProperties>()->getContentLength());
+ BOOST_CHECK_EQUAL(messageId, msg->getProperties<MessageProperties>()->getMessageId());
+ BOOST_CHECK_EQUAL(string("xyz"), msg->getProperties<MessageProperties>()->getApplicationHeaders().getAsString("abc"));
+ BOOST_CHECK_EQUAL((uint8_t) PERSISTENT, msg->getProperties<DeliveryProperties>()->getDeliveryMode());
+ BOOST_CHECK(msg->isPersistent());
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/MessageUtils.h b/RC9/qpid/cpp/src/tests/MessageUtils.h
new file mode 100644
index 0000000000..81508e534e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/MessageUtils.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/broker/Message.h"
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/Uuid.h"
+
+using namespace qpid;
+using namespace broker;
+using namespace framing;
+
+struct MessageUtils
+{
+ static boost::intrusive_ptr<Message> createMessage(const string& exchange="", const string& routingKey="",
+ const Uuid& messageId=Uuid(true), uint64_t contentSize = 0)
+ {
+ boost::intrusive_ptr<Message> msg(new Message());
+
+ AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ MessageProperties* props = msg->getFrames().getHeaders()->get<MessageProperties>(true);
+ props->setContentLength(contentSize);
+ props->setMessageId(messageId);
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ return msg;
+ }
+
+ static void addContent(boost::intrusive_ptr<Message> msg, const string& data)
+ {
+ AMQFrame content(in_place<AMQContentBody>(data));
+ msg->getFrames().append(content);
+ }
+};
diff --git a/RC9/qpid/cpp/src/tests/PollerTest.cpp b/RC9/qpid/cpp/src/tests/PollerTest.cpp
new file mode 100644
index 0000000000..fcb1d0dadf
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/PollerTest.cpp
@@ -0,0 +1,164 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Use socketpair to test the poller
+ */
+
+#include "qpid/sys/Poller.h"
+
+#include <string>
+#include <iostream>
+#include <memory>
+#include <exception>
+
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+using namespace std;
+using namespace qpid::sys;
+
+int writeALot(int fd, const string& s) {
+ int bytesWritten = 0;
+ do {
+ errno = 0;
+ int lastWrite = ::write(fd, s.c_str(), s.size());
+ if ( lastWrite >= 0) {
+ bytesWritten += lastWrite;
+ }
+ } while (errno != EAGAIN);
+ return bytesWritten;
+}
+
+int readALot(int fd) {
+ int bytesRead = 0;
+ char buf[1024];
+
+ do {
+ errno = 0;
+ int lastRead = ::read(fd, buf, sizeof(buf));
+ if ( lastRead >= 0) {
+ bytesRead += lastRead;
+ }
+ } while (errno != EAGAIN);
+ return bytesRead;
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ int sv[2];
+ int rc = ::socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
+ assert(rc >= 0);
+
+ // Set non-blocking
+ rc = ::fcntl(sv[0], F_SETFL, O_NONBLOCK);
+ assert(rc >= 0);
+
+ rc = ::fcntl(sv[1], F_SETFL, O_NONBLOCK);
+ assert(rc >= 0);
+
+ // Make up a large string
+ string testString = "This is only a test ... 1,2,3,4,5,6,7,8,9,10;";
+ for (int i = 0; i < 6; i++)
+ testString += testString;
+
+ // Read as much as we can from socket 0
+ int bytesRead = readALot(sv[0]);
+ assert(bytesRead == 0);
+ cout << "Read(0): " << bytesRead << " bytes\n";
+
+ // Write as much as we can to socket 0
+ int bytesWritten = writeALot(sv[0], testString);
+ cout << "Wrote(0): " << bytesWritten << " bytes\n";
+
+ // Read as much as we can from socket 1
+ bytesRead = readALot(sv[1]);
+ assert(bytesRead == bytesWritten);
+ cout << "Read(1): " << bytesRead << " bytes\n";
+
+ auto_ptr<Poller> poller(new Poller);
+
+ PollerHandle h0(sv[0]);
+ PollerHandle h1(sv[1]);
+
+ poller->addFd(h0, Poller::INOUT);
+
+ // Wait for 500ms - h0 should be writable
+ Poller::Event event = poller->wait();
+ assert(event.handle == &h0);
+ assert(event.dir == Poller::OUT);
+
+ // Write as much as we can to socket 0
+ bytesWritten = writeALot(sv[0], testString);
+ cout << "Wrote(0): " << bytesWritten << " bytes\n";
+
+ // Wait for 500ms - h0 no longer writable
+ poller->rearmFd(h0);
+ event = poller->wait(500000000);
+ assert(event.handle == 0);
+
+ // Test we can read it all now
+ poller->addFd(h1, Poller::INOUT);
+ event = poller->wait();
+ assert(event.handle == &h1);
+ assert(event.dir == Poller::INOUT);
+
+ bytesRead = readALot(sv[1]);
+ assert(bytesRead == bytesWritten);
+ cout << "Read(1): " << bytesRead << " bytes\n";
+
+ // At this point h1 should have been disabled from the poller
+ // (as it was just returned) and h0 can write again
+ event = poller->wait();
+ assert(event.handle == &h0);
+ assert(event.dir == Poller::OUT);
+
+ // Now both the handles should be disabled
+ event = poller->wait(500000000);
+ assert(event.handle == 0);
+
+ // Test shutdown
+ poller->shutdown();
+ event = poller->wait();
+ assert(event.handle == 0);
+ assert(event.dir == Poller::SHUTDOWN);
+
+ event = poller->wait();
+ assert(event.handle == 0);
+ assert(event.dir == Poller::SHUTDOWN);
+
+ poller->delFd(h1);
+ poller->delFd(h0);
+
+ return 0;
+ } catch (exception& e) {
+ cout << "Caught exception " << e.what() << "\n";
+ }
+}
+
+
diff --git a/RC9/qpid/cpp/src/tests/QueueOptionsTest.cpp b/RC9/qpid/cpp/src/tests/QueueOptionsTest.cpp
new file mode 100644
index 0000000000..bac369bfec
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/QueueOptionsTest.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include <iostream>
+#include "qpid/framing/Array.h"
+#include "qpid/client/QueueOptions.h"
+#include <alloca.h>
+
+#include "unit_test.h"
+
+using namespace qpid::client;
+
+
+QPID_AUTO_TEST_SUITE(QueueOptionsTestSuite)
+
+QPID_AUTO_TEST_CASE(testSizePolicy)
+{
+ QueueOptions ft;
+
+ ft.setSizePolicy(REJECT,1,2);
+
+ BOOST_CHECK(QueueOptions::strREJECT == ft.getAsString(QueueOptions::strTypeKey));
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strMaxSizeKey));
+ BOOST_CHECK(2 == ft.getAsInt(QueueOptions::strMaxCountKey));
+
+ ft.setSizePolicy(FLOW_TO_DISK,0,2);
+ BOOST_CHECK(QueueOptions::strFLOW_TO_DISK == ft.getAsString(QueueOptions::strTypeKey));
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strMaxSizeKey));
+ BOOST_CHECK(2 == ft.getAsInt(QueueOptions::strMaxCountKey));
+
+ ft.setSizePolicy(RING,1,0);
+ BOOST_CHECK(QueueOptions::strRING == ft.getAsString(QueueOptions::strTypeKey));
+
+ ft.setSizePolicy(RING_STRICT,1,0);
+ BOOST_CHECK(QueueOptions::strRING_STRICT == ft.getAsString(QueueOptions::strTypeKey));
+
+ ft.clearSizePolicy();
+ BOOST_CHECK(!ft.isSet(QueueOptions::strTypeKey));
+ BOOST_CHECK(!ft.isSet(QueueOptions::strMaxSizeKey));
+ BOOST_CHECK(!ft.isSet(QueueOptions::strMaxCountKey));
+}
+
+QPID_AUTO_TEST_CASE(testFlags)
+{
+ QueueOptions ft;
+
+ ft.setPersistLastNode();
+ ft.setOrdering(LVQ);
+
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strPersistLastNode));
+ BOOST_CHECK(1 == ft.getAsInt(QueueOptions::strLastValueQueue));
+
+ ft.clearPersistLastNode();
+ ft.setOrdering(FIFO);
+
+ BOOST_CHECK(!ft.isSet(QueueOptions::strPersistLastNode));
+ BOOST_CHECK(!ft.isSet(QueueOptions::strLastValueQueue));
+
+}
+
+QPID_AUTO_TEST_CASE(testSetOrdering)
+{
+ //ensure setOrdering(FIFO) works even if not preceded by a call to
+ //setOrdering(LVQ)
+ QueueOptions ft;
+ ft.setOrdering(FIFO);
+ BOOST_CHECK(!ft.isSet(QueueOptions::strLastValueQueue));
+
+}
+
+QPID_AUTO_TEST_CASE(testClearPersistLastNode)
+{
+ //ensure clear works even if not preceded by the setting on the
+ //option
+ QueueOptions ft;
+ ft.clearPersistLastNode();
+ BOOST_CHECK(!ft.isSet(QueueOptions::strPersistLastNode));
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/QueuePolicyTest.cpp b/RC9/qpid/cpp/src/tests/QueuePolicyTest.cpp
new file mode 100644
index 0000000000..6c650169c7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/QueuePolicyTest.cpp
@@ -0,0 +1,274 @@
+ /*
+ *
+ * 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.
+ *
+ */
+#include "unit_test.h"
+#include "test_tools.h"
+
+#include "qpid/broker/QueuePolicy.h"
+#include "qpid/client/QueueOptions.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "MessageUtils.h"
+#include "BrokerFixture.h"
+
+using namespace qpid::broker;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+QPID_AUTO_TEST_SUITE(QueuePolicyTestSuite)
+
+QueuedMessage createMessage(uint32_t size)
+{
+ QueuedMessage msg;
+ msg.payload = MessageUtils::createMessage();
+ MessageUtils::addContent(msg.payload, std::string (size, 'x'));
+ return msg;
+}
+
+
+QPID_AUTO_TEST_CASE(testCount)
+{
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(5, 0));
+ BOOST_CHECK_EQUAL((uint64_t) 0, policy->getMaxSize());
+ BOOST_CHECK_EQUAL((uint32_t) 5, policy->getMaxCount());
+
+ QueuedMessage msg = createMessage(10);
+ for (size_t i = 0; i < 5; i++) {
+ policy->tryEnqueue(msg);
+ }
+ try {
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on enqueuing sixth message");
+ } catch (const ResourceLimitExceededException&) {}
+
+ policy->dequeued(msg);
+ policy->tryEnqueue(msg);
+
+ try {
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on enqueuing sixth message (after dequeue)");
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testSize)
+{
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(0, 50));
+ QueuedMessage msg = createMessage(10);
+
+ for (size_t i = 0; i < 5; i++) {
+ policy->tryEnqueue(msg);
+ }
+ try {
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+
+ policy->dequeued(msg);
+ policy->tryEnqueue(msg);
+
+ try {
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on aggregate size exceeding 50 (after dequeue). " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testBoth)
+{
+ std::auto_ptr<QueuePolicy> policy(QueuePolicy::createQueuePolicy(5, 50));
+ try {
+ QueuedMessage msg = createMessage(51);
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on single message exceeding 50. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+
+ std::vector<QueuedMessage> messages;
+ messages.push_back(createMessage(15));
+ messages.push_back(createMessage(10));
+ messages.push_back(createMessage(11));
+ messages.push_back(createMessage(2));
+ messages.push_back(createMessage(7));
+ for (size_t i = 0; i < messages.size(); i++) {
+ policy->tryEnqueue(messages[i]);
+ }
+ //size = 45 at this point, count = 5
+ try {
+ QueuedMessage msg = createMessage(5);
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on count exceeding 6. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+ try {
+ QueuedMessage msg = createMessage(10);
+ policy->tryEnqueue(msg);
+ BOOST_FAIL("Policy did not fail on aggregate size exceeding 50. " << *policy);
+ } catch (const ResourceLimitExceededException&) {}
+
+
+ policy->dequeued(messages[0]);
+ try {
+ QueuedMessage msg = createMessage(20);
+ policy->tryEnqueue(msg);
+ } catch (const ResourceLimitExceededException&) {
+ BOOST_FAIL("Policy failed incorrectly after dequeue. " << *policy);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testSettings)
+{
+ //test reading and writing the policy from/to field table
+ std::auto_ptr<QueuePolicy> a(QueuePolicy::createQueuePolicy(101, 303));
+ FieldTable settings;
+ a->update(settings);
+ std::auto_ptr<QueuePolicy> b(QueuePolicy::createQueuePolicy(settings));
+ BOOST_CHECK_EQUAL(a->getMaxCount(), b->getMaxCount());
+ BOOST_CHECK_EQUAL(a->getMaxSize(), b->getMaxSize());
+}
+
+QPID_AUTO_TEST_CASE(testRingPolicy)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("my-ring-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ for (int i = 0; i < 10; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ client::Message msg;
+ for (int i = 5; i < 10; i++) {
+ BOOST_CHECK(f.subs.get(msg, q, qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL((boost::format("%1%_%2%") % "Message" % (i+1)).str(), msg.getData());
+ }
+ BOOST_CHECK(!f.subs.get(msg, q));
+}
+
+QPID_AUTO_TEST_CASE(testStrictRingPolicy)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::RING_STRICT);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("my-ring-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ LocalQueue incoming;
+ SubscriptionSettings settings(FlowControl::unlimited());
+ settings.autoAck = 0; // no auto ack.
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
+ for (int i = 0; i < 5; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 0; i < 5; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f.session.messageTransfer(arg::content=client::Message("Message_6", q));
+ BOOST_FAIL("expecting ResourceLimitExceededException.");
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+QPID_AUTO_TEST_CASE(testPolicyWithDtx)
+{
+ FieldTable args;
+ std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy(5, 0, QueuePolicy::REJECT);
+ policy->update(args);
+
+ ProxySessionFixture f;
+ std::string q("my-policy-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ LocalQueue incoming;
+ SubscriptionSettings settings(FlowControl::unlimited());
+ settings.autoAck = 0; // no auto ack.
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
+ f.session.dtxSelect();
+ Xid tx1(1, "test-dtx-mgr", "tx1");
+ f.session.dtxStart(arg::xid=tx1);
+ for (int i = 0; i < 5; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ f.session.dtxEnd(arg::xid=tx1);
+ f.session.dtxCommit(arg::xid=tx1, arg::onePhase=true);
+
+ Xid tx2(1, "test-dtx-mgr", "tx2");
+ f.session.dtxStart(arg::xid=tx2);
+ for (int i = 0; i < 5; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ SequenceSet accepting=sub.getUnaccepted();
+ f.session.messageAccept(accepting);
+ f.session.dtxEnd(arg::xid=tx2);
+ f.session.dtxPrepare(arg::xid=tx2);
+ f.session.dtxRollback(arg::xid=tx2);
+ f.session.messageRelease(accepting);
+
+ Xid tx3(1, "test-dtx-mgr", "tx3");
+ f.session.dtxStart(arg::xid=tx3);
+ for (int i = 0; i < 5; i++) {
+ incoming.pop();
+ }
+ accepting=sub.getUnaccepted();
+ f.session.messageAccept(accepting);
+ f.session.dtxEnd(arg::xid=tx3);
+ f.session.dtxPrepare(arg::xid=tx3);
+
+ Session other = f.connection.newSession();
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ other.messageTransfer(arg::content=client::Message("Message_6", q));
+ BOOST_FAIL("expecting ResourceLimitExceededException.");
+ } catch (const ResourceLimitExceededException&) {}
+
+ f.session.dtxCommit(arg::xid=tx3);
+ //now retry and this time should succeed
+ other = f.connection.newSession();
+ other.messageTransfer(arg::content=client::Message("Message_6", q));
+}
+
+QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore)
+{
+ //Ensure that with no store loaded, we don't flow to disk but
+ //fallback to rejecting messages
+ QueueOptions args;
+ args.setSizePolicy(FLOW_TO_DISK, 0, 5);
+
+ ProxySessionFixture f;
+ std::string q("my-queue");
+ f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args);
+ LocalQueue incoming;
+ SubscriptionSettings settings(FlowControl::unlimited());
+ settings.autoAck = 0; // no auto ack.
+ Subscription sub = f.subs.subscribe(incoming, q, settings);
+ for (int i = 0; i < 5; i++) {
+ f.session.messageTransfer(arg::content=client::Message((boost::format("%1%_%2%") % "Message" % (i+1)).str(), q));
+ }
+ for (int i = 0; i < 5; i++) {
+ BOOST_CHECK_EQUAL(incoming.pop().getData(), (boost::format("%1%_%2%") % "Message" % (i+1)).str());
+ }
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f.session.messageTransfer(arg::content=client::Message("Message_6", q));
+ BOOST_FAIL("expecting ResourceLimitExceededException.");
+ } catch (const ResourceLimitExceededException&) {}
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/QueueRegistryTest.cpp b/RC9/qpid/cpp/src/tests/QueueRegistryTest.cpp
new file mode 100644
index 0000000000..7ad4e0b89d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/QueueRegistryTest.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#include "qpid/broker/QueueRegistry.h"
+#include "unit_test.h"
+#include <string>
+
+using namespace qpid::broker;
+
+QPID_AUTO_TEST_SUITE(QueueRegistryTest)
+
+QPID_AUTO_TEST_CASE(testDeclare)
+{
+ std::string foo("foo");
+ std::string bar("bar");
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ qc = reg.declare(foo, false, 0, 0);
+ Queue::shared_ptr q = qc.first;
+ BOOST_CHECK(q);
+ BOOST_CHECK(qc.second); // New queue
+ BOOST_CHECK_EQUAL(foo, q->getName());
+
+ qc = reg.declare(foo, false, 0, 0);
+ BOOST_CHECK_EQUAL(q, qc.first);
+ BOOST_CHECK(!qc.second);
+
+ qc = reg.declare(bar, false, 0, 0);
+ q = qc.first;
+ BOOST_CHECK(q);
+ BOOST_CHECK_EQUAL(true, qc.second);
+ BOOST_CHECK_EQUAL(bar, q->getName());
+}
+
+QPID_AUTO_TEST_CASE(testDeclareTmp)
+{
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ qc = reg.declare(std::string(), false, 0, 0);
+ BOOST_CHECK(qc.second);
+ BOOST_CHECK_EQUAL(std::string("tmp_1"), qc.first->getName());
+}
+
+QPID_AUTO_TEST_CASE(testFind)
+{
+ std::string foo("foo");
+ std::string bar("bar");
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ BOOST_CHECK(reg.find(foo) == 0);
+
+ reg.declare(foo, false, 0, 0);
+ reg.declare(bar, false, 0, 0);
+ Queue::shared_ptr q = reg.find(bar);
+ BOOST_CHECK(q);
+ BOOST_CHECK_EQUAL(bar, q->getName());
+}
+
+QPID_AUTO_TEST_CASE(testDestroy)
+{
+ std::string foo("foo");
+ QueueRegistry reg;
+ std::pair<Queue::shared_ptr, bool> qc;
+
+ qc = reg.declare(foo, false, 0, 0);
+ reg.destroy(foo);
+ // Queue is gone from the registry.
+ BOOST_CHECK(reg.find(foo) == 0);
+ // Queue is not actually destroyed till we drop our reference.
+ BOOST_CHECK_EQUAL(foo, qc.first->getName());
+ // We shoud be the only reference.
+ BOOST_CHECK_EQUAL(1L, qc.first.use_count());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/QueueTest.cpp b/RC9/qpid/cpp/src/tests/QueueTest.cpp
new file mode 100644
index 0000000000..f1771e26cd
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/QueueTest.cpp
@@ -0,0 +1,501 @@
+ /*
+ *
+ * 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.
+ *
+ */
+#include "unit_test.h"
+#include "qpid/Exception.h"
+#include "qpid/broker/Broker.h"
+#include "qpid/broker/Queue.h"
+#include "qpid/broker/Deliverable.h"
+#include "qpid/broker/ExchangeRegistry.h"
+#include "qpid/broker/QueueRegistry.h"
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/client/QueueOptions.h"
+#include <iostream>
+#include "boost/format.hpp"
+
+using boost::intrusive_ptr;
+using namespace qpid;
+using namespace qpid::broker;
+using namespace qpid::framing;
+using namespace qpid::sys;
+
+class TestConsumer : public virtual Consumer{
+public:
+ typedef boost::shared_ptr<TestConsumer> shared_ptr;
+
+ intrusive_ptr<Message> last;
+ bool received;
+ TestConsumer(bool acquire = true):Consumer(acquire), received(false) {};
+
+ virtual bool deliver(QueuedMessage& msg){
+ last = msg.payload;
+ received = true;
+ return true;
+ };
+ void notify() {}
+ OwnershipToken* getSession() { return 0; }
+};
+
+class FailOnDeliver : public Deliverable
+{
+ Message msg;
+public:
+ void deliverTo(const boost::shared_ptr<Queue>& queue)
+ {
+ throw Exception(QPID_MSG("Invalid delivery to " << queue->getName()));
+ }
+ Message& getMessage() { return msg; }
+};
+
+intrusive_ptr<Message> create_message(std::string exchange, std::string routingKey) {
+ intrusive_ptr<Message> msg(new Message());
+ AMQFrame method(in_place<MessageTransferBody>(ProtocolVersion(), exchange, 0, 0));
+ AMQFrame header(in_place<AMQHeaderBody>());
+ msg->getFrames().append(method);
+ msg->getFrames().append(header);
+ msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey);
+ return msg;
+}
+
+QPID_AUTO_TEST_SUITE(QueueTestSuite)
+
+QPID_AUTO_TEST_CASE(testAsyncMessage) {
+ Queue::shared_ptr queue(new Queue("my_test_queue", true));
+ intrusive_ptr<Message> received;
+
+ TestConsumer::shared_ptr c1(new TestConsumer());
+ queue->consume(c1);
+
+
+ //Test basic delivery:
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ msg1->enqueueAsync();//this is done on enqueue which is not called from process
+ queue->process(msg1);
+ sleep(2);
+
+ BOOST_CHECK(!c1->received);
+ msg1->enqueueComplete();
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg1.get(), received.get());
+}
+
+
+QPID_AUTO_TEST_CASE(testAsyncMessageCount){
+ Queue::shared_ptr queue(new Queue("my_test_queue", true));
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ msg1->enqueueAsync();//this is done on enqueue which is not called from process
+
+ queue->process(msg1);
+ sleep(2);
+ uint32_t compval=0;
+ BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
+ msg1->enqueueComplete();
+ compval=1;
+ BOOST_CHECK_EQUAL(compval, queue->getMessageCount());
+}
+
+QPID_AUTO_TEST_CASE(testConsumers){
+ Queue::shared_ptr queue(new Queue("my_queue", true));
+
+ //Test adding consumers:
+ TestConsumer::shared_ptr c1(new TestConsumer());
+ TestConsumer::shared_ptr c2(new TestConsumer());
+ queue->consume(c1);
+ queue->consume(c2);
+
+ BOOST_CHECK_EQUAL(uint32_t(2), queue->getConsumerCount());
+
+ //Test basic delivery:
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+
+ queue->deliver(msg1);
+ BOOST_CHECK(queue->dispatch(c1));
+ BOOST_CHECK_EQUAL(msg1.get(), c1->last.get());
+
+ queue->deliver(msg2);
+ BOOST_CHECK(queue->dispatch(c2));
+ BOOST_CHECK_EQUAL(msg2.get(), c2->last.get());
+
+ c1->received = false;
+ queue->deliver(msg3);
+ BOOST_CHECK(queue->dispatch(c1));
+ BOOST_CHECK_EQUAL(msg3.get(), c1->last.get());
+
+ //Test cancellation:
+ queue->cancel(c1);
+ BOOST_CHECK_EQUAL(uint32_t(1), queue->getConsumerCount());
+ queue->cancel(c2);
+ BOOST_CHECK_EQUAL(uint32_t(0), queue->getConsumerCount());
+}
+
+QPID_AUTO_TEST_CASE(testRegistry){
+ //Test use of queues in registry:
+ QueueRegistry registry;
+ registry.declare("queue1", true, true);
+ registry.declare("queue2", true, true);
+ registry.declare("queue3", true, true);
+
+ BOOST_CHECK(registry.find("queue1"));
+ BOOST_CHECK(registry.find("queue2"));
+ BOOST_CHECK(registry.find("queue3"));
+
+ registry.destroy("queue1");
+ registry.destroy("queue2");
+ registry.destroy("queue3");
+
+ BOOST_CHECK(!registry.find("queue1"));
+ BOOST_CHECK(!registry.find("queue2"));
+ BOOST_CHECK(!registry.find("queue3"));
+}
+
+QPID_AUTO_TEST_CASE(testDequeue){
+ Queue::shared_ptr queue(new Queue("my_queue", true));
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+ intrusive_ptr<Message> received;
+
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+
+ BOOST_CHECK_EQUAL(uint32_t(3), queue->getMessageCount());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg1.get(), received.get());
+ BOOST_CHECK_EQUAL(uint32_t(2), queue->getMessageCount());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg2.get(), received.get());
+ BOOST_CHECK_EQUAL(uint32_t(1), queue->getMessageCount());
+
+ TestConsumer::shared_ptr consumer(new TestConsumer());
+ queue->consume(consumer);
+ queue->dispatch(consumer);
+ if (!consumer->received)
+ sleep(2);
+
+ BOOST_CHECK_EQUAL(msg3.get(), consumer->last.get());
+ BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount());
+
+ received = queue->get().payload;
+ BOOST_CHECK(!received);
+ BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount());
+
+}
+
+QPID_AUTO_TEST_CASE(testBound)
+{
+ //test the recording of bindings, and use of those to allow a queue to be unbound
+ string key("my-key");
+ FieldTable args;
+
+ Queue::shared_ptr queue(new Queue("my-queue", true));
+ ExchangeRegistry exchanges;
+ //establish bindings from exchange->queue and notify the queue as it is bound:
+ Exchange::shared_ptr exchange1 = exchanges.declare("my-exchange-1", "direct").first;
+ exchange1->bind(queue, key, &args);
+ queue->bound(exchange1->getName(), key, args);
+
+ Exchange::shared_ptr exchange2 = exchanges.declare("my-exchange-2", "fanout").first;
+ exchange2->bind(queue, key, &args);
+ queue->bound(exchange2->getName(), key, args);
+
+ Exchange::shared_ptr exchange3 = exchanges.declare("my-exchange-3", "topic").first;
+ exchange3->bind(queue, key, &args);
+ queue->bound(exchange3->getName(), key, args);
+
+ //delete one of the exchanges:
+ exchanges.destroy(exchange2->getName());
+ exchange2.reset();
+
+ //unbind the queue from all exchanges it knows it has been bound to:
+ queue->unbind(exchanges, queue);
+
+ //ensure the remaining exchanges don't still have the queue bound to them:
+ FailOnDeliver deliverable;
+ exchange1->route(deliverable, key, &args);
+ exchange3->route(deliverable, key, &args);
+}
+
+QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){
+
+ client::QueueOptions args;
+ args.setPersistLastNode();
+
+ Queue::shared_ptr queue(new Queue("my-queue", true));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+
+ //enqueue 2 messages
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+
+ //change mode
+ queue->setLastNodeFailure();
+
+ //enqueue 1 message
+ queue->deliver(msg3);
+
+ //check all have persistent ids.
+ BOOST_CHECK(msg1->isPersistent());
+ BOOST_CHECK(msg2->isPersistent());
+ BOOST_CHECK(msg3->isPersistent());
+
+}
+
+class TestMessageStoreOC : public NullMessageStore
+{
+ public:
+
+ virtual void dequeue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& /*msg*/,
+ const PersistableQueue& /*queue*/)
+ {
+ }
+
+ virtual void enqueue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& /*msg*/,
+ const PersistableQueue& /* queue */)
+ {
+ }
+
+ TestMessageStoreOC() : NullMessageStore() {}
+ ~TestMessageStoreOC(){}
+};
+
+
+QPID_AUTO_TEST_CASE(testLVQOrdering){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+
+ Queue::shared_ptr queue(new Queue("my-queue", true ));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+ intrusive_ptr<Message> msg4 = create_message("e", "D");
+ intrusive_ptr<Message> received;
+
+ //set deliever match for LVQ a,b,c,a
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg3->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+ msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+
+ //enqueue 4 message
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+ queue->deliver(msg4);
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg4.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg2.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg3.get(), received.get());
+
+ intrusive_ptr<Message> msg5 = create_message("e", "A");
+ intrusive_ptr<Message> msg6 = create_message("e", "B");
+ intrusive_ptr<Message> msg7 = create_message("e", "C");
+ msg5->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg6->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg7->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+ queue->deliver(msg5);
+ queue->deliver(msg6);
+ queue->deliver(msg7);
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg5.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg6.get(), received.get());
+
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg7.get(), received.get());
+
+}
+
+QPID_AUTO_TEST_CASE(testLVQAcquire){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+
+ Queue::shared_ptr queue(new Queue("my-queue", true ));
+ queue->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "B");
+ intrusive_ptr<Message> msg3 = create_message("e", "C");
+ intrusive_ptr<Message> msg4 = create_message("e", "D");
+ intrusive_ptr<Message> msg5 = create_message("e", "F");
+ intrusive_ptr<Message> msg6 = create_message("e", "G");
+
+ //set deliever match for LVQ a,b,c,a
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg3->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+ msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg5->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b");
+ msg6->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c");
+
+ //enqueue 4 message
+ queue->deliver(msg1);
+ queue->deliver(msg2);
+ queue->deliver(msg3);
+ queue->deliver(msg4);
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ framing::SequenceNumber sequence(1);
+ QueuedMessage qmsg(queue.get(), msg1, sequence);
+ QueuedMessage qmsg2(queue.get(), msg2, ++sequence);
+
+ BOOST_CHECK(!queue->acquire(qmsg));
+ BOOST_CHECK(queue->acquire(qmsg2));
+
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u);
+
+ queue->deliver(msg5);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ // set mode to no browse and check
+ args.setOrdering(client::LVQ_NO_BROWSE);
+ queue->configure(args);
+ TestConsumer::shared_ptr c1(new TestConsumer(false));
+
+ queue->dispatch(c1);
+ queue->dispatch(c1);
+ queue->dispatch(c1);
+
+ queue->deliver(msg6);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 3u);
+
+ intrusive_ptr<Message> received;
+ received = queue->get().payload;
+ BOOST_CHECK_EQUAL(msg4.get(), received.get());
+
+}
+
+QPID_AUTO_TEST_CASE(testLVQMultiQueue){
+
+ client::QueueOptions args;
+ // set queue mode
+ args.setOrdering(client::LVQ);
+
+ Queue::shared_ptr queue1(new Queue("my-queue", true ));
+ Queue::shared_ptr queue2(new Queue("my-queue", true ));
+ intrusive_ptr<Message> received;
+ queue1->configure(args);
+ queue2->configure(args);
+
+ intrusive_ptr<Message> msg1 = create_message("e", "A");
+ intrusive_ptr<Message> msg2 = create_message("e", "A");
+
+ string key;
+ args.getLVQKey(key);
+ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key");
+
+ msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+ msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a");
+
+ queue1->deliver(msg1);
+ queue2->deliver(msg1);
+ queue1->deliver(msg2);
+
+ received = queue1->get().payload;
+ BOOST_CHECK_EQUAL(msg2.get(), received.get());
+
+ received = queue2->get().payload;
+ BOOST_CHECK_EQUAL(msg1.get(), received.get());
+
+}
+
+void addMessagesToQueue(uint count, Queue& queue, uint oddTtl = 200, uint evenTtl = 0)
+{
+ for (uint i = 0; i < count; i++) {
+ intrusive_ptr<Message> m = create_message("exchange", "key");
+ if (i % 2) {
+ if (oddTtl) m->getProperties<DeliveryProperties>()->setTtl(oddTtl);
+ } else {
+ if (evenTtl) m->getProperties<DeliveryProperties>()->setTtl(evenTtl);
+ }
+ m->setTimestamp();
+ queue.deliver(m);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testPurgeExpired) {
+ Queue queue("my-queue");
+ addMessagesToQueue(10, queue);
+ BOOST_CHECK_EQUAL(queue.getMessageCount(), 10u);
+ ::usleep(300*1000);
+ queue.purgeExpired();
+ BOOST_CHECK_EQUAL(queue.getMessageCount(), 5u);
+}
+
+QPID_AUTO_TEST_CASE(testQueueCleaner) {
+ Timer timer;
+ QueueRegistry queues;
+ Queue::shared_ptr queue = queues.declare("my-queue").first;
+ addMessagesToQueue(10, *queue, 200, 400);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 10u);
+
+ QueueCleaner cleaner(queues, timer);
+ cleaner.start(100 * qpid::sys::TIME_MSEC);
+ ::usleep(300*1000);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 5u);
+ ::usleep(300*1000);
+ BOOST_CHECK_EQUAL(queue->getMessageCount(), 0u);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/README b/RC9/qpid/cpp/src/tests/README
new file mode 100644
index 0000000000..0f4edee493
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/README
@@ -0,0 +1,54 @@
+= Running Qpid C++ tests =
+
+General philosophy is that "make check" run all tests by default, but
+developers can run tests selectively as explained below.
+
+== Valgrind ==
+
+By default we run tests under valgrind to detect memory errors if valgrind
+is present. ./configure --disable-valgrind will disable it.
+
+Default valgrind options are specified in .valgrindrc-default, which a
+checked-in file. The actual options used are in .valgrindrc which is a
+local file. Normally it is a copy of valgrindrc-default but you can
+modify at will.
+
+Supressed errors are listed in .valgrind.supp. If you want to change
+suppressions for local testing, just modify .valgrindrc to point to a
+different file. Do NOT add suppressions to .valgrindrc.supp unless
+they are known problems outside of Qpid that can't reasonably be
+worked around in Qpid.
+
+
+== Unit Tests ==
+Unit tests use the boost test framework, and are compiled to rogram
+ unit_test
+There are several options to control how test results are displayed,
+see
+ http://www.boost.org/doc/libs/1_35_0/libs/test/doc/components/utf/parameters/index.html
+
+NOTE: some unit tests are written as CppUnit plug-ins, we are moving away
+from CppUnit so new tests should use the boost framework.
+
+CppUnit tests are run by the script run-unit-tests.
+
+== System Tests ==
+
+System tests are self contained AMQP client executables or scripts.
+They are listed in the TESTS make variable, which can be over-ridden.
+
+The ./start_broker "test" launches the broker, ./stop_broker" stops it.
+Tests in between assume the broker is running.
+
+./python_tests: runs ../python/run_tests. This is the main set of
+system testss for the broker.
+
+Other C++ client test executables and scripts under client/test are
+system tests for the client.
+
+By setting TESTS in a make command you can run a different subset of tests
+against an already-running broker.
+
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/RangeSet.cpp b/RC9/qpid/cpp/src/tests/RangeSet.cpp
new file mode 100644
index 0000000000..9c602de78d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/RangeSet.cpp
@@ -0,0 +1,141 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "qpid/RangeSet.h"
+
+using namespace std;
+using namespace qpid;
+
+QPID_AUTO_TEST_SUITE(RangeSetTestSuite)
+
+typedef qpid::Range<int> TestRange;
+typedef qpid::RangeSet<int> TestRangeSet;
+
+QPID_AUTO_TEST_CASE(testEmptyRange) {
+ TestRange r;
+ BOOST_CHECK(r.empty());
+ BOOST_CHECK(!r.contains(0));
+ // BOOST_CHECK(r.contiguous(0));
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetAddPoint) {
+ TestRangeSet r;
+ BOOST_CHECK(r.empty());
+ r += 3;
+ BOOST_CHECK_MESSAGE(r.contains(3), r);
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(3,4)), r);
+ BOOST_CHECK(!r.empty());
+ r += 5;
+ BOOST_CHECK_MESSAGE(r.contains(5), r);
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(5,6)), r);
+ BOOST_CHECK_MESSAGE(!r.contains(TestRange(3,6)), r);
+ r += 4;
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(3,6)), r);
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetAddRange) {
+ TestRangeSet r;
+ r += TestRange(0,3);
+ BOOST_CHECK(r.contains(TestRange(0,3)));
+ r += TestRange(4,6);
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(4,6)), r);
+ r += 3;
+ BOOST_CHECK_MESSAGE(r.contains(TestRange(0,6)), r);
+ BOOST_CHECK(r.front() == 0);
+ BOOST_CHECK(r.back() == 6);
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetAddSet) {
+ TestRangeSet r;
+ TestRangeSet s = TestRangeSet(0,3)+TestRange(5,10);
+ r += s;
+ BOOST_CHECK_EQUAL(r,s);
+ r += TestRangeSet(3,5) + TestRange(7,12) + 15;
+ BOOST_CHECK_EQUAL(r, TestRangeSet(0,12) + 15);
+
+ r.clear();
+ BOOST_CHECK(r.empty());
+ r += TestRange::makeClosed(6,10);
+ BOOST_CHECK_EQUAL(r, TestRangeSet(6,11));
+ r += TestRangeSet(2,6)+8;
+ BOOST_CHECK_EQUAL(r, TestRangeSet(2,11));
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetIterate) {
+ TestRangeSet r;
+ (((r += 1) += 10) += TestRange(4,7)) += 2;
+ BOOST_MESSAGE(r);
+ std::vector<int> actual;
+ std::copy(r.begin(), r.end(), std::back_inserter(actual));
+ std::vector<int> expect = boost::assign::list_of(1)(2)(4)(5)(6)(10);
+ BOOST_CHECK_EQUAL(expect, actual);
+}
+
+QPID_AUTO_TEST_CASE(testRangeSetRemove) {
+ // points
+ BOOST_CHECK_EQUAL(TestRangeSet(0,5)-3, TestRangeSet(0,3)+TestRange(4,5));
+ BOOST_CHECK_EQUAL(TestRangeSet(1,5)-5, TestRangeSet(1,5));
+ BOOST_CHECK_EQUAL(TestRangeSet(1,5)-0, TestRangeSet(1,5));
+
+ TestRangeSet r(TestRangeSet(0,5)+TestRange(10,15)+TestRange(20,25));
+
+ // TestRanges
+ BOOST_CHECK_EQUAL(r-TestRange(0,5), TestRangeSet(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(10,15), TestRangeSet(0,5)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(20,25), TestRangeSet(0,5)+TestRange(10,15));
+
+ BOOST_CHECK_EQUAL(r-TestRange(-5, 30), TestRangeSet());
+
+ BOOST_CHECK_EQUAL(r-TestRange(-5, 7), TestRangeSet(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(8,19), TestRangeSet(0,5)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(17,30), TestRangeSet(0,5)+TestRange(10,15));
+ BOOST_CHECK_EQUAL(r-TestRange(17,30), TestRangeSet(0,5)+TestRange(10,15));
+
+ BOOST_CHECK_EQUAL(r-TestRange(-5, 5), TestRangeSet(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(10,19), TestRangeSet(0,5)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(18,25), TestRangeSet(0,5)+TestRange(10,15));
+ BOOST_CHECK_EQUAL(r-TestRange(23,25), TestRangeSet(0,5)+TestRange(10,15)+TestRange(20,23));
+
+ BOOST_CHECK_EQUAL(r-TestRange(-3, 3), TestRangeSet(3,5)+TestRange(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(3, 7), TestRangeSet(0,2)+TestRange(10,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(3, 12), TestRangeSet(0,3)+TestRange(12,15)+TestRange(20,25));
+ BOOST_CHECK_EQUAL(r-TestRange(3, 22), TestRangeSet(12,15)+TestRange(22,25));
+ BOOST_CHECK_EQUAL(r-TestRange(12, 22), TestRangeSet(0,5)+TestRange(10,11)+TestRange(22,25));
+
+ // Sets
+ BOOST_CHECK_EQUAL(r-(TestRangeSet(-1,6)+TestRange(11,14)+TestRange(23,25)),
+ TestRangeSet(10,11)+TestRange(14,15)+TestRange(20,23));
+}
+
+QPID_AUTO_TEST_CASE(testRangeContaining) {
+ TestRangeSet r;
+ (((r += 1) += TestRange(3,5)) += 7);
+ BOOST_CHECK_EQUAL(r.rangeContaining(0), TestRange(0,0));
+ BOOST_CHECK_EQUAL(r.rangeContaining(1), TestRange(1,2));
+ BOOST_CHECK_EQUAL(r.rangeContaining(2), TestRange(2,2));
+ BOOST_CHECK_EQUAL(r.rangeContaining(3), TestRange(3,5));
+ BOOST_CHECK_EQUAL(r.rangeContaining(4), TestRange(3,5));
+ BOOST_CHECK_EQUAL(r.rangeContaining(5), TestRange(5,5));
+ BOOST_CHECK_EQUAL(r.rangeContaining(6), TestRange(6,6));
+ BOOST_CHECK_EQUAL(r.rangeContaining(7), TestRange(7,8));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/RefCounted.cpp b/RC9/qpid/cpp/src/tests/RefCounted.cpp
new file mode 100644
index 0000000000..8c679a3d2e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/RefCounted.cpp
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/RefCounted.h"
+#include <boost/intrusive_ptr.hpp>
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(RefCountedTestSuiteTestSuite)
+
+using boost::intrusive_ptr;
+using namespace std;
+using namespace qpid;
+
+struct CountMe : public RefCounted {
+ static int instances;
+ CountMe() { ++instances; }
+ ~CountMe() { --instances; }
+};
+
+int CountMe::instances=0;
+
+QPID_AUTO_TEST_CASE(testRefCounted) {
+ BOOST_CHECK_EQUAL(0, CountMe::instances);
+ intrusive_ptr<CountMe> p(new CountMe());
+ BOOST_CHECK_EQUAL(1, CountMe::instances);
+ intrusive_ptr<CountMe> q(p);
+ BOOST_CHECK_EQUAL(1, CountMe::instances);
+ q=0;
+ BOOST_CHECK_EQUAL(1, CountMe::instances);
+ p=0;
+ BOOST_CHECK_EQUAL(0, CountMe::instances);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/SequenceNumberTest.cpp b/RC9/qpid/cpp/src/tests/SequenceNumberTest.cpp
new file mode 100644
index 0000000000..e4c6d066ef
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SequenceNumberTest.cpp
@@ -0,0 +1,205 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "unit_test.h"
+#include <iostream>
+#include "qpid/framing/SequenceNumber.h"
+#include "qpid/framing/SequenceNumberSet.h"
+
+using namespace qpid::framing;
+
+
+void checkDifference(SequenceNumber& a, SequenceNumber& b, int gap)
+{
+ BOOST_CHECK_EQUAL(gap, a - b);
+ BOOST_CHECK_EQUAL(-gap, b - a);
+
+ //increment until b wraps around
+ for (int i = 0; i < (gap + 2); i++, ++a, ++b) {
+ BOOST_CHECK_EQUAL(gap, a - b);
+ }
+ //keep incrementing until a also wraps around
+ for (int i = 0; i < (gap + 2); i++, ++a, ++b) {
+ BOOST_CHECK_EQUAL(gap, a - b);
+ }
+ //let b catch up and overtake
+ for (int i = 0; i < (gap*2); i++, ++b) {
+ BOOST_CHECK_EQUAL(gap - i, a - b);
+ BOOST_CHECK_EQUAL(i - gap, b - a);
+ }
+}
+
+void checkComparison(SequenceNumber& a, SequenceNumber& b, int gap)
+{
+ //increment until b wraps around
+ for (int i = 0; i < (gap + 2); i++) {
+ BOOST_CHECK(++a < ++b);//test prefix
+ }
+ //keep incrementing until a also wraps around
+ for (int i = 0; i < (gap + 2); i++) {
+ BOOST_CHECK(a++ < b++);//test postfix
+ }
+ //let a 'catch up'
+ for (int i = 0; i < gap; i++) {
+ a++;
+ }
+ BOOST_CHECK(a == b);
+ BOOST_CHECK(++a > b);
+}
+
+
+QPID_AUTO_TEST_SUITE(SequenceNumberTestSuite)
+
+QPID_AUTO_TEST_CASE(testIncrementPostfix)
+{
+ SequenceNumber a;
+ SequenceNumber b;
+ BOOST_CHECK(!(a > b));
+ BOOST_CHECK(!(b < a));
+ BOOST_CHECK(a == b);
+
+ SequenceNumber c = a++;
+ BOOST_CHECK(a > b);
+ BOOST_CHECK(b < a);
+ BOOST_CHECK(a != b);
+ BOOST_CHECK(c < a);
+ BOOST_CHECK(a != c);
+
+ b++;
+ BOOST_CHECK(!(a > b));
+ BOOST_CHECK(!(b < a));
+ BOOST_CHECK(a == b);
+ BOOST_CHECK(c < b);
+ BOOST_CHECK(b != c);
+}
+
+QPID_AUTO_TEST_CASE(testIncrementPrefix)
+{
+ SequenceNumber a;
+ SequenceNumber b;
+ BOOST_CHECK(!(a > b));
+ BOOST_CHECK(!(b < a));
+ BOOST_CHECK(a == b);
+
+ SequenceNumber c = ++a;
+ BOOST_CHECK(a > b);
+ BOOST_CHECK(b < a);
+ BOOST_CHECK(a != b);
+ BOOST_CHECK(a == c);
+
+ ++b;
+ BOOST_CHECK(!(a > b));
+ BOOST_CHECK(!(b < a));
+ BOOST_CHECK(a == b);
+}
+
+QPID_AUTO_TEST_CASE(testWrapAround)
+{
+ const uint32_t max = 0xFFFFFFFF;
+ SequenceNumber a(max - 10);
+ SequenceNumber b(max - 5);
+ checkComparison(a, b, 5);
+
+ const uint32_t max_signed = 0x7FFFFFFF;
+ SequenceNumber c(max_signed - 10);
+ SequenceNumber d(max_signed - 5);
+ checkComparison(c, d, 5);
+}
+
+QPID_AUTO_TEST_CASE(testCondense)
+{
+ SequenceNumberSet set;
+ for (uint i = 0; i < 6; i++) {
+ set.push_back(SequenceNumber(i));
+ }
+ set.push_back(SequenceNumber(7));
+ for (uint i = 9; i < 13; i++) {
+ set.push_back(SequenceNumber(i));
+ }
+ set.push_back(SequenceNumber(13));
+ SequenceNumberSet actual = set.condense();
+
+ SequenceNumberSet expected;
+ expected.addRange(SequenceNumber(0), SequenceNumber(5));
+ expected.addRange(SequenceNumber(7), SequenceNumber(7));
+ expected.addRange(SequenceNumber(9), SequenceNumber(13));
+ BOOST_CHECK_EQUAL(expected, actual);
+}
+
+QPID_AUTO_TEST_CASE(testCondenseSingleRange)
+{
+ SequenceNumberSet set;
+ for (uint i = 0; i < 6; i++) {
+ set.push_back(SequenceNumber(i));
+ }
+ SequenceNumberSet actual = set.condense();
+
+ SequenceNumberSet expected;
+ expected.addRange(SequenceNumber(0), SequenceNumber(5));
+ BOOST_CHECK_EQUAL(expected, actual);
+}
+
+QPID_AUTO_TEST_CASE(testCondenseSingleItem)
+{
+ SequenceNumberSet set;
+ set.push_back(SequenceNumber(1));
+ SequenceNumberSet actual = set.condense();
+
+ SequenceNumberSet expected;
+ expected.addRange(SequenceNumber(1), SequenceNumber(1));
+ BOOST_CHECK_EQUAL(expected, actual);
+}
+
+QPID_AUTO_TEST_CASE(testDifference)
+{
+ SequenceNumber a;
+ SequenceNumber b;
+
+ for (int i = 0; i < 10; i++, ++a) {
+ BOOST_CHECK_EQUAL(i, a - b);
+ BOOST_CHECK_EQUAL(-i, b - a);
+ }
+
+ b = a;
+
+ for (int i = 0; i < 10; i++, ++b) {
+ BOOST_CHECK_EQUAL(-i, a - b);
+ BOOST_CHECK_EQUAL(i, b - a);
+ }
+}
+
+QPID_AUTO_TEST_CASE(testDifferenceWithWrapAround1)
+{
+ const uint32_t max = 0xFFFFFFFF;
+ SequenceNumber a(max - 5);
+ SequenceNumber b(max - 10);
+ checkDifference(a, b, 5);
+}
+
+QPID_AUTO_TEST_CASE(testDifferenceWithWrapAround2)
+{
+ const uint32_t max_signed = 0x7FFFFFFF;
+ SequenceNumber c(max_signed - 5);
+ SequenceNumber d(max_signed - 10);
+ checkDifference(c, d, 5);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/SequenceSet.cpp b/RC9/qpid/cpp/src/tests/SequenceSet.cpp
new file mode 100644
index 0000000000..ba2f1391a1
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SequenceSet.cpp
@@ -0,0 +1,140 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/framing/SequenceSet.h"
+#include "unit_test.h"
+#include <list>
+
+QPID_AUTO_TEST_SUITE(SequenceSetTestSuite)
+
+using namespace qpid::framing;
+
+struct RangeExpectations
+{
+ typedef std::pair<SequenceNumber, SequenceNumber> Range;
+ typedef std::list<Range> Ranges;
+
+ Ranges ranges;
+
+ RangeExpectations& expect(const SequenceNumber& start, const SequenceNumber& end) {
+ ranges.push_back(Range(start, end));
+ return *this;
+ }
+
+ void operator()(const SequenceNumber& start, const SequenceNumber& end) {
+ BOOST_CHECK(!ranges.empty());
+ if (!ranges.empty()) {
+ BOOST_CHECK_EQUAL(start, ranges.front().first);
+ BOOST_CHECK_EQUAL(end, ranges.front().second);
+ ranges.pop_front();
+ }
+ }
+
+ void check(SequenceSet& set) {
+ set.for_each(*this);
+ BOOST_CHECK(ranges.empty());
+ }
+};
+
+QPID_AUTO_TEST_CASE(testAdd) {
+ SequenceSet s;
+ s.add(2);
+ s.add(8,8);
+ s.add(3,5);
+
+ for (uint32_t i = 0; i <= 1; i++)
+ BOOST_CHECK(!s.contains(i));
+
+ for (uint32_t i = 2; i <= 5; i++)
+ BOOST_CHECK(s.contains(i));
+
+ for (uint32_t i = 6; i <= 7; i++)
+ BOOST_CHECK(!s.contains(i));
+
+ BOOST_CHECK(s.contains(8));
+
+ for (uint32_t i = 9; i <= 10; i++)
+ BOOST_CHECK(!s.contains(i));
+
+ RangeExpectations().expect(2, 5).expect(8, 8).check(s);
+
+ SequenceSet t;
+ t.add(6, 10);
+ t.add(s);
+
+ for (uint32_t i = 0; i <= 1; i++)
+ BOOST_CHECK(!t.contains(i));
+
+ for (uint32_t i = 2; i <= 10; i++)
+ BOOST_CHECK_MESSAGE(t.contains(i), t << " contains " << i);
+
+ RangeExpectations().expect(2, 10).check(t);
+}
+
+QPID_AUTO_TEST_CASE(testAdd2) {
+ SequenceSet s;
+ s.add(7,6);
+ s.add(4,4);
+ s.add(3,10);
+ s.add(2);
+ RangeExpectations().expect(2, 10).check(s);
+}
+
+QPID_AUTO_TEST_CASE(testRemove) {
+ SequenceSet s;
+ SequenceSet t;
+ s.add(0, 10);
+ t.add(0, 10);
+
+ s.remove(7);
+ s.remove(3, 5);
+ s.remove(9, 10);
+
+ t.remove(s);
+
+ for (uint32_t i = 0; i <= 2; i++) {
+ BOOST_CHECK(s.contains(i));
+ BOOST_CHECK(!t.contains(i));
+ }
+
+ for (uint32_t i = 3; i <= 5; i++) {
+ BOOST_CHECK(!s.contains(i));
+ BOOST_CHECK(t.contains(i));
+ }
+
+ BOOST_CHECK(s.contains(6));
+ BOOST_CHECK(!t.contains(6));
+
+ BOOST_CHECK(!s.contains(7));
+ BOOST_CHECK(t.contains(7));
+
+ BOOST_CHECK(s.contains(8));
+ BOOST_CHECK(!t.contains(8));
+
+ for (uint32_t i = 9; i <= 10; i++) {
+ BOOST_CHECK(!s.contains(i));
+ BOOST_CHECK(t.contains(i));
+ }
+
+ RangeExpectations().expect(0, 2).expect(6, 6).expect(8, 8).check(s);
+ RangeExpectations().expect(3, 5).expect(7, 7).expect(9, 10).check(t);
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+
diff --git a/RC9/qpid/cpp/src/tests/SessionState.cpp b/RC9/qpid/cpp/src/tests/SessionState.cpp
new file mode 100644
index 0000000000..2db25f9fe8
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SessionState.cpp
@@ -0,0 +1,300 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "unit_test.h"
+
+#include "qpid/SessionState.h"
+#include "qpid/Exception.h"
+#include "qpid/framing/MessageTransferBody.h"
+#include "qpid/framing/SessionFlushBody.h"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <functional>
+#include <numeric>
+
+QPID_AUTO_TEST_SUITE(SessionStateTestSuite)
+
+using namespace std;
+using namespace boost;
+using namespace qpid::framing;
+
+// ================================================================
+// Utility functions.
+
+// Apply f to [begin, end) and accumulate the result
+template <class Iter, class T, class F>
+T applyAccumulate(Iter begin, Iter end, T seed, const F& f) {
+ return std::accumulate(begin, end, seed, bind(std::plus<T>(), _1, bind(f, _2)));
+}
+
+// Create a frame with a one-char string.
+AMQFrame& frame(char s) {
+ static AMQFrame frame;
+ frame.setBody(AMQContentBody(string(&s, 1)));
+ return frame;
+}
+
+// Simple string representation of a frame.
+string str(const AMQFrame& f) {
+ if (f.getMethod()) return "C"; // Command or Control
+ const AMQContentBody* c = dynamic_cast<const AMQContentBody*>(f.getBody());
+ if (c) return c->getData(); // Return data for content frames.
+ return "H"; // Must be a header.
+}
+// Make a string from a range of frames.
+string str(const boost::iterator_range<vector<AMQFrame>::const_iterator>& frames) {
+ string (*strFrame)(const AMQFrame&) = str;
+ return applyAccumulate(frames.begin(), frames.end(), string(), ptr_fun(strFrame));
+}
+// Make a transfer command frame.
+AMQFrame transferFrame(bool hasContent) {
+ AMQFrame t(in_place<MessageTransferBody>());
+ t.setFirstFrame(true);
+ t.setLastFrame(true);
+ t.setFirstSegment(true);
+ t.setLastSegment(!hasContent);
+ return t;
+}
+// Make a content frame
+AMQFrame contentFrame(string content, bool isLast=true) {
+ AMQFrame f(in_place<AMQContentBody>(content));
+ f.setFirstFrame(true);
+ f.setLastFrame(true);
+ f.setFirstSegment(false);
+ f.setLastSegment(isLast);
+ return f;
+}
+AMQFrame contentFrameChar(char content, bool isLast=true) {
+ return contentFrame(string(1, content), isLast);
+}
+
+// Send frame & return size of frame.
+size_t send(qpid::SessionState& s, const AMQFrame& f) { s.senderRecord(f); return f.encodedSize(); }
+// Send transfer command with no content.
+size_t transfer0(qpid::SessionState& s) { return send(s, transferFrame(false)); }
+// Send transfer frame with single content frame.
+size_t transfer1(qpid::SessionState& s, string content) {
+ return send(s,transferFrame(true)) + send(s,contentFrame(content));
+}
+size_t transfer1Char(qpid::SessionState& s, char content) {
+ return transfer1(s, string(1,content));
+}
+
+// Send transfer frame with multiple single-byte content frames.
+size_t transferN(qpid::SessionState& s, string content) {
+ size_t size=send(s, transferFrame(!content.empty()));
+ if (!content.empty()) {
+ char last = content[content.size()-1];
+ content.resize(content.size()-1);
+ size += applyAccumulate(content.begin(), content.end(), 0,
+ bind(&send, ref(s),
+ bind(contentFrameChar, _1, false)));
+ size += send(s, contentFrameChar(last, true));
+ }
+ return size;
+}
+
+// Send multiple transfers with single-byte content.
+size_t transfers(qpid::SessionState& s, string content) {
+ return applyAccumulate(content.begin(), content.end(), 0,
+ bind(transfer1Char, ref(s), _1));
+}
+
+size_t contentFrameSize(size_t n=1) { return AMQFrame(in_place<AMQContentBody>()).encodedSize() + n; }
+size_t transferFrameSize() { return AMQFrame(in_place<MessageTransferBody>()).encodedSize(); }
+
+// ==== qpid::SessionState test classes
+
+using qpid::SessionId;
+using qpid::SessionPoint;
+
+
+QPID_AUTO_TEST_CASE(testSendGetReplyList) {
+ qpid::SessionState s;
+ s.setTimeout(1);
+ s.senderGetCommandPoint();
+ transfer1(s, "abc");
+ transfers(s, "def");
+ transferN(s, "xyz");
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))),"CabcCdCeCfCxyz");
+ // Ignore controls.
+ s.senderRecord(AMQFrame(in_place<SessionFlushBody>()));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(2,0))),"CeCfCxyz");
+}
+
+QPID_AUTO_TEST_CASE(testNeedFlush) {
+ qpid::SessionState::Configuration c;
+ // sync after 2 1-byte transfers or equivalent bytes.
+ c.replayFlushLimit = 2*(transferFrameSize()+contentFrameSize());
+ qpid::SessionState s(SessionId(), c);
+ s.setTimeout(1);
+ s.senderGetCommandPoint();
+ transfers(s, "a");
+ BOOST_CHECK(!s.senderNeedFlush());
+ transfers(s, "b");
+ BOOST_CHECK(s.senderNeedFlush());
+ s.senderRecordFlush();
+ BOOST_CHECK(!s.senderNeedFlush());
+ transfers(s, "c");
+ BOOST_CHECK(!s.senderNeedFlush());
+ transfers(s, "d");
+ BOOST_CHECK(s.senderNeedFlush());
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint())), "CaCbCcCd");
+}
+
+QPID_AUTO_TEST_CASE(testPeerConfirmed) {
+ qpid::SessionState::Configuration c;
+ // sync after 2 1-byte transfers or equivalent bytes.
+ c.replayFlushLimit = 2*(transferFrameSize()+contentFrameSize());
+ qpid::SessionState s(SessionId(), c);
+ s.setTimeout(1);
+ s.senderGetCommandPoint();
+ transfers(s, "ab");
+ BOOST_CHECK(s.senderNeedFlush());
+ transfers(s, "cd");
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))), "CaCbCcCd");
+ s.senderConfirmed(SessionPoint(3));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(3,0))), "Cd");
+ BOOST_CHECK(!s.senderNeedFlush());
+
+ // Multi-frame transfer.
+ transfer1(s, "efg");
+ transfers(s, "xy");
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(3,0))), "CdCefgCxCy");
+ BOOST_CHECK(s.senderNeedFlush());
+
+ s.senderConfirmed(SessionPoint(4));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(4,0))), "CefgCxCy");
+ BOOST_CHECK(s.senderNeedFlush());
+
+ s.senderConfirmed(SessionPoint(5));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(5,0))), "CxCy");
+ BOOST_CHECK(s.senderNeedFlush());
+
+ s.senderConfirmed(SessionPoint(6));
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(6,0))), "Cy");
+ BOOST_CHECK(!s.senderNeedFlush());
+}
+
+QPID_AUTO_TEST_CASE(testPeerCompleted) {
+ qpid::SessionState s;
+ s.setTimeout(1);
+ s.senderGetCommandPoint();
+ // Completion implies confirmation
+ transfers(s, "abc");
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(0,0))), "CaCbCc");
+ SequenceSet set(SequenceSet() + 0 + 1);
+ s.senderCompleted(set);
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(2,0))), "Cc");
+
+ transfers(s, "def");
+ // We dont do out-of-order confirmation, so this will only confirm up to 3:
+ set = SequenceSet(SequenceSet() + 2 + 3 + 5);
+ s.senderCompleted(set);
+ BOOST_CHECK_EQUAL(str(s.senderExpected(SessionPoint(4,0))), "CeCf");
+}
+
+QPID_AUTO_TEST_CASE(testReceive) {
+ // Advance expected/received correctly
+ qpid::SessionState s;
+ s.receiverSetCommandPoint(SessionPoint());
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(0));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(0));
+
+ BOOST_CHECK(s.receiverRecord(transferFrame(false)));
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(1));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(1));
+
+ BOOST_CHECK(s.receiverRecord(transferFrame(true)));
+ SessionPoint point = SessionPoint(1, transferFrameSize());
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), point);
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), point);
+ BOOST_CHECK(s.receiverRecord(contentFrame("", false)));
+ point.offset += contentFrameSize(0);
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), point);
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), point);
+ BOOST_CHECK(s.receiverRecord(contentFrame("", true)));
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(2));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(2));
+
+ // Idempotence barrier, rewind expected & receive some duplicates.
+ s.receiverSetCommandPoint(SessionPoint(1));
+ BOOST_CHECK(!s.receiverRecord(transferFrame(false)));
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(2));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(2));
+ BOOST_CHECK(s.receiverRecord(transferFrame(false)));
+ BOOST_CHECK_EQUAL(s.receiverGetExpected(), SessionPoint(3));
+ BOOST_CHECK_EQUAL(s.receiverGetReceived(), SessionPoint(3));
+}
+
+QPID_AUTO_TEST_CASE(testCompleted) {
+ // completed & unknownCompleted
+ qpid::SessionState s;
+ s.receiverSetCommandPoint(SessionPoint());
+ s.receiverRecord(transferFrame(false));
+ s.receiverRecord(transferFrame(false));
+ s.receiverRecord(transferFrame(false));
+ s.receiverCompleted(1);
+ BOOST_CHECK_EQUAL(s.receiverGetUnknownComplete(), SequenceSet(SequenceSet()+1));
+ s.receiverCompleted(0);
+ BOOST_CHECK_EQUAL(s.receiverGetUnknownComplete(),
+ SequenceSet(SequenceSet() + qpid::Range<SequenceNumber>(0,2)));
+ s.receiverKnownCompleted(SequenceSet(SequenceSet()+1));
+ BOOST_CHECK_EQUAL(s.receiverGetUnknownComplete(), SequenceSet(SequenceSet()+2));
+ // TODO aconway 2008-04-30: missing tests for known-completed.
+}
+
+QPID_AUTO_TEST_CASE(testNeedKnownCompleted) {
+ size_t flushInterval= 2*(transferFrameSize()+contentFrameSize())+1;
+ qpid::SessionState::Configuration c(flushInterval);
+ qpid::SessionState s(qpid::SessionId(), c);
+ s.senderGetCommandPoint();
+ transfers(s, "a");
+ SequenceSet set(SequenceSet() + 0);
+ s.senderCompleted(set);
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+
+ transfers(s, "b");
+ set += 1;
+ s.senderCompleted(set);
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+
+ transfers(s, "c");
+ set += 2;
+ s.senderCompleted(set);
+ BOOST_CHECK(s.senderNeedKnownCompleted());
+ s.senderRecordKnownCompleted();
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+
+ transfers(s, "de");
+ set += 3;
+ set += 4;
+ s.senderCompleted(set);
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+
+ transfers(s, "f");
+ set += 2;
+ s.senderCompleted(set);
+ BOOST_CHECK(s.senderNeedKnownCompleted());
+ s.senderRecordKnownCompleted();
+ BOOST_CHECK(!s.senderNeedKnownCompleted());
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/Shlib.cpp b/RC9/qpid/cpp/src/tests/Shlib.cpp
new file mode 100644
index 0000000000..426a052c9f
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Shlib.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ *
+ */
+
+#include "test_tools.h"
+#include "qpid/sys/Shlib.h"
+#include "qpid/Exception.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(ShlibTestSuite)
+
+using namespace qpid::sys;
+typedef void (*CallMe)(int*);
+
+QPID_AUTO_TEST_CASE(testShlib) {
+ Shlib sh(".libs/libshlibtest.so");
+ // Double cast to avoid ISO warning.
+ CallMe callMe=sh.getSymbol<CallMe>("callMe");
+ BOOST_REQUIRE(callMe != 0);
+ int unloaded=0;
+ callMe(&unloaded);
+ sh.unload();
+ BOOST_CHECK_EQUAL(42, unloaded);
+ try {
+ sh.getSymbol("callMe");
+ BOOST_FAIL("Expected exception");
+ }
+ catch (const qpid::Exception&) {}
+}
+
+QPID_AUTO_TEST_CASE(testAutoShlib) {
+ int unloaded = 0;
+ {
+ AutoShlib sh(".libs/libshlibtest.so");
+ CallMe callMe=sh.getSymbol<CallMe>("callMe");
+ BOOST_REQUIRE(callMe != 0);
+ callMe(&unloaded);
+ }
+ BOOST_CHECK_EQUAL(42, unloaded);
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.cpp b/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.cpp
new file mode 100644
index 0000000000..2739734731
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.cpp
@@ -0,0 +1,87 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "SimpleTestCaseBase.h"
+
+using namespace qpid;
+
+void SimpleTestCaseBase::start()
+{
+ if (worker.get()) {
+ worker->start();
+ }
+}
+
+void SimpleTestCaseBase::stop()
+{
+ if (worker.get()) {
+ worker->stop();
+ }
+}
+
+void SimpleTestCaseBase::report(client::Message& report)
+{
+ if (worker.get()) {
+ report.getHeaders().setInt("MESSAGE_COUNT", worker->getCount());
+ //add number of messages sent or received
+ std::stringstream reportstr;
+ reportstr << worker->getCount();
+ report.setData(reportstr.str());
+ }
+}
+
+SimpleTestCaseBase::Sender::Sender(ConnectionOptions& options,
+ const Exchange& _exchange,
+ const std::string& _key,
+ const int _messages)
+ : Worker(options, _messages), exchange(_exchange), key(_key) {}
+
+void SimpleTestCaseBase::Sender::init()
+{
+ channel.start();
+}
+
+void SimpleTestCaseBase::Sender::start(){
+ Message msg;
+ while (count < messages) {
+ channel.publish(msg, exchange, key);
+ count++;
+ }
+ stop();
+}
+
+SimpleTestCaseBase::Worker::Worker(ConnectionOptions& options, const int _messages) :
+ messages(_messages), count(0)
+{
+ connection.open(options.host, options.port);
+ connection.openChannel(channel);
+}
+
+void SimpleTestCaseBase::Worker::stop()
+{
+ channel.close();
+ connection.close();
+}
+
+int SimpleTestCaseBase::Worker::getCount()
+{
+ return count;
+}
+
diff --git a/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.h b/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.h
new file mode 100644
index 0000000000..0c1052d0c2
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SimpleTestCaseBase.h
@@ -0,0 +1,89 @@
+#ifndef _SimpleTestCaseBase_
+#define _SimpleTestCaseBase_
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <memory>
+#include <sstream>
+
+#include "qpid/Exception.h"
+#include "qpid/client/Channel.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Connection.h"
+#include "ConnectionOptions.h"
+#include "qpid/client/MessageListener.h"
+#include "TestCase.h"
+
+
+namespace qpid {
+
+using namespace qpid::client;
+
+class SimpleTestCaseBase : public TestCase
+{
+protected:
+ class Worker
+ {
+ protected:
+ client::Connection connection;
+ client::Channel channel;
+ const int messages;
+ int count;
+
+ public:
+
+ Worker(ConnectionOptions& options, const int messages);
+ virtual ~Worker(){}
+
+ virtual void stop();
+ virtual int getCount();
+ virtual void init() = 0;
+ virtual void start() = 0;
+ };
+
+ class Sender : public Worker
+ {
+ const Exchange& exchange;
+ const std::string key;
+ public:
+ Sender(ConnectionOptions& options,
+ const Exchange& exchange,
+ const std::string& key,
+ const int messages);
+ void init();
+ void start();
+ };
+
+ std::auto_ptr<Worker> worker;
+
+public:
+ virtual void assign(const std::string& role, framing::FieldTable& params, ConnectionOptions& options) = 0;
+
+ virtual ~SimpleTestCaseBase() {}
+
+ void start();
+ void stop();
+ void report(client::Message& report);
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/SocketProxy.h b/RC9/qpid/cpp/src/tests/SocketProxy.h
new file mode 100644
index 0000000000..9722359d82
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/SocketProxy.h
@@ -0,0 +1,143 @@
+#ifndef SOCKETPROXY_H
+#define SOCKETPROXY_H
+
+/*
+ * 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.
+ *
+ */
+
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/Poller.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Mutex.h"
+#include "qpid/client/Connection.h"
+#include "qpid/log/Statement.h"
+
+#include <algorithm>
+
+/**
+ * A simple socket proxy that forwards to another socket.
+ * Used between client & local broker to simulate network failures.
+ */
+class SocketProxy : private qpid::sys::Runnable
+{
+ public:
+ /** Connect to connectPort on host, start a forwarding thread.
+ * Listen for connection on getPort().
+ */
+ SocketProxy(int connectPort, const std::string host="localhost")
+ : closed(false), port(listener.listen()), dropClient(), dropServer()
+ {
+ client.connect(host, connectPort);
+ thread = qpid::sys::Thread(static_cast<qpid::sys::Runnable*>(this));
+ }
+
+ ~SocketProxy() { close(); }
+
+ /** Simulate a network disconnect. */
+ void close() {
+ {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ if (closed) return;
+ closed=true;
+ }
+ poller.shutdown();
+ if (thread.id() != qpid::sys::Thread::current().id())
+ thread.join();
+ client.close();
+ }
+
+ /** Simulate lost packets, drop data from client */
+ void dropClientData(bool drop=true) { dropClient=drop; }
+
+ /** Simulate lost packets, drop data from server */
+ void dropServerData(bool drop=true) { dropServer=drop; }
+
+ bool isClosed() const {
+ qpid::sys::Mutex::ScopedLock l(lock);
+ return closed;
+ }
+
+ uint16_t getPort() const { return port; }
+
+ private:
+ static void throwErrno(const std::string& msg) {
+ throw qpid::Exception(msg+":"+qpid::sys::strError(errno));
+ }
+ static void throwIf(bool condition, const std::string& msg) {
+ if (condition) throw qpid::Exception(msg);
+ }
+
+ void run() {
+ std::auto_ptr<qpid::sys::Socket> server;
+ try {
+ qpid::sys::PollerHandle listenerHandle(listener);
+ poller.addFd(listenerHandle, qpid::sys::Poller::INPUT);
+ qpid::sys::Poller::Event event = poller.wait();
+ throwIf(event.type == qpid::sys::Poller::SHUTDOWN, "SocketProxy: Closed by close()");
+ throwIf(!(event.type == qpid::sys::Poller::READABLE && event.handle == &listenerHandle), "SocketProxy: Accept failed");
+
+ poller.delFd(listenerHandle);
+ server.reset(listener.accept(0, 0));
+
+ // Pump data between client & server sockets
+ qpid::sys::PollerHandle clientHandle(client);
+ qpid::sys::PollerHandle serverHandle(*server);
+ poller.addFd(clientHandle, qpid::sys::Poller::INPUT);
+ poller.addFd(serverHandle, qpid::sys::Poller::INPUT);
+ char buffer[1024];
+ for (;;) {
+ qpid::sys::Poller::Event event = poller.wait();
+ throwIf(event.type == qpid::sys::Poller::SHUTDOWN, "SocketProxy: Closed by close()");
+ throwIf(event.type == qpid::sys::Poller::DISCONNECTED, "SocketProxy: client/server disconnected");
+ if (event.handle == &serverHandle) {
+ ssize_t n = server->read(buffer, sizeof(buffer));
+ if (!dropServer) client.write(buffer, n);
+ poller.rearmFd(serverHandle);
+ } else if (event.handle == &clientHandle) {
+ ssize_t n = client.read(buffer, sizeof(buffer));
+ if (!dropClient) server->write(buffer, n);
+ poller.rearmFd(clientHandle);
+ } else {
+ throwIf(true, "SocketProxy: No handle ready");
+ }
+ }
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(debug, "SocketProxy::run exception: " << e.what());
+ }
+ try {
+ if (server.get()) server->close();
+ close();
+ }
+ catch (const std::exception& e) {
+ QPID_LOG(debug, "SocketProxy::run exception in client/server close()" << e.what());
+ }
+ }
+
+ mutable qpid::sys::Mutex lock;
+ bool closed;
+ qpid::sys::Poller poller;
+ qpid::sys::Socket client, listener;
+ uint16_t port;
+ qpid::sys::Thread thread;
+ bool dropClient, dropServer;
+};
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/StringUtils.cpp b/RC9/qpid/cpp/src/tests/StringUtils.cpp
new file mode 100644
index 0000000000..6a19119288
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/StringUtils.cpp
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include <iostream>
+#include "qpid/StringUtils.h"
+
+#include "unit_test.h"
+
+QPID_AUTO_TEST_SUITE(StringUtilsTestSuite)
+
+using namespace qpid;
+using std::string;
+
+QPID_AUTO_TEST_CASE(testSplit_general)
+{
+ std::vector<std::string> results = split("a bbbb, car,d123,,,e", ", ");
+ BOOST_CHECK_EQUAL(5u, results.size());
+ BOOST_CHECK_EQUAL(string("a"), results[0]);
+ BOOST_CHECK_EQUAL(string("bbbb"), results[1]);
+ BOOST_CHECK_EQUAL(string("car"), results[2]);
+ BOOST_CHECK_EQUAL(string("d123"), results[3]);
+ BOOST_CHECK_EQUAL(string("e"), results[4]);
+}
+
+QPID_AUTO_TEST_CASE(testSplit_noDelims)
+{
+ std::vector<std::string> results = split("abc", ", ");
+ BOOST_CHECK_EQUAL(1u, results.size());
+ BOOST_CHECK_EQUAL(string("abc"), results[0]);
+}
+
+QPID_AUTO_TEST_CASE(testSplit_delimAtEnd)
+{
+ std::vector<std::string> results = split("abc def,,", ", ");
+ BOOST_CHECK_EQUAL(2u, results.size());
+ BOOST_CHECK_EQUAL(string("abc"), results[0]);
+ BOOST_CHECK_EQUAL(string("def"), results[1]);
+}
+
+QPID_AUTO_TEST_CASE(testSplit_delimAtStart)
+{
+ std::vector<std::string> results = split(",,abc def", ", ");
+ BOOST_CHECK_EQUAL(2u, results.size());
+ BOOST_CHECK_EQUAL(string("abc"), results[0]);
+ BOOST_CHECK_EQUAL(string("def"), results[1]);
+}
+
+QPID_AUTO_TEST_CASE(testSplit_onlyDelims)
+{
+ std::vector<std::string> results = split(",, , ", ", ");
+ BOOST_CHECK_EQUAL(0u, results.size());
+}
+
+QPID_AUTO_TEST_CASE(testSplit_empty)
+{
+ std::vector<std::string> results = split("", ", ");
+ BOOST_CHECK_EQUAL(0u, results.size());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/TestCase.h b/RC9/qpid/cpp/src/tests/TestCase.h
new file mode 100644
index 0000000000..ba3330c951
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TestCase.h
@@ -0,0 +1,64 @@
+#ifndef _TestCase_
+#define _TestCase_
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "ConnectionOptions.h"
+#include "qpid/client/Message.h"
+
+
+namespace qpid {
+
+/**
+ * Interface to be implemented by test cases for use with the test
+ * runner.
+ */
+class TestCase
+{
+public:
+ /**
+ * Directs the test case to act in a particular role. Some roles
+ * may be 'activated' at this stage others may require an explicit
+ * start request.
+ */
+ virtual void assign(const std::string& role, framing::FieldTable& params, client::ConnectionOptions& options) = 0;
+ /**
+ * Each test will be started on its own thread, which should block
+ * until the test completes (this may or may not require an
+ * explicit stop() request).
+ */
+ virtual void start() = 0;
+ /**
+ * Requests that the test be stopped if still running.
+ */
+ virtual void stop() = 0;
+ /**
+ * Allows the test to fill in details on the final report
+ * message. Will be called only after start has returned.
+ */
+ virtual void report(client::Message& report) = 0;
+
+ virtual ~TestCase() {}
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/TestMessageStore.h b/RC9/qpid/cpp/src/tests/TestMessageStore.h
new file mode 100644
index 0000000000..be1ed57349
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TestMessageStore.h
@@ -0,0 +1,58 @@
+#ifndef _tests_TestMessageStore_h
+#define _tests_TestMessageStore_h
+
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/broker/NullMessageStore.h"
+#include <vector>
+
+using namespace qpid;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+typedef std::pair<string, boost::intrusive_ptr<PersistableMessage> > msg_queue_pair;
+
+class TestMessageStore : public NullMessageStore
+{
+ public:
+ std::vector<boost::intrusive_ptr<PersistableMessage> > dequeued;
+ std::vector<msg_queue_pair> enqueued;
+
+ void dequeue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& /*queue*/)
+ {
+ dequeued.push_back(msg);
+ }
+
+ void enqueue(TransactionContext*,
+ const boost::intrusive_ptr<PersistableMessage>& msg,
+ const PersistableQueue& queue)
+ {
+ msg->enqueueComplete();
+ enqueued.push_back(msg_queue_pair(queue.getName(), msg));
+ }
+
+ TestMessageStore() : NullMessageStore() {}
+ ~TestMessageStore(){}
+};
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/TestOptions.h b/RC9/qpid/cpp/src/tests/TestOptions.h
new file mode 100644
index 0000000000..a400fe5ecb
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TestOptions.h
@@ -0,0 +1,79 @@
+#ifndef _TestOptions_
+#define _TestOptions_
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/Options.h"
+#include "qpid/log/Options.h"
+#include "qpid/Url.h"
+#include "qpid/log/Logger.h"
+#include "qpid/client/Connection.h"
+#include "ConnectionOptions.h"
+
+#include <iostream>
+#include <exception>
+
+namespace qpid {
+
+struct TestOptions : public qpid::Options
+{
+ TestOptions(const std::string& helpText_=std::string(),
+ const std::string& argv0=std::string())
+ : Options("Test Options"), help(false), log(argv0), helpText(helpText_)
+ {
+ addOptions()
+ ("help", optValue(help), "print this usage statement");
+ add(con);
+ add(log);
+ }
+
+ /** As well as parsing, throw help message if requested. */
+ void parse(int argc, char** argv) {
+ try {
+ qpid::Options::parse(argc, argv);
+ } catch (const std::exception& e) {
+ std::ostringstream msg;
+ msg << *this << std::endl << std::endl << e.what() << std::endl;
+ throw qpid::Options::Exception(msg.str());
+ }
+ qpid::log::Logger::instance().configure(log);
+ if (help) {
+ std::ostringstream msg;
+ msg << *this << std::endl << std::endl << helpText << std::endl;
+ throw qpid::Options::Exception(msg.str());
+ }
+ }
+
+ /** Open a connection using option values */
+ void open(qpid::client::Connection& connection) {
+ connection.open(con);
+ }
+
+
+ bool help;
+ ConnectionOptions con;
+ qpid::log::Options log;
+ std::string helpText;
+};
+
+}
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/TimerTest.cpp b/RC9/qpid/cpp/src/tests/TimerTest.cpp
new file mode 100644
index 0000000000..50712ff79c
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TimerTest.cpp
@@ -0,0 +1,120 @@
+
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/broker/Timer.h"
+#include "qpid/sys/Monitor.h"
+#include "unit_test.h"
+#include <math.h>
+#include <iostream>
+#include <memory>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+
+using namespace qpid::broker;
+using namespace qpid::sys;
+using boost::intrusive_ptr;
+using boost::dynamic_pointer_cast;
+
+class Counter
+{
+ Mutex lock;
+ uint counter;
+ public:
+ Counter() : counter(0) {}
+ uint next()
+ {
+ Mutex::ScopedLock l(lock);
+ return ++counter;
+ }
+};
+
+class TestTask : public TimerTask
+{
+ const AbsTime start;
+ const Duration expected;
+ AbsTime end;
+ bool fired;
+ uint position;
+ Monitor monitor;
+ Counter& counter;
+
+ public:
+ TestTask(Duration timeout, Counter& _counter)
+ : TimerTask(timeout), start(now()), expected(timeout), end(start), fired(false), counter(_counter) {}
+
+ void fire()
+ {
+ Monitor::ScopedLock l(monitor);
+ fired = true;
+ position = counter.next();
+ end = now();
+ monitor.notify();
+ }
+
+ void check(uint expected_position, uint64_t tolerance = 500 * TIME_MSEC)
+ {
+ Monitor::ScopedLock l(monitor);
+ BOOST_CHECK(fired);
+ BOOST_CHECK_EQUAL(expected_position, position);
+ Duration actual(start, end);
+ uint64_t difference = abs(expected - actual);
+ std::string msg(boost::lexical_cast<std::string>(boost::format("tolerance = %1%, difference = %2%") % tolerance % difference));
+ BOOST_CHECK_MESSAGE(difference < tolerance, msg);
+ }
+
+ void wait(Duration d)
+ {
+ Monitor::ScopedLock l(monitor);
+ monitor.wait(AbsTime(now(), d));
+ }
+};
+
+class DummyRunner : public Runnable
+{
+ public:
+ void run() {}
+};
+
+QPID_AUTO_TEST_SUITE(TimerTestSuite)
+
+QPID_AUTO_TEST_CASE(testGeneral)
+{
+ Counter counter;
+ Timer timer;
+ intrusive_ptr<TestTask> task1(new TestTask(Duration(3 * TIME_SEC), counter));
+ intrusive_ptr<TestTask> task2(new TestTask(Duration(1 * TIME_SEC), counter));
+ intrusive_ptr<TestTask> task3(new TestTask(Duration(4 * TIME_SEC), counter));
+ intrusive_ptr<TestTask> task4(new TestTask(Duration(2 * TIME_SEC), counter));
+
+ timer.add(task1);
+ timer.add(task2);
+ timer.add(task3);
+ timer.add(task4);
+
+ dynamic_pointer_cast<TestTask>(task3)->wait(Duration(6 * TIME_SEC));
+
+ dynamic_pointer_cast<TestTask>(task1)->check(3);
+ dynamic_pointer_cast<TestTask>(task2)->check(1);
+ dynamic_pointer_cast<TestTask>(task3)->check(4);
+ dynamic_pointer_cast<TestTask>(task4)->check(2);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/TopicExchangeTest.cpp b/RC9/qpid/cpp/src/tests/TopicExchangeTest.cpp
new file mode 100644
index 0000000000..af4263de34
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TopicExchangeTest.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+#include "qpid/broker/TopicExchange.h"
+#include "unit_test.h"
+#include "test_tools.h"
+
+using namespace qpid::broker;
+
+Tokens makeTokens(const char** begin, const char** end)
+{
+ Tokens t;
+ t.insert(t.end(), begin, end);
+ return t;
+}
+
+// Calculate size of an array.
+#define LEN(a) (sizeof(a)/sizeof(a[0]))
+
+// Convert array to token vector
+#define TOKENS(a) makeTokens(a, a + LEN(a))
+
+#define ASSERT_NORMALIZED(expect, pattern) \
+ BOOST_CHECK_EQUAL(Tokens(expect), static_cast<Tokens>(TopicPattern(pattern)))
+
+
+QPID_AUTO_TEST_SUITE(TopicExchangeTestSuite)
+
+QPID_AUTO_TEST_CASE(testTokens)
+{
+ Tokens tokens("hello.world");
+ const char* expect[] = {"hello", "world"};
+ BOOST_CHECK_EQUAL(TOKENS(expect), tokens);
+
+ tokens = "a.b.c";
+ const char* expect2[] = { "a", "b", "c" };
+ BOOST_CHECK_EQUAL(TOKENS(expect2), tokens);
+
+ tokens = "";
+ BOOST_CHECK(tokens.empty());
+
+ tokens = "x";
+ const char* expect3[] = { "x" };
+ BOOST_CHECK_EQUAL(TOKENS(expect3), tokens);
+
+ tokens = (".x");
+ const char* expect4[] = { "", "x" };
+ BOOST_CHECK_EQUAL(TOKENS(expect4), tokens);
+
+ tokens = ("x.");
+ const char* expect5[] = { "x", "" };
+ BOOST_CHECK_EQUAL(TOKENS(expect5), tokens);
+
+ tokens = (".");
+ const char* expect6[] = { "", "" };
+ BOOST_CHECK_EQUAL(TOKENS(expect6), tokens);
+
+ tokens = ("..");
+ const char* expect7[] = { "", "", "" };
+ BOOST_CHECK_EQUAL(TOKENS(expect7), tokens);
+}
+
+QPID_AUTO_TEST_CASE(testNormalize)
+{
+ BOOST_CHECK(TopicPattern("").empty());
+ ASSERT_NORMALIZED("a.b.c", "a.b.c");
+ ASSERT_NORMALIZED("a.*.c", "a.*.c");
+ ASSERT_NORMALIZED("#", "#");
+ ASSERT_NORMALIZED("#", "#.#.#.#");
+ ASSERT_NORMALIZED("*.*.*.#", "#.*.#.*.#.#.*");
+ ASSERT_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*.#");
+ ASSERT_NORMALIZED("a.*.*.*.#", "a.*.#.*.#.*");
+}
+
+QPID_AUTO_TEST_CASE(testPlain)
+{
+ TopicPattern p("ab.cd.e");
+ BOOST_CHECK(p.match("ab.cd.e"));
+ BOOST_CHECK(!p.match("abx.cd.e"));
+ BOOST_CHECK(!p.match("ab.cd"));
+ BOOST_CHECK(!p.match("ab.cd..e."));
+ BOOST_CHECK(!p.match("ab.cd.e."));
+ BOOST_CHECK(!p.match(".ab.cd.e"));
+
+ p = "";
+ BOOST_CHECK(p.match(""));
+
+ p = ".";
+ BOOST_CHECK(p.match("."));
+}
+
+
+QPID_AUTO_TEST_CASE(testStar)
+{
+ TopicPattern p("a.*.b");
+ BOOST_CHECK(p.match("a.xx.b"));
+ BOOST_CHECK(!p.match("a.b"));
+
+ p = "*.x";
+ BOOST_CHECK(p.match("y.x"));
+ BOOST_CHECK(p.match(".x"));
+ BOOST_CHECK(!p.match("x"));
+
+ p = "x.x.*";
+ BOOST_CHECK(p.match("x.x.y"));
+ BOOST_CHECK(p.match("x.x."));
+ BOOST_CHECK(!p.match("x.x"));
+ BOOST_CHECK(!p.match("q.x.y"));
+}
+
+QPID_AUTO_TEST_CASE(testHash)
+{
+ TopicPattern p("a.#.b");
+ BOOST_CHECK(p.match("a.b"));
+ BOOST_CHECK(p.match("a.x.b"));
+ BOOST_CHECK(p.match("a..x.y.zz.b"));
+ BOOST_CHECK(!p.match("a.b."));
+ BOOST_CHECK(!p.match("q.x.b"));
+
+ p = "a.#";
+ BOOST_CHECK(p.match("a"));
+ BOOST_CHECK(p.match("a.b"));
+ BOOST_CHECK(p.match("a.b.c"));
+
+ p = "#.a";
+ BOOST_CHECK(p.match("a"));
+ BOOST_CHECK(p.match("x.y.a"));
+}
+
+QPID_AUTO_TEST_CASE(testMixed)
+{
+ TopicPattern p("*.x.#.y");
+ BOOST_CHECK(p.match("a.x.y"));
+ BOOST_CHECK(p.match("a.x.p.qq.y"));
+ BOOST_CHECK(!p.match("a.a.x.y"));
+ BOOST_CHECK(!p.match("aa.x.b.c"));
+
+ p = "a.#.b.*";
+ BOOST_CHECK(p.match("a.b.x"));
+ BOOST_CHECK(p.match("a.x.x.x.b.x"));
+}
+
+QPID_AUTO_TEST_CASE(testCombo)
+{
+ TopicPattern p("*.#.#.*.*.#");
+ BOOST_CHECK(p.match("x.y.z"));
+ BOOST_CHECK(p.match("x.y.z.a.b.c"));
+ BOOST_CHECK(!p.match("x.y"));
+ BOOST_CHECK(!p.match("x"));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/TxBufferTest.cpp b/RC9/qpid/cpp/src/tests/TxBufferTest.cpp
new file mode 100644
index 0000000000..3d6a12cacc
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TxBufferTest.cpp
@@ -0,0 +1,176 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/broker/TxBuffer.h"
+#include "unit_test.h"
+#include <iostream>
+#include <vector>
+#include "TxMocks.h"
+
+using namespace qpid::broker;
+using boost::static_pointer_cast;
+
+QPID_AUTO_TEST_SUITE(TxBufferTestSuite)
+
+QPID_AUTO_TEST_CASE(testCommitLocal)
+{
+ MockTransactionalStore store;
+ store.expectBegin().expectCommit();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectCommit();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare().expectPrepare().expectCommit().expectCommit();//opB enlisted twice to test relative order
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectPrepare().expectCommit();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));//opB enlisted twice
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ BOOST_CHECK(buffer.commitLocal(&store));
+ store.check();
+ BOOST_CHECK(store.isCommitted());
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testFailOnCommitLocal)
+{
+ MockTransactionalStore store;
+ store.expectBegin().expectAbort();
+
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectPrepare().expectRollback();
+ MockTxOp::shared_ptr opC(new MockTxOp());//will never get prepare as b will fail
+ opC->expectRollback();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ BOOST_CHECK(!buffer.commitLocal(&store));
+ BOOST_CHECK(store.isAborted());
+ store.check();
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testPrepare)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectPrepare();
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectPrepare();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ BOOST_CHECK(buffer.prepare(0));
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testFailOnPrepare)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectPrepare();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectPrepare();
+ MockTxOp::shared_ptr opC(new MockTxOp());//will never get prepare as b will fail
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ BOOST_CHECK(!buffer.prepare(0));
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testRollback)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp(true));
+ opB->expectRollback();
+ MockTxOp::shared_ptr opC(new MockTxOp());
+ opC->expectRollback();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+ buffer.enlist(static_pointer_cast<TxOp>(opC));
+
+ buffer.rollback();
+ opA->check();
+ opB->check();
+ opC->check();
+}
+
+QPID_AUTO_TEST_CASE(testBufferIsClearedAfterRollback)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectRollback();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectRollback();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+
+ buffer.rollback();
+ buffer.commit();//second call should not reach ops
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_CASE(testBufferIsClearedAfterCommit)
+{
+ MockTxOp::shared_ptr opA(new MockTxOp());
+ opA->expectCommit();
+ MockTxOp::shared_ptr opB(new MockTxOp());
+ opB->expectCommit();
+
+ TxBuffer buffer;
+ buffer.enlist(static_pointer_cast<TxOp>(opA));
+ buffer.enlist(static_pointer_cast<TxOp>(opB));
+
+ buffer.commit();
+ buffer.rollback();//second call should not reach ops
+ opA->check();
+ opB->check();
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/TxMocks.h b/RC9/qpid/cpp/src/tests/TxMocks.h
new file mode 100644
index 0000000000..fe103c5fe5
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TxMocks.h
@@ -0,0 +1,229 @@
+/*
+ *
+ * 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.
+ *
+ */
+#ifndef _tests_TxMocks_h
+#define _tests_TxMocks_h
+
+
+#include "qpid/Exception.h"
+#include "qpid/broker/TransactionalStore.h"
+#include "qpid/broker/TxOp.h"
+#include <iostream>
+#include <vector>
+
+using namespace qpid::broker;
+using boost::static_pointer_cast;
+using std::string;
+
+template <class T> void assertEqualVector(std::vector<T>& expected, std::vector<T>& actual){
+ unsigned int i = 0;
+ while(i < expected.size() && i < actual.size()){
+ BOOST_CHECK_EQUAL(expected[i], actual[i]);
+ i++;
+ }
+ if (i < expected.size()) {
+ throw qpid::Exception(QPID_MSG("Missing " << expected[i]));
+ } else if (i < actual.size()) {
+ throw qpid::Exception(QPID_MSG("Extra " << actual[i]));
+ }
+ BOOST_CHECK_EQUAL(expected.size(), actual.size());
+}
+
+class TxOpConstants{
+protected:
+ const string PREPARE;
+ const string COMMIT;
+ const string ROLLBACK;
+
+ TxOpConstants() : PREPARE("PREPARE"), COMMIT("COMMIT"), ROLLBACK("ROLLBACK") {}
+};
+
+class MockTxOp : public TxOp, public TxOpConstants{
+ std::vector<string> expected;
+ std::vector<string> actual;
+ bool failOnPrepare;
+ string debugName;
+public:
+ typedef boost::shared_ptr<MockTxOp> shared_ptr;
+
+ MockTxOp() : failOnPrepare(false) {}
+ MockTxOp(bool _failOnPrepare) : failOnPrepare(_failOnPrepare) {}
+
+ void setDebugName(string name){
+ debugName = name;
+ }
+
+ void printExpected(){
+ std::cout << std::endl << "MockTxOp[" << debugName << "] expects: ";
+ for (std::vector<string>::iterator i = expected.begin(); i < expected.end(); i++) {
+ if(i != expected.begin()) std::cout << ", ";
+ std::cout << *i;
+ }
+ std::cout << std::endl;
+ }
+
+ void printActual(){
+ std::cout << std::endl << "MockTxOp[" << debugName << "] actual: ";
+ for (std::vector<string>::iterator i = actual.begin(); i < actual.end(); i++) {
+ if(i != actual.begin()) std::cout << ", ";
+ std::cout << *i;
+ }
+ std::cout << std::endl;
+ }
+
+ bool prepare(TransactionContext*) throw(){
+ actual.push_back(PREPARE);
+ return !failOnPrepare;
+ }
+ void commit() throw(){
+ actual.push_back(COMMIT);
+ }
+ void rollback() throw(){
+ if(!debugName.empty()) std::cout << std::endl << "MockTxOp[" << debugName << "]::rollback()" << std::endl;
+ actual.push_back(ROLLBACK);
+ }
+ MockTxOp& expectPrepare(){
+ expected.push_back(PREPARE);
+ return *this;
+ }
+ MockTxOp& expectCommit(){
+ expected.push_back(COMMIT);
+ return *this;
+ }
+ MockTxOp& expectRollback(){
+ expected.push_back(ROLLBACK);
+ return *this;
+ }
+ void check(){
+ assertEqualVector(expected, actual);
+ }
+
+ void accept(TxOpConstVisitor&) const {}
+
+ ~MockTxOp(){}
+};
+
+class MockTransactionalStore : public TransactionalStore{
+ const string BEGIN;
+ const string BEGIN2PC;
+ const string PREPARE;
+ const string COMMIT;
+ const string ABORT;
+ std::vector<string> expected;
+ std::vector<string> actual;
+
+ enum states {OPEN = 1, PREPARED = 2, COMMITTED = 3, ABORTED = 4};
+ int state;
+
+ class TestTransactionContext : public TPCTransactionContext{
+ MockTransactionalStore* store;
+ public:
+ TestTransactionContext(MockTransactionalStore* _store) : store(_store) {}
+ void prepare(){
+ if(!store->isOpen()) throw "txn already completed";
+ store->state = PREPARED;
+ }
+
+ void commit(){
+ if(!store->isOpen() && !store->isPrepared()) throw "txn already completed";
+ store->state = COMMITTED;
+ }
+
+ void abort(){
+ if(!store->isOpen() && !store->isPrepared()) throw "txn already completed";
+ store->state = ABORTED;
+ }
+ ~TestTransactionContext(){}
+ };
+
+public:
+ MockTransactionalStore() :
+ BEGIN("BEGIN"), BEGIN2PC("BEGIN2PC"), PREPARE("PREPARE"), COMMIT("COMMIT"), ABORT("ABORT"), state(OPEN){}
+
+ void collectPreparedXids(std::set<std::string>&)
+ {
+ throw "Operation not supported";
+ }
+
+ std::auto_ptr<TPCTransactionContext> begin(const std::string&){
+ actual.push_back(BEGIN2PC);
+ std::auto_ptr<TPCTransactionContext> txn(new TestTransactionContext(this));
+ return txn;
+ }
+ std::auto_ptr<TransactionContext> begin(){
+ actual.push_back(BEGIN);
+ std::auto_ptr<TransactionContext> txn(new TestTransactionContext(this));
+ return txn;
+ }
+ void prepare(TPCTransactionContext& ctxt){
+ actual.push_back(PREPARE);
+ dynamic_cast<TestTransactionContext&>(ctxt).prepare();
+ }
+ void commit(TransactionContext& ctxt){
+ actual.push_back(COMMIT);
+ dynamic_cast<TestTransactionContext&>(ctxt).commit();
+ }
+ void abort(TransactionContext& ctxt){
+ actual.push_back(ABORT);
+ dynamic_cast<TestTransactionContext&>(ctxt).abort();
+ }
+ MockTransactionalStore& expectBegin(){
+ expected.push_back(BEGIN);
+ return *this;
+ }
+ MockTransactionalStore& expectBegin2PC(){
+ expected.push_back(BEGIN2PC);
+ return *this;
+ }
+ MockTransactionalStore& expectPrepare(){
+ expected.push_back(PREPARE);
+ return *this;
+ }
+ MockTransactionalStore& expectCommit(){
+ expected.push_back(COMMIT);
+ return *this;
+ }
+ MockTransactionalStore& expectAbort(){
+ expected.push_back(ABORT);
+ return *this;
+ }
+ void check(){
+ assertEqualVector(expected, actual);
+ }
+
+ bool isPrepared(){
+ return state == PREPARED;
+ }
+
+ bool isCommitted(){
+ return state == COMMITTED;
+ }
+
+ bool isAborted(){
+ return state == ABORTED;
+ }
+
+ bool isOpen() const{
+ return state == OPEN;
+ }
+ ~MockTransactionalStore(){}
+};
+
+#endif
diff --git a/RC9/qpid/cpp/src/tests/TxPublishTest.cpp b/RC9/qpid/cpp/src/tests/TxPublishTest.cpp
new file mode 100644
index 0000000000..9e9715c987
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/TxPublishTest.cpp
@@ -0,0 +1,94 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "qpid/broker/NullMessageStore.h"
+#include "qpid/broker/RecoveryManager.h"
+#include "qpid/broker/TxPublish.h"
+#include "unit_test.h"
+#include <iostream>
+#include <list>
+#include <vector>
+#include "MessageUtils.h"
+#include "TestMessageStore.h"
+
+using std::list;
+using std::pair;
+using std::vector;
+using boost::intrusive_ptr;
+using namespace qpid::broker;
+using namespace qpid::framing;
+
+struct TxPublishTest
+{
+
+ TestMessageStore store;
+ Queue::shared_ptr queue1;
+ Queue::shared_ptr queue2;
+ intrusive_ptr<Message> msg;
+ TxPublish op;
+
+ TxPublishTest() :
+ queue1(new Queue("queue1", false, &store, 0)),
+ queue2(new Queue("queue2", false, &store, 0)),
+ msg(MessageUtils::createMessage("exchange", "routing_key", "id")),
+ op(msg)
+ {
+ msg->getProperties<DeliveryProperties>()->setDeliveryMode(PERSISTENT);
+ op.deliverTo(queue1);
+ op.deliverTo(queue2);
+ }
+};
+
+
+QPID_AUTO_TEST_SUITE(TxPublishTestSuite)
+
+QPID_AUTO_TEST_CASE(testPrepare)
+{
+ TxPublishTest t;
+
+ intrusive_ptr<PersistableMessage> pmsg = static_pointer_cast<PersistableMessage>(t.msg);
+ //ensure messages are enqueued in store
+ t.op.prepare(0);
+ BOOST_CHECK_EQUAL((size_t) 2, t.store.enqueued.size());
+ BOOST_CHECK_EQUAL(string("queue1"), t.store.enqueued[0].first);
+ BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[0].second);
+ BOOST_CHECK_EQUAL(string("queue2"), t.store.enqueued[1].first);
+ BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[1].second);
+ BOOST_CHECK_EQUAL( true, ( static_pointer_cast<PersistableMessage>(t.msg))->isEnqueueComplete());
+}
+
+QPID_AUTO_TEST_CASE(testCommit)
+{
+ TxPublishTest t;
+
+ //ensure messages are delivered to queue
+ t.op.prepare(0);
+ t.op.commit();
+ BOOST_CHECK_EQUAL((uint32_t) 1, t.queue1->getMessageCount());
+ intrusive_ptr<Message> msg_dequeue = t.queue1->get().payload;
+
+ BOOST_CHECK_EQUAL( true, (static_pointer_cast<PersistableMessage>(msg_dequeue))->isEnqueueComplete());
+ BOOST_CHECK_EQUAL(t.msg, msg_dequeue);
+
+ BOOST_CHECK_EQUAL((uint32_t) 1, t.queue2->getMessageCount());
+ BOOST_CHECK_EQUAL(t.msg, t.queue2->get().payload);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/Url.cpp b/RC9/qpid/cpp/src/tests/Url.cpp
new file mode 100644
index 0000000000..f3b42a7208
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Url.cpp
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "qpid/Url.h"
+#include <boost/assign.hpp>
+
+using namespace std;
+using namespace qpid;
+using namespace boost::assign;
+
+QPID_AUTO_TEST_SUITE(UrlTestSuite)
+
+#define URL_CHECK_STR(STR) BOOST_CHECK_EQUAL(Url(STR).str(), STR)
+#define URL_CHECK_INVALID(STR) BOOST_CHECK_THROW(Url(STR), Url::Invalid)
+
+QPID_AUTO_TEST_CASE(TestParseTcp) {
+ URL_CHECK_STR("amqp:tcp:host:42");
+ URL_CHECK_STR("amqp:tcp:host-._~%ff%23:42"); // unreserved chars and pct encoded hex.
+
+ // Check defaults
+ BOOST_CHECK_EQUAL(Url("amqp:host:42").str(), "amqp:tcp:host:42");
+ BOOST_CHECK_EQUAL(Url("amqp:tcp:host").str(), "amqp:tcp:host:5672");
+ BOOST_CHECK_EQUAL(Url("amqp:tcp:").str(), "amqp:tcp:127.0.0.1:5672");
+ BOOST_CHECK_EQUAL(Url("amqp:").str(), "amqp:tcp:127.0.0.1:5672");
+ BOOST_CHECK_EQUAL(Url("amqp::42").str(), "amqp:tcp:127.0.0.1:42");
+
+ URL_CHECK_INVALID("amqp::badHost!#$#");
+ URL_CHECK_INVALID("amqp::host:badPort");
+}
+
+QPID_AUTO_TEST_CASE(TestParseExample) {
+ URL_CHECK_STR("amqp:example:x");
+ URL_CHECK_INVALID("amqp:example:badExample");
+}
+
+QPID_AUTO_TEST_CASE(TestParseMultiAddress) {
+ URL_CHECK_STR("amqp:tcp:host:0,example:y,tcp:foo:0,example:1");
+ URL_CHECK_STR("amqp:example:z,tcp:foo:0");
+ URL_CHECK_INVALID("amqp:tcp:h:0,");
+ URL_CHECK_INVALID(",amqp:tcp:h");
+}
+
+
+QPID_AUTO_TEST_CASE(TestInvalidAddress) {
+ URL_CHECK_INVALID("xxxx");
+ URL_CHECK_INVALID("");
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/Uuid.cpp b/RC9/qpid/cpp/src/tests/Uuid.cpp
new file mode 100644
index 0000000000..ee86d75a26
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/Uuid.cpp
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/Buffer.h"
+
+#include "unit_test.h"
+
+#include <set>
+#include <alloca.h>
+
+QPID_AUTO_TEST_SUITE(UuidTestSuite)
+
+using namespace std;
+using namespace qpid::framing;
+
+struct UniqueSet : public std::set<Uuid> {
+ void operator()(const Uuid& uuid) {
+ BOOST_REQUIRE(find(uuid) == end());
+ insert(uuid);
+ }
+};
+
+QPID_AUTO_TEST_CASE(testUuidCtor) {
+ // Uniqueness
+ boost::array<Uuid,1000> uuids;
+ for_each(uuids.begin(), uuids.end(), mem_fun_ref(&Uuid::generate));
+ UniqueSet unique;
+ for_each(uuids.begin(), uuids.end(), unique);
+}
+
+boost::array<uint8_t, 16> sample = {{'\x1b', '\x4e', '\x28', '\xba', '\x2f', '\xa1', '\x11', '\xd2', '\x88', '\x3f', '\xb9', '\xa7', '\x61', '\xbd', '\xe3', '\xfb'}};
+const string sampleStr("1b4e28ba-2fa1-11d2-883f-b9a761bde3fb");
+
+QPID_AUTO_TEST_CASE(testUuidIstream) {
+ Uuid uuid;
+ istringstream in(sampleStr);
+ in >> uuid;
+ BOOST_CHECK(!in.fail());
+ BOOST_CHECK(uuid == sample);
+}
+
+QPID_AUTO_TEST_CASE(testUuidOstream) {
+ Uuid uuid(sample.c_array());
+ ostringstream out;
+ out << uuid;
+ BOOST_CHECK(out.good());
+ BOOST_CHECK_EQUAL(out.str(), sampleStr);
+}
+
+QPID_AUTO_TEST_CASE(testUuidEncodeDecode) {
+ char* buff = static_cast<char*>(::alloca(Uuid::size()));
+ Buffer wbuf(buff, Uuid::size());
+ Uuid uuid(sample.c_array());
+ uuid.encode(wbuf);
+
+ Buffer rbuf(buff, Uuid::size());
+ Uuid decoded;
+ decoded.decode(rbuf);
+ BOOST_CHECK_EQUAL(string(sample.begin(), sample.end()),
+ string(decoded.begin(), decoded.end()));
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/XmlClientSessionTest.cpp b/RC9/qpid/cpp/src/tests/XmlClientSessionTest.cpp
new file mode 100644
index 0000000000..98558f0a76
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/XmlClientSessionTest.cpp
@@ -0,0 +1,221 @@
+/*
+ *
+ * Licensed to the Apachef 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.
+ *
+ */
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/sys/Shlib.h"
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/framing/TransferContent.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/LocalQueue.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+
+#include <boost/optional.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <vector>
+
+QPID_AUTO_TEST_SUITE(XmlClientSessionTest)
+
+using namespace qpid::client;
+
+using namespace qpid::client::arg;
+using namespace qpid::framing;
+using namespace qpid;
+using qpid::sys::Shlib;
+using qpid::sys::Monitor;
+using std::string;
+using std::cout;
+using std::endl;
+
+Shlib shlib("../.libs/xml.so");
+
+class SubscribedLocalQueue : public LocalQueue {
+ private:
+ SubscriptionManager& subscriptions;
+ public:
+ SubscribedLocalQueue(SubscriptionManager& subs) : subscriptions(subs) {}
+ Message get () { return pop(); }
+ virtual ~SubscribedLocalQueue() {}
+};
+
+
+struct SimpleListener : public MessageListener
+{
+ Monitor lock;
+ std::vector<Message> messages;
+
+ void received(Message& msg)
+ {
+ Monitor::ScopedLock l(lock);
+ messages.push_back(msg);
+ lock.notifyAll();
+ }
+
+ void waitFor(const uint n)
+ {
+ Monitor::ScopedLock l(lock);
+ while (messages.size() < n) {
+ lock.wait();
+ }
+ }
+};
+
+struct ClientSessionFixture : public ProxySessionFixture
+{
+ void declareSubscribe(const string& q="odd_blue",
+ const string& dest="xml")
+ {
+ session.queueDeclare(queue=q);
+ session.messageSubscribe(queue=q, destination=dest, acquireMode=1);
+ session.messageFlow(destination=dest, unit=0, value=0xFFFFFFFF);//messages
+ session.messageFlow(destination=dest, unit=1, value=0xFFFFFFFF);//bytes
+ }
+};
+
+// ########### START HERE ####################################
+
+
+
+QPID_AUTO_TEST_CASE(testXmlBinding) {
+ ClientSessionFixture f;
+
+ SubscriptionManager subscriptions(f.session);
+ SubscribedLocalQueue localQueue(subscriptions);
+
+ f.session.exchangeDeclare(qpid::client::arg::exchange="xml", qpid::client::arg::type="xml");
+ f.session.queueDeclare(qpid::client::arg::queue="odd_blue");
+ subscriptions.subscribe(localQueue, "odd_blue");
+
+ FieldTable binding;
+ binding.setString("xquery", "declare variable $color external;"
+ "(./message/id mod 2 = 1) and ($color = 'blue')");
+ f.session.exchangeBind(qpid::client::arg::exchange="xml", qpid::client::arg::queue="odd_blue", qpid::client::arg::bindingKey="query_name", qpid::client::arg::arguments=binding);
+
+ Message message;
+ message.getDeliveryProperties().setRoutingKey("query_name");
+
+ message.getHeaders().setString("color", "blue");
+ string m = "<message><id>1</id></message>";
+ message.setData(m);
+
+ f.session.messageTransfer(qpid::client::arg::content=message, qpid::client::arg::destination="xml");
+
+ Message m2 = localQueue.get();
+ BOOST_CHECK_EQUAL(m, m2.getData());
+}
+
+/**
+ * Ensure that multiple queues can be bound using the same routing key
+ */
+QPID_AUTO_TEST_CASE(testXMLBindMultipleQueues) {
+ ClientSessionFixture f;
+
+
+ f.session.exchangeDeclare(arg::exchange="xml", arg::type="xml");
+ f.session.queueDeclare(arg::queue="blue", arg::exclusive=true, arg::autoDelete=true);
+ f.session.queueDeclare(arg::queue="red", arg::exclusive=true, arg::autoDelete=true);
+
+ FieldTable blue;
+ blue.setString("xquery", "./colour = 'blue'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-colour", arg::arguments=blue);
+ FieldTable red;
+ red.setString("xquery", "./colour = 'red'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="red", arg::bindingKey="by-colour", arg::arguments=red);
+
+ Message sent1("<colour>blue</colour>", "by-colour");
+ f.session.messageTransfer(arg::content=sent1, arg::destination="xml");
+
+ Message sent2("<colour>red</colour>", "by-colour");
+ f.session.messageTransfer(arg::content=sent2, arg::destination="xml");
+
+ Message received;
+ BOOST_CHECK(f.subs.get(received, "blue"));
+ BOOST_CHECK_EQUAL(sent1.getData(), received.getData());
+ BOOST_CHECK(f.subs.get(received, "red"));
+ BOOST_CHECK_EQUAL(sent2.getData(), received.getData());
+}
+
+//### Test: Bad XML does not kill the server - and does not even
+// raise an exception, the content is not required to be XML.
+
+QPID_AUTO_TEST_CASE(testXMLSendBadXML) {
+ ClientSessionFixture f;
+
+ f.session.exchangeDeclare(arg::exchange="xml", arg::type="xml");
+ f.session.queueDeclare(arg::queue="blue", arg::exclusive=true, arg::autoDelete=true)\
+ ;
+ f.session.queueDeclare(arg::queue="red", arg::exclusive=true, arg::autoDelete=true);
+
+ FieldTable blue;
+ blue.setString("xquery", "./colour = 'blue'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-c\
+olour", arg::arguments=blue);
+ FieldTable red;
+ red.setString("xquery", "./colour = 'red'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="red", arg::bindingKey="by-co\
+lour", arg::arguments=red);
+
+ Message sent1("<>colour>blue</colour>", "by-colour");
+ f.session.messageTransfer(arg::content=sent1, arg::destination="xml");
+
+ BOOST_CHECK_EQUAL(1, 1);
+}
+
+
+//### Test: Bad XQuery does not kill the server, but does raise an exception
+
+QPID_AUTO_TEST_CASE(testXMLBadXQuery) {
+ ClientSessionFixture f;
+
+ f.session.exchangeDeclare(arg::exchange="xml", arg::type="xml");
+ f.session.queueDeclare(arg::queue="blue", arg::exclusive=true, arg::autoDelete=true)\
+ ;
+
+ try {
+ ScopedSuppressLogging sl; // Supress logging of error messages for expected error.
+ FieldTable blue;
+ blue.setString("xquery", "./colour $=! 'blue'");
+ f.session.exchangeBind(arg::exchange="xml", arg::queue="blue", arg::bindingKey="by-c\
+olour", arg::arguments=blue);
+ }
+ catch (const InternalErrorException& e) {
+ return;
+ }
+ BOOST_ERROR("A bad XQuery must raise an exception when used in an XML Binding.");
+
+}
+
+
+//### Test: Each session can provide its own definition for a query name
+
+
+
+//### Test: Bindings persist, surviving broker restart
+
+QPID_AUTO_TEST_SUITE_END()
+
diff --git a/RC9/qpid/cpp/src/tests/acl.py b/RC9/qpid/cpp/src/tests/acl.py
new file mode 100755
index 0000000000..671b2fe247
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/acl.py
@@ -0,0 +1,459 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+import sys
+import qpid
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import uuid4
+from qpid.testlib import TestBase010, testrunner
+from qmf.console import Session
+from qpid.datatypes import Message
+
+def scan_args(name, default=None, args=sys.argv[1:]):
+ if (name in args):
+ pos = args.index(name)
+ return args[pos + 1]
+ elif default:
+ return default
+ else:
+ print "Please specify extra argument: %s" % name
+ sys.exit(2)
+
+def extract_args(name, args):
+ if (name in args):
+ pos = args.index(name)
+ del args[pos:pos+2]
+ else:
+ return None
+
+def get_broker_port():
+ return scan_args("--port", "5672")
+
+def get_session(user, passwd):
+ socket = connect('127.0.0.1', int(get_broker_port()))
+ connection = Connection (sock=socket, username=user, password=passwd)
+ connection.start()
+ return connection.session(str(uuid4()))
+
+class ACLFile:
+ def __init__(self):
+ self.f = open('data_dir/policy.acl','w');
+
+ def write(self,line):
+ self.f.write(line)
+
+ def close(self):
+ self.f.close()
+
+class ACLTests(TestBase010):
+
+ def reload_acl(self):
+ acl = self.qmf.getObjects(_class="acl")[0]
+ return acl.reloadACLFile()
+
+ def setUp(self):
+ aclf = ACLFile()
+ aclf.write('acl allow all all\n')
+ aclf.close()
+ TestBase010.setUp(self)
+ self.startQmf()
+ self.reload_acl()
+
+ #=====================================
+ # ACL general tests
+ #=====================================
+
+ def test_deny_all(self):
+ """
+ Test the deny all mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl allow guest@QPID all all\n')
+ aclf.write('acl allow bob@QPID create queue\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+ try:
+ session.queue_declare(queue="deny_queue")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request");
+ self.fail("Error during queue create request");
+
+ try:
+ session.exchange_bind(exchange="amq.direct", queue="deny_queue", binding_key="routing_key")
+ self.fail("ACL should deny queue bind request");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+
+ def test_allow_all(self):
+ """
+ Test the allow all mode
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID bind exchange\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+ try:
+ session.queue_declare(queue="allow_queue")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request");
+ self.fail("Error during queue create request");
+
+ try:
+ session.exchange_bind(exchange="amq.direct", queue="allow_queue", binding_key="routing_key")
+ self.fail("ACL should deny queue bind request");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+
+
+ #=====================================
+ # ACL file format tests
+ #=====================================
+
+ def test_empty_groups(self):
+ """
+ Test empty groups
+ """
+ aclf = ACLFile()
+ aclf.write('acl group\n')
+ aclf.write('acl group admins bob@QPID joe@QPID\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("Insufficient tokens for acl definition",0,len(result.text)) == -1):
+ self.fail("ACL Reader should reject the acl file due to empty group name")
+
+ def test_illegal_acl_formats(self):
+ """
+ Test illegal acl formats
+ """
+ aclf = ACLFile()
+ aclf.write('acl group admins bob@QPID joe@QPID\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("Unknown ACL permission",0,len(result.text)) == -1):
+ self.fail(result)
+
+ def test_illegal_extension_lines(self):
+ """
+ Test illegal extension lines
+ """
+
+ aclf = ACLFile()
+ aclf.write('group admins bob@QPID \ ')
+ aclf.write(' \ \n')
+ aclf.write('joe@QPID \n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result.text.find("contains illegal characters",0,len(result.text)) == -1):
+ self.fail(result)
+
+
+
+ #=====================================
+ # ACL queue tests
+ #=====================================
+
+ def test_queue_acl(self):
+ """
+ Test various modes for queue acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID create queue name=q1 durable=true passive=true\n')
+ aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true\n')
+ aclf.write('acl deny bob@QPID access queue name=q3\n')
+ aclf.write('acl deny bob@QPID purge queue name=q3\n')
+ aclf.write('acl deny bob@QPID delete queue name=q4\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q1", durable='true', passive='true')
+ self.fail("ACL should deny queue create request with name=q1 durable=true passive=true");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q2", exclusive='true')
+ self.fail("ACL should deny queue create request with name=q2 exclusive=true");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="q3", exclusive='true')
+ session.queue_declare(queue="q4", durable='true')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request for q3 and q4 with any parameter");
+
+ try:
+ session.queue_query(queue="q3")
+ self.fail("ACL should deny queue query request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q3")
+ self.fail("ACL should deny queue purge request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_purge(queue="q4")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue purge request for q4");
+
+ try:
+ session.queue_delete(queue="q4")
+ self.fail("ACL should deny queue delete request for q4");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.queue_delete(queue="q3")
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow queue delete request for q3");
+
+ #=====================================
+ # ACL exchange tests
+ #=====================================
+
+ def test_exchange_acl(self):
+ """
+ Test various modes for exchange acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID create exchange name=testEx durable=true passive=true\n')
+ aclf.write('acl deny bob@QPID create exchange name=ex1 type=direct\n')
+ aclf.write('acl deny bob@QPID access exchange name=myEx\n')
+ aclf.write('acl deny bob@QPID bind exchange name=myEx queuename=q1 routingkey=rk1\n')
+ aclf.write('acl deny bob@QPID unbind exchange name=myEx queuename=q1 routingkey=rk1\n')
+ aclf.write('acl deny bob@QPID delete exchange name=myEx\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='testEx', durable='true', passive='true')
+ self.fail("ACL should deny exchange create request with name=testEx durable=true passive=true");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='ex1', type='direct')
+ self.fail("ACL should deny exchange create request with name=ex1 type=direct");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='myXml', type='direct')
+ session.queue_declare(queue='q1')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange create request for myXml with any parameter");
+
+ try:
+ session.exchange_query(name='myEx')
+ self.fail("ACL should deny queue query request for q3");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_bind(exchange='myEx', queue='q1', binding_key='rk1')
+ self.fail("ACL should deny exchange bind request with exchange='myEx' queuename='q1' bindingkey='rk1'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_bind(exchange='myXml', queue='q1', binding_key='x')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange bind request for exchange='myXml', queue='q1', binding_key='x'");
+ try:
+ session.exchange_unbind(exchange='myEx', queue='q1', binding_key='rk1')
+ self.fail("ACL should deny exchange unbind request with exchange='myEx' queuename='q1' bindingkey='rk1'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_unbind(exchange='myXml', queue='q1', binding_key='x')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange unbind request for exchange='myXml', queue='q1', binding_key='x'");
+
+ try:
+ session.exchange_delete(exchange='myEx')
+ self.fail("ACL should deny exchange delete request for myEx");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_delete(exchange='myXml')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange delete request for myXml");
+
+
+ #=====================================
+ # ACL consume tests
+ #=====================================
+
+ def test_consume_acl(self):
+ """
+ Test various consume acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID consume queue name=q1 durable=true\n')
+ aclf.write('acl deny bob@QPID consume queue name=q2 exclusive=true\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+
+
+ try:
+ session.queue_declare(queue='q1', durable='true')
+ session.queue_declare(queue='q2', exclusive='true')
+ session.queue_declare(queue='q3', durable='true')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow create queue request");
+
+ try:
+ session.message_subscribe(queue='q1', destination='myq1')
+ self.fail("ACL should deny message subscriber request for queue='q1'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.message_subscribe(queue='q2', destination='myq1')
+ self.fail("ACL should deny message subscriber request for queue='q2'");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.message_subscribe(queue='q3', destination='myq1')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow create message subscribe");
+
+
+ #=====================================
+ # ACL publish tests
+ #=====================================
+
+ def test_publish_acl(self):
+ """
+ Test various publish acl
+ """
+ aclf = ACLFile()
+ aclf.write('acl deny bob@QPID publish exchange name=amq.direct routingkey=rk1\n')
+ aclf.write('acl deny bob@QPID publish exchange name=amq.topic\n')
+ aclf.write('acl deny bob@QPID publish exchange name=myEx routingkey=rk2\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ self.reload_acl()
+
+ session = get_session('bob','bob')
+
+ try:
+ session.exchange_declare(exchange='myEx', type='topic')
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow exchange create request for myEx with any parameter");
+
+ props = session.delivery_properties(routing_key="rk1")
+
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=amq.direct routingkey=rk1");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.message_transfer(destination="amq.topic", message=Message(props,"Test"))
+ self.fail("ACL should deny message transfer to name=amq.topic");
+ except qpid.session.SessionException, e:
+ self.assertEqual(530,e.args[0].error_code)
+ session = get_session('bob','bob')
+
+ try:
+ session.message_transfer(destination="myEx", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange myEx with routing key rk1");
+
+
+ props = session.delivery_properties(routing_key="rk2")
+ try:
+ session.message_transfer(destination="amq.direct", message=Message(props,"Test"))
+ except qpid.session.SessionException, e:
+ if (530 == e.args[0].error_code):
+ self.fail("ACL should allow message transfer to exchange amq.direct");
+
+
+if __name__ == '__main__':
+ args = sys.argv[1:]
+ #need to remove the extra options from args as test runner doesn't recognize them
+ extract_args("--port", args)
+ args.append("acl")
+
+ if not testrunner.run(args): sys.exit(1)
diff --git a/RC9/qpid/cpp/src/tests/ais_check b/RC9/qpid/cpp/src/tests/ais_check
new file mode 100755
index 0000000000..5687110165
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ais_check
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# 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.
+#
+
+srcdir=`dirname $0`
+
+# Check AIS requirements and run tests if found.
+id -nG | grep '\<ais\>' >/dev/null || \
+ NOGROUP="You are not a member of the ais group."
+ps -u root | grep 'aisexec\|corosync' >/dev/null || \
+ NOAISEXEC="The aisexec or corosync daemon is not running as root"
+
+if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then
+ cat <<EOF
+
+ =========== WARNING: NOT RUNNING AIS TESTS ==============
+
+ Tests that depend on the openais library (used for clustering)
+ will not be run because:
+
+ $NOGROUP
+ $NOAISEXEC
+
+ ==========================================================
+
+EOF
+ exit 0; # A warning, not a failure.
+fi
+
+# Execute command with the ais group set.
+with_ais_group() {
+ id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group."; exit 1; }
+ echo $* | newgrp ais
+}
+
+# Run the tests
+srcdir=`dirname $0`
+with_ais_group $srcdir/run_test ./cluster_test || ERROR=1
+exit $ERROR
+
diff --git a/RC9/qpid/cpp/src/tests/ais_test.cpp b/RC9/qpid/cpp/src/tests/ais_test.cpp
new file mode 100644
index 0000000000..00c61242e4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ais_test.cpp
@@ -0,0 +1,23 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Defines test_main function to link with actual unit test code.
+#define BOOST_AUTO_TEST_MAIN // Boost 1.33
+#define BOOST_TEST_MAIN
+#include "unit_test.h"
+
diff --git a/RC9/qpid/cpp/src/tests/allSegmentTypes.h b/RC9/qpid/cpp/src/tests/allSegmentTypes.h
new file mode 100644
index 0000000000..e942250c89
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/allSegmentTypes.h
@@ -0,0 +1,128 @@
+#ifndef TESTS_ALLSEGMENTTYPES_H
+#define TESTS_ALLSEGMENTTYPES_H
+/*
+ *
+ * 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.
+ *
+ */
+
+///
+/// This file was automatically generated from the AMQP specification.
+/// Do not edit.
+///
+
+
+#include "qpid/amqp_0_10/specification.h"
+#include "qpid/amqp_0_10/Header.h"
+#include "qpid/amqp_0_10/Body.h"
+
+using namespace qpid::amqp_0_10;
+
+template <class Op> size_t allSegmentTypes(Op& op) {
+ op(Header());
+ op(Body());
+ op(ControlHolder(connection::Start()));
+ op(ControlHolder(connection::StartOk()));
+ op(ControlHolder(connection::Secure()));
+ op(ControlHolder(connection::SecureOk()));
+ op(ControlHolder(connection::Tune()));
+ op(ControlHolder(connection::TuneOk()));
+ op(ControlHolder(connection::Open()));
+ op(ControlHolder(connection::OpenOk()));
+ // op(ControlHolder(connection::Redirect())); // known-hosts array
+ op(ControlHolder(connection::Heartbeat()));
+ // op(ControlHolder(connection::Close())); // class/method dropped
+ op(ControlHolder(connection::CloseOk()));
+ op(ControlHolder(session::Attach()));
+ op(ControlHolder(session::Attached()));
+ op(ControlHolder(session::Detach()));
+ op(ControlHolder(session::Detached()));
+ op(ControlHolder(session::RequestTimeout()));
+ op(ControlHolder(session::Timeout()));
+ op(ControlHolder(session::CommandPoint()));
+ // op(ControlHolder(session::Expected())); // fragments array encoding problem
+ // op(ControlHolder(session::Confirmed())); // fragments array encoding problem
+ op(ControlHolder(session::Completed()));
+ op(ControlHolder(session::KnownCompleted()));
+ op(ControlHolder(session::Flush()));
+ op(ControlHolder(session::Gap()));
+ // FIXME aconway 2008-04-15: command encoding, fix headers, fix sized structs.
+ op(CommandHolder(execution::Sync()));
+ op(CommandHolder(execution::Result()));
+
+ // FIXME aconway 2008-04-16: investigate remaining failures.
+ // op(CommandHolder(execution::Exception()));
+ op(CommandHolder(message::Transfer()));
+ op(CommandHolder(message::Accept()));
+ // op(CommandHolder(message::Reject()));
+ op(CommandHolder(message::Release()));
+ op(CommandHolder(message::Acquire()));
+ // op(CommandHolder(message::Resume()));
+ op(CommandHolder(message::Subscribe()));
+ op(CommandHolder(message::Cancel()));
+ op(CommandHolder(message::SetFlowMode()));
+ op(CommandHolder(message::Flow()));
+ op(CommandHolder(message::Flush()));
+ op(CommandHolder(message::Stop()));
+ op(CommandHolder(tx::Select()));
+ op(CommandHolder(tx::Commit()));
+ op(CommandHolder(tx::Rollback()));
+ op(CommandHolder(dtx::Select()));
+ // op(CommandHolder(dtx::Start()));
+ // op(CommandHolder(dtx::End()));
+ // op(CommandHolder(dtx::Commit()));
+ // op(CommandHolder(dtx::Forget()));
+ // op(CommandHolder(dtx::GetTimeout()));
+ // op(CommandHolder(dtx::Prepare()));
+ // op(CommandHolder(dtx::Recover()));
+ // op(CommandHolder(dtx::Rollback()));
+ // op(CommandHolder(dtx::SetTimeout()));
+ op(CommandHolder(exchange::Declare()));
+ op(CommandHolder(exchange::Delete()));
+ op(CommandHolder(exchange::Query()));
+ op(CommandHolder(exchange::Bind()));
+ op(CommandHolder(exchange::Unbind()));
+ op(CommandHolder(exchange::Bound()));
+ op(CommandHolder(queue::Declare()));
+ op(CommandHolder(queue::Delete()));
+ op(CommandHolder(queue::Purge()));
+ op(CommandHolder(queue::Query()));
+ // op(CommandHolder(file::Qos()));
+ // op(CommandHolder(file::QosOk()));
+// op(CommandHolder(file::Consume()));
+// op(CommandHolder(file::ConsumeOk()));
+// op(CommandHolder(file::Cancel()));
+// op(CommandHolder(file::Open()));
+// op(CommandHolder(file::OpenOk()));
+// op(CommandHolder(file::Stage()));
+// op(CommandHolder(file::Publish()));
+// op(CommandHolder(file::Return()));
+// op(CommandHolder(file::Deliver()));
+// op(CommandHolder(file::Ack()));
+// op(CommandHolder(file::Reject()));
+// op(CommandHolder(stream::Qos()));
+// op(CommandHolder(stream::QosOk()));
+// op(CommandHolder(stream::Consume()));
+// op(CommandHolder(stream::ConsumeOk()));
+// op(CommandHolder(stream::Cancel()));
+// op(CommandHolder(stream::Publish()));
+// op(CommandHolder(stream::Return()));
+// op(CommandHolder(stream::Deliver()));
+ return 0;
+}
+#endif /*!TESTS_ALLSEGMENTTYPES_H*/
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/Map.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/Map.cpp
new file mode 100644
index 0000000000..efde967050
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/Map.cpp
@@ -0,0 +1,98 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "unit_test.h"
+#include "qpid/amqp_0_10/Map.h"
+#include "qpid/amqp_0_10/Array.h"
+#include "qpid/amqp_0_10/Struct32.h"
+#include "qpid/amqp_0_10/UnknownType.h"
+#include "qpid/amqp_0_10/Codec.h"
+#include <iostream>
+
+using namespace qpid::amqp_0_10;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(MapTestSuite)
+
+ QPID_AUTO_TEST_CASE(testGetSet) {
+ MapValue v;
+ v = Str8("foo");
+ BOOST_CHECK(v.get<Str8>());
+ BOOST_CHECK(!v.get<uint8_t>());
+ BOOST_CHECK_EQUAL(*v.get<Str8>(), "foo");
+
+ v = uint8_t(42);
+ BOOST_CHECK(!v.get<Str8>());
+ BOOST_CHECK(v.get<uint8_t>());
+ BOOST_CHECK_EQUAL(*v.get<uint8_t>(), 42);
+
+ v = uint16_t(12);
+ BOOST_CHECK(v.get<uint16_t>());
+ BOOST_CHECK_EQUAL(*v.get<uint16_t>(), 12);
+}
+
+template <class R> struct TestVisitor : public MapValue::Visitor<R> {
+ template <class T> R operator()(const T&) const { throw MapValue::BadTypeException(); }
+ R operator()(const R& r) const { return r; }
+};
+
+QPID_AUTO_TEST_CASE(testVisit) {
+ MapValue v;
+ v = Str8("foo");
+ BOOST_CHECK_EQUAL(v.apply_visitor(TestVisitor<Str8>()), "foo");
+ v = Uint16(42);
+ BOOST_CHECK_EQUAL(v.apply_visitor(TestVisitor<Uint16>()), 42);
+ try {
+ v.apply_visitor(TestVisitor<bool>());
+ BOOST_FAIL("Expecting exception");
+ }
+ catch(const MapValue::BadTypeException&) {}
+}
+
+
+QPID_AUTO_TEST_CASE(testEncodeMapValue) {
+ MapValue mv;
+ std::string data;
+ mv = Str8("hello");
+ Codec::encode(back_inserter(data))(mv);
+ BOOST_CHECK_EQUAL(data.size(), Codec::size(mv));
+ MapValue mv2;
+ Codec::decode(data.begin())(mv2);
+ BOOST_CHECK_EQUAL(mv2.getCode(), 0x85);
+ BOOST_REQUIRE(mv2.get<Str8>());
+ BOOST_CHECK_EQUAL(*mv2.get<Str8>(), "hello");
+}
+
+QPID_AUTO_TEST_CASE(testEncode) {
+ Map map;
+ std::string data;
+ map["A"] = true;
+ map["b"] = Str8("hello");
+ Codec::encode(back_inserter(data))(map);
+ BOOST_CHECK_EQUAL(Codec::size(map), data.size());
+ Map map2;
+ Codec::decode(data.begin())(map2);
+ BOOST_CHECK_EQUAL(map.size(), 2u);
+ BOOST_CHECK(map["A"].get<bool>());
+ BOOST_CHECK_EQUAL(*map["b"].get<Str8>(), "hello");
+}
+
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp
new file mode 100644
index 0000000000..9d4fcb8935
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/ProxyTemplate.cpp
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "unit_test.h"
+#include "qpid/amqp_0_10/ProxyTemplate.h"
+#include <boost/any.hpp>
+
+QPID_AUTO_TEST_SUITE(ProxyTemplateTestSuite)
+
+using namespace qpid::amqp_0_10;
+
+struct ToAny {
+ template <class T>
+ boost::any operator()(const T& t) { return boost::any(t); }
+};
+
+struct AnyProxy : public ProxyTemplate<ToAny, boost::any> {};
+
+QPID_AUTO_TEST_CASE(testAnyProxy) {
+ AnyProxy p;
+ boost::any a=p.connectionTune(1,2,3,4);
+ BOOST_CHECK_EQUAL(a.type().name(), typeid(connection::Tune).name());
+ connection::Tune* tune=boost::any_cast<connection::Tune>(&a);
+ BOOST_REQUIRE(tune);
+ BOOST_CHECK_EQUAL(tune->channelMax, 1u);
+ BOOST_CHECK_EQUAL(tune->maxFrameSize, 2u);
+ BOOST_CHECK_EQUAL(tune->heartbeatMin, 3u);
+ BOOST_CHECK_EQUAL(tune->heartbeatMax, 4u);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/apply.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/apply.cpp
new file mode 100644
index 0000000000..5a67c28c79
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/apply.cpp
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.
+ *
+ */
+#include "unit_test.h"
+#include "qpid/amqp_0_10/specification.h"
+#include "qpid/amqp_0_10/ApplyControl.h"
+
+QPID_AUTO_TEST_SUITE(VisitorTestSuite)
+
+using namespace qpid::amqp_0_10;
+
+struct GetCode : public ApplyFunctor<uint8_t> {
+ template <class T> uint8_t operator()(const T&) const { return T::CODE; }
+};
+
+struct SetChannelMax : ApplyFunctor<void> {
+ template <class T> void operator()(T&) const { BOOST_FAIL(""); }
+ void operator()(connection::Tune& t) const { t.channelMax=42; }
+};
+
+struct TestFunctor {
+ typedef bool result_type;
+ bool operator()(const connection::Tune& tune) {
+ BOOST_CHECK_EQUAL(tune.channelMax, 1u);
+ BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u);
+ return true;
+ }
+ template <class T>
+ bool operator()(const T&) { return false; }
+};
+
+QPID_AUTO_TEST_CASE(testApply) {
+ connection::Tune tune(1,2,3,4);
+ Control* p = &tune;
+
+ // boost oddity - without the cast we get undefined symbol errors.
+ BOOST_CHECK_EQUAL(apply(GetCode(), *p), (uint8_t)connection::Tune::CODE);
+
+ TestFunctor tf;
+ BOOST_CHECK(apply(tf, *p));
+
+ connection::Start start;
+ p = &start;
+ BOOST_CHECK(!apply(tf, *p));
+
+ apply(SetChannelMax(), tune);
+ BOOST_CHECK_EQUAL(tune.channelMax, 42);
+}
+
+struct VoidTestFunctor {
+ typedef void result_type;
+
+ int code;
+ VoidTestFunctor() : code() {}
+
+ void operator()(const connection::Tune& tune) {
+ BOOST_CHECK_EQUAL(tune.channelMax, 1u);
+ BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u);
+ code=connection::Tune::CODE;
+ }
+ template <class T>
+ void operator()(const T&) { code=0xFF; }
+};
+
+QPID_AUTO_TEST_CASE(testApplyVoid) {
+ connection::Tune tune(1,2,3,4);
+ Control* p = &tune;
+ VoidTestFunctor tf;
+ apply(tf, *p);
+ BOOST_CHECK_EQUAL(uint8_t(connection::Tune::CODE), tf.code);
+
+ connection::Start start;
+ p = &start;
+ apply(tf, *p);
+ BOOST_CHECK_EQUAL(0xFF, tf.code);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/handlers.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/handlers.cpp
new file mode 100644
index 0000000000..428643c802
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/handlers.cpp
@@ -0,0 +1,125 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "unit_test.h"
+#include "qpid/Exception.h"
+#include "qpid/amqp_0_10/Unit.h"
+#include "qpid/amqp_0_10/ControlHolder.h"
+#include "qpid/amqp_0_10/CommandHolder.h"
+#include "qpid/amqp_0_10/handlers.h"
+#include "qpid/amqp_0_10/specification.h"
+
+QPID_AUTO_TEST_SUITE(handler_tests)
+
+using namespace qpid::amqp_0_10;
+using namespace std;
+
+string called; // Set by called handler function
+
+// Note on handlers:
+//
+// Control and Command handlers are separate, both behave the same way,
+// so substitute "control or command" for command in the following.
+//
+// Command handlers derive from CommandHandler and implement functions
+// for all the commands they handle. Handling an unimplemented command
+// will raise NotImplementedException.
+//
+// Using virtual inheritance from CommandHandler allows multiple
+// handlers to be aggregated into one with multiple inheritance,
+// See test code for example.
+//
+// E.g. the existing broker model would have two control handlers:
+// - ConnectionHandler: ControlHandler for connection controls.
+// - SessionHandler: ControlHandler for session controls.
+// It would have class-command handlers for each AMQP class:
+// - QueueHandler, MessageHandler etc.. handle each class.
+// And an aggregate handler in place of BrokerAdapter
+// - BrokerCommandHandler: public QueueHandler, MessageHandler ...
+//
+// In other applications (e.g. cluster) any combination of commands
+// can be handled by a given handler. It _might_ simplify the code
+// to collaps ConnectionHandler and SessionHandler into a single
+// ControlHandler (or it might not.)
+
+struct TestExecutionHandler : public virtual CommandHandler {
+ void executionSync() { called = "executionSync"; }
+ // ... etc. for all execution commands
+};
+
+struct TestMessageHandler : public virtual CommandHandler {
+ void messageCancel(const Str8&) { called="messageCancel"; }
+ // ... etc.
+};
+
+// Aggregate handler for all recognised commands.
+struct TestCommandHandler :
+ public TestExecutionHandler,
+ public TestMessageHandler
+ // ... etc. handlers for all command classes.
+{}; // Nothing to do.
+
+
+// Sample unit handler, written as a static_visitor.
+// Note it could equally be written with if/else statements
+// in handle.
+//
+struct TestUnitHandler : public boost::static_visitor<void> {
+ TestCommandHandler handler;
+ void handle(const Unit& u) { u.applyVisitor(*this); }
+
+ void operator()(const Body&) { called="Body"; }
+ void operator()(const Header&) { called="Header"; }
+ void operator()(const ControlHolder&) { throw qpid::Exception("I don't do controls."); }
+ void operator()(const CommandHolder& c) { c.invoke(handler); }
+};
+
+QPID_AUTO_TEST_CASE(testHandlers) {
+ TestUnitHandler handler;
+ Unit u;
+
+ u = Body();
+ handler.handle(u);
+ BOOST_CHECK_EQUAL("Body", called);
+
+ u = Header();
+ handler.handle(u);
+ BOOST_CHECK_EQUAL("Header", called);
+
+ // in_place<Foo>(...) is equivalent to Foo(...) but
+ // constructs Foo directly in the holder, avoiding
+ // a copy.
+
+ u = CommandHolder(in_place<execution::Sync>());
+ handler.handle(u);
+ BOOST_CHECK_EQUAL("executionSync", called);
+
+ u = ControlHolder(in_place<connection::Start>(Map(), Str16Array(), Str16Array()));
+ try {
+ handler.handle(u);
+ } catch (const qpid::Exception&) {}
+
+ u = CommandHolder(in_place<message::Cancel>(Str8()));
+ handler.handle(u);
+ BOOST_CHECK_EQUAL("messageCancel", called);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/amqp_0_10/serialize.cpp b/RC9/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
new file mode 100644
index 0000000000..0cfeb8d28d
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/amqp_0_10/serialize.cpp
@@ -0,0 +1,429 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "unit_test.h"
+#include "allSegmentTypes.h"
+
+#include "qpid/framing/AMQFrame.h"
+#include "qpid/framing/Buffer.h"
+
+#include "qpid/amqp_0_10/Packer.h"
+#include "qpid/amqp_0_10/built_in_types.h"
+#include "qpid/amqp_0_10/Codec.h"
+#include "qpid/amqp_0_10/specification.h"
+#include "qpid/amqp_0_10/ControlHolder.h"
+#include "qpid/amqp_0_10/Struct32.h"
+#include "qpid/amqp_0_10/FrameHeader.h"
+#include "qpid/amqp_0_10/Map.h"
+#include "qpid/amqp_0_10/Unit.h"
+#include "tests/allSegmentTypes.h"
+
+#include <boost/test/test_case_template.hpp>
+#include <boost/type_traits/is_arithmetic.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/optional.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/back_inserter.hpp>
+#include <boost/mpl/copy.hpp>
+#include <boost/mpl/empty_sequence.hpp>
+#include <boost/current_function.hpp>
+#include <iterator>
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <netinet/in.h>
+
+// Missing operators needed for tests.
+namespace boost {
+template <class T, size_t N>
+std::ostream& operator<<(std::ostream& out, const array<T,N>& a) {
+ std::ostream_iterator<T> o(out, " ");
+ std::copy(a.begin(), a.end(), o);
+ return out;
+}
+} // boost
+
+QPID_AUTO_TEST_SUITE(SerializeTestSuite)
+
+using namespace std;
+namespace mpl=boost::mpl;
+using namespace qpid::amqp_0_10;
+using qpid::framing::in_place;
+
+template <class A, class B> struct concat2 { typedef typename mpl::copy<B, typename mpl::back_inserter<A> >::type type; };
+template <class A, class B, class C> struct concat3 { typedef typename concat2<A, typename concat2<B, C>::type>::type type; };
+template <class A, class B, class C, class D> struct concat4 { typedef typename concat2<A, typename concat3<B, C, D>::type>::type type; };
+
+typedef mpl::vector<Boolean, Char, Int32, Int64, Int8, Uint16, CharUtf32, Uint32, Uint64, Bin8, Uint8>::type IntegralTypes;
+typedef mpl::vector<Bin1024, Bin128, Bin16, Bin256, Bin32, Bin40, Bin512, Bin64, Bin72>::type BinTypes;
+typedef mpl::vector<Double, Float>::type FloatTypes;
+typedef mpl::vector<SequenceNo, Uuid, Datetime, Dec32, Dec64> FixedSizeClassTypes;
+typedef mpl::vector<Map, Vbin8, Str8Latin, Str8, Str8Utf16, Vbin16, Str16Latin, Str16, Str16Utf16, Vbin32> VariableSizeTypes;
+
+typedef concat4<IntegralTypes, BinTypes, FloatTypes, FixedSizeClassTypes>::type FixedSizeTypes;
+typedef concat2<FixedSizeTypes, VariableSizeTypes>::type AllTypes;
+
+// TODO aconway 2008-02-20: should test 64 bit integrals for order also.
+QPID_AUTO_TEST_CASE(testNetworkByteOrder) {
+ string data;
+
+ uint32_t l = 0x11223344;
+ Codec::encode(std::back_inserter(data))(l);
+ uint32_t enc=reinterpret_cast<const uint32_t&>(*data.data());
+ uint32_t l2 = ntohl(enc);
+ BOOST_CHECK_EQUAL(l, l2);
+
+ data.clear();
+ uint16_t s = 0x1122;
+ Codec::encode(std::back_inserter(data))(s);
+ uint32_t s2 = ntohs(*reinterpret_cast<const uint32_t*>(data.data()));
+ BOOST_CHECK_EQUAL(s, s2);
+}
+
+QPID_AUTO_TEST_CASE(testSetLimit) {
+ typedef Codec::Encoder<back_insert_iterator<string> > Encoder;
+ string data;
+ Encoder encode(back_inserter(data), 3);
+ encode('1')('2')('3');
+ try {
+ encode('4');
+ BOOST_FAIL("Expected exception");
+ } catch (...) {} // FIXME aconway 2008-04-03: catch proper exception
+ BOOST_CHECK_EQUAL(data, "123");
+}
+
+QPID_AUTO_TEST_CASE(testScopedLimit) {
+ typedef Codec::Encoder<back_insert_iterator<string> > Encoder;
+ string data;
+ Encoder encode(back_inserter(data), 10);
+ encode(Str8("123")); // 4 bytes
+ {
+ Encoder::ScopedLimit l(encode, 3);
+ encode('a')('b')('c');
+ try {
+ encode('d');
+ BOOST_FAIL("Expected exception");
+ } catch(...) {} // FIXME aconway 2008-04-03: catch proper exception
+ }
+ BOOST_CHECK_EQUAL(data, "\003123abc");
+ encode('x')('y')('z');
+ try {
+ encode('!');
+ BOOST_FAIL("Expected exception");
+ } catch(...) {} // FIXME aconway 2008-04-03: catch proper exception
+ BOOST_CHECK_EQUAL(data.size(), 10u);
+}
+
+// Assign test values to the various types.
+void testValue(bool& b) { b = true; }
+void testValue(Bit&) { }
+template <class T> typename boost::enable_if<boost::is_arithmetic<T> >::type testValue(T& n) { n=42; }
+void testValue(CharUtf32& c) { c = 43; }
+void testValue(long long& l) { l = 0x012345; }
+void testValue(Datetime& dt) { dt = qpid::sys::now(); }
+void testValue(Uuid& uuid) { uuid=Uuid(true); }
+template <class E, class M> void testValue(Decimal<E,M>& d) { d.exponent=2; d.mantissa=0x1122; }
+void testValue(SequenceNo& s) { s = 42; }
+template <size_t N> void testValue(Bin<N>& a) { a.assign(42); }
+template <class T, class S, int Unique> void testValue(SerializableString<T, S, Unique>& s) {
+ char msg[]="foobar";
+ s.assign(msg, msg+sizeof(msg));
+}
+void testValue(Str16& s) { s = "the quick brown fox jumped over the lazy dog"; }
+void testValue(Str8& s) { s = "foobar"; }
+void testValue(Map& m) { m["s"] = Str8("foobar"); m["b"] = true; m["c"] = uint16_t(42); }
+
+//typedef mpl::vector<Str8, Str16>::type TestTypes;
+/*BOOST_AUTO_TEST_CASE_TEMPLATE(testEncodeDecode, T, AllTypes)
+{
+ string data;
+ T t;
+ testValue(t);
+ Codec::encode(std::back_inserter(data))(t);
+
+ BOOST_CHECK_EQUAL(Codec::size(t), data.size());
+
+ T t2;
+ Codec::decode(data.begin())(t2);
+ BOOST_CHECK_EQUAL(t,t2);
+}
+*/
+
+struct TestMe {
+ bool encoded, decoded;
+ char value;
+ TestMe(char v) : encoded(), decoded(), value(v) {}
+ template <class S> void encode(S& s) const {
+ const_cast<TestMe*>(this)->encoded=true; s(value);
+ }
+ template <class S> void decode(S& s) { decoded=true; s(value); }
+ template <class S> void serialize(S& s) { s.split(*this); }
+};
+
+QPID_AUTO_TEST_CASE(testSplit) {
+ string data;
+ TestMe t1('x');
+ Codec::encode(std::back_inserter(data))(t1);
+ BOOST_CHECK(t1.encoded);
+ BOOST_CHECK(!t1.decoded);
+ BOOST_CHECK_EQUAL(data, "x");
+
+ TestMe t2('y');
+ Codec::decode(data.begin())(t2);
+ BOOST_CHECK(!t2.encoded);
+ BOOST_CHECK(t2.decoded);
+ BOOST_CHECK_EQUAL(t2.value, 'x');
+}
+
+QPID_AUTO_TEST_CASE(testControlEncodeDecode) {
+ string data;
+ Control::Holder h(in_place<connection::Tune>(1,2,3,4));
+ Codec::encode(std::back_inserter(data))(h);
+
+ BOOST_CHECK_EQUAL(data.size(), Codec::size(h));
+
+ Codec::Decoder<string::iterator> decode(data.begin());
+ Control::Holder h2;
+ decode(h2);
+
+ BOOST_REQUIRE(h2.get());
+ BOOST_CHECK_EQUAL(h2.get()->getClassCode(), connection::CODE);
+ BOOST_CHECK_EQUAL(h2.get()->getCode(), uint8_t(connection::Tune::CODE));
+ connection::Tune& tune=static_cast<connection::Tune&>(*h2.get());
+ BOOST_CHECK_EQUAL(tune.channelMax, 1u);
+ BOOST_CHECK_EQUAL(tune.maxFrameSize, 2u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMin, 3u);
+ BOOST_CHECK_EQUAL(tune.heartbeatMax, 4u);
+}
+
+QPID_AUTO_TEST_CASE(testStruct32) {
+ message::DeliveryProperties dp;
+ dp.priority=message::MEDIUM;
+ dp.routingKey="foo";
+ Struct32 s(dp);
+ string data;
+ Codec::encode(back_inserter(data))(s);
+
+ uint32_t structSize; // Starts with size
+ Codec::decode(data.begin())(structSize);
+ BOOST_CHECK_EQUAL(structSize, Codec::size(dp) + 2); // +2 for code
+ BOOST_CHECK_EQUAL(structSize, data.size()-4); // encoded body
+
+ BOOST_CHECK_EQUAL(data.size(), Codec::size(s));
+ Struct32 s2;
+ Codec::decode(data.begin())(s2);
+ message::DeliveryProperties* dp2 = s2.getIf<message::DeliveryProperties>();
+ BOOST_REQUIRE(dp2);
+ BOOST_CHECK_EQUAL(dp2->priority, message::MEDIUM);
+ BOOST_CHECK_EQUAL(dp2->routingKey, "foo");
+}
+
+QPID_AUTO_TEST_CASE(testStruct32Unknown) {
+ // Verify we can recode an unknown struct unchanged.
+ Struct32 s;
+ string data;
+ Codec::encode(back_inserter(data))(uint32_t(10));
+ data.append(10, 'X');
+ Codec::decode(data.begin())(s);
+ string data2;
+ Codec::encode(back_inserter(data2))(s);
+ BOOST_CHECK_EQUAL(data.size(), data2.size());
+ BOOST_CHECK_EQUAL(data, data2);
+}
+
+struct DummyPacked {
+ static const uint8_t PACK=1;
+ boost::optional<char> i, j;
+ char k;
+ Bit l,m;
+ DummyPacked(char a=0, char b=0, char c=0) : i(a), j(b), k(c), l(), m() {}
+ template <class S> void serialize(S& s) { s(i)(j)(k)(l)(m); }
+};
+
+Packer<DummyPacked> serializable(DummyPacked& d) { return Packer<DummyPacked>(d); }
+
+QPID_AUTO_TEST_CASE(testPackBits) {
+ DummyPacked d('a','b','c');
+ BOOST_CHECK_EQUAL(packBits(d), 7u);
+ d.j = boost::none;
+ BOOST_CHECK_EQUAL(packBits(d), 5u);
+ d.m = true;
+ BOOST_CHECK_EQUAL(packBits(d), 0x15u);
+}
+
+
+QPID_AUTO_TEST_CASE(testPacked) {
+ string data;
+
+ Codec::encode(back_inserter(data))('a')(boost::optional<char>('b'))(boost::optional<char>())('c');
+ BOOST_CHECK_EQUAL(data, "abc");
+ data.clear();
+
+ DummyPacked dummy('a','b','c');
+
+ Codec::encode(back_inserter(data))(dummy);
+ BOOST_CHECK_EQUAL(data.size(), 4u);
+ BOOST_CHECK_EQUAL(data, string("\007abc"));
+ data.clear();
+
+ dummy.i = boost::none;
+ Codec::encode(back_inserter(data))(dummy);
+ BOOST_CHECK_EQUAL(data, string("\6bc"));
+ data.clear();
+
+ const char* missing = "\5xy";
+ Codec::decode(missing)(dummy);
+ BOOST_CHECK(dummy.i);
+ BOOST_CHECK_EQUAL(*dummy.i, 'x');
+ BOOST_CHECK(!dummy.j);
+ BOOST_CHECK_EQUAL(dummy.k, 'y');
+}
+
+QPID_AUTO_TEST_CASE(testUnitControl) {
+ string data;
+ Control::Holder h(in_place<connection::Tune>(1,2,3,4));
+ Codec::encode(std::back_inserter(data))(h);
+
+ Unit unit(FrameHeader(FIRST_FRAME|LAST_FRAME, CONTROL));
+ Codec::decode(data.begin())(unit);
+
+ BOOST_REQUIRE(unit.get<ControlHolder>());
+
+ string data2;
+ Codec::encode(back_inserter(data2))(unit);
+
+ BOOST_CHECK_EQUAL(data, data2);
+}
+
+QPID_AUTO_TEST_CASE(testArray) {
+ ArrayDomain<char> a;
+ a.resize(3, 'x');
+ string data;
+ Codec::encode(back_inserter(data))(a);
+
+ ArrayDomain<char> b;
+ Codec::decode(data.begin())(b);
+ BOOST_CHECK_EQUAL(b.size(), 3u);
+ string data3;
+ Codec::encode(back_inserter(data3))(a);
+ BOOST_CHECK_EQUAL(data, data3);
+
+ Array x;
+ Codec::decode(data.begin())(x);
+ BOOST_CHECK_EQUAL(x.size(), 3u);
+ BOOST_CHECK_EQUAL(x[0].size(), 1u);
+ BOOST_CHECK_EQUAL(*x[0].begin(), 'x');
+ BOOST_CHECK_EQUAL(*x[2].begin(), 'x');
+
+ string data2;
+ Codec::encode(back_inserter(data2))(x);
+ BOOST_CHECK_EQUAL(data,data2);
+}
+
+QPID_AUTO_TEST_CASE(testStruct) {
+ string data;
+
+ message::DeliveryProperties dp;
+ BOOST_CHECK(!dp.discardUnroutable);
+ dp.immediate = true;
+ dp.redelivered = false;
+ dp.priority = message::MEDIUM;
+ dp.exchange = "foo";
+
+ Codec::encode(back_inserter(data))(dp);
+ // Skip 4 bytes size, little-endian decode for pack bits.
+ uint16_t encodedBits=uint8_t(data[5]);
+ encodedBits <<= 8;
+ encodedBits += uint8_t(data[4]);
+ BOOST_CHECK_EQUAL(encodedBits, packBits(dp));
+
+ data.clear();
+ Struct32 h(dp);
+ Codec::encode(back_inserter(data))(h);
+
+ Struct32 h2;
+ Codec::decode(data.begin())(h2);
+ BOOST_CHECK_EQUAL(h2.getClassCode(), Uint8(message::DeliveryProperties::CLASS_CODE));
+ BOOST_CHECK_EQUAL(h2.getCode(), Uint8(message::DeliveryProperties::CODE));
+ message::DeliveryProperties* dp2 =
+ dynamic_cast<message::DeliveryProperties*>(h2.get());
+ BOOST_CHECK(dp2);
+ BOOST_CHECK(!dp2->discardUnroutable);
+ BOOST_CHECK(dp2->immediate);
+ BOOST_CHECK(!dp2->redelivered);
+ BOOST_CHECK_EQUAL(dp2->priority, message::MEDIUM);
+ BOOST_CHECK_EQUAL(dp2->exchange, "foo");
+}
+
+struct RecodeUnit {
+ template <class T>
+ void operator() (const T& t) {
+ BOOST_MESSAGE(BOOST_CURRENT_FUNCTION << " called with: " << t);
+ using qpid::framing::Buffer;
+ using qpid::framing::AMQFrame;
+
+ session::Header sh;
+ BOOST_CHECK_EQUAL(Codec::size(sh), 2u);
+
+ // Encode unit.
+ Unit u(t);
+ string data;
+ Codec::encode(back_inserter(data))(u.getHeader())(u);
+ data.push_back(char(0xCE)); // Preview end-of-frame
+
+ // Decode AMQFrame
+ Buffer buf(&data[0], data.size());
+ AMQFrame f;
+ f.decode(buf);
+ BOOST_MESSAGE("AMQFrame decoded: " << f);
+ // Encode AMQFrame
+ string data2(f.size(), ' ');
+ Buffer buf2(&data2[0], data.size());
+ f.encode(buf2);
+
+ // Verify encoded by unit == encoded by AMQFrame
+ BOOST_CHECK_MESSAGE(data == data2, BOOST_CURRENT_FUNCTION);
+
+ // Decode unit
+ // FIXME aconway 2008-04-15: must set limit to decode a header.
+ Codec::Decoder<string::iterator> decode(data2.begin(), data2.size()-1);
+
+ FrameHeader h;
+ decode(h);
+ BOOST_CHECK_EQUAL(u.getHeader(), h);
+ Unit u2(h);
+ decode(u2);
+
+ // Re-encode unit
+ string data3;
+ Codec::encode(back_inserter(data3))(u2.getHeader())(u2);
+ data3.push_back(char(0xCE)); // Preview end-of-frame
+
+ BOOST_CHECK_MESSAGE(data3 == data2, BOOST_CURRENT_FUNCTION);
+ }
+};
+
+QPID_AUTO_TEST_CASE(testSerializeAllSegmentTypes) {
+ RecodeUnit recode;
+ allSegmentTypes(recode);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/benchmark b/RC9/qpid/cpp/src/tests/benchmark
new file mode 100755
index 0000000000..c075837847
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/benchmark
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# 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.
+#
+# A basic "benchmark" to generate performacne samples of throughput
+# and latency against a single cluster member while they are replicating.
+#
+# Must be run in the qpid src/tests build directory.
+#
+
+usage() {
+cat <<EOF
+Usage: $0 [options] -- client hosts --- broker hosts
+Read the script for options.
+EOF
+}
+# Defaults
+TESTDIR=${TESTDIR:-$PWD} # Absolute path to test exes on all hosts.
+SCRIPTDIR=${SCRIPTDIR:-`dirname $0`} # Path to local test scripts directory.
+SAMPLES=10 # Runs of each test.
+COUNT=${COUNT:-10000} # Count for pub/sub tests.
+SIZE=${SIZE:-600} # Size of messages
+ECHO=${ECHO:-1000} # Count for echo test.
+NSUBS=${NSUBS:-4}
+NPUBS=${NPUBS:-4}
+
+collect() { eval $COLLECT=\""\$$COLLECT $*"\"; }
+COLLECT=ARGS
+while test $# -gt 0; do
+ case $1 in
+ --testdir) TESTDIR=$2 ; shift 2 ;;
+ --samples) SAMPLES=$2 ; shift 2 ;;
+ --count) COUNT=$2 ; shift 2 ;;
+ --echos) ECHO=$2 ; shift 2 ;;
+ --size) SIZE=$2 ; shift 2 ;;
+ --nsubs) NSUBS=$2 ; shift 2 ;;
+ --npubs) NPUBS=$2 ; shift 2 ;;
+ --) COLLECT=CLIENTARG; shift ;;
+ ---) COLLECT=BROKERARG; shift;;
+ *) collect $1; shift ;;
+ esac
+done
+
+CLIENTS=${CLIENTARG:-$CLIENTS}
+BROKERS=${BROKERARG:-$BROKERS}
+test -z "$CLIENTS" && { echo "Must specify at least one client host."; exit 1; }
+test -z "$BROKERS" && { echo "Must specify at least one broker host."; exit 1; }
+
+export TESTDIR # For perfdist
+CLIENTS=($CLIENTS) # Convert to array
+BROKERS=($BROKERS)
+trap "rm -f $FILES" EXIT
+
+dosamples() {
+ FILE=`mktemp`
+ FILES="$FILES $FILE"
+ TABS=`echo "$HEADING" | sed s'/[^ ]//g'`
+ {
+ echo "\"$*\"$TABS"
+ echo "$HEADING"
+ for (( i=0; i<$SAMPLES; ++i)) ; do echo "`$*`" ; done
+ echo
+ } | tee $FILE
+}
+
+HEADING="pub sub total Mb"
+dosamples $SCRIPTDIR/perfdist --size $SIZE --count $COUNT --nsubs $NSUBS --npubs $NPUBS -s -- ${CLIENTS[*]} --- ${BROKERS[*]}
+HEADING="pub"
+dosamples ssh -A ${CLIENTS[0]} $TESTDIR/publish --routing-key perftest0 --size $SIZE --count $COUNT -s -b ${BROKERS[0]}
+HEADING="sub"
+dosamples ssh -A ${CLIENTS[0]} $TESTDIR/consume --queue perftest0 -s --count $COUNT -b ${BROKERS[0]}
+HEADING="min max avg"
+dosamples ssh -A ${CLIENTS[0]} $TESTDIR/echotest --count $ECHO -s -b ${BROKERS[0]}
+
+echo
+echo "Tab separated spreadsheet (also saved as benchmark.tab):"
+echo
+
+echo "benchmark -- ${CLIENTS[*]} --- ${BROKERS[*]} " | tee benchmark.tab
+paste $FILES | tee -a benchmark.tab
diff --git a/RC9/qpid/cpp/src/tests/client_test.cpp b/RC9/qpid/cpp/src/tests/client_test.cpp
new file mode 100644
index 0000000000..204c2c4b71
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/client_test.cpp
@@ -0,0 +1,149 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * This file provides a simple test (and example) of basic
+ * functionality including declaring an exchange and a queue, binding
+ * these together, publishing a message and receiving that message
+ * asynchronously.
+ */
+
+#include <iostream>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Session.h"
+#include "qpid/framing/FrameSet.h"
+#include "qpid/framing/all_method_bodies.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+using std::string;
+
+struct Args : public TestOptions {
+ uint msgSize;
+ bool verbose;
+
+ Args() : TestOptions("Simple test of Qpid c++ client; sends and receives a single message."), msgSize(26)
+ {
+ addOptions()
+ ("size", optValue(msgSize, "N"), "message size")
+ ("verbose", optValue(verbose), "print out some status messages");
+ }
+};
+
+const std::string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+std::string generateData(uint size)
+{
+ if (size < chars.length()) {
+ return chars.substr(0, size);
+ }
+ std::string data;
+ for (uint i = 0; i < (size / chars.length()); i++) {
+ data += chars;
+ }
+ data += chars.substr(0, size % chars.length());
+ return data;
+}
+
+void print(const std::string& text, const Message& msg)
+{
+ std::cout << text;
+ if (msg.getData().size() > 16) {
+ std::cout << msg.getData().substr(0, 16) << "...";
+ } else {
+ std::cout << msg.getData();
+ }
+ std::cout << std::endl;
+}
+
+int main(int argc, char** argv)
+{
+ try {
+ Args opts;
+ opts.parse(argc, argv);
+
+ //Connect to the broker:
+ Connection connection;
+ opts.open(connection);
+ if (opts.verbose) std::cout << "Opened connection." << std::endl;
+
+ //Create and open a session on the connection through which
+ //most functionality is exposed:
+ Session session = connection.newSession();
+ if (opts.verbose) std::cout << "Opened session." << std::endl;
+
+
+ //'declare' the exchange and the queue, which will create them
+ //as they don't exist
+ session.exchangeDeclare(arg::exchange="MyExchange", arg::type="direct");
+ if (opts.verbose) std::cout << "Declared exchange." << std::endl;
+ session.queueDeclare(arg::queue="MyQueue", arg::autoDelete=true, arg::exclusive=true);
+ if (opts.verbose) std::cout << "Declared queue." << std::endl;
+
+ //now bind the queue to the exchange
+ session.exchangeBind(arg::exchange="MyExchange", arg::queue="MyQueue", arg::bindingKey="MyKey");
+ if (opts.verbose) std::cout << "Bound queue to exchange." << std::endl;
+
+ //create and send a message to the exchange using the routing
+ //key we bound our queue with:
+ Message msgOut(generateData(opts.msgSize));
+ msgOut.getDeliveryProperties().setRoutingKey("MyKey");
+ session.messageTransfer(arg::destination="MyExchange", arg::content=msgOut, arg::acceptMode=1);
+ if (opts.verbose) print("Published message: ", msgOut);
+
+ //subscribe to the queue, add sufficient credit and then get
+ //incoming 'frameset', check that its a message transfer and
+ //then convert it to a message (see Dispatcher and
+ //SubscriptionManager utilties for common reusable patterns at
+ //a higher level)
+ session.messageSubscribe(arg::queue="MyQueue", arg::destination="MyId");
+ session.messageFlow(arg::destination="MyId", arg::unit=0, arg::value=1); //credit for one message
+ session.messageFlow(arg::destination="MyId", arg::unit=1, arg::value=0xFFFFFFFF); //credit for infinite bytes
+ if (opts.verbose) std::cout << "Subscribed to queue." << std::endl;
+ FrameSet::shared_ptr incoming = session.get();
+ if (incoming->isA<MessageTransferBody>()) {
+ Message msgIn(*incoming);
+ if (msgIn.getData() == msgOut.getData()) {
+ if (opts.verbose) std::cout << "Received the exepected message." << std::endl;
+ session.messageAccept(SequenceSet(msgIn.getId()));
+ session.markCompleted(msgIn.getId(), true, true);
+ } else {
+ print("Received an unexepected message: ", msgIn);
+ }
+ } else {
+ throw Exception("Unexpected command received");
+ }
+
+ //close the session & connection
+ session.close();
+ if (opts.verbose) std::cout << "Closed session." << std::endl;
+ connection.close();
+ if (opts.verbose) std::cout << "Closed connection." << std::endl;
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/cluster.mk b/RC9/qpid/cpp/src/tests/cluster.mk
new file mode 100644
index 0000000000..1f027ccb4c
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/cluster.mk
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+
+if HAVE_LIBCPG
+
+#
+# Cluster tests makefile fragment, to be included in Makefile.am
+#
+
+# NOTE: Programs using the openais library must be run with gid=ais
+# You should do "newgrp ais" before running the tests to run these.
+#
+
+
+# ais_check checks pre-requisites for cluster tests and runs them if ok.
+TESTS+=ais_check
+EXTRA_DIST+=ais_check start_cluster stop_cluster
+
+check_PROGRAMS+=cluster_test
+cluster_test_SOURCES=unit_test.cpp cluster_test.cpp
+cluster_test_LDADD=$(lib_client) ../cluster.la -lboost_unit_test_framework
+
+unit_test_LDADD+=../cluster.la
+
+endif
diff --git a/RC9/qpid/cpp/src/tests/cluster_test.cpp b/RC9/qpid/cpp/src/tests/cluster_test.cpp
new file mode 100644
index 0000000000..f4a38ae861
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/cluster_test.cpp
@@ -0,0 +1,648 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test_tools.h"
+#include "unit_test.h"
+#include "ForkedBroker.h"
+#include "BrokerFixture.h"
+
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionAccess.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/FailoverListener.h"
+#include "qpid/cluster/Cluster.h"
+#include "qpid/cluster/Cpg.h"
+#include "qpid/cluster/DumpClient.h"
+#include "qpid/framing/AMQBody.h"
+#include "qpid/framing/Uuid.h"
+#include "qpid/framing/reply_exceptions.h"
+#include "qpid/framing/enum.h"
+#include "qpid/log/Logger.h"
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <string>
+#include <iostream>
+#include <iterator>
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <iterator>
+
+namespace std { // ostream operators in std:: namespace
+template <class T>
+ostream& operator<<(ostream& o, const std::set<T>& s) { return seqPrint(o, s); }
+}
+
+
+QPID_AUTO_TEST_SUITE(cluster)
+
+using namespace std;
+using namespace qpid;
+using namespace qpid::cluster;
+using namespace qpid::framing;
+using namespace qpid::client;
+using qpid::sys::TIME_SEC;
+using qpid::broker::Broker;
+using boost::shared_ptr;
+using qpid::cluster::Cluster;
+
+/** Parse broker & cluster options */
+Broker::Options parseOpts(size_t argc, const char* argv[]) {
+ Broker::Options opts;
+ Plugin::addOptions(opts); // Pick up cluster options.
+ opts.parse(argc, argv, "", true); // Allow-unknown for --load-module
+ return opts;
+}
+
+/** Cluster fixture is a vector of ports for the replicas.
+ *
+ * At most one replica (by default replica 0) is in the current
+ * process, all others are forked as children.
+ */
+class ClusterFixture : public vector<uint16_t> {
+ string name;
+ std::auto_ptr<BrokerFixture> localBroker;
+ int localIndex;
+ std::vector<shared_ptr<ForkedBroker> > forkedBrokers;
+
+ public:
+ /** @param localIndex can be -1 meaning don't automatically start a local broker.
+ * A local broker can be started with addLocal().
+ */
+ ClusterFixture(size_t n, int localIndex=0);
+ void add(size_t n) { for (size_t i=0; i < n; ++i) add(); }
+ void add(); // Add a broker.
+ void addLocal(); // Add a local broker.
+ void setup();
+
+ bool hasLocal() const { return localIndex >= 0 && size_t(localIndex) < size(); }
+
+ /** Kill a forked broker with sig, or shutdown localBroker if n==0. */
+ void kill(size_t n, int sig=SIGINT) {
+ if (n == size_t(localIndex))
+ localBroker->broker->shutdown();
+ else
+ forkedBrokers[n]->kill(sig);
+ }
+
+ /** Kill a broker and suppress errors from connection. */
+ void killWithSilencer(size_t n, client::Connection& c, int sig=SIGINT) {
+ ScopedSuppressLogging sl;
+ kill(n,sig);
+ try { c.close(); } catch(...) {}
+ }
+};
+
+ClusterFixture::ClusterFixture(size_t n, int localIndex_) : name(Uuid(true).str()), localIndex(localIndex_) {
+ add(n);
+}
+
+void ClusterFixture::add() {
+ if (size() != size_t(localIndex)) { // fork a broker process.
+ std::ostringstream os; os << "fork" << size();
+ std::string prefix = os.str();
+ const char* argv[] = {
+ "qpidd " __FILE__ ,
+ "--no-module-dir",
+ "--load-module=../.libs/cluster.so",
+ "--cluster-name", name.c_str(),
+ "--auth=no", "--no-data-dir",
+ "--log-prefix", prefix.c_str(),
+ };
+ size_t argc = sizeof(argv)/sizeof(argv[0]);
+ forkedBrokers.push_back(shared_ptr<ForkedBroker>(new ForkedBroker(argc, argv)));
+ push_back(forkedBrokers.back()->getPort());
+ }
+ else { // Run in this process
+ addLocal();
+ }
+}
+
+void ClusterFixture::addLocal() {
+ assert(int(size()) == localIndex || localIndex == -1);
+ localIndex = size();
+ const char* argv[] = {
+ "qpidd " __FILE__ ,
+ "--load-module=../.libs/cluster.so",
+ "--cluster-name", name.c_str(),
+ "--auth=no", "--no-data-dir"
+ };
+ size_t argc = sizeof(argv)/sizeof(argv[0]);
+ ostringstream os; os << "local" << localIndex;
+ qpid::log::Logger::instance().setPrefix(os.str());
+ localBroker.reset(new BrokerFixture(parseOpts(argc, argv)));
+ push_back(localBroker->getPort());
+ forkedBrokers.push_back(shared_ptr<ForkedBroker>());
+}
+
+ostream& operator<<(ostream& o, const cpg_name* n) {
+ return o << qpid::cluster::Cpg::str(*n);
+}
+
+ostream& operator<<(ostream& o, const cpg_address& a) {
+ return o << "(" << a.nodeid <<","<<a.pid<<","<<a.reason<<")";
+}
+
+template <class T>
+ostream& operator<<(ostream& o, const pair<T*, int>& array) {
+ o << "{ ";
+ ostream_iterator<cpg_address> i(o, " ");
+ copy(array.first, array.first+array.second, i);
+ o << "}";
+ return o;
+}
+
+template <class C> set<uint16_t> makeSet(const C& c) {
+ set<uint16_t> s;
+ std::copy(c.begin(), c.end(), std::inserter(s, s.begin()));
+ return s;
+}
+
+template <class T> std::set<uint16_t> knownBrokerPorts(T& source, int n=-1) {
+ vector<Url> urls = source.getKnownBrokers();
+ if (n >= 0 && unsigned(n) != urls.size()) {
+ BOOST_MESSAGE("knownBrokerPorts waiting for " << n << ": " << urls);
+ // Retry up to 10 secs in .1 second intervals.
+ for (size_t retry=100; urls.size() != unsigned(n) && retry != 0; --retry) {
+ ::usleep(1000*100); // 0.1 secs
+ urls = source.getKnownBrokers();
+ }
+ }
+ BOOST_MESSAGE("knownBrokerPorts expecting " << n << ": " << urls);
+ set<uint16_t> s;
+ for (vector<Url>::const_iterator i = urls.begin(); i != urls.end(); ++i)
+ s.insert((*i)[0].get<TcpAddress>()->port);
+ return s;
+}
+
+class Sender {
+ public:
+ Sender(boost::shared_ptr<ConnectionImpl> ci, uint16_t ch) : connection(ci), channel(ch) {}
+ void send(const AMQBody& body, bool firstSeg, bool lastSeg, bool firstFrame, bool lastFrame) {
+ AMQFrame f(body);
+ f.setChannel(channel);
+ f.setFirstSegment(firstSeg);
+ f.setLastSegment(lastSeg);
+ f.setFirstFrame(firstFrame);
+ f.setLastFrame(lastFrame);
+ connection->handle(f);
+ }
+
+ private:
+ boost::shared_ptr<ConnectionImpl> connection;
+ uint16_t channel;
+};
+
+int64_t getMsgSequence(const Message& m) {
+ return m.getMessageProperties().getApplicationHeaders().getAsInt64("qpid.msg_sequence");
+}
+
+QPID_AUTO_TEST_CASE(testSequenceOptions) {
+ // Make sure the exchange qpid.msg_sequence property is properly replicated.
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+ FieldTable args;
+ args.setInt("qpid.msg_sequence", 1); // FIXME aconway 2008-11-11: works with "qpid.sequence_counter"??
+ c0.session.queueDeclare(arg::queue="q");
+ c0.session.exchangeDeclare(arg::exchange="ex", arg::type="direct", arg::arguments=args);
+ c0.session.exchangeBind(arg::exchange="ex", arg::queue="q", arg::bindingKey="k");
+ c0.session.messageTransfer(arg::content=Message("1", "k"), arg::destination="ex");
+ c0.session.messageTransfer(arg::content=Message("2", "k"), arg::destination="ex");
+ BOOST_CHECK_EQUAL(1, getMsgSequence(c0.subs.get("q", TIME_SEC)));
+ BOOST_CHECK_EQUAL(2, getMsgSequence(c0.subs.get("q", TIME_SEC)));
+
+ cluster.add();
+ Client c1(cluster[1]);
+ c1.session.messageTransfer(arg::content=Message("3", "k"), arg::destination="ex");
+ BOOST_CHECK_EQUAL(3, getMsgSequence(c1.subs.get("q", TIME_SEC)));
+}
+
+QPID_AUTO_TEST_CASE(testUnsupported) {
+ ScopedSuppressLogging sl;
+ ClusterFixture cluster(1);
+ Client c1(cluster[0], "c1");
+ BOOST_CHECK_THROW(c1.session.dtxSelect(), FramingErrorException);
+ Client c2(cluster[0], "c2");
+ Message m;
+ m.getDeliveryProperties().setTtl(1);
+ BOOST_CHECK_THROW(c2.session.messageTransfer(arg::content=m), Exception);
+}
+
+QPID_AUTO_TEST_CASE(testTxTransaction) {
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare(arg::queue="q");
+ c0.session.messageTransfer(arg::content=Message("A", "q"));
+ c0.session.messageTransfer(arg::content=Message("B", "q"));
+
+ // Start a transaction that will commit.
+ Session commitSession = c0.connection.newSession("commit");
+ SubscriptionManager commitSubs(commitSession);
+ commitSession.txSelect();
+ commitSession.messageTransfer(arg::content=Message("a", "q"));
+ commitSession.messageTransfer(arg::content=Message("b", "q"));
+ BOOST_CHECK_EQUAL(commitSubs.get("q", TIME_SEC).getData(), "A");
+
+ // Start a transaction that will roll back.
+ Session rollbackSession = c0.connection.newSession("rollback");
+ SubscriptionManager rollbackSubs(rollbackSession);
+ rollbackSession.txSelect();
+ rollbackSession.messageTransfer(arg::content=Message("1", "q"));
+ Message rollbackMessage = rollbackSubs.get("q", TIME_SEC);
+ BOOST_CHECK_EQUAL(rollbackMessage.getData(), "B");
+
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q").getMessageCount(), 0u);
+ // Add new member mid transaction.
+ cluster.add();
+ Client c1(cluster[1], "c1");
+
+ // More transactional work
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+ rollbackSession.messageTransfer(arg::content=Message("2", "q"));
+ commitSession.messageTransfer(arg::content=Message("c", "q"));
+ rollbackSession.messageTransfer(arg::content=Message("3", "q"));
+
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+
+ // Commit/roll back.
+ commitSession.txCommit();
+ rollbackSession.txRollback();
+ rollbackSession.messageRelease(rollbackMessage.getId());
+
+
+ // Verify queue status: just the comitted messages and dequeues should remain.
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 4u);
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIME_SEC).getData(), "B");
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIME_SEC).getData(), "a");
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIME_SEC).getData(), "b");
+ BOOST_CHECK_EQUAL(c1.subs.get("q", TIME_SEC).getData(), "c");
+}
+
+QPID_AUTO_TEST_CASE(testUnacked) {
+ // Verify replication of unacknowledged messages.
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+
+ Message m;
+
+ // Create unacked message: acquired but not accepted.
+ SubscriptionSettings manualAccept(FlowControl::unlimited(), ACCEPT_MODE_EXPLICIT, ACQUIRE_MODE_PRE_ACQUIRED, 0);
+ c0.session.queueDeclare("q1");
+ c0.session.messageTransfer(arg::content=Message("11","q1"));
+ LocalQueue q1;
+ c0.subs.subscribe(q1, "q1", manualAccept);
+ BOOST_CHECK_EQUAL(q1.get(TIME_SEC).getData(), "11"); // Acquired but not accepted
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q1").getMessageCount(), 0u); // Gone from queue
+
+ // Create unacked message: not acquired, accepted or completeed.
+ SubscriptionSettings manualAcquire(FlowControl::unlimited(), ACCEPT_MODE_EXPLICIT, ACQUIRE_MODE_NOT_ACQUIRED, 0);
+ c0.session.queueDeclare("q2");
+ c0.session.messageTransfer(arg::content=Message("21","q2"));
+ c0.session.messageTransfer(arg::content=Message("22","q2"));
+ LocalQueue q2;
+ c0.subs.subscribe(q2, "q2", manualAcquire);
+ m = q2.get(TIME_SEC); // Not acquired or accepted, still on queue
+ BOOST_CHECK_EQUAL(m.getData(), "21");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q2").getMessageCount(), 2u); // Not removed
+ c0.subs.getSubscription("q2").acquire(m); // Acquire manually
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q2").getMessageCount(), 1u); // Removed
+ BOOST_CHECK_EQUAL(q2.get(TIME_SEC).getData(), "22"); // Not acquired or accepted, still on queue
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q2").getMessageCount(), 1u); // 1 not acquired.
+
+ // Create empty credit record: acquire and accept but don't complete.
+ SubscriptionSettings manualComplete(FlowControl::messageWindow(1), ACCEPT_MODE_EXPLICIT, ACQUIRE_MODE_PRE_ACQUIRED, 1, MANUAL_COMPLETION);
+ c0.session.queueDeclare("q3");
+ c0.session.messageTransfer(arg::content=Message("31", "q3"));
+ c0.session.messageTransfer(arg::content=Message("32", "q3"));
+ LocalQueue q3;
+ c0.subs.subscribe(q3, "q3", manualComplete);
+ Message m31=q3.get(TIME_SEC);
+ BOOST_CHECK_EQUAL(m31.getData(), "31"); // Automatically acquired & accepted but not completed.
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q3").getMessageCount(), 1u);
+
+ // Add new member while there are unacked messages.
+ cluster.add();
+ Client c1(cluster[1], "c1");
+
+ // Check queue counts
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q1").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q2").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q3").getMessageCount(), 1u);
+
+ // Complete the empty credit message, should unblock the message behind it.
+ BOOST_CHECK_THROW(q3.get(0), Exception);
+ c0.session.markCompleted(SequenceSet(m31.getId()), true);
+ BOOST_CHECK_EQUAL(q3.get(TIME_SEC).getData(), "32");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q3").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q3").getMessageCount(), 0u);
+
+ // Close the original session - unacked messages should be requeued.
+ c0.session.close();
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q1").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q2").getMessageCount(), 2u);
+
+ BOOST_CHECK_EQUAL(c1.subs.get("q1", TIME_SEC).getData(), "11");
+ BOOST_CHECK_EQUAL(c1.subs.get("q2", TIME_SEC).getData(), "21");
+ BOOST_CHECK_EQUAL(c1.subs.get("q2", TIME_SEC).getData(), "22");
+}
+
+QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(testDumpTxState, 1) {
+ // Verify that we dump transaction state correctly to new members.
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+
+ // Do work in a transaction.
+ c0.session.txSelect();
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("1","q"));
+ c0.session.messageTransfer(arg::content=Message("2","q"));
+ Message m;
+ BOOST_CHECK(c0.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "1");
+
+ // New member, TX not comitted, c1 should see nothing.
+ cluster.add();
+ Client c1(cluster[1], "c1");
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 0u);
+
+ // After commit c1 shoudl see results of tx.
+ c0.session.txCommit();
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 1u);
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "2");
+
+ // Another transaction with both members active.
+ c0.session.messageTransfer(arg::content=Message("3","q"));
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 0u);
+ c0.session.txCommit();
+ BOOST_CHECK_EQUAL(c1.session.queueQuery(arg::queue="q").getMessageCount(), 1u);
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "3");
+}
+
+QPID_AUTO_TEST_CASE(testDumpMessageBuilder) {
+ // Verify that we dump a partially recieved message to a new member.
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("q");
+ Sender sender(ConnectionAccess::getImpl(c0.connection), c0.session.getChannel());
+
+ // Send first 2 frames of message.
+ MessageTransferBody transfer(
+ ProtocolVersion(), std::string(), // default exchange.
+ framing::message::ACCEPT_MODE_NONE,
+ framing::message::ACQUIRE_MODE_PRE_ACQUIRED);
+ sender.send(transfer, true, false, true, true);
+ AMQHeaderBody header;
+ header.get<DeliveryProperties>(true)->setRoutingKey("q");
+ sender.send(header, false, false, true, true);
+
+ // No reliable way to ensure the partial message has arrived
+ // before we start the new broker, so we sleep.
+ ::usleep(2500);
+ cluster.add();
+
+ // Send final 2 frames of message.
+ sender.send(AMQContentBody("ab"), false, true, true, false);
+ sender.send(AMQContentBody("cd"), false, true, false, true);
+
+ // Verify message is enqued correctly on second member.
+ Message m;
+ Client c1(cluster[1], "c1");
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "abcd");
+ BOOST_CHECK_EQUAL(2u, knownBrokerPorts(c1.connection).size());
+}
+
+QPID_AUTO_TEST_CASE(testConnectionKnownHosts) {
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+ set<uint16_t> kb0 = knownBrokerPorts(c0.connection);
+ BOOST_CHECK_EQUAL(kb0.size(), 1u);
+ BOOST_CHECK_EQUAL(kb0, makeSet(cluster));
+
+ cluster.add();
+ Client c1(cluster[1], "c1");
+ set<uint16_t> kb1 = knownBrokerPorts(c1.connection);
+ kb0 = knownBrokerPorts(c0.connection, 2);
+ BOOST_CHECK_EQUAL(kb1.size(), 2u);
+ BOOST_CHECK_EQUAL(kb1, makeSet(cluster));
+ BOOST_CHECK_EQUAL(kb1,kb0);
+
+ cluster.add();
+ Client c2(cluster[2], "c2");
+ set<uint16_t> kb2 = knownBrokerPorts(c2.connection);
+ kb1 = knownBrokerPorts(c1.connection, 3);
+ kb0 = knownBrokerPorts(c0.connection, 3);
+ BOOST_CHECK_EQUAL(kb2.size(), 3u);
+ BOOST_CHECK_EQUAL(kb2, makeSet(cluster));
+ BOOST_CHECK_EQUAL(kb2,kb0);
+ BOOST_CHECK_EQUAL(kb2,kb1);
+
+ cluster.killWithSilencer(1,c1.connection,9);
+ kb0 = knownBrokerPorts(c0.connection, 2);
+ kb2 = knownBrokerPorts(c2.connection, 2);
+ BOOST_CHECK_EQUAL(kb0.size(), 2u);
+ BOOST_CHECK_EQUAL(kb0, kb2);
+}
+
+QPID_AUTO_TEST_CASE(DumpConsumers) {
+ ClusterFixture cluster(1, 1);
+
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("p");
+ c0.session.queueDeclare("q");
+ c0.subs.subscribe(c0.lq, "q", FlowControl::zero());
+ LocalQueue lp;
+ c0.subs.subscribe(lp, "p", FlowControl::messageCredit(1));
+ c0.session.sync();
+
+ // Start new members
+ cluster.add(); // Local
+ Client c1(cluster[1], "c1");
+ cluster.add();
+ Client c2(cluster[2], "c2");
+
+ // Transfer messages
+ c0.session.messageTransfer(arg::content=Message("aaa", "q"));
+
+ c0.session.messageTransfer(arg::content=Message("bbb", "p"));
+ c0.session.messageTransfer(arg::content=Message("ccc", "p"));
+
+ // Activate the subscription, ensure message removed on all queues.
+ c0.subs.setFlowControl("q", FlowControl::unlimited());
+ Message m;
+ BOOST_CHECK(c0.lq.get(m, TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "aaa");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("q").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+ BOOST_CHECK_EQUAL(c2.session.queueQuery("q").getMessageCount(), 0u);
+
+ // Check second subscription's flow control: gets first message, not second.
+ BOOST_CHECK(lp.get(m, TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "bbb");
+ BOOST_CHECK_EQUAL(c0.session.queueQuery("p").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("p").getMessageCount(), 1u);
+ BOOST_CHECK_EQUAL(c2.session.queueQuery("p").getMessageCount(), 1u);
+
+ BOOST_CHECK(c0.subs.get(m, "p", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "ccc");
+
+ // Kill the subscribing member, ensure further messages are not removed.
+ cluster.killWithSilencer(0,c0.connection,9);
+ BOOST_REQUIRE_EQUAL(knownBrokerPorts(c1.connection, 2).size(), 2u);
+ for (int i = 0; i < 10; ++i) {
+ c1.session.messageTransfer(arg::content=Message("xxx", "q"));
+ BOOST_REQUIRE(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_REQUIRE_EQUAL(m.getData(), "xxx");
+ }
+}
+
+QPID_AUTO_TEST_CASE(testCatchupSharedState) {
+ ClusterFixture cluster(1);
+ Client c0(cluster[0], "c0");
+
+ // Create some shared state.
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("foo","q"));
+ c0.session.messageTransfer(arg::content=Message("bar","q"));
+ while (c0.session.queueQuery("q").getMessageCount() != 2)
+ ::usleep(1000); // Wait for message to show up on broker 0.
+
+ // Add a new broker, it should catch up.
+ cluster.add();
+
+ // Do some work post-add
+ c0.session.queueDeclare("p");
+ c0.session.messageTransfer(arg::content=Message("pfoo","p"));
+
+ // Do some work post-join
+ BOOST_REQUIRE_EQUAL(knownBrokerPorts(c0.connection, 2).size(), 2u);
+ c0.session.messageTransfer(arg::content=Message("pbar","p"));
+
+ // Verify new brokers have state.
+ Message m;
+
+ Client c1(cluster[1], "c1");
+
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "foo");
+ BOOST_CHECK(c1.subs.get(m, "q", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "bar");
+ BOOST_CHECK_EQUAL(c1.session.queueQuery("q").getMessageCount(), 0u);
+
+ // Add another broker, don't wait for join - should be stalled till ready.
+ cluster.add();
+ Client c2(cluster[2], "c2");
+ BOOST_CHECK(c2.subs.get(m, "p", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "pfoo");
+ BOOST_CHECK(c2.subs.get(m, "p", TIME_SEC));
+ BOOST_CHECK_EQUAL(m.getData(), "pbar");
+ BOOST_CHECK_EQUAL(c2.session.queueQuery("p").getMessageCount(), 0u);
+}
+
+QPID_AUTO_TEST_CASE(testWiringReplication) {
+ ClusterFixture cluster(3);
+ Client c0(cluster[0]);
+ BOOST_CHECK(c0.session.queueQuery("q").getQueue().empty());
+ BOOST_CHECK(c0.session.exchangeQuery("ex").getType().empty());
+ c0.session.queueDeclare("q");
+ c0.session.exchangeDeclare("ex", arg::type="direct");
+ c0.session.close();
+ c0.connection.close();
+ // Verify all brokers get wiring update.
+ for (size_t i = 0; i < cluster.size(); ++i) {
+ BOOST_MESSAGE("i == "<< i);
+ Client c(cluster[i]);
+ BOOST_CHECK_EQUAL("q", c.session.queueQuery("q").getQueue());
+ BOOST_CHECK_EQUAL("direct", c.session.exchangeQuery("ex").getType());
+ }
+}
+
+QPID_AUTO_TEST_CASE(testMessageEnqueue) {
+ // Enqueue on one broker, dequeue on another.
+ ClusterFixture cluster(2);
+ Client c0(cluster[0]);
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("foo", "q"));
+ c0.session.messageTransfer(arg::content=Message("bar", "q"));
+ c0.session.close();
+ Client c1(cluster[1]);
+ Message msg;
+ BOOST_CHECK(c1.subs.get(msg, "q", qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(string("foo"), msg.getData());
+ BOOST_CHECK(c1.subs.get(msg, "q", qpid::sys::TIME_SEC));
+ BOOST_CHECK_EQUAL(string("bar"), msg.getData());
+}
+
+QPID_AUTO_TEST_CASE(testMessageDequeue) {
+ // Enqueue on one broker, dequeue on two others.
+ ClusterFixture cluster(3);
+ Client c0(cluster[0], "c0");
+ c0.session.queueDeclare("q");
+ c0.session.messageTransfer(arg::content=Message("foo", "q"));
+ c0.session.messageTransfer(arg::content=Message("bar", "q"));
+
+ Message msg;
+
+ // Dequeue on 2 others, ensure correct order.
+ Client c1(cluster[1], "c1");
+ BOOST_CHECK(c1.subs.get(msg, "q"));
+ BOOST_CHECK_EQUAL("foo", msg.getData());
+
+ Client c2(cluster[2], "c2");
+ BOOST_CHECK(c1.subs.get(msg, "q"));
+ BOOST_CHECK_EQUAL("bar", msg.getData());
+
+ // Queue should be empty on all cluster members.
+ BOOST_CHECK_EQUAL(0u, c0.session.queueQuery("q").getMessageCount());
+ BOOST_CHECK_EQUAL(0u, c1.session.queueQuery("q").getMessageCount());
+ BOOST_CHECK_EQUAL(0u, c2.session.queueQuery("q").getMessageCount());
+}
+
+QPID_AUTO_TEST_CASE(testDequeueWaitingSubscription) {
+ ClusterFixture cluster(3);
+ Client c0(cluster[0]);
+ BOOST_REQUIRE_EQUAL(knownBrokerPorts(c0.connection, 3).size(), 3u); // Wait for brokers.
+
+ // First start a subscription.
+ c0.session.queueDeclare("q");
+ c0.subs.subscribe(c0.lq, "q", FlowControl::messageCredit(2));
+
+ // Now send messages
+ Client c1(cluster[1]);
+ c1.session.messageTransfer(arg::content=Message("foo", "q"));
+ c1.session.messageTransfer(arg::content=Message("bar", "q"));
+
+ // Check they arrived
+ Message m;
+ BOOST_CHECK(c0.lq.get(m, sys::TIME_SEC));
+ BOOST_CHECK_EQUAL("foo", m.getData());
+ BOOST_CHECK(c0.lq.get(m, sys::TIME_SEC));
+ BOOST_CHECK_EQUAL("bar", m.getData());
+
+ // Queue should be empty on all cluster members.
+ Client c2(cluster[2]);
+ BOOST_CHECK_EQUAL(0u, c0.session.queueQuery("q").getMessageCount());
+ BOOST_CHECK_EQUAL(0u, c1.session.queueQuery("q").getMessageCount());
+ BOOST_CHECK_EQUAL(0u, c2.session.queueQuery("q").getMessageCount());
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/config.null b/RC9/qpid/cpp/src/tests/config.null
new file mode 100644
index 0000000000..565c7da435
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/config.null
@@ -0,0 +1 @@
+# empty config
diff --git a/RC9/qpid/cpp/src/tests/consume.cpp b/RC9/qpid/cpp/src/tests/consume.cpp
new file mode 100644
index 0000000000..4d74b8ae57
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/consume.cpp
@@ -0,0 +1,119 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using namespace std;
+
+typedef vector<string> StringSet;
+
+struct Args : public qpid::TestOptions {
+ uint count;
+ uint ack;
+ string queue;
+ bool declare;
+ bool summary;
+
+ Args() : count(1000), ack(0), queue("publish-consume"),
+ declare(false), summary(false)
+ {
+ addOptions()
+ ("count", optValue(count, "N"), "number of messages to publish")
+ ("ack-frequency", optValue(ack, "N"), "ack every N messages (0 means use no-ack mode)")
+ ("queue", optValue(queue, "<queue name>"), "queue to consume from")
+ ("declare", optValue(declare), "declare the queue")
+ ("s,summary", optValue(summary), "Print undecorated rate.");
+ }
+};
+
+Args opts;
+
+struct Client
+{
+ Connection connection;
+ Session session;
+
+ Client()
+ {
+ opts.open(connection);
+ session = connection.newSession();
+ }
+
+ void consume()
+ {
+ if (opts.declare)
+ session.queueDeclare(opts.queue);
+ SubscriptionManager subs(session);
+ LocalQueue lq;
+ SubscriptionSettings settings;
+ settings.acceptMode = opts.ack > 0 ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE;
+ settings.flowControl = FlowControl(opts.count, SubscriptionManager::UNLIMITED,false);
+ Subscription sub = subs.subscribe(lq, opts.queue, settings);
+ Message msg;
+ AbsTime begin=now();
+ for (size_t i = 0; i < opts.count; ++i) {
+ msg=lq.pop();
+ QPID_LOG(info, "Received: " << msg.getMessageProperties().getCorrelationId());
+ }
+ if (opts.ack != 0)
+ sub.accept(sub.getUnaccepted()); // Cumulative ack for final batch.
+ AbsTime end=now();
+ double secs(double(Duration(begin,end))/TIME_SEC);
+ if (opts.summary) cout << opts.count/secs << endl;
+ else cout << "Time: " << secs << "s Rate: " << opts.count/secs << endl;
+ }
+
+ ~Client()
+ {
+ try{
+ session.close();
+ connection.close();
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ }
+};
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ Client client;
+ client.consume();
+ return 0;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/declare_queues.cpp b/RC9/qpid/cpp/src/tests/declare_queues.cpp
new file mode 100644
index 0000000000..7f61bde12a
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/declare_queues.cpp
@@ -0,0 +1,69 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/Exception.h>
+
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid::client;
+
+using namespace std;
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+ if ( argc != 3 )
+ {
+ cerr << "Usage: declare_queues host port\n";
+ return 1;
+ }
+
+ settings.host = argv[1];
+ settings.port = atoi(argv[2]);
+
+ FailoverManager connection(settings);
+ try {
+ bool complete = false;
+ while (!complete) {
+ Session session = connection.connect().newSession();
+ try {
+ session.queueDeclare(arg::queue="message_queue");
+ complete = true;
+ } catch (const qpid::TransportFailure&) {}
+ }
+ connection.close();
+ return 0;
+ } catch (const exception& error) {
+ cerr << "declare_queues failed:" << error.what() << endl;
+ cerr << " host: " << settings.host
+ << " port: " << settings.port << endl;
+ return 1;
+ }
+
+}
+
+
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/dlclose_noop.c b/RC9/qpid/cpp/src/tests/dlclose_noop.c
new file mode 100644
index 0000000000..ba2fa75891
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/dlclose_noop.c
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * Loaded via LD_PRELOAD this will turn dlclose into a no-op.
+ *
+ * Allows valgrind to generate useful reports from programs that
+ * dynamically unload libraries before exit, such as CppUnit's
+ * DllPlugInTester.
+ *
+ */
+
+#include <stdio.h>
+void* dlclose(void* handle) {}
+
diff --git a/RC9/qpid/cpp/src/tests/echotest.cpp b/RC9/qpid/cpp/src/tests/echotest.cpp
new file mode 100644
index 0000000000..7cbf3e7df4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/echotest.cpp
@@ -0,0 +1,150 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/SubscriptionManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/sys/Time.h>
+
+#include <iostream>
+
+using namespace qpid::client;
+using namespace qpid::framing;
+using namespace qpid::sys;
+using namespace std;
+
+struct Args : public qpid::Options,
+ public qpid::client::ConnectionSettings
+{
+ bool help;
+ uint count;
+ uint size;
+ bool summary;
+
+ Args() : qpid::Options("Simple latency test optins"), help(false), count(20), size(0), summary()
+ {
+ using namespace qpid;
+ addOptions()
+ ("help", optValue(help), "Print this usage statement")
+ ("count", optValue(count, "N"), "Number of messages to send")
+ ("size", optValue(count, "N"), "Size of messages")
+ ("broker,b", optValue(host, "HOST"), "Broker host to connect to")
+ ("port,p", optValue(port, "PORT"), "Broker port to connect to")
+ ("username", optValue(username, "USER"), "user name for broker log in.")
+ ("password", optValue(password, "PASSWORD"), "password for broker log in.")
+ ("mechanism", optValue(mechanism, "MECH"), "SASL mechanism to use when authenticating.")
+ ("tcp-nodelay", optValue(tcpNoDelay), "Turn on tcp-nodelay")
+ ("s,summary", optValue(summary), "Print only average latency.");
+ }
+};
+
+uint64_t current_time()
+{
+ Duration t(now());
+ return t;
+}
+
+class Listener : public MessageListener
+{
+ private:
+ Session session;
+ SubscriptionManager subscriptions;
+ uint counter;
+ const uint limit;
+ std::string queue;
+ Message request;
+ double total, min, max;
+ bool summary;
+
+ public:
+ Listener(Session& session, uint limit, bool summary);
+ void start(uint size);
+ void received(Message& message);
+};
+
+Listener::Listener(Session& s, uint l, bool summary_) :
+ session(s), subscriptions(s), counter(0), limit(l),
+ queue(session.getId().getName()), total(),
+ min(std::numeric_limits<double>::max()), max(), summary(summary_)
+{}
+
+void Listener::start(uint size)
+{
+ session.queueDeclare(arg::queue=queue, arg::exclusive=true, arg::autoDelete=true);
+ request.getDeliveryProperties().setRoutingKey(queue);
+ subscriptions.subscribe(*this, queue, SubscriptionSettings(FlowControl::unlimited(), ACCEPT_MODE_NONE));
+
+ request.getDeliveryProperties().setTimestamp(current_time());
+ if (size) request.setData(std::string(size, 'X'));
+ async(session).messageTransfer(arg::content=request);
+ subscriptions.run();
+}
+
+void Listener::received(Message& response)
+{
+ //extract timestamp and compute latency:
+ uint64_t sentAt = response.getDeliveryProperties().getTimestamp();
+ uint64_t receivedAt = current_time();
+
+ double latency = ((double) (receivedAt - sentAt)) / TIME_MSEC;
+ if (!summary) cout << "Latency: " << latency << "ms" << endl;
+ min = std::min(latency, min);
+ max = std::max(latency, max);
+ total += latency;
+
+ if (++counter < limit) {
+ request.getDeliveryProperties().setTimestamp(current_time());
+ async(session).messageTransfer(arg::content=request);
+ } else {
+ subscriptions.cancel(queue);
+ if (summary) cout << min << "\t" << max << "\t" << total/limit << endl;
+ else cout << "min: " << min << " max: " << max << " average: " << total/limit << endl;
+ }
+}
+
+int main(int argc, char** argv)
+{
+ Args opts;
+ opts.parse(argc, argv);
+
+ if (opts.help) {
+ std::cout << opts << std::endl;
+ return 0;
+ }
+
+ Connection connection;
+ try {
+ connection.open(opts);
+ Session session = connection.newSession();
+ Listener listener(session, opts.count, opts.summary);
+ listener.start(opts.size);
+
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
diff --git a/RC9/qpid/cpp/src/tests/exception_test.cpp b/RC9/qpid/cpp/src/tests/exception_test.cpp
new file mode 100644
index 0000000000..e420bf2f0b
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/exception_test.cpp
@@ -0,0 +1,121 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "unit_test.h"
+#include "test_tools.h"
+#include "BrokerFixture.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Runnable.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/framing/reply_exceptions.h"
+
+QPID_AUTO_TEST_SUITE(exception_test)
+
+// FIXME aconway 2008-06-12: need to update our exception handling to
+// 0-10 handling and extend this test to provoke all the exceptional
+// conditions we know of and verify the correct exception is thrown.
+
+using namespace std;
+using namespace qpid;
+using namespace sys;
+using namespace client;
+using namespace framing;
+
+using qpid::broker::Broker;
+using boost::bind;
+using boost::function;
+
+template <class Ex>
+struct Catcher : public Runnable {
+ function<void ()> f;
+ bool caught;
+ Thread thread;
+
+ Catcher(function<void ()> f_) : f(f_), caught(false), thread(this) {}
+ ~Catcher() { join(); }
+
+ void run() {
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f();
+ }
+ catch(const Ex& e) {
+ caught=true;
+ BOOST_MESSAGE(string("Caught expected exception: ")+e.what()+"["+typeid(e).name()+"]");
+ }
+ catch(const std::exception& e) {
+ BOOST_ERROR(string("Bad exception: ")+e.what()+"["+typeid(e).name()+"] expected: "+typeid(Ex).name());
+ }
+ catch(...) {
+ BOOST_ERROR(string("Bad exception: unknown"));
+ }
+ }
+
+ bool join() {
+ if (thread.id()) {
+ thread.join();
+ thread=Thread();
+ }
+ return caught;
+ }
+};
+
+QPID_AUTO_TEST_CASE(TestSessionBusy) {
+ SessionFixture f;
+ try {
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ f.connection.newSession(f.session.getId().getName());
+ BOOST_FAIL("Expected SessionBusyException for " << f.session.getId().getName());
+ } catch (const SessionBusyException&) {} // FIXME aconway 2008-09-22: client is not throwing correct exception.
+}
+
+QPID_AUTO_TEST_CASE(DisconnectedPop) {
+ ProxySessionFixture fix;
+ ProxyConnection c(fix.broker->getPort(Broker::TCP_TRANSPORT));
+ fix.session.queueDeclare(arg::queue="q");
+ fix.subs.subscribe(fix.lq, "q");
+ Catcher<TransportFailure> pop(bind(&LocalQueue::pop, &fix.lq, sys::TIME_SEC));
+ fix.connection.proxy.close();
+ BOOST_CHECK(pop.join());
+}
+
+QPID_AUTO_TEST_CASE(DisconnectedListen) {
+ ProxySessionFixture fix;
+ struct NullListener : public MessageListener {
+ void received(Message&) { BOOST_FAIL("Unexpected message"); }
+ } l;
+ ProxyConnection c(fix.broker->getPort(Broker::TCP_TRANSPORT));
+ fix.session.queueDeclare(arg::queue="q");
+ fix.subs.subscribe(l, "q");
+
+ Catcher<TransportFailure> runner(bind(&SubscriptionManager::run, boost::ref(fix.subs)));
+ fix.connection.proxy.close();
+ runner.join();
+ BOOST_CHECK_THROW(fix.session.close(), TransportFailure);
+}
+
+QPID_AUTO_TEST_CASE(NoSuchQueueTest) {
+ ProxySessionFixture fix;
+ ScopedSuppressLogging sl; // Suppress messages for expected errors.
+ BOOST_CHECK_THROW(fix.subs.subscribe(fix.lq, "no such queue"), NotFoundException);
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/failover_soak.cpp b/RC9/qpid/cpp/src/tests/failover_soak.cpp
new file mode 100644
index 0000000000..6149e845e4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/failover_soak.cpp
@@ -0,0 +1,654 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <string.h>
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <ForkedBroker.h>
+
+
+
+
+using namespace std;
+
+
+typedef vector<ForkedBroker *> brokerVector;
+
+typedef enum
+{
+ NO_STATUS,
+ RUNNING,
+ COMPLETED
+}
+childStatus;
+
+
+
+struct child
+{
+ child ( string & name, pid_t pid )
+ : name(name), pid(pid), retval(-999), status(RUNNING)
+ {
+ gettimeofday ( & startTime, 0 );
+ }
+
+
+ void
+ done ( int _retval )
+ {
+ retval = _retval;
+ status = COMPLETED;
+ gettimeofday ( & stopTime, 0 );
+ }
+
+
+ string name;
+ pid_t pid;
+ int retval;
+ childStatus status;
+ struct timeval startTime,
+ stopTime;
+};
+
+
+
+
+struct children : public vector<child *>
+{
+ void
+ add ( string & name, pid_t pid )
+ {
+ push_back(new child ( name, pid ));
+ }
+
+
+ child *
+ get ( pid_t pid )
+ {
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ if ( pid == (*i)->pid )
+ return *i;
+
+ return 0;
+ }
+
+
+ void
+ exited ( pid_t pid, int retval )
+ {
+ child * kid = get ( pid );
+ if(! kid)
+ {
+ if ( verbosity > 0 )
+ {
+ cerr << "children::exited warning: Can't find child with pid "
+ << pid
+ << endl;
+ }
+ return;
+ }
+
+ kid->done ( retval );
+ }
+
+
+ int
+ unfinished ( )
+ {
+ int count = 0;
+
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ if ( COMPLETED != (*i)->status )
+ ++ count;
+
+ return count;
+ }
+
+
+ int
+ checkChildren ( )
+ {
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ if ( (COMPLETED == (*i)->status) && (0 != (*i)->retval) )
+ return (*i)->retval;
+
+ return 0;
+ }
+
+
+ void
+ killEverybody ( )
+ {
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ kill ( (*i)->pid, 9 );
+ }
+
+
+
+ void
+ print ( )
+ {
+ cout << "--- status of all children --------------\n";
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ cout << "child: " << (*i)->name
+ << " status: " << (*i)->status
+ << endl;
+ cout << "\n\n\n\n";
+ }
+
+
+ /*
+ Only call this if you already know there is at least
+ one child still running. Supply a time in seconds.
+ If it has been at least that long since a shild stopped
+ running, we judge the system to have hung.
+ */
+ bool
+ hanging ( int hangTime )
+ {
+ struct timeval now,
+ duration;
+ gettimeofday ( &now, 0 );
+
+ vector<child *>::iterator i;
+ for ( i = begin(); i != end(); ++ i )
+ {
+ timersub ( & now, &((*i)->startTime), & duration );
+ if ( duration.tv_sec >= hangTime )
+ return true;
+ }
+
+ return false;
+ }
+
+
+ int verbosity;
+};
+
+
+
+children allMyChildren;
+
+
+
+
+void
+childExit ( int signalNumber )
+{
+ signalNumber ++; // Now maybe the compiler willleave me alone?
+ int childReturnCode;
+ pid_t pid = waitpid ( 0, & childReturnCode, WNOHANG);
+
+ if ( pid > 0 )
+ allMyChildren.exited ( pid, childReturnCode );
+}
+
+
+
+int
+mrand ( int maxDesiredVal ) {
+ double zeroToOne = (double) rand() / (double) RAND_MAX;
+ return (int) (zeroToOne * (double) maxDesiredVal);
+}
+
+
+
+int
+mrand ( int minDesiredVal, int maxDesiredVal ) {
+ int interval = maxDesiredVal - minDesiredVal;
+ return minDesiredVal + mrand ( interval );
+}
+
+
+
+void
+makeClusterName ( string & s, int & num ) {
+ num = mrand(1000);
+ stringstream ss;
+ ss << "soakTestCluster_" << num;
+ s = ss.str();
+}
+
+
+
+
+
+void
+printBrokers ( brokerVector & brokers )
+{
+ cout << "Broker List ------------ size: " << brokers.size() << "\n";
+ for ( brokerVector::iterator i = brokers.begin(); i != brokers.end(); ++ i) {
+ cout << "pid: "
+ << (*i)->getPID()
+ << " port: "
+ << (*i)->getPort()
+ << endl;
+ }
+ cout << "end Broker List ------------\n";
+}
+
+
+
+
+
+void
+startNewBroker ( brokerVector & brokers,
+ char const * srcRoot,
+ char const * moduleDir,
+ string const clusterName )
+{
+ static int brokerId = 0;
+ stringstream path, prefix, module;
+ module << moduleDir << "/cluster.so";
+ path << srcRoot << "/qpidd";
+ prefix << "soak-" << brokerId++;
+
+ const char * const argv[] =
+ {
+ "qpidd",
+ "-p0",
+ "--load-module=cluster.so",
+ "--cluster-name",
+ clusterName.c_str(),
+ "--auth=no",
+ "--no-data-dir",
+ "--no-module-dir",
+ "--mgmt-enable=no",
+ "--log-prefix", prefix.str().c_str(),
+ 0
+ };
+
+ size_t argc = sizeof(argv)/sizeof(argv[0]);
+ brokers.push_back ( new ForkedBroker ( argc, argv ) );
+}
+
+
+
+
+
+void
+killFrontBroker ( brokerVector & brokers, int verbosity )
+{
+ if ( verbosity > 0 )
+ cout << "killFrontBroker pid: " << brokers[0]->getPID() << " on port " << brokers[0]->getPort() << endl;
+ try { brokers[0]->kill(9); }
+ catch ( const exception& error ) {
+ if ( verbosity > 0 )
+ cout << "error killing broker: " << error.what() << endl;
+ }
+ delete brokers[0];
+ brokers.erase ( brokers.begin() );
+}
+
+
+
+
+
+void
+killAllBrokers ( brokerVector & brokers )
+{
+ for ( uint i = 0; i < brokers.size(); ++ i )
+ try { brokers[i]->kill(9); }
+ catch ( ... ) { }
+}
+
+
+
+
+
+pid_t
+runDeclareQueuesClient ( brokerVector brokers,
+ char const * host,
+ char const * path,
+ int verbosity
+ )
+{
+ string name("declareQueues");
+ int port = brokers[0]->getPort ( );
+
+ if ( verbosity > 0 )
+ cout << "startDeclareQueuesClient: host: "
+ << host
+ << " port: "
+ << port
+ << endl;
+ stringstream portSs;
+ portSs << port;
+
+ vector<const char*> argv;
+ argv.push_back ( "declareQueues" );
+ argv.push_back ( host );
+ argv.push_back ( portSs.str().c_str() );
+ argv.push_back ( 0 );
+ pid_t pid = fork();
+
+ if ( ! pid ) {
+ execv ( path, const_cast<char * const *>(&argv[0]) );
+ perror ( "error executing dq: " );
+ return 0;
+ }
+
+ allMyChildren.add ( name, pid );
+ return pid;
+}
+
+
+
+
+
+pid_t
+startReceivingClient ( brokerVector brokers,
+ char const * host,
+ char const * receiverPath,
+ char const * reportFrequency,
+ int verbosity
+ )
+{
+ string name("receiver");
+ int port = brokers[0]->getPort ( );
+
+ if ( verbosity > 0 )
+ cout << "startReceivingClient: port " << port << endl;
+ char portStr[100];
+ char verbosityStr[100];
+ sprintf(portStr, "%d", port);
+ sprintf(verbosityStr, "%d", verbosity);
+
+
+ vector<const char*> argv;
+ argv.push_back ( "resumingReceiver" );
+ argv.push_back ( host );
+ argv.push_back ( portStr );
+ argv.push_back ( reportFrequency );
+ argv.push_back ( verbosityStr );
+ argv.push_back ( 0 );
+
+ pid_t pid = fork();
+
+ if ( ! pid ) {
+ execv ( receiverPath, const_cast<char * const *>(&argv[0]) );
+ perror ( "error executing receiver: " );
+ return 0;
+ }
+
+ allMyChildren.add ( name, pid );
+ return pid;
+}
+
+
+
+
+
+pid_t
+startSendingClient ( brokerVector brokers,
+ char const * host,
+ char const * senderPath,
+ char const * nMessages,
+ char const * reportFrequency,
+ int verbosity
+ )
+{
+ string name("sender");
+ int port = brokers[0]->getPort ( );
+
+ if ( verbosity )
+ cout << "startSenderClient: port " << port << endl;
+ char portStr[100];
+ char verbosityStr[100];
+
+ sprintf ( portStr, "%d", port);
+ sprintf ( verbosityStr, "%d", verbosity);
+
+ vector<const char*> argv;
+ argv.push_back ( "replayingSender" );
+ argv.push_back ( host );
+ argv.push_back ( portStr );
+ argv.push_back ( nMessages );
+ argv.push_back ( reportFrequency );
+ argv.push_back ( verbosityStr );
+ argv.push_back ( 0 );
+
+ pid_t pid = fork();
+
+ if ( ! pid ) {
+ execv ( senderPath, const_cast<char * const *>(&argv[0]) );
+ perror ( "error executing sender: " );
+ return 0;
+ }
+
+ allMyChildren.add ( name, pid );
+ return pid;
+}
+
+
+
+#define HUNKY_DORY 0
+#define BAD_ARGS 1
+#define CANT_FORK_DQ 2
+#define CANT_FORK_RECEIVER 3
+#define DQ_FAILED 4
+#define ERROR_ON_CHILD 5
+#define HANGING 6
+
+
+int
+main ( int argc, char const ** argv )
+{
+ if ( argc < 9 ) {
+ cerr << "Usage: failoverSoak srcRoot moduleDir host senderPath receiverPath nMessages verbosity\n";
+ cerr << " ( argc was " << argc << " )\n";
+ return BAD_ARGS;
+ }
+
+ signal ( SIGCHLD, childExit );
+
+ char const * srcRoot = argv[1];
+ char const * moduleDir = argv[2];
+ char const * host = argv[3];
+ char const * declareQueuesPath = argv[4];
+ char const * senderPath = argv[5];
+ char const * receiverPath = argv[6];
+ char const * nMessages = argv[7];
+ char const * reportFrequency = argv[8];
+ int verbosity = atoi(argv[9]);
+
+ int maxBrokers = 50;
+
+ allMyChildren.verbosity = verbosity;
+
+ int clusterNum;
+ string clusterName;
+
+ srand ( getpid() );
+
+ makeClusterName ( clusterName, clusterNum );
+
+ brokerVector brokers;
+
+ if ( verbosity > 0 )
+ cout << "Starting initial cluster...\n";
+
+ int nBrokers = 3;
+ for ( int i = 0; i < nBrokers; ++ i ) {
+ startNewBroker ( brokers,
+ srcRoot,
+ moduleDir,
+ clusterName );
+ }
+
+
+ if ( verbosity > 0 )
+ printBrokers ( brokers );
+
+ // Run the declareQueues child.
+ int childStatus;
+ pid_t dqClientPid =
+ runDeclareQueuesClient ( brokers, host, declareQueuesPath, verbosity );
+ if ( -1 == dqClientPid ) {
+ cerr << "failoverSoak error: Couldn't fork declareQueues.\n";
+ return CANT_FORK_DQ;
+ }
+
+ // Don't continue until declareQueues is finished.
+ pid_t retval = waitpid ( dqClientPid, & childStatus, 0);
+ if ( retval != dqClientPid) {
+ cerr << "failoverSoak error: waitpid on declareQueues returned value " << retval << endl;
+ return DQ_FAILED;
+ }
+ allMyChildren.exited ( dqClientPid, childStatus );
+
+
+
+ // Start the receiving client.
+ pid_t receivingClientPid =
+ startReceivingClient ( brokers,
+ host,
+ receiverPath,
+ reportFrequency,
+ verbosity );
+ if ( -1 == receivingClientPid ) {
+ cerr << "failoverSoak error: Couldn't fork receiver.\n";
+ return CANT_FORK_RECEIVER;
+ }
+
+
+ // Start the sending client.
+ pid_t sendingClientPid =
+ startSendingClient ( brokers,
+ host,
+ senderPath,
+ nMessages,
+ reportFrequency,
+ verbosity );
+ if ( -1 == sendingClientPid ) {
+ cerr << "failoverSoak error: Couldn't fork sender.\n";
+ return CANT_FORK_RECEIVER;
+ }
+
+
+ int minSleep = 3,
+ maxSleep = 6;
+
+
+ for ( int totalBrokers = 3;
+ totalBrokers < maxBrokers;
+ ++ totalBrokers
+ )
+ {
+ if ( verbosity > 0 )
+ cout << totalBrokers << " brokers have been added to the cluster.\n\n\n";
+
+ // Sleep for a while. -------------------------
+ int sleepyTime = mrand ( minSleep, maxSleep );
+ if ( verbosity > 0 )
+ cout << "Sleeping for " << sleepyTime << " seconds.\n";
+ sleep ( sleepyTime );
+
+ // Kill the oldest broker. --------------------------
+ killFrontBroker ( brokers, verbosity );
+
+ // Sleep for a while. -------------------------
+ sleepyTime = mrand ( minSleep, maxSleep );
+ if ( verbosity > 0 )
+ cerr << "Sleeping for " << sleepyTime << " seconds.\n";
+ sleep ( sleepyTime );
+
+ // Start a new broker. --------------------------
+ if ( verbosity > 0 )
+ cout << "Starting new broker.\n\n";
+
+ startNewBroker ( brokers,
+ srcRoot,
+ moduleDir,
+ clusterName );
+
+ if ( verbosity > 0 )
+ printBrokers ( brokers );
+
+ // If all children have exited, quit.
+ int unfinished = allMyChildren.unfinished();
+ if ( ! unfinished ) {
+ killAllBrokers ( brokers );
+
+ if ( verbosity > 0 )
+ cout << "failoverSoak: all children have exited.\n";
+ int retval = allMyChildren.checkChildren();
+ if ( verbosity > 0 )
+ std::cerr << "failoverSoak: checkChildren: " << retval << endl;
+ return retval ? ERROR_ON_CHILD : HUNKY_DORY;
+ }
+
+ // Even if some are still running, if there's an error, quit.
+ if ( allMyChildren.checkChildren() )
+ {
+ if ( verbosity > 0 )
+ cout << "failoverSoak: error on child.\n";
+ allMyChildren.killEverybody();
+ killAllBrokers ( brokers );
+ return ERROR_ON_CHILD;
+ }
+
+ // If one is hanging, quit.
+ if ( allMyChildren.hanging ( 120 ) )
+ {
+ if ( verbosity > 0 )
+ cout << "failoverSoak: child hanging.\n";
+ allMyChildren.killEverybody();
+ killAllBrokers ( brokers );
+ return HANGING;
+ }
+
+ if ( verbosity > 0 ) {
+ std::cerr << "------- next kill-broker loop --------\n";
+ allMyChildren.print();
+ }
+ }
+
+ retval = allMyChildren.checkChildren();
+ if ( verbosity > 0 )
+ std::cerr << "failoverSoak: checkChildren: " << retval << endl;
+
+ if ( verbosity > 0 )
+ cout << "failoverSoak: maxBrokers reached.\n";
+
+ allMyChildren.killEverybody();
+ killAllBrokers ( brokers );
+
+ return retval ? ERROR_ON_CHILD : HUNKY_DORY;
+}
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/fanout_perftest b/RC9/qpid/cpp/src/tests/fanout_perftest
new file mode 100755
index 0000000000..d8a7661f49
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/fanout_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+exec `dirname $0`/run_perftest 10000 --mode fanout --npubs 16 --nsubs 16 --size 64
diff --git a/RC9/qpid/cpp/src/tests/federated_topic_test b/RC9/qpid/cpp/src/tests/federated_topic_test
new file mode 100755
index 0000000000..21d8411eaf
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/federated_topic_test
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Run the topic test on a federated setup
+
+# Clean up old log files
+rm -f subscriber_*.log
+
+# Defaults values
+SUBSCRIBERS=2
+MESSAGES=1000
+BATCHES=1
+VERBOSE=1
+
+while getopts "s:m:b:" opt ; do
+ case $opt in
+ s) SUBSCRIBERS=$OPTARG ;;
+ m) MESSAGES=$OPTARG ;;
+ b) BATCHES=$OPTARG ;;
+ ?)
+ echo "Usage: %0 [-s <subscribers>] [-m <messages.] [-b <batches>]"
+ exit 1
+ ;;
+ esac
+done
+
+MY_DIR=$(dirname $(which $0))
+PYTHON_DIR=${MY_DIR}/../../../python
+
+trap stop_brokers EXIT
+
+start_broker() {
+ ${MY_DIR}/../qpidd --daemon --port 0 --no-module-dir --no-data-dir --auth no > qpidd.port
+}
+
+start_brokers() {
+ start_broker
+ PORT_A=`cat qpidd.port`
+ start_broker
+ PORT_B=`cat qpidd.port`
+ start_broker
+ PORT_C=`cat qpidd.port`
+}
+
+stop_brokers() {
+ for p in $PORT_A $PORT_B $PORT_C; do
+ ${MY_DIR}/../qpidd -q --port $p
+ done
+}
+
+subscribe() {
+ #which broker should we connect to?
+ if (( $1 % 2 )); then
+ MY_PORT=$PORT_C;
+ else
+ MY_PORT=$PORT_A;
+ fi
+
+ echo Subscriber $1 connecting on $MY_PORT
+ LOG="subscriber_$1.log"
+ ${MY_DIR}/topic_listener -p $MY_PORT > $LOG 2>&1 && rm -f $LOG
+}
+
+publish() {
+ ${MY_DIR}/topic_publisher --messages $MESSAGES --batches $BATCHES --subscribers $SUBSCRIBERS -p $PORT_A
+}
+
+setup_routes() {
+ BROKER_A="localhost:$PORT_A"
+ BROKER_B="localhost:$PORT_B"
+ BROKER_C="localhost:$PORT_C"
+ export PYTHONPATH=$PYTHON_DIR
+ if (($VERBOSE)); then
+ echo "Establishing routes for topic..."
+ fi
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_A amq.topic topic_control B B
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_C $BROKER_B amq.topic topic_control C C
+ if (($VERBOSE)); then
+ echo "linked A->B->C"
+ fi
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_C amq.topic topic_control B B
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_A $BROKER_B amq.topic topic_control A A
+ if (($VERBOSE)); then
+ echo "linked C->B->A"
+ echo "Establishing routes for response queue..."
+ fi
+
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_B $BROKER_C amq.direct response B B
+ $PYTHON_DIR/commands/qpid-route route add $BROKER_A $BROKER_B amq.direct response A A
+ if (($VERBOSE)); then
+ echo "linked C->B->A"
+ for b in $BROKER_A $BROKER_B $BROKER_C; do
+ echo "Routes for $b"
+ $PYTHON_DIR/commands/qpid-route route list $b
+ done
+ fi
+}
+
+if test -d ${PYTHON_DIR} ; then
+ start_brokers
+ if (($VERBOSE)); then
+ echo "Running federated topic test against brokers on ports $PORT_A $PORT_B $PORT_C"
+ fi
+
+ for ((i=$SUBSCRIBERS ; i--; )); do
+ subscribe $i &
+ done
+
+ setup_routes
+
+ publish || exit 1
+fi
diff --git a/RC9/qpid/cpp/src/tests/federation.py b/RC9/qpid/cpp/src/tests/federation.py
new file mode 100755
index 0000000000..ad82964007
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/federation.py
@@ -0,0 +1,505 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+import sys
+from qpid.testlib import TestBase010, testrunner
+from qpid.datatypes import Message
+from qpid.queue import Empty
+from time import sleep
+
+def add_module(args=sys.argv[1:]):
+ for a in args:
+ if a.startswith("federation"):
+ return False
+ return True
+
+def scan_args(name, default=None, args=sys.argv[1:]):
+ if (name in args):
+ pos = args.index(name)
+ return args[pos + 1]
+ elif default:
+ return default
+ else:
+ print "Please specify extra argument: %s" % name
+ sys.exit(2)
+
+def extract_args(name, args):
+ if (name in args):
+ pos = args.index(name)
+ del args[pos:pos+2]
+ else:
+ return None
+
+def remote_host():
+ return scan_args("--remote-host", "localhost")
+
+def remote_port():
+ return int(scan_args("--remote-port"))
+
+class FederationTests(TestBase010):
+
+ def test_bridge_create_and_close(self):
+ self.startQmf();
+ qmf = self.qmf
+
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.direct", "my-key", "", "", False, False, False)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_pull_from_exchange(self):
+ session = self.session
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "", "", False, False, False)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+
+ #setup queue to receive messages from local broker
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+ sleep(6)
+
+ #send messages to remote broker and confirm it is routed to local broker
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_pull_from_exchange")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="my-key")
+ r_session.message_transfer(destination="amq.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_push_to_exchange(self):
+ session = self.session
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "", "", False, True, False)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+
+ #setup queue to receive messages from remote broker
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_push_to_exchange")
+ r_session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ r_session.exchange_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(session=r_session, queue="fed1", destination="f1")
+ queue = r_session.incoming("f1")
+ sleep(6)
+
+ #send messages to local broker and confirm it is routed to remote broker
+ for i in range(1, 11):
+ dp = session.delivery_properties(routing_key="my-key")
+ session.message_transfer(destination="amq.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_pull_from_queue(self):
+ session = self.session
+
+ #setup queue on remote broker and add some messages
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_pull_from_queue")
+ r_session.queue_declare(queue="my-bridge-queue", auto_delete=True)
+ for i in range(1, 6):
+ dp = r_session.delivery_properties(routing_key="my-bridge-queue")
+ r_session.message_transfer(message=Message(dp, "Message %d" % i))
+
+ #setup queue to receive messages from local broker
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "my-bridge-queue", "amq.fanout", "my-key", "", "", True, False, False)
+ self.assertEqual(result.status, 0)
+
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(3)
+
+ #add some more messages (i.e. after bridge was created)
+ for i in range(6, 11):
+ dp = r_session.delivery_properties(routing_key="my-bridge-queue")
+ r_session.message_transfer(message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ try:
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ except Empty:
+ self.fail("Failed to find expected message containing 'Message %d'" % i)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_tracing_automatic(self):
+ remoteUrl = "%s:%d" % (remote_host(), remote_port())
+ self.startQmf()
+ l_broker = self.qmf_broker
+ r_broker = self.qmf.addBroker(remoteUrl)
+
+ l_brokerObj = self.qmf.getObjects(_class="broker", _broker=l_broker)[0]
+ r_brokerObj = self.qmf.getObjects(_class="broker", _broker=r_broker)[0]
+
+ l_res = l_brokerObj.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ r_res = r_brokerObj.connect(testrunner.host, testrunner.port, False, "PLAIN", "guest", "guest", "tcp")
+
+ self.assertEqual(l_res.status, 0)
+ self.assertEqual(r_res.status, 0)
+
+ l_link = self.qmf.getObjects(_class="link", _broker=l_broker)[0]
+ r_link = self.qmf.getObjects(_class="link", _broker=r_broker)[0]
+
+ l_res = l_link.bridge(False, "amq.direct", "amq.direct", "key", "", "", False, False, False)
+ r_res = r_link.bridge(False, "amq.direct", "amq.direct", "key", "", "", False, False, False)
+
+ self.assertEqual(l_res.status, 0)
+ self.assertEqual(r_res.status, 0)
+
+ count = 0
+ while l_link.state != "Operational" or r_link.state != "Operational":
+ count += 1
+ if count > 10:
+ self.fail("Fed links didn't become operational after 10 seconds")
+ sleep(1)
+ l_link = self.qmf.getObjects(_class="link", _broker=l_broker)[0]
+ r_link = self.qmf.getObjects(_class="link", _broker=r_broker)[0]
+ sleep(3)
+
+ #setup queue to receive messages from local broker
+ session = self.session
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="amq.direct", binding_key="key")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ #setup queue on remote broker and add some messages
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_trace")
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="key")
+ r_session.message_transfer(destination="amq.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ try:
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ except Empty:
+ self.fail("Failed to find expected message containing 'Message %d'" % i)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ def test_tracing(self):
+ session = self.session
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "my-bridge-id",
+ "exclude-me,also-exclude-me", False, False, False)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+
+ #setup queue to receive messages from local broker
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="amq.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+ sleep(6)
+
+ #send messages to remote broker and confirm it is routed to local broker
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_tracing")
+
+ trace = [None, "exclude-me", "a,exclude-me,b", "also-exclude-me,c", "dont-exclude-me"]
+ body = ["yes", "first-bad", "second-bad", "third-bad", "yes"]
+ for b, t in zip(body, trace):
+ headers = {}
+ if (t): headers["x-qpid.trace"]=t
+ dp = r_session.delivery_properties(routing_key="my-key")
+ mp = r_session.message_properties(application_headers=headers)
+ r_session.message_transfer(destination="amq.direct", message=Message(dp, mp, b))
+
+ for e in ["my-bridge-id", "dont-exclude-me,my-bridge-id"]:
+ msg = queue.get(timeout=5)
+ self.assertEqual("yes", msg.body)
+ self.assertEqual(e, self.getAppHeader(msg, "x-qpid.trace"))
+
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+ def test_dynamic_fanout(self):
+ session = self.session
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_dynamic_fanout")
+
+ session.exchange_declare(exchange="fed.fanout", type="fanout")
+ r_session.exchange_declare(exchange="fed.fanout", type="fanout")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.fanout", "fed.fanout", "", "", "", False, False, True)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.fanout")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties()
+ r_session.message_transfer(destination="fed.fanout", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+
+ def test_dynamic_direct(self):
+ session = self.session
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_dynamic_direct")
+
+ session.exchange_declare(exchange="fed.direct", type="direct")
+ r_session.exchange_declare(exchange="fed.direct", type="direct")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.direct", "fed.direct", "", "", "", False, False, True)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.direct", binding_key="fd-key")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="fd-key")
+ r_session.message_transfer(destination="fed.direct", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+
+ def test_dynamic_topic(self):
+ session = self.session
+ r_conn = self.connect(host=remote_host(), port=remote_port())
+ r_session = r_conn.session("test_dynamic_topic")
+
+ session.exchange_declare(exchange="fed.topic", type="topic")
+ r_session.exchange_declare(exchange="fed.topic", type="topic")
+
+ self.startQmf()
+ qmf = self.qmf
+ broker = qmf.getObjects(_class="broker")[0]
+ result = broker.connect(remote_host(), remote_port(), False, "PLAIN", "guest", "guest", "tcp")
+ self.assertEqual(result.status, 0)
+
+ link = qmf.getObjects(_class="link")[0]
+ result = link.bridge(False, "fed.topic", "fed.topic", "", "", "", False, False, True)
+ self.assertEqual(result.status, 0)
+ bridge = qmf.getObjects(_class="bridge")[0]
+ sleep(5)
+
+ session.queue_declare(queue="fed1", exclusive=True, auto_delete=True)
+ session.exchange_bind(queue="fed1", exchange="fed.topic", binding_key="ft-key.#")
+ self.subscribe(queue="fed1", destination="f1")
+ queue = session.incoming("f1")
+
+ for i in range(1, 11):
+ dp = r_session.delivery_properties(routing_key="ft-key.one.two")
+ r_session.message_transfer(destination="fed.topic", message=Message(dp, "Message %d" % i))
+
+ for i in range(1, 11):
+ msg = queue.get(timeout=5)
+ self.assertEqual("Message %d" % i, msg.body)
+ try:
+ extra = queue.get(timeout=1)
+ self.fail("Got unexpected message in queue: " + extra.body)
+ except Empty: None
+
+ result = bridge.close()
+ self.assertEqual(result.status, 0)
+ result = link.close()
+ self.assertEqual(result.status, 0)
+
+ sleep(3)
+ self.assertEqual(len(qmf.getObjects(_class="bridge")), 0)
+ self.assertEqual(len(qmf.getObjects(_class="link")), 0)
+
+
+ def getProperty(self, msg, name):
+ for h in msg.headers:
+ if hasattr(h, name): return getattr(h, name)
+ return None
+
+ def getAppHeader(self, msg, name):
+ headers = self.getProperty(msg, "application_headers")
+ if headers:
+ return headers[name]
+ return None
+
+
+if __name__ == '__main__':
+ args = sys.argv[1:]
+ #need to remove the extra options from args as test runner doesn't recognise them
+ extract_args("--remote-port", args)
+ extract_args("--remote-host", args)
+
+ if add_module():
+ #add module(s) to run to testrunners args
+ args.append("federation")
+
+ if not testrunner.run(args): sys.exit(1)
diff --git a/RC9/qpid/cpp/src/tests/header_test.cpp b/RC9/qpid/cpp/src/tests/header_test.cpp
new file mode 100644
index 0000000000..ba9ffacc9b
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/header_test.cpp
@@ -0,0 +1,59 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <iostream>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ TestOptions opts;
+ try {
+ opts.parse(argc, argv);
+ Connection connection;
+ connection.open(opts.con);
+ Session session = connection.newSession();
+ std::string q("header_interop_test_queue");
+ session.queueDeclare(arg::queue=q);
+ double pi = 3.14159265;
+ float e = 2.71828;
+ Message msg("", q);
+ msg.getMessageProperties().getApplicationHeaders().setDouble("pi", pi);
+ msg.getMessageProperties().getApplicationHeaders().setFloat("e", e);
+ session.messageTransfer(arg::content=msg);
+
+ session.close();
+ connection.close();
+
+ return 0;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/header_test.py b/RC9/qpid/cpp/src/tests/header_test.py
new file mode 100755
index 0000000000..d5a2c16c01
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/header_test.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+import qpid
+import sys
+import os
+from qpid.util import connect
+from qpid.connection import Connection
+from qpid.datatypes import Message, RangedSet, uuid4
+from qpid.queue import Empty
+from math import fabs
+
+def getApplicationHeaders(msg):
+ for h in msg.headers:
+ if hasattr(h, 'application_headers'): return getattr(h, 'application_headers')
+ return None
+
+# Set parameters for login
+
+host="127.0.0.1"
+port=5672
+user="guest"
+password="guest"
+
+if len(sys.argv) > 1 :
+ host=sys.argv[1]
+if len(sys.argv) > 2 :
+ port=int(sys.argv[2])
+
+# Create a connection.
+socket = connect(host, port)
+connection = Connection (sock=socket)
+connection.start()
+session = connection.session(str(uuid4()))
+
+q = "header_interop_test_queue"
+session.queue_declare(queue=q)
+
+session.message_subscribe(queue=q, destination="received")
+queue = session.incoming("received")
+queue.start()
+
+msg = queue.get(timeout=10)
+pi = 3.14159265
+e = 2.71828
+
+headers = getApplicationHeaders(msg)
+pi_ = headers["pi"]
+e_ = headers["e"]
+session.close(timeout=10)
+
+failed = False
+
+if pi != pi_:
+ print "got incorrect value for pi: ", pi_, " expected:", pi
+ failed = True
+
+if fabs(e - e_) > 0.0001:
+ print "got incorrect value for e: ", e_, " expected:", e
+ failed = True
+
+if failed:
+ sys.exit(1)
+else:
+ print "Correct header values received."
+ sys.exit(0)
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/interop_runner.cpp b/RC9/qpid/cpp/src/tests/interop_runner.cpp
new file mode 100644
index 0000000000..8c6e0a6991
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/interop_runner.cpp
@@ -0,0 +1,251 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/Options.h"
+#include "qpid/ptr_map.h"
+#include "qpid/Exception.h"
+#include "qpid/client/Channel.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/ConnectionOptions.h"
+#include "qpid/client/Exchange.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Queue.h"
+#include "qpid/sys/Thread.h"
+#include "qpid/sys/Time.h"
+#include <iostream>
+#include <memory>
+#include "BasicP2PTest.h"
+#include "BasicPubSubTest.h"
+#include "TestCase.h"
+#include <boost/ptr_container/ptr_map.hpp>
+
+/**
+ * Framework for interop tests.
+ *
+ * [see http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification for details].
+ */
+
+using namespace qpid::client;
+using namespace qpid::sys;
+using qpid::TestCase;
+using qpid::framing::FieldTable;
+using qpid::framing::ReplyTo;
+using namespace std;
+
+class DummyRun : public TestCase
+{
+public:
+ DummyRun() {}
+ void assign(const string&, FieldTable&, ConnectionOptions&) {}
+ void start() {}
+ void stop() {}
+ void report(qpid::client::Message&) {}
+};
+
+string parse_next_word(const string& input, const string& delims, string::size_type& position);
+
+/**
+ */
+class Listener : public MessageListener, private Runnable{
+ typedef boost::ptr_map<string, TestCase> TestMap;
+
+ Channel& channel;
+ ConnectionOptions& options;
+ TestMap tests;
+ const string name;
+ const string topic;
+ TestCase* test;
+ auto_ptr<Thread> runner;
+ ReplyTo reportTo;
+ string reportCorrelator;
+
+ void shutdown();
+ bool invite(const string& name);
+ void run();
+
+ void sendResponse(Message& response, ReplyTo replyTo);
+ void sendResponse(Message& response, Message& request);
+ void sendSimpleResponse(const string& type, Message& request);
+ void sendReport();
+public:
+ Listener(Channel& channel, ConnectionOptions& options);
+ void received(Message& msg);
+ void bindAndConsume();
+ void registerTest(string name, TestCase* test);
+};
+
+struct TestSettings : ConnectionOptions
+{
+ bool help;
+
+ TestSettings() : help(false)
+ {
+ addOptions()
+ ("help", qpid::optValue(help), "print this usage statement");
+ }
+};
+
+int main(int argc, char** argv) {
+ try {
+ TestSettings options;
+ options.parse(argc, argv);
+ if (options.help) {
+ cout << options;
+ } else {
+ Connection connection;
+ connection.open(options.host, options.port, "guest", "guest", options.virtualhost);
+
+ Channel channel;
+ connection.openChannel(channel);
+
+ Listener listener(channel, options);
+ listener.registerTest("TC1_DummyRun", new DummyRun());
+ listener.registerTest("TC2_BasicP2P", new qpid::BasicP2PTest());
+ listener.registerTest("TC3_BasicPubSub", new qpid::BasicPubSubTest());
+
+ listener.bindAndConsume();
+
+ channel.run();
+ connection.close();
+ }
+ } catch(const exception& error) {
+ cout << error.what() << endl << "Type " << argv[0] << " --help for help" << endl;
+ }
+}
+
+Listener::Listener(Channel& _channel, ConnectionOptions& _options) : channel(_channel), options(_options), name(options.clientid), topic("iop.control." + name)
+{}
+
+void Listener::registerTest(string name, TestCase* test)
+{
+ tests.insert(name, test);
+}
+
+void Listener::bindAndConsume()
+{
+ Queue control(name, true);
+ channel.declareQueue(control);
+ qpid::framing::FieldTable bindArgs;
+ //replace these separate binds with a wildcard once that is supported on java broker
+ channel.bind(Exchange::STANDARD_TOPIC_EXCHANGE, control, "iop.control", bindArgs);
+ channel.bind(Exchange::STANDARD_TOPIC_EXCHANGE, control, topic, bindArgs);
+
+ string tag;
+ channel.consume(control, tag, this);
+}
+
+void Listener::sendSimpleResponse(const string& type, Message& request)
+{
+ Message response;
+ response.getHeaders().setString("CONTROL_TYPE", type);
+ response.getHeaders().setString("CLIENT_NAME", name);
+ response.getHeaders().setString("CLIENT_PRIVATE_CONTROL_KEY", topic);
+ response.getMessageProperties().setCorrelationId(request.getMessageProperties().getCorrelationId());
+ sendResponse(response, request);
+}
+
+void Listener::sendResponse(Message& response, Message& request)
+{
+ sendResponse(response, request.getMessageProperties().getReplyTo());
+}
+
+void Listener::sendResponse(Message& response, ReplyTo replyTo)
+{
+ string exchange = replyTo.getExchange();
+ string routingKey = replyTo.getRoutingKey();
+ channel.publish(response, exchange, routingKey);
+}
+
+void Listener::received(Message& message)
+{
+ string type(message.getHeaders().getString("CONTROL_TYPE"));
+
+ if (type == "INVITE") {
+ string name(message.getHeaders().getString("TEST_NAME"));
+ if (name.empty() || invite(name)) {
+ sendSimpleResponse("ENLIST", message);
+ } else {
+ cout << "Can't take part in '" << name << "'" << endl;
+ }
+ } else if (type == "ASSIGN_ROLE") {
+ test->assign(message.getHeaders().getString("ROLE"), message.getHeaders(), options);
+ sendSimpleResponse("ACCEPT_ROLE", message);
+ } else if (type == "START") {
+ reportTo = message.getMessageProperties().getReplyTo();
+ reportCorrelator = message.getMessageProperties().getCorrelationId();
+ runner = auto_ptr<Thread>(new Thread(this));
+ } else if (type == "STATUS_REQUEST") {
+ reportTo = message.getMessageProperties().getReplyTo();
+ reportCorrelator = message.getMessageProperties().getCorrelationId();
+ test->stop();
+ sendReport();
+ } else if (type == "TERMINATE") {
+ if (test) test->stop();
+ shutdown();
+ } else {
+ cerr <<"ERROR!: Received unknown control message: " << type << endl;
+ shutdown();
+ }
+}
+
+void Listener::shutdown()
+{
+ channel.close();
+}
+
+bool Listener::invite(const string& name)
+{
+ TestMap::iterator i = tests.find(name);
+ test = (i != tests.end()) ? qpid::ptr_map_ptr(i) : 0;
+ return test;
+}
+
+void Listener::run()
+{
+ //NB: this method will be called in its own thread
+ //start test and when start returns...
+ test->start();
+ sendReport();
+}
+
+void Listener::sendReport()
+{
+ Message report;
+ report.getHeaders().setString("CONTROL_TYPE", "REPORT");
+ test->report(report);
+ report.getMessageProperties().setCorrelationId(reportCorrelator);
+ sendResponse(report, reportTo);
+}
+
+string parse_next_word(const string& input, const string& delims, string::size_type& position)
+{
+ string::size_type start = input.find_first_not_of(delims, position);
+ if (start == string::npos) {
+ return "";
+ } else {
+ string::size_type end = input.find_first_of(delims, start);
+ if (end == string::npos) {
+ end = input.length();
+ }
+ position = end;
+ return input.substr(start, end - start);
+ }
+}
diff --git a/RC9/qpid/cpp/src/tests/latencytest.cpp b/RC9/qpid/cpp/src/tests/latencytest.cpp
new file mode 100644
index 0000000000..6895964133
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/latencytest.cpp
@@ -0,0 +1,432 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+#include <algorithm>
+#include <limits>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Time.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using std::string;
+
+typedef std::vector<std::string> StringSet;
+
+struct Args : public qpid::TestOptions {
+ uint size;
+ uint count;
+ uint rate;
+ bool sync;
+ uint reportFrequency;
+ uint timeLimit;
+ uint queues;
+ uint prefetch;
+ uint ack;
+ bool cumulative;
+ bool csv;
+ bool durable;
+ string base;
+
+ Args() : size(256), count(1000), rate(0), reportFrequency(1000),
+ timeLimit(0), queues(1),
+ prefetch(100), ack(0),
+ durable(false), base("latency-test")
+ {
+ addOptions()
+
+ ("size", optValue(size, "N"), "message size")
+ ("queues", optValue(queues, "N"), "number of queues")
+ ("count", optValue(count, "N"), "number of messages to send")
+ ("rate", optValue(rate, "N"), "target message rate (causes count to be ignored)")
+ ("sync", optValue(sync), "send messages synchronously")
+ ("report-frequency", optValue(reportFrequency, "N"),
+ "number of milliseconds to wait between reports (ignored unless rate specified)")
+ ("time-limit", optValue(timeLimit, "N"),
+ "test duration, in seconds")
+ ("prefetch", optValue(prefetch, "N"), "prefetch count (0 implies no flow control, and no acking)")
+ ("ack", optValue(ack, "N"), "Ack frequency in messages (defaults to half the prefetch value)")
+ ("durable", optValue(durable, "yes|no"), "use durable messages")
+ ("csv", optValue(csv), "print stats in csv format (rate,min,max,avg)")
+ ("cumulative", optValue(cumulative), "cumulative stats in csv format")
+ ("queue-base-name", optValue(base, "<name>"), "base name for queues");
+ }
+};
+
+const std::string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+Args opts;
+double c_min, c_avg, c_max;
+
+uint64_t current_time()
+{
+ Duration t(now());
+ return t;
+}
+
+struct Stats
+{
+ Mutex lock;
+ uint count;
+ double minLatency;
+ double maxLatency;
+ double totalLatency;
+
+ Stats();
+ void update(double l);
+ void print();
+ void reset();
+};
+
+class Client : public Runnable
+{
+protected:
+ Connection connection;
+ AsyncSession session;
+ Thread thread;
+ string queue;
+
+public:
+ Client(const string& q);
+ virtual ~Client() {}
+
+ void start();
+ void join();
+ void run();
+ virtual void test() = 0;
+};
+
+class Receiver : public Client, public MessageListener
+{
+ SubscriptionManager mgr;
+ uint count;
+ Stats& stats;
+
+public:
+ Receiver(const string& queue, Stats& stats);
+ void test();
+ void received(Message& msg);
+ Stats getStats();
+ uint getCount() { return count; }
+ void stop() { mgr.stop(); mgr.cancel(queue); }
+};
+
+
+class Sender : public Client
+{
+ string generateData(uint size);
+ void sendByRate();
+ void sendByCount();
+ Receiver& receiver;
+ const string data;
+public:
+ Sender(const string& queue, Receiver& receiver);
+ void test();
+};
+
+
+class Test
+{
+ const string queue;
+ Stats stats;
+ Receiver receiver;
+ Sender sender;
+ AbsTime begin;
+
+public:
+ Test(const string& q) : queue(q), receiver(queue, stats), sender(queue, receiver), begin(now()) {}
+ void start();
+ void join();
+ void report();
+};
+
+
+Client::Client(const string& q) : queue(q)
+{
+ opts.open(connection);
+ session = connection.newSession();
+}
+
+void Client::start()
+{
+ thread = Thread(this);
+}
+
+void Client::join()
+{
+ thread.join();
+}
+
+void Client::run()
+{
+ try{
+ test();
+ session.close();
+ connection.close();
+ } catch(const std::exception& e) {
+ std::cout << "Error in receiver: " << e.what() << std::endl;
+ }
+}
+
+Receiver::Receiver(const string& q, Stats& s) : Client(q), mgr(session), count(0), stats(s)
+{
+ session.queueDeclare(arg::queue=queue, arg::durable=opts.durable, arg::autoDelete=true);
+ uint msgCount = session.queueQuery(arg::queue=queue).get().getMessageCount();
+ if (msgCount) {
+ std::cout << "Warning: found " << msgCount << " msgs on " << queue << ". Purging..." << std::endl;
+ session.queuePurge(arg::queue=queue);
+ }
+ SubscriptionSettings settings;
+ if (opts.prefetch) {
+ settings.autoAck = (opts.ack ? opts.ack : (opts.prefetch / 2));
+ settings.flowControl = FlowControl::messageWindow(opts.prefetch);
+ } else {
+ settings.acceptMode = ACCEPT_MODE_NONE;
+ settings.flowControl = FlowControl::unlimited();
+ }
+ mgr.subscribe(*this, queue, settings);
+}
+
+void Receiver::test()
+{
+ mgr.run();
+ mgr.cancel(queue);
+}
+
+void Receiver::received(Message& msg)
+{
+ ++count;
+ uint64_t sentAt = msg.getDeliveryProperties().getTimestamp();
+ //uint64_t sentAt = msg.getHeaders().getTimestamp("sent-at");// TODO: add support for uint64_t as a field table type
+ uint64_t receivedAt = current_time();
+
+ //std::cerr << "Latency: " << (receivedAt - sentAt) << std::endl;
+ stats.update(((double) (receivedAt - sentAt)) / TIME_MSEC);
+
+ if (!opts.rate && count >= opts.count) {
+ mgr.stop();
+ }
+}
+
+void Stats::update(double latency)
+{
+ Mutex::ScopedLock l(lock);
+ count++;
+ minLatency = std::min(minLatency, latency);
+ maxLatency = std::max(maxLatency, latency);
+ totalLatency += latency;
+}
+
+Stats::Stats() : count(0), minLatency(std::numeric_limits<double>::max()), maxLatency(0), totalLatency(0) {}
+
+void Stats::print()
+{
+ static bool already_have_stats = false;
+ uint value;
+
+ if (opts.rate)
+ value = opts.rate;
+ else
+ value = opts.count;
+ Mutex::ScopedLock l(lock);
+ double aux_avg = (totalLatency / count);
+ if (!opts.cumulative) {
+ if (!opts.csv) {
+ std::cout << "Latency(ms): min=" << minLatency << ", max=" <<
+ maxLatency << ", avg=" << aux_avg;
+ } else {
+ std::cout << value << "," << minLatency << "," << maxLatency <<
+ "," << aux_avg;
+ }
+ } else {
+ if (already_have_stats) {
+ c_avg = (c_min + aux_avg) / 2;
+ if (c_min > minLatency) c_min = minLatency;
+ if (c_max < maxLatency) c_max = maxLatency;
+ } else {
+ c_avg = aux_avg;
+ c_min = minLatency;
+ c_max = maxLatency;
+ already_have_stats = true;
+ }
+ std::cout << value << "," << c_min << "," << c_max <<
+ "," << c_avg;
+ }
+
+}
+
+void Stats::reset()
+{
+ Mutex::ScopedLock l(lock);
+ count = 0;
+ totalLatency = maxLatency = 0;
+ minLatency = std::numeric_limits<double>::max();
+}
+
+Sender::Sender(const string& q, Receiver& receiver) : Client(q), receiver(receiver), data(generateData(opts.size)) {}
+
+void Sender::test()
+{
+ if (opts.rate) sendByRate();
+ else sendByCount();
+}
+
+void Sender::sendByCount()
+{
+ Message msg(data, queue);
+ if (opts.durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+
+ for (uint i = 0; i < opts.count; i++) {
+ uint64_t sentAt(current_time());
+ msg.getDeliveryProperties().setTimestamp(sentAt);
+ async(session).messageTransfer(arg::content=msg, arg::acceptMode=1);
+ if (opts.sync) session.sync();
+ }
+ session.sync();
+}
+
+void Sender::sendByRate()
+{
+ Message msg(data, queue);
+ if (opts.durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+
+ //calculate interval (in micro secs) between messages to achieve desired rate
+ uint64_t interval = (1000*1000)/opts.rate;
+ uint64_t timeLimit(opts.timeLimit * TIME_SEC);
+ uint64_t start(current_time());
+
+ while (true) {
+ uint64_t start_msg(current_time());
+ msg.getDeliveryProperties().setTimestamp(start_msg);
+ async(session).messageTransfer(arg::content=msg, arg::acceptMode=1);
+ if (opts.sync) session.sync();
+
+ uint64_t now = current_time();
+
+ if (timeLimit != 0 && (now - start) > timeLimit) {
+ session.sync();
+ receiver.stop();
+ break;
+ }
+
+ uint64_t timeTaken = (now - start_msg) / TIME_USEC;
+ if (timeTaken < interval) {
+ qpid::sys::usleep(interval - timeTaken);
+ } else if (timeTaken > interval &&
+ !opts.csv && !opts.cumulative) { // Don't be so verbose in this case, we're piping the results to another program
+ std::cout << "Could not achieve desired rate! (Took " << timeTaken
+ << " microsecs to send message, aiming for " << interval << " microsecs)" << std::endl;
+ }
+ }
+}
+
+string Sender::generateData(uint size)
+{
+ if (size < chars.length()) {
+ return chars.substr(0, size);
+ }
+ std::string data;
+ for (uint i = 0; i < (size / chars.length()); i++) {
+ data += chars;
+ }
+ data += chars.substr(0, size % chars.length());
+ return data;
+}
+
+
+void Test::start()
+{
+ receiver.start();
+ begin = AbsTime(now());
+ sender.start();
+}
+
+void Test::join()
+{
+ sender.join();
+ receiver.join();
+ AbsTime end = now();
+ Duration time(begin, end);
+ double msecs(time / TIME_MSEC);
+ if (!opts.csv) {
+ std::cout << "Sent " << receiver.getCount() << " msgs through " << queue
+ << " in " << msecs << "ms (" << (receiver.getCount() * 1000 / msecs) << " msgs/s) ";
+ }
+ stats.print();
+ std::cout << std::endl;
+}
+
+void Test::report()
+{
+ stats.print();
+ std::cout << std::endl;
+ stats.reset();
+}
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ if (opts.cumulative)
+ opts.csv = true;
+ boost::ptr_vector<Test> tests(opts.queues);
+ for (uint i = 0; i < opts.queues; i++) {
+ std::ostringstream out;
+ out << opts.base << "-" << (i+1);
+ tests.push_back(new Test(out.str()));
+ }
+ for (boost::ptr_vector<Test>::iterator i = tests.begin(); i != tests.end(); i++) {
+ i->start();
+ }
+ if (opts.rate && !opts.timeLimit) {
+ while (true) {
+ qpid::sys::usleep(opts.reportFrequency * 1000);
+ //print latency report:
+ for (boost::ptr_vector<Test>::iterator i = tests.begin(); i != tests.end(); i++) {
+ i->report();
+ }
+ }
+ } else {
+ for (boost::ptr_vector<Test>::iterator i = tests.begin(); i != tests.end(); i++) {
+ i->join();
+ }
+ }
+
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/logging.cpp b/RC9/qpid/cpp/src/tests/logging.cpp
new file mode 100644
index 0000000000..051722e7c8
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/logging.cpp
@@ -0,0 +1,366 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test_tools.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Options.h"
+#include "qpid/log/OstreamOutput.h"
+#include "qpid/memory.h"
+#include "qpid/Options.h"
+#if defined (_WIN32)
+#else
+# include "qpid/log/posix/SinkOptions.h"
+#endif
+
+#include <boost/test/floating_point_comparison.hpp>
+#include <boost/format.hpp>
+#include "unit_test.h"
+
+#include <exception>
+#include <fstream>
+#include <time.h>
+
+
+QPID_AUTO_TEST_SUITE(loggingTestSuite)
+
+using namespace std;
+using namespace boost;
+using namespace qpid::log;
+
+QPID_AUTO_TEST_CASE(testStatementInit) {
+ Statement s=QPID_LOG_STATEMENT_INIT(debug); int line=__LINE__;
+ BOOST_CHECK(!s.enabled);
+ BOOST_CHECK_EQUAL(string(__FILE__), s.file);
+ BOOST_CHECK_EQUAL(line, s.line);
+ BOOST_CHECK_EQUAL(debug, s.level);
+}
+
+
+QPID_AUTO_TEST_CASE(testSelector_enable) {
+ Selector s;
+ // Simple enable
+ s.enable(debug,"foo");
+ BOOST_CHECK(s.isEnabled(debug,"foo"));
+ BOOST_CHECK(!s.isEnabled(error,"foo"));
+ BOOST_CHECK(!s.isEnabled(error,"bar"));
+
+ // Substring match
+ BOOST_CHECK(s.isEnabled(debug, "bazfoobar"));
+ BOOST_CHECK(!s.isEnabled(debug, "bazbar"));
+
+ // Different levels for different substrings.
+ s.enable(info, "bar");
+ BOOST_CHECK(s.isEnabled(debug, "foobar"));
+ BOOST_CHECK(s.isEnabled(info, "foobar"));
+ BOOST_CHECK(!s.isEnabled(debug, "bar"));
+ BOOST_CHECK(!s.isEnabled(info, "foo"));
+
+ // Enable-strings
+ s.enable("notice:blob");
+ BOOST_CHECK(s.isEnabled(notice, "blob"));
+ s.enable("error+:oops");
+ BOOST_CHECK(s.isEnabled(error, "oops"));
+ BOOST_CHECK(s.isEnabled(critical, "oops"));
+}
+
+QPID_AUTO_TEST_CASE(testStatementEnabled) {
+ // Verify that the singleton enables and disables static
+ // log statements.
+ Logger& l = Logger::instance();
+ ScopedSuppressLogging ls(l);
+ l.select(Selector(debug));
+ static Statement s=QPID_LOG_STATEMENT_INIT(debug);
+ BOOST_CHECK(!s.enabled);
+ static Statement::Initializer init(s);
+ BOOST_CHECK(s.enabled);
+
+ static Statement s2=QPID_LOG_STATEMENT_INIT(warning);
+ static Statement::Initializer init2(s2);
+ BOOST_CHECK(!s2.enabled);
+
+ l.select(Selector(warning));
+ BOOST_CHECK(!s.enabled);
+ BOOST_CHECK(s2.enabled);
+}
+
+struct TestOutput : public Logger::Output {
+ vector<string> msg;
+ vector<Statement> stmt;
+
+ TestOutput(Logger& l) {
+ l.output(std::auto_ptr<Logger::Output>(this));
+ }
+
+ void log(const Statement& s, const string& m) {
+ msg.push_back(m);
+ stmt.push_back(s);
+ }
+ string last() { return msg.back(); }
+};
+
+using boost::assign::list_of;
+
+QPID_AUTO_TEST_CASE(testLoggerOutput) {
+ Logger l;
+ l.clear();
+ l.select(Selector(debug));
+ Statement s=QPID_LOG_STATEMENT_INIT(debug);
+
+ TestOutput* out=new TestOutput(l);
+
+ // Verify message is output.
+ l.log(s, "foo");
+ vector<string> expect=list_of("foo\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+
+ // Verify multiple outputs
+ TestOutput* out2=new TestOutput(l);
+ l.log(Statement(), "baz");
+ expect.push_back("baz\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+ expect.erase(expect.begin());
+ BOOST_CHECK_EQUAL(expect, out2->msg);
+}
+
+QPID_AUTO_TEST_CASE(testMacro) {
+ Logger& l=Logger::instance();
+ ScopedSuppressLogging ls(l);
+ l.select(Selector(info));
+ TestOutput* out=new TestOutput(l);
+ QPID_LOG(info, "foo");
+ vector<string> expect=list_of("foo\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+ BOOST_CHECK_EQUAL(__FILE__, out->stmt.front().file);
+
+ // Not enabled:
+ QPID_LOG(debug, "bar");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+
+ QPID_LOG(info, 42 << " bingo");
+ expect.push_back("42 bingo\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+}
+
+QPID_AUTO_TEST_CASE(testLoggerFormat) {
+ Logger& l = Logger::instance();
+ ScopedSuppressLogging ls(l);
+ l.select(Selector(critical));
+ TestOutput* out=new TestOutput(l);
+
+ l.format(Logger::FILE);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_EQUAL(out->last(), string(__FILE__)+": foo\n");
+
+ l.format(Logger::FILE|Logger::LINE);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_REGEX(string(__FILE__)+":\\d+: foo\n", out->last());
+
+ l.format(Logger::FUNCTION);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_REGEX("void .*testLoggerFormat.*\\(\\): foo\n", out->last());
+
+ l.format(Logger::LEVEL);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_EQUAL("critical foo\n", out->last());
+}
+
+QPID_AUTO_TEST_CASE(testOstreamOutput) {
+ Logger& l=Logger::instance();
+ ScopedSuppressLogging ls(l);
+ l.select(Selector(error));
+ ostringstream os;
+ l.output(qpid::make_auto_ptr<Logger::Output>(new OstreamOutput(os)));
+ QPID_LOG(error, "foo");
+ QPID_LOG(error, "bar");
+ QPID_LOG(error, "baz");
+ BOOST_CHECK_EQUAL("foo\nbar\nbaz\n", os.str());
+}
+
+#if 0 // This test requires manual intervention. Normally disabled.
+QPID_AUTO_TEST_CASE(testSyslogOutput) {
+ Logger& l=Logger::instance();
+ Logger::StateSaver ls(l);
+ l.clear();
+ l.select(Selector(info));
+ l.syslog("qpid_test");
+ QPID_LOG(info, "Testing QPID");
+ BOOST_ERROR("Manually verify that /var/log/messages contains a recent line 'Testing QPID'");
+}
+#endif // 0
+
+int count() {
+ static int n = 0;
+ return n++;
+}
+
+int loggedCount() {
+ static int n = 0;
+ QPID_LOG(debug, "counting: " << n);
+ return n++;
+}
+
+
+using namespace qpid::sys;
+
+// Measure CPU time.
+clock_t timeLoop(int times, int (*fp)()) {
+ clock_t start=clock();
+ while (times-- > 0)
+ (*fp)();
+ return clock() - start;
+}
+
+// Overhead test disabled because it consumes a ton of CPU and takes
+// forever under valgrind. Not friendly for regular test runs.
+//
+#if 0
+QPID_AUTO_TEST_CASE(testOverhead) {
+ // Ensure that the ratio of CPU time for an incrementing loop
+ // with and without disabled log statements is in acceptable limits.
+ //
+ int times=100000000;
+ clock_t noLog=timeLoop(times, count);
+ clock_t withLog=timeLoop(times, loggedCount);
+ double ratio=double(withLog)/double(noLog);
+
+ // NB: in initial tests the ratio was consistently below 1.5,
+ // 2.5 is reasonable and should avoid spurios failures
+ // due to machine load.
+ //
+ BOOST_CHECK_SMALL(ratio, 2.5);
+}
+#endif // 0
+
+Statement statement(
+ Level level, const char* file="", int line=0, const char* fn=0)
+{
+ Statement s={0, file, line, fn, level};
+ return s;
+}
+
+
+#define ARGC(argv) (sizeof(argv)/sizeof(char*))
+
+QPID_AUTO_TEST_CASE(testOptionsParse) {
+ const char* argv[]={
+ 0,
+ "--log-enable", "error+:foo",
+ "--log-enable", "debug:bar",
+ "--log-enable", "info",
+ "--log-to-stderr", "no",
+ "--log-to-file", "logout",
+ "--log-level", "yes",
+ "--log-source", "1",
+ "--log-thread", "true",
+ "--log-function", "YES"
+ };
+ qpid::log::Options opts("");
+ qpid::log::posix::SinkOptions sinks("test");
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ sinks = *opts.sinkOptions;
+ vector<string> expect=list_of("error+:foo")("debug:bar")("info");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ BOOST_CHECK(!sinks.logToStderr);
+ BOOST_CHECK(!sinks.logToStdout);
+ BOOST_CHECK(sinks.logFile == "logout");
+ BOOST_CHECK(opts.level);
+ BOOST_CHECK(opts.source);
+ BOOST_CHECK(opts.function);
+ BOOST_CHECK(opts.thread);
+}
+
+QPID_AUTO_TEST_CASE(testOptionsDefault) {
+ Options opts("");
+ qpid::log::posix::SinkOptions sinks("test");
+ sinks = *opts.sinkOptions;
+ BOOST_CHECK(sinks.logToStderr);
+ BOOST_CHECK(!sinks.logToStdout);
+ BOOST_CHECK(sinks.logFile.length() == 0);
+ vector<string> expect=list_of("notice+");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ BOOST_CHECK(opts.time && opts.level);
+ BOOST_CHECK(!(opts.source || opts.function || opts.thread));
+}
+
+QPID_AUTO_TEST_CASE(testSelectorFromOptions) {
+ const char* argv[]={
+ 0,
+ "--log-enable", "error+:foo",
+ "--log-enable", "debug:bar",
+ "--log-enable", "info"
+ };
+ qpid::log::Options opts("");
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ vector<string> expect=list_of("error+:foo")("debug:bar")("info");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ Selector s(opts);
+ BOOST_CHECK(!s.isEnabled(warning, "x"));
+ BOOST_CHECK(!s.isEnabled(debug, "x"));
+ BOOST_CHECK(s.isEnabled(debug, "bar"));
+ BOOST_CHECK(s.isEnabled(error, "foo"));
+ BOOST_CHECK(s.isEnabled(critical, "foo"));
+}
+
+QPID_AUTO_TEST_CASE(testLoggerStateure) {
+ Logger& l=Logger::instance();
+ ScopedSuppressLogging ls(l);
+ Options opts("test");
+ const char* argv[]={
+ 0,
+ "--log-time", "no",
+ "--log-source", "yes",
+ "--log-to-stderr", "no",
+ "--log-to-file", "logging.tmp",
+ "--log-enable", "critical"
+ };
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ l.configure(opts);
+ QPID_LOG(critical, "foo"); int srcline=__LINE__;
+ ifstream log("logging.tmp");
+ string line;
+ getline(log, line);
+ string expect=(format("critical %s:%d: foo")%__FILE__%srcline).str();
+ BOOST_CHECK_EQUAL(expect, line);
+ log.close();
+ unlink("logging.tmp");
+}
+
+QPID_AUTO_TEST_CASE(testQuoteNonPrintable) {
+ Logger& l=Logger::instance();
+ ScopedSuppressLogging ls(l);
+ Options opts("test");
+ opts.time=false;
+ qpid::log::posix::SinkOptions *sinks =
+ dynamic_cast<qpid::log::posix::SinkOptions *>(opts.sinkOptions.get());
+ sinks->logToStderr = false;
+ sinks->logFile = "logging.tmp";
+ l.configure(opts);
+
+ char s[] = "null\0tab\tspace newline\nret\r\x80\x99\xff";
+ string str(s, sizeof(s));
+ QPID_LOG(critical, str);
+ ifstream log("logging.tmp");
+ string line;
+ getline(log, line, '\0');
+ string expect="critical null\\x00tab\tspace newline\nret\r\\x80\\x99\\xFF\\x00\n";
+ BOOST_CHECK_EQUAL(expect, line);
+ log.close();
+ unlink("logging.tmp");
+}
+
+QPID_AUTO_TEST_SUITE_END()
diff --git a/RC9/qpid/cpp/src/tests/multiq_perftest b/RC9/qpid/cpp/src/tests/multiq_perftest
new file mode 100755
index 0000000000..10f9edd2a6
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/multiq_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+exec `dirname $0`/run_perftest 10000 --mode shared --qt 16
diff --git a/RC9/qpid/cpp/src/tests/perfdist b/RC9/qpid/cpp/src/tests/perfdist
new file mode 100755
index 0000000000..59548b23f7
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/perfdist
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+#
+# 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.
+#
+
+
+#
+# Distributed perftest.
+# Runs perftest clients on multiple hosts using ssh.
+#
+
+set -e
+usage() {
+cat <<EOF
+usage: $0 <perftest-args> -- <client-hosts ...> [ --- <broker hosts...> ]
+Client & broker hosts can also be set in env vars CLIENTS and BROKERS.
+
+Run perftest clients on the client hosts against brokers on the broker
+hosts Clients are assigned to client hosts round robin: publishers
+first, then subscribers. If there are multiple brokers (for cluster
+tests) clients connect to them round robin.
+
+Broker hosts can be listed with -b in perftest-args or after ---
+at the end of the arguments.
+
+Error: $*
+EOF
+exit 1
+}
+
+TESTDIR=${TESTDIR:-$PWD} # Absolute path to test exes on all hosts.
+
+collect() { eval $COLLECT=\""\$$COLLECT $*"\"; }
+NPUBS=1
+NSUBS=1
+COLLECT=ARGS
+while test $# -gt 0; do
+ case $1 in
+ --publish|--subscribe|--setup|--control) usage "Don't pass perftest action flags: $1" ;;
+ --npubs) collect $1 $2; NPUBS=$2; shift 2 ;;
+ --nsubs) collect $1 $2; NSUBS=$2; shift 2 ;;
+ -s|--summary) collect $1; QUIET=yes; shift 1 ;;
+ -b|--broker) BROKERS="$BROKERS $2"; shift 2;;
+ --) COLLECT=CLIENTARG; shift ;;
+ ---) COLLECT=BROKERARG; shift;;
+ *) collect $1; shift ;;
+ esac
+done
+
+CLIENTS=${CLIENTARG:-$CLIENTS}
+if [ -z "$CLIENTS" ]; then usage "No client hosts listed after --"; fi
+BROKERS=${BROKERARG:-$BROKERS}
+if [ -z "$BROKERS" ]; then usage "No brokers specified"; fi
+
+PERFTEST="$TESTDIR/perftest $ARGS"
+
+CLIENTS=($CLIENTS)
+BROKERS=($BROKERS)
+start() {
+ CLIENT=${CLIENTS[i % ${#CLIENTS[*]}]}
+ BROKER=${BROKERS[i % ${#BROKERS[*]}]}
+ ARGS="$* --broker $BROKER"
+ cmd="ssh -n $CLIENT $PERFTEST $ARGS"
+ test -z "$QUIET" && echo "Client $i: $cmd"
+ $cmd &
+}
+
+$PERFTEST --setup -b ${BROKERS[0]}
+for (( i=0 ; i < $NPUBS ; ++i)); do start --publish; done
+for (( ; i < $NPUBS+$NSUBS ; ++i)); do start --subscribe; done
+$PERFTEST --control -b ${BROKERS[0]}
diff --git a/RC9/qpid/cpp/src/tests/perftest.cpp b/RC9/qpid/cpp/src/tests/perftest.cpp
new file mode 100644
index 0000000000..be9ffd846e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/perftest.cpp
@@ -0,0 +1,701 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "TestOptions.h"
+
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Completion.h"
+#include "qpid/client/Message.h"
+#include "qpid/framing/FieldTable.h"
+#include "qpid/sys/Time.h"
+
+#include <boost/lexical_cast.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <numeric>
+#include <algorithm>
+#include <unistd.h>
+#include <math.h>
+
+
+using namespace std;
+using namespace qpid;
+using namespace client;
+using namespace sys;
+using boost::lexical_cast;
+using boost::bind;
+
+enum Mode { SHARED, FANOUT, TOPIC };
+const char* modeNames[] = { "shared", "fanout", "topic" };
+
+// istream/ostream ops so Options can read/display Mode.
+istream& operator>>(istream& in, Mode& mode) {
+ string s;
+ in >> s;
+ int i = find(modeNames, modeNames+3, s) - modeNames;
+ if (i >= 3) throw Exception("Invalid mode: "+s);
+ mode = Mode(i);
+ return in;
+}
+
+ostream& operator<<(ostream& out, Mode mode) {
+ return out << modeNames[mode];
+}
+
+
+struct Opts : public TestOptions {
+
+ // Actions
+ bool setup, control, publish, subscribe;
+
+ // Queue policy
+ uint32_t queueMaxCount;
+ uint64_t queueMaxSize;
+ bool queueDurable;
+
+ // Publisher
+ size_t pubs;
+ size_t count ;
+ size_t size;
+ bool confirm;
+ bool durable;
+ bool uniqueData;
+ bool syncPub;
+
+ // Subscriber
+ size_t subs;
+ size_t ack;
+
+ // General
+ size_t qt;
+ size_t iterations;
+ Mode mode;
+ bool summary;
+ uint32_t intervalSub;
+ uint32_t intervalPub;
+ size_t tx;
+ size_t txPub;
+ size_t txSub;
+ bool commitAsync;
+
+ static const std::string helpText;
+
+ Opts() :
+ TestOptions(helpText),
+ setup(false), control(false), publish(false), subscribe(false),
+ pubs(1), count(500000), size(1024), confirm(true), durable(false), uniqueData(false), syncPub(false),
+ subs(1), ack(0),
+ qt(1), iterations(1), mode(SHARED), summary(false),
+ intervalSub(0), intervalPub(0), tx(0), txPub(0), txSub(0), commitAsync(false)
+ {
+ addOptions()
+ ("setup", optValue(setup), "Create shared queues.")
+ ("control", optValue(control), "Run test, print report.")
+ ("publish", optValue(publish), "Publish messages.")
+ ("subscribe", optValue(subscribe), "Subscribe for messages.")
+
+ ("mode", optValue(mode, "shared|fanout|topic"), "Test mode."
+ "\nshared: --qt queues, --npubs publishers and --nsubs subscribers per queue.\n"
+ "\nfanout: --npubs publishers, --nsubs subscribers, fanout exchange."
+ "\ntopic: --qt topics, --npubs publishers and --nsubs subscribers per topic.\n")
+
+ ("npubs", optValue(pubs, "N"), "Create N publishers.")
+ ("count", optValue(count, "N"), "Each publisher sends N messages.")
+ ("size", optValue(size, "BYTES"), "Size of messages in bytes.")
+ ("pub-confirm", optValue(confirm, "yes|no"), "Publisher use confirm-mode.")
+ ("durable", optValue(durable, "yes|no"), "Publish messages as durable.")
+ ("unique-data", optValue(uniqueData, "yes|no"), "Make data for each message unique.")
+ ("sync-publish", optValue(syncPub, "yes|no"), "Wait for confirmation of each message before sending the next one.")
+
+ ("nsubs", optValue(subs, "N"), "Create N subscribers.")
+ ("sub-ack", optValue(ack, "N"), "N>0: Subscriber acks batches of N.\n"
+ "N==0: Subscriber uses unconfirmed mode")
+
+ ("qt", optValue(qt, "N"), "Create N queues or topics.")
+ ("iterations", optValue(iterations, "N"), "Desired number of iterations of the test.")
+ ("summary,s", optValue(summary), "Summary output: pubs/sec subs/sec transfers/sec Mbytes/sec")
+
+ ("queue-max-count", optValue(queueMaxCount, "N"), "queue policy: count to trigger 'flow to disk'")
+ ("queue-max-size", optValue(queueMaxSize, "N"), "queue policy: accumulated size to trigger 'flow to disk'")
+ ("queue-durable", optValue(queueDurable, "N"), "Make queue durable (implied if durable set)")
+
+ ("interval_sub", optValue(intervalSub, "ms"), ">=0 delay between msg consume")
+ ("interval_pub", optValue(intervalPub, "ms"), ">=0 delay between msg publish")
+
+ ("tx", optValue(tx, "N"), "if non-zero, the transaction batch size for publishing and consuming")
+ ("pub-tx", optValue(txPub, "N"), "if non-zero, the transaction batch size for publishing")
+ ("async-commit", optValue(commitAsync, "yes|no"), "Don't wait for completion of commit")
+ ("sub-tx", optValue(txSub, "N"), "if non-zero, the transaction batch size for consuming");
+ }
+
+ // Computed values
+ size_t totalPubs;
+ size_t totalSubs;
+ size_t transfers;
+ size_t subQuota;
+
+ void parse(int argc, char** argv) {
+ TestOptions::parse(argc, argv);
+ switch (mode) {
+ case SHARED:
+ if (count % subs) {
+ count += subs - (count % subs);
+ cout << "WARNING: Adjusted --count to " << count
+ << " the nearest multiple of --nsubs" << endl;
+ }
+ totalPubs = pubs*qt;
+ totalSubs = subs*qt;
+ subQuota = (pubs*count)/subs;
+ break;
+ case FANOUT:
+ if (qt != 1) cerr << "WARNING: Fanout mode, ignoring --qt="
+ << qt << endl;
+ qt=1;
+ totalPubs = pubs;
+ totalSubs = subs;
+ subQuota = totalPubs*count;
+ break;
+ case TOPIC:
+ totalPubs = pubs*qt;
+ totalSubs = subs*qt;
+ subQuota = pubs*count;
+ break;
+ }
+ transfers=(totalPubs*count) + (totalSubs*subQuota);
+ if (tx) {
+ if (txPub) {
+ cerr << "WARNING: Using overriden tx value for publishers: " << txPub << std::endl;
+ } else {
+ txPub = tx;
+ }
+ if (txSub) {
+ cerr << "WARNING: Using overriden tx value for subscribers: " << txSub << std::endl;
+ } else {
+ txSub = tx;
+ }
+ }
+ }
+};
+
+const std::string Opts::helpText=
+"There are two ways to use perftest: single process or multi-process.\n\n"
+"If none of the --setup, --publish, --subscribe or --control options\n"
+"are given perftest will run a single-process test.\n"
+"For a multi-process test first run:\n"
+" perftest --setup <other options>\n"
+"and wait for it to complete. The remaining process should run concurrently::\n"
+"Run --npubs times: perftest --publish <other options>\n"
+"Run --nsubs times: perftest --subscribe <other options>\n"
+"Run once: perftest --control <other options>\n"
+"Note the <other options> must be identical for all processes.\n";
+
+Opts opts;
+
+struct Client : public Runnable {
+ Connection connection;
+ AsyncSession session;
+ Thread thread;
+
+ Client() {
+ opts.open(connection);
+ session = connection.newSession();
+ }
+
+ ~Client() {
+ try {
+ session.close();
+ connection.close();
+ } catch (const std::exception& e) {
+ std::cerr << "Error in shutdown: " << e.what() << std::endl;
+ }
+ }
+};
+
+struct Setup : public Client {
+
+ void queueInit(string name, bool durable=false, const framing::FieldTable& settings=framing::FieldTable()) {
+ session.queueDeclare(arg::queue=name, arg::durable=durable, arg::arguments=settings);
+ session.queuePurge(arg::queue=name);
+ session.sync();
+ }
+
+ void run() {
+ queueInit("pub_start");
+ queueInit("pub_done");
+ queueInit("sub_ready");
+ queueInit("sub_done");
+ if (opts.mode==SHARED) {
+ framing::FieldTable settings;//queue policy settings
+ settings.setInt("qpid.max_count", opts.queueMaxCount);
+ settings.setInt("qpid.max_size", opts.queueMaxSize);
+ for (size_t i = 0; i < opts.qt; ++i) {
+ ostringstream qname;
+ qname << "perftest" << i;
+ queueInit(qname.str(), opts.durable || opts.queueDurable, settings);
+ }
+ }
+ }
+};
+
+void expect(string actual, string expect) {
+ if (expect != actual)
+ throw Exception("Expecting "+expect+" but received "+actual);
+
+}
+
+double secs(Duration d) { return double(d)/TIME_SEC; }
+double secs(AbsTime start, AbsTime finish) {
+ return secs(Duration(start,finish));
+}
+
+
+// Collect rates & print stats.
+class Stats {
+ vector<double> values;
+ double sum;
+
+ public:
+ Stats() : sum(0) {}
+
+ // Functor to collect rates.
+ void operator()(const string& data) {
+ try {
+ double d=lexical_cast<double>(data);
+ values.push_back(d);
+ sum += d;
+ } catch (const std::exception&) {
+ throw Exception("Bad report: "+data);
+ }
+ }
+
+ double mean() const {
+ return sum/values.size();
+ }
+
+ double stdev() const {
+ if (values.size() <= 1) return 0;
+ double avg = mean();
+ double ssq = 0;
+ for (vector<double>::const_iterator i = values.begin();
+ i != values.end(); ++i) {
+ double x=*i;
+ x -= avg;
+ ssq += x*x;
+ }
+ return sqrt(ssq/(values.size()-1));
+ }
+
+ ostream& print(ostream& out) {
+ ostream_iterator<double> o(out, "\n");
+ copy(values.begin(), values.end(), o);
+ out << "Average: " << mean();
+ if (values.size() > 1)
+ out << " (std.dev. " << stdev() << ")";
+ return out << endl;
+ }
+};
+
+
+// Manage control queues, collect and print reports.
+struct Controller : public Client {
+
+ SubscriptionManager subs;
+
+ Controller() : subs(session) {}
+
+ /** Process messages from queue by applying a functor. */
+ void process(size_t n, string queue,
+ boost::function<void (const string&)> msgFn)
+ {
+ if (!opts.summary)
+ cout << "Processing " << n << " messages from "
+ << queue << " " << flush;
+ LocalQueue lq;
+ subs.setFlowControl(n, SubscriptionManager::UNLIMITED, false);
+ subs.subscribe(lq, queue);
+ for (size_t i = 0; i < n; ++i) {
+ if (!opts.summary) cout << "." << flush;
+ msgFn(lq.pop().getData());
+ }
+ if (!opts.summary) cout << " done." << endl;
+ }
+
+ void process(size_t n, LocalQueue lq, string queue,
+ boost::function<void (const string&)> msgFn)
+ {
+ session.messageFlow(queue, 0, n);
+ if (!opts.summary)
+ cout << "Processing " << n << " messages from "
+ << queue << " " << flush;
+ for (size_t i = 0; i < n; ++i) {
+ if (!opts.summary) cout << "." << flush;
+ msgFn(lq.pop().getData());
+ }
+ if (!opts.summary) cout << " done." << endl;
+ }
+
+ void send(size_t n, string queue, string data) {
+ if (!opts.summary)
+ cout << "Sending " << data << " " << n << " times to " << queue
+ << endl;
+ Message msg(data, queue);
+ for (size_t i = 0; i < n; ++i)
+ session.messageTransfer(arg::content=msg, arg::acceptMode=1);
+ }
+
+ void run() { // Controller
+ try {
+ // Wait for subscribers to be ready.
+ process(opts.totalSubs, "sub_ready", bind(expect, _1, "ready"));
+
+ LocalQueue pubDone;
+ LocalQueue subDone;
+ subs.setFlowControl(0, SubscriptionManager::UNLIMITED, false);
+ subs.subscribe(pubDone, "pub_done");
+ subs.subscribe(subDone, "sub_done");
+
+ double txrateTotal(0);
+ double mbytesTotal(0);
+ double pubRateTotal(0);
+ double subRateTotal(0);
+
+ for (size_t j = 0; j < opts.iterations; ++j) {
+ AbsTime start=now();
+ send(opts.totalPubs, "pub_start", "start"); // Start publishers
+
+ Stats pubRates;
+ Stats subRates;
+
+ process(opts.totalPubs, pubDone, "pub_done", boost::ref(pubRates));
+ process(opts.totalSubs, subDone, "sub_done", boost::ref(subRates));
+
+ AbsTime end=now();
+
+ double time=secs(start, end);
+ double txrate=opts.transfers/time;
+ double mbytes=(txrate*opts.size)/(1024*1024);
+
+ if (!opts.summary) {
+ cout << endl << "Total " << opts.transfers << " transfers of "
+ << opts.size << " bytes in "
+ << time << " seconds." << endl;
+ cout << endl << "Publish transfers/sec: " << endl;
+ pubRates.print(cout);
+ cout << endl << "Subscribe transfers/sec: " << endl;
+ subRates.print(cout);
+ cout << endl
+ << "Total transfers/sec: " << txrate << endl
+ << "Total Mbytes/sec: " << mbytes << endl;
+ }
+ else {
+ cout << pubRates.mean() << "\t"
+ << subRates.mean() << "\t"
+ << txrate << "\t"
+ << mbytes << endl;
+ }
+
+ txrateTotal += txrate;
+ mbytesTotal += mbytes;
+ pubRateTotal += pubRates.mean();
+ subRateTotal += subRates.mean();
+ }
+ if (opts.iterations > 1) {
+ cout << "Averages: "<< endl
+ << (pubRateTotal / opts.iterations) << "\t"
+ << (subRateTotal / opts.iterations) << "\t"
+ << (txrateTotal / opts.iterations) << "\t"
+ << (mbytesTotal / opts.iterations) << endl;
+ }
+ }
+ catch (const std::exception& e) {
+ cout << "Controller exception: " << e.what() << endl;
+ }
+ }
+};
+
+
+struct PublishThread : public Client {
+ string destination;
+ string routingKey;
+
+ PublishThread() {};
+
+ PublishThread(string key, string dest=string()) {
+ destination=dest;
+ routingKey=key;
+ }
+
+ void run() { // Publisher
+ try {
+ string data;
+ size_t offset(0);
+ if (opts.uniqueData) {
+ offset = 5;
+ data += "data:";//marker (requested for latency testing tool scripts)
+ data += string(sizeof(size_t), 'X');//space for seq no
+ data += session.getId().str();
+ if (opts.size > data.size()) {
+ data += string(opts.size - data.size(), 'X');
+ } else if(opts.size < data.size()) {
+ cout << "WARNING: Increased --size to " << data.size()
+ << " to honour --unique-data" << endl;
+ }
+ } else {
+ size_t msgSize=max(opts.size, sizeof(size_t));
+ data = string(msgSize, 'X');
+ }
+
+ Message msg(data, routingKey);
+ if (opts.durable)
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+
+
+ if (opts.txPub){
+ session.txSelect();
+ }
+ SubscriptionManager subs(session);
+ LocalQueue lq;
+ subs.setFlowControl(1, SubscriptionManager::UNLIMITED, true);
+ subs.subscribe(lq, "pub_start");
+
+ for (size_t j = 0; j < opts.iterations; ++j) {
+ expect(lq.pop().getData(), "start");
+ AbsTime start=now();
+ for (size_t i=0; i<opts.count; i++) {
+ // Stamp the iteration into the message data, avoid
+ // any heap allocation.
+ const_cast<std::string&>(msg.getData()).replace(offset, sizeof(size_t),
+ reinterpret_cast<const char*>(&i), sizeof(size_t));
+ if (opts.syncPub) {
+ sync(session).messageTransfer(
+ arg::destination=destination,
+ arg::content=msg,
+ arg::acceptMode=1);
+ } else {
+ session.messageTransfer(
+ arg::destination=destination,
+ arg::content=msg,
+ arg::acceptMode=1);
+ }
+ if (opts.txPub && ((i+1) % opts.txPub == 0)){
+ if (opts.commitAsync){
+ session.txCommit();
+ } else {
+ sync(session).txCommit();
+ }
+ }
+ if (opts.intervalPub) ::usleep(opts.intervalPub*1000);
+ }
+ if (opts.confirm) session.sync();
+ AbsTime end=now();
+ double time=secs(start,end);
+
+ // Send result to controller.
+ Message report(lexical_cast<string>(opts.count/time), "pub_done");
+ session.messageTransfer(arg::content=report, arg::acceptMode=1);
+ if (opts.txPub){
+ sync(session).txCommit();
+ }
+ }
+ session.close();
+ }
+ catch (const std::exception& e) {
+ cout << "PublishThread exception: " << e.what() << endl;
+ }
+ }
+};
+
+struct SubscribeThread : public Client {
+
+ string queue;
+
+ SubscribeThread() {}
+
+ SubscribeThread(string q) { queue = q; }
+
+ SubscribeThread(string key, string ex) {
+ queue=session.getId().str(); // Unique name.
+ session.queueDeclare(arg::queue=queue,
+ arg::exclusive=true,
+ arg::autoDelete=true,
+ arg::durable=opts.durable);
+ session.exchangeBind(arg::queue=queue,
+ arg::exchange=ex,
+ arg::bindingKey=key);
+ }
+
+ void verify(bool cond, const char* test, uint32_t expect, uint32_t actual) {
+ if (!cond) {
+ Message error(
+ QPID_MSG("Sequence error: expected n" << test << expect << " but got " << actual),
+ "sub_done");
+ session.messageTransfer(arg::content=error, arg::acceptMode=1);
+ throw Exception(error.getData());
+ }
+ }
+
+ void run() { // Subscribe
+ try {
+ if (opts.txSub) sync(session).txSelect();
+ SubscriptionManager subs(session);
+ SubscriptionSettings settings;
+ settings.autoAck = opts.txSub ? opts.txSub : opts.ack;
+ settings.acceptMode = (opts.txSub || opts.ack ? ACCEPT_MODE_EXPLICIT : ACCEPT_MODE_NONE);
+ settings.flowControl = FlowControl::messageCredit(opts.subQuota);
+ LocalQueue lq;
+ Subscription subscription = subs.subscribe(lq, queue, settings);
+ // Notify controller we are ready.
+ session.messageTransfer(arg::content=Message("ready", "sub_ready"), arg::acceptMode=1);
+ if (opts.txSub) {
+ if (opts.commitAsync) session.txCommit();
+ else sync(session).txCommit();
+ }
+
+ for (size_t j = 0; j < opts.iterations; ++j) {
+ if (j > 0) {
+ //need to allocate some more credit
+ session.messageFlow(queue, 0, opts.subQuota);
+ }
+ Message msg;
+ AbsTime start=now();
+ size_t expect=0;
+ for (size_t i = 0; i < opts.subQuota; ++i) {
+ msg=lq.pop();
+ if (opts.txSub && ((i+1) % opts.txSub == 0)) {
+ if (opts.commitAsync) session.txCommit();
+ else sync(session).txCommit();
+ }
+ if (opts.intervalSub) ::usleep(opts.intervalSub*1000);
+ // TODO aconway 2007-11-23: check message order for.
+ // multiple publishers. Need an array of counters,
+ // one per publisher and a publisher ID in the
+ // message. Careful not to introduce a lot of overhead
+ // here, e.g. no std::map, std::string etc.
+ //
+ // For now verify order only for a single publisher.
+ size_t offset = opts.uniqueData ? 5 /*marker is 'data:'*/ : 0;
+ size_t n = *reinterpret_cast<const size_t*>(msg.getData().data() + offset);
+ if (opts.pubs == 1) {
+ if (opts.subs == 1 || opts.mode == FANOUT) verify(n==expect, "==", expect, n);
+ else verify(n>=expect, ">=", expect, n);
+ expect = n+1;
+ }
+ }
+ if (opts.txSub || opts.ack)
+ subscription.accept(subscription.getUnaccepted());
+ if (opts.txSub) {
+ if (opts.commitAsync) session.txCommit();
+ else sync(session).txCommit();
+ }
+ AbsTime end=now();
+
+ // Report to publisher.
+ Message result(lexical_cast<string>(opts.subQuota/secs(start,end)),
+ "sub_done");
+ session.messageTransfer(arg::content=result, arg::acceptMode=1);
+ if (opts.txSub) sync(session).txCommit();
+ }
+ session.close();
+ }
+ catch (const std::exception& e) {
+ cout << "SubscribeThread exception: " << e.what() << endl;
+ }
+ }
+};
+
+int main(int argc, char** argv) {
+
+ try {
+ opts.parse(argc, argv);
+
+ string exchange;
+ switch (opts.mode) {
+ case FANOUT: exchange="amq.fanout"; break;
+ case TOPIC: exchange="amq.topic"; break;
+ case SHARED: break;
+ }
+
+ bool singleProcess=
+ (!opts.setup && !opts.control && !opts.publish && !opts.subscribe);
+ if (singleProcess)
+ opts.setup = opts.control = opts.publish = opts.subscribe = true;
+
+ if (opts.setup) Setup().run(); // Set up queues
+
+ boost::ptr_vector<Client> subs(opts.subs);
+ boost::ptr_vector<Client> pubs(opts.pubs);
+
+ // Start pubs/subs for each queue/topic.
+ for (size_t i = 0; i < opts.qt; ++i) {
+ ostringstream key;
+ key << "perftest" << i; // Queue or topic name.
+ if (opts.publish) {
+ size_t n = singleProcess ? opts.pubs : 1;
+ for (size_t j = 0; j < n; ++j) {
+ pubs.push_back(new PublishThread(key.str(), exchange));
+ pubs.back().thread=Thread(pubs.back());
+ }
+ }
+ if (opts.subscribe) {
+ size_t n = singleProcess ? opts.subs : 1;
+ for (size_t j = 0; j < n; ++j) {
+ if (opts.mode==SHARED)
+ subs.push_back(new SubscribeThread(key.str()));
+ else
+ subs.push_back(new SubscribeThread(key.str(),exchange));
+ subs.back().thread=Thread(subs.back());
+ }
+ }
+ }
+
+ if (opts.control) Controller().run();
+
+
+ // Wait for started threads.
+ if (opts.publish) {
+ for (boost::ptr_vector<Client>::iterator i=pubs.begin();
+ i != pubs.end();
+ ++i)
+ i->thread.join();
+ }
+
+
+ if (opts.subscribe) {
+ for (boost::ptr_vector<Client>::iterator i=subs.begin();
+ i != subs.end();
+ ++i)
+ i->thread.join();
+ }
+ return 0;
+ }
+ catch (const std::exception& e) {
+ cout << endl << e.what() << endl;
+ }
+ return 1;
+}
+
+
diff --git a/RC9/qpid/cpp/src/tests/policy.acl b/RC9/qpid/cpp/src/tests/policy.acl
new file mode 100644
index 0000000000..ef46026555
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/policy.acl
@@ -0,0 +1 @@
+acl allow all all
diff --git a/RC9/qpid/cpp/src/tests/publish.cpp b/RC9/qpid/cpp/src/tests/publish.cpp
new file mode 100644
index 0000000000..34c2b8fefc
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/publish.cpp
@@ -0,0 +1,128 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using namespace std;
+
+typedef vector<string> StringSet;
+
+struct Args : public qpid::TestOptions {
+ uint size;
+ uint count;
+ bool durable;
+ string destination;
+ string routingKey;
+ bool summary;
+ bool id;
+
+ Args() : size(256), count(1000), durable(true), routingKey("publish-consume"), summary(false), id(false) {
+ addOptions()
+ ("size", optValue(size, "N"), "message size")
+ ("count", optValue(count, "N"), "number of messages to publish")
+ ("durable", optValue(durable, "yes|no"), "use durable messages")
+ ("destination", optValue(destination, "<exchange name>"), "destination to publish to")
+ ("routing-key", optValue(routingKey, "<key>"), "routing key to publish with")
+ ("summary,s", optValue(summary), "Output only the rate.")
+ ("id", optValue(id), "Add unique correlation ID");
+ }
+};
+
+Args opts;
+
+struct Client
+{
+ Connection connection;
+ AsyncSession session;
+
+ Client()
+ {
+ opts.open(connection);
+ session = connection.newSession();
+ }
+
+ // Cheap hex calculation, avoid expensive ostrstream and string
+ // creation to generate correlation ids in message loop.
+ char hex(char i) { return i<10 ? '0'+i : 'A'+i-10; }
+ void hex(char i, string& s) {
+ s[0]=hex(i>>24); s[1]=hex(i>>16); s[2]=hex(i>>8); s[3]=i;
+ }
+
+ void publish()
+ {
+ AbsTime begin=now();
+ Message msg(string(opts.size, 'X'), opts.routingKey);
+ string correlationId = "0000";
+ if (opts.durable)
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+
+ for (uint i = 0; i < opts.count; i++) {
+ if (opts.id) {
+ hex(i+1, correlationId);
+ msg.getMessageProperties().setCorrelationId(correlationId);
+ }
+ session.messageTransfer(arg::destination=opts.destination,
+ arg::content=msg,
+ arg::acceptMode=1);
+ }
+ session.sync();
+ AbsTime end=now();
+ double secs(double(Duration(begin,end))/TIME_SEC);
+ if (opts.summary) cout << opts.count/secs << endl;
+ else cout << "Time: " << secs << "s Rate: " << opts.count/secs << endl;
+ }
+
+ ~Client()
+ {
+ try{
+ session.close();
+ connection.close();
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ }
+};
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ Client client;
+ client.publish();
+ return 0;
+ } catch(const exception& e) {
+ cout << e.what() << endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/python_tests b/RC9/qpid/cpp/src/tests/python_tests
new file mode 100755
index 0000000000..30bb8259a4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/python_tests
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Run the python tests.
+QPID_PORT=${QPID_PORT:-5672}
+PYTHON_TESTS=${PYTHON_TESTS:-$*}
+MY_DIR=`dirname \`which $0\``
+QPID_PYTHON_DIR=${QPID_PYTHON_DIR:-${MY_DIR}/../../../python}
+
+run() {
+ SPEC=$1
+ FAILING=$2
+ ./run-tests --skip-self-test -v -s $SPEC -I $FAILING -b localhost:$QPID_PORT $PYTHON_TESTS || { echo "FAIL python tests for $SPEC"; exit 1; }
+}
+
+if test -d ${QPID_PYTHON_DIR} ; then
+ cd ${QPID_PYTHON_DIR}
+ run 0-10-errata cpp_failing_0-10.txt
+else
+ echo "WARNING: No python tests. $QPID_PYTHON_DIR not found."
+fi
diff --git a/RC9/qpid/cpp/src/tests/quick_perftest b/RC9/qpid/cpp/src/tests/quick_perftest
new file mode 100755
index 0000000000..4f7cf3cb54
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/quick_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+exec `dirname $0`/run_test ./perftest --summary --count 100
diff --git a/RC9/qpid/cpp/src/tests/quick_topictest b/RC9/qpid/cpp/src/tests/quick_topictest
new file mode 100755
index 0000000000..5e7d85849f
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/quick_topictest
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+
+# Quick and quiet topic test for make check.
+test -z "$srcdir" && srcdir=.
+$srcdir/topictest -s2 -m2 -b1 > topictest.log 2>&1 || {
+ echo $0 FAILED:
+ cat topictest.log
+ exit 1
+}
+rm topictest.log
diff --git a/RC9/qpid/cpp/src/tests/quick_txtest b/RC9/qpid/cpp/src/tests/quick_txtest
new file mode 100755
index 0000000000..938e3805d8
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/quick_txtest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+exec `dirname $0`/run_test ./txtest --queues 4 --tx-count 10 --quiet
diff --git a/RC9/qpid/cpp/src/tests/receiver.cpp b/RC9/qpid/cpp/src/tests/receiver.cpp
new file mode 100644
index 0000000000..1b0b6b2548
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/receiver.cpp
@@ -0,0 +1,129 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/SubscriptionManager.h>
+#include <qpid/client/SubscriptionManager.h>
+#include "TestOptions.h"
+
+#include <iostream>
+#include <fstream>
+
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+struct Args : public qpid::TestOptions
+{
+ string queue;
+ uint messages;
+ bool ignoreDuplicates;
+ uint creditWindow;
+ uint ackFrequency;
+
+ Args() : queue("test-queue"), messages(0), ignoreDuplicates(false), creditWindow(0), ackFrequency(1)
+ {
+ addOptions()
+ ("queue", qpid::optValue(queue, "QUEUE NAME"), "Queue from which to request messages")
+ ("messages", qpid::optValue(messages, "N"), "Number of messages to receive; 0 means receive indefinitely")
+ ("ignore-duplicates", qpid::optValue(ignoreDuplicates), "Detect and ignore duplicates (by checking 'sn' header)")
+ ("credit-window", qpid::optValue(creditWindow, "N"), "Credit window (0 implies infinite window)")
+ ("ack-frequency", qpid::optValue(ackFrequency, "N"), "Ack frequency (0 implies none of the messages will get accepted)");
+ }
+};
+
+const string EOS("eos");
+
+class Receiver : public MessageListener, public FailoverManager::Command
+{
+ public:
+ Receiver(const string& queue, uint messages, bool ignoreDuplicates, uint creditWindow, uint ackFrequency);
+ void received(Message& message);
+ void execute(AsyncSession& session, bool isRetry);
+ private:
+ const string queue;
+ const uint count;
+ const bool skipDups;
+ SubscriptionSettings settings;
+ Subscription subscription;
+ uint processed;
+ uint lastSn;
+
+ bool isDuplicate(Message& message);
+};
+
+Receiver::Receiver(const string& q, uint messages, bool ignoreDuplicates, uint creditWindow, uint ackFrequency) :
+ queue(q), count(messages), skipDups(ignoreDuplicates), processed(0), lastSn(0)
+{
+ if (creditWindow) settings.flowControl = FlowControl::messageWindow(creditWindow);
+ settings.autoAck = ackFrequency;
+}
+
+void Receiver::received(Message & message)
+{
+ if (!(skipDups && isDuplicate(message))) {
+ bool eos = message.getData() == EOS;
+ if (!eos) std::cout << message.getData() << std::endl;
+ if (eos || ++processed == count) subscription.cancel();
+ }
+}
+
+bool Receiver::isDuplicate(Message& message)
+{
+ uint sn = message.getHeaders().getAsInt("sn");
+ if (lastSn < sn) {
+ lastSn = sn;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void Receiver::execute(AsyncSession& session, bool /*isRetry*/)
+{
+ SubscriptionManager subs(session);
+ subscription = subs.subscribe(*this, queue, settings);
+ subs.run();
+}
+
+int main(int argc, char ** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ FailoverManager connection(opts.con);
+ Receiver receiver(opts.queue, opts.messages, opts.ignoreDuplicates, opts.creditWindow, opts.ackFrequency);
+ connection.execute(receiver);
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cerr << "Failure: " << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/replaying_sender.cpp b/RC9/qpid/cpp/src/tests/replaying_sender.cpp
new file mode 100644
index 0000000000..7e148e277f
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/replaying_sender.cpp
@@ -0,0 +1,131 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageReplayTracker.h>
+#include <qpid/Exception.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+class Sender : public FailoverManager::Command
+{
+ public:
+ Sender(const std::string& queue, uint count, uint reportFreq);
+ void execute(AsyncSession& session, bool isRetry);
+ uint getSent();
+
+ int verbosity;
+
+ private:
+ MessageReplayTracker sender;
+ const uint count;
+ uint sent;
+ const uint reportFrequency;
+ Message message;
+
+};
+
+Sender::Sender(const std::string& queue, uint count_, uint reportFreq ) : sender(10), count(count_), sent(0), reportFrequency(reportFreq)
+{
+ message.getDeliveryProperties().setRoutingKey(queue);
+}
+
+void Sender::execute(AsyncSession& session, bool isRetry)
+{
+ if (isRetry) sender.replay(session);
+ else sender.init(session);
+ while (sent < count) {
+ stringstream message_data;
+ message_data << ++sent;
+ message.setData(message_data.str());
+ message.getHeaders().setInt("sn", sent);
+ sender.send(message);
+ if (count > reportFrequency && !(sent % reportFrequency)) {
+ if ( verbosity > 0 )
+ std::cout << "sent " << sent << " of " << count << std::endl;
+ }
+ }
+ message.setData("That's all, folks!");
+ sender.send(message);
+
+ if ( verbosity > 0 )
+ std::cout << "SENDER COMPLETED\n";
+}
+
+uint Sender::getSent()
+{
+ return sent;
+}
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+
+ if ( argc != 6 )
+ {
+ std::cerr << "Usage: replaying_sender host port n_messages report_frequency verbosity\n";
+ return 1;
+ }
+
+ settings.host = argv[1];
+ settings.port = atoi(argv[2]);
+ int n_messages = atoi(argv[3]);
+ int reportFrequency = atoi(argv[4]);
+ int verbosity = atoi(argv[5]);
+
+ FailoverManager connection(settings);
+ Sender sender("message_queue", n_messages, reportFrequency );
+ sender.verbosity = verbosity;
+ try {
+ connection.execute ( sender );
+ if ( verbosity > 0 )
+ {
+ std::cout << "Sender finished. Sent "
+ << sender.getSent()
+ << " messages."
+ << endl;
+ }
+ connection.close();
+ return 0;
+ }
+ catch(const std::exception& error)
+ {
+ cerr << "Sender (host: "
+ << settings.host
+ << " port: "
+ << settings.port
+ << " ) "
+ << " Failed: "
+ << error.what()
+ << std::endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/restart_cluster b/RC9/qpid/cpp/src/tests/restart_cluster
new file mode 100755
index 0000000000..6a6abc8042
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/restart_cluster
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Re-start a cluster on the local host.
+
+srcdir=`dirname $0`
+$srcdir/stop_cluster
+exec $srcdir/start_cluster "$@"
+#!/bin/sh
+# Re-start a cluster on the local host.
+
+srcdir=`dirname $0`
+$srcdir/stop_cluster
+exec $srcdir/start_cluster "$@"
+#!/bin/sh
+# Re-start a cluster on the local host.
+
+srcdir=`dirname $0`
+$srcdir/stop_cluster
+exec $srcdir/start_cluster "$@"
diff --git a/RC9/qpid/cpp/src/tests/resuming_receiver.cpp b/RC9/qpid/cpp/src/tests/resuming_receiver.cpp
new file mode 100644
index 0000000000..f49a115e1e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/resuming_receiver.cpp
@@ -0,0 +1,163 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include <iostream>
+#include <fstream>
+
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+
+class Listener : public MessageListener,
+ public FailoverManager::Command,
+ public FailoverManager::ReconnectionStrategy
+{
+ public:
+ Listener ( int report_frequency = 1000, int verbosity = 0 );
+ void received(Message& message);
+ void execute(AsyncSession& session, bool isRetry);
+ void check();
+ void editUrlList(std::vector<Url>& urls);
+ private:
+ Subscription subscription;
+ uint count;
+ uint received_twice;
+ uint lastSn;
+ bool gaps;
+ uint reportFrequency;
+ int verbosity;
+};
+
+
+Listener::Listener(int freq, int verbosity)
+ : count(0),
+ received_twice(0),
+ lastSn(0),
+ gaps(false),
+ reportFrequency(freq),
+ verbosity(verbosity)
+{}
+
+
+void Listener::received(Message & message)
+{
+ if (message.getData() == "That's all, folks!")
+ {
+ if(verbosity > 0 )
+ {
+ std::cout << "Shutting down listener for "
+ << message.getDestination() << std::endl;
+
+ std::cout << "Listener received "
+ << count
+ << " messages ("
+ << received_twice
+ << " received_twice)"
+ << endl;
+ }
+ subscription.cancel();
+ if ( verbosity > 0 )
+ std::cout << "LISTENER COMPLETED\n";
+ } else {
+ uint sn = message.getHeaders().getAsInt("sn");
+ if (lastSn < sn) {
+ if (sn - lastSn > 1) {
+ std::cerr << "Error: gap in sequence between " << lastSn << " and " << sn << std::endl;
+ gaps = true;
+ }
+ lastSn = sn;
+ ++count;
+ if ( ! ( count % reportFrequency ) ) {
+ if ( verbosity > 0 )
+ std::cout << "Listener has received "
+ << count
+ << " messages.\n";
+ }
+ } else {
+ ++received_twice;
+ }
+ }
+}
+
+void Listener::check()
+{
+ if (gaps) throw Exception("Detected gaps in sequence; messages appear to have been lost.");
+}
+
+void Listener::execute(AsyncSession& session, bool isRetry)
+{
+ if (isRetry) {
+ // std::cout << "Resuming from " << count << std::endl;
+ }
+ SubscriptionManager subs(session);
+ subscription = subs.subscribe(*this, "message_queue");
+ subs.run();
+}
+
+void Listener::editUrlList(std::vector<Url>& urls)
+{
+ /**
+ * A more realistic algorithm would be to search through the list
+ * for prefered hosts and ensure they come first in the list.
+ */
+ if (urls.size() > 1) std::rotate(urls.begin(), urls.begin() + 1, urls.end());
+}
+
+int main(int argc, char ** argv)
+{
+ ConnectionSettings settings;
+
+ if ( argc != 5 )
+ {
+ std::cerr << "Usage: resuming_receiver host port report_frequency verbosity\n";
+ return 1;
+ }
+
+ settings.host = argv[1];
+ settings.port = atoi(argv[2]);
+ int reportFrequency = atoi(argv[3]);
+ int verbosity = atoi(argv[4]);
+
+ Listener listener(reportFrequency, verbosity);
+ FailoverManager connection(settings, &listener);
+
+ try {
+ connection.execute(listener);
+ connection.close();
+ listener.check();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cerr << "Receiver failed: " << error.what() << std::endl;
+ }
+ return 1;
+}
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/run-unit-tests b/RC9/qpid/cpp/src/tests/run-unit-tests
new file mode 100755
index 0000000000..862a76c4f5
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run-unit-tests
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+#
+# Library names (without path or .so) and CppUnit test paths can be
+# specified on the command line or in env var UNIT_TESTS. For example:
+#
+# Selected test classes:
+# ./run-unit-tests ValueTest ClientChannelTest
+#
+# Individual test method
+# ./run-unit-tests ValueTest :ValueTest::testStringValueEquals
+#
+# Build and run selected tests:
+# make check TESTS=run-unit-tests UNIT_TESTS=ClientChannelTest
+#
+
+for u in $* $UNIT_TESTS ; do
+ case $u in
+ :*) TEST_ARGS="$TEST_ARGS $u" ;; # A test path.
+ *) TEST_ARGS="$TEST_ARGS .libs/$u.so" ;; # A test library.
+ esac
+done
+test -z "$TEST_ARGS" && TEST_ARGS=".libs/*Test.so"
+
+test -z "$srcdir" && srcdir=.
+
+# libdlclose_noop prevents unloading symbols needed for valgrind output.
+export LD_PRELOAD=.libs/libdlclose_noop.so
+source $srcdir/run_test DllPlugInTester -c -b $TEST_ARGS
diff --git a/RC9/qpid/cpp/src/tests/run_acl_tests b/RC9/qpid/cpp/src/tests/run_acl_tests
new file mode 100755
index 0000000000..8d583c1895
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_acl_tests
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Run the acl tests. $srcdir is set by the Makefile.
+PYTHON_DIR=$srcdir/../../../python
+DATA_DIR=`pwd`/data_dir
+
+trap stop_brokers INT TERM QUIT
+
+start_brokers() {
+ ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIR --load-module ../.libs/acl.so --acl-file policy.acl --auth no > qpidd.port
+ LOCAL_PORT=`cat qpidd.port`
+}
+
+stop_brokers() {
+ ../qpidd -q --port $LOCAL_PORT
+}
+
+test_loading_acl_from_absolute_path(){
+ POLICY_FILE=$PWD/$srcdir/policy.acl
+ ../qpidd --daemon --port 0 --no-module-dir --no-data-dir --auth no --load-module ../.libs/acl.so --acl-file $POLICY_FILE -t --log-to-file temp.log 2>/dev/null
+ PORT=`grep "Listening on TCP port" temp.log | awk '{print $8}'`
+ ACL_FILE=`grep "notice Read ACL file" temp.log | awk '{print $7}'`
+ ../qpidd -q --port $PORT
+ if test "$ACL_FILE" != "\"$POLICY_FILE\""; then
+ echo "unable to load policy file from an absolute path";
+ return 1;
+ fi
+ rm temp.log
+}
+
+if test -d ${PYTHON_DIR} ; then
+ rm -rf $DATA_DIR
+ mkdir -p $DATA_DIR
+ cp $srcdir/policy.acl $DATA_DIR
+ start_brokers
+ echo "Running acl tests using brokers on ports $LOCAL_PORT"
+ PYTHONPATH=$PYTHON_DIR
+ export PYTHONPATH
+ $srcdir/acl.py -v -s $srcdir/../../../specs/amqp.0-10-qpid-errata.xml -b localhost:$LOCAL_PORT --port $LOCAL_PORT || EXITCODE=1
+ stop_brokers || EXITCODE=1
+ test_loading_acl_from_absolute_path || EXITCODE=1
+ rm -rf $DATA_DIR
+ exit $EXITCODE
+fi
+
diff --git a/RC9/qpid/cpp/src/tests/run_failover_soak b/RC9/qpid/cpp/src/tests/run_failover_soak
new file mode 100755
index 0000000000..9dddf59cf1
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_failover_soak
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Check AIS requirements and run tests if found.
+id -ng | grep '\<ais\>' >/dev/null || \
+ NOGROUP="The ais group is not your primary group."
+ps -u root | grep aisexec >/dev/null || \
+ NOAISEXEC="The aisexec daemon is not running as root"
+
+if test -n "$NOGROUP" -o -n "$NOAISEXEC"; then
+ cat <<EOF
+
+ =========== WARNING: NOT RUNNING AIS TESTS ==============
+
+ Tests that depend on the openais library (used for clustering)
+ will not be run because:
+
+ $NOGROUP
+ $NOAISEXEC
+
+ ==========================================================
+
+EOF
+ exit 0; # A warning, not a failure.
+fi
+
+
+host=127.0.0.1
+
+src_root=..
+module_dir=$src_root/.libs
+n_messages=300000
+report_frequency=10000
+verbosity=1
+
+
+exec `dirname $0`/failover_soak $src_root $module_dir $host ./declare_queues ./replaying_sender ./resuming_receiver $n_messages $report_frequency $verbosity
+
diff --git a/RC9/qpid/cpp/src/tests/run_federation_tests b/RC9/qpid/cpp/src/tests/run_federation_tests
new file mode 100755
index 0000000000..28bcc012cc
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_federation_tests
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Run the federation tests.
+MY_DIR=`dirname \`which $0\``
+PYTHON_DIR=${MY_DIR}/../../../python
+
+trap stop_brokers INT TERM QUIT
+
+start_brokers() {
+ ../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no > qpidd.port
+ LOCAL_PORT=`cat qpidd.port`
+ ../qpidd --daemon --port 0 --no-data-dir --no-module-dir --auth no > qpidd.port
+ REMOTE_PORT=`cat qpidd.port`
+}
+
+stop_brokers() {
+ ../qpidd -q --port $LOCAL_PORT
+ ../qpidd -q --port $REMOTE_PORT
+}
+
+if test -d ${PYTHON_DIR} ; then
+ start_brokers
+ echo "Running federation tests using brokers on ports $LOCAL_PORT $REMOTE_PORT"
+ PYTHONPATH=${PYTHON_DIR}
+ export PYTHONPATH
+ ${MY_DIR}/federation.py -v -s ${MY_DIR}/../../../specs/amqp.0-10-qpid-errata.xml -b localhost:$LOCAL_PORT --remote-port $REMOTE_PORT $@
+ RETCODE=$?
+ stop_brokers
+ if test x$RETCODE != x0; then
+ echo "FAIL federation tests"; exit 1;
+ fi
+fi
+
diff --git a/RC9/qpid/cpp/src/tests/run_header_test b/RC9/qpid/cpp/src/tests/run_header_test
new file mode 100755
index 0000000000..39d4a24f84
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_header_test
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Simple test of encode/decode of a double in application headers
+# TODO: this should be expanded to cover a wider set of types and go
+# in both directions
+
+srcdir=`dirname $0`
+PYTHON_DIR=$srcdir/../../../python
+test -f qpidd.port && QPID_PORT=`cat qpidd.port`
+
+if test -d ${PYTHON_DIR} ; then
+ ./header_test -p $QPID_PORT
+ export PYTHONPATH=$PYTHON_DIR:$PYTHONPATH
+ $srcdir/header_test.py "localhost" $QPID_PORT
+else
+ echo "Skipping header test as python libs not found"
+fi
+
diff --git a/RC9/qpid/cpp/src/tests/run_perftest b/RC9/qpid/cpp/src/tests/run_perftest
new file mode 100755
index 0000000000..1a9b934641
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_perftest
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Args: count [perftest options...]
+# Run a perftest with count multiplied.
+#
+MULTIPLIER=3
+COUNT=`expr $1 \* $MULTIPLIER`
+shift
+exec `dirname $0`/run_test ./perftest --summary --count $COUNT "$@"
diff --git a/RC9/qpid/cpp/src/tests/run_test b/RC9/qpid/cpp/src/tests/run_test
new file mode 100755
index 0000000000..062e9e137e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/run_test
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+# 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.
+#
+
+#
+# Set up environment and run a test executable or script.
+#
+# Output nothing if test passes, show the output if it fails and
+# leave output in <test>.log for examination.
+#
+# If qpidd.port exists run test with QPID_PORT=`cat qpidd.port`
+#
+# If $VALGRIND if is set run under valgrind. If there are valgrind
+# erros show valgrind output, also leave it in <test>.valgrind for
+# examination.
+#
+
+srcdir=`dirname $0`
+. $srcdir/vg_check
+
+# Export variables from makefile.
+export VALGRIND srcdir
+
+# Set QPID_PORT if qpidd.port exists.
+test -f qpidd.port && QPID_PORT=`cat qpidd.port`
+export QPID_PORT
+
+# Avoid silly libtool error messages if these are not defined
+test -z "$LC_ALL" && LC_ALL=
+test -z "$LC_CTYPE" && LC_CTYPE=
+test -z "$LC_COLLATE" && LC_COLLATE=
+test -z "$LC_MESSAGES" && LC_MESSAGES=
+export LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+
+VG_LOG="`basename $1`.vglog"
+rm -f $VG_LOG*
+
+VALGRIND_OPTS="
+--gen-suppressions=all
+--leak-check=full
+--demangle=yes
+--suppressions=$srcdir/.valgrind.supp
+--num-callers=25
+--log-file=$VG_LOG --
+"
+# FIXME aconway 2008-07-16: removed --trace-children=yes, problems with cluster tests forking
+# qpidd libtool script. Investigate & restore --trace-children if possible.
+
+ERROR=0
+if grep -l "^# Generated by .*libtool" "$1" >/dev/null 2>&1; then
+ # This is a libtool "executable". Valgrind it if VALGRIND specified.
+ test -n "$VALGRIND" && VALGRIND="$VALGRIND $VALGRIND_OPTS"
+ # Hide output unless there's an error.
+ libtool --mode=execute $VALGRIND "$@" 2>&1 || ERROR=1
+ test -n "$VALGRIND" && { vg_check $VG_LOG* || ERROR=1 ; }
+else
+ # This is a non-libtool shell script, just execute it.
+ exec "$@"
+fi
+
+exit $ERROR
+
diff --git a/RC9/qpid/cpp/src/tests/sender.cpp b/RC9/qpid/cpp/src/tests/sender.cpp
new file mode 100644
index 0000000000..a02b713d86
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/sender.cpp
@@ -0,0 +1,100 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <qpid/client/FailoverManager.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/AsyncSession.h>
+#include <qpid/client/Message.h>
+#include <qpid/client/MessageReplayTracker.h>
+#include <qpid/Exception.h>
+#include "TestOptions.h"
+
+#include <iostream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::framing;
+
+using namespace std;
+
+struct Args : public qpid::TestOptions
+{
+ string destination;
+ string key;
+ uint sendEos;
+
+ Args() : key("test-queue"), sendEos(0)
+ {
+ addOptions()
+ ("exchange", qpid::optValue(destination, "EXCHANGE"), "Exchange to send messages to")
+ ("routing-key", qpid::optValue(key, "KEY"), "Routing key to add to messages")
+ ("send-eos", qpid::optValue(sendEos, "N"), "Send N EOS messages to mark end of input");
+ }
+};
+
+const string EOS("eos");
+
+class Sender : public FailoverManager::Command
+{
+ public:
+ Sender(const std::string& destination, const std::string& key, uint sendEos);
+ void execute(AsyncSession& session, bool isRetry);
+ private:
+ MessageReplayTracker sender;
+ Message message;
+ const uint sendEos;
+ uint sent;
+};
+
+Sender::Sender(const std::string& destination, const std::string& key, uint eos) :
+ sender(10), message(destination, key), sendEos(eos), sent(0) {}
+
+void Sender::execute(AsyncSession& session, bool isRetry)
+{
+ if (isRetry) sender.replay(session);
+ else sender.init(session);
+ string data;
+ while (std::cin >> data) {
+ message.setData(data);
+ message.getHeaders().setInt("sn", ++sent);
+ sender.send(message);
+ }
+ for (uint i = sendEos; i > 0; --i) {
+ message.setData(EOS);
+ sender.send(message);
+ }
+}
+
+int main(int argc, char ** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ FailoverManager connection(opts.con);
+ Sender sender(opts.destination, opts.key, opts.sendEos);
+ connection.execute(sender);
+ connection.close();
+ return 0;
+ } catch(const std::exception& error) {
+ std::cout << "Failed: " << error.what() << std::endl;
+ }
+ return 1;
+}
diff --git a/RC9/qpid/cpp/src/tests/shared_perftest b/RC9/qpid/cpp/src/tests/shared_perftest
new file mode 100755
index 0000000000..cc192d25bd
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/shared_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+exec `dirname $0`/run_perftest 100000 --mode shared --npubs 16 --nsubs 16
diff --git a/RC9/qpid/cpp/src/tests/shlibtest.cpp b/RC9/qpid/cpp/src/tests/shlibtest.cpp
new file mode 100644
index 0000000000..80320ea7be
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/shlibtest.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ *
+ */
+
+int* loaderData = 0;
+extern "C" void callMe(int *i) { loaderData=i; }
+
+struct OnUnload { ~OnUnload() { *loaderData=42; } };
+OnUnload unloader; // For destructor.
+
+
+
diff --git a/RC9/qpid/cpp/src/tests/ssl.mk b/RC9/qpid/cpp/src/tests/ssl.mk
new file mode 100644
index 0000000000..cb887c8fda
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ssl.mk
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+TESTS+=ssl_test
+EXTRA_DIST+=ssl_test
+clean-local:
+ rm -rf test_cert_db cert.password \ No newline at end of file
diff --git a/RC9/qpid/cpp/src/tests/ssl_test b/RC9/qpid/cpp/src/tests/ssl_test
new file mode 100755
index 0000000000..047db93d20
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/ssl_test
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Run a simple test over SSL
+
+CONFIG=$(dirname $0)/config.null
+CERT_DIR=`pwd`/test_cert_db
+CERT_PW_FILE=`pwd`/cert.password
+HOSTNAME=`hostname`
+COUNT=10000
+
+trap stop_broker EXIT
+
+error() { echo $*; exit 1; }
+
+create_certs() {
+ #create certificate and key databases with single, simple, self-signed certificate in it
+ mkdir ${CERT_DIR}
+ certutil -N -d ${CERT_DIR} -f ${CERT_PW_FILE}
+ certutil -S -d ${CERT_DIR} -n ${HOSTNAME} -s "CN=${HOSTNAME}" -t "CT,," -x -f ${CERT_PW_FILE} -z /usr/bin/certutil
+}
+
+start_broker() {
+ ../qpidd --daemon --transport ssl --port 0 --ssl-port 0 --no-data-dir --no-module-dir --auth no --config $CONFIG --load-module ../.libs/ssl.so --ssl-cert-db $CERT_DIR --ssl-cert-password-file $CERT_PW_FILE > qpidd.port
+ PORT=`cat qpidd.port`
+}
+
+stop_broker() {
+ if [[ $PORT ]] ; then
+ ../qpidd -q --port $PORT
+ fi
+}
+CERTUTIL=$(type -p certutil)
+if [[ !(-x $CERTUTIL) ]] ; then
+ echo "No certutil, skipping ssl test";
+ exit 0;
+fi
+
+if [[ !(-e ${CERT_PW_FILE}) ]] ; then
+ echo password > ${CERT_PW_FILE}
+fi
+if [[ !(-e ${CERT_DIR}) ]] ; then
+ create_certs || error "Could not create test certificate"
+fi
+
+start_broker || error "Could not start broker"
+echo "Running SSL test on port $PORT"
+export QPID_NO_MODULE_DIR=1
+export QPID_LOAD_MODULE=../.libs/sslconnector.so
+export QPID_SSL_CERT_DB=${CERT_DIR}
+export QPID_SSL_CERT_PASSWORD_FILE=${CERT_PW_FILE}
+./perftest --count ${COUNT} --port ${PORT} -P ssl -b $HOSTNAME --summary
+
diff --git a/RC9/qpid/cpp/src/tests/start_broker b/RC9/qpid/cpp/src/tests/start_broker
new file mode 100755
index 0000000000..093c44051a
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/start_broker
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Start a test broker.
+srcdir=`dirname $0`
+exec $srcdir/run_test ../qpidd --auth=no --no-module-dir --daemon --port=0 --log-to-file qpidd.log "$@" > qpidd.port
diff --git a/RC9/qpid/cpp/src/tests/start_cluster b/RC9/qpid/cpp/src/tests/start_cluster
new file mode 100755
index 0000000000..ee306edf14
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/start_cluster
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Start a cluster of brokers on local host, put the list of ports for cluster members in cluster.ports
+#
+
+# Execute command with the ais group set.
+with_ais_group() {
+ id -nG | grep '\<ais\>' >/dev/null || { echo "You are not a member of the ais group." 1>&2; exit 1; }
+ echo $* | newgrp ais
+}
+
+test -f cluster.ports && { echo "cluster.ports file already exists" ; exit 1; }
+rm -f cluster*.log
+SIZE=$1; shift
+CLUSTER=`pwd` # Cluster name=pwd, avoid clashes.
+OPTS="-d --load-module ../.libs/cluster.so --cluster-name=$CLUSTER --no-data-dir --auth=no $*"
+
+if test "$SIZE" = "one"; then # Special case of singleton cluster, use default port.
+ ../qpidd -q
+ with_ais_group ../qpidd $OPTS --log-to-file=cluster.log || exit 1
+else
+ for (( i=0; i<SIZE; ++i )); do
+ PORT=`with_ais_group ../qpidd -p0 --log-to-file=cluster$i.log $OPTS` || exit 1
+ echo $PORT >> cluster.ports
+ done
+fi
+
diff --git a/RC9/qpid/cpp/src/tests/start_cluster_hosts b/RC9/qpid/cpp/src/tests/start_cluster_hosts
new file mode 100755
index 0000000000..7680da01ad
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/start_cluster_hosts
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+#
+# Start a cluster of brokers on local host, put the list of host port addresses
+# in cluster.ports
+#
+# Arguments: [-k] [-p port] HOST [HOST...]
+# -p port to start broker on, can be 0. Actual ports recorded in cluster.addr.
+# -k kill any qpidd processes owned by this user before starting.
+#
+# Start a broker on each named host. Name a host twice to start multiple brokers.
+#
+# You must be able to ssh to each host and be in group ais.
+# $QPIDD must be executable on each host.
+# Logs go to syslog on each host, with a unique prefix per broker.
+#
+
+QPIDD=${QPIDD:-$PWD/../qpidd}
+LIBQPIDCLUSTER=${LIBQPIDCLUSTER:-$PWD/../.libs/cluster.so}
+NAME=$USER # User name is default cluster name.
+RESTART=NO
+
+while getopts "kp:n:q:r" ARG ; do
+ case $ARG in
+ k) KILL=yes ;;
+ p) PORT="$OPTARG" ;;
+ n) NAME=$OPTARG ;;
+ q) QPIDD=$OPTARG ;;
+ l) LIBQPIDCLUSTER=$OPTARG ;;
+ r) RESTART=yes ;;
+ *) echo "Error parsing options: $ARG"; exit 1 ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+test -n "$PORT" && PORTOPT="-p $PORT"
+test "$KILL" = yes && KILL="$QPIDD -q $PORTOPT ;"
+CLUSTER=${*:-$CLUSTER} # Use args or env
+test -z "$CLUSTER" && { echo Must specify at least one host; exit 1; }
+
+
+OPTS="-d $PORTOPT --load-module $LIBQPIDCLUSTER --cluster-name=$NAME --no-data-dir --auth=no --log-to-syslog --log-enable=info+"
+
+num=0
+for h in $CLUSTER; do
+ num=`expr $num + 1` # Give a unique log prefix to each node.
+ cmd="$KILL $QPIDD $OPTS --log-prefix $num.$h"
+ out=`echo "$cmd" | ssh $h newgrp ais` || { echo == $h error: $out ; exit 1; }
+ if [ "$PORT" = 0 ] ; then p=$out; else p=$PORT; fi
+ echo "$h $p"
+done
+
diff --git a/RC9/qpid/cpp/src/tests/stop_broker b/RC9/qpid/cpp/src/tests/stop_broker
new file mode 100755
index 0000000000..2f45309a2b
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/stop_broker
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Stop the broker, check for errors.
+#
+QPID_PORT=`cat qpidd.port`
+export QPID_PORT
+rm -f qpidd.port
+
+../qpidd --quit || ERROR=1
+
+# Check qpidd.log.
+egrep 'warning\|error\|critical' qpidd.log && {
+ echo "WARNING: Suspicious broker log entries in qpidd.log, above."
+}
+
+# Check valgrind log.
+if test -n "$VALGRIND"; then
+ . `dirname $0`/vg_check $VG_LOG*
+ vg_check qpidd.vglog* || ERROR=1
+fi
+
+exit $ERROR
diff --git a/RC9/qpid/cpp/src/tests/stop_cluster b/RC9/qpid/cpp/src/tests/stop_cluster
new file mode 100755
index 0000000000..b3f0e7395e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/stop_cluster
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+# Stop brokers on ports listed in cluster.ports
+
+PORTS=`cat cluster.ports`
+for PORT in $PORTS ; do
+ ../qpidd -qp $PORT || ERROR="$ERROR $PORT"
+done
+rm -f cluster.ports
+
+if [ -n "$ERROR" ]; then
+ echo "Errors stopping brokers on ports: $ERROR"
+ exit 1
+fi
diff --git a/RC9/qpid/cpp/src/tests/test_tools.h b/RC9/qpid/cpp/src/tests/test_tools.h
new file mode 100644
index 0000000000..37a6594f8a
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/test_tools.h
@@ -0,0 +1,94 @@
+#ifndef TEST_TOOLS_H
+#define TEST_TOOLS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "qpid/log/Logger.h"
+
+#include <limits.h> // Include before boost/test headers.
+#include <boost/test/test_tools.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/regex.hpp>
+#include <boost/assign/list_of.hpp>
+#include <vector>
+#include <ostream>
+
+// Print a sequence
+template <class T> std::ostream& seqPrint(std::ostream& o, const T& seq) {
+ std::copy(seq.begin(), seq.end(), std::ostream_iterator<typename T::value_type>(o, " "));
+ return o;
+}
+
+// Compare sequences
+template <class T, class U>
+bool seqEqual(const T& a, const U& b) {
+ typename T::const_iterator i = a.begin();
+ typename U::const_iterator j = b.begin();
+ while (i != a.end() && j != b.end() && *i == *j) { ++i; ++j; }
+ return (i == a.end()) && (j == b.end());
+}
+
+// ostream and == operators so we can compare vectors and boost::assign::list_of
+// with BOOST_CHECK_EQUALS
+namespace std { // In namespace std so boost can find them.
+
+template <class T>
+ostream& operator<<(ostream& o, const vector<T>& v) { return seqPrint(o, v); }
+
+template <class T>
+ostream& operator<<(ostream& o, const boost::assign_detail::generic_list<T>& l) { return seqPrint(o, l); }
+
+template <class T>
+bool operator == (const vector<T>& a, const boost::assign_detail::generic_list<T>& b) { return seqEqual(a, b); }
+
+template <class T>
+bool operator == (const boost::assign_detail::generic_list<T>& b, const vector<T>& a) { return seqEqual(a, b); }
+}
+
+/** NB: order of parameters is regex first, in line with
+ * CHECK(expected, actual) convention.
+ */
+inline bool regexPredicate(const std::string& re, const std::string& text) {
+ return boost::regex_match(text, boost::regex(re));
+}
+
+/** Check for regular expression match. You must #include <boost/regex.hpp> */
+#if (BOOST_VERSION < 103300)
+ #define BOOST_CHECK_REGEX(re, text)
+#else
+ #define BOOST_CHECK_REGEX(re, text) \
+ BOOST_CHECK_PREDICATE(regexPredicate, (re)(text))
+#endif
+
+/** Check if types of two objects (as given by typeinfo::name()) match. */
+#define BOOST_CHECK_TYPEID_EQUAL(a,b) BOOST_CHECK_EQUAL(typeid(a).name(),typeid(b).name())
+
+/**
+ * Supress all logging in a scope, restore to previous configuration in destructor.
+ */
+struct ScopedSuppressLogging {
+ typedef qpid::log::Logger Logger;
+ ScopedSuppressLogging(Logger& l=Logger::instance()) : logger(l), opts(l.getOptions()) { l.clear(); }
+ ~ScopedSuppressLogging() { logger.configure(opts); }
+ Logger& logger;
+ qpid::log::Options opts;
+};
+
+
+#endif /*!TEST_TOOLS_H*/
+
diff --git a/RC9/qpid/cpp/src/tests/topic_listener.cpp b/RC9/qpid/cpp/src/tests/topic_listener.cpp
new file mode 100644
index 0000000000..7bdc2c32de
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/topic_listener.cpp
@@ -0,0 +1,202 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * This file provides one half of a test and example of a pub-sub
+ * style of interaction. See topic_publisher.cpp for the other half,
+ * in which the logic for publishing is defined.
+ *
+ * This file contains the listener logic. A listener will subscribe to
+ * a logical 'topic'. It will count the number of messages it receives
+ * and the time elapsed between the first one and the last one. It
+ * recognises two types of 'special' message that tell it to (a) send
+ * a report containing this information, (b) shutdown (i.e. stop
+ * listening).
+ */
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/Session.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Time.h"
+#include "qpid/framing/FieldValue.h"
+#include <iostream>
+#include <sstream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using namespace qpid::framing;
+using namespace std;
+
+/**
+ * A message listener implementation in which the runtime logic is
+ * defined.
+ */
+class Listener : public MessageListener{
+ Session session;
+ SubscriptionManager& mgr;
+ const string responseQueue;
+ const bool transactional;
+ bool init;
+ int count;
+ AbsTime start;
+
+ void shutdown();
+ void report();
+public:
+ Listener(const Session& session, SubscriptionManager& mgr, const string& reponseQueue, bool tx);
+ virtual void received(Message& msg);
+ Subscription subscription;
+};
+
+/**
+ * A utility class for managing the options passed in.
+ */
+struct Args : public qpid::TestOptions {
+ int ack;
+ bool transactional;
+ bool durable;
+ int prefetch;
+ string statusqueue;
+
+ Args() : ack(0), transactional(false), durable(false), prefetch(0) {
+ addOptions()
+ ("ack", optValue(ack, "MODE"), "Ack frequency in messages (defaults to half the prefetch value)")
+ ("transactional", optValue(transactional), "Use transactions")
+ ("durable", optValue(durable), "subscribers should use durable queues")
+ ("prefetch", optValue(prefetch, "N"), "prefetch count (0 implies no flow control, and no acking)")
+ ("status-queue", optValue(statusqueue, "QUEUE-NAME"), "Message queue to put status messages on");
+ }
+};
+
+
+/**
+ * The main routine creates a Listener instance and sets it up to
+ * consume from a private queue bound to the exchange with the
+ * appropriate topic name.
+ */
+int main(int argc, char** argv){
+ try{
+ Args args;
+ args.parse(argc, argv);
+ if(args.help)
+ cout << args << endl;
+ else {
+ Connection connection;
+ args.open(connection);
+ AsyncSession session = connection.newSession();
+
+ //declare exchange, queue and bind them:
+ session.queueDeclare(arg::queue="response");
+ std::string control = "control_" + session.getId().str();
+ if (args.durable) {
+ session.queueDeclare(arg::queue=control, arg::durable=true);
+ } else {
+ session.queueDeclare(arg::queue=control, arg::exclusive=true, arg::autoDelete=true);
+ }
+ session.exchangeBind(arg::exchange="amq.topic", arg::queue=control, arg::bindingKey="topic_control");
+
+ //set up listener
+ SubscriptionManager mgr(session);
+ Listener listener(session, mgr, "response", args.transactional);
+ SubscriptionSettings settings;
+ if (args.prefetch) {
+ settings.autoAck = (args.ack ? args.ack : (args.prefetch / 2));
+ settings.flowControl = FlowControl::messageCredit(args.prefetch);
+ } else {
+ settings.acceptMode = ACCEPT_MODE_NONE;
+ settings.flowControl = FlowControl::unlimited();
+ }
+ listener.subscription = mgr.subscribe(listener, control, settings);
+ session.sync();
+
+ if( args.statusqueue.length() > 0 ) {
+ stringstream msg_str;
+ msg_str << "topic_listener: " << (int)getpid();
+ session.messageTransfer(arg::content=Message(msg_str.str(), args.statusqueue));
+ cout << "Ready status put on queue '" << args.statusqueue << "'" << endl;
+ }
+
+ if (args.transactional) {
+ session.txSelect();
+ }
+
+ cout << "topic_listener: listening..." << endl;
+ mgr.run();
+ if (args.durable) {
+ session.queueDelete(arg::queue=control);
+ }
+ session.close();
+ cout << "closing connection" << endl;
+ connection.close();
+ }
+ return 0;
+ } catch (const std::exception& error) {
+ cout << "topic_listener: " << error.what() << endl;
+ }
+ return 1;
+}
+
+Listener::Listener(const Session& s, SubscriptionManager& m, const string& _responseq, bool tx) :
+ session(s), mgr(m), responseQueue(_responseq), transactional(tx), init(false), count(0){}
+
+void Listener::received(Message& message){
+ if(!init){
+ start = now();
+ count = 0;
+ init = true;
+ cout << "Batch started." << endl;
+ }
+ string type = message.getHeaders().getAsString("TYPE");
+
+ if(string("TERMINATION_REQUEST") == type){
+ shutdown();
+ }else if(string("REPORT_REQUEST") == type){
+ subscription.accept(subscription.getUnaccepted()); // Accept everything upto this point
+ cout <<"Batch ended, sending report." << endl;
+ //send a report:
+ report();
+ init = false;
+ }else if (++count % 1000 == 0){
+ cout <<"Received " << count << " messages." << endl;
+ }
+}
+
+void Listener::shutdown(){
+ mgr.stop();
+}
+
+void Listener::report(){
+ AbsTime finish = now();
+ Duration time(start, finish);
+ stringstream reportstr;
+ reportstr << "Received " << count << " messages in "
+ << time/TIME_MSEC << " ms.";
+ Message msg(reportstr.str(), responseQueue);
+ msg.getHeaders().setString("TYPE", "REPORT");
+ session.messageTransfer(arg::destination="amq.direct", arg::content=msg, arg::acceptMode=1);
+ if(transactional){
+ sync(session).txCommit();
+ }
+}
+
diff --git a/RC9/qpid/cpp/src/tests/topic_perftest b/RC9/qpid/cpp/src/tests/topic_perftest
new file mode 100755
index 0000000000..cd440b2458
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/topic_perftest
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+exec `dirname $0`/run_perftest 10000 --mode topic --qt 16
diff --git a/RC9/qpid/cpp/src/tests/topic_publisher.cpp b/RC9/qpid/cpp/src/tests/topic_publisher.cpp
new file mode 100644
index 0000000000..f37ad2dc0e
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/topic_publisher.cpp
@@ -0,0 +1,224 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * This file provides one half of a test and example of a pub-sub
+ * style of interaction. See topic_listener.cpp for the other half, in
+ * which the logic for subscribers is defined.
+ *
+ * This file contains the publisher logic. The publisher will send a
+ * number of messages to the exchange with the appropriate routing key
+ * for the logical 'topic'. Once it has done this it will then send a
+ * request that each subscriber report back with the number of message
+ * it has received and the time that elapsed between receiving the
+ * first one and receiving the report request. Once the expected
+ * number of reports are received, it sends out a request that each
+ * subscriber shutdown.
+ */
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/MessageListener.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Monitor.h"
+#include <unistd.h>
+#include "qpid/sys/Time.h"
+#include <cstdlib>
+#include <iostream>
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using namespace std;
+
+/**
+ * The publishing logic is defined in this class. It implements
+ * message listener and can therfore be used to receive messages sent
+ * back by the subscribers.
+ */
+class Publisher {
+ AsyncSession session;
+ SubscriptionManager mgr;
+ LocalQueue queue;
+ const string controlTopic;
+ const bool transactional;
+ const bool durable;
+
+ string generateData(int size);
+
+public:
+ Publisher(const AsyncSession& session, const string& controlTopic, bool tx, bool durable);
+ int64_t publish(int msgs, int listeners, int size);
+ void terminate();
+};
+
+/**
+ * A utility class for managing the options passed in to the test
+ */
+struct Args : public TestOptions {
+ int messages;
+ int subscribers;
+ bool transactional;
+ bool durable;
+ int batches;
+ int delay;
+ int size;
+ string statusqueue;
+
+ Args() : messages(1000), subscribers(1),
+ transactional(false), durable(false),
+ batches(1), delay(0), size(256)
+ {
+ addOptions()
+ ("messages", optValue(messages, "N"), "how many messages to send")
+ ("subscribers", optValue(subscribers, "N"), "how many subscribers to expect reports from")
+ ("transactional", optValue(transactional), "client should use transactions")
+ ("durable", optValue(durable), "messages should be durable")
+ ("batches", optValue(batches, "N"), "how many batches to run")
+ ("delay", optValue(delay, "SECONDS"), "Causes a delay between each batch")
+ ("size", optValue(size, "BYTES"), "size of the published messages")
+ ("status-queue", optValue(statusqueue, "QUEUE-NAME"), "Message queue to read status messages from");
+ }
+};
+
+int main(int argc, char** argv) {
+ try{
+ Args args;
+ args.parse(argc, argv);
+ if(args.help)
+ cout << args << endl;
+ else {
+ Connection connection;
+ args.open(connection);
+ AsyncSession session = connection.newSession();
+
+ // If status-queue is defined, wait for all expected listeners to join in before we start
+ if( args.statusqueue.length() > 0 ) {
+ cout << "Waiting for " << args.subscribers << " listeners..." << endl;
+ SubscriptionManager statusSubs(session);
+ LocalQueue statusQ;
+ statusSubs.subscribe(statusQ, args.statusqueue);
+ for (int i = 0; i < args.subscribers; i++) {
+ Message m = statusQ.get();
+ if( m.getData().find("topic_listener: ", 0) == 0 ) {
+ cout << "Listener " << (i+1) << " of " << args.subscribers
+ << " is ready (pid " << m.getData().substr(16, m.getData().length() - 16)
+ << ")" << endl;
+ } else {
+ throw Exception(QPID_MSG("Unexpected message received on status queue: " << m.getData()));
+ }
+ }
+ }
+
+ if (args.transactional) {
+ session.txSelect();
+ }
+ session.queueDeclare(arg::queue="response");
+ session.exchangeBind(arg::exchange="amq.direct", arg::queue="response", arg::bindingKey="response");
+
+ Publisher publisher(session, "topic_control", args.transactional, args.durable);
+
+ int batchSize(args.batches);
+ int64_t max(0);
+ int64_t min(0);
+ int64_t sum(0);
+ for(int i = 0; i < batchSize; i++){
+ if(i > 0 && args.delay) sleep(args.delay);
+ int64_t msecs =
+ publisher.publish(args.messages,
+ args.subscribers,
+ args.size) / TIME_MSEC;
+ if(!max || msecs > max) max = msecs;
+ if(!min || msecs < min) min = msecs;
+ sum += msecs;
+ cout << "Completed " << (i+1) << " of " << batchSize
+ << " in " << msecs << "ms" << endl;
+ }
+ publisher.terminate();
+ int64_t avg = sum / batchSize;
+ if(batchSize > 1){
+ cout << batchSize << " batches completed. avg=" << avg <<
+ ", max=" << max << ", min=" << min << endl;
+ }
+ session.close();
+ connection.close();
+ }
+ return 0;
+ }catch(exception& error) {
+ cout << error.what() << endl;
+ }
+ return 1;
+}
+
+Publisher::Publisher(const AsyncSession& _session, const string& _controlTopic, bool tx, bool d) :
+ session(_session), mgr(session), controlTopic(_controlTopic), transactional(tx), durable(d)
+{
+ mgr.subscribe(queue, "response");
+}
+
+int64_t Publisher::publish(int msgs, int listeners, int size){
+ Message msg(generateData(size), controlTopic);
+ if (durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+ AbsTime start = now();
+
+ for(int i = 0; i < msgs; i++){
+ session.messageTransfer(arg::content=msg, arg::destination="amq.topic", arg::acceptMode=1);
+ }
+ //send report request
+ Message reportRequest("", controlTopic);
+ reportRequest.getHeaders().setString("TYPE", "REPORT_REQUEST");
+ session.messageTransfer(arg::content=reportRequest, arg::destination="amq.topic", arg::acceptMode=1);
+ if(transactional){
+ sync(session).txCommit();
+ }
+ //wait for a response from each listener (TODO, could log these)
+ for (int i = 0; i < listeners; i++) {
+ Message report = queue.pop();
+ }
+
+ if(transactional){
+ sync(session).txCommit();
+ }
+
+ AbsTime finish = now();
+ return Duration(start, finish);
+}
+
+string Publisher::generateData(int size){
+ string data;
+ for(int i = 0; i < size; i++){
+ data += ('A' + (i / 26));
+ }
+ return data;
+}
+
+void Publisher::terminate(){
+ //send termination request
+ Message terminationRequest("", controlTopic);
+ terminationRequest.getHeaders().setString("TYPE", "TERMINATION_REQUEST");
+ session.messageTransfer(arg::content=terminationRequest, arg::destination="amq.topic", arg::acceptMode=1);
+ if(transactional){
+ session.txCommit();
+ }
+}
diff --git a/RC9/qpid/cpp/src/tests/topictest b/RC9/qpid/cpp/src/tests/topictest
new file mode 100755
index 0000000000..8fd680ee35
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/topictest
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+#
+# 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.
+#
+
+# Run the C++ topic test
+
+# Clean up old log files
+rm -f subscriber_*.log
+
+# Defaults values
+SUBSCRIBERS=10
+MESSAGES=2000
+BATCHES=10
+
+while getopts "s:m:b:h:t" opt ; do
+ case $opt in
+ s) SUBSCRIBERS=$OPTARG ;;
+ m) MESSAGES=$OPTARG ;;
+ b) BATCHES=$OPTARG ;;
+ h) HOST=-h$OPTARG ;;
+ t) TRANSACTIONAL="--transactional --durable" ;;
+ ?)
+ echo "Usage: %0 [-s <subscribers>] [-m <messages.] [-b <batches>]"
+ exit 1
+ ;;
+ esac
+done
+
+subscribe() {
+ echo Start subscriber $1
+ LOG="subscriber_$1.log"
+ ./topic_listener $TRANSACTIONAL > $LOG 2>&1 && rm -f $LOG
+}
+
+publish() {
+ ./topic_publisher --messages $MESSAGES --batches $BATCHES --subscribers $SUBSCRIBERS $HOST $TRANSACTIONAL
+}
+
+for ((i=$SUBSCRIBERS ; i--; )); do
+ subscribe $i &
+done
+# FIXME aconway 2007-03-27: Hack around startup race. Fix topic test.
+sleep 2
+publish 2>&1 || exit 1
diff --git a/RC9/qpid/cpp/src/tests/txjob.cpp b/RC9/qpid/cpp/src/tests/txjob.cpp
new file mode 100644
index 0000000000..94db96a666
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/txjob.cpp
@@ -0,0 +1,95 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include "TestOptions.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/FailoverManager.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/sys/Thread.h"
+
+using namespace qpid::client;
+using namespace qpid::sys;
+
+struct Args : public qpid::TestOptions
+{
+ string workQueue;
+ string source;
+ string dest;
+ uint messages;
+ uint jobs;
+ bool quit;
+ bool declareQueues;
+
+ Args() : workQueue("txshift-control"), source("txshift-1"), dest("txshift-2"), messages(0), jobs(0),
+ quit(false), declareQueues(false)
+ {
+ addOptions()
+ ("messages", qpid::optValue(messages, "N"), "Number of messages to shift")
+ ("jobs", qpid::optValue(jobs, "N"), "Number of shift jobs to request")
+ ("source", qpid::optValue(source, "QUEUE NAME"), "source queue from which messages will be shifted")
+ ("dest", qpid::optValue(dest, "QUEUE NAME"), "dest queue to which messages will be shifted")
+ ("work-queue", qpid::optValue(workQueue, "QUEUE NAME"), "work queue from which to take instructions")
+ ("add-quit", qpid::optValue(quit), "add a 'quit' instruction to the queue (after any other jobs)")
+ ("declare-queues", qpid::optValue(declareQueues), "issue a declare for all queues");
+ }
+};
+
+//TODO: might be nice to make this capable of failover as well at some
+//point; for now its just for the setup phase.
+int main(int argc, char** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ Connection connection;
+ connection.open(opts.con);
+ Session session = connection.newSession();
+ if (opts.declareQueues) {
+ session.queueDeclare(arg::queue=opts.workQueue);
+ session.queueDeclare(arg::queue=opts.source);
+ session.queueDeclare(arg::queue=opts.dest);
+ }
+ for (uint i = 0; i < opts.jobs; ++i) {
+ Message job("transfer", opts.workQueue);
+ job.getHeaders().setString("src", opts.source);
+ job.getHeaders().setString("dest", opts.dest);
+ job.getHeaders().setInt("count", opts.messages);
+ async(session).messageTransfer(arg::content=job);
+ }
+
+ if (opts.quit) {
+ async(session).messageTransfer(arg::content=Message("quit", opts.workQueue));
+ }
+
+ session.sync();
+ session.close();
+
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/RC9/qpid/cpp/src/tests/txshift.cpp b/RC9/qpid/cpp/src/tests/txshift.cpp
new file mode 100644
index 0000000000..5db08d7a53
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/txshift.cpp
@@ -0,0 +1,185 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include "TestOptions.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/FailoverManager.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Thread.h"
+
+using namespace qpid::client;
+using namespace qpid::sys;
+
+struct Args : public qpid::TestOptions
+{
+ string workQueue;
+ size_t workers;
+
+ Args() : workQueue("txshift-control"), workers(1)
+ {
+ addOptions()
+ ("workers", qpid::optValue(workers, "N"), "Number of separate worker sessions to start")
+ ("work-queue", qpid::optValue(workQueue, "NAME"), "work queue from which to take instructions");
+ }
+};
+
+struct Transfer : MessageListener
+{
+ std::string control;
+ std::string source;
+ std::string destination;
+ uint expected;
+ uint transfered;
+ SubscriptionSettings controlSettings;
+ Subscription controlSubscription;
+ SubscriptionSettings sourceSettings;
+ Subscription sourceSubscription;
+
+ Transfer(const std::string control_) : control(control_), expected(0), transfered(0) {}
+
+ void subscribeToSource(SubscriptionManager& manager)
+ {
+ sourceSettings.autoAck = 0;//will accept once at the end of the batch
+ sourceSettings.flowControl = FlowControl::messageCredit(expected);
+ sourceSubscription = manager.subscribe(*this, source, sourceSettings);
+ QPID_LOG(info, "Subscribed to source: " << source << " expecting: " << expected);
+ }
+
+ void subscribeToControl(SubscriptionManager& manager)
+ {
+ controlSettings.flowControl = FlowControl::messageCredit(1);
+ controlSubscription = manager.subscribe(*this, control, controlSettings);
+ QPID_LOG(info, "Subscribed to job queue");
+ }
+
+ void received(Message& message)
+ {
+ QPID_LOG(debug, "received: " << message.getData() << " for " << message.getDestination());
+ if (message.getDestination() == source) {
+ receivedFromSource(message);
+ } else if (message.getDestination() == control) {
+ receivedFromControl(message);
+ } else {
+ QPID_LOG(error, "Unexpected message: " << message.getData() << " to " << message.getDestination());
+ }
+ }
+
+ void receivedFromSource(Message& message)
+ {
+ QPID_LOG(debug, "transfering " << (transfered+1) << " of " << expected);
+ message.getDeliveryProperties().setRoutingKey(destination);
+ async(sourceSubscription.getSession()).messageTransfer(arg::content=message);
+ if (++transfered == expected) {
+ QPID_LOG(info, "completed job: " << transfered << " messages shifted from " <<
+ source << " to " << destination);
+ sourceSubscription.accept(sourceSubscription.getUnaccepted());
+ sourceSubscription.getSession().txCommit();
+ sourceSubscription.cancel();
+ //grant credit to allow broker to send us another control message
+ controlSubscription.grantMessageCredit(1);
+ }
+ }
+
+ void receivedFromControl(Message& message)
+ {
+ if (message.getData() == "transfer") {
+ source = message.getHeaders().getAsString("src");
+ destination = message.getHeaders().getAsString("dest");
+ expected = message.getHeaders().getAsInt("count");
+ transfered = 0;
+ QPID_LOG(info, "received transfer request: " << expected << " messages to be shifted from " <<
+ source << " to " << destination);
+ subscribeToSource(controlSubscription.getSubscriptionManager());
+ } else if (message.getData() == "quit") {
+ QPID_LOG(info, "received quit request");
+ controlSubscription.cancel();
+ } else {
+ std::cerr << "Rejecting invalid message: " << message.getData() << std::endl;
+ controlSubscription.getSession().messageReject(SequenceSet(message.getId()));
+ }
+ }
+
+};
+
+struct Worker : FailoverManager::Command, Runnable
+{
+ FailoverManager& connection;
+ Transfer transfer;
+ Thread runner;
+
+ Worker(FailoverManager& c, const std::string& controlQueue) : connection(c), transfer(controlQueue) {}
+
+ void run()
+ {
+ connection.execute(*this);
+ }
+
+ void start()
+ {
+ runner = Thread(this);
+ }
+
+ void join()
+ {
+ runner.join();
+ }
+
+ void execute(AsyncSession& session, bool isRetry)
+ {
+ if (isRetry) QPID_LOG(info, "Retrying...");
+ session.txSelect();
+ SubscriptionManager subs(session);
+ transfer.subscribeToControl(subs);
+ subs.run();
+ }
+};
+
+int main(int argc, char** argv)
+{
+ Args opts;
+ try {
+ opts.parse(argc, argv);
+ FailoverManager connection(opts.con);
+ connection.connect();
+ if (opts.workers == 1) {
+ Worker worker(connection, opts.workQueue);
+ worker.run();
+ } else {
+ boost::ptr_vector<Worker> workers;
+ for (size_t i = 0; i < opts.workers; i++) {
+ workers.push_back(new Worker(connection, opts.workQueue));
+ }
+ for_each(workers.begin(), workers.end(), boost::bind(&Worker::start, _1));
+ for_each(workers.begin(), workers.end(), boost::bind(&Worker::join, _1));
+ }
+
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/RC9/qpid/cpp/src/tests/txtest.cpp b/RC9/qpid/cpp/src/tests/txtest.cpp
new file mode 100644
index 0000000000..0c8ce90648
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/txtest.cpp
@@ -0,0 +1,329 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <algorithm>
+#include <iomanip>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+#include "TestOptions.h"
+#include "qpid/client/Connection.h"
+#include "qpid/client/Message.h"
+#include "qpid/client/AsyncSession.h"
+#include "qpid/client/SubscriptionManager.h"
+#include "qpid/framing/Array.h"
+#include "qpid/framing/Buffer.h"
+#include "qpid/sys/uuid.h"
+
+using namespace qpid;
+using namespace qpid::client;
+using namespace qpid::sys;
+using std::string;
+
+typedef std::vector<std::string> StringSet;
+
+struct Args : public qpid::TestOptions {
+ bool init, transfer, check;//actions
+ uint size;
+ bool durable;
+ uint queues;
+ string base;
+ uint msgsPerTx;
+ uint txCount;
+ uint totalMsgCount;
+ bool dtx;
+ bool quiet;
+
+ Args() : init(true), transfer(true), check(true),
+ size(256), durable(true), queues(2),
+ base("tx-test"), msgsPerTx(1), txCount(1), totalMsgCount(10),
+ dtx(false), quiet(false)
+ {
+ addOptions()
+
+ ("init", optValue(init, "yes|no"), "Declare queues and populate one with the initial set of messages.")
+ ("transfer", optValue(transfer, "yes|no"), "'Move' messages from one queue to another using transactions to ensure no message loss.")
+ ("check", optValue(check, "yes|no"), "Check that the initial messages are all still available.")
+ ("size", optValue(size, "N"), "message size")
+ ("durable", optValue(durable, "yes|no"), "use durable messages")
+ ("queues", optValue(queues, "N"), "number of queues")
+ ("queue-base-name", optValue(base, "<name>"), "base name for queues")
+ ("messages-per-tx", optValue(msgsPerTx, "N"), "number of messages transferred per transaction")
+ ("tx-count", optValue(txCount, "N"), "number of transactions per 'agent'")
+ ("total-messages", optValue(totalMsgCount, "N"), "total number of messages in 'circulation'")
+ ("dtx", optValue(dtx, "yes|no"), "use distributed transactions")
+ ("quiet", optValue(quiet), "reduce output from test");
+ }
+};
+
+const std::string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+std::string generateData(uint size)
+{
+ if (size < chars.length()) {
+ return chars.substr(0, size);
+ }
+ std::string data;
+ for (uint i = 0; i < (size / chars.length()); i++) {
+ data += chars;
+ }
+ data += chars.substr(0, size % chars.length());
+ return data;
+}
+
+void generateSet(const std::string& base, uint count, StringSet& collection)
+{
+ for (uint i = 0; i < count; i++) {
+ std::ostringstream out;
+ out << base << "-" << (i+1);
+ collection.push_back(out.str());
+ }
+}
+
+Args opts;
+
+struct Client
+{
+ Connection connection;
+ AsyncSession session;
+
+ Client()
+ {
+ opts.open(connection);
+ session = connection.newSession();
+ }
+
+ ~Client()
+ {
+ try{
+ session.close();
+ connection.close();
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ }
+};
+
+struct Transfer : public Client, public Runnable
+{
+ std::string src;
+ std::string dest;
+ Thread thread;
+ uuid_t uuid;
+ char uuidStr[37]; // Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + trailing \0
+ framing::Xid xid;
+
+ Transfer(const std::string& to, const std::string& from) : src(to), dest(from), xid(0x4c414e47, "", from) {}
+
+ void run()
+ {
+ try {
+
+ if (opts.dtx) session.dtxSelect();
+ else session.txSelect();
+ SubscriptionManager subs(session);
+
+ LocalQueue lq;
+ SubscriptionSettings settings(FlowControl::messageWindow(opts.msgsPerTx));
+ settings.autoAck = 0; // Disabled
+ Subscription sub = subs.subscribe(lq, src, settings);
+
+ for (uint t = 0; t < opts.txCount; t++) {
+ Message in;
+ Message out("", dest);
+ if (opts.dtx) {
+ setNewXid(xid);
+ session.dtxStart(arg::xid=xid);
+ }
+ for (uint m = 0; m < opts.msgsPerTx; m++) {
+ in = lq.pop();
+ out.setData(in.getData());
+ out.getMessageProperties().setCorrelationId(in.getMessageProperties().getCorrelationId());
+ out.getDeliveryProperties().setDeliveryMode(in.getDeliveryProperties().getDeliveryMode());
+ session.messageTransfer(arg::content=out, arg::acceptMode=1);
+ }
+ sub.accept(sub.getUnaccepted());
+ if (opts.dtx) {
+ session.dtxEnd(arg::xid=xid);
+ session.dtxPrepare(arg::xid=xid);
+ session.dtxCommit(arg::xid=xid);
+ } else {
+ session.txCommit();
+ }
+ }
+ } catch(const std::exception& e) {
+ std::cout << "Transfer interrupted: " << e.what() << std::endl;
+ }
+ }
+
+ void setNewXid(framing::Xid& xid) {
+ ::uuid_generate(uuid);
+ ::uuid_unparse(uuid, uuidStr);
+ xid.setGlobalId(uuidStr);
+ }
+};
+
+struct Controller : public Client
+{
+ StringSet ids;
+ StringSet queues;
+
+ Controller()
+ {
+ generateSet(opts.base, opts.queues, queues);
+ generateSet("msg", opts.totalMsgCount, ids);
+ }
+
+ void init()
+ {
+ //declare queues
+ for (StringSet::iterator i = queues.begin(); i != queues.end(); i++) {
+ session.queueDeclare(arg::queue=*i, arg::durable=opts.durable);
+ session.sync();
+ }
+
+ Message msg(generateData(opts.size), *queues.begin());
+ if (opts.durable) {
+ msg.getDeliveryProperties().setDeliveryMode(framing::PERSISTENT);
+ }
+
+ //publish messages
+ for (StringSet::iterator i = ids.begin(); i != ids.end(); i++) {
+ msg.getMessageProperties().setCorrelationId(*i);
+ session.messageTransfer(arg::content=msg, arg::acceptMode=1);
+ }
+ }
+
+ void transfer()
+ {
+ boost::ptr_vector<Transfer> agents(opts.queues);
+ //launch transfer agents
+ for (StringSet::iterator i = queues.begin(); i != queues.end(); i++) {
+ StringSet::iterator next = i + 1;
+ if (next == queues.end()) next = queues.begin();
+
+ if (!opts.quiet) std::cout << "Transfering from " << *i << " to " << *next << std::endl;
+ agents.push_back(new Transfer(*i, *next));
+ agents.back().thread = Thread(agents.back());
+ }
+
+ for (boost::ptr_vector<Transfer>::iterator i = agents.begin(); i != agents.end(); i++) {
+ i->thread.join();
+ }
+ }
+
+ int check()
+ {
+ SubscriptionManager subs(session);
+
+ // Recover DTX transactions (if any)
+ if (opts.dtx) {
+ std::vector<std::string> inDoubtXids;
+ framing::DtxRecoverResult dtxRes = session.dtxRecover().get();
+ const framing::Array& xidArr = dtxRes.getInDoubt();
+ xidArr.collect(inDoubtXids);
+
+ if (inDoubtXids.size()) {
+ if (!opts.quiet) std::cout << "Recovering DTX in-doubt transaction(s):" << std::endl;
+ framing::StructHelper decoder;
+ framing::Xid xid;
+ // abort even, commit odd transactions
+ for (unsigned i = 0; i < inDoubtXids.size(); i++) {
+ decoder.decode(xid, inDoubtXids[i]);
+ if (!opts.quiet) std::cout << (i%2 ? " * aborting " : " * committing ");
+ xid.print(std::cout);
+ std::cout << std::endl;
+ if (i%2) {
+ session.dtxRollback(arg::xid=xid);
+ } else {
+ session.dtxCommit(arg::xid=xid);
+ }
+ }
+ }
+ }
+
+ StringSet drained;
+ //drain each queue and verify the correct set of messages are available
+ for (StringSet::iterator i = queues.begin(); i != queues.end(); i++) {
+ //subscribe, allocate credit and flushn
+ LocalQueue lq;
+ SubscriptionSettings settings(FlowControl::unlimited(), ACCEPT_MODE_NONE);
+ subs.subscribe(lq, *i, settings);
+ session.messageFlush(arg::destination=*i);
+ session.sync();
+
+ uint count(0);
+ while (!lq.empty()) {
+ Message m = lq.pop();
+ //add correlation ids of received messages to drained
+ drained.push_back(m.getMessageProperties().getCorrelationId());
+ ++count;
+ }
+ if (!opts.quiet) std::cout << "Drained " << count << " messages from " << *i << std::endl;
+ }
+
+ sort(ids.begin(), ids.end());
+ sort(drained.begin(), drained.end());
+
+ //check that drained == ids
+ StringSet missing;
+ set_difference(ids.begin(), ids.end(), drained.begin(), drained.end(), back_inserter(missing));
+
+ StringSet extra;
+ set_difference(drained.begin(), drained.end(), ids.begin(), ids.end(), back_inserter(extra));
+
+ if (missing.empty() && extra.empty()) {
+ std::cout << "All expected messages were retrieved." << std::endl;
+ return 0;
+ } else {
+ if (!missing.empty()) {
+ std::cout << "The following ids were missing:" << std::endl;
+ for (StringSet::iterator i = missing.begin(); i != missing.end(); i++) {
+ std::cout << " '" << *i << "'" << std::endl;
+ }
+ }
+ if (!extra.empty()) {
+ std::cout << "The following extra ids were encountered:" << std::endl;
+ for (StringSet::iterator i = extra.begin(); i != extra.end(); i++) {
+ std::cout << " '" << *i << "'" << std::endl;
+ }
+ }
+ return 1;
+ }
+ }
+};
+
+int main(int argc, char** argv)
+{
+ try {
+ opts.parse(argc, argv);
+ Controller controller;
+ if (opts.init) controller.init();
+ if (opts.transfer) controller.transfer();
+ if (opts.check) return controller.check();
+ return 0;
+ } catch(const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ return 2;
+}
diff --git a/RC9/qpid/cpp/src/tests/unit_test.cpp b/RC9/qpid/cpp/src/tests/unit_test.cpp
new file mode 100644
index 0000000000..00c61242e4
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/unit_test.cpp
@@ -0,0 +1,23 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Defines test_main function to link with actual unit test code.
+#define BOOST_AUTO_TEST_MAIN // Boost 1.33
+#define BOOST_TEST_MAIN
+#include "unit_test.h"
+
diff --git a/RC9/qpid/cpp/src/tests/unit_test.h b/RC9/qpid/cpp/src/tests/unit_test.h
new file mode 100644
index 0000000000..df3ebfb1fe
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/unit_test.h
@@ -0,0 +1,86 @@
+#ifndef QPIPD_TEST_UNIT_TEST_H_
+#define QPIPD_TEST_UNIT_TEST_H_
+
+/*
+ *
+ * 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.
+ *
+ */
+
+// Workaround so we can build against boost 1.33 and boost 1.34.
+// Remove when we no longer need to support 1.33.
+//
+#include <boost/version.hpp>
+#include <limits.h> // Must be inclued beofre boost/test headers.
+
+// #include the correct header file.
+//
+#if (BOOST_VERSION < 103400)
+# include <boost/test/auto_unit_test.hpp>
+#else
+# include <boost/test/unit_test.hpp>
+#endif // BOOST_VERSION
+
+// Workarounds for BOOST_AUTO_TEST_CASE|SUITE|SUITE_END
+//
+#if (BOOST_VERSION < 103300)
+
+# define QPID_AUTO_TEST_SUITE(name)
+# define QPID_AUTO_TEST_CASE(name) BOOST_AUTO_UNIT_TEST(name)
+# define QPID_AUTO_TEST_SUITE_END()
+
+#elif (BOOST_VERSION < 103400)
+// Note the trailing ';'
+# define QPID_AUTO_TEST_SUITE(name) BOOST_AUTO_TEST_SUITE(name);
+# define QPID_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END();
+
+#endif // Workarounds for BOOST_AUTO_TEST_CASE|SUITE|SUITE_END
+
+// Workaround for BOOST_AUTO_TEST_SUITE_EXPECTED_FAILURES
+//
+#if (BOOST_VERSION < 103600)
+
+// Keep the test function for compilation but do not not register it.
+// TODO aconway 2008-04-23: better workaround for expected failures.
+# define QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(test_name,n) \
+ namespace { struct test_name { void test_method(); }; } \
+ void test_name::test_method()
+
+#endif // Workaround for BOOST_AUTO_TEST_SUITE_EXPECTED_FAILURES
+
+//
+// Default definitions for latest version of boost.
+//
+
+#ifndef QPID_AUTO_TEST_SUITE
+# define QPID_AUTO_TEST_SUITE(name) BOOST_AUTO_TEST_SUITE(name)
+#endif
+
+#ifndef QPID_AUTO_TEST_CASE
+# define QPID_AUTO_TEST_CASE(name) BOOST_AUTO_TEST_CASE(name)
+#endif
+
+#ifndef QPID_AUTO_TEST_CASE_EXPECTED_FAILURES
+# define QPID_AUTO_TEST_CASE_EXPECTED_FAILURES(name,n) BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(name,n)
+#endif
+
+#ifndef QPID_AUTO_TEST_SUITE_END
+# define QPID_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
+#endif
+
+#endif // !QPIPD_TEST_UNIT_TEST_H_
diff --git a/RC9/qpid/cpp/src/tests/vg_check b/RC9/qpid/cpp/src/tests/vg_check
new file mode 100644
index 0000000000..c5a1e6d2d0
--- /dev/null
+++ b/RC9/qpid/cpp/src/tests/vg_check
@@ -0,0 +1,24 @@
+# Check for valgrind errors. Sourced by test scripts.
+
+vg_failed() {
+ echo "Valgrind error log in $VG_LOG." 1>&2
+ cat $VG_LOG 1>&2
+ echo $1 1>&2
+ exit 1
+}
+
+vg_check()
+{
+ test -z "$1" || VG_LOG=$1
+ test -f $VG_LOG || vg_failed Valgrind log file $VG_LOG missing.
+ # Ensure there is an ERROR SUMMARY line.
+ grep -E '^==[0-9]+== ERROR SUMMARY:' $VG_LOG > /dev/null || \
+ vg_failed "No valgrind ERROR SUMMARY line in $VG_LOG."
+ # Ensure that the number of errors is 0.
+ grep -E '^==[0-9]+== ERROR SUMMARY: [^0]' $VG_LOG > /dev/null && \
+ vg_failed "Valgrind reported errors in $VG_LOG; see above."
+ # Check for leaks.
+ grep -E '^==[0-9]+== +.* lost: [^0]' $VG_LOG && \
+ vg_failed "Found memory leaks (see log file, $VG_LOG); see above."
+ true
+}