diff options
Diffstat (limited to 'qpid/cpp/src/tests/cluster_authentication_soak.cpp')
-rw-r--r-- | qpid/cpp/src/tests/cluster_authentication_soak.cpp | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/qpid/cpp/src/tests/cluster_authentication_soak.cpp b/qpid/cpp/src/tests/cluster_authentication_soak.cpp new file mode 100644 index 0000000000..b8e8a22693 --- /dev/null +++ b/qpid/cpp/src/tests/cluster_authentication_soak.cpp @@ -0,0 +1,310 @@ +/* + * + * 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 <signal.h> +#include <fcntl.h> + +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <string> +#include <iostream> +#include <sstream> +#include <vector> + +#include <boost/assign.hpp> + +#include "qpid/framing/Uuid.h" + +#include <ForkedBroker.h> +#include <qpid/client/Connection.h> + +#include <sasl/sasl.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + + + +using namespace std; +using boost::assign::list_of; +using namespace qpid::framing; +using namespace qpid::client; + + +namespace qpid { +namespace tests { + +vector<pid_t> brokerPids; + +typedef vector<ForkedBroker *> brokerVector; + + + + + +int runSilent = 1; +int newbiePort = 0; + + +void +makeClusterName ( string & s ) { + stringstream ss; + ss << "authenticationSoakCluster_" << Uuid(true).str(); + s = ss.str(); +} + + + +void +startBroker ( brokerVector & brokers , int brokerNumber, string const & clusterName ) { + stringstream prefix, clusterArg; + prefix << "soak-" << brokerNumber; + clusterArg << "--cluster-name=" << clusterName; + + std::vector<std::string> argv; + + argv.push_back ("../qpidd"); + argv.push_back ("--no-module-dir"); + argv.push_back ("--load-module=../.libs/cluster.so"); + argv.push_back (clusterArg.str()); + argv.push_back ("--cluster-username=zig"); + argv.push_back ("--cluster-password=zig"); + argv.push_back ("--cluster-mechanism=ANONYMOUS"); + argv.push_back ("--sasl-config=./sasl_config"); + argv.push_back ("--auth=yes"); + argv.push_back ("--mgmt-enable=yes"); + argv.push_back ("--log-prefix"); + argv.push_back (prefix.str()); + argv.push_back ("--log-to-file"); + argv.push_back (prefix.str()+".log"); + argv.push_back ("TMP_DATA_DIR"); + + ForkedBroker * newbie = new ForkedBroker (argv); + newbiePort = newbie->getPort(); + brokers.push_back ( newbie ); +} + + + + +bool +runPerftest ( bool hangTest ) { + stringstream portSs; + portSs << newbiePort; + string portStr = portSs.str(); + char const * path = "./qpid-perftest"; + + vector<char const *> argv; + argv.push_back ( "./qpid-perftest" ); + argv.push_back ( "-p" ); + argv.push_back ( portStr.c_str() ); + argv.push_back ( "--username" ); + argv.push_back ( "zig" ); + argv.push_back ( "--password" ); + argv.push_back ( "zig" ); + argv.push_back ( "--mechanism" ); + argv.push_back ( "DIGEST-MD5" ); + argv.push_back ( "--count" ); + argv.push_back ( "20000" ); + argv.push_back ( 0 ); + + pid_t pid = fork(); + + if ( ! pid ) { + int i=open("/dev/null",O_RDWR); + dup2 ( i, fileno(stdout) ); + dup2 ( i, fileno(stderr) ); + + execv ( path, const_cast<char * const *>(&argv[0]) ); + // The exec failed: we are still in parent process. + perror ( "error running qpid-perftest: " ); + return false; + } + else { + if ( hangTest ) { + if ( ! runSilent ) + cerr << "Pausing perftest " << pid << endl; + kill ( pid, 19 ); + } + + struct timeval startTime, + currentTime, + duration; + + gettimeofday ( & startTime, 0 ); + + while ( 1 ) { + sleep ( 2 ); + int status; + int returned_pid = waitpid ( pid, &status, WNOHANG ); + if ( returned_pid == pid ) { + int exit_status = WEXITSTATUS(status); + if ( exit_status ) { + cerr << "qpid-perftest failed. exit_status was: " << exit_status << endl; + return false; + } + else { + return true; // qpid-perftest succeeded. + } + } + else { // qpid-perftest has not yet completed. + gettimeofday ( & currentTime, 0 ); + timersub ( & currentTime, & startTime, & duration ); + if ( duration.tv_sec > 60 ) { + kill ( pid, 9 ); + cerr << "qpid-perftest pid " << pid << " hanging: killed.\n"; + return false; + } + } + } + + } +} + + + +bool +allBrokersAreAlive ( brokerVector & brokers ) { + for ( unsigned int i = 0; i < brokers.size(); ++ i ) + if ( ! brokers[i]->isRunning() ) + return false; + + return true; +} + + + + + +void +killAllBrokers ( brokerVector & brokers ) { + for ( unsigned int i = 0; i < brokers.size(); ++ i ) { + brokers[i]->kill ( 9 ); + } +} + + + + +void +killOneBroker ( brokerVector & brokers ) { + int doomedBroker = getpid() % brokers.size(); + cout << "Killing broker " << brokers[doomedBroker]->getPID() << endl; + brokers[doomedBroker]->kill ( 9 ); + sleep ( 2 ); +} + + + + +}} // namespace qpid::tests + +using namespace qpid::tests; + + + +/* + * Please note that this test has self-test capability. + * It is intended to detect + * 1. perftest hangs. + * 2. broker deaths + * Both of these condtions can be forced when running manually + * to ensure that the test really does detect them. + * See command-line arguments 3 and 4. + */ +int +main ( int argc, char ** argv ) +{ + // I need the SASL_PATH_TYPE_CONFIG feature, which did not appear until SASL 2.1.22 +#if (SASL_VERSION_FULL < ((2<<16)|(1<<8)|22)) + cout << "Skipping SASL test, SASL version too low." << endl; + return 0; +#endif + + int n_iterations = argc > 1 ? atoi(argv[1]) : 1; + runSilent = argc > 2 ? atoi(argv[2]) : 1; // default to silent + int killBroker = argc > 3 ? atoi(argv[3]) : 0; // Force the kill of one broker. + int hangTest = argc > 4 ? atoi(argv[4]) : 0; // Force the first perftest to hang. + int n_brokers = 3; + brokerVector brokers; + + srand ( getpid() ); + string clusterName; + makeClusterName ( clusterName ); + for ( int i = 0; i < n_brokers; ++ i ) { + startBroker ( brokers, i, clusterName ); + } + + sleep ( 3 ); + + /* Run all qpid-perftest iterations, and only then check for brokers + * still being up. If you just want a quick check for the failure + * mode in which a single iteration would kill all brokers except + * the client-connected one, just run it with the iterations arg + * set to 1. + */ + for ( int iteration = 0; iteration < n_iterations; ++ iteration ) { + if ( ! runPerftest ( hangTest ) ) { + if ( ! runSilent ) + cerr << "qpid-perftest " << iteration << " failed.\n"; + return 1; + } + if ( ! ( iteration % 10 ) ) { + if ( ! runSilent ) + cerr << "qpid-perftest " << iteration << " complete. -------------- \n"; + } + } + if ( ! runSilent ) + cerr << "\nqpid-perftest " << n_iterations << " iterations complete. -------------- \n\n"; + + /* If the command-line tells us to kill a broker, do + * it now. Use this option to prove that this test + * really can detect broker-deaths. + */ + if ( killBroker ) { + killOneBroker ( brokers ); + } + + if ( ! allBrokersAreAlive ( brokers ) ) { + if ( ! runSilent ) + cerr << "not all brokers are alive.\n"; + killAllBrokers ( brokers ); + return 2; + } + + killAllBrokers ( brokers ); + if ( ! runSilent ) + cout << "success.\n"; + + return 0; +} + + + |