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