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> </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