blob: a3271701c381397658e621b0935c7e11e51e2e90 [file] [log] [blame]
/*
*
* 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=PLAIN");
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;
}