From baae218dacf7b5e56b52602ad4fbf2be0b81a2af Mon Sep 17 00:00:00 2001 From: Alan Conway Date: Tue, 26 Jun 2007 02:11:55 +0000 Subject: 2007-06-25 Cluster class implementing cluster membership map. * src/qpid/cluster/Cluster.cpp: Cluster membership implementation. * src/qpid/cluster/Cpg.cpp: Support for boost::function callbacks. * src/tests/Url.cpp: Implements AMQP-95 URL format. * xml/cluster.xml: Cluster join method. Build/packaging * README: Remove mention of openais till clustering is functional. For now it is optional and we depend on an unpackaged version. * configure.ac: Check openais has cpg_local_get(). * Makefile.am: Added cluster.xml to EXTRA_DIST. * src/generate.sh: add cluster.xml to codegen. * src/tests/Makefile.am: - Generate individual "sudo -u ais" wrappers for openais tests. - Drop "unit" directory, all unit tests in "tests" directory Minor changes: * src/qpid/sys/posix/Socket.cpp: * src/qpid/sys/posix/PosixAcceptor.cpp: * src/qpid/sys/posix/EventChannelAcceptor.cpp: * src/qpid/sys/apr/APRAcceptor.cpp: * src/qpid/sys/Acceptor.h (getHost): Added getHost() * src/tests/.valgrind.supp-default: Suppress benign valgrind warning in libcpg. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@550658 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/cpp/src/tests/.valgrind.supp-default | 9 + qpid/cpp/src/tests/Cluster.cpp | 72 ++++++ qpid/cpp/src/tests/Cluster.h | 83 +++++++ qpid/cpp/src/tests/Cpg.cpp | 107 +++++++++ qpid/cpp/src/tests/Makefile.am | 53 +++-- qpid/cpp/src/tests/Url.cpp | 56 +++++ qpid/cpp/src/tests/ais_unit_tests | 2 - qpid/cpp/src/tests/cluster.mk | 38 +-- qpid/cpp/src/tests/logging.cpp | 375 ++++++++++++++++++++++++++++++ qpid/cpp/src/tests/run_test | 6 +- qpid/cpp/src/tests/test_tools.h | 56 +++++ qpid/cpp/src/tests/unit/Cpg.cpp | 97 -------- qpid/cpp/src/tests/unit/Url.cpp | 55 ----- qpid/cpp/src/tests/unit/logging.cpp | 374 ----------------------------- qpid/cpp/src/tests/unit/test_tools.h | 53 ----- 15 files changed, 815 insertions(+), 621 deletions(-) create mode 100644 qpid/cpp/src/tests/Cluster.cpp create mode 100644 qpid/cpp/src/tests/Cluster.h create mode 100644 qpid/cpp/src/tests/Cpg.cpp create mode 100644 qpid/cpp/src/tests/Url.cpp delete mode 100755 qpid/cpp/src/tests/ais_unit_tests create mode 100644 qpid/cpp/src/tests/logging.cpp create mode 100644 qpid/cpp/src/tests/test_tools.h delete mode 100644 qpid/cpp/src/tests/unit/Cpg.cpp delete mode 100644 qpid/cpp/src/tests/unit/Url.cpp delete mode 100644 qpid/cpp/src/tests/unit/logging.cpp delete mode 100644 qpid/cpp/src/tests/unit/test_tools.h (limited to 'qpid/cpp/src/tests') diff --git a/qpid/cpp/src/tests/.valgrind.supp-default b/qpid/cpp/src/tests/.valgrind.supp-default index 8b13789179..21fa58db45 100644 --- a/qpid/cpp/src/tests/.valgrind.supp-default +++ b/qpid/cpp/src/tests/.valgrind.supp-default @@ -1 +1,10 @@ +{ + Benign error in libcpg. + + Memcheck:Param + socketcall.sendmsg(msg.msg_iov[i]) + obj:*/libpthread-2.5.so + obj:*/libcpg.so.2.0.0 +} + diff --git a/qpid/cpp/src/tests/Cluster.cpp b/qpid/cpp/src/tests/Cluster.cpp new file mode 100644 index 0000000000..ed50cc5d7b --- /dev/null +++ b/qpid/cpp/src/tests/Cluster.cpp @@ -0,0 +1,72 @@ +/* + * + * 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. + * + */ + +#define BOOST_AUTO_TEST_MAIN // Must come before #include +#include +#include "test_tools.h" +#include "Cluster.h" +#include "qpid/framing/ChannelOkBody.h" +#include "qpid/framing/BasicGetOkBody.h" + + + +static const ProtocolVersion VER; + +/** Verify membership ind a cluster with one member. */ +BOOST_AUTO_TEST_CASE(clusterOne) { + VectorFrameHandler received; + Cluster cluster("Test", "amqp:one:1", received, VER); + AMQFrame frame(VER, 1, new ChannelOkBody(VER)); + + cluster.handle(frame); + BOOST_REQUIRE(received.waitFor(1)); + BOOST_CHECK_EQUAL(1u, cluster.size()); + Cluster::MemberList members = cluster.getMembers(); + BOOST_CHECK_EQUAL(1u, members.size()); + BOOST_REQUIRE_EQUAL(members.front()->url, "amqp:one:1"); + BOOST_CHECK_EQUAL(1u, received.size()); + BOOST_CHECK_TYPEID_EQUAL(ChannelOkBody, *received[0].getBody()); +} + +/** Fork a process to verify membership in a cluster with two members */ +BOOST_AUTO_TEST_CASE(clusterTwo) { + VectorFrameHandler received; + pid_t pid=fork(); + BOOST_REQUIRE(pid >= 0); + if (pid) { // Parent + TestCluster cluster("Test", "amqp::1", received, VER); + BOOST_REQUIRE(cluster.waitFor(2)); + + // Exchange frames with child. + AMQFrame frame(VER, 1, new ChannelOkBody(VER)); + cluster.handle(frame); + BOOST_REQUIRE(received.waitFor(2)); + BOOST_CHECK_TYPEID_EQUAL(ChannelOkBody, *received[0].getBody()); + BOOST_CHECK_TYPEID_EQUAL(BasicGetOkBody, *received[1].getBody()); + + // Wait for child to exit. + int status; + BOOST_CHECK_EQUAL(::wait(&status), pid); + BOOST_CHECK_EQUAL(0, status); + BOOST_CHECK(cluster.waitFor(1)); + BOOST_CHECK_EQUAL(1u, cluster.size()); + } + else { // Child + BOOST_REQUIRE(execl("Cluster_child", "Cluster_child", NULL)); + } +} diff --git a/qpid/cpp/src/tests/Cluster.h b/qpid/cpp/src/tests/Cluster.h new file mode 100644 index 0000000000..7ca5445e10 --- /dev/null +++ b/qpid/cpp/src/tests/Cluster.h @@ -0,0 +1,83 @@ +#ifndef CLUSTER_H +#define CLUSTER_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/cluster/Cluster.h" +#include "qpid/framing/AMQFrame.h" +#include "qpid/framing/ChannelOkBody.h" +#include "qpid/framing/BasicGetOkBody.h" +#include "qpid/log/Logger.h" +#include +#include + +/** + * Definitions for the Cluster.cpp and Cluster_child.cpp child program. + */ + +// using namespace in header file is bad manners, but this is strictly for +// the tests. +using namespace std; +using namespace qpid; +using namespace qpid::cluster; +using namespace qpid::framing; +using namespace qpid::sys; + +struct TestCluster : public Cluster { + TestCluster(const std::string& name, + const std::string& url, + framing::FrameHandler& next, + framing::ProtocolVersion ver) : Cluster(name,url,next, ver) {} + + /** Wait for the cluster to be of expected size (exactly) */ + bool waitFor(size_t n) { + Mutex::ScopedLock l(lock); + AbsTime deadline(now(),2*TIME_SEC); + while(size() != n && lock.wait(deadline)) + ; + return size() == n; + } +}; + +struct VectorFrameHandler : + public std::vector, public FrameHandler, public Monitor + +{ + void handle(AMQFrame& f) { + ScopedLock l(*this); + push_back(f); + notifyAll(); + } + + /** Wait for vector to reach size n exactly */ + bool waitFor(size_t n) { + ScopedLock l(*this); + AbsTime deadline(now(), 1*TIME_SEC); + while (size() != n && wait(deadline)) + ; + return size() == n; + } +}; + + +// namespace + + + +#endif /*!CLUSTER_H*/ diff --git a/qpid/cpp/src/tests/Cpg.cpp b/qpid/cpp/src/tests/Cpg.cpp new file mode 100644 index 0000000000..97b829ea63 --- /dev/null +++ b/qpid/cpp/src/tests/Cpg.cpp @@ -0,0 +1,107 @@ +/* + * + * 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. + * + */ + +#define BOOST_AUTO_TEST_MAIN // Must come before #include +#include +#include "test_tools.h" +#include "qpid/cluster/Cpg.h" +#include "qpid/framing/AMQBody.h" +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace qpid::cluster; +using namespace qpid::framing; + +// For debugging: op << for CPG types. + +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 <<","< +ostream& operator<<(ostream& o, const pair& array) { + o << "{ "; + ostream_iterator i(o, " "); + copy(array.first, array.first+array.second, i); + cout << "}"; + return o; +} + +struct Callback { + Callback(const string group_) : group(group_) {} + string group; + vector delivered; + vector configChanges; + + void deliver ( + cpg_handle_t /*handle*/, + struct cpg_name *grp, + uint32_t /*nodeid*/, + uint32_t /*pid*/, + void* msg, + int msg_len) + { + BOOST_CHECK_EQUAL(group, Cpg::str(*grp)); + delivered.push_back(string((char*)msg,msg_len)); + } + + void configChange( + cpg_handle_t /*handle*/, + struct cpg_name *grp, + struct cpg_address */*members*/, int nMembers, + struct cpg_address */*left*/, int /*nLeft*/, + struct cpg_address */*joined*/, int /*nJoined*/ + ) + { + BOOST_CHECK_EQUAL(group, Cpg::str(*grp)); + configChanges.push_back(nMembers); + } +}; + +BOOST_AUTO_TEST_CASE(Cpg_basic) { + // Verify basic functionality of cpg. This will catch any + // openais configuration or permission errors. + // + Cpg::Name group("foo"); + Callback cb(group.str()); + Cpg::DeliverFn deliver=boost::bind(&Callback::deliver, &cb, _1, _2, _3, _4, _5, _6); + Cpg::ConfigChangeFn reconfig=boost::bind(&Callback::configChange, &cb, _1, _2, _3, _4, _5, _6, _7, _8); + + Cpg cpg(deliver, reconfig); + cpg.join(group); + iovec iov = { (void*)"Hello!", 6 }; + cpg.mcast(group, &iov, 1); + cpg.leave(group); + cpg.dispatchSome(); + + BOOST_REQUIRE_EQUAL(1u, cb.delivered.size()); + BOOST_CHECK_EQUAL("Hello!", cb.delivered.front()); + BOOST_REQUIRE_EQUAL(2u, cb.configChanges.size()); + BOOST_CHECK_EQUAL(1, cb.configChanges[0]); + BOOST_CHECK_EQUAL(0, cb.configChanges[1]); +} + diff --git a/qpid/cpp/src/tests/Makefile.am b/qpid/cpp/src/tests/Makefile.am index 76d675ee12..ab772ea744 100644 --- a/qpid/cpp/src/tests/Makefile.am +++ b/qpid/cpp/src/tests/Makefile.am @@ -1,25 +1,34 @@ AM_CXXFLAGS = $(WARNING_CFLAGS) $(CPPUNIT_CXXFLAGS) $(APR_CXXFLAGS) INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../gen -I$(top_builddir)/src/gen +abs_builddir=@abs_builddir@ +extra_libs = $(CPPUNIT_LIBS) +lib_client = $(abs_builddir)/../libqpidclient.la +lib_common = $(abs_builddir)/../libqpidcommon.la +lib_broker = $(abs_builddir)/../libqpidbroker.la + # -# Unit test programs. +# Initialize variables that are incremented with += # -UNIT_TESTS= +check_PROGRAMS= +unit_progs= +unit_wrappers= -UNIT_TESTS+=logging -logging_SOURCES=unit/logging.cpp unit/test_tools.h -logging_LDADD=-lboost_unit_test_framework -lboost_regex $(lib_common) +# +# Unit test programs. +# +unit_progs+=logging +logging_SOURCES=logging.cpp test_tools.h +logging_LDADD=-lboost_unit_test_framework -lboost_regex $(lib_common) -UNIT_TESTS+=Url -Url_SOURCES=unit/Url.cpp unit/test_tools.h -Url_LDADD=-lboost_unit_test_framework $(lib_common) +unit_progs+=Url +Url_SOURCES=Url.cpp test_tools.h +Url_LDADD=-lboost_unit_test_framework $(lib_common) -if CLUSTER include cluster.mk -endif # NB: CppUnit test libraries below will be migrated to boost test programs. -# UNIT_TESTS+= ... +# # Unit tests broker_unit_tests = \ @@ -74,7 +83,7 @@ testprogs = \ topic_publisher -check_PROGRAMS = $(UNIT_TESTS) $(AIS_UNIT_TESTS) $(testprogs) interop_runner +check_PROGRAMS += $(unit_progs) $(testprogs) interop_runner # FIXME aconway 2007-05-30: TESTS_ENVIRONMENT should have ./run_test # as below to run valgrind on all test programs. @@ -83,13 +92,12 @@ check_PROGRAMS = $(UNIT_TESTS) $(AIS_UNIT_TESTS) $(testprogs) interop_runner #TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir) ./run_test TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir) -SYSTEM_TESTS = client_test quick_topictest -TESTS = $(UNIT_TESTS) run-unit-tests $(RUN_AIS_TESTS) start_broker $(SYSTEM_TESTS) python_tests kill_broker daemon_test +system_tests = client_test quick_topictest +TESTS = dummy_test $(unit_progs) $(unit_wrappers) run-unit-tests start_broker $(system_tests) python_tests kill_broker daemon_test EXTRA_DIST = \ test_env run_test \ run-unit-tests start_broker python_tests kill_broker daemon_test \ - ais_unit_tests \ quick_topictest \ topictest \ .valgrind.supp-default \ @@ -106,12 +114,6 @@ check_LTLIBRARIES += libdlclose_noop.la libdlclose_noop_la_LDFLAGS = -module -rpath /home/aconway/svn/qpid/cpp/tests libdlclose_noop_la_SOURCES = dlclose_noop.c -abs_builddir = @abs_builddir@ -extra_libs = $(CPPUNIT_LIBS) -lib_client = $(abs_builddir)/../libqpidclient.la -lib_common = $(abs_builddir)/../libqpidcommon.la -lib_broker = $(abs_builddir)/../libqpidbroker.la - gen.mk: Makefile.am ( \ for i in $(testprogs); do \ @@ -131,11 +133,14 @@ gen.mk: Makefile.am > $@-t mv $@-t $@ -check: .valgrindrc .valgrind.supp - check-unit: $(MAKE) check TESTS=$(UNIT_TESTS) run-unit-tests +# Dummy test to force necessary test files to be generated. +dummy_test: .valgrind.supp .valgrindrc + { echo "#!/bin/sh"; echo "# Dummy test, does nothing. "; } > $@ + chmod a+x $@ + # Create a copy so that can be modified without risk of committing the changes. .valgrindrc: .valgrindrc-default cp $^ $@ @@ -147,7 +152,7 @@ check-unit: # ltmain invocations, one may corrupt the temporaries of the other. .NOTPARALLEL: -CLEANFILES=valgrind.out qpidd.log .valgrindrc .valgrind.supp +CLEANFILES=valgrind.out qpidd.log .valgrindrc .valgrind.supp dummy_test $(unit_wrappers) MAINTAINERCLEANFILES=gen.mk interop_runner_SOURCES = \ diff --git a/qpid/cpp/src/tests/Url.cpp b/qpid/cpp/src/tests/Url.cpp new file mode 100644 index 0000000000..09aabb80b3 --- /dev/null +++ b/qpid/cpp/src/tests/Url.cpp @@ -0,0 +1,56 @@ +/* + * + * 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. + * + */ + +#define BOOST_AUTO_TEST_MAIN // Must come before #include +#include +#include "test_tools.h" +#include "qpid/Url.h" +#include + +using namespace std; +using namespace qpid; +using namespace boost::assign; + +BOOST_AUTO_TEST_CASE(testUrl_str) { + Url url; + url.push_back(TcpAddress("foo.com")); + url.push_back(TcpAddress("bar.com", 6789)); + + BOOST_CHECK_EQUAL( + url.str(), "amqp:tcp:foo.com:5672,tcp:bar.com:6789"); + BOOST_CHECK_EQUAL(Url().str(), "amqp:"); +} + + +BOOST_AUTO_TEST_CASE(testUrl_ctor) { + BOOST_CHECK_EQUAL( + Url("amqp:foo.com,tcp:bar.com:1234").str(), + "amqp:tcp:foo.com:5672,tcp:bar.com:1234"); + BOOST_CHECK_EQUAL( + Url("amqp:foo/ignorethis").str(), + "amqp:tcp:foo:5672"); + BOOST_CHECK_EQUAL("amqp:tcp::5672", Url("amqp:").str()); + BOOST_CHECK_EQUAL(0u, Url("xxx", nothrow).size()); + try { + Url invalid("xxx"); + BOOST_FAIL("Expected InvalidUrl exception"); + } + catch (const Url::InvalidUrl&) {} +} + + diff --git a/qpid/cpp/src/tests/ais_unit_tests b/qpid/cpp/src/tests/ais_unit_tests deleted file mode 100755 index 9758891891..0000000000 --- a/qpid/cpp/src/tests/ais_unit_tests +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -make check-ais diff --git a/qpid/cpp/src/tests/cluster.mk b/qpid/cpp/src/tests/cluster.mk index 489eec748e..fd8f789363 100644 --- a/qpid/cpp/src/tests/cluster.mk +++ b/qpid/cpp/src/tests/cluster.mk @@ -1,23 +1,35 @@ -#-*-Makefile-*- +if CLUSTER # Cluster tests makefile fragment, to be included in Makefile.am # lib_cluster = $(abs_builddir)/../libqpidcluster.la -# -# AIS_UNIT_TESTS must be called with gid=ais. They are run -# separately under sudo -u ais. -# -AIS_UNIT_TESTS= -AIS_UNIT_TESTS+=Cpg -Cpg_SOURCES=unit/Cpg.cpp -Cpg_LDADD=-lboost_unit_test_framework $(lib_cluster) - -RUN_AIS_TESTS=ais_unit_tests # Run ais unit tests via check-ais. +# NOTE: Programs using the openais library must be run with gid=ais +# Such programs are built as *.ais, with a wrapper script *.sh that +# runs the program under sudo -u ais. +# +# Rule to generate wrappers. # The chmod is a horrible hack to allow libtools annoying wrapers to # relink the executable when run as user ais. -check-ais: $(AIS_UNIT_TESTS) +.ais.sh: + echo sudo -u ais env VALGRIND=$(VALGRIND) srcdir=$(srcdir) $(srcdir)/run_test ./$< >$@; chmod a+x $@ chmod a+rwx . .libs - sudo -u ais $(MAKE) check TESTS=$(AIS_UNIT_TESTS) +# Cluster tests. +# +check_PROGRAMS+=Cpg.ais +Cpg_ais_SOURCES=Cpg.cpp +Cpg_ais_LDADD=$(lib_cluster) -lboost_unit_test_framework +unit_wrappers+=Cpg.sh + +check_PROGRAMS+=Cluster.ais +Cluster_ais_SOURCES=Cluster.cpp Cluster.h +Cluster_ais_LDADD=$(lib_cluster) -lboost_unit_test_framework +unit_wrappers+=Cluster.sh + +check_PROGRAMS+=Cluster_child +Cluster_child_SOURCES=Cluster_child.cpp Cluster.h +Cluster_child_LDADD=$(lib_cluster) -lboost_test_exec_monitor + +endif diff --git a/qpid/cpp/src/tests/logging.cpp b/qpid/cpp/src/tests/logging.cpp new file mode 100644 index 0000000000..ebe8f4d6e8 --- /dev/null +++ b/qpid/cpp/src/tests/logging.cpp @@ -0,0 +1,375 @@ +/* + * + * 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. + * + */ + +#define BOOST_AUTO_TEST_MAIN // Must come before #include +#include +#include "test_tools.h" +#include "qpid/log/Logger.h" +#include "qpid/log/Options.h" +#include "qpid/memory.h" +#include "qpid/CommonOptions.h" +#include +#include +#include +#include +#include + + +using namespace std; +using namespace boost; +using namespace qpid::log; + +BOOST_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(string("void testStatementInit()"), s.function); + BOOST_CHECK_EQUAL(debug, s.level); +} + + +BOOST_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")); +} + +Logger& clearLogger() { + Logger::instance().clear(); + return Logger::instance(); +} + +BOOST_AUTO_TEST_CASE(testStatementEnabled) { + // Verify that the logger enables and disables log statements. + Logger& l=clearLogger(); + l.select(Selector(debug)); + Statement s=QPID_LOG_STATEMENT_INIT(debug); + BOOST_CHECK(!s.enabled); + Statement::Initializer init(s); + BOOST_CHECK(s.enabled); + + Statement s2=QPID_LOG_STATEMENT_INIT(warning); + 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 msg; + vector stmt; + + TestOutput() { + Logger::instance().output(qpid::make_auto_ptr(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; + +BOOST_AUTO_TEST_CASE(testLoggerOutput) { + Logger& l=clearLogger(); + l.select(Selector(debug)); + Statement s=QPID_LOG_STATEMENT_INIT(debug); + TestOutput* out=new TestOutput(); + + // Verify message is output. + l.log(s, "foo"); + vector expect=list_of("foo\n"); + BOOST_CHECK_EQUAL(expect, out->msg); + + // Verify multiple outputs + TestOutput* out2=new TestOutput(); + 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); +} + +BOOST_AUTO_TEST_CASE(testMacro) { + Logger& l = clearLogger(); + l.select(Selector(info)); + TestOutput* out=new TestOutput(); + QPID_LOG(info, "foo"); + vector expect=list_of("foo\n"); + BOOST_CHECK_EQUAL(expect, out->msg); + BOOST_CHECK_EQUAL(__FILE__, out->stmt.front().file); + BOOST_CHECK_EQUAL("void testMacro()", out->stmt.front().function); + + // 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); +} + +BOOST_AUTO_TEST_CASE(testLoggerFormat) { + Logger& l=clearLogger(); + l.select(Selector(critical)); + TestOutput* out=new TestOutput(); + + // Time format is YYY-Month-dd hh:mm:ss + l.format(Logger::TIME); + QPID_LOG(critical, "foo"); + string re("\\d\\d\\d\\d-[A-Z][a-z]+-\\d\\d \\d\\d:\\d\\d:\\d\\d foo\n"); + BOOST_CHECK_REGEX(re, out->last()); + + 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_EQUAL("void testLoggerFormat(): foo\n", out->last()); + + l.format(Logger::LEVEL); + QPID_LOG(critical, "foo"); + BOOST_CHECK_EQUAL("critical foo\n", out->last()); + + l.format(~0); // Everything + QPID_LOG(critical, "foo"); + re=".* critical \\[[0-9a-f]*] "+string(__FILE__)+":\\d+:void testLoggerFormat\\(\\): foo\n"; + BOOST_CHECK_REGEX(re, out->last()); +} + +BOOST_AUTO_TEST_CASE(testOstreamOutput) { + Logger& l=clearLogger(); + l.select(Selector(error)); + ostringstream os; + l.output(os); + QPID_LOG(error, "foo"); + QPID_LOG(error, "bar"); + QPID_LOG(error, "baz"); + BOOST_CHECK_EQUAL("foo\nbar\nbaz\n", os.str()); + l.clear(); +} + +#if 0 // This test requires manual intervention. Normally disabled. +BOOST_AUTO_TEST_CASE(testSyslogOutput) { + Logger& l = clearLogger(); + 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 +BOOST_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; +} + + +struct TestOptions : public Options { + TestOptions(int argc, char** argv) { + qpid::po::options_description desc; + addTo(desc); + qpid::parseOptions(desc, argc, argv); + } +}; + +#define ARGC(argv) (sizeof(argv)/sizeof(char*)) + +BOOST_AUTO_TEST_CASE(testOptionsParse) { + char* argv[]={ + 0, + "--log.enable", "error+:foo", + "--log.enable", "debug:bar", + "--log.enable", "info", + "--log.output", "x", + "--log.output", "y", + "--log.level", "yes", + "--log.source", "1", + "--log.thread", "true", + "--log.function", "YES" + }; + TestOptions opts(ARGC(argv), argv); + vector expect=list_of("error+:foo")("debug:bar")("info"); + BOOST_CHECK_EQUAL(expect, opts.selectors); + expect=list_of("x")("y"); + BOOST_CHECK_EQUAL(expect, opts.outputs); + BOOST_CHECK(opts.level); + BOOST_CHECK(opts.source); + BOOST_CHECK(opts.function); + BOOST_CHECK(opts.thread); +} + +BOOST_AUTO_TEST_CASE(testOptionsDefault) { + Options opts; + vector expect=list_of("stderr"); + BOOST_CHECK_EQUAL(expect, opts.outputs); + expect=list_of("error+"); + BOOST_CHECK_EQUAL(expect, opts.selectors); + BOOST_CHECK(opts.time && opts.level); + BOOST_CHECK(!(opts.source || opts.function || opts.thread)); +} + +BOOST_AUTO_TEST_CASE(testSelectorFromOptions) { + char* argv[]={ + 0, + "--log.enable", "error+:foo", + "--log.enable", "debug:bar", + "--log.enable", "info" + }; + TestOptions opts(ARGC(argv), argv); + vector 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")); +} + +BOOST_AUTO_TEST_CASE(testOptionsFormat) { + Logger& l = clearLogger(); + Options opts; + BOOST_CHECK_EQUAL(Logger::TIME|Logger::LEVEL, l.format(opts)); + char* argv[]={ + 0, + "--log.time", "no", + "--log.level", "no", + "--log.source", "1", + "--log.thread", "1" + }; + qpid::po::options_description desc; + opts.addTo(desc); + qpid::parseOptions(desc, ARGC(argv), argv); + BOOST_CHECK_EQUAL( + Logger::FILE|Logger::LINE|Logger::THREAD, l.format(opts)); + opts = Options(); // Clear. + char* argv2[]={ + 0, + "--log.level", "no", + "--log.thread", "true", + "--log.function", "YES", + "--log.time", "YES" + }; + qpid::po::options_description desc2; + opts.addTo(desc2); + qpid::parseOptions(desc2, ARGC(argv2), argv2); + BOOST_CHECK_EQUAL( + Logger::THREAD|Logger::FUNCTION|Logger::TIME, + l.format(opts)); +} + + +BOOST_AUTO_TEST_CASE(testLoggerConfigure) { + Logger& l = clearLogger(); + Options opts; + char* argv[]={ + 0, + "--log.time", "no", + "--log.source", "yes", + "--log.output", "logging.tmp", + "--log.enable", "critical" + }; + qpid::po::options_description desc; + opts.addTo(desc); + qpid::parseOptions(desc, ARGC(argv), argv); + l.configure(opts, "test"); + 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"); +} diff --git a/qpid/cpp/src/tests/run_test b/qpid/cpp/src/tests/run_test index ef608e55ca..bfd6991481 100755 --- a/qpid/cpp/src/tests/run_test +++ b/qpid/cpp/src/tests/run_test @@ -22,7 +22,7 @@ vg_check() grep -E '^==[0-9]+== ERROR SUMMARY:' $VG_LOG > /dev/null || \ vg_failed "No valgrind ERROR SUMMARY line in $$vg_failed." # Ensure that the number of errors is 0. - grep -E '^==[0-9]+== ERROR SUMMARY: [^0] ' $VG_LOG > /dev/null && \ + grep -E '^==[0-9]+== ERROR SUMMARY: [^0]' $VG_LOG > /dev/null && \ vg_failed "Valgrind reported errors in $vg_out; see above." # Check for leaks. grep -E '^==[0-9]+== +.* lost: [^0]' $VG_LOG && \ @@ -41,14 +41,14 @@ 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 --log-file-exactly=$VG_LOG --" # Hide output unless there's an error. - libtool --mode=execute $VALGRIND "$@" >$TEST_LOG 2>&1 || { + libtool --mode=execute "$VALGRIND" "$@" >$TEST_LOG 2>&1 || { ERROR=$? cat $TEST_LOG } test -n "$VALGRIND" && vg_check else # This is a non-libtool shell script, just execute it. - "$@" + exec "$@" fi if test -z "$ERROR"; then diff --git a/qpid/cpp/src/tests/test_tools.h b/qpid/cpp/src/tests/test_tools.h new file mode 100644 index 0000000000..e564b9a473 --- /dev/null +++ b/qpid/cpp/src/tests/test_tools.h @@ -0,0 +1,56 @@ +#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 +#include +#include +#include + +/** Stream operator so BOOST_CHECK_EQUALS works on vectors. */ +namespace std { +template +ostream& operator <<(ostream& o, const vector& v) { + o << " {"; + typename vector::const_iterator i = v.begin(); + if (i != v.end()) + o << *i++; + while (i != v.end()) + o << ", " << *i++; + return o << "}"; +} +} // namespace std + +/** 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 */ +#define BOOST_CHECK_REGEX(re, text) \ + BOOST_CHECK_PREDICATE(regexPredicate, (re)(text)) + +/** 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()) + +#endif /*!TEST_TOOLS_H*/ + diff --git a/qpid/cpp/src/tests/unit/Cpg.cpp b/qpid/cpp/src/tests/unit/Cpg.cpp deleted file mode 100644 index 74c6532338..0000000000 --- a/qpid/cpp/src/tests/unit/Cpg.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * 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. - * - */ - -#define BOOST_AUTO_TEST_MAIN // Must come before #include -#include "test_tools.h" -#include "qpid/cluster/Cpg.h" -#include -#include -#include -#include -#include - -using namespace std; -using namespace qpid::cluster; - -// For debugging: op << for CPG types. - -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 <<","< -ostream& operator<<(ostream& o, const pair& array) { - o << "{ "; - ostream_iterator i(o, " "); - copy(array.first, array.first+array.second, i); - cout << "}"; - return o; -} - -const string testGroup("foo"); -vector delivered; -vector configChanges; - -void testDeliver ( - cpg_handle_t /*handle*/, - struct cpg_name *group, - uint32_t /*nodeid*/, - uint32_t /*pid*/, - void* msg, - int msg_len) -{ - BOOST_CHECK_EQUAL(testGroup, Cpg::str(*group)); - delivered.push_back(string((char*)msg,msg_len)); -} - -void testConfigChange( - cpg_handle_t /*handle*/, - struct cpg_name *group, - struct cpg_address */*members*/, int nMembers, - struct cpg_address */*left*/, int /*nLeft*/, - struct cpg_address */*joined*/, int /*nJoined*/ -) -{ - BOOST_CHECK_EQUAL(testGroup, Cpg::str(*group)); - configChanges.push_back(nMembers); -} - -BOOST_AUTO_TEST_CASE(basic) { - // Verify basic functionality of cpg. This will catch any - // openais configuration or permission errors. - // - Cpg cpg(&testDeliver, &testConfigChange); - Cpg::Name group("foo"); - - cpg.join(group); - iovec iov = { (void*)"Hello!", 6 }; - cpg.mcast(group, &iov, 1); - cpg.leave(group); - - cpg.dispatch(CPG_DISPATCH_ONE); // Wait for at least one. - cpg.dispatch(CPG_DISPATCH_ALL); - BOOST_REQUIRE_EQUAL(1u, delivered.size()); - BOOST_CHECK_EQUAL("Hello!", delivered.front()); - BOOST_REQUIRE_EQUAL(2u, configChanges.size()); - BOOST_CHECK_EQUAL(1, configChanges[0]); - BOOST_CHECK_EQUAL(0, configChanges[1]); -} diff --git a/qpid/cpp/src/tests/unit/Url.cpp b/qpid/cpp/src/tests/unit/Url.cpp deleted file mode 100644 index a8b415e641..0000000000 --- a/qpid/cpp/src/tests/unit/Url.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * 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. - * - */ - -#define BOOST_AUTO_TEST_MAIN // Must come before #include -#include "test_tools.h" -#include "qpid/Url.h" -#include - -using namespace std; -using namespace qpid; -using namespace boost::assign; - -BOOST_AUTO_TEST_CASE(testUrl_str) { - Url url; - url.push_back(TcpAddress("foo.com")); - url.push_back(TcpAddress("bar.com", 6789)); - - BOOST_CHECK_EQUAL( - url.str(), "amqp:tcp:foo.com:5672,tcp:bar.com:6789"); - BOOST_CHECK_EQUAL(Url().str(), "amqp:"); -} - - -BOOST_AUTO_TEST_CASE(testUrl_ctor) { - BOOST_CHECK_EQUAL( - Url("amqp:foo.com,tcp:bar.com:1234").str(), - "amqp:tcp:foo.com:5672,tcp:bar.com:1234"); - BOOST_CHECK_EQUAL( - Url("amqp:foo/ignorethis").str(), - "amqp:tcp:foo:5672"); - BOOST_CHECK_EQUAL("amqp:tcp::5672", Url("amqp:").str()); - BOOST_CHECK_EQUAL(0u, Url("xxx", nothrow).size()); - try { - Url invalid("xxx"); - BOOST_FAIL("Expected InvalidUrl exception"); - } - catch (const Url::InvalidUrl&) {} -} - - diff --git a/qpid/cpp/src/tests/unit/logging.cpp b/qpid/cpp/src/tests/unit/logging.cpp deleted file mode 100644 index c80bf7b337..0000000000 --- a/qpid/cpp/src/tests/unit/logging.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/* - * - * 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. - * - */ - -#define BOOST_AUTO_TEST_MAIN // Must come before #include -#include "test_tools.h" -#include "qpid/log/Logger.h" -#include "qpid/log/Options.h" -#include "qpid/memory.h" -#include "qpid/CommonOptions.h" -#include -#include -#include -#include -#include - - -using namespace std; -using namespace boost; -using namespace qpid::log; - -BOOST_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(string("void testStatementInit()"), s.function); - BOOST_CHECK_EQUAL(debug, s.level); -} - - -BOOST_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")); -} - -Logger& clearLogger() { - Logger::instance().clear(); - return Logger::instance(); -} - -BOOST_AUTO_TEST_CASE(testStatementEnabled) { - // Verify that the logger enables and disables log statements. - Logger& l=clearLogger(); - l.select(Selector(debug)); - Statement s=QPID_LOG_STATEMENT_INIT(debug); - BOOST_CHECK(!s.enabled); - Statement::Initializer init(s); - BOOST_CHECK(s.enabled); - - Statement s2=QPID_LOG_STATEMENT_INIT(warning); - 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 msg; - vector stmt; - - TestOutput() { - Logger::instance().output(qpid::make_auto_ptr(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; - -BOOST_AUTO_TEST_CASE(testLoggerOutput) { - Logger& l=clearLogger(); - l.select(Selector(debug)); - Statement s=QPID_LOG_STATEMENT_INIT(debug); - TestOutput* out=new TestOutput(); - - // Verify message is output. - l.log(s, "foo"); - vector expect=list_of("foo\n"); - BOOST_CHECK_EQUAL(expect, out->msg); - - // Verify multiple outputs - TestOutput* out2=new TestOutput(); - 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); -} - -BOOST_AUTO_TEST_CASE(testMacro) { - Logger& l = clearLogger(); - l.select(Selector(info)); - TestOutput* out=new TestOutput(); - QPID_LOG(info, "foo"); - vector expect=list_of("foo\n"); - BOOST_CHECK_EQUAL(expect, out->msg); - BOOST_CHECK_EQUAL(__FILE__, out->stmt.front().file); - BOOST_CHECK_EQUAL("void testMacro()", out->stmt.front().function); - - // 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); -} - -BOOST_AUTO_TEST_CASE(testLoggerFormat) { - Logger& l=clearLogger(); - l.select(Selector(critical)); - TestOutput* out=new TestOutput(); - - // Time format is YYY-Month-dd hh:mm:ss - l.format(Logger::TIME); - QPID_LOG(critical, "foo"); - string re("\\d\\d\\d\\d-[A-Z][a-z]+-\\d\\d \\d\\d:\\d\\d:\\d\\d foo\n"); - BOOST_CHECK_REGEX(re, out->last()); - - 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_EQUAL("void testLoggerFormat(): foo\n", out->last()); - - l.format(Logger::LEVEL); - QPID_LOG(critical, "foo"); - BOOST_CHECK_EQUAL("critical foo\n", out->last()); - - l.format(~0); // Everything - QPID_LOG(critical, "foo"); - re=".* critical \\[[0-9a-f]*] "+string(__FILE__)+":\\d+:void testLoggerFormat\\(\\): foo\n"; - BOOST_CHECK_REGEX(re, out->last()); -} - -BOOST_AUTO_TEST_CASE(testOstreamOutput) { - Logger& l=clearLogger(); - l.select(Selector(error)); - ostringstream os; - l.output(os); - QPID_LOG(error, "foo"); - QPID_LOG(error, "bar"); - QPID_LOG(error, "baz"); - BOOST_CHECK_EQUAL("foo\nbar\nbaz\n", os.str()); - l.clear(); -} - -#if 0 // This test requires manual intervention. Normally disabled. -BOOST_AUTO_TEST_CASE(testSyslogOutput) { - Logger& l = clearLogger(); - 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 -BOOST_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; -} - - -struct TestOptions : public Options { - TestOptions(int argc, char** argv) { - qpid::po::options_description desc; - addTo(desc); - qpid::parseOptions(desc, argc, argv); - } -}; - -#define ARGC(argv) (sizeof(argv)/sizeof(char*)) - -BOOST_AUTO_TEST_CASE(testOptionsParse) { - char* argv[]={ - 0, - "--log.enable", "error+:foo", - "--log.enable", "debug:bar", - "--log.enable", "info", - "--log.output", "x", - "--log.output", "y", - "--log.level", "yes", - "--log.source", "1", - "--log.thread", "true", - "--log.function", "YES" - }; - TestOptions opts(ARGC(argv), argv); - vector expect=list_of("error+:foo")("debug:bar")("info"); - BOOST_CHECK_EQUAL(expect, opts.selectors); - expect=list_of("x")("y"); - BOOST_CHECK_EQUAL(expect, opts.outputs); - BOOST_CHECK(opts.level); - BOOST_CHECK(opts.source); - BOOST_CHECK(opts.function); - BOOST_CHECK(opts.thread); -} - -BOOST_AUTO_TEST_CASE(testOptionsDefault) { - Options opts; - vector expect=list_of("stderr"); - BOOST_CHECK_EQUAL(expect, opts.outputs); - expect=list_of("error+"); - BOOST_CHECK_EQUAL(expect, opts.selectors); - BOOST_CHECK(opts.time && opts.level); - BOOST_CHECK(!(opts.source || opts.function || opts.thread)); -} - -BOOST_AUTO_TEST_CASE(testSelectorFromOptions) { - char* argv[]={ - 0, - "--log.enable", "error+:foo", - "--log.enable", "debug:bar", - "--log.enable", "info" - }; - TestOptions opts(ARGC(argv), argv); - vector 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")); -} - -BOOST_AUTO_TEST_CASE(testOptionsFormat) { - Logger& l = clearLogger(); - Options opts; - BOOST_CHECK_EQUAL(Logger::TIME|Logger::LEVEL, l.format(opts)); - char* argv[]={ - 0, - "--log.time", "no", - "--log.level", "no", - "--log.source", "1", - "--log.thread", "1" - }; - qpid::po::options_description desc; - opts.addTo(desc); - qpid::parseOptions(desc, ARGC(argv), argv); - BOOST_CHECK_EQUAL( - Logger::FILE|Logger::LINE|Logger::THREAD, l.format(opts)); - opts = Options(); // Clear. - char* argv2[]={ - 0, - "--log.level", "no", - "--log.thread", "true", - "--log.function", "YES", - "--log.time", "YES" - }; - qpid::po::options_description desc2; - opts.addTo(desc2); - qpid::parseOptions(desc2, ARGC(argv2), argv2); - BOOST_CHECK_EQUAL( - Logger::THREAD|Logger::FUNCTION|Logger::TIME, - l.format(opts)); -} - - -BOOST_AUTO_TEST_CASE(testLoggerConfigure) { - Logger& l = clearLogger(); - Options opts; - char* argv[]={ - 0, - "--log.time", "no", - "--log.source", "yes", - "--log.output", "logging.tmp", - "--log.enable", "critical" - }; - qpid::po::options_description desc; - opts.addTo(desc); - qpid::parseOptions(desc, ARGC(argv), argv); - l.configure(opts, "test"); - 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"); -} diff --git a/qpid/cpp/src/tests/unit/test_tools.h b/qpid/cpp/src/tests/unit/test_tools.h deleted file mode 100644 index faa198af9a..0000000000 --- a/qpid/cpp/src/tests/unit/test_tools.h +++ /dev/null @@ -1,53 +0,0 @@ -#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 -#include -#include -#include - -/** Stream operator so BOOST_CHECK_EQUALS works on vectors. */ -namespace std { -template -ostream& operator <<(ostream& o, const vector& v) { - o << " {"; - typename vector::const_iterator i = v.begin(); - if (i != v.end()) - o << *i++; - while (i != v.end()) - o << ", " << *i++; - return o << "}"; -} -} // namespace std - -/** 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 */ -#define BOOST_CHECK_REGEX(re, text) \ - BOOST_CHECK_PREDICATE(regexPredicate, (re)(text)) - -#endif /*!TEST_TOOLS_H*/ - -- cgit v1.2.1