diff options
Diffstat (limited to 'storage/ndb/test/src/NDBT_Test.cpp')
-rw-r--r-- | storage/ndb/test/src/NDBT_Test.cpp | 1188 |
1 files changed, 1188 insertions, 0 deletions
diff --git a/storage/ndb/test/src/NDBT_Test.cpp b/storage/ndb/test/src/NDBT_Test.cpp new file mode 100644 index 00000000000..7fd92db533e --- /dev/null +++ b/storage/ndb/test/src/NDBT_Test.cpp @@ -0,0 +1,1188 @@ +/* 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 <my_pthread.h> + +#include "NDBT.hpp" +#include "NDBT_Test.hpp" + +#include <PortDefs.h> + +#include <getarg.h> +#include <time.h> + +// No verbose outxput + +NDBT_Context::NDBT_Context(Ndb_cluster_connection& con) + : m_cluster_connection(con) +{ + 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::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(ctx->m_cluster_connection); + 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_cluster_connection& con){ + ndb = new Ndb(&con, "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(Ndb_cluster_connection& con, + const char* _testname){ + + if(tests.size() == 0) + return NDBT_FAILED; + Ndb ndb(&con, "TEST_DB"); + ndb.init(1024); + + int result = ndb.waitUntilReady(500); // 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(con, &ndb, ptab, _testname); + } + testSuiteTimer.doStop(); + return reportAllTables(_testname); +} + +int +NDBT_TestSuite::executeOne(Ndb_cluster_connection& con, + const char* _tabname, const char* _testname){ + + if(tests.size() == 0) + return NDBT_FAILED; + Ndb ndb(&con, "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(con, &ndb, ptab, _testname); + + if (numTestsFail > 0){ + return NDBT_FAILED; + }else{ + return NDBT_OK; + } +} + +void NDBT_TestSuite::execute(Ndb_cluster_connection& con, + 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(con); + 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; + + Ndb_cluster_connection con; + if(con.connect(12, 5, 1)) + { + return NDBT_ProgramExit(NDBT_FAILED); + } + + if(optind == argc){ + // No table specified + res = executeAll(con, _testname); + } else { + testSuiteTimer.doStart(); + for(int i = optind; i<argc; i++){ + executeOne(con, 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> </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*>; |