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