NDBT_Test.hpp 12.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef NDBT_TEST_HPP
#define NDBT_TEST_HPP

unknown's avatar
unknown committed
20
#include <ndb_global.h>
21 22 23 24 25 26 27 28

#include "NDBT_ReturnCodes.h"
#include <Properties.hpp>
#include <NdbThread.h>
#include <NdbSleep.h>
#include <NdbCondition.h>
#include <NdbTimer.hpp>
#include <Vector.hpp>
29
#include <NdbApi.hpp>
30 31 32 33 34 35 36 37 38
#include <NdbDictionary.hpp>

class NDBT_Step;
class NDBT_TestCase;
class NDBT_TestSuite;
class NDBT_TestCaseImpl1;

class NDBT_Context {
public:
39 40 41
  Ndb_cluster_connection& m_cluster_connection;
  
  NDBT_Context(Ndb_cluster_connection&);
42 43
  ~NDBT_Context();
  const NdbDictionary::Table* getTab();
unknown's avatar
unknown committed
44
  const NdbDictionary::Table** getTables();
unknown's avatar
unknown committed
45 46
  int getNumTables() const;
  const char * getTableName(int) const;
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
  NDBT_TestSuite* getSuite();
  NDBT_TestCase* getCase();

  // Get arguments
  int getNumRecords() const;
  int getNumLoops() const;
  char * getRemoteMgm() const;
  // Common place to store state between 
  // steps, for example information from one step to the 
  // verifier about how many records have been inserted
  Uint32 getProperty(const char*, Uint32 = 0 );
  const char* getProperty(const char*, const char* );
  void setProperty(const char*, Uint32);
  void setProperty(const char*, const char*);

  // Signal that a property value that another 
  // thread might be waiting for has changed
  void broadcast();
  // Wait for the signal that a property has changed
  void wait();
  void wait_timeout(int msec);

  // Wait until the property has been set to a certain value
  bool getPropertyWait(const char*, Uint32);
  const char* getPropertyWait(const char*, const char* );

unknown's avatar
unknown committed
73
  void decProperty(const char *);
unknown's avatar
unknown committed
74 75
  void incProperty(const char *);

76 77 78 79 80 81 82 83 84 85
  // Communicate with other tests
  void stopTest();
  bool isTestStopped();

  // Communicate with tests in other API nodes
  // This is done using a "system" table in the database
  Uint32 getDbProperty(const char*);
  bool setDbProperty(const char*, Uint32);

  void setTab(const NdbDictionary::Table*);
unknown's avatar
unknown committed
86
  void addTab(const NdbDictionary::Table*);
87 88 89 90 91 92 93
  void setRemoteMgm(char * mgm);

  /**
   * Get no of steps running/completed
   */
  int getNoOfRunningSteps() const ;
  int getNoOfCompletedSteps() const ;
unknown's avatar
unknown committed
94 95 96 97 98 99

  /**
   * Thread sync
   */
  void sync_down(const char * key);
  void sync_up_and_wait(const char * key, Uint32 count = 0);
100 101 102 103 104 105 106 107 108 109
private:
  friend class NDBT_Step;
  friend class NDBT_TestSuite;
  friend class NDBT_TestCase;
  friend class NDBT_TestCaseImpl1;

  void setSuite(NDBT_TestSuite*);
  void setCase(NDBT_TestCase*);
  void setNumRecords(int);
  void setNumLoops(int);
unknown's avatar
unknown committed
110
  Vector<const NdbDictionary::Table*> tables;
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
  NDBT_TestSuite* suite;
  NDBT_TestCase* testcase;
  Ndb* ndb;
  int records;
  int loops;
  bool stopped;
  char * remote_mgm;
  Properties props;
  NdbMutex* propertyMutexPtr;
  NdbCondition* propertyCondPtr;
};

typedef int (NDBT_TESTFUNC)(NDBT_Context*, NDBT_Step*);

