summaryrefslogtreecommitdiff
path: root/ndb/test/include/NDBT_Test.hpp
blob: 027ac356e0cc613ffed5eb32948a5b26dea60b09 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
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
268
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
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
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
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
/* 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


#include "NDBT_ReturnCodes.h"
#include <Properties.hpp>
#include <NdbThread.h>
#include <NdbSleep.h>
#include <NdbCondition.h>
#include <NdbTimer.hpp>
#include <Vector.hpp>
#include <NdbApi.hpp>
#include <NdbDictionary.hpp>

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

class NDBT_Context {
public:
  Ndb_cluster_connection& m_cluster_connection;
  
  NDBT_Context(Ndb_cluster_connection&);
  ~NDBT_Context();
  const NdbDictionary::Table* getTab();
  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* );

  void decProperty(const char *);
  void incProperty(const char *);

  // 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*);
  void setRemoteMgm(char * mgm);

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

  /**
   * Thread sync
   */
  void sync_down(const char * key);
  void sync_up_and_wait(const char * key, Uint32 count = 0);
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);
  const NdbDictionary::Table* tab;
  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);
  virtual ~NDBT_Step() {}
  int execute(NDBT_Context*);
  virtual int setUp(Ndb_cluster_connection&) = 0;
  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);
  virtual ~NDBT_NdbApiStep() {}
  virtual int setUp(Ndb_cluster_connection&);
  virtual void tearDown();

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

class NDBT_ParallelStep : public NDBT_NdbApiStep {
public:
  NDBT_ParallelStep(NDBT_TestCase* ptest,
		    const char* pname,
		    NDBT_TESTFUNC* pfunc);
  virtual ~NDBT_ParallelStep() {}
};

class NDBT_Verifier : public NDBT_NdbApiStep {
public:
  NDBT_Verifier(NDBT_TestCase* ptest,
		const char* name,
		NDBT_TESTFUNC* func);
  virtual ~NDBT_Verifier() {}
};

class NDBT_Initializer  : public NDBT_NdbApiStep {
public:
  NDBT_Initializer(NDBT_TestCase* ptest,
		   const char* name,
		   NDBT_TESTFUNC* func);
  virtual ~NDBT_Initializer() {}
};

class NDBT_Finalizer  : public NDBT_NdbApiStep {
public:
  NDBT_Finalizer(NDBT_TestCase* ptest,
		 const char* name,
		 NDBT_TESTFUNC* func);
  virtual ~NDBT_Finalizer() {}
};


class NDBT_TestCase {
public:
  NDBT_TestCase(NDBT_TestSuite* psuite, 
		const char* name, 
		const char* comment);
  virtual ~NDBT_TestCase() {}

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

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*);

  BaseString _name;
  BaseString _comment;
  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;
    BaseString::snprintf(buf, 255, "%d secs (%d ms)", secTime, lapTime);
    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 

  // 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);
private:
  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);
  
  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;
};



#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) \
  { int i; for (i = 0; i < num; i++){ \
    pts = new NDBT_ParallelStep(pt, #stepfunc, stepfunc); \
    pt->addStep(pts);\
  } }

#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);

#define NDBT_TESTSUITE_END(suitname) \
 } } ; C##suitname suitname

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

#endif