/* 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 <NDBT.hpp> #include <NDBT_Test.hpp> #include <HugoTransactions.hpp> #include <UtilTransactions.hpp> #include <NdbRestarter.hpp> #include <NdbRestarts.hpp> #include <Vector.hpp> #include <random.h> #include <NdbTick.h> #define MAX_NDB_OBJECTS 32678 #define CHECK(b) if (!(b)) { \ ndbout << "ERR: "<< step->getName() \ << " failed on line " << __LINE__ << endl; \ result = NDBT_FAILED; \ continue; } #define CHECKE(b) if (!(b)) { \ errors++; \ ndbout << "ERR: "<< step->getName() \ << " failed on line " << __LINE__ << endl; \ result = NDBT_FAILED; \ continue; } int runTestMaxNdb(NDBT_Context* ctx, NDBT_Step* step){ Uint32 loops = ctx->getNumLoops(); Uint32 l = 0; int oldi = 0; int result = NDBT_OK; while (l < loops && result == NDBT_OK){ ndbout_c("loop %d", l + 1); int errors = 0; int maxErrors = 5; Vector<Ndb*> ndbVector; int i = 0; int init = 0; do { Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; errors++; continue; } i++; ndbVector.push_back(pNdb); if (pNdb->init()){ ERR(pNdb->getNdbError()); errors++; continue; } init++; } while (errors == 0); ndbout << i << " ndb objects created" << endl; if (l > 0 && i != oldi && init != MAX_NDB_OBJECTS){ ndbout << l << ": not as manyNdb objects created" << endl << i << " != " << oldi << endl; result = NDBT_FAILED; } oldi = i; for(size_t j = 0; j < ndbVector.size(); j++){ delete ndbVector[j]; if(((j+1) % 250) == 0){ ndbout << "Deleted " << (Uint64) j << " ndb objects " << endl; } } ndbVector.clear(); l++; } return result; } int runTestMaxTransaction(NDBT_Context* ctx, NDBT_Step* step){ Uint32 loops = ctx->getNumLoops(); Uint32 l = 0; int oldi = 0; int result = NDBT_OK; Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init(2048)){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } while (l < loops && result == NDBT_OK){ int errors = 0; int maxErrors = 5; Vector<NdbConnection*> conVector; int i = 0; do { NdbConnection* pCon; int type = i%4; switch (type){ case 0: pCon = pNdb->startTransaction(); break; case 1: pCon = pNdb->startTransaction(2, "DATA", 4); break; case 2: pCon = pNdb->startTransactionDGroup(1, "TEST", 0); break; case 3: pCon = pNdb->startTransactionDGroup(2, "TEST", 1); break; default: abort(); } if (pCon == NULL){ ERR(pNdb->getNdbError()); errors++; continue; } conVector.push_back(pCon); i++; } while (errors < maxErrors); ndbout << i << " connections created" << endl; if (l > 0 && i != oldi){ ndbout << l << ": not as many transactions created" << endl << i << " != " << oldi << endl; result = NDBT_FAILED; } oldi = i; for(size_t j = 0; j < conVector.size(); j++){ pNdb->closeTransaction(conVector[j]); } conVector.clear(); l++; } // BONUS Test closeTransaction with null trans pNdb->closeTransaction(NULL); delete pNdb; return result; } int runTestMaxOperations(NDBT_Context* ctx, NDBT_Step* step){ Uint32 l = 1; int result = NDBT_OK; int maxOpsLimit = 1; const NdbDictionary::Table* pTab = ctx->getTab(); Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init(2048)){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } HugoOperations hugoOps(*pTab); bool endTest = false; while (!endTest && result == NDBT_OK){ int errors = 0; int maxErrors = 5; maxOpsLimit = l*1000; if (hugoOps.startTransaction(pNdb) != NDBT_OK){ delete pNdb; return NDBT_FAILED; } int i = 0; while (errors < maxErrors){ if(hugoOps.pkReadRecord(pNdb,1, 1) != NDBT_OK){ errors++; continue; } i++; if (i >= maxOpsLimit){ errors = maxErrors; } } ndbout << i << " operations used" << endl; int execResult = hugoOps.execute_Commit(pNdb); switch(execResult){ case NDBT_OK: break; case 233: // Out of operation records in transaction coordinator // OK - end test endTest = true; break; default: result = NDBT_FAILED; break; } hugoOps.closeTransaction(pNdb); l++; } delete pNdb; return result; } int runTestGetValue(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; const NdbDictionary::Table* pTab = ctx->getTab(); Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init(2048)){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } HugoOperations hugoOps(*pTab); for (int m = 1; m < 100; m++){ int errors = 0; int maxErrors = 5; NdbConnection* pCon = pNdb->startTransaction(); if (pCon == NULL){ delete pNdb; return NDBT_FAILED; } NdbOperation* pOp = pCon->getNdbOperation(pTab->getName()); if (pOp == NULL){ pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } if (pOp->readTuple() != 0){ pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } for(int a = 0; a<pTab->getNoOfColumns(); a++){ if (pTab->getColumn(a)->getPrimaryKey() == true){ if(hugoOps.equalForAttr(pOp, a, 1) != 0){ ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } } } int i = 0; int maxLimit = 1000*m; do { if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) { const NdbError err = pCon->getNdbError(); ERR(err); if (err.code == 0) result = NDBT_FAILED; errors++; continue; } i++; } while (errors < maxErrors && i < maxLimit); ndbout << i << " getValues called" << endl; if (pCon->execute(Commit) != 0){ const NdbError err = pCon->getNdbError(); switch(err.code){ case 880: // TUP - Read too much case 823: // TUP - Too much AI case 4257: // NDBAPI - Too much AI // OK errors ERR(pCon->getNdbError()); break; default: ERR(pCon->getNdbError()); ndbout << "Illegal error" << endl; result= NDBT_FAILED; break; } } pNdb->closeTransaction(pCon); }// m delete pNdb; return result; } int runTestEqual(NDBT_Context* ctx, NDBT_Step* step){ Uint32 loops = ctx->getNumLoops(); Uint32 l = 0; int result = NDBT_OK; const NdbDictionary::Table* pTab = ctx->getTab(); Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init(2048)){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } HugoOperations hugoOps(*pTab); while (l < loops){ for(int m = 1; m < 10; m++){ int errors = 0; int maxErrors = 5; NdbConnection* pCon = pNdb->startTransaction(); if (pCon == NULL){ ndbout << "Could not start transaction" << endl; delete pNdb; return NDBT_FAILED; } NdbOperation* pOp = pCon->getNdbOperation(pTab->getName()); if (pOp == NULL){ ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } if (pOp->readTuple() != 0){ ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } int i = 0; int maxLimit = 1000*m; do { if ((l%2)!=0){ // Forward for(int a = 0; a<pTab->getNoOfColumns(); a++){ if (pTab->getColumn(a)->getPrimaryKey() == true){ if(hugoOps.equalForAttr(pOp, a, 1) != 0){ const NdbError err = pCon->getNdbError(); ERR(err); if (err.code == 0) result = NDBT_FAILED; errors++; } } } } else { // Backward for(int a = pTab->getNoOfColumns()-1; a>=0; a--){ if (pTab->getColumn(a)->getPrimaryKey() == true){ if(hugoOps.equalForAttr(pOp, a, 1) != 0){ const NdbError err = pCon->getNdbError(); ERR(err); if (err.code == 0) result = NDBT_FAILED; errors++; } } } } i++; } while (errors < maxErrors && i < maxLimit); if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) { const NdbError err = pCon->getNdbError(); ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; if (err.code == 4225) { return NDBT_OK; } else { return NDBT_FAILED; }//if } ndbout << i << " equal called" << endl; int check = pCon->execute(Commit); if (check != 0){ ERR(pCon->getNdbError()); } pNdb->closeTransaction(pCon); }// m l++; }// l delete pNdb; return result; } int runTestDeleteNdb(NDBT_Context* ctx, NDBT_Step* step){ Uint32 loops = ctx->getNumLoops(); Uint32 l = 0; int result = NDBT_OK; NdbRestarts restarts; Vector<Ndb*> ndbVector; const NdbDictionary::Table* pTab = ctx->getTab(); HugoTransactions hugoTrans(*pTab); int records = ctx->getNumRecords(); while (l < loops && result == NDBT_OK){ // Create 5 ndb objects for( int i = 0; i < 5; i++){ Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; result = NDBT_FAILED; goto end_test; } ndbVector.push_back(pNdb); if (pNdb->init()){ ERR(pNdb->getNdbError()); result = NDBT_FAILED; goto end_test; } if (pNdb->waitUntilReady() != 0){ ERR(pNdb->getNdbError()); result = NDBT_FAILED; goto end_test; } if (hugoTrans.pkReadRecords(pNdb, records) != 0){ result = NDBT_FAILED; goto end_test; } } if ((l % 2) == 0){ // Restart random node ndbout << "Restart random node " << endl; if(restarts.executeRestart("RestartRandomNodeAbort", 120) != 0){ g_err << "Failed to executeRestart(RestartRandomNode)"<<endl; result = NDBT_FAILED; goto end_test; } } else { // Restart all nodes ndbout << "Restart all nodes " << endl; if(restarts.executeRestart("RestartAllNodesAbort", 120) != 0){ g_err << "Failed to executeRestart(RestartAllNodes)"<<endl; result = NDBT_FAILED; goto end_test; } } // Delete the ndb objects for(size_t j = 0; j < ndbVector.size(); j++) delete ndbVector[j]; ndbVector.clear(); l++; } end_test: for(size_t i = 0; i < ndbVector.size(); i++) delete ndbVector[i]; ndbVector.clear(); return result; } int runClearTable(NDBT_Context* ctx, NDBT_Step* step){ int records = ctx->getNumRecords(); UtilTransactions utilTrans(*ctx->getTab()); if (utilTrans.clearTable2(GETNDB(step), records) != 0){ return NDBT_FAILED; } return NDBT_OK; } int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){ int records = ctx->getNumRecords(); HugoTransactions hugoTrans(*ctx->getTab()); if (hugoTrans.loadTable(GETNDB(step), records) != 0){ return NDBT_FAILED; } return NDBT_OK; } int runTestWaitUntilReady(NDBT_Context* ctx, NDBT_Step* step){ Ndb* pNdb = new Ndb("TEST_DB"); // Forget about calling pNdb->init(); if (pNdb->waitUntilReady() == 0){ ndbout << "waitUntilReady returned OK" << endl; delete pNdb; return NDBT_FAILED; } const NdbError err = pNdb->getNdbError(); delete pNdb; ERR(err); if (err.code != 4256) return NDBT_FAILED; return NDBT_OK; } int runGetNdbOperationNoTab(NDBT_Context* ctx, NDBT_Step* step){ Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init()){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } NdbConnection* pCon = pNdb->startTransaction(); if (pCon == NULL){ delete pNdb; return NDBT_FAILED; } // Call getNdbOperation on an unknown table NdbOperation* pOp = pCon->getNdbOperation("HUPP76"); if (pOp == NULL){ NdbError err = pCon->getNdbError(); ERR(err); if (err.code == 0){ pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } } pNdb->closeTransaction(pCon); delete pNdb; return NDBT_OK; } int runMissingOperation(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; const NdbDictionary::Table* pTab = ctx->getTab(); Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init()){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } NdbConnection* pCon = pNdb->startTransaction(); if (pCon == NULL){ pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } NdbOperation* pOp = pCon->getNdbOperation(pTab->getName()); if (pOp == NULL){ ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } // Forget about calling pOp->insertTuple(); // Call getValue should not work if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) { const NdbError err = pCon->getNdbError(); ERR(err); if (err.code == 0){ ndbout << "hupp" << endl; result = NDBT_FAILED; } } else { ndbout << "hupp2" << endl; result = NDBT_FAILED; } pNdb->closeTransaction(pCon); delete pNdb; return result; } int runGetValueInUpdate(NDBT_Context* ctx, NDBT_Step* step){ const NdbDictionary::Table* pTab = ctx->getTab(); Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init()){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } NdbConnection* pCon = pNdb->startTransaction(); if (pCon == NULL){ pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } NdbOperation* pOp = pCon->getNdbOperation(pTab->getName()); if (pOp == NULL){ ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } if (pOp->updateTuple() != 0){ pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } // Call getValue should not work if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) { // It didn't work const NdbError err = pCon->getNdbError(); ERR(err); if (err.code == 0){ pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } } else { // It worked, not good! pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } int check = pCon->execute(Commit); if (check != 0){ ERR(pCon->getNdbError()); } pNdb->closeTransaction(pCon); delete pNdb; return NDBT_OK; } int runUpdateWithoutValues(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; const NdbDictionary::Table* pTab = ctx->getTab(); HugoOperations hugoOps(*pTab); Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init()){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } NdbConnection* pCon = pNdb->startTransaction(); if (pCon == NULL){ pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } NdbOperation* pOp = pCon->getNdbOperation(pTab->getName()); if (pOp == NULL){ ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } if (pOp->updateTuple() != 0){ pNdb->closeTransaction(pCon); ERR(pOp->getNdbError()); delete pNdb; return NDBT_FAILED; } for(int a = 0; a<pTab->getNoOfColumns(); a++){ if (pTab->getColumn(a)->getPrimaryKey() == true){ if(hugoOps.equalForAttr(pOp, a, 1) != 0){ ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } } } // Dont' call any setValues // Execute should work int check = pCon->execute(Commit); if (check == 0){ ndbout << "execute worked" << endl; } else { ERR(pCon->getNdbError()); result = NDBT_FAILED; } pNdb->closeTransaction(pCon); delete pNdb; return result; } int runUpdateWithoutKeys(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; const NdbDictionary::Table* pTab = ctx->getTab(); Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init()){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } NdbConnection* pCon = pNdb->startTransaction(); if (pCon == NULL){ pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } NdbOperation* pOp = pCon->getNdbOperation(pTab->getName()); if (pOp == NULL){ ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } if (pOp->updateTuple() != 0){ pNdb->closeTransaction(pCon); ERR(pOp->getNdbError()); delete pNdb; return NDBT_FAILED; } // Dont' call any equal or setValues // Execute should not work int check = pCon->execute(Commit); if (check == 0){ ndbout << "execute worked" << endl; result = NDBT_FAILED; } else { ERR(pCon->getNdbError()); } pNdb->closeTransaction(pCon); delete pNdb; return result; } int runCheckGetNdbErrorOperation(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; const NdbDictionary::Table* pTab = ctx->getTab(); Ndb* pNdb = new Ndb("TEST_DB"); if (pNdb == NULL){ ndbout << "pNdb == NULL" << endl; return NDBT_FAILED; } if (pNdb->init(2048)){ ERR(pNdb->getNdbError()); delete pNdb; return NDBT_FAILED; } HugoOperations hugoOps(*pTab); NdbConnection* pCon = pNdb->startTransaction(); if (pCon == NULL){ ndbout << "Could not start transaction" << endl; delete pNdb; return NDBT_FAILED; } NdbOperation* pOp = pCon->getNdbOperation(pTab->getName()); if (pOp == NULL){ ERR(pCon->getNdbError()); pNdb->closeTransaction(pCon); delete pNdb; return NDBT_FAILED; } // Dont call readTuple here // That's the error! for(int a = 0; a<pTab->getNoOfColumns(); a++){ if (pTab->getColumn(a)->getPrimaryKey() == true){ if(hugoOps.equalForAttr(pOp, a, 1) != 0){ // An error has occured, check that // it's possible to get the NdbErrorOperation const NdbError err = pCon->getNdbError(); ERR(err); if (err.code == 0) result = NDBT_FAILED; NdbOperation* pOp2 = pCon->getNdbErrorOperation(); if (pOp2 == NULL) result = NDBT_FAILED; else { const NdbError err2 = pOp2->getNdbError(); ERR(err2); if (err.code == 0) result = NDBT_FAILED; } } } } pNdb->closeTransaction(pCon); delete pNdb; return result; } NDBT_TESTSUITE(testNdbApi); TESTCASE("MaxNdb", "Create Ndb objects until no more can be created\n"){ INITIALIZER(runTestMaxNdb); } TESTCASE("MaxTransactions", "Start transactions until no more can be created\n"){ INITIALIZER(runTestMaxTransaction); } TESTCASE("MaxOperations", "Get operations until no more can be created\n"){ INITIALIZER(runLoadTable); INITIALIZER(runTestMaxOperations); FINALIZER(runClearTable); } TESTCASE("MaxGetValue", "Call getValue loads of time\n"){ INITIALIZER(runLoadTable); INITIALIZER(runTestGetValue); FINALIZER(runClearTable); } TESTCASE("MaxEqual", "Call equal loads of time\n"){ INITIALIZER(runTestEqual); } TESTCASE("DeleteNdb", "Make sure that a deleted Ndb object is properly deleted\n" "and removed from transporter\n"){ INITIALIZER(runLoadTable); INITIALIZER(runTestDeleteNdb); FINALIZER(runClearTable); } TESTCASE("WaitUntilReady", "Make sure you get an error message when calling waitUntilReady\n" "without an init'ed Ndb\n"){ INITIALIZER(runTestWaitUntilReady); } TESTCASE("GetOperationNoTab", "Call getNdbOperation on a table that does not exist\n"){ INITIALIZER(runGetNdbOperationNoTab); } TESTCASE("MissingOperation", "Missing operation request(insertTuple) should give an error code\n"){ INITIALIZER(runMissingOperation); } TESTCASE("GetValueInUpdate", "Test that it's not possible to perform getValue in an update\n"){ INITIALIZER(runLoadTable); INITIALIZER(runGetValueInUpdate); FINALIZER(runClearTable); } TESTCASE("UpdateWithoutKeys", "Test that it's not possible to perform update without setting\n" "PKs"){ INITIALIZER(runLoadTable); INITIALIZER(runUpdateWithoutKeys); FINALIZER(runClearTable); } TESTCASE("UpdateWithoutValues", "Test that it's not possible to perform update without setValues\n"){ INITIALIZER(runLoadTable); INITIALIZER(runUpdateWithoutValues); FINALIZER(runClearTable); } TESTCASE("NdbErrorOperation", "Test that NdbErrorOperation is properly set"){ INITIALIZER(runCheckGetNdbErrorOperation); } NDBT_TESTSUITE_END(testNdbApi); int main(int argc, const char** argv){ ndb_init(); // TABLE("T1"); return testNdbApi.execute(argc, argv); } template class Vector<Ndb*>; template class Vector<NdbConnection*>;