class NDBT_Step {
public:
  NDBT_Step(NDBT_TestCase* ptest, 
		const char* pname,
		NDBT_TESTFUNC* pfunc);
130
  virtual ~NDBT_Step() {}
131
  int execute(NDBT_Context*);
132
  virtual int setUp(Ndb_cluster_connection&) = 0;
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
  virtual void tearDown() = 0;
  void setContext(NDBT_Context*);
  NDBT_Context* getContext();
  void print();
  const char* getName() { return name; }
  int getStepNo() { return step_no; }
  void setStepNo(int n) { step_no = n; }
protected:
  NDBT_Context* m_ctx;
  const char* name;
  NDBT_TESTFUNC* func;
  NDBT_TestCase* testcase;
  int step_no;
};

class NDBT_NdbApiStep : public NDBT_Step {
public:
  NDBT_NdbApiStep(NDBT_TestCase* ptest,
		  const char* pname,
		  NDBT_TESTFUNC* pfunc);
153
  virtual ~NDBT_NdbApiStep() {}
154
  virtual int setUp(Ndb_cluster_connection&);
155
  virtual void tearDown();
156 157 158 159 160 161 162 163 164 165 166

  Ndb* getNdb();
protected:
  Ndb* ndb;
};

class NDBT_ParallelStep : public NDBT_NdbApiStep {
public:
  NDBT_ParallelStep(NDBT_TestCase* ptest,
		    const char* pname,
		    NDBT_TESTFUNC* pfunc);
167
  virtual ~NDBT_ParallelStep() {}
168 169 170 171 172 173 174
};

class NDBT_Verifier : public NDBT_NdbApiStep {
public:
  NDBT_Verifier(NDBT_TestCase* ptest,
		const char* name,
		NDBT_TESTFUNC* func);
175
  virtual ~NDBT_Verifier() {}
176 177 178 179 180 181 182
};

class NDBT_Initializer  : public NDBT_NdbApiStep {
public:
  NDBT_Initializer(NDBT_TestCase* ptest,
		   const char* name,
		   NDBT_TESTFUNC* func);
183
  virtual ~NDBT_Initializer() {}
184 185 186 187 188 189 190
};

class NDBT_Finalizer  : public NDBT_NdbApiStep {
public:
  NDBT_Finalizer(NDBT_TestCase* ptest,
		 const char* name,
		 NDBT_TESTFUNC* func);
191
  virtual ~NDBT_Finalizer() {}
192 193 194 195 196 197 198 199
};


class NDBT_TestCase {
public:
  NDBT_TestCase(NDBT_TestSuite* psuite, 
		const char* name, 
		const char* comment);
unknown's avatar
ndb -  
unknown committed
200
  virtual ~NDBT_TestCase() {}
201

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
  // This is the default executor of a test case
  // When a test case is executed it will need to be suplied with a number of 
  // different parameters and settings, these are passed to the test in the 
  // NDBT_Context object
  virtual int execute(NDBT_Context*);
  void setProperty(const char*, Uint32);
  void setProperty(const char*, const char*);
  virtual void print() = 0;
  virtual void printHTML() = 0;

  const char* getName(){return name;};
  virtual bool tableExists(NdbDictionary::Table* aTable) = 0;
  virtual bool isVerify(const NdbDictionary::Table* aTable) = 0;

  virtual void saveTestResult(const NdbDictionary::Table* ptab, int result) = 0;
  virtual void printTestResult() = 0;
  void initBeforeTest(){ timer.doReset();};

  /**
   * Get no of steps running/completed
   */
  virtual int getNoOfRunningSteps() const = 0;
  virtual int getNoOfCompletedSteps() const = 0;

unknown's avatar
unknown committed
226 227 228
  bool m_all_tables;
  bool m_has_run;

229 230 231 232 233 234 235 236 237 238 239
protected:
  virtual int runInit(NDBT_Context* ctx) = 0;
  virtual int runSteps(NDBT_Context* ctx) = 0;
  virtual int runVerifier(NDBT_Context* ctx) = 0;
  virtual int runFinal(NDBT_Context* ctx) = 0;
  virtual void addTable(const char* aTableName, bool isVerify=true) = 0;

