1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 #include <ndb_opts.h>
27 
28 #include "NDBT.hpp"
29 #include "NDBT_Test.hpp"
30 
NDBT_Context(Ndb_cluster_connection & con)31 NDBT_Context::NDBT_Context(Ndb_cluster_connection& con)
32   : m_cluster_connection(con)
33 {
34   suite = NULL;
35   testcase = NULL;
36   ndb = NULL;
37   records = 1;
38   loops = 1;
39   stopped = false;
40   propertyMutexPtr = NdbMutex_Create();
41   propertyCondPtr = NdbCondition_Create();
42 }
43 
44 
~NDBT_Context()45 NDBT_Context::~NDBT_Context(){
46   NdbCondition_Destroy(propertyCondPtr);
47   NdbMutex_Destroy(propertyMutexPtr);
48 }
49 
getTab()50 const NdbDictionary::Table* NDBT_Context::getTab(){
51   assert(tables.size());
52   return tables[0];
53 }
54 
getSuite()55 NDBT_TestSuite* NDBT_Context::getSuite(){
56   assert(suite != NULL);
57   return suite;
58 }
59 
getCase()60 NDBT_TestCase* NDBT_Context::getCase(){
61   assert(testcase != NULL);
62   return testcase;
63 }
64 
getTableName(int n) const65 const char* NDBT_Context::getTableName(int n) const
66 {
67   assert(suite != NULL);
68   return suite->m_tables_in_test[n].c_str();
69 }
70 
getNumTables() const71 int NDBT_Context::getNumTables() const
72 {
73   assert(suite != NULL);
74   return suite->m_tables_in_test.size();
75 }
76 
getNumRecords() const77 int NDBT_Context::getNumRecords() const{
78   return records;
79 }
80 
getNumLoops() const81 int NDBT_Context::getNumLoops() const{
82   return loops;
83 }
84 
getNoOfRunningSteps() const85 int NDBT_Context::getNoOfRunningSteps() const {
86   return testcase->getNoOfRunningSteps();
87 
88 }
getNoOfCompletedSteps() const89 int NDBT_Context::getNoOfCompletedSteps() const {
90   return testcase->getNoOfCompletedSteps();
91 }
92 
93 
getProperty(const char * _name,Uint32 _default)94 Uint32 NDBT_Context::getProperty(const char* _name, Uint32 _default){
95   Uint32 val;
96   NdbMutex_Lock(propertyMutexPtr);
97   if(!props.get(_name, &val))
98     val = _default;
99   NdbMutex_Unlock(propertyMutexPtr);
100   return val;
101 }
102 
getPropertyWait(const char * _name,Uint32 _waitVal)103 bool NDBT_Context::getPropertyWait(const char* _name, Uint32 _waitVal){
104   bool result;
105   NdbMutex_Lock(propertyMutexPtr);
106   Uint32 val =! _waitVal;
107 
108   while((!props.get(_name, &val) || (props.get(_name, &val) && val != _waitVal)) &&
109 	!stopped)
110     NdbCondition_Wait(propertyCondPtr,
111 		      propertyMutexPtr);
112   result = (val == _waitVal);
113   NdbMutex_Unlock(propertyMutexPtr);
114   return stopped;
115 }
116 
getProperty(const char * _name,const char * _default)117 const char* NDBT_Context::getProperty(const char* _name, const char* _default){
118   const char* val;
119   NdbMutex_Lock(propertyMutexPtr);
120   if(!props.get(_name, &val))
121     val = _default;
122   NdbMutex_Unlock(propertyMutexPtr);
123   return val;
124 }
125 
getPropertyWait(const char * _name,const char * _waitVal)126 const char* NDBT_Context::getPropertyWait(const char* _name, const char* _waitVal){
127   const char* val;
128   NdbMutex_Lock(propertyMutexPtr);
129   while(!props.get(_name, &val) && (strcmp(val, _waitVal)==0))
130     NdbCondition_Wait(propertyCondPtr,
131 		      propertyMutexPtr);
132 
133   NdbMutex_Unlock(propertyMutexPtr);
134   return val;
135 }
136 
setProperty(const char * _name,Uint32 _val)137 void  NDBT_Context::setProperty(const char* _name, Uint32 _val){
138   NdbMutex_Lock(propertyMutexPtr);
139   const bool b = props.put(_name, _val, true);
140   assert(b == true);
141   NdbCondition_Broadcast(propertyCondPtr);
142   NdbMutex_Unlock(propertyMutexPtr);
143 }
144 
145 void
decProperty(const char * name)146 NDBT_Context::decProperty(const char * name){
147   NdbMutex_Lock(propertyMutexPtr);
148   Uint32 val = 0;
149   if(props.get(name, &val)){
150     assert(val > 0);
151     props.put(name, (val - 1), true);
152   }
153   NdbCondition_Broadcast(propertyCondPtr);
154   NdbMutex_Unlock(propertyMutexPtr);
155 }
156 
157 void
incProperty(const char * name)158 NDBT_Context::incProperty(const char * name){
159   NdbMutex_Lock(propertyMutexPtr);
160   Uint32 val = 0;
161   props.get(name, &val);
162   props.put(name, (val + 1), true);
163   NdbCondition_Broadcast(propertyCondPtr);
164   NdbMutex_Unlock(propertyMutexPtr);
165 }
166 
167 Uint32
casProperty(const char * name,Uint32 oldValue,Uint32 newValue)168 NDBT_Context::casProperty(const char * name, Uint32 oldValue, Uint32 newValue)
169 {
170   NdbMutex_Lock(propertyMutexPtr);
171   Uint32 val = 0;
172   props.get(name, &val);
173   if (val == oldValue)
174   {
175     props.put(name, newValue, true);
176     NdbCondition_Broadcast(propertyCondPtr);
177   }
178   NdbMutex_Unlock(propertyMutexPtr);
179   return val;
180 }
181 
setProperty(const char * _name,const char * _val)182 void  NDBT_Context::setProperty(const char* _name, const char* _val){
183   NdbMutex_Lock(propertyMutexPtr);
184   const bool b = props.put(_name, _val, true);
185   assert(b == true);
186   NdbCondition_Broadcast(propertyCondPtr);
187   NdbMutex_Unlock(propertyMutexPtr);
188 }
189 
stopTest()190 void NDBT_Context::stopTest(){
191   NdbMutex_Lock(propertyMutexPtr);
192   g_info << "|- stopTest called" << endl;
193   stopped = true;
194   NdbCondition_Broadcast(propertyCondPtr);
195   NdbMutex_Unlock(propertyMutexPtr);
196 }
197 
isTestStopped()198 bool NDBT_Context::isTestStopped(){
199   NdbMutex_Lock(propertyMutexPtr);
200   bool val = stopped;
201   NdbMutex_Unlock(propertyMutexPtr);
202   return val;
203 }
204 
wait()205 void NDBT_Context::wait(){
206   NdbMutex_Lock(propertyMutexPtr);
207   NdbCondition_Wait(propertyCondPtr,
208 		    propertyMutexPtr);
209   NdbMutex_Unlock(propertyMutexPtr);
210 }
211 
wait_timeout(int msec)212 void NDBT_Context::wait_timeout(int msec){
213   NdbMutex_Lock(propertyMutexPtr);
214   NdbCondition_WaitTimeout(propertyCondPtr,
215 			   propertyMutexPtr,
216 			   msec);
217   NdbMutex_Unlock(propertyMutexPtr);
218 }
219 
broadcast()220 void NDBT_Context::broadcast(){
221   NdbMutex_Lock(propertyMutexPtr);
222   NdbCondition_Broadcast(propertyCondPtr);
223   NdbMutex_Unlock(propertyMutexPtr);
224 }
225 
getDbProperty(const char *)226 Uint32 NDBT_Context::getDbProperty(const char*){
227   abort();
228   return 0;
229 }
230 
setDbProperty(const char *,Uint32)231 bool NDBT_Context::setDbProperty(const char*, Uint32){
232   abort();
233   return true;
234 }
235 
setTab(const NdbDictionary::Table * ptab)236 void NDBT_Context::setTab(const NdbDictionary::Table* ptab){
237   tables.clear();
238   tables.push_back(ptab);
239   tables.push_back(0);
240 }
241 
addTab(const NdbDictionary::Table * ptab)242 void NDBT_Context::addTab(const NdbDictionary::Table* ptab){
243   if(tables.size())
244     tables.back() = ptab;
245   else
246     tables.push_back(ptab);
247 
248   tables.push_back(0);
249 }
250 
251 
252 const NdbDictionary::Table**
getTables()253 NDBT_Context::getTables()
254 {
255   return tables.getBase();
256 }
257 
setSuite(NDBT_TestSuite * psuite)258 void NDBT_Context::setSuite(NDBT_TestSuite* psuite){
259   assert(psuite != NULL);
260   suite = psuite;
261 }
262 
setCase(NDBT_TestCase * pcase)263 void NDBT_Context::setCase(NDBT_TestCase* pcase){
264   assert(pcase != NULL);
265   testcase = pcase;
266 }
267 
setNumRecords(int _records)268 void NDBT_Context::setNumRecords(int _records){
269   records = _records;
270 
271 }
272 
setNumLoops(int _loops)273 void NDBT_Context::setNumLoops(int _loops){
274   loops = _loops;
275 }
276 
NDBT_Step(NDBT_TestCase * ptest,const char * pname,NDBT_TESTFUNC * pfunc)277 NDBT_Step::NDBT_Step(NDBT_TestCase* ptest, const char* pname,
278                      NDBT_TESTFUNC* pfunc) :
279   m_ctx(NULL), name(pname), func(pfunc),
280   testcase(ptest), step_no(-1), m_ndb(NULL)
281 {
282 }
283 
284 #include "../../src/ndbapi/ndb_internal.hpp"
285 
286 int
setUp(Ndb_cluster_connection & con)287 NDBT_Step::setUp(Ndb_cluster_connection& con){
288 
289   switch(testcase->getDriverType())
290   {
291   case DummyDriver:
292     break;
293 
294   case NdbApiDriver:
295   {
296     m_ndb = new Ndb(&con, "TEST_DB" );
297     m_ndb->init(1024);
298 
299     Ndb_internal::setForceShortRequests(m_ndb,
300                                         m_ctx->suite->getForceShort());
301 
302     int result = m_ndb->waitUntilReady(300); // 5 minutes
303     if (result != 0){
304       g_err << "Ndb was not ready" << endl;
305       return NDBT_FAILED;
306     }
307     break;
308   }
309 
310   default:
311     abort();
312     break;
313 
314   }
315 
316   return NDBT_OK;
317 }
318 
319 
320 void
tearDown()321 NDBT_Step::tearDown(){
322   delete m_ndb;
323   m_ndb = NULL;
324 }
325 
326 
getNdb() const327 Ndb* NDBT_Step::getNdb() const {
328   assert(m_ndb != NULL);
329   return m_ndb;
330 }
331 
332 
execute(NDBT_Context * ctx)333 int NDBT_Step::execute(NDBT_Context* ctx) {
334   assert(ctx != NULL);
335 
336   int result;
337 
338   g_info << "  |- " << name << " started [" << ctx->suite->getDate() << "]"
339 	 << endl;
340 
341   result = setUp(ctx->m_cluster_connection);
342   if (result != NDBT_OK){
343     return result;
344   }
345 
346   result = func(ctx, this);
347 
348   if (result != NDBT_OK) {
349     g_err << "  |- " << name << " FAILED [" << ctx->suite->getDate()
350 	   << "]" << endl;
351   }
352    else {
353     g_info << "  |- " << name << " PASSED [" << ctx->suite->getDate() << "]"
354 	   << endl;
355   }
356 
357   tearDown();
358 
359   return result;
360 }
361 
setContext(NDBT_Context * pctx)362 void NDBT_Step::setContext(NDBT_Context* pctx){
363   assert(pctx != NULL);
364   m_ctx = pctx;
365 }
366 
getContext()367 NDBT_Context* NDBT_Step::getContext(){
368   assert(m_ctx != NULL);
369   return m_ctx;
370 }
371 
372 
NDBT_ParallelStep(NDBT_TestCase * ptest,const char * pname,NDBT_TESTFUNC * pfunc)373 NDBT_ParallelStep::NDBT_ParallelStep(NDBT_TestCase* ptest,
374 				     const char* pname,
375 				     NDBT_TESTFUNC* pfunc)
376   : NDBT_Step(ptest, pname, pfunc) {
377 }
NDBT_Verifier(NDBT_TestCase * ptest,const char * pname,NDBT_TESTFUNC * pfunc)378 NDBT_Verifier::NDBT_Verifier(NDBT_TestCase* ptest,
379 			     const char* pname,
380 			     NDBT_TESTFUNC* pfunc)
381   : NDBT_Step(ptest, pname, pfunc) {
382 }
NDBT_Initializer(NDBT_TestCase * ptest,const char * pname,NDBT_TESTFUNC * pfunc)383 NDBT_Initializer::NDBT_Initializer(NDBT_TestCase* ptest,
384 				   const char* pname,
385 				   NDBT_TESTFUNC* pfunc)
386   : NDBT_Step(ptest, pname, pfunc) {
387 }
NDBT_Finalizer(NDBT_TestCase * ptest,const char * pname,NDBT_TESTFUNC * pfunc)388 NDBT_Finalizer::NDBT_Finalizer(NDBT_TestCase* ptest,
389 			       const char* pname,
390 			       NDBT_TESTFUNC* pfunc)
391   : NDBT_Step(ptest, pname, pfunc) {
392 }
393 
NDBT_TestCase(NDBT_TestSuite * psuite,const char * pname,const char * pcomment)394 NDBT_TestCase::NDBT_TestCase(NDBT_TestSuite* psuite,
395 			     const char* pname,
396 			     const char* pcomment) :
397   _name(pname) ,
398   _comment(pcomment),
399   suite(psuite)
400 {
401   assert(suite != NULL);
402 
403   m_all_tables = false;
404   m_has_run = false;
405 }
406 
NDBT_TestCaseImpl1(NDBT_TestSuite * psuite,const char * pname,const char * pcomment)407 NDBT_TestCaseImpl1::NDBT_TestCaseImpl1(NDBT_TestSuite* psuite,
408 				       const char* pname,
409 				       const char* pcomment) :
410   NDBT_TestCase(psuite, pname, pcomment){
411 
412   numStepsOk = 0;
413   numStepsFail = 0;
414   numStepsCompleted = 0;
415   waitThreadsMutexPtr = NdbMutex_Create();
416   waitThreadsCondPtr = NdbCondition_Create();
417 
418   m_driverType= psuite->getDriverType();
419 }
420 
~NDBT_TestCaseImpl1()421 NDBT_TestCaseImpl1::~NDBT_TestCaseImpl1(){
422   NdbCondition_Destroy(waitThreadsCondPtr);
423   NdbMutex_Destroy(waitThreadsMutexPtr);
424   size_t i;
425   for(i = 0; i < initializers.size();  i++)
426     delete initializers[i];
427   initializers.clear();
428   for(i = 0; i < verifiers.size();  i++)
429     delete verifiers[i];
430   verifiers.clear();
431   for(i = 0; i < finalizers.size();  i++)
432     delete finalizers[i];
433   finalizers.clear();
434   for(i = 0; i < steps.size();  i++)
435     delete steps[i];
436   steps.clear();
437   results.clear();
438   for(i = 0; i < testTables.size();  i++)
439     delete testTables[i];
440   testTables.clear();
441   for(i = 0; i < testResults.size();  i++)
442     delete testResults[i];
443   testResults.clear();
444 
445 }
446 
addStep(NDBT_Step * pStep)447 int NDBT_TestCaseImpl1::addStep(NDBT_Step* pStep){
448   assert(pStep != NULL);
449   steps.push_back(pStep);
450   pStep->setStepNo(steps.size());
451   int res = NORESULT;
452   results.push_back(res);
453   return 0;
454 }
455 
addVerifier(NDBT_Verifier * pVerifier)456 int NDBT_TestCaseImpl1::addVerifier(NDBT_Verifier* pVerifier){
457   assert(pVerifier != NULL);
458   verifiers.push_back(pVerifier);
459   return 0;
460 }
461 
addInitializer(NDBT_Initializer * pInitializer,bool first)462 int NDBT_TestCaseImpl1::addInitializer(NDBT_Initializer* pInitializer,
463                                        bool first){
464   assert(pInitializer != NULL);
465   if (first)
466     initializers.push(pInitializer, 0);
467   else
468     initializers.push_back(pInitializer);
469   return 0;
470 }
471 
addFinalizer(NDBT_Finalizer * pFinalizer)472 int NDBT_TestCaseImpl1::addFinalizer(NDBT_Finalizer* pFinalizer){
473   assert(pFinalizer != NULL);
474   finalizers.push_back(pFinalizer);
475   return 0;
476 }
477 
addTable(const char * tableName,bool isVerify)478 void NDBT_TestCaseImpl1::addTable(const char* tableName, bool isVerify) {
479   assert(tableName != NULL);
480   const NdbDictionary::Table* pTable = NDBT_Tables::getTable(tableName);
481   assert(pTable != NULL);
482   testTables.push_back(pTable);
483   isVerifyTables = isVerify;
484 }
485 
tableExists(NdbDictionary::Table * aTable)486 bool NDBT_TestCaseImpl1::tableExists(NdbDictionary::Table* aTable) {
487   for (unsigned i = 0; i < testTables.size(); i++) {
488     if (strcasecmp(testTables[i]->getName(), aTable->getName()) == 0) {
489       return true;
490     }
491   }
492   return false;
493 }
494 
isVerify(const NdbDictionary::Table * aTable)495 bool NDBT_TestCaseImpl1::isVerify(const NdbDictionary::Table* aTable) {
496   if (testTables.size() > 0) {
497     int found = false;
498     // OK, we either exclude or include this table in the actual test
499     for (unsigned i = 0; i < testTables.size(); i++) {
500       if (strcasecmp(testTables[i]->getName(), aTable->getName()) == 0) {
501 	// Found one!
502 	if (isVerifyTables) {
503 	  // Found one to test
504 	  found = true;
505 	} else {
506 	  // Skip this one!
507 	  found = false;
508 	}
509       }
510     } // for
511     return found;
512   } else {
513     // No included or excluded test tables, i.e., all tables should be
514     // tested
515     return true;
516   }
517   return true;
518 }
519 
setProperty(const char * _name,Uint32 _val)520 void  NDBT_TestCase::setProperty(const char* _name, Uint32 _val){
521   const bool b = props.put(_name, _val);
522   assert(b == true);
523 }
524 
setProperty(const char * _name,const char * _val)525 void  NDBT_TestCase::setProperty(const char* _name, const char* _val){
526   const bool b = props.put(_name, _val);
527   assert(b == true);
528 }
529 
530 
531 void *
runStep(void * s)532 runStep(void * s){
533   assert(s != NULL);
534   NDBT_Step* pStep = (NDBT_Step*)s;
535   NDBT_Context* ctx = pStep->getContext();
536   assert(ctx != NULL);
537    // Execute function
538   int res = pStep->execute(ctx);
539   if(res != NDBT_OK){
540     ctx->stopTest();
541   }
542   // Report
543   NDBT_TestCaseImpl1* pCase = (NDBT_TestCaseImpl1*)ctx->getCase();
544   assert(pCase != NULL);
545   pCase->reportStepResult(pStep, res);
546   return NULL;
547 }
548 
549 extern "C"
550 void *
runStep_C(void * s)551 runStep_C(void * s)
552 {
553   runStep(s);
554   return NULL;
555 }
556 
557 
startStepInThread(int stepNo,NDBT_Context * ctx)558 void NDBT_TestCaseImpl1::startStepInThread(int stepNo, NDBT_Context* ctx){
559   NDBT_Step* pStep = steps[stepNo];
560   pStep->setContext(ctx);
561   char buf[16];
562   BaseString::snprintf(buf, sizeof(buf), "step_%d", stepNo);
563   Uint32 stackSize = ctx->getProperty(NDBT_TestCase::getStepThreadStackSizePropName(),
564                                       Uint32(0));
565 
566   NdbThread* pThread = NdbThread_Create(runStep_C,
567 					(void**)pStep,
568                                         stackSize,
569 					buf,
570 					NDB_THREAD_PRIO_LOW);
571   threads.push_back(pThread);
572 }
573 
waitSteps()574 void NDBT_TestCaseImpl1::waitSteps(){
575   NdbMutex_Lock(waitThreadsMutexPtr);
576   while(numStepsCompleted != steps.size())
577     NdbCondition_Wait(waitThreadsCondPtr,
578 		     waitThreadsMutexPtr);
579 
580   unsigned completedSteps = 0;
581   unsigned i;
582   for(i=0; i<steps.size(); i++){
583     if (results[i] != NORESULT){
584       completedSteps++;
585       if (results[i] == NDBT_OK)
586 	numStepsOk++;
587       else
588 	numStepsFail++;
589     }
590   }
591   assert(completedSteps == steps.size());
592   assert(completedSteps == numStepsCompleted);
593 
594   NdbMutex_Unlock(waitThreadsMutexPtr);
595   void *status;
596   for(i=0; i<steps.size();i++){
597     NdbThread_WaitFor(threads[i], &status);
598     NdbThread_Destroy(&threads[i]);
599   }
600   threads.clear();
601 }
602 
603 
604 int
getNoOfRunningSteps() const605 NDBT_TestCaseImpl1::getNoOfRunningSteps() const {
606   return steps.size() - getNoOfCompletedSteps();
607 }
608 
609 int
getNoOfCompletedSteps() const610 NDBT_TestCaseImpl1::getNoOfCompletedSteps() const {
611   return numStepsCompleted;
612 }
613 
reportStepResult(const NDBT_Step * pStep,int result)614 void NDBT_TestCaseImpl1::reportStepResult(const NDBT_Step* pStep, int result){
615   NdbMutex_Lock(waitThreadsMutexPtr);
616   assert(pStep != NULL);
617   for (unsigned i = 0; i < steps.size(); i++){
618     if(steps[i] != NULL && steps[i] == pStep){
619       results[i] = result;
620       numStepsCompleted++;
621     }
622   }
623   if(numStepsCompleted == steps.size()){
624     NdbCondition_Signal(waitThreadsCondPtr);
625   }
626   NdbMutex_Unlock(waitThreadsMutexPtr);
627 }
628 
629 
execute(NDBT_Context * ctx)630 int NDBT_TestCase::execute(NDBT_Context* ctx){
631   int res;
632 
633   ndbout << "- " << _name << " started [" << ctx->suite->getDate()
634 	 << "]" << endl;
635 
636   ctx->setCase(this);
637 
638   // Copy test case properties to ctx
639   Properties::Iterator it(&props);
640   for(const char * key = it.first(); key != 0; key = it.next()){
641 
642     PropertiesType pt;
643     const bool b = props.getTypeOf(key, &pt);
644     assert(b == true);
645     switch(pt){
646     case PropertiesType_Uint32:{
647       Uint32 val;
648       props.get(key, &val);
649       ctx->setProperty(key, val);
650       break;
651     }
652     case PropertiesType_char:{
653       const char * val;
654       props.get(key, &val);
655       ctx->setProperty(key, val);
656       break;
657     }
658     default:
659       abort();
660     }
661   }
662 
663   // start timer so that we get a time even if
664   // test case consist only of initializer
665   startTimer(ctx);
666 
667   if ((res = runInit(ctx)) == NDBT_OK){
668     // If initialiser is ok, run steps
669 
670     res = runSteps(ctx);
671     if (res == NDBT_OK){
672       // If steps is ok, run verifier
673       res = runVerifier(ctx);
674     }
675 
676   }
677 
678   stopTimer(ctx);
679   printTimer(ctx);
680 
681   // Always run finalizer to clean up db
682   runFinal(ctx);
683 
684   if (res == NDBT_OK) {
685     ndbout << "- " << _name << " PASSED [" << ctx->suite->getDate() << "]"
686 	   << endl;
687   }
688   else {
689     ndbout << "- " << _name << " FAILED [" << ctx->suite->getDate() << "]"
690 	   << endl;
691   }
692   return res;
693 }
694 
startTimer(NDBT_Context * ctx)695 void NDBT_TestCase::startTimer(NDBT_Context* ctx){
696   timer.doStart();
697 }
698 
stopTimer(NDBT_Context * ctx)699 void NDBT_TestCase::stopTimer(NDBT_Context* ctx){
700   timer.doStop();
701 }
702 
printTimer(NDBT_Context * ctx)703 void NDBT_TestCase::printTimer(NDBT_Context* ctx){
704   if (suite->timerIsOn()){
705     g_info << endl;
706     timer.printTestTimer(ctx->getNumLoops(), ctx->getNumRecords());
707   }
708 }
709 
runInit(NDBT_Context * ctx)710 int NDBT_TestCaseImpl1::runInit(NDBT_Context* ctx){
711   int res = NDBT_OK;
712   for (unsigned i = 0; i < initializers.size(); i++){
713     initializers[i]->setContext(ctx);
714     res = initializers[i]->execute(ctx);
715     if (res != NDBT_OK)
716       break;
717   }
718   return res;
719 }
720 
runSteps(NDBT_Context * ctx)721 int NDBT_TestCaseImpl1::runSteps(NDBT_Context* ctx){
722   int res = NDBT_OK;
723 
724   // Reset variables
725   numStepsOk = 0;
726   numStepsFail = 0;
727   numStepsCompleted = 0;
728   unsigned i;
729   for (i = 0; i < steps.size(); i++)
730     startStepInThread(i, ctx);
731   waitSteps();
732 
733   for(i = 0; i < steps.size(); i++)
734     if (results[i] != NDBT_OK)
735       res = NDBT_FAILED;
736   return res;
737 }
738 
runVerifier(NDBT_Context * ctx)739 int NDBT_TestCaseImpl1::runVerifier(NDBT_Context* ctx){
740   int res = NDBT_OK;
741   for (unsigned i = 0; i < verifiers.size(); i++){
742     verifiers[i]->setContext(ctx);
743     res = verifiers[i]->execute(ctx);
744     if (res != NDBT_OK)
745       break;
746   }
747   return res;
748 }
749 
runFinal(NDBT_Context * ctx)750 int NDBT_TestCaseImpl1::runFinal(NDBT_Context* ctx){
751   int res = NDBT_OK;
752   for (unsigned i = 0; i < finalizers.size(); i++){
753     finalizers[i]->setContext(ctx);
754     res = finalizers[i]->execute(ctx);
755     if (res != NDBT_OK)
756       break;
757   }
758   return res;
759 }
760 
761 
saveTestResult(const char * test_name,int result)762 void NDBT_TestCaseImpl1::saveTestResult(const char* test_name,
763 					int result){
764   testResults.push_back(new NDBT_TestCaseResult(test_name,
765 						result,
766 						timer.elapsedTime()));
767 }
768 
printTestResult()769 void NDBT_TestCaseImpl1::printTestResult(){
770 
771   char buf[255];
772   ndbout << _name<<endl;
773 
774   for (unsigned i = 0; i < testResults.size(); i++){
775     NDBT_TestCaseResult* tcr = testResults[i];
776     const char* res = "<unknown>";
777     if (tcr->getResult() == NDBT_OK)
778       res = "OK";
779     else if (tcr->getResult() == NDBT_FAILED)
780       res = "FAIL";
781     else if (tcr->getResult() == FAILED_TO_CREATE)
782       res = "FAILED TO CREATE TABLE";
783     else if (tcr->getResult() == FAILED_TO_DISCOVER)
784       res = "FAILED TO DISCOVER TABLE";
785     BaseString::snprintf(buf, 255," %-10s %-5s %-20s",
786                          tcr->getName(),
787                          res,
788                          tcr->getTimeStr());
789     ndbout << buf<<endl;
790   }
791 }
792 
793 
794 
795 
796 
NDBT_TestSuite(const char * pname)797 NDBT_TestSuite::NDBT_TestSuite(const char* pname) :
798   name(pname),
799   m_createTable(true),
800   m_createAll(false),
801   m_connect_cluster(true),
802   m_logging(true),
803   m_driverType(NdbApiDriver)
804 {
805    numTestsOk = 0;
806    numTestsFail = 0;
807    numTestsExecuted = 0;
808    records = 0;
809    loops = 0;
810    diskbased = false;
811    tsname = NULL;
812    temporaryTables = false;
813    runonce = false;
814    m_noddl = false;
815    m_forceShort = false;
816 }
817 
818 
~NDBT_TestSuite()819 NDBT_TestSuite::~NDBT_TestSuite(){
820   for(unsigned i=0; i<tests.size(); i++){
821     delete tests[i];
822   }
823   tests.clear();
824 }
825 
setCreateTable(bool _flag)826 void NDBT_TestSuite::setCreateTable(bool _flag){
827   m_createTable = _flag;
828 }
829 
setRunAllTables(bool _flag)830 void NDBT_TestSuite::setRunAllTables(bool _flag){
831   runonce = _flag;
832 }
setCreateAllTables(bool _flag)833 void NDBT_TestSuite::setCreateAllTables(bool _flag){
834   m_createAll = _flag;
835 }
setConnectCluster(bool _flag)836 void NDBT_TestSuite::setConnectCluster(bool _flag){
837   assert(m_createTable == false);
838   m_connect_cluster = _flag;
839 }
840 
setTemporaryTables(bool val)841 void NDBT_TestSuite::setTemporaryTables(bool val){
842   temporaryTables = val;
843 }
844 
getTemporaryTables() const845 bool NDBT_TestSuite::getTemporaryTables() const {
846   return temporaryTables;
847 }
848 
setLogging(bool val)849 void NDBT_TestSuite::setLogging(bool val){
850   m_logging = val;
851 }
852 
getLogging() const853 bool NDBT_TestSuite::getLogging() const {
854   return m_logging;
855 }
856 
getForceShort() const857 bool NDBT_TestSuite::getForceShort() const {
858   return m_forceShort;
859 }
860 
timerIsOn()861 bool NDBT_TestSuite::timerIsOn(){
862   return (timer != 0);
863 }
864 
addTest(NDBT_TestCase * pTest)865 int NDBT_TestSuite::addTest(NDBT_TestCase* pTest){
866   assert(pTest != NULL);
867   tests.push_back(pTest);
868   return 0;
869 }
870 
executeAll(Ndb_cluster_connection & con,const char * _testname)871 int NDBT_TestSuite::executeAll(Ndb_cluster_connection& con,
872 			       const char* _testname){
873 
874   if(tests.size() == 0)
875     return NDBT_FAILED;
876 
877   ndbout << name << " started [" << getDate() << "]" << endl;
878 
879   if(!runonce)
880   {
881     testSuiteTimer.doStart();
882     for (int t=0; t < NDBT_Tables::getNumTables(); t++){
883       const NdbDictionary::Table* ptab = NDBT_Tables::getTable(t);
884       ndbout << "|- " << ptab->getName() << endl;
885       execute(con, ptab, _testname);
886     }
887     testSuiteTimer.doStop();
888   }
889   else
890   {
891     for (unsigned i = 0; i < tests.size(); i++){
892       if (_testname != NULL && strcasecmp(tests[i]->getName(), _testname) != 0)
893 	continue;
894 
895       tests[i]->initBeforeTest();
896       ctx = new NDBT_Context(con);
897 
898       ctx->setNumRecords(records);
899       ctx->setNumLoops(loops);
900       ctx->setSuite(this);
901       ctx->setProperty("NoDDL", (Uint32) m_noddl);
902 
903       int result = tests[i]->execute(ctx);
904 
905       tests[i]->saveTestResult("", result);
906       if (result != NDBT_OK)
907 	numTestsFail++;
908       else
909 	numTestsOk++;
910       numTestsExecuted++;
911 
912       delete ctx;
913     }
914   }
915   return reportAllTables(_testname);
916 }
917 
918 int
executeOne(Ndb_cluster_connection & con,const char * _tabname,const char * _testname)919 NDBT_TestSuite::executeOne(Ndb_cluster_connection& con,
920 			   const char* _tabname, const char* _testname){
921 
922   if(tests.size() == 0)
923     return NDBT_FAILED;
924 
925   ndbout << name << " started [" << getDate() << "]" << endl;
926 
927   const NdbDictionary::Table* ptab = NDBT_Tables::getTable(_tabname);
928   if (ptab == NULL)
929     return NDBT_FAILED;
930 
931   ndbout << "|- " << ptab->getName() << endl;
932 
933   execute(con, ptab, _testname);
934 
935   if (numTestsFail > 0){
936     return NDBT_FAILED;
937   }else{
938     return NDBT_OK;
939   }
940 }
941 
942 int
executeOneCtx(Ndb_cluster_connection & con,const NdbDictionary::Table * ptab,const char * _testname)943 NDBT_TestSuite::executeOneCtx(Ndb_cluster_connection& con,
944 			   const NdbDictionary::Table *ptab, const char* _testname){
945 
946   testSuiteTimer.doStart();
947 
948   do{
949     if(tests.size() == 0)
950       break;
951 
952     Ndb ndb(&con, "TEST_DB");
953     ndb.init(1024);
954 
955     Ndb_internal::setForceShortRequests(&ndb, m_forceShort);
956 
957     int result = ndb.waitUntilReady(300); // 5 minutes
958     if (result != 0){
959       g_err << name <<": Ndb was not ready" << endl;
960       break;
961     }
962 
963     ndbout << name << " started [" << getDate() << "]" << endl;
964     ndbout << "|- " << ptab->getName() << endl;
965 
966     for (unsigned t = 0; t < tests.size(); t++){
967 
968       if (_testname != NULL &&
969 	      strcasecmp(tests[t]->getName(), _testname) != 0)
970         continue;
971 
972       tests[t]->initBeforeTest();
973 
974       ctx = new NDBT_Context(con);
975       ctx->setTab(ptab);
976       ctx->setNumRecords(records);
977       ctx->setNumLoops(loops);
978       ctx->setSuite(this);
979       ctx->setProperty("NoDDL", (Uint32) m_noddl);
980 
981       result = tests[t]->execute(ctx);
982       if (result != NDBT_OK)
983         numTestsFail++;
984       else
985         numTestsOk++;
986       numTestsExecuted++;
987 
988     delete ctx;
989   }
990 
991     if (numTestsFail > 0)
992       break;
993   }while(0);
994 
995   testSuiteTimer.doStop();
996   int res = report(_testname);
997   return NDBT_ProgramExit(res);
998 }
999 
1000 int
createHook(Ndb * ndb,NdbDictionary::Table & tab,int when)1001 NDBT_TestSuite::createHook(Ndb* ndb, NdbDictionary::Table& tab, int when)
1002 {
1003   if (when == 0) {
1004     if (diskbased)
1005     {
1006       for (int i = 0; i < tab.getNoOfColumns(); i++)
1007       {
1008         NdbDictionary::Column* col = tab.getColumn(i);
1009         if (! col->getPrimaryKey())
1010 	{
1011           col->setStorageType(NdbDictionary::Column::StorageTypeDisk);
1012         }
1013       }
1014     }
1015     else if (temporaryTables)
1016     {
1017       tab.setTemporary(true);
1018       tab.setLogging(false);
1019     }
1020 
1021     if (tsname != NULL) {
1022       tab.setTablespaceName(tsname);
1023     }
1024   }
1025   return 0;
1026 }
1027 
execute(Ndb_cluster_connection & con,const NdbDictionary::Table * pTab,const char * _testname)1028 void NDBT_TestSuite::execute(Ndb_cluster_connection& con,
1029 			     const NdbDictionary::Table* pTab,
1030 			     const char* _testname){
1031   int result;
1032 
1033   for (unsigned t = 0; t < tests.size(); t++){
1034 
1035     if (_testname != NULL &&
1036 	strcasecmp(tests[t]->getName(), _testname) != 0)
1037       continue;
1038 
1039     if (tests[t]->m_all_tables && tests[t]->m_has_run)
1040     {
1041       continue;
1042     }
1043 
1044     if (tests[t]->isVerify(pTab) == false) {
1045       continue;
1046     }
1047 
1048     tests[t]->initBeforeTest();
1049 
1050     ctx = new NDBT_Context(con);
1051     ctx->setNumRecords(records);
1052     ctx->setNumLoops(loops);
1053     ctx->setSuite(this);
1054     ctx->setTab(pTab);
1055     ctx->setProperty("NoDDL", (Uint32) m_noddl);
1056 
1057     result = tests[t]->execute(ctx);
1058     tests[t]->saveTestResult(pTab->getName(), result);
1059     if (result != NDBT_OK)
1060       numTestsFail++;
1061     else
1062       numTestsOk++;
1063     numTestsExecuted++;
1064 
1065     tests[t]->m_has_run = true;
1066 
1067     delete ctx;
1068   }
1069 }
1070 
1071 
1072 
1073 int
createTables(Ndb_cluster_connection & con) const1074 NDBT_TestSuite::createTables(Ndb_cluster_connection& con) const
1075 {
1076   Ndb ndb(&con, "TEST_DB");
1077   ndb.init(1);
1078 
1079   NdbDictionary::Dictionary* pDict = ndb.getDictionary();
1080   for(unsigned i = 0; i<m_tables_in_test.size(); i++)
1081   {
1082     const char *tab_name=  m_tables_in_test[i].c_str();
1083     if (pDict->dropTable(tab_name) != 0 &&
1084         pDict->getNdbError().code != 723) // No such table
1085     {
1086       g_err << "runCreateTables: Failed to drop table " << tab_name << endl
1087             << pDict->getNdbError() << endl;
1088       return NDBT_FAILED;
1089     }
1090     if(NDBT_Tables::createTable(&ndb, tab_name, !getLogging()) != 0)
1091     {
1092       g_err << "runCreateTables: Failed to create table " << tab_name << endl
1093             << pDict->getNdbError() << endl;
1094       return NDBT_FAILED;
1095     }
1096 
1097     if (i == 0){
1098       // Update ctx with a pointer to the first created table
1099       const NdbDictionary::Table* pTab2 = pDict->getTable(tab_name);
1100       ctx->setTab(pTab2);
1101     }
1102     g_info << "created " << tab_name << endl;
1103   }
1104 
1105   return NDBT_OK;
1106 }
1107 
1108 
1109 static int
runCreateTables(NDBT_Context * ctx,NDBT_Step * step)1110 runCreateTables(NDBT_Context* ctx, NDBT_Step* step)
1111 {
1112   NDBT_TestSuite* suite= ctx->getSuite();
1113   return suite->createTables(ctx->m_cluster_connection);
1114 }
1115 
1116 
1117 static int
runCreateTable(NDBT_Context * ctx,NDBT_Step * step)1118 runCreateTable(NDBT_Context* ctx, NDBT_Step* step)
1119 {
1120   Ndb ndb(&ctx->m_cluster_connection, "TEST_DB");
1121   ndb.init(1);
1122 
1123   NdbDictionary::Dictionary* pDict = ndb.getDictionary();
1124   const NdbDictionary::Table* pTab = ctx->getTab();
1125   const char *tab_name=  pTab->getName();
1126   if (pDict->dropTable(tab_name) != 0 &&
1127       pDict->getNdbError().code != 723) // No such table
1128   {
1129     g_err << "runCreateTable: Failed to drop table " << tab_name << endl
1130           << pDict->getNdbError() << endl;
1131     return NDBT_FAILED;
1132   }
1133 
1134   if(NDBT_Tables::createTable(&ndb, tab_name,
1135                               !ctx->getSuite()->getLogging()) != 0)
1136   {
1137     g_err << "runCreateTable: Failed to create table " << tab_name
1138           << pDict->getNdbError() << endl;
1139     return NDBT_FAILED;
1140   }
1141 
1142   // Update ctx with a pointer to the created table
1143   const NdbDictionary::Table* pTab2 = pDict->getTable(tab_name);
1144   ctx->setTab(pTab2);
1145   ctx->setProperty("$table", tab_name);
1146 
1147   return NDBT_OK;
1148 }
1149 
1150 
1151 int
dropTables(Ndb_cluster_connection & con) const1152 NDBT_TestSuite::dropTables(Ndb_cluster_connection& con) const
1153 {
1154   Ndb ndb(&con, "TEST_DB");
1155   ndb.init(1);
1156 
1157   NdbDictionary::Dictionary* pDict = ndb.getDictionary();
1158   for(unsigned i = 0; i<m_tables_in_test.size(); i++)
1159   {
1160     const char *tab_name=  m_tables_in_test[i].c_str();
1161     pDict->dropTable(tab_name);
1162   }
1163   return NDBT_OK;
1164 }
1165 
1166 
1167 static int
runDropTables(NDBT_Context * ctx,NDBT_Step * step)1168 runDropTables(NDBT_Context* ctx, NDBT_Step* step)
1169 {
1170   NDBT_TestSuite* suite= ctx->getSuite();
1171   return suite->dropTables(ctx->m_cluster_connection);
1172 }
1173 
1174 
1175 static int
runDropTable(NDBT_Context * ctx,NDBT_Step * step)1176 runDropTable(NDBT_Context* ctx, NDBT_Step* step)
1177 {
1178   const char * tab_name = ctx->getProperty("$table", (const char*)0);
1179   if (tab_name)
1180   {
1181     Ndb ndb(&ctx->m_cluster_connection, "TEST_DB");
1182     ndb.init(1);
1183 
1184     NdbDictionary::Dictionary* pDict = ndb.getDictionary();
1185     pDict->dropTable(tab_name);
1186   }
1187   return NDBT_OK;
1188 }
1189 
1190 
1191 static int
runCheckTableExists(NDBT_Context * ctx,NDBT_Step * step)1192 runCheckTableExists(NDBT_Context* ctx, NDBT_Step* step)
1193 {
1194   Ndb ndb(&ctx->m_cluster_connection, "TEST_DB");
1195   ndb.init(1);
1196 
1197   NdbDictionary::Dictionary* pDict = ndb.getDictionary();
1198   const NdbDictionary::Table* pTab = ctx->getTab();
1199   const char *tab_name=  pTab->getName();
1200 
1201   const NdbDictionary::Table* pDictTab = pDict->getTable(tab_name);
1202 
1203   if (pDictTab == NULL)
1204   {
1205     g_err << "runCheckTableExists : Failed to find table "
1206           << tab_name << endl;
1207     g_err << "Required schema : " << *((NDBT_Table*)pTab) << endl;
1208     return NDBT_FAILED;
1209   }
1210 
1211   /* Todo : better check that table in DB is same as
1212    * table we expect
1213    */
1214 
1215   // Update ctx with a pointer to dict table
1216   ctx->setTab(pDictTab);
1217   ctx->setProperty("$table", tab_name);
1218 
1219   return NDBT_OK;
1220 }
1221 
1222 static int
runEmptyDropTable(NDBT_Context * ctx,NDBT_Step * step)1223 runEmptyDropTable(NDBT_Context* ctx, NDBT_Step* step)
1224 {
1225   return NDBT_OK;
1226 }
1227 
1228 int
report(const char * _tcname)1229 NDBT_TestSuite::report(const char* _tcname){
1230   int result;
1231   ndbout << "Completed " << name << " [" << getDate() << "]" << endl;
1232   printTestCaseSummary(_tcname);
1233   ndbout << numTestsExecuted << " test(s) executed" << endl;
1234   ndbout << numTestsOk << " test(s) OK"
1235 	 << endl;
1236   if(numTestsFail > 0)
1237     ndbout << numTestsFail << " test(s) failed"
1238 	   << endl;
1239   testSuiteTimer.printTotalTime();
1240   if (numTestsFail > 0 || numTestsExecuted == 0){
1241     result = NDBT_FAILED;
1242   }else{
1243     result = NDBT_OK;
1244   }
1245   return result;
1246 }
1247 
printTestCaseSummary(const char * _tcname)1248 void NDBT_TestSuite::printTestCaseSummary(const char* _tcname){
1249   ndbout << "= SUMMARY OF TEST EXECUTION ==============" << endl;
1250   for (unsigned t = 0; t < tests.size(); t++){
1251     if (_tcname != NULL &&
1252 	strcasecmp(tests[t]->getName(), _tcname) != 0)
1253       continue;
1254 
1255     tests[t]->printTestResult();
1256   }
1257   ndbout << "==========================================" << endl;
1258 }
1259 
reportAllTables(const char * _testname)1260 int NDBT_TestSuite::reportAllTables(const char* _testname){
1261   int result;
1262   ndbout << "Completed running test [" << getDate() << "]" << endl;
1263   const int totalNumTests = numTestsExecuted;
1264   printTestCaseSummary(_testname);
1265   ndbout << numTestsExecuted<< " test(s) executed" << endl;
1266   ndbout << numTestsOk << " test(s) OK("
1267 	 <<(int)(((float)numTestsOk/totalNumTests)*100.0) <<"%)"
1268 	 << endl;
1269   if(numTestsFail > 0)
1270     ndbout << numTestsFail << " test(s) failed("
1271 	   <<(int)(((float)numTestsFail/totalNumTests)*100.0) <<"%)"
1272 	   << endl;
1273   testSuiteTimer.printTotalTime();
1274   if (numTestsExecuted > 0){
1275     if (numTestsFail > 0){
1276       result = NDBT_FAILED;
1277     }else{
1278       result = NDBT_OK;
1279     }
1280   } else {
1281     result = NDBT_FAILED;
1282   }
1283   return result;
1284 }
1285 
1286 static int opt_print = false;
1287 static int opt_print_html = false;
1288 static int opt_print_cases = false;
1289 static int opt_records;
1290 static int opt_loops;
1291 static int opt_timer;
1292 static char * opt_testname = NULL;
1293 static int opt_verbose;
1294 unsigned opt_seed = 0;
1295 static int opt_nologging = 0;
1296 static int opt_temporary = 0;
1297 static int opt_noddl = 0;
1298 static int opt_forceShort = 0;
1299 
1300 static struct my_option my_long_options[] =
1301 {
1302   NDB_STD_OPTS(""),
1303   { "print", NDB_OPT_NOSHORT, "Print execution tree",
1304     (uchar **) &opt_print, (uchar **) &opt_print, 0,
1305     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1306   { "print_html", NDB_OPT_NOSHORT, "Print execution tree in html table format",
1307     (uchar **) &opt_print_html, (uchar **) &opt_print_html, 0,
1308     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1309   { "print_cases", NDB_OPT_NOSHORT, "Print list of test cases",
1310     (uchar **) &opt_print_cases, (uchar **) &opt_print_cases, 0,
1311     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1312   { "records", 'r', "Number of records",
1313     (uchar **) &opt_records, (uchar **) &opt_records, 0,
1314     GET_INT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0 },
1315   { "loops", 'l', "Number of loops",
1316     (uchar **) &opt_loops, (uchar **) &opt_loops, 0,
1317     GET_INT, REQUIRED_ARG, 5, 0, 0, 0, 0, 0 },
1318   { "seed", NDB_OPT_NOSHORT, "Random seed",
1319     (uchar **) &opt_seed, (uchar **) &opt_seed, 0,
1320     GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
1321   { "testname", 'n', "Name of test to run",
1322     (uchar **) &opt_testname, (uchar **) &opt_testname, 0,
1323     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
1324   { "timer", 't', "Print execution time",
1325     (uchar **) &opt_timer, (uchar **) &opt_timer, 0,
1326     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1327   { "verbose", 'v', "Print verbose status",
1328     (uchar **) &opt_verbose, (uchar **) &opt_verbose, 0,
1329     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1330   { "temporary-tables", 'T', "Create temporary table(s)",
1331     (uchar **) &opt_temporary, (uchar **) &opt_temporary, 0,
1332     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1333   { "nologging", NDB_OPT_NOSHORT, "Create table(s) wo/ logging",
1334     (uchar **) &opt_nologging, (uchar **) &opt_nologging, 0,
1335     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1336   { "noddl", NDB_OPT_NOSHORT,
1337     "Don't create/drop tables as part of running tests",
1338     (uchar**) &opt_noddl, (uchar**) &opt_noddl, 0,
1339     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1340   { "forceshortreqs", NDB_OPT_NOSHORT, "Use short signals for NdbApi requests",
1341     (uchar**) &opt_forceShort, (uchar**) &opt_forceShort, 0,
1342     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
1343   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
1344 };
1345 
1346 extern int global_flag_skip_invalidate_cache;
1347 
1348 const char *load_default_groups[]= { "mysql_cluster",0 };
1349 
short_usage_sub(void)1350 static void short_usage_sub(void)
1351 {
1352   ndb_short_usage_sub("[tabname1 tabname2 ... tabnameN]");
1353 }
usage()1354 static void usage()
1355 {
1356   ndb_usage(short_usage_sub, load_default_groups, my_long_options);
1357 }
1358 
execute(int argc,const char ** argv)1359 int NDBT_TestSuite::execute(int argc, const char** argv){
1360   int res = NDBT_FAILED;
1361   /* Arguments:
1362        Run only a subset of tests
1363        -n testname Which test to run
1364        Recommendations to test functions:
1365        --records Number of records to use(default: 10000)
1366        --loops Number of loops to execute in the test(default: 100)
1367 
1368        Other parameters should:
1369        * be calculated from the above two parameters
1370        * be divided into different test cases, ex. one testcase runs
1371          with FragmentType = Single and another perfoms the same
1372          test with FragmentType = Large
1373        * let the test case iterate over all/subset of appropriate parameters
1374          ex. iterate over FragmentType = Single to FragmentType = AllLarge
1375 
1376        Remeber that the intention is that it should be _easy_ to run
1377        a complete test suite without any greater knowledge of what
1378        should be tested ie. keep arguments at a minimum
1379   */
1380 
1381   char **_argv= (char **)argv;
1382 
1383   if (!my_progname)
1384     my_progname= _argv[0];
1385 
1386   ndb_opt_set_usage_funcs(short_usage_sub, usage);
1387 
1388   load_defaults("my",load_default_groups,&argc,&_argv);
1389 
1390   int ho_error;
1391 #ifndef DBUG_OFF
1392   opt_debug= "d:t:i:F:L";
1393 #endif
1394   if ((ho_error=handle_options(&argc, &_argv, my_long_options,
1395 			       ndb_std_get_one_option)))
1396   {
1397     usage();
1398     return NDBT_ProgramExit(NDBT_WRONGARGS);
1399   }
1400 
1401   if (opt_verbose)
1402     setOutputLevel(2); // Show g_info
1403   else
1404     setOutputLevel(0); // Show only g_err ?
1405 
1406   records = opt_records;
1407   loops = opt_loops;
1408   timer = opt_timer;
1409   if (opt_nologging)
1410     setLogging(false);
1411   temporaryTables = opt_temporary;
1412   m_noddl = opt_noddl;
1413   m_forceShort = opt_forceShort;
1414 
1415   if (opt_seed == 0)
1416   {
1417     opt_seed = (unsigned)NdbTick_CurrentMillisecond();
1418   }
1419   ndbout_c("random seed: %u", opt_seed);
1420   srand(opt_seed);
1421   srandom(opt_seed);
1422 
1423   global_flag_skip_invalidate_cache = 1;
1424 
1425   int num_tables= argc;
1426   if (argc == 0)
1427     num_tables = NDBT_Tables::getNumTables();
1428 
1429   for(int i = 0; i<num_tables; i++)
1430   {
1431     if (argc == 0)
1432       m_tables_in_test.push_back(NDBT_Tables::getTable(i)->getName());
1433     else
1434       m_tables_in_test.push_back(_argv[i]);
1435   }
1436 
1437   if (m_createTable)
1438   {
1439     for (unsigned t = 0; t < tests.size(); t++)
1440     {
1441       const char* createFuncName= NULL;
1442       NDBT_TESTFUNC* createFunc= NULL;
1443       const char* dropFuncName= NULL;
1444       NDBT_TESTFUNC* dropFunc= NULL;
1445 
1446       if (!m_noddl)
1447       {
1448         createFuncName= m_createAll ? "runCreateTable" : "runCreateTable";
1449         createFunc=   m_createAll ? &runCreateTables : &runCreateTable;
1450         dropFuncName= m_createAll ? "runDropTables" : "runDropTable";
1451         dropFunc= m_createAll ? &runDropTables : &runDropTable;
1452       }
1453       else
1454       {
1455         /* No DDL allowed, so we substitute 'do nothing' variants
1456          * of the create + drop table test procs
1457          */
1458         createFuncName= "runCheckTableExists";
1459         createFunc= &runCheckTableExists;
1460         dropFuncName= "runEmptyDropTable";
1461         dropFunc= &runEmptyDropTable;
1462       }
1463 
1464       NDBT_TestCaseImpl1* pt= (NDBT_TestCaseImpl1*)tests[t];
1465       NDBT_Initializer* pti =
1466         new NDBT_Initializer(pt,
1467                              createFuncName,
1468                              *createFunc);
1469       pt->addInitializer(pti, true);
1470       NDBT_Finalizer* ptf =
1471         new NDBT_Finalizer(pt,
1472                            dropFuncName,
1473                            *dropFunc);
1474       pt->addFinalizer(ptf);
1475     }
1476   }
1477 
1478   if (opt_print == true){
1479     printExecutionTree();
1480     return 0;
1481   }
1482 
1483   if (opt_print_html == true){
1484     printExecutionTreeHTML();
1485     return 0;
1486   }
1487 
1488   if (opt_print_cases == true){
1489     printCases();
1490     return 0;
1491   }
1492 
1493   Ndb_cluster_connection con(opt_ndb_connectstring, opt_ndb_nodeid);
1494   if(m_connect_cluster && con.connect(12, 5, 1))
1495   {
1496     return NDBT_ProgramExit(NDBT_FAILED);
1497   }
1498 
1499   if(argc == 0){
1500     // No table specified
1501     res = executeAll(con, opt_testname);
1502   } else {
1503     testSuiteTimer.doStart();
1504     for(int i = 0; i<argc; i++){
1505       executeOne(con, _argv[i], opt_testname);
1506     }
1507     testSuiteTimer.doStop();
1508     res = report(opt_testname);
1509   }
1510 
1511   return NDBT_ProgramExit(res);
1512 }
1513 
1514 
printExecutionTree()1515 void NDBT_TestSuite::printExecutionTree(){
1516   ndbout << "Testsuite: " << name << endl;
1517   for (unsigned t = 0; t < tests.size(); t++){
1518     tests[t]->print();
1519     ndbout << endl;
1520   }
1521 }
1522 
printExecutionTreeHTML()1523 void NDBT_TestSuite::printExecutionTreeHTML(){
1524   ndbout << "<tr>" << endl;
1525   ndbout << "<td><h3>" << name << "</h3></td>" << endl;
1526   ndbout << "</tr>" << endl;
1527   for (unsigned t = 0; t < tests.size(); t++){
1528     tests[t]->printHTML();
1529     ndbout << endl;
1530   }
1531 
1532 }
1533 
printCases()1534 void NDBT_TestSuite::printCases(){
1535   ndbout << "# Testsuite: " << name << endl;
1536   ndbout << "# Number of tests: " << tests.size() << endl;
1537   for (unsigned t = 0; t < tests.size(); t++){
1538     ndbout << name << " -n " << tests[t]->getName() << endl;
1539   }
1540 }
1541 
getDate()1542 const char* NDBT_TestSuite::getDate(){
1543   static char theTime[128];
1544   struct tm* tm_now;
1545   time_t now;
1546   now = time((time_t*)NULL);
1547 #ifdef NDB_WIN32
1548   tm_now = localtime(&now);
1549 #else
1550   tm_now = gmtime(&now);
1551 #endif
1552 
1553   BaseString::snprintf(theTime, 128,
1554 	   "%d-%.2d-%.2d %.2d:%.2d:%.2d",
1555 	   tm_now->tm_year + 1900,
1556 	   tm_now->tm_mon + 1,
1557 	   tm_now->tm_mday,
1558 	   tm_now->tm_hour,
1559 	   tm_now->tm_min,
1560 	   tm_now->tm_sec);
1561 
1562   return theTime;
1563 }
1564 
printHTML()1565 void NDBT_TestCaseImpl1::printHTML(){
1566 
1567   ndbout << "<tr><td>&nbsp;</td>" << endl;
1568   ndbout << "<td name=tc>" << endl << _name << "</td><td width=70%>"
1569 	 << _comment << "</td></tr>" << endl;
1570 }
1571 
print()1572 void NDBT_TestCaseImpl1::print(){
1573   ndbout << "Test case: " << _name << endl;
1574   ndbout << "Description: "<< _comment << endl;
1575 
1576   ndbout << "Parameters: " << endl;
1577 
1578   Properties::Iterator it(&props);
1579   for(const char * key = it.first(); key != 0; key = it.next()){
1580     PropertiesType pt;
1581     const bool b = props.getTypeOf(key, &pt);
1582     assert(b == true);
1583     switch(pt){
1584     case PropertiesType_Uint32:{
1585       Uint32 val;
1586       props.get(key, &val);
1587       ndbout << "      " << key << ": " << val << endl;
1588       break;
1589     }
1590     case PropertiesType_char:{
1591       const char * val;
1592       props.get(key, &val);
1593       ndbout << "    " << key << ": " << val << endl;
1594       break;
1595     }
1596     default:
1597       abort();
1598     }
1599   }
1600   unsigned i;
1601   for(i=0; i<initializers.size(); i++){
1602     ndbout << "Initializers[" << i << "]: " << endl;
1603     initializers[i]->print();
1604   }
1605   for(i=0; i<steps.size(); i++){
1606     ndbout << "Step[" << i << "]: " << endl;
1607     steps[i]->print();
1608   }
1609   for(i=0; i<verifiers.size(); i++){
1610     ndbout << "Verifier[" << i << "]: " << endl;
1611     verifiers[i]->print();
1612   }
1613   for(i=0; i<finalizers.size(); i++){
1614     ndbout << "Finalizer[" << i << "]: " << endl;
1615     finalizers[i]->print();
1616   }
1617 
1618 }
1619 
print()1620 void NDBT_Step::print(){
1621   ndbout << "      "<< name << endl;
1622 
1623 }
1624 
1625 void
sync_down(const char * key)1626 NDBT_Context::sync_down(const char * key){
1627   Uint32 threads = getProperty(key, (unsigned)0);
1628   if(threads){
1629     decProperty(key);
1630   }
1631 }
1632 
1633 void
sync_up_and_wait(const char * key,Uint32 value)1634 NDBT_Context::sync_up_and_wait(const char * key, Uint32 value){
1635   setProperty(key, value);
1636   getPropertyWait(key, (unsigned)0);
1637 }
1638 
1639 template class Vector<NDBT_TestCase*>;
1640 template class Vector<NDBT_TestCaseResult*>;
1641 template class Vector<NDBT_Step*>;
1642 template class Vector<NdbThread*>;
1643 template class Vector<NDBT_Verifier*>;
1644 template class Vector<NDBT_Initializer*>;
1645 template class Vector<NDBT_Finalizer*>;
1646 template class Vector<const NdbDictionary::Table*>;
1647