summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/dbm/tests
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/dbm/tests')
-rw-r--r--security/nss/lib/dbm/tests/Makefile41
-rw-r--r--security/nss/lib/dbm/tests/dbmtest.pkg2
-rw-r--r--security/nss/lib/dbm/tests/lots.c553
3 files changed, 596 insertions, 0 deletions
diff --git a/security/nss/lib/dbm/tests/Makefile b/security/nss/lib/dbm/tests/Makefile
new file mode 100644
index 0000000000..3ecabe27cb
--- /dev/null
+++ b/security/nss/lib/dbm/tests/Makefile
@@ -0,0 +1,41 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+DEPTH = ../../..
+CORE_DEPTH = ../../..
+
+VPATH = $(CORE_DEPTH)/../dbm/tests
+
+MODULE = dbm
+
+CSRCS = lots.c
+
+PROGRAM = lots
+
+include $(DEPTH)/coreconf/config.mk
+
+include $(DEPTH)/dbm/config/config.mk
+
+ifeq (,$(filter-out WIN%,$(OS_TARGET)))
+LIBDBM = ../src/$(PLATFORM)/dbm$(STATIC_LIB_SUFFIX)
+else
+LIBDBM = ../src/$(PLATFORM)/libdbm$(STATIC_LIB_SUFFIX)
+endif
+
+INCLUDES += -I$(CORE_DEPTH)/../dbm/include
+
+LDFLAGS = $(LDOPTS) $(LIBDBM)
+
+include $(DEPTH)/coreconf/rules.mk
+
+lots.pure: lots
+ purify $(CC) -o lots.pure $(CFLAGS) $(OBJS) $(MYLIBS)
+
+crash: crash.o $(MYLIBS)
+ $(CC) -o crash $(CFLAGS) $^
+
+crash.pure: crash.o $(MYLIBS)
+ purify $(CC) -o crash.pure $(CFLAGS) $^
+
diff --git a/security/nss/lib/dbm/tests/dbmtest.pkg b/security/nss/lib/dbm/tests/dbmtest.pkg
new file mode 100644
index 0000000000..abd564bedf
--- /dev/null
+++ b/security/nss/lib/dbm/tests/dbmtest.pkg
@@ -0,0 +1,2 @@
+[gecko-tests]
+dist/bin/lots@BINS@
diff --git a/security/nss/lib/dbm/tests/lots.c b/security/nss/lib/dbm/tests/lots.c
new file mode 100644
index 0000000000..4a12884ba0
--- /dev/null
+++ b/security/nss/lib/dbm/tests/lots.c
@@ -0,0 +1,553 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* use sequental numbers printed to strings
+ * to store lots and lots of entries in the
+ * database.
+ *
+ * Start with 100 entries, put them and then
+ * read them out. Then delete the first
+ * half and verify that all of the first half
+ * is gone and then verify that the second
+ * half is still there.
+ * Then add the first half back and verify
+ * again. Then delete the middle third
+ * and verify again.
+ * Then increase the size by 1000 and do
+ * the whole add delete thing again.
+ *
+ * The data for each object is the number string translated
+ * to hex and replicated a random number of times. The
+ * number of times that the data is replicated is the first
+ * int32 in the data.
+ */
+
+#include <stdio.h>
+
+#include <stdlib.h>
+#ifdef STDC_HEADERS
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <string.h>
+#include <assert.h>
+#include "mcom_db.h"
+
+DB *database = 0;
+int MsgPriority = 5;
+
+#if defined(_WINDOWS) && !defined(WIN32)
+#define int32 long
+#define uint32 unsigned long
+#else
+#define int32 int
+#define uint32 unsigned int
+#endif
+
+typedef enum {
+ USE_LARGE_KEY,
+ USE_SMALL_KEY
+} key_type_enum;
+
+#define TraceMe(priority, msg) \
+ do { \
+ if (priority <= MsgPriority) { \
+ ReportStatus msg; \
+ } \
+ } while (0)
+
+int
+ReportStatus(char *string, ...)
+{
+ va_list args;
+
+#ifdef STDC_HEADERS
+ va_start(args, string);
+#else
+ va_start(args);
+#endif
+ vfprintf(stderr, string, args);
+ va_end(args);
+
+ fprintf(stderr, "\n");
+
+ return (0);
+}
+
+int
+ReportError(char *string, ...)
+{
+ va_list args;
+
+#ifdef STDC_HEADERS
+ va_start(args, string);
+#else
+ va_start(args);
+#endif
+ fprintf(stderr, "\n ");
+ vfprintf(stderr, string, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+
+ return (0);
+}
+
+DBT *
+MakeLargeKey(int32 num)
+{
+ int32 low_bits;
+ static DBT rv;
+ static char *string_rv = 0;
+ int rep_char;
+ size_t size;
+
+ if (string_rv)
+ free(string_rv);
+
+ /* generate a really large text key derived from
+ * an int32
+ */
+ low_bits = (num % 10000) + 1;
+
+ /* get the repeat char from the low 26 */
+ rep_char = (char)((low_bits % 26) + 'a');
+
+ /* malloc a string low_bits wide */
+ size = low_bits * sizeof(char);
+ string_rv = (char *)malloc(size);
+
+ memset(string_rv, rep_char, size);
+
+ rv.data = string_rv;
+ rv.size = size;
+
+ return (&rv);
+}
+
+DBT *
+MakeSmallKey(int32 num)
+{
+ static DBT rv;
+ static char data_string[64];
+
+ rv.data = data_string;
+
+ snprintf(data_string, sizeof(data_string), "%ld", (long)num);
+ rv.size = strlen(data_string);
+
+ return (&rv);
+}
+
+DBT *
+GenKey(int32 num, key_type_enum key_type)
+{
+ DBT *key;
+
+ switch (key_type) {
+ case USE_LARGE_KEY:
+ key = MakeLargeKey(num);
+ break;
+ case USE_SMALL_KEY:
+ key = MakeSmallKey(num);
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ return (key);
+}
+
+int
+SeqDatabase()
+{
+ int status;
+ DBT key, data;
+
+ ReportStatus("SEQuencing through database...");
+
+ /* seq through the whole database */
+ if (!(status = (*database->seq)(database, &key, &data, R_FIRST))) {
+ while (!(status = (database->seq)(database, &key, &data, R_NEXT)))
+ ; /* null body */
+ }
+
+ if (status < 0)
+ ReportError("Error seq'ing database");
+
+ return (status);
+}
+
+int
+VerifyData(DBT *data, int32 num, key_type_enum key_type)
+{
+ int32 count, compare_num;
+ size_t size;
+ int32 *int32_array;
+
+ /* The first int32 is count
+ * The other n entries should
+ * all equal num
+ */
+ if (data->size < sizeof(int32)) {
+ ReportError("Data size corrupted");
+ return -1;
+ }
+
+ memcpy(&count, data->data, sizeof(int32));
+
+ size = sizeof(int32) * (count + 1);
+
+ if (size != data->size) {
+ ReportError("Data size corrupted");
+ return -1;
+ }
+
+ int32_array = (int32 *)data->data;
+
+ for (; count > 0; count--) {
+ memcpy(&compare_num, &int32_array[count], sizeof(int32));
+
+ if (compare_num != num) {
+ ReportError("Data corrupted");
+ return -1;
+ }
+ }
+
+ return (0);
+}
+
+/* verify that a range of number strings exist
+ * or don't exist. And that the data is valid
+ */
+#define SHOULD_EXIST 1
+#define SHOULD_NOT_EXIST 0
+int
+VerifyRange(int32 low, int32 high, int32 should_exist, key_type_enum key_type)
+{
+ DBT *key, data;
+ int32 num;
+ int status;
+
+ TraceMe(1, ("Verifying: %ld to %ld, using %s keys",
+ low, high, key_type == USE_SMALL_KEY ? "SMALL" : "LARGE"));
+
+ for (num = low; num <= high; num++) {
+
+ key = GenKey(num, key_type);
+
+ status = (*database->get)(database, key, &data, 0);
+
+ if (status == 0) {
+ /* got the item */
+ if (!should_exist) {
+ ReportError("Item exists but shouldn't: %ld", num);
+ } else {
+ /* else verify the data */
+ VerifyData(&data, num, key_type);
+ }
+ } else if (status > 0) {
+ /* item not found */
+ if (should_exist) {
+ ReportError("Item not found but should be: %ld", num);
+ }
+ } else {
+ /* database error */
+ ReportError("Database error");
+ return (-1);
+ }
+ }
+
+ TraceMe(1, ("Correctly verified: %ld to %ld", low, high));
+
+ return (0);
+}
+
+DBT *
+GenData(int32 num)
+{
+ int32 n;
+ static DBT *data = 0;
+ int32 *int32_array;
+ size_t size;
+
+ if (!data) {
+ data = (DBT *)malloc(sizeof(DBT));
+ data->size = 0;
+ data->data = 0;
+ } else if (data->data) {
+ free(data->data);
+ }
+
+ n = rand();
+
+ n = n % 512; /* bound to a 2K size */
+
+ size = sizeof(int32) * (n + 1);
+ int32_array = (int32 *)malloc(size);
+
+ memcpy(&int32_array[0], &n, sizeof(int32));
+
+ for (; n > 0; n--) {
+ memcpy(&int32_array[n], &num, sizeof(int32));
+ }
+
+ data->data = (void *)int32_array;
+ data->size = size;
+
+ return (data);
+}
+
+#define ADD_RANGE 1
+#define DELETE_RANGE 2
+
+int
+AddOrDelRange(int32 low, int32 high, int action, key_type_enum key_type)
+{
+ DBT *key, *data;
+#if 0 /* only do this if your really analy checking the puts */
+ DBT tmp_data;
+#endif
+ int32 num;
+ int status;
+
+ if (action != ADD_RANGE && action != DELETE_RANGE)
+ assert(0);
+
+ if (action == ADD_RANGE) {
+ TraceMe(1, ("Adding: %ld to %ld: %s keys", low, high,
+ key_type == USE_SMALL_KEY ? "SMALL" : "LARGE"));
+ } else {
+ TraceMe(1, ("Deleting: %ld to %ld: %s keys", low, high,
+ key_type == USE_SMALL_KEY ? "SMALL" : "LARGE"));
+ }
+
+ for (num = low; num <= high; num++) {
+
+ key = GenKey(num, key_type);
+
+ if (action == ADD_RANGE) {
+ data = GenData(num);
+ status = (*database->put)(database, key, data, 0);
+ } else {
+ status = (*database->del)(database, key, 0);
+ }
+
+ if (status < 0) {
+ ReportError("Database error %s item: %ld",
+ action == ADD_RANGE ? "ADDING" : "DELETING",
+ num);
+ } else if (status > 0) {
+ ReportError("Could not %s item: %ld",
+ action == ADD_RANGE ? "ADD" : "DELETE",
+ num);
+ } else if (action == ADD_RANGE) {
+#define SYNC_EVERY_TIME
+#ifdef SYNC_EVERY_TIME
+ status = (*database->sync)(database, 0);
+ if (status != 0)
+ ReportError("Database error syncing after add");
+#endif
+
+#if 0 /* only do this if your really analy checking the puts */
+
+ /* make sure we can still get it
+ */
+ status = (*database->get)(database, key, &tmp_data, 0);
+
+ if(status != 0)
+ {
+ ReportError("Database error checking item just added: %d",
+ num);
+ }
+ else
+ {
+ /* now verify that none of the ones we already
+ * put in have disappeared
+ */
+ VerifyRange(low, num, SHOULD_EXIST, key_type);
+ }
+#endif
+ }
+ }
+
+ if (action == ADD_RANGE) {
+ TraceMe(1, ("Successfully added: %ld to %ld", low, high));
+ } else {
+ TraceMe(1, ("Successfully deleted: %ld to %ld", low, high));
+ }
+
+ return (0);
+}
+
+int
+TestRange(int32 low, int32 range, key_type_enum key_type)
+{
+ int status;
+ int32 low_of_range1, high_of_range1;
+ int32 low_of_range2, high_of_range2;
+ int32 low_of_range3, high_of_range3;
+
+ status = AddOrDelRange(low, low + range, ADD_RANGE, key_type);
+ status = VerifyRange(low, low + range, SHOULD_EXIST, key_type);
+
+ TraceMe(1, ("Finished with sub test 1"));
+
+ SeqDatabase();
+
+ low_of_range1 = low;
+ high_of_range1 = low + (range / 2);
+ low_of_range2 = high_of_range1 + 1;
+ high_of_range2 = low + range;
+ status = AddOrDelRange(low_of_range1, high_of_range1, DELETE_RANGE, key_type);
+ status = VerifyRange(low_of_range1, high_of_range1, SHOULD_NOT_EXIST, key_type);
+ status = VerifyRange(low_of_range2, low_of_range2, SHOULD_EXIST, key_type);
+
+ TraceMe(1, ("Finished with sub test 2"));
+
+ SeqDatabase();
+
+ status = AddOrDelRange(low_of_range1, high_of_range1, ADD_RANGE, key_type);
+ /* the whole thing should exist now */
+ status = VerifyRange(low, low + range, SHOULD_EXIST, key_type);
+
+ TraceMe(1, ("Finished with sub test 3"));
+
+ SeqDatabase();
+
+ status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type);
+ status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type);
+ status = VerifyRange(low_of_range2, high_of_range2, SHOULD_NOT_EXIST, key_type);
+
+ TraceMe(1, ("Finished with sub test 4"));
+
+ SeqDatabase();
+
+ status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type);
+ /* the whole thing should exist now */
+ status = VerifyRange(low, low + range, SHOULD_EXIST, key_type);
+
+ TraceMe(1, ("Finished with sub test 5"));
+
+ SeqDatabase();
+
+ low_of_range1 = low;
+ high_of_range1 = low + (range / 3);
+ low_of_range2 = high_of_range1 + 1;
+ high_of_range2 = high_of_range1 + (range / 3);
+ low_of_range3 = high_of_range2 + 1;
+ high_of_range3 = low + range;
+ /* delete range 2 */
+ status = AddOrDelRange(low_of_range2, high_of_range2, DELETE_RANGE, key_type);
+ status = VerifyRange(low_of_range1, high_of_range1, SHOULD_EXIST, key_type);
+ status = VerifyRange(low_of_range2, low_of_range2, SHOULD_NOT_EXIST, key_type);
+ status = VerifyRange(low_of_range3, low_of_range2, SHOULD_EXIST, key_type);
+
+ TraceMe(1, ("Finished with sub test 6"));
+
+ SeqDatabase();
+
+ status = AddOrDelRange(low_of_range2, high_of_range2, ADD_RANGE, key_type);
+ /* the whole thing should exist now */
+ status = VerifyRange(low, low + range, SHOULD_EXIST, key_type);
+
+ TraceMe(1, ("Finished with sub test 7"));
+
+ return (0);
+}
+
+#define START_RANGE 109876
+int
+main(int argc, char **argv)
+{
+ int32 i, j = 0;
+ int quick_exit = 0;
+ int large_keys = 0;
+ HASHINFO hash_info = {
+ 16 * 1024,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ if (argc > 1) {
+ while (argc > 1) {
+ if (!strcmp(argv[argc - 1], "-quick"))
+ quick_exit = 1;
+ else if (!strcmp(argv[argc - 1], "-large")) {
+ large_keys = 1;
+ }
+ argc--;
+ }
+ }
+
+ database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, &hash_info);
+
+ if (!database) {
+ ReportError("Could not open database");
+#ifdef unix
+ perror("");
+#endif
+ exit(1);
+ }
+
+ if (quick_exit) {
+ if (large_keys)
+ TestRange(START_RANGE, 200, USE_LARGE_KEY);
+ else
+ TestRange(START_RANGE, 200, USE_SMALL_KEY);
+
+ (*database->sync)(database, 0);
+ (*database->close)(database);
+ exit(0);
+ }
+
+ for (i = 100; i < 10000000; i += 200) {
+ if (1 || j) {
+ TestRange(START_RANGE, i, USE_LARGE_KEY);
+ j = 0;
+ } else {
+ TestRange(START_RANGE, i, USE_SMALL_KEY);
+ j = 1;
+ }
+
+ if (1 == rand() % 3) {
+ (*database->sync)(database, 0);
+ }
+
+ if (1 == rand() % 3) {
+ /* close and reopen */
+ (*database->close)(database);
+ database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0);
+ if (!database) {
+ ReportError("Could not reopen database");
+#ifdef unix
+ perror("");
+#endif
+ exit(1);
+ }
+ } else {
+ /* reopen database without closeing the other */
+ database = dbopen("test.db", O_RDWR | O_CREAT, 0644, DB_HASH, 0);
+ if (!database) {
+ ReportError("Could not reopen database "
+ "after not closing the other");
+#ifdef unix
+ perror("");
+#endif
+ exit(1);
+ }
+ }
+ }
+
+ return (0);
+}