test.h 7.48 KB
Newer Older
Yoni Fogel's avatar
Yoni Fogel committed
1
/* -*- mode: C; c-basic-offset: 4 -*- */
2 3 4 5 6 7 8 9

#ifndef __TEST_H
#define __TEST_H

#if defined(__cilkplusplus) || defined(__cplusplus)
extern "C" {
#endif

Yoni Fogel's avatar
Yoni Fogel committed
10 11 12
#ident "Copyright (c) 2007 Tokutek Inc.  All rights reserved."
#include <toku_portability.h>

13
#include <string.h>
14
#include <stdlib.h>
15
#include <toku_stdint.h>
16 17
#include <stdio.h>
#include <db.h>
18
#include <limits.h>
19
#include <errno.h>
20
#include "toku_htonl.h"
21 22
#include "toku_assert.h"
#include <signal.h>
Rich Prohaska's avatar
Rich Prohaska committed
23
#if defined(USE_TDB)
Yoni Fogel's avatar
Yoni Fogel committed
24
#include "ydb.h"
25 26 27 28 29
//TDB uses DB_NOTFOUND for c_del and DB_CURRENT errors.
#ifdef DB_KEYEMPTY
#error
#endif
#define DB_KEYEMPTY DB_NOTFOUND
Rich Prohaska's avatar
Rich Prohaska committed
30
#endif
31 32 33
#ifndef DB_YESOVERWRITE
#define DB_YESOVERWRITE 0
#endif
34 35 36
#ifndef DB_DELETE_ANY
#define DB_DELETE_ANY 0
#endif
37

38 39
int verbose=0;

40 41
#define UU(x) x __attribute__((__unused__))

42 43 44
#define CKERR(r) do { if (r!=0) fprintf(stderr, "%s:%d error %d %s\n", __FILE__, __LINE__, r, db_strerror(r)); assert(r==0); } while (0)
#define CKERR2(r,r2) do { if (r!=r2) fprintf(stderr, "%s:%d error %d %s, expected %d\n", __FILE__, __LINE__, r, db_strerror(r), r2); assert(r==r2); } while (0)
#define CKERR2s(r,r2,r3) do { if (r!=r2 && r!=r3) fprintf(stderr, "%s:%d error %d %s, expected %d or %d\n", __FILE__, __LINE__, r, db_strerror(r), r2,r3); assert(r==r2||r==r3); } while (0)
45

46 47 48 49 50 51 52
// If the error code depends on BDB vs TDB use this
#ifdef USE_TDB
#define CKERR_depending(r,tdbexpect,bdbexpect) CKERR2(r,tdbexpect)
#else
#define CKERR_depending(r,tdbexpect,bdbexpect) CKERR2(r,bdbexpect)
#endif

53
static __attribute__((__unused__)) void
54
parse_args (int argc, char *argv[]) {
55 56 57 58
    const char *argv0=argv[0];
    while (argc>1) {
	int resultcode=0;
	if (strcmp(argv[1], "-v")==0) {
59
	    verbose++;
60 61 62
	} else if (strcmp(argv[1],"-q")==0) {
	    verbose--;
	    if (verbose<0) verbose=0;
63 64
	} else if (strcmp(argv[1], "-h")==0) {
	do_usage:
65
	    fprintf(stderr, "Usage:\n%s [-v|-q] [-h]\n", argv0);
66 67 68 69 70 71 72 73 74
	    exit(resultcode);
	} else {
	    resultcode=1;
	    goto do_usage;
	}
	argc--;
	argv++;
    }
}
75

76 77 78 79 80 81 82 83
static __attribute__((__unused__)) void 
print_engine_status(DB_ENV * UU(env)) {
#ifdef USE_TDB
    if (verbose) {  // verbose declared statically in this file
      int buffsize = 1024 * 32;
      char buff[buffsize];
      env->get_engine_status_text(env, buff, buffsize);
      printf("Engine status:\n");
84
      printf("%s", buff);
85 86 87 88 89
    }
#endif
}


90
static __attribute__((__unused__)) DBT *
91
dbt_init(DBT *dbt, const void *data, u_int32_t size) {
92
    memset(dbt, 0, sizeof *dbt);
93
    dbt->data = (void*)data;
94 95 96 97
    dbt->size = size;
    return dbt;
}

98 99
static __attribute__((__unused__)) DBT *
dbt_init_malloc (DBT *dbt) {
100 101 102 103
    memset(dbt, 0, sizeof *dbt);
    dbt->flags = DB_DBT_MALLOC;
    return dbt;
}
104

105 106 107 108 109 110 111
static __attribute__((__unused__)) DBT *
dbt_init_realloc (DBT *dbt) {
    memset(dbt, 0, sizeof *dbt);
    dbt->flags = DB_DBT_REALLOC;
    return dbt;
}

112
// Simple LCG random number generator.  Not high quality, but good enough.
Yoni Fogel's avatar
Yoni Fogel committed
113
static u_int32_t rstate=1;
114 115 116
static inline void mysrandom (int s) {
    rstate=s;
}
Yoni Fogel's avatar
Yoni Fogel committed
117 118
static inline u_int32_t myrandom (void) {
    rstate = (279470275ull*(u_int64_t)rstate)%4294967291ull;
119 120
    return rstate;
}
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
121

122
static __attribute__((__unused__)) int
123 124 125 126 127 128
int64_dbt_cmp (DB *db UU(), const DBT *a, const DBT *b) {
//    assert(db && a && b);
    assert(a);
    assert(b);
//    assert(db);

129 130 131 132 133 134 135 136 137 138 139
    assert(a->size == sizeof(int64_t));
    assert(b->size == sizeof(int64_t));

    int64_t x = *(int64_t *) a->data;
    int64_t y = *(int64_t *) b->data;

    if (x<y) return -1;
    if (x>y) return 1;
    return 0;
}

140 141
static __attribute__((__unused__)) int
int_dbt_cmp (DB *db, const DBT *a, const DBT *b) {
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
142 143 144 145 146 147 148
  assert(db && a && b);
  assert(a->size == sizeof(int));
  assert(b->size == sizeof(int));

  int x = *(int *) a->data;
  int y = *(int *) b->data;

149 150 151
    if (x<y) return -1;
    if (x>y) return 1;
    return 0;
Vincenzo Liberatore's avatar
Vincenzo Liberatore committed
152
}
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
153

154 155 156 157 158 159 160 161 162 163 164 165 166 167
static __attribute__((__unused__)) int
uint_dbt_cmp (DB *db, const DBT *a, const DBT *b) {
  assert(db && a && b);
  assert(a->size == sizeof(unsigned int));
  assert(b->size == sizeof(unsigned int));

  unsigned int x = *(unsigned int *) a->data;
  unsigned int y = *(unsigned int *) b->data;

    if (x<y) return -1;
    if (x>y) return 1;
    return 0;
}

168 169
#if !TOKU_WINDOWS && !defined(BOOL_DEFINED)
#define BOOL_DEFINED
Bradley C. Kuszmaul's avatar
Bradley C. Kuszmaul committed
170
typedef enum __toku_bool { FALSE=0, TRUE=1} BOOL;
171
#endif
172 173 174 175 176 177 178 179

#ifdef USE_TDB
#define SET_TRACE_FILE(x) toku_set_trace_file(x)
#define CLOSE_TRACE_FILE(x) toku_close_trace_file()
#else
#define SET_TRACE_FILE(x) ((void)0)
#define CLOSE_TRACE_FILE(x) ((void)0)
#endif
Yoni Fogel's avatar
Yoni Fogel committed
180

181
#include <memory.h>
Yoni Fogel's avatar
Yoni Fogel committed
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
static int __attribute__((__unused__))
abort_on_upgrade(DB* UU(pdb),
                 u_int32_t UU(old_version), const DBT *UU(old_descriptor), const DBT *UU(old_key), const DBT *UU(old_val),
                 u_int32_t UU(new_version), const DBT *UU(new_descriptor), const DBT *UU(new_key), const DBT *UU(new_val)) {
    assert(FALSE); //Must not upgrade.
    return ENOSYS;
}

unsigned int seed = 0xFEEDFACE;

static u_int64_t __attribute__((__unused__))
random64(void) {
    static int seeded = 0;
    if (!seeded) {
        seeded = 1;
        srandom(seed);
    }
    //random() generates 31 bits of randomness (low order)
    u_int64_t low     = random();
    u_int64_t high    = random();
    u_int64_t twobits = random();
    u_int64_t ret     = low | (high<<31) | (twobits<<62); 
    return ret;
}


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
//Simulate as hard a crash as possible.
//Choices:
//  raise(SIGABRT)
//  kill -SIGKILL $pid
//  divide by 0
//  null dereference
//  abort()
//  assert(FALSE) (from <assert.h>)
//  assert(FALSE) (from <toku_assert.h>)
//
//Linux:
//  abort() and both assert(FALSE) cause FILE buffers to be flushed and written to disk: Unacceptable
//Windows:
//  None of them cause file buffers to be flushed/written to disk, however
//  abort(), assert(FALSE) <assert.h>, null dereference, and divide by 0 cause popups requiring user intervention during tests: Unacceptable
//
//kill -SIGKILL $pid is annoying (and so far untested)
//
//raise(SIGABRT) has the downside that perhaps it could be caught?
//I'm choosing raise(SIGABRT), followed by divide by 0, followed by null dereference, followed by all the others just in case one gets caught.
static void UU()
toku_hard_crash_on_purpose(void) {
#if TOKU_WINDOWS
    TerminateProcess(GetCurrentProcess(), 137);
#else
    raise(SIGKILL); //Does not flush buffers on linux; cannot be caught.
#endif
    {
        int zero = 0;
        int infinity = 1/zero;
        fprintf(stderr, "Force use of %d\n", infinity);
        fflush(stderr); //Make certain the string is calculated.
    }
    {
        void * intothevoid = NULL;
        (*(int*)intothevoid)++;
        fprintf(stderr, "Force use of *(%p) = %d\n", intothevoid, *(int*)intothevoid);
        fflush(stderr);
    }
    abort();
    fprintf(stderr, "This line should never be printed\n");
    fflush(stderr);
}

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
#if defined(__cilkplusplus) || defined(__cplusplus)
}
#endif

int test_main (int argc, char *argv[]);
int
#if defined(__cilkplusplus)
cilk_main(int argc, char *argv[]) 
#else
main(int argc, char *argv[]) 
#endif
{
    int r;
#if IS_TDB && (defined(_WIN32) || defined(_WIN64))
    int rinit = toku_ydb_init();
    CKERR(rinit);
#endif
#if !IS_TDB && DB_VERSION_MINOR==4 && DB_VERSION_MINOR == 7
    r = db_env_set_func_malloc(toku_malloc);   assert(r==0);
    r = db_env_set_func_free(toku_free);      assert(r==0);
    r = db_env_set_func_realloc(toku_realloc);   assert(r==0);
#endif
    toku_os_initialize_settings(1);
    r = test_main(argc, argv);
#if IS_TDB && (defined(_WIN32) || defined(_WIN64))
    int rdestroy = toku_ydb_destroy();
    CKERR(rdestroy);
#endif
    return r;
}

#endif // __TEST_H