1
0
mirror of https://github.com/MariaDB/server.git synced 2025-10-30 04:26:45 +03:00
Files
mariadb/ndb/test/src/NDBT_Test.cpp
jonas@eel.(none) 6ec3fa6ac1 ndb
new testprogram testSRBank
2005-09-09 12:39:06 +02:00

1188 lines
28 KiB
C++

/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <ndb_global.h>
#include "NDBT.hpp"
#include "NDBT_Test.hpp"
#include <PortDefs.h>
#include <getarg.h>
#include <time.h>
// No verbose outxput
NDBT_Context::NDBT_Context(){
tab = NULL;
suite = NULL;
testcase = NULL;
ndb = NULL;
records = 1;
loops = 1;
stopped = false;
remote_mgm ="";
propertyMutexPtr = NdbMutex_Create();
propertyCondPtr = NdbCondition_Create();
}
char * NDBT_Context::getRemoteMgm() const {
return remote_mgm;
}
void NDBT_Context::setRemoteMgm(char * mgm) {
remote_mgm = strdup(mgm);
}
NDBT_Context::~NDBT_Context(){
NdbCondition_Destroy(propertyCondPtr);
NdbMutex_Destroy(propertyMutexPtr);
}
const NdbDictionary::Table* NDBT_Context::getTab(){
assert(tab != NULL);
return tab;
}
NDBT_TestSuite* NDBT_Context::getSuite(){
assert(suite != NULL);
return suite;
}
NDBT_TestCase* NDBT_Context::getCase(){
assert(testcase != NULL);
return testcase;
}
int NDBT_Context::getNumRecords() const{
return records;
}
int NDBT_Context::getNumLoops() const{
return loops;
}
int NDBT_Context::getNoOfRunningSteps() const {
return testcase->getNoOfRunningSteps();
}
int NDBT_Context::getNoOfCompletedSteps() const {
return testcase->getNoOfCompletedSteps();
}
Uint32 NDBT_Context::getProperty(const char* _name, Uint32 _default){
Uint32 val;
NdbMutex_Lock(propertyMutexPtr);
if(!props.get(_name, &val))
val = _default;
NdbMutex_Unlock(propertyMutexPtr);
return val;
}
bool NDBT_Context::getPropertyWait(const char* _name, Uint32 _waitVal){
bool result;
NdbMutex_Lock(propertyMutexPtr);
Uint32 val =! _waitVal;
while((!props.get(_name, &val) || (props.get(_name, &val) && val != _waitVal)) &&
!stopped)
NdbCondition_Wait(propertyCondPtr,
propertyMutexPtr);
result = (val == _waitVal);
NdbMutex_Unlock(propertyMutexPtr);
return stopped;
}
const char* NDBT_Context::getProperty(const char* _name, const char* _default){
const char* val;
NdbMutex_Lock(propertyMutexPtr);
if(!props.get(_name, &val))
val = _default;
NdbMutex_Unlock(propertyMutexPtr);
return val;
}
const char* NDBT_Context::getPropertyWait(const char* _name, const char* _waitVal){
const char* val;
NdbMutex_Lock(propertyMutexPtr);
while(!props.get(_name, &val) && (strcmp(val, _waitVal)==0))
NdbCondition_Wait(propertyCondPtr,
propertyMutexPtr);
NdbMutex_Unlock(propertyMutexPtr);
return val;
}
void NDBT_Context::setProperty(const char* _name, Uint32 _val){
NdbMutex_Lock(propertyMutexPtr);
const bool b = props.put(_name, _val, true);
assert(b == true);
NdbMutex_Unlock(propertyMutexPtr);
}
void
NDBT_Context::decProperty(const char * name){
NdbMutex_Lock(propertyMutexPtr);
Uint32 val = 0;
if(props.get(name, &val)){
assert(val > 0);
props.put(name, (val - 1), true);
}
NdbCondition_Broadcast(propertyCondPtr);
NdbMutex_Unlock(propertyMutexPtr);
}
void
NDBT_Context::incProperty(const char * name){
NdbMutex_Lock(propertyMutexPtr);
Uint32 val = 0;
props.get(name, &val);
props.put(name, (val + 1), true);
NdbCondition_Broadcast(propertyCondPtr);
NdbMutex_Unlock(propertyMutexPtr);
}
void NDBT_Context::setProperty(const char* _name, const char* _val){
NdbMutex_Lock(propertyMutexPtr);
const bool b = props.put(_name, _val);
assert(b == true);
NdbMutex_Unlock(propertyMutexPtr);
}
void NDBT_Context::stopTest(){
NdbMutex_Lock(propertyMutexPtr);
g_info << "|- stopTest called" << endl;
stopped = true;
NdbCondition_Broadcast(propertyCondPtr);
NdbMutex_Unlock(propertyMutexPtr);
}
bool NDBT_Context::isTestStopped(){
NdbMutex_Lock(propertyMutexPtr);
bool val = stopped;
NdbMutex_Unlock(propertyMutexPtr);
return val;
}
void NDBT_Context::wait(){
NdbMutex_Lock(propertyMutexPtr);
NdbCondition_Wait(propertyCondPtr,
propertyMutexPtr);
NdbMutex_Unlock(propertyMutexPtr);
}
void NDBT_Context::wait_timeout(int msec){
NdbMutex_Lock(propertyMutexPtr);
NdbCondition_WaitTimeout(propertyCondPtr,
propertyMutexPtr,
msec);
NdbMutex_Unlock(propertyMutexPtr);
}
void NDBT_Context::broadcast(){
NdbMutex_Lock(propertyMutexPtr);
NdbCondition_Broadcast(propertyCondPtr);
NdbMutex_Unlock(propertyMutexPtr);
}
Uint32 NDBT_Context::getDbProperty(const char*){
abort();
return 0;
}
bool NDBT_Context::setDbProperty(const char*, Uint32){
abort();
return true;
}
void NDBT_Context::setTab(const NdbDictionary::Table* ptab){
assert(ptab != NULL);
tab = ptab;
}
void NDBT_Context::setSuite(NDBT_TestSuite* psuite){
assert(psuite != NULL);
suite = psuite;
}
void NDBT_Context::setCase(NDBT_TestCase* pcase){
assert(pcase != NULL);
testcase = pcase;
}
void NDBT_Context::setNumRecords(int _records){
records = _records;
}
void NDBT_Context::setNumLoops(int _loops){
loops = _loops;
}
NDBT_Step::NDBT_Step(NDBT_TestCase* ptest, const char* pname,
NDBT_TESTFUNC* pfunc): name(pname){
assert(pfunc != NULL);
func = pfunc;
testcase = ptest;
step_no = -1;
}
int NDBT_Step::execute(NDBT_Context* ctx) {
assert(ctx != NULL);
int result;
g_info << " |- " << name << " started [" << ctx->suite->getDate() << "]"
<< endl;
result = setUp();
if (result != NDBT_OK){
return result;
}
result = func(ctx, this);
if (result != NDBT_OK) {
g_err << " |- " << name << " FAILED [" << ctx->suite->getDate()
<< "]" << endl;
}
else {
g_info << " |- " << name << " PASSED [" << ctx->suite->getDate() << "]"
<< endl;
}
tearDown();
return result;
}
void NDBT_Step::setContext(NDBT_Context* pctx){
assert(pctx != NULL);
m_ctx = pctx;
}
NDBT_Context* NDBT_Step::getContext(){
assert(m_ctx != NULL);
return m_ctx;
}
NDBT_NdbApiStep::NDBT_NdbApiStep(NDBT_TestCase* ptest,
const char* pname,
NDBT_TESTFUNC* pfunc)
: NDBT_Step(ptest, pname, pfunc),
ndb(NULL) {
}
int
NDBT_NdbApiStep::setUp(){
ndb = new Ndb( "TEST_DB" );
ndb->init(1024);
int result = ndb->waitUntilReady(300); // 5 minutes
if (result != 0){
g_err << name << ": Ndb was not ready" << endl;
return NDBT_FAILED;
}
return NDBT_OK;
}
void
NDBT_NdbApiStep::tearDown(){
delete ndb;
ndb = NULL;
}
Ndb* NDBT_NdbApiStep::getNdb(){
assert(ndb != NULL);
return ndb;
}
NDBT_ParallelStep::NDBT_ParallelStep(NDBT_TestCase* ptest,
const char* pname,
NDBT_TESTFUNC* pfunc)
: NDBT_NdbApiStep(ptest, pname, pfunc) {
}
NDBT_Verifier::NDBT_Verifier(NDBT_TestCase* ptest,
const char* pname,
NDBT_TESTFUNC* pfunc)
: NDBT_NdbApiStep(ptest, pname, pfunc) {
}
NDBT_Initializer::NDBT_Initializer(NDBT_TestCase* ptest,
const char* pname,
NDBT_TESTFUNC* pfunc)
: NDBT_NdbApiStep(ptest, pname, pfunc) {
}
NDBT_Finalizer::NDBT_Finalizer(NDBT_TestCase* ptest,
const char* pname,
NDBT_TESTFUNC* pfunc)
: NDBT_NdbApiStep(ptest, pname, pfunc) {
}
NDBT_TestCase::NDBT_TestCase(NDBT_TestSuite* psuite,
const char* pname,
const char* pcomment) :
name(strdup(pname)) ,
comment(strdup(pcomment)),
suite(psuite)
{
_name.assign(pname);
_comment.assign(pcomment);
name= _name.c_str();
comment= _comment.c_str();
assert(suite != NULL);
}
NDBT_TestCaseImpl1::NDBT_TestCaseImpl1(NDBT_TestSuite* psuite,
const char* pname,
const char* pcomment) :
NDBT_TestCase(psuite, pname, pcomment){
numStepsOk = 0;
numStepsFail = 0;
numStepsCompleted = 0;
waitThreadsMutexPtr = NdbMutex_Create();
waitThreadsCondPtr = NdbCondition_Create();
}
NDBT_TestCaseImpl1::~NDBT_TestCaseImpl1(){
NdbCondition_Destroy(waitThreadsCondPtr);
NdbMutex_Destroy(waitThreadsMutexPtr);
size_t i;
for(i = 0; i < initializers.size(); i++)
delete initializers[i];
initializers.clear();
for(i = 0; i < verifiers.size(); i++)
delete verifiers[i];
verifiers.clear();
for(i = 0; i < finalizers.size(); i++)
delete finalizers[i];
finalizers.clear();
for(i = 0; i < steps.size(); i++)
delete steps[i];
steps.clear();
results.clear();
for(i = 0; i < testTables.size(); i++)
delete testTables[i];
testTables.clear();
for(i = 0; i < testResults.size(); i++)
delete testResults[i];
testResults.clear();
}
int NDBT_TestCaseImpl1::addStep(NDBT_Step* pStep){
assert(pStep != NULL);
steps.push_back(pStep);
pStep->setStepNo(steps.size());
int res = NORESULT;
results.push_back(res);
return 0;
}
int NDBT_TestCaseImpl1::addVerifier(NDBT_Verifier* pVerifier){
assert(pVerifier != NULL);
verifiers.push_back(pVerifier);
return 0;
}
int NDBT_TestCaseImpl1::addInitializer(NDBT_Initializer* pInitializer){
assert(pInitializer != NULL);
initializers.push_back(pInitializer);
return 0;
}
int NDBT_TestCaseImpl1::addFinalizer(NDBT_Finalizer* pFinalizer){
assert(pFinalizer != NULL);
finalizers.push_back(pFinalizer);
return 0;
}
void NDBT_TestCaseImpl1::addTable(const char* tableName, bool isVerify) {
assert(tableName != NULL);
const NdbDictionary::Table* pTable = NDBT_Tables::getTable(tableName);
assert(pTable != NULL);
testTables.push_back(pTable);
isVerifyTables = isVerify;
}
bool NDBT_TestCaseImpl1::tableExists(NdbDictionary::Table* aTable) {
for (unsigned i = 0; i < testTables.size(); i++) {
if (strcasecmp(testTables[i]->getName(), aTable->getName()) == 0) {
return true;
}
}
return false;
}
bool NDBT_TestCaseImpl1::isVerify(const NdbDictionary::Table* aTable) {
if (testTables.size() > 0) {
int found = false;
// OK, we either exclude or include this table in the actual test
for (unsigned i = 0; i < testTables.size(); i++) {
if (strcasecmp(testTables[i]->getName(), aTable->getName()) == 0) {
// Found one!
if (isVerifyTables) {
// Found one to test
found = true;
} else {
// Skip this one!
found = false;
}
}
} // for
return found;
} else {
// No included or excluded test tables, i.e., all tables should be
// tested
return true;
}
return true;
}
void NDBT_TestCase::setProperty(const char* _name, Uint32 _val){
const bool b = props.put(_name, _val);
assert(b == true);
}
void NDBT_TestCase::setProperty(const char* _name, const char* _val){
const bool b = props.put(_name, _val);
assert(b == true);
}
void *
runStep(void * s){
assert(s != NULL);
NDBT_Step* pStep = (NDBT_Step*)s;
NDBT_Context* ctx = pStep->getContext();
assert(ctx != NULL);
// Execute function
int res = pStep->execute(ctx);
if(res != NDBT_OK){
ctx->stopTest();
}
// Report
NDBT_TestCaseImpl1* pCase = (NDBT_TestCaseImpl1*)ctx->getCase();
assert(pCase != NULL);
pCase->reportStepResult(pStep, res);
return NULL;
}
extern "C"
void *
runStep_C(void * s)
{
runStep(s);
return NULL;
}
void NDBT_TestCaseImpl1::startStepInThread(int stepNo, NDBT_Context* ctx){
NDBT_Step* pStep = steps[stepNo];
pStep->setContext(ctx);
char buf[16];
BaseString::snprintf(buf, sizeof(buf), "step_%d", stepNo);
NdbThread* pThread = NdbThread_Create(runStep_C,
(void**)pStep,
65535,
buf,
NDB_THREAD_PRIO_LOW);
threads.push_back(pThread);
}
void NDBT_TestCaseImpl1::waitSteps(){
NdbMutex_Lock(waitThreadsMutexPtr);
while(numStepsCompleted != steps.size())
NdbCondition_Wait(waitThreadsCondPtr,
waitThreadsMutexPtr);
unsigned completedSteps = 0;
unsigned i;
for(i=0; i<steps.size(); i++){
if (results[i] != NORESULT){
completedSteps++;
if (results[i] == NDBT_OK)
numStepsOk++;
else
numStepsFail++;
}
}
assert(completedSteps == steps.size());
assert(completedSteps == numStepsCompleted);
NdbMutex_Unlock(waitThreadsMutexPtr);
void *status;
for(i=0; i<steps.size();i++){
NdbThread_WaitFor(threads[i], &status);
NdbThread_Destroy(&threads[i]);
}
threads.clear();
}
int
NDBT_TestCaseImpl1::getNoOfRunningSteps() const {
return steps.size() - getNoOfCompletedSteps();
}
int
NDBT_TestCaseImpl1::getNoOfCompletedSteps() const {
return numStepsCompleted;
}
void NDBT_TestCaseImpl1::reportStepResult(const NDBT_Step* pStep, int result){
NdbMutex_Lock(waitThreadsMutexPtr);
assert(pStep != NULL);
for (unsigned i = 0; i < steps.size(); i++){
if(steps[i] != NULL && steps[i] == pStep){
results[i] = result;
numStepsCompleted++;
}
}
if(numStepsCompleted == steps.size()){
NdbCondition_Signal(waitThreadsCondPtr);
}
NdbMutex_Unlock(waitThreadsMutexPtr);
}
int NDBT_TestCase::execute(NDBT_Context* ctx){
int res;
ndbout << "- " << name << " started [" << ctx->suite->getDate()
<< "]" << endl;
ctx->setCase(this);
// Copy test case properties to ctx
Properties::Iterator it(&props);
for(const char * key = it.first(); key != 0; key = it.next()){
PropertiesType pt;
const bool b = props.getTypeOf(key, &pt);
assert(b == true);
switch(pt){
case PropertiesType_Uint32:{
Uint32 val;
props.get(key, &val);
ctx->setProperty(key, val);
break;
}
case PropertiesType_char:{
const char * val;
props.get(key, &val);
ctx->setProperty(key, val);
break;
}
default:
abort();
}
}
// start timer so that we get a time even if
// test case consist only of initializer
startTimer(ctx);
if ((res = runInit(ctx)) == NDBT_OK){
// If initialiser is ok, run steps
res = runSteps(ctx);
if (res == NDBT_OK){
// If steps is ok, run verifier
res = runVerifier(ctx);
}
}
stopTimer(ctx);
printTimer(ctx);
// Always run finalizer to clean up db
runFinal(ctx);
if (res == NDBT_OK) {
ndbout << "- " << name << " PASSED [" << ctx->suite->getDate() << "]"
<< endl;
}
else {
ndbout << "- " << name << " FAILED [" << ctx->suite->getDate() << "]"
<< endl;
}
return res;
};
void NDBT_TestCase::startTimer(NDBT_Context* ctx){
timer.doStart();
}
void NDBT_TestCase::stopTimer(NDBT_Context* ctx){
timer.doStop();
}
void NDBT_TestCase::printTimer(NDBT_Context* ctx){
if (suite->timerIsOn()){
g_info << endl;
timer.printTestTimer(ctx->getNumLoops(), ctx->getNumRecords());
}
}
int NDBT_TestCaseImpl1::runInit(NDBT_Context* ctx){
int res = NDBT_OK;
for (unsigned i = 0; i < initializers.size(); i++){
initializers[i]->setContext(ctx);
res = initializers[i]->execute(ctx);
if (res != NDBT_OK)
break;
}
return res;
}
int NDBT_TestCaseImpl1::runSteps(NDBT_Context* ctx){
int res = NDBT_OK;
// Reset variables
numStepsOk = 0;
numStepsFail = 0;
numStepsCompleted = 0;
unsigned i;
for (i = 0; i < steps.size(); i++)
startStepInThread(i, ctx);
waitSteps();
for(i = 0; i < steps.size(); i++)
if (results[i] != NDBT_OK)
res = NDBT_FAILED;
return res;
}
int NDBT_TestCaseImpl1::runVerifier(NDBT_Context* ctx){
int res = NDBT_OK;
for (unsigned i = 0; i < verifiers.size(); i++){
verifiers[i]->setContext(ctx);
res = verifiers[i]->execute(ctx);
if (res != NDBT_OK)
break;
}
return res;
}
int NDBT_TestCaseImpl1::runFinal(NDBT_Context* ctx){
int res = NDBT_OK;
for (unsigned i = 0; i < finalizers.size(); i++){
finalizers[i]->setContext(ctx);
res = finalizers[i]->execute(ctx);
if (res != NDBT_OK)
break;
}
return res;
}
void NDBT_TestCaseImpl1::saveTestResult(const NdbDictionary::Table* ptab,
int result){
testResults.push_back(new NDBT_TestCaseResult(ptab->getName(),
result,
timer.elapsedTime()));
}
void NDBT_TestCaseImpl1::printTestResult(){
char buf[255];
ndbout << name<<endl;
for (unsigned i = 0; i < testResults.size(); i++){
NDBT_TestCaseResult* tcr = testResults[i];
const char* res;
if (tcr->getResult() == NDBT_OK)
res = "OK";
else if (tcr->getResult() == NDBT_FAILED)
res = "FAIL";
else if (tcr->getResult() == FAILED_TO_CREATE)
res = "FAILED TO CREATE TABLE";
else if (tcr->getResult() == FAILED_TO_DISCOVER)
res = "FAILED TO DISCOVER TABLE";
BaseString::snprintf(buf, 255," %-10s %-5s %-20s", tcr->getName(), res, tcr->getTimeStr());
ndbout << buf<<endl;
}
}
NDBT_TestSuite::NDBT_TestSuite(const char* pname):name(pname){
numTestsOk = 0;
numTestsFail = 0;
numTestsExecuted = 0;
records = 0;
loops = 0;
createTable = true;
}
NDBT_TestSuite::~NDBT_TestSuite(){
for(unsigned i=0; i<tests.size(); i++){
delete tests[i];
}
tests.clear();
}
void NDBT_TestSuite::setCreateTable(bool _flag){
createTable = _flag;
}
bool NDBT_TestSuite::timerIsOn(){
return (timer != 0);
}
int NDBT_TestSuite::addTest(NDBT_TestCase* pTest){
assert(pTest != NULL);
tests.push_back(pTest);
return 0;
}
int NDBT_TestSuite::executeAll(const char* _testname){
if(tests.size() == 0)
return NDBT_FAILED;
Ndb ndb("TEST_DB");
ndb.init(1024);
int result = ndb.waitUntilReady(300); // 5 minutes
if (result != 0){
g_err << name <<": Ndb was not ready" << endl;
return NDBT_FAILED;
}
ndbout << name << " started [" << getDate() << "]" << endl;
testSuiteTimer.doStart();
for (int t=0; t < NDBT_Tables::getNumTables(); t++){
const NdbDictionary::Table* ptab = NDBT_Tables::getTable(t);
ndbout << "|- " << ptab->getName() << endl;
execute(&ndb, ptab, _testname);
}
testSuiteTimer.doStop();
return reportAllTables(_testname);
}
int
NDBT_TestSuite::executeOne(const char* _tabname, const char* _testname){
if(tests.size() == 0)
return NDBT_FAILED;
Ndb ndb("TEST_DB");
ndb.init(1024);
int result = ndb.waitUntilReady(300); // 5 minutes
if (result != 0){
g_err << name <<": Ndb was not ready" << endl;
return NDBT_FAILED;
}
ndbout << name << " started [" << getDate() << "]" << endl;
const NdbDictionary::Table* ptab = NDBT_Tables::getTable(_tabname);
if (ptab == NULL)
return NDBT_FAILED;
ndbout << "|- " << ptab->getName() << endl;
execute(&ndb, ptab, _testname);
if (numTestsFail > 0){
return NDBT_FAILED;
}else{
return NDBT_OK;
}
}
void NDBT_TestSuite::execute(Ndb* ndb, const NdbDictionary::Table* pTab,
const char* _testname){
int result;
for (unsigned t = 0; t < tests.size(); t++){
if (_testname != NULL &&
strcasecmp(tests[t]->getName(), _testname) != 0)
continue;
if (tests[t]->isVerify(pTab) == false) {
continue;
}
tests[t]->initBeforeTest();
NdbDictionary::Dictionary* pDict = ndb->getDictionary();
const NdbDictionary::Table* pTab2 = pDict->getTable(pTab->getName());
if (createTable == true){
if(pTab2 != 0 && pDict->dropTable(pTab->getName()) != 0){
numTestsFail++;
numTestsExecuted++;
g_err << "ERROR0: Failed to drop table " << pTab->getName() << endl;
tests[t]->saveTestResult(pTab, FAILED_TO_CREATE);
continue;
}
if(NDBT_Tables::createTable(ndb, pTab->getName()) != 0){
numTestsFail++;
numTestsExecuted++;
g_err << "ERROR1: Failed to create table " << pTab->getName()
<< pDict->getNdbError() << endl;
tests[t]->saveTestResult(pTab, FAILED_TO_CREATE);
continue;
}
pTab2 = pDict->getTable(pTab->getName());
} else if(!pTab2) {
pTab2 = pTab;
}
ctx = new NDBT_Context();
ctx->setTab(pTab2);
ctx->setNumRecords(records);
ctx->setNumLoops(loops);
if(remote_mgm != NULL)
ctx->setRemoteMgm(remote_mgm);
ctx->setSuite(this);
result = tests[t]->execute(ctx);
tests[t]->saveTestResult(pTab, result);
if (result != NDBT_OK)
numTestsFail++;
else
numTestsOk++;
numTestsExecuted++;
if (result == NDBT_OK && createTable == true){
pDict->dropTable(pTab->getName());
}
delete ctx;
}
}
int
NDBT_TestSuite::report(const char* _tcname){
int result;
ndbout << "Completed " << name << " [" << getDate() << "]" << endl;
printTestCaseSummary(_tcname);
ndbout << numTestsExecuted << " test(s) executed" << endl;
ndbout << numTestsOk << " test(s) OK"
<< endl;
if(numTestsFail > 0)
ndbout << numTestsFail << " test(s) failed"
<< endl;
testSuiteTimer.printTotalTime();
if (numTestsFail > 0 || numTestsExecuted == 0){
result = NDBT_FAILED;
}else{
result = NDBT_OK;
}
return result;
}
void NDBT_TestSuite::printTestCaseSummary(const char* _tcname){
ndbout << "= SUMMARY OF TEST EXECUTION ==============" << endl;
for (unsigned t = 0; t < tests.size(); t++){
if (_tcname != NULL &&
strcasecmp(tests[t]->getName(), _tcname) != 0)
continue;
tests[t]->printTestResult();
}
ndbout << "==========================================" << endl;
}
int NDBT_TestSuite::reportAllTables(const char* _testname){
int result;
ndbout << "Completed running test [" << getDate() << "]" << endl;
const int totalNumTests = numTestsExecuted;
printTestCaseSummary(_testname);
ndbout << numTestsExecuted<< " test(s) executed" << endl;
ndbout << numTestsOk << " test(s) OK("
<<(int)(((float)numTestsOk/totalNumTests)*100.0) <<"%)"
<< endl;
if(numTestsFail > 0)
ndbout << numTestsFail << " test(s) failed("
<<(int)(((float)numTestsFail/totalNumTests)*100.0) <<"%)"
<< endl;
testSuiteTimer.printTotalTime();
if (numTestsExecuted > 0){
if (numTestsFail > 0){
result = NDBT_FAILED;
}else{
result = NDBT_OK;
}
} else {
result = NDBT_FAILED;
}
return result;
}
int NDBT_TestSuite::execute(int argc, const char** argv){
int res = NDBT_FAILED;
/* Arguments:
Run only a subset of tests
-n testname Which test to run
Recommendations to test functions:
--records Number of records to use(default: 10000)
--loops Number of loops to execute in the test(default: 100)
Other parameters should:
* be calculated from the above two parameters
* be divided into different test cases, ex. one testcase runs
with FragmentType = Single and another perfoms the same
test with FragmentType = Large
* let the test case iterate over all/subset of appropriate parameters
ex. iterate over FragmentType = Single to FragmentType = AllLarge
Remeber that the intention is that it should be _easy_ to run
a complete test suite without any greater knowledge of what
should be tested ie. keep arguments at a minimum
*/
int _records = 1000;
int _loops = 5;
int _timer = 0;
char * _remote_mgm =NULL;
char* _testname = NULL;
const char* _tabname = NULL;
int _print = false;
int _print_html = false;
int _print_cases = false;
int _verbose = false;
#ifndef DBUG_OFF
const char *debug_option= 0;
#endif
struct getargs args[] = {
{ "print", '\0', arg_flag, &_print, "Print execution tree", "" },
{ "print_html", '\0', arg_flag, &_print_html, "Print execution tree in html table format", "" },
{ "print_cases", '\0', arg_flag, &_print_cases, "Print list of test cases", "" },
{ "records", 'r', arg_integer, &_records, "Number of records", "records" },
{ "loops", 'l', arg_integer, &_loops, "Number of loops", "loops" },
{ "testname", 'n', arg_string, &_testname, "Name of test to run", "testname" },
{ "remote_mgm", 'm', arg_string, &_remote_mgm,
"host:port to mgmsrv of remote cluster", "host:port" },
{ "timer", 't', arg_flag, &_timer, "Print execution time", "time" },
#ifndef DBUG_OFF
{ "debug", 0, arg_string, &debug_option,
"Specify debug options e.g. d:t:i:o,out.trace", "options" },
#endif
{ "verbose", 'v', arg_flag, &_verbose, "Print verbose status", "verbose" }
};
int num_args = sizeof(args) / sizeof(args[0]);
int optind = 0;
if(getarg(args, num_args, argc, argv, &optind)) {
arg_printusage(args, num_args, argv[0], "tabname1 tabname2 ... tabnameN\n");
return NDBT_WRONGARGS;
}
#ifndef DBUG_OFF
if (debug_option)
DBUG_PUSH(debug_option);
#endif
// Check if table name is supplied
if (argv[optind] != NULL)
_tabname = argv[optind];
if (_print == true){
printExecutionTree();
return 0;
}
if (_print_html == true){
printExecutionTreeHTML();
return 0;
}
if (_print_cases == true){
printCases();
return NDBT_ProgramExit(NDBT_FAILED);
}
if (_verbose)
setOutputLevel(2); // Show g_info
else
setOutputLevel(0); // Show only g_err ?
remote_mgm = _remote_mgm;
records = _records;
loops = _loops;
timer = _timer;
if(optind == argc){
// No table specified
res = executeAll(_testname);
} else {
testSuiteTimer.doStart();
Ndb ndb("TEST_DB"); ndb.init();
for(int i = optind; i<argc; i++){
executeOne(argv[i], _testname);
}
testSuiteTimer.doStop();
res = report(_testname);
}
return NDBT_ProgramExit(res);
}
void NDBT_TestSuite::printExecutionTree(){
ndbout << "Testsuite: " << name << endl;
for (unsigned t = 0; t < tests.size(); t++){
tests[t]->print();
ndbout << endl;
}
}
void NDBT_TestSuite::printExecutionTreeHTML(){
ndbout << "<tr>" << endl;
ndbout << "<td><h3>" << name << "</h3></td>" << endl;
ndbout << "</tr>" << endl;
for (unsigned t = 0; t < tests.size(); t++){
tests[t]->printHTML();
ndbout << endl;
}
}
void NDBT_TestSuite::printCases(){
ndbout << "# Testsuite: " << name << endl;
ndbout << "# Number of tests: " << tests.size() << endl;
for (unsigned t = 0; t < tests.size(); t++){
ndbout << name << " -n " << tests[t]->getName() << endl;
}
}
const char* NDBT_TestSuite::getDate(){
static char theTime[128];
struct tm* tm_now;
time_t now;
now = time((time_t*)NULL);
#ifdef NDB_WIN32
tm_now = localtime(&now);
#else
tm_now = gmtime(&now);
#endif
BaseString::snprintf(theTime, 128,
"%d-%.2d-%.2d %.2d:%.2d:%.2d",
tm_now->tm_year + 1900,
tm_now->tm_mon + 1,
tm_now->tm_mday,
tm_now->tm_hour,
tm_now->tm_min,
tm_now->tm_sec);
return theTime;
}
void NDBT_TestCaseImpl1::printHTML(){
ndbout << "<tr><td>&nbsp;</td>" << endl;
ndbout << "<td name=tc>" << endl << name << "</td><td width=70%>"
<< comment << "</td></tr>" << endl;
}
void NDBT_TestCaseImpl1::print(){
ndbout << "Test case: " << name << endl;
ndbout << "Description: "<< comment << endl;
ndbout << "Parameters: " << endl;
Properties::Iterator it(&props);
for(const char * key = it.first(); key != 0; key = it.next()){
PropertiesType pt;
const bool b = props.getTypeOf(key, &pt);
assert(b == true);
switch(pt){
case PropertiesType_Uint32:{
Uint32 val;
props.get(key, &val);
ndbout << " " << key << ": " << val << endl;
break;
}
case PropertiesType_char:{
const char * val;
props.get(key, &val);
ndbout << " " << key << ": " << val << endl;
break;
}
default:
abort();
}
}
unsigned i;
for(i=0; i<initializers.size(); i++){
ndbout << "Initializers[" << i << "]: " << endl;
initializers[i]->print();
}
for(i=0; i<steps.size(); i++){
ndbout << "Step[" << i << "]: " << endl;
steps[i]->print();
}
for(i=0; i<verifiers.size(); i++){
ndbout << "Verifier[" << i << "]: " << endl;
verifiers[i]->print();
}
for(i=0; i<finalizers.size(); i++){
ndbout << "Finalizer[" << i << "]: " << endl;
finalizers[i]->print();
}
}
void NDBT_Step::print(){
ndbout << " "<< name << endl;
}
void
NDBT_Context::sync_down(const char * key){
Uint32 threads = getProperty(key, (unsigned)0);
if(threads){
decProperty(key);
}
}
void
NDBT_Context::sync_up_and_wait(const char * key, Uint32 value){
setProperty(key, value);
getPropertyWait(key, (unsigned)0);
}
template class Vector<NDBT_TestCase*>;
template class Vector<NDBT_TestCaseResult*>;
template class Vector<NDBT_Step*>;
template class Vector<NdbThread*>;
template class Vector<NDBT_Verifier*>;
template class Vector<NDBT_Initializer*>;
template class Vector<NDBT_Finalizer*>;
template class Vector<const NdbDictionary::Table*>;