  void startTimer(NDBT_Context*);
  void stopTimer(NDBT_Context*);
  void printTimer(NDBT_Context*);

unknown's avatar
ndb -  
unknown committed
240 241
  BaseString _name;
  BaseString _comment;
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
  const char* name;
  const char* comment;
  NDBT_TestSuite* suite;
  Properties props;
  NdbTimer timer;
  bool isVerifyTables;
};

static const int FAILED_TO_CREATE = 1000;
static const int FAILED_TO_DISCOVER = 1001;


class NDBT_TestCaseResult{
public: 
  NDBT_TestCaseResult(const char* name, int _result, NDB_TICKS _ticks):
    m_result(_result){
    m_name.assign(name); 
    m_ticks = _ticks;
    
  };
  const char* getName(){return m_name.c_str(); };
  int getResult(){return m_result; };
  const char* getTimeStr(){
      // Convert to Uint32 in order to be able to print it to screen
    Uint32 lapTime = (Uint32)m_ticks;
    Uint32 secTime = lapTime/1000;
268
    BaseString::snprintf(buf, 255, "%d secs (%d ms)", secTime, lapTime);
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
    return buf;
  }
private:
  char buf[255];
  int m_result;
  BaseString m_name;
  NDB_TICKS m_ticks;
};

class NDBT_TestCaseImpl1 : public NDBT_TestCase {
public:
  NDBT_TestCaseImpl1(NDBT_TestSuite* psuite, 
		const char* name, 
		const char* comment);
  virtual ~NDBT_TestCaseImpl1();
  int addStep(NDBT_Step*);
  int addVerifier(NDBT_Verifier*);
  int addInitializer(NDBT_Initializer*);
  int addFinalizer(NDBT_Finalizer*);
  void addTable(const char*, bool);
  bool tableExists(NdbDictionary::Table*);
  bool isVerify(const NdbDictionary::Table*);
  void reportStepResult(const NDBT_Step*, int result);
  //  int execute(NDBT_Context* ctx);
  int runInit(NDBT_Context* ctx);
  int runSteps(NDBT_Context* ctx);
  int runVerifier(NDBT_Context* ctx);
  int runFinal(NDBT_Context* ctx);
  void print();
  void printHTML();

  virtual int getNoOfRunningSteps() const;
  virtual int getNoOfCompletedSteps() const;
private:
  static const int  NORESULT = 999;
  
  void saveTestResult(const NdbDictionary::Table* ptab, int result);
  void printTestResult();

  void startStepInThread(int stepNo, NDBT_Context* ctx);
  void waitSteps();
  Vector<NDBT_Step*> steps;
  Vector<NdbThread*> threads;
  Vector<int> results;
  Vector<NDBT_Verifier*> verifiers; 
  Vector<NDBT_Initializer*> initializers; 
  Vector<NDBT_Finalizer*> finalizers; 
  Vector<const NdbDictionary::Table*> testTables; 
  Vector<NDBT_TestCaseResult*> testResults;
  unsigned numStepsFail;
  unsigned numStepsOk;
  unsigned numStepsCompleted;
  NdbMutex* waitThreadsMutexPtr;
  NdbCondition* waitThreadsCondPtr;
};


// A NDBT_TestSuite is a collection of TestCases
// the test suite will know how to execute the test cases
class NDBT_TestSuite {
public:
  NDBT_TestSuite(const char* name);
  ~NDBT_TestSuite();

  // Default executor of a test suite
  // supply argc and argv as parameters
  int execute(int, const char**);


  // These function can be used from main in the test program 
  // to control the behaviour of the testsuite
  void setCreateTable(bool);     // Create table before test func is called
  void setCreateAllTables(bool); // Create all tables before testsuite is executed 
unknown's avatar
unknown committed
342
  void setRunAllTables(bool); // Run once with all tables
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362

  // Prints the testsuite, testcases and teststeps
  void printExecutionTree();
  void printExecutionTreeHTML();

  // Prints list of testcases
  void printCases();

  // Print summary of executed tests
  void printTestCaseSummary(const char* tcname = NULL);

  /**
   * Returns current date and time in the format of 2002-12-04 10:00:01
   */
  const char* getDate();

