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