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