  // Returns true if timing info should be printed
  bool timerIsOn();

  int addTest(NDBT_TestCase* pTest);
unknown's avatar
unknown committed
363

unknown's avatar
unknown committed
364 365
  // Table create tweaks
  int createHook(Ndb*, NdbDictionary::Table&, int when);
unknown's avatar
unknown committed
366
  Vector<BaseString> m_tables_in_test;
unknown's avatar
unknown committed
367 368 369

  void setTemporaryTables(bool val);
  bool getTemporaryTables() const;
370
private:
371 372 373 374 375 376 377
  int executeOne(Ndb_cluster_connection&,
		 const char* _tabname, const char* testname = NULL);
  int executeAll(Ndb_cluster_connection&,
		 const char* testname = NULL);
  void execute(Ndb_cluster_connection&,
	       Ndb*, const NdbDictionary::Table*, const char* testname = NULL);
  
378 379 380 381 382 383 384 385 386 387 388 389 390 391
  int report(const char* _tcname = NULL);
  int reportAllTables(const char* );
  const char* name;
  char* remote_mgm;
  int numTestsOk;
  int numTestsFail;
  int numTestsExecuted;
  Vector<NDBT_TestCase*> tests;
  NDBT_Context* ctx;
  int records;
  int loops;
  int timer;
  NdbTimer testSuiteTimer;
  bool createTable;
unknown's avatar
unknown committed
392 393 394
  bool diskbased;
  bool runonce;
  const char* tsname;
unknown's avatar
unknown committed
395
  bool createAllTables;
unknown's avatar
unknown committed
396
  bool temporaryTables;
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
};



#define NDBT_TESTSUITE(suitname) \
class C##suitname : public NDBT_TestSuite { \
public: \
C##suitname():NDBT_TestSuite(#suitname){ \
 NDBT_TestCaseImpl1* pt; pt = NULL; \
 NDBT_Step* pts; pts = NULL; \
 NDBT_Verifier* ptv; ptv = NULL; \
 NDBT_Initializer* pti; pti = NULL; \
 NDBT_Finalizer* ptf; ptf = NULL; 

#define TESTCASE(testname, comment) \
  pt = new NDBT_TestCaseImpl1(this, testname, comment); \
  addTest(pt);

#define TC_PROPERTY(propname, propval) \
  pt->setProperty(propname, propval);

#define STEP(stepfunc) \
  pts = new NDBT_ParallelStep(pt, #stepfunc, stepfunc); \
  pt->addStep(pts);

// Add a number of equal steps to the testcase
#define STEPS(stepfunc, num) \
424
  { int i; for (i = 0; i < num; i++){ \
425 426
    pts = new NDBT_ParallelStep(pt, #stepfunc, stepfunc); \
    pt->addStep(pts);\
427
  } }
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453

#define VERIFIER(stepfunc) \
  ptv = new NDBT_Verifier(pt, #stepfunc, stepfunc); \
  pt->addVerifier(ptv);

#define INITIALIZER(stepfunc) \
  pti = new NDBT_Initializer(pt, #stepfunc, stepfunc); \
  pt->addInitializer(pti);

#define FINALIZER(stepfunc) \
  ptf = new NDBT_Finalizer(pt, #stepfunc, stepfunc); \
  pt->addFinalizer(ptf);

// Test case can be run only on this table(s), can be multiple tables
// Ex TABLE("T1")
//    TABLE("T3")
// Means test will only be run on T1 and T3
#define TABLE(tableName) \
  pt->addTable(tableName, true);

// Test case can be run on all tables except
// Ex NOT_TABLE("T10")
// Means test will be run on all tables execept T10
#define NOT_TABLE(tableName) \
  pt->addTable(tableName, false);

unknown's avatar
unknown committed
454 455 456 457
// Text case will only be run once, not once per table as normally
#define ALL_TABLES() \
  pt->m_all_tables= true;

458
#define NDBT_TESTSUITE_END(suitname) \
unknown's avatar
unknown committed
459
 } } ; C##suitname suitname
460 461 462 463 464

// Helper functions for retrieving variables from NDBT_Step
#define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb()

#endif