0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 17:10:48 +01:00
mongodb/dbtests/framework.cpp

366 lines
12 KiB
C++
Raw Normal View History

2009-09-17 23:23:38 +02:00
// framework.cpp
/**
* Copyright (C) 2008 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2009-09-30 20:32:17 +02:00
#include "stdafx.h"
#include <boost/program_options.hpp>
#undef assert
#define assert xassert
2009-09-17 23:23:38 +02:00
#include "framework.h"
#include "../util/file_allocator.h"
2009-09-17 23:23:38 +02:00
#ifndef _WIN32
#include <cxxabi.h>
2009-09-18 23:48:30 +02:00
#include <sys/file.h>
2009-09-17 23:23:38 +02:00
#endif
namespace po = boost::program_options;
2009-09-17 23:23:38 +02:00
namespace mongo {
2009-09-25 16:46:49 +02:00
CmdLine cmdLine;
2009-09-17 23:23:38 +02:00
namespace regression {
map<string,Suite*> * mongo::regression::Suite::_suites = 0;
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
class Result {
public:
Result( string name ) : _name( name ) , _rc(0) , _tests(0) , _fails(0) , _asserts(0) {
}
string toString(){
2009-12-04 06:17:14 +01:00
stringstream ss;
2009-12-03 20:30:51 +01:00
char result[128];
2009-12-03 20:46:29 +01:00
sprintf(result, "%-20s | tests: %4d | fails: %4d | assert calls: %6d\n", _name.c_str(), _tests, _fails, _asserts);
2009-12-04 06:17:14 +01:00
ss << result;
for ( list<string>::iterator i=_messages.begin(); i!=_messages.end(); i++ ){
ss << "\t" << *i << "\n";
}
return ss.str();
2009-09-17 23:23:38 +02:00
}
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
int rc(){
return _rc;
}
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
string _name;
int _rc;
int _tests;
int _fails;
int _asserts;
list<string> _messages;
static Result * cur;
};
Result * Result::cur = 0;
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
Result * Suite::run(){
2009-09-30 16:30:25 +02:00
log(1) << "\t about to setupTests" << endl;
2009-09-17 23:23:38 +02:00
setupTests();
2009-09-30 16:30:25 +02:00
log(1) << "\t done setupTests" << endl;
2009-09-17 23:23:38 +02:00
Result * r = new Result( _name );
Result::cur = r;
/* see note in SavedContext */
2009-12-06 17:18:35 +01:00
//writelock lk("");
2009-09-17 23:23:38 +02:00
for ( list<TestCase*>::iterator i=_tests.begin(); i!=_tests.end(); i++ ){
TestCase * tc = *i;
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
r->_tests++;
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
bool passes = false;
2009-09-25 16:46:49 +02:00
2009-09-30 16:30:25 +02:00
log(1) << "\t going to run test: " << tc->getName() << endl;
2009-09-25 16:46:49 +02:00
stringstream err;
err << tc->getName() << "\t";
2009-09-17 23:23:38 +02:00
try {
tc->run();
passes = true;
}
2009-09-25 16:56:56 +02:00
catch ( MyAssertionException * ae ){
2009-09-25 16:46:49 +02:00
err << ae->ss.str();
delete( ae );
}
catch ( std::exception& e ){
2009-10-01 16:41:22 +02:00
err << " exception: " << e.what();
2009-09-25 16:46:49 +02:00
}
catch ( int x ){
err << " caught int : " << x << endl;
}
2009-09-17 23:23:38 +02:00
catch ( ... ){
2009-09-25 16:46:49 +02:00
cerr << "unknown exception in test: " << tc->getName() << endl;
2009-09-17 23:23:38 +02:00
}
2009-09-25 16:46:49 +02:00
if ( ! passes ){
2009-11-30 21:10:23 +01:00
string s = err.str();
log() << "FAIL: " << s << endl;
2009-09-17 23:23:38 +02:00
r->_fails++;
2009-11-30 21:10:23 +01:00
r->_messages.push_back( s );
2009-10-01 16:41:22 +02:00
}
2009-09-17 23:23:38 +02:00
}
2009-10-08 17:48:04 +02:00
if ( r->_fails )
r->_rc = 17;
log(1) << "\t DONE running tests" << endl;
2009-09-30 16:30:25 +02:00
2009-09-17 23:23:38 +02:00
return r;
}
void show_help_text(const char* name, po::options_description options) {
cout << "usage: " << name << " [options] [suite]..." << endl
<< options << "suite: run the specified test suite(s) only" << endl;
}
int Suite::run( int argc , char** argv , string default_dbpath ) {
unsigned long long seed = time( 0 );
string dbpathSpec;
po::options_description shell_options("options");
po::options_description hidden_options("Hidden options");
po::options_description cmdline_options("Command line options");
po::positional_options_description positional_options;
shell_options.add_options()
("help,h", "show this usage information")
("dbpath", po::value<string>(&dbpathSpec)->default_value(default_dbpath),
"db data path for this test run. NOTE: the contents of this "
"directory will be overwritten if it already exists")
("debug", "run tests with verbose output")
("list,l", "list available test suites")
2009-09-30 16:30:25 +02:00
("verbose,v", "verbose")
("seed", po::value<unsigned long long>(&seed), "random number seed")
;
hidden_options.add_options()
("suites", po::value< vector<string> >(), "test suites to run")
;
positional_options.add("suites", -1);
cmdline_options.add(shell_options).add(hidden_options);
po::variables_map params;
int command_line_style = (((po::command_line_style::unix_style ^
po::command_line_style::allow_guessing) |
po::command_line_style::allow_long_disguise) ^
po::command_line_style::allow_sticky);
try {
po::store(po::command_line_parser(argc, argv).options(cmdline_options).
positional(positional_options).
style(command_line_style).run(), params);
po::notify(params);
} catch (po::error &e) {
cout << "ERROR: " << e.what() << endl << endl;
show_help_text(argv[0], shell_options);
return EXIT_BADOPTIONS;
}
if (params.count("help")) {
show_help_text(argv[0], shell_options);
return EXIT_CLEAN;
}
2009-09-30 16:30:25 +02:00
if (params.count("debug") || params.count("verbose") ) {
logLevel = 1;
}
if (params.count("list")) {
for ( map<string,Suite*>::iterator i = _suites->begin() ; i != _suites->end(); i++ )
cout << i->first << endl;
return 0;
}
boost::filesystem::path p(dbpathSpec);
/* remove the contents of the test directory if it exists. */
if (boost::filesystem::exists(p)) {
if (!boost::filesystem::is_directory(p)) {
cout << "ERROR: path \"" << p.string() << "\" is not a directory" << endl << endl;
show_help_text(argv[0], shell_options);
return EXIT_BADOPTIONS;
}
boost::filesystem::directory_iterator end_iter;
for (boost::filesystem::directory_iterator dir_iter(p);
dir_iter != end_iter; ++dir_iter) {
boost::filesystem::remove_all(*dir_iter);
}
} else {
boost::filesystem::create_directory(p);
}
string dbpathString = p.native_directory_string();
dbpath = dbpathString.c_str();
2009-10-14 22:57:11 +02:00
cmdLine.prealloc = false;
2009-10-17 05:32:34 +02:00
cmdLine.smallfiles = true;
cmdLine.oplogSize = 10 * 1024 * 1024;
Client::initThread("testsuite");
acquirePathLock();
srand( (unsigned) seed );
printGitVersion();
printSysInfo();
out() << "random seed: " << seed << endl;
theFileAllocator().start();
vector<string> suites;
if (params.count("suites")) {
suites = params["suites"].as< vector<string> >();
}
int ret = run(suites);
#if !defined(_WIN32) && !defined(__sunos__)
flock( lockFile, LOCK_UN );
#endif
2009-10-21 15:57:51 +02:00
cc().shutdown();
dbexit( (ExitCode)ret ); // so everything shuts down cleanly
return ret;
}
int Suite::run( vector<string> suites ){
for ( unsigned int i = 0; i < suites.size(); i++ ) {
if ( _suites->find( suites[i] ) == _suites->end() ) {
cout << "invalid test [" << suites[i] << "], use --list to see valid names" << endl;
2009-09-17 23:23:38 +02:00
return -1;
}
}
2009-09-18 19:10:07 +02:00
list<string> torun(suites.begin(), suites.end());
2009-09-17 23:23:38 +02:00
if ( torun.size() == 0 )
for ( map<string,Suite*>::iterator i=_suites->begin() ; i!=_suites->end(); i++ )
torun.push_back( i->first );
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
list<Result*> results;
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
for ( list<string>::iterator i=torun.begin(); i!=torun.end(); i++ ){
string name = *i;
Suite * s = (*_suites)[name];
assert( s );
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
log() << "going to run suite: " << name << endl;
results.push_back( s->run() );
}
2009-09-18 19:10:07 +02:00
2009-10-17 05:32:34 +02:00
Logstream::get().flush();
2009-09-17 23:23:38 +02:00
cout << "**************************************************" << endl;
cout << "**************************************************" << endl;
cout << "**************************************************" << endl;
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
int rc = 0;
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
int tests = 0;
int fails = 0;
int asserts = 0;
for ( list<Result*>::iterator i=results.begin(); i!=results.end(); i++ ){
Result * r = *i;
cout << r->toString();
if ( abs( r->rc() ) > abs( rc ) )
rc = r->rc();
2009-10-08 17:48:04 +02:00
2009-09-17 23:23:38 +02:00
tests += r->_tests;
fails += r->_fails;
asserts += r->_asserts;
}
2009-12-03 20:30:51 +01:00
Result totals ("TOTALS");
totals._tests = tests;
totals._fails = fails;
totals._asserts = asserts;
2009-10-08 17:48:04 +02:00
2009-12-03 20:30:51 +01:00
cout << totals.toString(); // includes endl
2009-09-17 23:23:38 +02:00
return rc;
}
void Suite::registerSuite( string name , Suite * s ){
if ( ! _suites )
_suites = new map<string,Suite*>();
Suite*& m = (*_suites)[name];
uassert( 10162 , "already have suite with that name" , ! m );
2009-09-17 23:23:38 +02:00
m = s;
}
void assert_pass(){
Result::cur->_asserts++;
}
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
void assert_fail( const char * exp , const char * file , unsigned line ){
Result::cur->_asserts++;
2009-09-25 16:46:49 +02:00
2009-10-01 07:25:53 +02:00
MyAssertionException * e = new MyAssertionException();
e->ss << "ASSERT FAILED! " << file << ":" << line << endl;
throw e;
2009-09-17 23:23:38 +02:00
}
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
void fail( const char * exp , const char * file , unsigned line ){
assert(0);
}
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
string demangleName( const type_info& typeinfo ){
#ifdef _WIN32
return typeinfo.name();
#else
2009-09-17 23:23:38 +02:00
int status;
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
char * niceName = abi::__cxa_demangle(typeinfo.name(), 0, 0, &status);
if ( ! niceName )
return typeinfo.name();
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
string s = niceName;
free(niceName);
return s;
#endif
2009-09-17 23:23:38 +02:00
}
2009-09-25 16:56:56 +02:00
MyAssertionException * MyAsserts::getBase(){
MyAssertionException * e = new MyAssertionException();
2009-09-25 16:46:49 +02:00
e->ss << _file << ":" << _line << " " << _aexp << " != " << _bexp << " ";
return e;
}
2009-09-17 23:23:38 +02:00
void MyAsserts::printLocation(){
log() << _file << ":" << _line << " " << _aexp << " != " << _bexp << " ";
}
2009-10-08 17:04:13 +02:00
void MyAsserts::_gotAssert(){
2009-09-17 23:23:38 +02:00
Result::cur->_asserts++;
}
2009-09-18 19:10:07 +02:00
2009-09-17 23:23:38 +02:00
}
void setupSignals(){}
2009-09-17 23:23:38 +02:00
}