diff options
Diffstat (limited to '')
36 files changed, 9343 insertions, 0 deletions
diff --git a/test/Makefile.in b/test/Makefile.in new file mode 100644 index 0000000..73a92e5 --- /dev/null +++ b/test/Makefile.in @@ -0,0 +1,90 @@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +# PROGRAMS includes all test programs built on this platform. +# STDTEST_PORTABLE +# test programs invoked via standard user interface, run on all platforms +# ALL_TESTS +# test modules invoked through the abts suite (./testall) +# OTHER_PROGRAMS +# programs such as sockperf, that have to be invoked in a special sequence +# or with special parameters + +INCLUDES = @APRUTIL_PRIV_INCLUDES@ @APR_INCLUDES@ @APRUTIL_INCLUDES@ + +STDTEST_PORTABLE = dbd testall + +TESTS = teststrmatch.lo testuri.lo testuuid.lo testbuckets.lo testpass.lo \ + testmd4.lo testmd5.lo testldap.lo testdate.lo testdbm.lo testdbd.lo \ + testxml.lo testrmm.lo testreslist.lo testqueue.lo testxlate.lo \ + testmemcache.lo testcrypto.lo testsiphash.lo testredis.lo + +PROGRAMS = $(STDTEST_PORTABLE) + +TARGETS = $(PROGRAMS) + +LOCAL_LIBS = ../lib@APRUTIL_LIBNAME@@APRUTIL_MAJOR_VERSION@.la + +CLEAN_TARGETS = manyfile.bin testfile.txt data/sqlite*.db + +# bring in rules.mk for standard functionality +@INCLUDE_RULES@ +APRUTIL_LIBS = @APRUTIL_LIBS@ +APRUTIL_LDFLAGS = $(ALL_LDFLAGS) @LT_NO_INSTALL@ @APRUTIL_LDFLAGS@ + +# link programs using -no-install to get real executables not +# libtool wrapper scripts which link an executable when first run. +LINK_PROG = $(LIBTOOL) $(LTFLAGS) --mode=link --tag=CC $(COMPILE) $(LT_LDFLAGS) \ + $(APRUTIL_LDFLAGS) -o $@ + +# STDTEST_PORTABLE; + +abts.lo: $(srcdir)/abts.c $(srcdir)/abts.h $(srcdir)/abts_tests.h \ + $(srcdir)/testutil.h + +testutil.lo: $(srcdir)/abts.c $(srcdir)/abts.h $(srcdir)/abts_tests.h \ + $(srcdir)/testutil.h + +OBJECTS_testall = abts.lo testutil.lo $(TESTS) $(LOCAL_LIBS) +testall: $(OBJECTS_testall) + $(LINK_PROG) $(OBJECTS_testall) $(APRUTIL_LIBS) @LDADD_ldap@ +# For VPATH builds; where we have no ./data, copy us some data +# if we wait until 'make check', then 'make; ./testall' fails; + if test ! -d "./data"; then cp -r $(srcdir)/data data; fi + +OBJECTS_dbd = dbd.lo $(LOCAL_LIBS) +dbd: $(OBJECTS_dbd) + $(LINK_PROG) $(OBJECTS_dbd) $(APRUTIL_LIBS) + +check: $(TESTALL_COMPONENTS) $(STDTEST_PORTABLE) $(STDTEST_NONPORTABLE) + teststatus=0; \ + progfailed=""; \ + for prog in $(STDTEST_NONPORTABLE) $(STDTEST_PORTABLE); do \ + if test "$$prog" = 'dbd'; then \ + for driver in none @apu_dbd_tests@; do \ + if test "$$driver" != 'none'; then \ + @apr_shlibpath_var@="`echo "../crypto/.libs:../dbm/.libs:../dbd/.libs:../ldap/.libs:$$@apr_shlibpath_var@" | sed -e 's/::*$$//'`" \ + ./$$prog $$driver; \ + status=$$?; \ + if test $$status != 0; then \ + teststatus=$$status; \ + progfailed="$$progfailed '$$prog $$driver'"; \ + fi; \ + fi; \ + done; \ + else \ + @apr_shlibpath_var@="`echo "../crypto/.libs:../dbm/.libs:../dbd/.libs:../ldap/.libs:$$@apr_shlibpath_var@" | sed -e 's/::*$$//'`" \ + ./$$prog; \ + status=$$?; \ + if test $$status != 0; then \ + teststatus=$$status; \ + progfailed="$$progfailed $$prog"; \ + fi; \ + fi; \ + done; \ + if test $$teststatus != 0; then \ + echo "Programs failed:$$progfailed"; \ + fi; \ + exit $$teststatus + +# DO NOT REMOVE diff --git a/test/Makefile.win b/test/Makefile.win new file mode 100644 index 0000000..fa3d2eb --- /dev/null +++ b/test/Makefile.win @@ -0,0 +1,171 @@ +# PROGRAMS +# test programs invoked via standard user interface, run on all platforms +# ALL_TESTS +# test modules invoked through the abts suite (./testall) +# OTHER_PROGRAMS +# programs such as sendfile, that have to be invoked in a special sequence +# or with special parameters + +# Windows Specific; +# MODEL +# dynamic or static - refers to which set of bindings are desired +# and controls which libraries (apr-1 or libapr-1) will be linked. +# OUTDIR +# the library path of the libraries, and also the path within test/ +# where all of the tests for that library will be built +# APROUTDIR +# The library path of apr (if different from OUTDIR) +# APR_PATH +# relative or absolute path to locate apr libs and includes +# API_PATH +# relative or absolute path to locate apr-iconv libs and includes + +!IFNDEF MODEL +MODEL=dynamic +!ENDIF + +!IFNDEF OUTDIR +!IF "$(MODEL)" == "static" +OUTDIR=LibR +!ELSE +OUTDIR=Release +!ENDIF + +!IF [$(COMSPEC) /c cl /nologo /? \ + | $(SystemRoot)\System32\find.exe "x64" >NUL ] == 0 +OUTDIR=x64\$(OUTDIR) +!ENDIF +!ENDIF + +!IF !EXIST("$(OUTDIR)\.") +!IF ([$(COMSPEC) /C mkdir $(OUTDIR)] == 0) +!ENDIF +!ENDIF + +!IFNDEF INTDIR +INTDIR=$(OUTDIR) +!ELSE +!IF !EXIST("$(INTDIR)\.") +!IF ([$(COMSPEC) /C mkdir $(INTDIR)] == 0) +!ENDIF +!ENDIF +!ENDIF + +!MESSAGE Building tests into $(OUTDIR) for $(MODEL) + +ALL_TESTS = $(INTDIR)\teststrmatch.obj $(INTDIR)\testuri.obj \ + $(INTDIR)\testuuid.obj $(INTDIR)\testutil.obj \ + $(INTDIR)\testbuckets.obj $(INTDIR)\testpass.obj \ + $(INTDIR)\testmd4.obj $(INTDIR)\testmd5.obj \ + $(INTDIR)\testldap.obj $(INTDIR)\testdbd.obj \ + $(INTDIR)\testdbm.obj $(INTDIR)\testreslist.obj \ + $(INTDIR)\testxml.obj $(INTDIR)\testqueue.obj \ + $(INTDIR)\testrmm.obj $(INTDIR)\testxlate.obj \ + $(INTDIR)\testdate.obj $(INTDIR)\testmemcache.obj \ + $(INTDIR)\testredis.obj $(INTDIR)\testsiphash.obj \ + $(INTDIR)\testcrypto.obj + +CLEAN_DATA = manyfile.bin testfile.txt data\sqlite*.db + +CLEAN_BUILDDIRS = Debug Release LibD LibR 9x x64 + +PROGRAMS = \ + $(OUTDIR)\testall.exe + +OTHER_PROGRAMS = \ + $(OUTDIR)\dbd.exe + +# bring in rules.mk for standard functionality +ALL: $(PROGRAMS) $(OTHER_PROGRAMS) + +CL = cl.exe +LD = link.exe + +APR_PATH = ..\..\apr +API_PATH = ..\..\apr-iconv + +APROUTDIR=$(OUTDIR) + +!IF "$(MODEL)" == "static" +PROGRAM_DEPENDENCIES = \ + $(APR_PATH)\$(APROUTDIR)\apr-1.lib \ + $(API_PATH)\$(OUTDIR)\apriconv-1.lib \ + ..\$(OUTDIR)\aprutil-1.lib +STATIC_CFLAGS = /D APR_DECLARE_STATIC /D APU_DECLARE_STATIC +STATIC_LIBS = libexpatMT.lib odbc32.lib odbccp32.lib wldap32.lib +!ELSE +PROGRAM_DEPENDENCIES = \ + $(APR_PATH)\$(APROUTDIR)\libapr-1.lib \ + ..\$(OUTDIR)\libaprutil-1.lib +STATIC_CFLAGS = +# APR 1.3 doesn't fully abstract ldap_ calls to permit switching providers; +STATIC_LIBS = wldap32.lib +!ENDIF + +!IFDEF _DEBUG +DEBUG_CFLAGS = /MDd +!ELSE +DEBUG_CFLAGS = /MD +!ENDIF + +INCLUDES=/I "../include" /I "$(API_PATH)/include" /I "$(APR_PATH)/include" + +CFLAGS = /nologo /c /W3 /Gm /EHsc /Zi /Od $(INCLUDES) \ + $(STATIC_CFLAGS) $(DEBUG_CFLAGS) /D "BINPATH=$(OUTDIR:\=/)" \ + /D _DEBUG /D WIN32 /Fo"$(INTDIR)/" /FD + +LD_LIBS = kernel32.lib advapi32.lib ws2_32.lib wsock32.lib \ + ole32.lib shell32.lib rpcrt4.lib $(STATIC_LIBS) + +LDFLAGS = /nologo /debug /subsystem:console /incremental:no +SHLDFLAGS = /nologo /dll /debug /subsystem:windows /incremental:no + +.c{$(INTDIR)}.obj:: + $(CL) $(CFLAGS) -c $< -Fd$(INTDIR)\ $(INCLUDES) + +# PROGRAMS; + +abts.c: abts.h abts_tests.h testutil.h + +testutil.c: abts.h abts_tests.h testutil.h + +$(OUTDIR)\testall.exe: $(ALL_TESTS) $(INTDIR)\abts.obj $(PROGRAM_DEPENDENCIES) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +# OTHER_PROGRAMS; + +$(OUTDIR)\dbd.exe: $(INTDIR)\dbd.obj $(PROGRAM_DEPENDENCIES) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + + +cleandata: + @for %f in ($(CLEAN_DATA)) do @if EXIST %f del /f %f + +clean: cleandata + @if EXIST $(INTDIR)\. rmdir /s /q $(INTDIR) + @if EXIST $(OUTDIR)\. rmdir /s /q $(OUTDIR) + +cleanall: + @for %d in ($(CLEAN_BUILDDIRS) $(INTDIR) $(OUTDIR)) do \ + @if EXIST %d\. rmdir /s /q %d + + +!IF "$(MODEL)" != "static" +PATH=$(OUTDIR);..\$(OUTDIR);..\ldap\$(OUTDIR);..\dbd\$(OUTDIR);$(API_PATH)\$(OUTDIR);$(APR_PATH)\$(APROUTDIR);$(PATH) +!ENDIF +APR_ICONV1_PATH=$(API_PATH)\$(OUTDIR)\iconv + +check: $(PROGRAMS) $(OTHER_PROGRAMS) + echo Testing dbd sqlite2 && $(OUTDIR)\dbd.exe sqlite2 || echo Failed + echo Testing dbd sqlite3 && $(OUTDIR)\dbd.exe sqlite3 || echo Failed + @for %p in ($(PROGRAMS)) do @( \ + echo Testing %p && %p -v || echo %p failed \ + ) + +checkall: check + +# DO NOT REMOVE diff --git a/test/NWGNUaputest b/test/NWGNUaputest new file mode 100644 index 0000000..caf3cd4 --- /dev/null +++ b/test/NWGNUaputest @@ -0,0 +1,282 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/NetWare \ + $(APU)/include \ + $(LDAPSDK)/inc \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = aputest +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = NLM is to test the apu layer + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = aputest + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = aputest + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 524288 + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/aputest.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# + +FILES_nlm_objs = \ + $(OBJDIR)/abts.o \ + $(OBJDIR)/testbuckets.o \ + $(OBJDIR)/testcrypto.o \ + $(OBJDIR)/testdate.o \ + $(OBJDIR)/testdbd.o \ + $(OBJDIR)/testdbm.o \ + $(OBJDIR)/testmemcache.o \ + $(OBJDIR)/testmd4.o \ + $(OBJDIR)/testmd5.o \ + $(OBJDIR)/testldap.o \ + $(OBJDIR)/testpass.o \ + $(OBJDIR)/testqueue.o \ + $(OBJDIR)/testreslist.o \ + $(OBJDIR)/testrmm.o \ + $(OBJDIR)/testsiphash.o \ + $(OBJDIR)/teststrmatch.o \ + $(OBJDIR)/testuri.o \ + $(OBJDIR)/testutil.o \ + $(OBJDIR)/testuuid.o \ + $(OBJDIR)/testxml.o \ + $(OBJDIR)/testxlate.o \ + $(OBJDIR)/nw_misc.o \ + $(EOLIST) + +# Pending tests + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + Libc \ + APRLIB \ + lldapsdk \ + lldapssl \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @libc.imp \ + @aprlib.imp \ + @lldapsdk.imp \ + @lldapssl.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUmakefile b/test/NWGNUmakefile new file mode 100644 index 0000000..a955f2c --- /dev/null +++ b/test/NWGNUmakefile @@ -0,0 +1,258 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(APR_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/NetWare \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/aputest.nlm \ + $(OBJDIR)/aputest.nlm \ + $(EOLIST) +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + $(call COPY,$(OBJDIR)/*.nlm,$(INSTALLBASE)) + $(call COPYR,data,$(INSTALLBASE)/data/) + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/abts.c b/test/abts.c new file mode 100644 index 0000000..da0097d --- /dev/null +++ b/test/abts.c @@ -0,0 +1,423 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "abts.h" +#include "abts_tests.h" +#include "testutil.h" + +#define ABTS_STAT_SIZE 6 +static char status[ABTS_STAT_SIZE] = {'|', '/', '-', '|', '\\', '-'}; +static int curr_char; +static int verbose = 0; +static int exclude = 0; +static int quiet = 0; +static int list_tests = 0; + +const char **testlist = NULL; + +static int find_test_name(const char *testname) { + int i; + for (i = 0; testlist[i] != NULL; i++) { + if (!strcmp(testlist[i], testname)) { + return 1; + } + } + return 0; +} + +/* Determine if the test should be run at all */ +static int should_test_run(const char *testname) { + int found = 0; + if (list_tests == 1) { + return 0; + } + if (testlist == NULL) { + return 1; + } + found = find_test_name(testname); + if ((found && !exclude) || (!found && exclude)) { + return 1; + } + return 0; +} + +static void reset_status(void) +{ + curr_char = 0; +} + +static void update_status(void) +{ + if (!quiet) { + curr_char = (curr_char + 1) % ABTS_STAT_SIZE; + fprintf(stdout, "\b%c", status[curr_char]); + fflush(stdout); + } +} + +static void end_suite(abts_suite *suite) +{ + if (suite != NULL) { + sub_suite *last = suite->tail; + if (!quiet) { + fprintf(stdout, "\b"); + fflush(stdout); + } + if (last->failed == 0) { + fprintf(stdout, "SUCCESS\n"); + fflush(stdout); + } + else { + fprintf(stdout, "FAILED %d of %d\n", last->failed, last->num_test); + fflush(stdout); + } + } +} + +abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name_full) +{ + sub_suite *subsuite; + char *p; + const char *suite_name; + curr_char = 0; + + /* Only end the suite if we actually ran it */ + if (suite && suite->tail &&!suite->tail->not_run) { + end_suite(suite); + } + + subsuite = malloc(sizeof(*subsuite)); + subsuite->num_test = 0; + subsuite->failed = 0; + subsuite->next = NULL; + /* suite_name_full may be an absolute path depending on __FILE__ + * expansion */ + suite_name = strrchr(suite_name_full, '/'); + if (!suite_name) { + suite_name = strrchr(suite_name_full, '\\'); + } + if (suite_name) { + suite_name++; + } else { + suite_name = suite_name_full; + } + p = strrchr(suite_name, '.'); + if (p) { + subsuite->name = memcpy(calloc(p - suite_name + 1, 1), + suite_name, p - suite_name); + } + else { + subsuite->name = suite_name; + } + + if (list_tests) { + fprintf(stdout, "%s\n", subsuite->name); + } + + subsuite->not_run = 0; + + if (suite == NULL) { + suite = malloc(sizeof(*suite)); + suite->head = subsuite; + suite->tail = subsuite; + } + else { + suite->tail->next = subsuite; + suite->tail = subsuite; + } + + if (!should_test_run(subsuite->name)) { + subsuite->not_run = 1; + return suite; + } + + reset_status(); + fprintf(stdout, "%-20s: ", subsuite->name); + update_status(); + fflush(stdout); + + return suite; +} + +void abts_run_test(abts_suite *ts, test_func f, void *value) +{ + abts_case *tc; + sub_suite *ss; + + if (!should_test_run(ts->tail->name)) { + return; + } + ss = ts->tail; + + tc = malloc(sizeof(*tc)); + tc->failed = 0; + tc->suite = ss; + + ss->num_test++; + update_status(); + + f(tc, value); + + if (tc->failed) { + ss->failed++; + } + free(tc); +} + +static int report(abts_suite *suite) +{ + int count = 0; + sub_suite *dptr; + + if (suite && suite->tail &&!suite->tail->not_run) { + end_suite(suite); + } + + for (dptr = suite->head; dptr; dptr = dptr->next) { + count += dptr->failed; + } + + if (list_tests) { + return 0; + } + + if (count == 0) { + printf("All tests passed.\n"); + return 0; + } + + dptr = suite->head; + fprintf(stdout, "%-15s\t\tTotal\tFail\tFailed %%\n", "Failed Tests"); + fprintf(stdout, "===================================================\n"); + while (dptr != NULL) { + if (dptr->failed != 0) { + float percent = ((float)dptr->failed / (float)dptr->num_test); + fprintf(stdout, "%-15s\t\t%5d\t%4d\t%6.2f%%\n", dptr->name, + dptr->num_test, dptr->failed, percent * 100); + } + dptr = dptr->next; + } + return 1; +} + +void abts_log_message(const char *fmt, ...) +{ + va_list args; + update_status(); + + if (verbose) { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + fflush(stderr); + } +} + +void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected == actual) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected != actual) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected something other than <%d>, but saw <%d>\n", + lineno, expected, actual); + fflush(stderr); + } +} + +void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + /* If both are NULL, match is good */ + if (!expected && !actual) return; + if (expected && actual) + if (!strcmp(expected, actual)) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_str_nequal(abts_case *tc, const char *expected, const char *actual, + size_t n, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (!strncmp(expected, actual, n)) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected something other than <%s>, but saw <%s>\n", + lineno, expected, actual); + fflush(stderr); + } +} + +void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (ptr != NULL) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected non-NULL, but saw NULL\n", lineno); + fflush(stderr); + } +} + +void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected == actual) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%p>, but saw <%p>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_fail(abts_case *tc, const char *message, int lineno) +{ + update_status(); + if (tc->failed) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: %s\n", lineno, message); + fflush(stderr); + } +} + +void abts_assert(abts_case *tc, const char *message, int condition, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (condition) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: %s\n", lineno, message); + fflush(stderr); + } +} + +void abts_true(abts_case *tc, int condition, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (condition) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: Condition is false, but expected true\n", lineno); + fflush(stderr); + } +} + +void abts_not_impl(abts_case *tc, const char *message, int lineno) +{ + update_status(); + + tc->suite->not_impl++; + if (verbose) { + fprintf(stderr, "Line %d: %s\n", lineno, message); + fflush(stderr); + } +} + +int main(int argc, const char *const argv[]) { + int i; + int rv; + int list_provided = 0; + abts_suite *suite = NULL; + + initialize(); + + quiet = !isatty(STDOUT_FILENO); + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-v")) { + verbose = 1; + continue; + } + if (!strcmp(argv[i], "-x")) { + exclude = 1; + continue; + } + if (!strcmp(argv[i], "-l")) { + list_tests = 1; + continue; + } + if (!strcmp(argv[i], "-q")) { + quiet = 1; + continue; + } + if (argv[i][0] == '-') { + fprintf(stderr, "Invalid option: `%s'\n", argv[i]); + exit(1); + } + list_provided = 1; + } + + if (list_provided) { + /* Waste a little space here, because it is easier than counting the + * number of tests listed. Besides it is at most three char *. + */ + testlist = calloc(argc + 1, sizeof(char *)); + for (i = 1; i < argc; i++) { + testlist[i - 1] = argv[i]; + } + } + + for (i = 0; i < (sizeof(alltests) / sizeof(struct testlist *)); i++) { + suite = alltests[i].func(suite); + apr_pool_clear(p); + } + + rv = report(suite); + return rv; +} + diff --git a/test/abts.h b/test/abts.h new file mode 100644 index 0000000..a31def7 --- /dev/null +++ b/test/abts.h @@ -0,0 +1,101 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef WIN32 +#include <io.h> +#else +#include <unistd.h> +#endif + +#ifndef ABTS_H +#define ABTS_H + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +struct sub_suite { + const char *name; + int num_test; + int failed; + int not_run; + int not_impl; + struct sub_suite *next; +}; +typedef struct sub_suite sub_suite; + +struct abts_suite { + sub_suite *head; + sub_suite *tail; +}; +typedef struct abts_suite abts_suite; + +struct abts_case { + int failed; + sub_suite *suite; +}; +typedef struct abts_case abts_case; + +typedef void (*test_func)(abts_case *tc, void *data); + +#define ADD_SUITE(suite) abts_add_suite(suite, __FILE__); + +abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name); +void abts_run_test(abts_suite *ts, test_func f, void *value); +void abts_log_message(const char *fmt, ...); + +void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno); +void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno); +void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno); +void abts_str_nequal(abts_case *tc, const char *expected, const char *actual, + size_t n, int lineno); +void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno); +void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno); +void abts_true(abts_case *tc, int condition, int lineno); +void abts_fail(abts_case *tc, const char *message, int lineno); +void abts_not_impl(abts_case *tc, const char *message, int lineno); +void abts_assert(abts_case *tc, const char *message, int condition, int lineno); + +/* Convenience macros. Ryan hates these! */ +#define ABTS_INT_EQUAL(a, b, c) abts_int_equal(a, b, c, __LINE__) +#define ABTS_INT_NEQUAL(a, b, c) abts_int_nequal(a, b, c, __LINE__) +#define ABTS_STR_EQUAL(a, b, c) abts_str_equal(a, b, c, __LINE__) +#define ABTS_STR_NEQUAL(a, b, c, d) abts_str_nequal(a, b, c, d, __LINE__) +#define ABTS_PTR_NOTNULL(a, b) abts_ptr_notnull(a, b, __LINE__) +#define ABTS_PTR_EQUAL(a, b, c) abts_ptr_equal(a, b, c, __LINE__) +#define ABTS_TRUE(a, b) abts_true(a, b, __LINE__); +#define ABTS_FAIL(a, b) abts_fail(a, b, __LINE__); +#define ABTS_NOT_IMPL(a, b) abts_not_impl(a, b, __LINE__); +#define ABTS_ASSERT(a, b, c) abts_assert(a, b, c, __LINE__); + +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/test/abts_tests.h b/test/abts_tests.h new file mode 100644 index 0000000..cb4e113 --- /dev/null +++ b/test/abts_tests.h @@ -0,0 +1,48 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef APR_TEST_INCLUDES +#define APR_TEST_INCLUDES + +#include "abts.h" +#include "testutil.h" + +const struct testlist { + abts_suite *(*func)(abts_suite *suite); +} alltests[] = { + {teststrmatch}, + {testuri}, + {testuuid}, + {testbuckets}, + {testpass}, + {testmd4}, + {testmd5}, + {testcrypto}, + {testldap}, + {testdbd}, + {testdate}, + {testmemcache}, + {testredis}, + {testxml}, + {testxlate}, + {testrmm}, + {testdbm}, + {testqueue}, + {testreslist}, + {testsiphash} +}; + +#endif /* APR_TEST_INCLUDES */ diff --git a/test/data/billion-laughs.xml b/test/data/billion-laughs.xml new file mode 100644 index 0000000..3af89ae --- /dev/null +++ b/test/data/billion-laughs.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!DOCTYPE billion [ +<!ELEMENT billion (#PCDATA)> +<!ENTITY laugh0 "ha"> +<!ENTITY laugh1 "&laugh0;&laugh0;"> +<!ENTITY laugh2 "&laugh1;&laugh1;"> +<!ENTITY laugh3 "&laugh2;&laugh2;"> +<!ENTITY laugh4 "&laugh3;&laugh3;"> +<!ENTITY laugh5 "&laugh4;&laugh4;"> +<!ENTITY laugh6 "&laugh5;&laugh5;"> +<!ENTITY laugh7 "&laugh6;&laugh6;"> +<!ENTITY laugh8 "&laugh7;&laugh7;"> +<!ENTITY laugh9 "&laugh8;&laugh8;"> +<!ENTITY laugh10 "&laugh9;&laugh9;"> +<!ENTITY laugh11 "&laugh10;&laugh10;"> +<!ENTITY laugh12 "&laugh11;&laugh11;"> +<!ENTITY laugh13 "&laugh12;&laugh12;"> +<!ENTITY laugh14 "&laugh13;&laugh13;"> +<!ENTITY laugh15 "&laugh14;&laugh14;"> +<!ENTITY laugh16 "&laugh15;&laugh15;"> +<!ENTITY laugh17 "&laugh16;&laugh16;"> +<!ENTITY laugh18 "&laugh17;&laugh17;"> +<!ENTITY laugh19 "&laugh18;&laugh18;"> +<!ENTITY laugh20 "&laugh19;&laugh19;"> +<!ENTITY laugh21 "&laugh20;&laugh20;"> +<!ENTITY laugh22 "&laugh21;&laugh21;"> +<!ENTITY laugh23 "&laugh22;&laugh22;"> +<!ENTITY laugh24 "&laugh23;&laugh23;"> +<!ENTITY laugh25 "&laugh24;&laugh24;"> +<!ENTITY laugh26 "&laugh25;&laugh25;"> +<!ENTITY laugh27 "&laugh26;&laugh26;"> +<!ENTITY laugh28 "&laugh27;&laugh27;"> +<!ENTITY laugh29 "&laugh28;&laugh28;"> +<!ENTITY laugh30 "&laugh29;&laugh29;"> +]> +<billion>&laugh30;</billion> diff --git a/test/dbd.c b/test/dbd.c new file mode 100644 index 0000000..61f49ab --- /dev/null +++ b/test/dbd.c @@ -0,0 +1,407 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apu.h" +#include "apr_pools.h" +#include "apr_dbd.h" + +#include <stdio.h> + +#define TEST(msg,func) \ + printf("======== %s ========\n", msg); \ + rv = func(pool, sql, driver); \ + if (rv != 0) { \ + printf("Error in %s: rc=%d\n\n", msg, rv); \ + } \ + else { \ + printf("%s test successful\n\n", msg); \ + } \ + fflush(stdout); + +static int create_table(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int nrows; + const char *statement = "CREATE TABLE apr_dbd_test (" + "col1 varchar(40) not null," + "col2 varchar(40)," + "col3 integer)" ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + return rv; +} +static int drop_table(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int nrows; + const char *statement = "DROP TABLE apr_dbd_test" ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + return rv; +} +static int insert_rows(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int i; + int rv = 0; + int nrows; + int nerrors = 0; + const char *statement = + "INSERT into apr_dbd_test (col1) values ('foo');" + "INSERT into apr_dbd_test values ('wibble', 'other', 5);" + "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);" + "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);" + "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);" + ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (rv) { + const char* stmt[] = { + "INSERT into apr_dbd_test (col1) values ('foo');", + "INSERT into apr_dbd_test values ('wibble', 'other', 5);", + "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);", + "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);", + "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);", + NULL + }; + printf("Compound insert failed; trying statements one-by-one\n") ; + for (i=0; stmt[i] != NULL; ++i) { + statement = stmt[i]; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (rv) { + nerrors++; + } + } + if (nerrors) { + printf("%d single inserts failed too.\n", nerrors) ; + } + } + return rv; +} +static int invalid_op(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int nrows; + const char *statement = "INSERT into apr_dbd_test1 (col2) values ('foo')" ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + printf("invalid op returned %d (should be nonzero). Error msg follows\n", rv); + printf("'%s'\n", apr_dbd_error(driver, handle, rv)); + statement = "INSERT into apr_dbd_test (col1, col2) values ('bar', 'foo')" ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + printf("valid op returned %d (should be zero; error shouldn't affect subsequent ops)\n", rv); + return rv; +} +static int select_sequential(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int i = 0; + int n; + const char* entry; + const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2"; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; + rv = apr_dbd_select(driver,pool,handle,&res,statement,0); + if (rv) { + printf("Select failed: %s", apr_dbd_error(driver, handle, rv)); + return rv; + } + for (rv = apr_dbd_get_row(driver, pool, res, &row, -1); + rv == 0; + rv = apr_dbd_get_row(driver, pool, res, &row, -1)) { + printf("ROW %d: ", ++i) ; + for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { + entry = apr_dbd_get_entry(driver, row, n); + if (entry == NULL) { + printf("(null) ") ; + } + else { + printf("%s ", entry); + } + } + fputs("\n", stdout); + } + return (rv == -1) ? 0 : 1; +} +static int select_random(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int n; + const char* entry; + const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2"; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; + rv = apr_dbd_select(driver,pool,handle,&res,statement,1); + if (rv) { + printf("Select failed: %s", apr_dbd_error(driver, handle, rv)); + return rv; + } + rv = apr_dbd_get_row(driver, pool, res, &row, 5) ; + if (rv) { + printf("get_row failed: %s", apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("ROW 5: "); + for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { + entry = apr_dbd_get_entry(driver, row, n); + if (entry == NULL) { + printf("(null) ") ; + } + else { + printf("%s ", entry); + } + } + fputs("\n", stdout); + rv = apr_dbd_get_row(driver, pool, res, &row, 1) ; + if (rv) { + printf("get_row failed: %s", apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("ROW 1: "); + for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { + entry = apr_dbd_get_entry(driver, row, n); + if (entry == NULL) { + printf("(null) ") ; + } + else { + printf("%s ", entry); + } + } + fputs("\n", stdout); + rv = apr_dbd_get_row(driver, pool, res, &row, 11) ; + if (rv != -1) { + printf("Oops! get_row out of range but thinks it succeeded!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return -1; + } + rv = 0; + + return rv; +} +static int test_transactions(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int nrows; + apr_dbd_transaction_t *trans = NULL; + const char* statement; + + /* trans 1 - error out early */ + printf("Transaction 1\n"); + rv = apr_dbd_transaction_start(driver, pool, handle, &trans); + if (rv) { + printf("Start transaction failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + statement = "UPDATE apr_dbd_test SET col2 = 'failed'"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (rv) { + printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv)); + apr_dbd_transaction_end(driver, pool, trans); + return rv; + } + printf("%d rows updated\n", nrows); + + statement = "INSERT INTO apr_dbd_test1 (col3) values (3)"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (!rv) { + printf("Oops, invalid op succeeded but shouldn't!\n"); + } + statement = "INSERT INTO apr_dbd_test values ('zzz', 'aaa', 3)"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + printf("Valid insert returned %d. Should be nonzero (fail) because transaction is bad\n", rv) ; + + rv = apr_dbd_transaction_end(driver, pool, trans); + if (rv) { + printf("End transaction failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("Transaction ended (should be rollback) - viewing table\n" + "A column of \"failed\" indicates transaction failed (no rollback)\n"); + select_sequential(pool, handle, driver); + + /* trans 2 - complete successfully */ + printf("Transaction 2\n"); + rv = apr_dbd_transaction_start(driver, pool, handle, &trans); + if (rv) { + printf("Start transaction failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + statement = "UPDATE apr_dbd_test SET col2 = 'success'"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (rv) { + printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv)); + apr_dbd_transaction_end(driver, pool, trans); + return rv; + } + printf("%d rows updated\n", nrows); + statement = "INSERT INTO apr_dbd_test values ('aaa', 'zzz', 3)"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + printf("Valid insert returned %d. Should be zero (OK)\n", rv) ; + rv = apr_dbd_transaction_end(driver, pool, trans); + if (rv) { + printf("End transaction failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("Transaction ended (should be commit) - viewing table\n"); + select_sequential(pool, handle, driver); + return rv; +} +static int test_pselect(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int i, n; + const char *query = + "SELECT * FROM apr_dbd_test WHERE col3 <= %s or col1 = 'bar'" ; + const char *label = "lowvalues"; + apr_dbd_prepared_t *statement = NULL; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; + const char *entry = NULL; + + rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement); + if (rv) { + printf("Prepare statement failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + rv = apr_dbd_pvselect(driver, pool, handle, &res, statement, 0, "3", NULL); + if (rv) { + printf("Exec of prepared statement failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + i = 0; + printf("Selecting rows where col3 <= 3 and bar row where it's unset.\nShould show four rows.\n"); + for (rv = apr_dbd_get_row(driver, pool, res, &row, -1); + rv == 0; + rv = apr_dbd_get_row(driver, pool, res, &row, -1)) { + printf("ROW %d: ", ++i) ; + for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { + entry = apr_dbd_get_entry(driver, row, n); + if (entry == NULL) { + printf("(null) ") ; + } + else { + printf("%s ", entry); + } + } + fputs("\n", stdout); + } + return (rv == -1) ? 0 : 1; +} +static int test_pquery(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + const char *query = "INSERT INTO apr_dbd_test VALUES (%s, %s, %d)"; + apr_dbd_prepared_t *statement = NULL; + const char *label = "testpquery"; + int nrows; + apr_dbd_transaction_t *trans =0; + + rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement); + /* rv = apr_dbd_prepare(driver, pool, handle, query, NULL, &statement); */ + if (rv) { + printf("Prepare statement failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + apr_dbd_transaction_start(driver, pool, handle, &trans); + rv = apr_dbd_pvquery(driver, pool, handle, &nrows, statement, + "prepared", "insert", "2", NULL); + apr_dbd_transaction_end(driver, pool, trans); + if (rv) { + printf("Exec of prepared statement failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("Showing table (should now contain row \"prepared insert 2\")\n"); + select_sequential(pool, handle, driver); + return rv; +} +int main(int argc, char** argv) +{ + const char *name; + const char *params; + apr_pool_t *pool = NULL; + apr_dbd_t *sql = NULL; + const apr_dbd_driver_t *driver = NULL; + int rv; + + apr_initialize(); + apr_pool_create(&pool, NULL); + + if (argc >= 2 && argc <= 3) { + name = argv[1]; + params = ( argc == 3 ) ? argv[2] : ""; + apr_dbd_init(pool); + setbuf(stdout,NULL); + rv = apr_dbd_get_driver(pool, name, &driver); + switch (rv) { + case APR_SUCCESS: + printf("Loaded %s driver OK.\n", name); + break; + case APR_EDSOOPEN: + printf("Failed to load driver file apr_dbd_%s.so\n", name); + goto finish; + case APR_ESYMNOTFOUND: + printf("Failed to load driver apr_dbd_%s_driver.\n", name); + goto finish; + case APR_ENOTIMPL: + printf("No driver available for %s.\n", name); + goto finish; + default: /* it's a bug if none of the above happen */ + printf("Internal error loading %s.\n", name); + goto finish; + } + rv = apr_dbd_open(driver, pool, params, &sql); + switch (rv) { + case APR_SUCCESS: + printf("Opened %s[%s] OK\n", name, params); + break; + case APR_EGENERAL: + printf("Failed to open %s[%s]\n", name, params); + goto finish; + default: /* it's a bug if none of the above happen */ + printf("Internal error opening %s[%s]\n", name, params); + goto finish; + } + TEST("create table", create_table); + TEST("insert rows", insert_rows); + TEST("invalid op", invalid_op); + TEST("select random", select_random); + TEST("select sequential", select_sequential); + TEST("transactions", test_transactions); + TEST("prepared select", test_pselect); + TEST("prepared query", test_pquery); + TEST("drop table", drop_table); + apr_dbd_close(driver, sql); + } + else { + fprintf(stderr, "Usage: %s driver-name [params]\n", argv[0]); + } +finish: + apr_pool_destroy(pool); + apr_terminate(); + return 0; +} diff --git a/test/nw_misc.c b/test/nw_misc.c new file mode 100644 index 0000000..b45f951 --- /dev/null +++ b/test/nw_misc.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <stdlib.h> +#include <screen.h> +/* +#include "testutil.h" +*/ + +/* function to keep the screen open if not launched from bash */ +void _NonAppStop( void ) +{ + if (getenv("_IN_NETWARE_BASH_") == NULL) { + printf("\r\n<Press any key to close screen> "); + getcharacter(); + } +} + +/* +static void test_not_impl(CuTest *tc) +{ + CuNotImpl(tc, "Test not implemented on this platform yet"); +} +*/ + diff --git a/test/test_apu.h b/test/test_apu.h new file mode 100644 index 0000000..642edec --- /dev/null +++ b/test/test_apu.h @@ -0,0 +1,100 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Some simple functions to make the test apps easier to write and + * a bit more consistent... + * this is a >copy< of apr_test.h + */ + +/* Things to bear in mind when using these... + * + * If you include '\t' within the string passed in it won't be included + * in the spacing, so use spaces instead :) + * + */ + +#ifndef APU_TEST_INCLUDES +#define APU_TEST_INCLUDES + +#include "apr_strings.h" +#include "apr_time.h" + +#define TEST_EQ(str, func, value, good, bad) \ + printf("%-60s", str); \ + { \ + apr_status_t rv; \ + if ((rv = func) == value){ \ + char errmsg[200]; \ + printf("%s\n", bad); \ + fprintf(stderr, "Error was %d : %s\n", rv, \ + apr_strerror(rv, (char*)&errmsg, 200)); \ + exit(-1); \ + } \ + printf("%s\n", good); \ + } + +#define TEST_NEQ(str, func, value, good, bad) \ + printf("%-60s", str); \ + { \ + apr_status_t rv; \ + if ((rv = func) != value){ \ + char errmsg[200]; \ + printf("%s\n", bad); \ + fprintf(stderr, "Error was %d : %s\n", rv, \ + apr_strerror(rv, (char*)&errmsg, 200)); \ + exit(-1); \ + } \ + printf("%s\n", good); \ + } + +#define TEST_STATUS(str, func, testmacro, good, bad) \ + printf("%-60s", str); \ + { \ + apr_status_t rv = func; \ + if (!testmacro(rv)) { \ + char errmsg[200]; \ + printf("%s\n", bad); \ + fprintf(stderr, "Error was %d : %s\n", rv, \ + apr_strerror(rv, (char*)&errmsg, 200)); \ + exit(-1); \ + } \ + printf("%s\n", good); \ + } + +#define STD_TEST_NEQ(str, func) \ + TEST_NEQ(str, func, APR_SUCCESS, "OK", "Failed"); + +#define PRINT_ERROR(rv) \ + { \ + char errmsg[200]; \ + fprintf(stderr, "Error was %d : %s\n", rv, \ + apr_strerror(rv, (char*)&errmsg, 200)); \ + exit(-1); \ + } + +#define MSG_AND_EXIT(msg) \ + printf("%s\n", msg); \ + exit (-1); + +#define TIME_FUNCTION(time, function) \ + { \ + apr_time_t tt = apr_time_now(); \ + function; \ + time = apr_time_now() - tt; \ + } + + +#endif /* APU_TEST_INCLUDES */ diff --git a/test/testall.dsw b/test/testall.dsw new file mode 100644 index 0000000..7fde202 --- /dev/null +++ b/test/testall.dsw @@ -0,0 +1,513 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "apr"="..\..\apr\apr.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "aprapp"="..\..\apr\build\aprapp.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name preaprapp + End Project Dependency +}}} + + +############################################################################### + +Project: "apr_dbd_mysql"="..\dbd\apr_dbd_mysql.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency +}}} + +############################################################################### + +Project: "apr_dbd_odbc"="..\dbd\apr_dbd_odbc.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency +}}} + +############################################################################### + +Project: "apr_dbd_oracle"="..\dbd\apr_dbd_oracle.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency +}}} + +############################################################################### + +Project: "apr_dbd_pgsql"="..\dbd\apr_dbd_pgsql.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency +}}} + +############################################################################### + +Project: "apr_dbd_sqlite2"="..\dbd\apr_dbd_sqlite2.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency +}}} + +############################################################################### + +Project: "apr_dbd_sqlite3"="..\dbd\apr_dbd_sqlite3.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency +}}} + +############################################################################### + +Project: "apr_dbm_db"="..\dbm\apr_dbm_db.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency +}}} + +############################################################################### + +Project: "apr_dbm_gdbm"="..\dbm\apr_dbm_gdbm.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency +}}} + +############################################################################### + +Project: "apr_ldap"="..\ldap\apr_ldap.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency +}}} + +############################################################################### + +Project: "apriconv"="..\..\apr-iconv\apriconv.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name preapriconv + End Project Dependency +}}} + +############################################################################### + +Project: "aprutil"="..\aprutil.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name preaprutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name apriconv + End Project Dependency + Begin Project Dependency + Project_Dep_Name xml + End Project Dependency +}}} + +############################################################################### + +Project: "libapr"="..\..\apr\libapr.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libaprapp"="..\..\apr\build\libaprapp.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name prelibaprapp + End Project Dependency +}}} + +############################################################################### + +Project: "libapriconv"="..\..\apr-iconv\libapriconv.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency +}}} + +############################################################################### + +Project: "libapriconv_ccs_modules"="..\..\apr-iconv\ccs\libapriconv_ccs_modules.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapriconv + End Project Dependency +}}} + +############################################################################### + +Project: "libapriconv_ces_modules"="..\..\apr-iconv\ces\libapriconv_ces_modules.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapriconv + End Project Dependency +}}} + +############################################################################### + +Project: "libaprutil"="..\libaprutil.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprapp + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapriconv + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapriconv_ccs_modules + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapriconv_ces_modules + End Project Dependency + Begin Project Dependency + Project_Dep_Name xml + End Project Dependency +}}} + +############################################################################### + +Project: "preaprapp"="..\..\apr\build\preaprapp.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name apr + End Project Dependency +}}} + +############################################################################### + +Project: "preapriconv"="..\..\apr-iconv\build\preapriconv.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name apr + End Project Dependency +}}} + +############################################################################### + +Project: "preaprutil"="..\build\preaprutil.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name apr + End Project Dependency + Begin Project Dependency + Project_Dep_Name aprapp + End Project Dependency +}}} + +############################################################################### + +Project: "prelibaprapp"="..\..\apr\build\prelibaprapp.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency +}}} + +############################################################################### + +Project: "testdll"="..\..\apr\test\testdll.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name apr_ldap + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprapp + End Project Dependency +}}} + +############################################################################### + +Project: "testlib"="..\..\apr\test\testlib.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name apr + End Project Dependency + Begin Project Dependency + Project_Dep_Name aprapp + End Project Dependency +}}} + +############################################################################### + +Project: "testutildll"=".\testutildll.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprapp + End Project Dependency + Begin Project Dependency + Project_Dep_Name libapriconv + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprutil + End Project Dependency +}}} + +############################################################################### + +Project: "testutillib"=".\testutillib.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name apr + End Project Dependency + Begin Project Dependency + Project_Dep_Name aprapp + End Project Dependency + Begin Project Dependency + Project_Dep_Name apriconv + End Project Dependency + Begin Project Dependency + Project_Dep_Name aprutil + End Project Dependency +}}} + +############################################################################### + +Project: "xml"="..\xml\expat\lib\xml.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/test/testbuckets.c b/test/testbuckets.c new file mode 100644 index 0000000..3d0d46d --- /dev/null +++ b/test/testbuckets.c @@ -0,0 +1,535 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "abts.h" +#include "testutil.h" +#include "apr_buckets.h" +#include "apr_strings.h" + +static void test_create(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba; + apr_bucket_brigade *bb; + + ba = apr_bucket_alloc_create(p); + bb = apr_brigade_create(p, ba); + + ABTS_ASSERT(tc, "new brigade not NULL", bb != NULL); + ABTS_ASSERT(tc, "new brigade is empty", APR_BRIGADE_EMPTY(bb)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static void test_simple(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba; + apr_bucket_brigade *bb; + apr_bucket *fb, *tb; + + ba = apr_bucket_alloc_create(p); + bb = apr_brigade_create(p, ba); + + fb = APR_BRIGADE_FIRST(bb); + ABTS_ASSERT(tc, "first bucket of empty brigade is sentinel", + fb == APR_BRIGADE_SENTINEL(bb)); + + fb = apr_bucket_flush_create(ba); + APR_BRIGADE_INSERT_HEAD(bb, fb); + + ABTS_ASSERT(tc, "first bucket of brigade is flush", + APR_BRIGADE_FIRST(bb) == fb); + + ABTS_ASSERT(tc, "bucket after flush is sentinel", + APR_BUCKET_NEXT(fb) == APR_BRIGADE_SENTINEL(bb)); + + tb = apr_bucket_transient_create("aaa", 3, ba); + APR_BUCKET_INSERT_BEFORE(fb, tb); + + ABTS_ASSERT(tc, "bucket before flush now transient", + APR_BUCKET_PREV(fb) == tb); + ABTS_ASSERT(tc, "bucket after transient is flush", + APR_BUCKET_NEXT(tb) == fb); + ABTS_ASSERT(tc, "bucket before transient is sentinel", + APR_BUCKET_PREV(tb) == APR_BRIGADE_SENTINEL(bb)); + + apr_brigade_cleanup(bb); + + ABTS_ASSERT(tc, "cleaned up brigade was empty", APR_BRIGADE_EMPTY(bb)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static apr_bucket_brigade *make_simple_brigade(apr_bucket_alloc_t *ba, + const char *first, + const char *second) +{ + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_bucket *e; + + e = apr_bucket_transient_create(first, strlen(first), ba); + APR_BRIGADE_INSERT_TAIL(bb, e); + + e = apr_bucket_transient_create(second, strlen(second), ba); + APR_BRIGADE_INSERT_TAIL(bb, e); + + return bb; +} + +/* tests that 'bb' flattens to string 'expect'. */ +static void flatten_match(abts_case *tc, const char *ctx, + apr_bucket_brigade *bb, + const char *expect) +{ + apr_size_t elen = strlen(expect); + char *buf = malloc(elen); + apr_size_t len = elen; + char msg[200]; + + sprintf(msg, "%s: flatten brigade", ctx); + apr_assert_success(tc, msg, apr_brigade_flatten(bb, buf, &len)); + sprintf(msg, "%s: length match (%ld not %ld)", ctx, + (long)len, (long)elen); + ABTS_ASSERT(tc, msg, len == elen); + sprintf(msg, "%s: result match", msg); + ABTS_STR_NEQUAL(tc, expect, buf, len); + free(buf); +} + +static void test_flatten(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb; + + bb = make_simple_brigade(ba, "hello, ", "world"); + + flatten_match(tc, "flatten brigade", bb, "hello, world"); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static int count_buckets(apr_bucket_brigade *bb) +{ + apr_bucket *e; + int count = 0; + + for (e = APR_BRIGADE_FIRST(bb); + e != APR_BRIGADE_SENTINEL(bb); + e = APR_BUCKET_NEXT(e)) { + count++; + } + + return count; +} + +static void test_split(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb, *bb2; + apr_bucket *e; + + bb = make_simple_brigade(ba, "hello, ", "world"); + + /* split at the "world" bucket */ + e = APR_BRIGADE_LAST(bb); + bb2 = apr_brigade_split(bb, e); + + ABTS_ASSERT(tc, "split brigade contains one bucket", + count_buckets(bb2) == 1); + ABTS_ASSERT(tc, "original brigade contains one bucket", + count_buckets(bb) == 1); + + flatten_match(tc, "match original brigade", bb, "hello, "); + flatten_match(tc, "match split brigade", bb2, "world"); + + apr_brigade_destroy(bb2); + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +#define COUNT 3000 +#define THESTR "hello" + +static void test_bwrite(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_off_t length; + int n; + + for (n = 0; n < COUNT; n++) { + apr_assert_success(tc, "brigade_write", + apr_brigade_write(bb, NULL, NULL, + THESTR, sizeof THESTR)); + } + + apr_assert_success(tc, "determine brigade length", + apr_brigade_length(bb, 1, &length)); + + ABTS_ASSERT(tc, "brigade has correct length", + length == (COUNT * sizeof THESTR)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static void test_splitline(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bin, *bout; + + bin = make_simple_brigade(ba, "blah blah blah-", + "end of line.\nfoo foo foo"); + bout = apr_brigade_create(p, ba); + + apr_assert_success(tc, "split line", + apr_brigade_split_line(bout, bin, + APR_BLOCK_READ, 100)); + + flatten_match(tc, "split line", bout, "blah blah blah-end of line.\n"); + flatten_match(tc, "remainder", bin, "foo foo foo"); + + apr_brigade_destroy(bout); + apr_brigade_destroy(bin); + apr_bucket_alloc_destroy(ba); +} + +/* Test that bucket E has content EDATA of length ELEN. */ +static void test_bucket_content(abts_case *tc, + apr_bucket *e, + const char *edata, + apr_size_t elen) +{ + const char *adata; + apr_size_t alen; + + apr_assert_success(tc, "read from bucket", + apr_bucket_read(e, &adata, &alen, + APR_BLOCK_READ)); + + ABTS_ASSERT(tc, "read expected length", alen == elen); + ABTS_STR_NEQUAL(tc, edata, adata, elen); +} + +static void test_splits(abts_case *tc, void *ctx) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb; + apr_bucket *e; + char *str = "alphabeta"; + int n; + + bb = apr_brigade_create(p, ba); + + APR_BRIGADE_INSERT_TAIL(bb, + apr_bucket_immortal_create(str, 9, ba)); + APR_BRIGADE_INSERT_TAIL(bb, + apr_bucket_transient_create(str, 9, ba)); + APR_BRIGADE_INSERT_TAIL(bb, + apr_bucket_heap_create(strdup(str), 9, free, ba)); + APR_BRIGADE_INSERT_TAIL(bb, + apr_bucket_pool_create(apr_pstrdup(p, str), 9, p, + ba)); + + ABTS_ASSERT(tc, "four buckets inserted", count_buckets(bb) == 4); + + /* now split each of the buckets after byte 5 */ + for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { + ABTS_ASSERT(tc, "reached end of brigade", + e != APR_BRIGADE_SENTINEL(bb)); + ABTS_ASSERT(tc, "split bucket OK", + apr_bucket_split(e, 5) == APR_SUCCESS); + e = APR_BUCKET_NEXT(e); + ABTS_ASSERT(tc, "split OK", e != APR_BRIGADE_SENTINEL(bb)); + e = APR_BUCKET_NEXT(e); + } + + ABTS_ASSERT(tc, "four buckets split into eight", + count_buckets(bb) == 8); + + for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { + const char *data; + apr_size_t len; + + apr_assert_success(tc, "read alpha from bucket", + apr_bucket_read(e, &data, &len, APR_BLOCK_READ)); + ABTS_ASSERT(tc, "read 5 bytes", len == 5); + ABTS_STR_NEQUAL(tc, "alpha", data, 5); + + e = APR_BUCKET_NEXT(e); + + apr_assert_success(tc, "read beta from bucket", + apr_bucket_read(e, &data, &len, APR_BLOCK_READ)); + ABTS_ASSERT(tc, "read 4 bytes", len == 4); + ABTS_STR_NEQUAL(tc, "beta", data, 5); + + e = APR_BUCKET_NEXT(e); + } + + /* now delete the "alpha" buckets */ + for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { + apr_bucket *f; + + ABTS_ASSERT(tc, "reached end of brigade", + e != APR_BRIGADE_SENTINEL(bb)); + f = APR_BUCKET_NEXT(e); + apr_bucket_delete(e); + e = APR_BUCKET_NEXT(f); + } + + ABTS_ASSERT(tc, "eight buckets reduced to four", + count_buckets(bb) == 4); + + flatten_match(tc, "flatten beta brigade", bb, + "beta" "beta" "beta" "beta"); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +#define TIF_FNAME "testfile.txt" + +static void test_insertfile(abts_case *tc, void *ctx) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb; + const apr_off_t bignum = (APR_INT64_C(2) << 32) + 424242; + apr_off_t count; + apr_file_t *f; + apr_bucket *e; + + ABTS_ASSERT(tc, "open test file", + apr_file_open(&f, TIF_FNAME, + APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE + | APR_FOPEN_CREATE | APR_FOPEN_SPARSE, + APR_OS_DEFAULT, p) == APR_SUCCESS); + + if (apr_file_trunc(f, bignum)) { + apr_file_close(f); + apr_file_remove(TIF_FNAME, p); + ABTS_NOT_IMPL(tc, "Skipped: could not create large file"); + return; + } + + bb = apr_brigade_create(p, ba); + + e = apr_brigade_insert_file(bb, f, 0, bignum, p); + + ABTS_ASSERT(tc, "inserted file was not at end of brigade", + e == APR_BRIGADE_LAST(bb)); + + /* check that the total size of inserted buckets is equal to the + * total size of the file. */ + count = 0; + + for (e = APR_BRIGADE_FIRST(bb); + e != APR_BRIGADE_SENTINEL(bb); + e = APR_BUCKET_NEXT(e)) { + ABTS_ASSERT(tc, "bucket size sane", e->length != (apr_size_t)-1); + count += e->length; + } + + ABTS_ASSERT(tc, "total size of buckets incorrect", count == bignum); + + apr_brigade_destroy(bb); + + /* Truncate the file to zero size before close() so that we don't + * actually write out the large file if we are on a non-sparse file + * system - like Mac OS X's HFS. Otherwise, pity the poor user who + * has to wait for the 8GB file to be written to disk. + */ + apr_file_trunc(f, 0); + + apr_file_close(f); + apr_bucket_alloc_destroy(ba); + apr_file_remove(TIF_FNAME, p); +} + +/* Make a test file named FNAME, and write CONTENTS to it. */ +static apr_file_t *make_test_file(abts_case *tc, const char *fname, + const char *contents) +{ + apr_file_t *f; + + ABTS_ASSERT(tc, "create test file", + apr_file_open(&f, fname, + APR_FOPEN_READ|APR_FOPEN_WRITE|APR_FOPEN_TRUNCATE|APR_FOPEN_CREATE, + APR_OS_DEFAULT, p) == APR_SUCCESS); + + ABTS_ASSERT(tc, "write test file contents", + apr_file_puts(contents, f) == APR_SUCCESS); + + return f; +} + +static void test_manyfile(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_file_t *f; + + f = make_test_file(tc, "manyfile.bin", + "world" "hello" "brave" " ,\n"); + + apr_brigade_insert_file(bb, f, 5, 5, p); + apr_brigade_insert_file(bb, f, 16, 1, p); + apr_brigade_insert_file(bb, f, 15, 1, p); + apr_brigade_insert_file(bb, f, 10, 5, p); + apr_brigade_insert_file(bb, f, 15, 1, p); + apr_brigade_insert_file(bb, f, 0, 5, p); + apr_brigade_insert_file(bb, f, 17, 1, p); + + /* can you tell what it is yet? */ + flatten_match(tc, "file seek test", bb, + "hello, brave world\n"); + + apr_file_close(f); + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +/* Regression test for PR 34708, where a file bucket will keep + * duplicating itself on being read() when EOF is reached + * prematurely. */ +static void test_truncfile(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_file_t *f = make_test_file(tc, "testfile.txt", "hello"); + apr_bucket *e; + const char *buf; + apr_size_t len; + + apr_brigade_insert_file(bb, f, 0, 5, p); + + apr_file_trunc(f, 0); + + e = APR_BRIGADE_FIRST(bb); + + ABTS_ASSERT(tc, "single bucket in brigade", + APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb)); + + apr_bucket_file_enable_mmap(e, 0); + + ABTS_ASSERT(tc, "read gave APR_EOF", + apr_bucket_read(e, &buf, &len, APR_BLOCK_READ) == APR_EOF); + + ABTS_ASSERT(tc, "read length 0", len == 0); + + ABTS_ASSERT(tc, "still a single bucket in brigade", + APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb)); + + apr_file_close(f); + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static const char hello[] = "hello, world"; + +static void test_partition(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_bucket *e; + + e = apr_bucket_immortal_create(hello, strlen(hello), ba); + APR_BRIGADE_INSERT_HEAD(bb, e); + + apr_assert_success(tc, "partition brigade", + apr_brigade_partition(bb, 5, &e)); + + test_bucket_content(tc, APR_BRIGADE_FIRST(bb), + "hello", 5); + + test_bucket_content(tc, APR_BRIGADE_LAST(bb), + ", world", 7); + + ABTS_ASSERT(tc, "partition returns APR_INCOMPLETE", + apr_brigade_partition(bb, 8192, &e)); + + ABTS_ASSERT(tc, "APR_INCOMPLETE partition returned sentinel", + e == APR_BRIGADE_SENTINEL(bb)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static void test_write_split(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb1 = apr_brigade_create(p, ba); + apr_bucket_brigade *bb2; + apr_bucket *e; + + e = apr_bucket_heap_create(hello, strlen(hello), NULL, ba); + APR_BRIGADE_INSERT_HEAD(bb1, e); + apr_bucket_split(e, strlen("hello, ")); + bb2 = apr_brigade_split(bb1, APR_BRIGADE_LAST(bb1)); + apr_brigade_write(bb1, NULL, NULL, "foo", strlen("foo")); + test_bucket_content(tc, APR_BRIGADE_FIRST(bb2), "world", 5); + + apr_brigade_destroy(bb1); + apr_brigade_destroy(bb2); + apr_bucket_alloc_destroy(ba); +} + +static void test_write_putstrs(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_bucket *e; + char buf[30]; + apr_size_t len = sizeof(buf); + const char *expect = "123456789abcdefghij"; + + e = apr_bucket_heap_create("1", 1, NULL, ba); + APR_BRIGADE_INSERT_HEAD(bb, e); + + apr_brigade_putstrs(bb, NULL, NULL, "2", "34", "567", "8", "9a", "bcd", + "e", "f", "gh", "i", NULL); + apr_brigade_putstrs(bb, NULL, NULL, "j", NULL); + apr_assert_success(tc, "apr_brigade_flatten", + apr_brigade_flatten(bb, buf, &len)); + ABTS_STR_NEQUAL(tc, expect, buf, strlen(expect)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +abts_suite *testbuckets(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_create, NULL); + abts_run_test(suite, test_simple, NULL); + abts_run_test(suite, test_flatten, NULL); + abts_run_test(suite, test_split, NULL); + abts_run_test(suite, test_bwrite, NULL); + abts_run_test(suite, test_splitline, NULL); + abts_run_test(suite, test_splits, NULL); + abts_run_test(suite, test_insertfile, NULL); + abts_run_test(suite, test_manyfile, NULL); + abts_run_test(suite, test_truncfile, NULL); + abts_run_test(suite, test_partition, NULL); + abts_run_test(suite, test_write_split, NULL); + abts_run_test(suite, test_write_putstrs, NULL); + + return suite; +} + + diff --git a/test/testcrypto.c b/test/testcrypto.c new file mode 100644 index 0000000..865cffc --- /dev/null +++ b/test/testcrypto.c @@ -0,0 +1,1545 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testutil.h" +#include "apr.h" +#include "apu.h" +#include "apu_errno.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr_crypto.h" +#include "apr_strings.h" + +#if APU_HAVE_CRYPTO + +#define TEST_STRING "12345" +#define ALIGNED_STRING "123456789012345" + +static const apr_crypto_driver_t *get_driver(abts_case *tc, apr_pool_t *pool, + const char *name, const char *params) +{ + + const apr_crypto_driver_t *driver = NULL; + const apu_err_t *result = NULL; + apr_status_t rv; + + rv = apr_crypto_init(pool); + ABTS_ASSERT(tc, "failed to init apr_crypto", rv == APR_SUCCESS); + + rv = apr_crypto_get_driver(&driver, name, params, &result, pool); + if (APR_ENOTIMPL == rv) { + ABTS_NOT_IMPL(tc, + apr_psprintf(pool, "Crypto driver '%s' not implemented", (char *)name)); + return NULL; + } + if (APR_EDSOOPEN == rv) { + ABTS_NOT_IMPL(tc, + apr_psprintf(pool, "Crypto driver '%s' DSO could not be opened", (char *)name)); + return NULL; + } + if (APR_SUCCESS != rv && result) { + char err[1024]; + apr_strerror(rv, err, sizeof(err) - 1); + fprintf(stderr, "get_driver error %d: %s: '%s' native error %d: %s (%s),", + rv, err, name, result->rc, result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, apr_psprintf(pool, "failed to apr_crypto_get_driver for '%s' with %d", + name, rv), rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_get_driver returned NULL", driver != NULL); + if (!driver || rv) { + return NULL; + } + + return driver; + +} + +static const apr_crypto_driver_t *get_nss_driver(abts_case *tc, + apr_pool_t *pool) +{ + + /* initialise NSS */ + return get_driver(tc, pool, "nss", ""); + +} + +static const apr_crypto_driver_t *get_openssl_driver(abts_case *tc, + apr_pool_t *pool) +{ + + return get_driver(tc, pool, "openssl", NULL); + +} + +static const apr_crypto_driver_t *get_commoncrypto_driver(abts_case *tc, + apr_pool_t *pool) +{ + + return get_driver(tc, pool, "commoncrypto", NULL); + +} + +static apr_crypto_t *make(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver) +{ + + apr_crypto_t *f = NULL; + + if (!driver) { + return NULL; + } + + /* get the context */ + apr_crypto_make(&f, driver, "engine=openssl", pool); + ABTS_ASSERT(tc, "apr_crypto_make returned NULL", f != NULL); + + return f; + +} + +static const apr_crypto_key_t *keysecret(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode, + int doPad, apr_size_t secretLen, const char *description) +{ + apr_crypto_key_t *key = NULL; + const apu_err_t *result = NULL; + apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t)); + apr_status_t rv; + + if (!f) { + return NULL; + } + + rec->ktype = APR_CRYPTO_KTYPE_SECRET; + rec->type = type; + rec->mode = mode; + rec->pad = doPad; + rec->k.secret.secret = apr_pcalloc(pool, secretLen); + rec->k.secret.secretLen = secretLen; + + /* init the passphrase */ + rv = apr_crypto_key(&key, rec, f, pool); + if (APR_ENOCIPHER == rv) { + apr_crypto_error(&result, f); + ABTS_NOT_IMPL(tc, + apr_psprintf(pool, "skipped: %s %s key return APR_ENOCIPHER: error %d: %s (%s)\n", description, apr_crypto_driver_name(driver), result->rc, result->reason ? result->reason : "", result->msg ? result->msg : "")); + return NULL; + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "key: %s %s apr error %d / native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING", + rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE", + rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL); + } + if (rv) { + return NULL; + } + return key; + +} + +static const apr_crypto_key_t *passphrase(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode, + int doPad, const char *description) +{ + + apr_crypto_key_t *key = NULL; + const apu_err_t *result = NULL; + const char *pass = "secret"; + const char *salt = "salt"; + apr_status_t rv; + + if (!f) { + return NULL; + } + + /* init the passphrase */ + rv = apr_crypto_passphrase(&key, NULL, pass, strlen(pass), + (unsigned char *) salt, strlen(salt), type, mode, doPad, 4096, f, + pool); + if (APR_ENOCIPHER == rv) { + apr_crypto_error(&result, f); + ABTS_NOT_IMPL(tc, apr_psprintf(pool, + "skipped: %s %s passphrase return APR_ENOCIPHER: error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), result->rc, + result->reason ? result->reason : "", result->msg ? result->msg : "")); + return NULL; + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "passphrase: %s %s apr error %d / native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_passphrase returned APR_ENOKEY", rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_passphrase returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_passphrase returned APR_EKEYTYPE", rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "failed to apr_crypto_passphrase", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_passphrase returned NULL context", key != NULL); + } + if (rv) { + return NULL; + } + return key; + +} + +static const apr_crypto_key_t *keypassphrase(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode, + int doPad, const char *description) +{ + + apr_crypto_key_t *key = NULL; + const apu_err_t *result = NULL; + const char *pass = "secret"; + const char *salt = "salt"; + apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t)); + apr_status_t rv; + + if (!f) { + return NULL; + } + + rec->ktype = APR_CRYPTO_KTYPE_PASSPHRASE; + rec->type = type; + rec->mode = mode; + rec->pad = doPad; + rec->k.passphrase.pass = pass; + rec->k.passphrase.passLen = strlen(pass); + rec->k.passphrase.salt = (unsigned char *)salt; + rec->k.passphrase.saltLen = strlen(salt); + rec->k.passphrase.iterations = 4096; + + /* init the passphrase */ + rv = apr_crypto_key(&key, rec, f, pool); + if (APR_ENOCIPHER == rv) { + apr_crypto_error(&result, f); + ABTS_NOT_IMPL(tc, apr_psprintf(pool, + "skipped: %s %s key passphrase return APR_ENOCIPHER: error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), result->rc, + result->reason ? result->reason : "", result->msg ? result->msg : "")); + return NULL; + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "key passphrase: %s %s apr error %d / native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE", rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL); + } + if (rv) { + return NULL; + } + return key; + +} + +static unsigned char *encrypt_block(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + const apr_crypto_key_t *key, const unsigned char *in, + const apr_size_t inlen, unsigned char **cipherText, + apr_size_t *cipherTextLen, const unsigned char **iv, + apr_size_t *blockSize, const char *description) +{ + + apr_crypto_block_t *block = NULL; + const apu_err_t *result = NULL; + apr_size_t len = 0; + apr_status_t rv; + + if (!driver || !f || !key || !in) { + return NULL; + } + + /* init the encryption */ + rv = apr_crypto_block_encrypt_init(&block, iv, key, blockSize, pool); + if (APR_ENOTIMPL == rv) { + ABTS_NOT_IMPL(tc, "apr_crypto_block_encrypt_init returned APR_ENOTIMPL"); + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, + "encrypt_init: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_ENOKEY", + rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_ENOIV", + rv != APR_ENOIV); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYTYPE", + rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYLENGTH", + rv != APR_EKEYLENGTH); + ABTS_ASSERT(tc, + "apr_crypto_block_encrypt_init returned APR_ENOTENOUGHENTROPY", + rv != APR_ENOTENOUGHENTROPY); + ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt_init", + rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned NULL context", + block != NULL); + } + if (!block || rv) { + return NULL; + } + + /* encrypt the block */ + rv = apr_crypto_block_encrypt(cipherText, cipherTextLen, in, inlen, block); + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "encrypt: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_encrypt returned APR_ECRYPT", rv != APR_ECRYPT); + ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt failed to allocate buffer", *cipherText != NULL); + if (rv) { + return NULL; + } + + /* finalise the encryption */ + rv = apr_crypto_block_encrypt_finish(*cipherText + *cipherTextLen, &len, + block); + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, + "encrypt_finish: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_ECRYPT", rv != APR_ECRYPT); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_ENOSPACE", rv != APR_ENOSPACE); + ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt_finish", rv == APR_SUCCESS); + *cipherTextLen += len; + apr_crypto_block_cleanup(block); + if (rv) { + return NULL; + } + + return *cipherText; + +} + +static unsigned char *decrypt_block(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + const apr_crypto_key_t *key, unsigned char *cipherText, + apr_size_t cipherTextLen, unsigned char **plainText, + apr_size_t *plainTextLen, const unsigned char *iv, + apr_size_t *blockSize, const char *description) +{ + + apr_crypto_block_t *block = NULL; + const apu_err_t *result = NULL; + apr_size_t len = 0; + apr_status_t rv; + + if (!driver || !f || !key || !cipherText) { + return NULL; + } + + /* init the decryption */ + rv = apr_crypto_block_decrypt_init(&block, blockSize, iv, key, pool); + if (APR_ENOTIMPL == rv) { + ABTS_NOT_IMPL(tc, "apr_crypto_block_decrypt_init returned APR_ENOTIMPL"); + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, + "decrypt_init: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_ENOKEY", rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_ENOIV", rv != APR_ENOIV); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_EKEYTYPE", rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH); + ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt_init", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned NULL context", block != NULL); + } + if (!block || rv) { + return NULL; + } + + /* decrypt the block */ + rv = apr_crypto_block_decrypt(plainText, plainTextLen, cipherText, + cipherTextLen, block); + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "decrypt: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_decrypt returned APR_ECRYPT", rv != APR_ECRYPT); + ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt failed to allocate buffer", *plainText != NULL); + if (rv) { + return NULL; + } + + /* finalise the decryption */ + rv = apr_crypto_block_decrypt_finish(*plainText + *plainTextLen, &len, + block); + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, + "decrypt_finish: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_ECRYPT", rv != APR_ECRYPT); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_ENOSPACE", rv != APR_ENOSPACE); + ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt_finish", rv == APR_SUCCESS); + if (rv) { + return NULL; + } + + *plainTextLen += len; + apr_crypto_block_cleanup(block); + + return *plainText; + +} + +/** + * Interoperability test. + * + * data must point at an array of two driver structures. Data will be encrypted + * with the first driver, and decrypted with the second. + * + * If the two drivers interoperate, the test passes. + */ +static void crypto_block_cross(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t **drivers, + const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, int doPad, + const unsigned char *in, apr_size_t inlen, apr_size_t secretLen, + const char *description) +{ + const apr_crypto_driver_t *driver1 = drivers[0]; + const apr_crypto_driver_t *driver2 = drivers[1]; + apr_crypto_t *f1 = NULL; + apr_crypto_t *f2 = NULL; + const apr_crypto_key_t *key1 = NULL; + const apr_crypto_key_t *key2 = NULL; + const apr_crypto_key_t *key3 = NULL; + const apr_crypto_key_t *key4 = NULL; + const apr_crypto_key_t *key5 = NULL; + const apr_crypto_key_t *key6 = NULL; + + unsigned char *cipherText = NULL; + apr_size_t cipherTextLen = 0; + unsigned char *plainText = NULL; + apr_size_t plainTextLen = 0; + const unsigned char *iv = NULL; + apr_size_t blockSize = 0; + + f1 = make(tc, pool, driver1); + f2 = make(tc, pool, driver2); + key1 = passphrase(tc, pool, driver1, f1, type, mode, doPad, description); + key2 = passphrase(tc, pool, driver2, f2, type, mode, doPad, description); + + cipherText = encrypt_block(tc, pool, driver1, f1, key1, in, inlen, + &cipherText, &cipherTextLen, &iv, &blockSize, description); + plainText = decrypt_block(tc, pool, driver2, f2, key2, cipherText, + cipherTextLen, &plainText, &plainTextLen, iv, &blockSize, + description); + + if (cipherText && plainText) { + if (memcmp(in, plainText, inlen)) { + fprintf(stderr, "passphrase cross mismatch: %s %s/%s\n", description, + apr_crypto_driver_name(driver1), apr_crypto_driver_name( + driver2)); + } + ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText); + } + + key3 = keysecret(tc, pool, driver1, f1, type, mode, doPad, secretLen, description); + key4 = keysecret(tc, pool, driver2, f2, type, mode, doPad, secretLen, description); + + iv = NULL; + blockSize = 0; + cipherText = NULL; + plainText = NULL; + cipherText = encrypt_block(tc, pool, driver1, f1, key3, in, inlen, + &cipherText, &cipherTextLen, &iv, &blockSize, description); + plainText = decrypt_block(tc, pool, driver2, f2, key4, cipherText, + cipherTextLen, &plainText, &plainTextLen, iv, &blockSize, + description); + + if (cipherText && plainText) { + if (memcmp(in, plainText, inlen)) { + fprintf(stderr, "key secret cross mismatch: %s %s/%s\n", description, + apr_crypto_driver_name(driver1), apr_crypto_driver_name( + driver2)); + } + ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText); + } + + key5 = keypassphrase(tc, pool, driver1, f1, type, mode, doPad, description); + key6 = keypassphrase(tc, pool, driver2, f2, type, mode, doPad, description); + + iv = NULL; + blockSize = 0; + cipherText = NULL; + plainText = NULL; + cipherText = encrypt_block(tc, pool, driver1, f1, key5, in, inlen, + &cipherText, &cipherTextLen, &iv, &blockSize, description); + plainText = decrypt_block(tc, pool, driver2, f2, key6, cipherText, + cipherTextLen, &plainText, &plainTextLen, iv, &blockSize, + description); + + if (cipherText && plainText) { + if (memcmp(in, plainText, inlen)) { + fprintf(stderr, "key passphrase cross mismatch: %s %s/%s\n", description, + apr_crypto_driver_name(driver1), apr_crypto_driver_name( + driver2)); + } + ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText); + } + +} + +/** + * Test initialisation. + */ +static void test_crypto_init(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + apr_status_t rv; + + apr_pool_create(&pool, NULL); + + rv = apr_crypto_init(pool); + ABTS_ASSERT(tc, "failed to init apr_crypto", rv == APR_SUCCESS); + + apr_pool_destroy(pool); + +} + +/** + * Simple test of OpenSSL key. + */ +static void test_crypto_key_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f = NULL; + + apr_pool_create(&pool, NULL); + driver = get_openssl_driver(tc, pool); + + f = make(tc, pool, driver); + keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32, + "KEY_AES_256/MODE_CBC"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of NSS key. + */ +static void test_crypto_key_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f = NULL; + + apr_pool_create(&pool, NULL); + driver = get_nss_driver(tc, pool); + + f = make(tc, pool, driver); + keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32, + "KEY_AES_256/MODE_CBC"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of CommonCrypto key. + */ +static void test_crypto_key_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f = NULL; + + apr_pool_create(&pool, NULL); + driver = get_commoncrypto_driver(tc, pool); + + f = make(tc, pool, driver); + keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32, + "KEY_AES_256/MODE_CBC"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of OpenSSL block crypt. + */ +static void test_crypto_block_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, + in, inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of NSS block crypt. + */ +static void test_crypto_block_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_nss_driver(tc, pool); + drivers[1] = get_nss_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, "KEY_3DES_192/MODE_ECB"); */ + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of Common Crypto block crypt. + */ +static void test_crypto_block_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, + in, inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Encrypt NSS, decrypt OpenSSL. + */ +static void test_crypto_block_nss_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_nss_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt NSS. + */ +static void test_crypto_block_openssl_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_nss_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt CommonCrypto. + */ +static void test_crypto_block_openssl_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt CommonCrypto. + */ +static void test_crypto_block_commoncrypto_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of OpenSSL block crypt. + */ +static void test_crypto_block_openssl_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, + in, inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** + * Simple test of NSS block crypt. + */ +static void test_crypto_block_nss_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_nss_driver(tc, pool); + drivers[1] = get_nss_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_192, MODE_ECB, 1, in, inlen, 24, "KEY_AES_192/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_128, MODE_ECB, 1, in, inlen, 16, "KEY_AES_128/MODE_ECB");*/ + + apr_pool_destroy(pool); + +} + +/** + * Simple test of Common Crypto block crypt. + */ +static void test_crypto_block_commoncrypto_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, + in, inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** + * Encrypt NSS, decrypt OpenSSL. + */ +static void test_crypto_block_nss_openssl_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_nss_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + + /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + + /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB");*/ + + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt NSS. + */ +static void test_crypto_block_openssl_nss_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_nss_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, inlen, + 24, "KEY_AES_192/MODE_CBC"); + + /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, inlen, + 24, "KEY_AES_192/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, inlen, + 16, "KEY_AES_128/MODE_CBC"); + + /* KEY_AES_128 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, inlen, + 16, "KEY_AES_128/MODE_ECB");*/ + + apr_pool_destroy(pool); + +} + +/** + * Encrypt CommonCrypto, decrypt OpenSSL. + */ +static void test_crypto_block_commoncrypto_openssl_pad(abts_case *tc, + void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt CommonCrypto. + */ +static void test_crypto_block_openssl_commoncrypto_pad(abts_case *tc, + void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** + * Get Types, OpenSSL. + */ +static void test_crypto_get_block_key_types_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *types; + int *key_3des_192; + int *key_aes_128; + int *key_aes_192; + int *key_aes_256; + + apr_pool_create(&pool, NULL); + driver = get_openssl_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_types(&types, f); + + key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_3des_192); + ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192); + + key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_128); + ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128); + + key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_192); + ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192); + + key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_256); + ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Types, NSS. + */ +static void test_crypto_get_block_key_types_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *types; + int *key_3des_192; + int *key_aes_128; + int *key_aes_192; + int *key_aes_256; + + apr_pool_create(&pool, NULL); + driver = get_nss_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_types(&types, f); + + key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_3des_192); + ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192); + + key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_128); + ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128); + + key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_192); + ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192); + + key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_256); + ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Types, Common Crypto. + */ +static void test_crypto_get_block_key_types_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *types; + int *key_3des_192; + int *key_aes_128; + int *key_aes_192; + int *key_aes_256; + + apr_pool_create(&pool, NULL); + driver = get_commoncrypto_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_types(&types, f); + + key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_3des_192); + ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192); + + key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_128); + ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128); + + key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_192); + ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192); + + key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_256); + ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Modes, OpenSSL. + */ +static void test_crypto_get_block_key_modes_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *modes; + int *mode_ecb; + int *mode_cbc; + + apr_pool_create(&pool, NULL); + driver = get_openssl_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_modes(&modes, f); + + mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_ecb); + ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB); + + mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_cbc); + ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Modes, NSS. + */ +static void test_crypto_get_block_key_modes_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *modes; + int *mode_ecb; + int *mode_cbc; + + apr_pool_create(&pool, NULL); + driver = get_nss_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_modes(&modes, f); + + mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_ecb); + ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB); + + mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_cbc); + ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Modes, Common Crypto. + */ +static void test_crypto_get_block_key_modes_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *modes; + int *mode_ecb; + int *mode_cbc; + + apr_pool_create(&pool, NULL); + driver = get_commoncrypto_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_modes(&modes, f); + + mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_ecb); + ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB); + + mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_cbc); + ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC); + + } + + apr_pool_destroy(pool); + +} + +static void test_crypto_memzero(abts_case *tc, void *data) +{ + /* Aligned message */ + struct { + char buf[7 * sizeof(int)]; + int untouched; + } msg; + /* A bit of type punning such that 'msg' might look unused + * after the call to apr_crypto_memzero(). + */ + int *ptr = (int *)&msg; + int i; + + /* Fill buf with non-zeros (odds) */ + for (i = 1; i < 2 * sizeof(msg.buf); i += 2) { + msg.buf[i / 2] = (char)i; + ABTS_ASSERT(tc, "test_crypto_memzero() barrier", msg.buf[i / 2] != 0); + } + + /* Zero out the whole, and check it */ + apr_crypto_memzero(&msg, sizeof msg); + for (i = 0; i < sizeof(msg) / sizeof(*ptr); ++i) { + ABTS_ASSERT(tc, "test_crypto_memzero() optimized out", ptr[i] == 0); + } +} + +static void test_crypto_equals(abts_case *tc, void *data) +{ + /* Buffers of each type of scalar */ + union { + char c; + short s; + int i; + long l; + float f; + double d; + void *p; + } buf0[7], buf1[7], buf[7]; + char *ptr = (char *)buf; + int i; + +#define TEST_SCALAR_MATCH(i, x, r) \ + ABTS_ASSERT(tc, "test_crypto_equals(" APR_STRINGIFY(x) ")" \ + " != " APR_STRINGIFY(r), \ + apr_crypto_equals(&buf##r[i].x, &buf[i].x, \ + sizeof(buf[i].x)) == r) + + /* Fill buf with non-zeros (odds) */ + for (i = 1; i < 2 * sizeof(buf); i += 2) { + ptr[i / 2] = (char)i; + } + /* Set buf1 = buf */ + memcpy(buf1, buf, sizeof buf); + /* Set buf0 = {0} */ + memset(buf0, 0, sizeof buf0); + + /* Check that buf1 == buf for each scalar */ + TEST_SCALAR_MATCH(0, c, 1); + TEST_SCALAR_MATCH(1, s, 1); + TEST_SCALAR_MATCH(2, i, 1); + TEST_SCALAR_MATCH(3, l, 1); + TEST_SCALAR_MATCH(4, f, 1); + TEST_SCALAR_MATCH(5, d, 1); + TEST_SCALAR_MATCH(6, p, 1); + + /* Check that buf0 != buf for each scalar */ + TEST_SCALAR_MATCH(0, c, 0); + TEST_SCALAR_MATCH(1, s, 0); + TEST_SCALAR_MATCH(2, i, 0); + TEST_SCALAR_MATCH(3, l, 0); + TEST_SCALAR_MATCH(4, f, 0); + TEST_SCALAR_MATCH(5, d, 0); + TEST_SCALAR_MATCH(6, p, 0); +} + +abts_suite *testcrypto(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + /* test simple init and shutdown */ + abts_run_test(suite, test_crypto_init, NULL); + + /* test key parsing - openssl */ + abts_run_test(suite, test_crypto_key_openssl, NULL); + + /* test key parsing - nss */ + abts_run_test(suite, test_crypto_key_nss, NULL); + + /* test key parsing - commoncrypto */ + abts_run_test(suite, test_crypto_key_commoncrypto, NULL); + + /* test a simple encrypt / decrypt operation - openssl */ + abts_run_test(suite, test_crypto_block_openssl, NULL); + + /* test a padded encrypt / decrypt operation - openssl */ + abts_run_test(suite, test_crypto_block_openssl_pad, NULL); + + /* test a simple encrypt / decrypt operation - nss */ + abts_run_test(suite, test_crypto_block_nss, NULL); + + /* test a padded encrypt / decrypt operation - nss */ + abts_run_test(suite, test_crypto_block_nss_pad, NULL); + + /* test a simple encrypt / decrypt operation - commoncrypto */ + abts_run_test(suite, test_crypto_block_commoncrypto, NULL); + + /* test a padded encrypt / decrypt operation - commoncrypto */ + abts_run_test(suite, test_crypto_block_commoncrypto_pad, NULL); + + /* test encrypt nss / decrypt openssl */ + abts_run_test(suite, test_crypto_block_nss_openssl, NULL); + + /* test padded encrypt nss / decrypt openssl */ + abts_run_test(suite, test_crypto_block_nss_openssl_pad, NULL); + + /* test encrypt openssl / decrypt nss */ + abts_run_test(suite, test_crypto_block_openssl_nss, NULL); + + /* test padded encrypt openssl / decrypt nss */ + abts_run_test(suite, test_crypto_block_openssl_nss_pad, NULL); + + /* test encrypt openssl / decrypt commoncrypto */ + abts_run_test(suite, test_crypto_block_openssl_commoncrypto, NULL); + + /* test padded encrypt openssl / decrypt commoncrypto */ + abts_run_test(suite, test_crypto_block_openssl_commoncrypto_pad, NULL); + + /* test encrypt commoncrypto / decrypt openssl */ + abts_run_test(suite, test_crypto_block_commoncrypto_openssl, NULL); + + /* test padded encrypt commoncrypto / decrypt openssl */ + abts_run_test(suite, test_crypto_block_commoncrypto_openssl_pad, NULL); + + /* test block key types openssl */ + abts_run_test(suite, test_crypto_get_block_key_types_openssl, NULL); + + /* test block key types nss */ + abts_run_test(suite, test_crypto_get_block_key_types_nss, NULL); + + /* test block key types commoncrypto */ + abts_run_test(suite, test_crypto_get_block_key_types_commoncrypto, NULL); + + /* test block key modes openssl */ + abts_run_test(suite, test_crypto_get_block_key_modes_openssl, NULL); + + /* test block key modes nss */ + abts_run_test(suite, test_crypto_get_block_key_modes_nss, NULL); + + /* test block key modes commoncrypto */ + abts_run_test(suite, test_crypto_get_block_key_modes_commoncrypto, NULL); + + abts_run_test(suite, test_crypto_memzero, NULL); + abts_run_test(suite, test_crypto_equals, NULL); + + return suite; +} + +#else + +/** + * Dummy test suite when crypto is turned off. + */ +abts_suite *testcrypto(abts_suite *suite) +{ + return ADD_SUITE(suite); +} + +#endif /* APU_HAVE_CRYPTO */ diff --git a/test/testdate.c b/test/testdate.c new file mode 100644 index 0000000..b4e2edf --- /dev/null +++ b/test/testdate.c @@ -0,0 +1,202 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "abts.h" +#include "testutil.h" +#include "apr_date.h" +#include "apr_general.h" + +#if APR_HAVE_TIME_H +#include <time.h> +#endif /* APR_HAVE_TIME_H */ + +static struct datetest { + const char *input; + const char *output; +} tests[] = { + { "Mon, 27 Feb 1995 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" }, + { "Fri, 1 Jul 2005 11:34:25 -0400", "Fri, 01 Jul 2005 15:34:25 GMT" }, + { "Monday, 27-Feb-95 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" }, + { "Tue, 4 Mar 1997 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" }, + { "Mon, 27 Feb 95 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" }, + { "Tue, 4 Mar 97 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" }, + { "Tue, 4 Mar 97 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" }, + { "Mon, 27 Feb 95 20:49 GMT", "Mon, 27 Feb 1995 20:49:00 GMT" }, + { "Tue, 4 Mar 97 12:43 GMT", "Tue, 04 Mar 1997 12:43:00 GMT" }, + { NULL, NULL } +}; + +static const apr_time_t year2secs[] = { + APR_INT64_C(0), /* 1970 */ + APR_INT64_C(31536000), /* 1971 */ + APR_INT64_C(63072000), /* 1972 */ + APR_INT64_C(94694400), /* 1973 */ + APR_INT64_C(126230400), /* 1974 */ + APR_INT64_C(157766400), /* 1975 */ + APR_INT64_C(189302400), /* 1976 */ + APR_INT64_C(220924800), /* 1977 */ + APR_INT64_C(252460800), /* 1978 */ + APR_INT64_C(283996800), /* 1979 */ + APR_INT64_C(315532800), /* 1980 */ + APR_INT64_C(347155200), /* 1981 */ + APR_INT64_C(378691200), /* 1982 */ + APR_INT64_C(410227200), /* 1983 */ + APR_INT64_C(441763200), /* 1984 */ + APR_INT64_C(473385600), /* 1985 */ + APR_INT64_C(504921600), /* 1986 */ + APR_INT64_C(536457600), /* 1987 */ + APR_INT64_C(567993600), /* 1988 */ + APR_INT64_C(599616000), /* 1989 */ + APR_INT64_C(631152000), /* 1990 */ + APR_INT64_C(662688000), /* 1991 */ + APR_INT64_C(694224000), /* 1992 */ + APR_INT64_C(725846400), /* 1993 */ + APR_INT64_C(757382400), /* 1994 */ + APR_INT64_C(788918400), /* 1995 */ + APR_INT64_C(820454400), /* 1996 */ + APR_INT64_C(852076800), /* 1997 */ + APR_INT64_C(883612800), /* 1998 */ + APR_INT64_C(915148800), /* 1999 */ + APR_INT64_C(946684800), /* 2000 */ + APR_INT64_C(978307200), /* 2001 */ + APR_INT64_C(1009843200), /* 2002 */ + APR_INT64_C(1041379200), /* 2003 */ + APR_INT64_C(1072915200), /* 2004 */ + APR_INT64_C(1104537600), /* 2005 */ + APR_INT64_C(1136073600), /* 2006 */ + APR_INT64_C(1167609600), /* 2007 */ + APR_INT64_C(1199145600), /* 2008 */ + APR_INT64_C(1230768000), /* 2009 */ + APR_INT64_C(1262304000), /* 2010 */ + APR_INT64_C(1293840000), /* 2011 */ + APR_INT64_C(1325376000), /* 2012 */ + APR_INT64_C(1356998400), /* 2013 */ + APR_INT64_C(1388534400), /* 2014 */ + APR_INT64_C(1420070400), /* 2015 */ + APR_INT64_C(1451606400), /* 2016 */ + APR_INT64_C(1483228800), /* 2017 */ + APR_INT64_C(1514764800), /* 2018 */ + APR_INT64_C(1546300800), /* 2019 */ + APR_INT64_C(1577836800), /* 2020 */ + APR_INT64_C(1609459200), /* 2021 */ + APR_INT64_C(1640995200), /* 2022 */ + APR_INT64_C(1672531200), /* 2023 */ + APR_INT64_C(1704067200), /* 2024 */ + APR_INT64_C(1735689600), /* 2025 */ + APR_INT64_C(1767225600), /* 2026 */ + APR_INT64_C(1798761600), /* 2027 */ + APR_INT64_C(1830297600), /* 2028 */ + APR_INT64_C(1861920000), /* 2029 */ + APR_INT64_C(1893456000), /* 2030 */ + APR_INT64_C(1924992000), /* 2031 */ + APR_INT64_C(1956528000), /* 2032 */ + APR_INT64_C(1988150400), /* 2033 */ + APR_INT64_C(2019686400), /* 2034 */ + APR_INT64_C(2051222400), /* 2035 */ + APR_INT64_C(2082758400), /* 2036 */ + APR_INT64_C(2114380800), /* 2037 */ + APR_INT64_C(2145916800) /* 2038 */ +}; + +const char month_snames[12][4] = { + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +/* XXX: non-portable */ +static void gm_timestr_822(char *ts, apr_time_t sec) +{ + static const char *const days[7]= + {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + struct tm *tms; + time_t ls = (time_t)sec; + + tms = gmtime(&ls); + + sprintf(ts, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", days[tms->tm_wday], + tms->tm_mday, month_snames[tms->tm_mon], tms->tm_year + 1900, + tms->tm_hour, tms->tm_min, tms->tm_sec); +} + +/* Linear congruential generator */ +static apr_uint32_t lgc(apr_uint32_t a) +{ + apr_uint64_t z = a; + z *= 279470273; + z %= APR_UINT64_C(4294967291); + return (apr_uint32_t)z; +} + +static void test_date_parse_http(abts_case *tc, void *data) +{ + int year, i; + apr_time_t guess; + apr_time_t offset = 0; + apr_time_t secstodate, newsecs; + char datestr[50]; + + for (year = 1970; year < 2038; ++year) { + secstodate = year2secs[year - 1970] + offset; + gm_timestr_822(datestr, secstodate); + secstodate *= APR_USEC_PER_SEC; + newsecs = apr_date_parse_http(datestr); + ABTS_TRUE(tc, secstodate == newsecs); + } + +#if APR_HAS_RANDOM + apr_generate_random_bytes((unsigned char *)&guess, sizeof(guess)); +#else + guess = apr_time_now() % APR_TIME_C(4294967291); +#endif + + for (i = 0; i < 10000; ++i) { + guess = (time_t)lgc((apr_uint32_t)guess); + if (guess < 0) + guess *= -1; + secstodate = guess + offset; + gm_timestr_822(datestr, secstodate); + secstodate *= APR_USEC_PER_SEC; + newsecs = apr_date_parse_http(datestr); + ABTS_TRUE(tc, secstodate == newsecs); + } +} + +static void test_date_rfc(abts_case *tc, void *data) +{ + apr_time_t date; + int i = 0; + + while (tests[i].input) { + char str_date[APR_RFC822_DATE_LEN] = { 0 }; + + date = apr_date_parse_rfc(tests[i].input); + + apr_rfc822_date(str_date, date); + + ABTS_STR_EQUAL(tc, str_date, tests[i].output); + + i++; + } +} + +abts_suite *testdate(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_date_parse_http, NULL); + abts_run_test(suite, test_date_rfc, NULL); + + return suite; +} diff --git a/test/testdbd.c b/test/testdbd.c new file mode 100644 index 0000000..6f0698a --- /dev/null +++ b/test/testdbd.c @@ -0,0 +1,245 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testutil.h" +#include "apr.h" +#include "apu.h" +#include "apr_pools.h" +#include "apr_dbd.h" +#include "apr_strings.h" + +static void test_dbd_init(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + + rv = apr_dbd_init(pool); + ABTS_ASSERT(tc, "failed to init apr_dbd", rv == APR_SUCCESS); +} + +#if APU_HAVE_SQLITE2 || APU_HAVE_SQLITE3 +static void test_statement(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver, const char* sql) +{ + int nrows; + apr_status_t rv; + + rv = apr_dbd_query(driver, handle, &nrows, sql); + + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); +} + +static void create_table(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + const char *sql = "CREATE TABLE apr_dbd_test (" + "col1 varchar(40) not null," + "col2 varchar(40)," + "col3 integer)"; + + test_statement(tc, handle, driver, sql); +} + +static void drop_table(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + const char *sql = "DROP TABLE apr_dbd_test"; + test_statement(tc, handle, driver, sql); +} + +static void delete_rows(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + const char *sql = "DELETE FROM apr_dbd_test"; + test_statement(tc, handle, driver, sql); +} + + +static void insert_data(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver, int count) +{ + apr_pool_t* pool = p; + const char* sql = "INSERT INTO apr_dbd_test VALUES('%d', '%d', %d)"; + char* sqf = NULL; + int i; + int nrows; + apr_status_t rv; + + for (i=0; i<count; i++) { + sqf = apr_psprintf(pool, sql, i, i, i); + rv = apr_dbd_query(driver, handle, &nrows, sqf); + ABTS_ASSERT(tc, sqf, rv == APR_SUCCESS); + ABTS_ASSERT(tc, sqf, 1 == nrows); + } +} + +static void select_rows(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver, int count) +{ + apr_status_t rv; + apr_pool_t* pool = p; + apr_pool_t* tpool; + const char* sql = "SELECT * FROM apr_dbd_test ORDER BY col1"; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; + int i; + + rv = apr_dbd_select(driver, pool, handle, &res, sql, 0); + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, res); + + apr_pool_create(&tpool, pool); + i = count; + while (i > 0) { + row = NULL; + rv = apr_dbd_get_row(driver, pool, res, &row, -1); + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, row); + apr_pool_clear(tpool); + i--; + } + ABTS_ASSERT(tc, "Missing Rows!", i == 0); + + res = NULL; + i = count; + + rv = apr_dbd_select(driver, pool, handle, &res, sql, 1); + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, res); + + rv = apr_dbd_num_tuples(driver, res); + ABTS_ASSERT(tc, "invalid row count", rv == count); + + while (i > 0) { + row = NULL; + rv = apr_dbd_get_row(driver, pool, res, &row, i); + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, row); + apr_pool_clear(tpool); + i--; + } + ABTS_ASSERT(tc, "Missing Rows!", i == 0); + rv = apr_dbd_get_row(driver, pool, res, &row, count+100); + ABTS_ASSERT(tc, "If we overseek, get_row should return -1", rv == -1); +} + +static void test_escape(abts_case *tc, apr_dbd_t *handle, + const apr_dbd_driver_t *driver) +{ + const char *escaped = apr_dbd_escape(driver, p, "foo'bar", handle); + + ABTS_STR_EQUAL(tc, "foo''bar", escaped); +} + +static void test_dbd_generic(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + void* native; + apr_pool_t *pool = p; + apr_status_t rv; + + native = apr_dbd_native_handle(driver, handle); + ABTS_PTR_NOTNULL(tc, native); + + apr_dbd_check_conn(driver, pool, handle); + + create_table(tc, handle, driver); + select_rows(tc, handle, driver, 0); + insert_data(tc, handle, driver, 5); + select_rows(tc, handle, driver, 5); + delete_rows(tc, handle, driver); + select_rows(tc, handle, driver, 0); + drop_table(tc, handle, driver); + + test_escape(tc, handle, driver); + + rv = apr_dbd_close(driver, handle); + ABTS_ASSERT(tc, "failed to close database", rv == APR_SUCCESS); +} +#endif + +#if APU_HAVE_SQLITE2 +static void test_dbd_sqlite2(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + const apr_dbd_driver_t* driver = NULL; + apr_dbd_t* handle = NULL; + + rv = apr_dbd_get_driver(pool, "sqlite2", &driver); + ABTS_ASSERT(tc, "failed to fetch sqlite2 driver", rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, driver); + if (!driver) { + return; + } + + ABTS_STR_EQUAL(tc, "sqlite2", apr_dbd_name(driver)); + + rv = apr_dbd_open(driver, pool, "data/sqlite2.db:600", &handle); + ABTS_ASSERT(tc, "failed to open sqlite2 atabase", rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, handle); + if (!handle) { + return; + } + + test_dbd_generic(tc, handle, driver); +} +#endif + +#if APU_HAVE_SQLITE3 +static void test_dbd_sqlite3(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + const apr_dbd_driver_t* driver = NULL; + apr_dbd_t* handle = NULL; + + rv = apr_dbd_get_driver(pool, "sqlite3", &driver); + ABTS_ASSERT(tc, "failed to fetch sqlite3 driver", rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, driver); + if (!driver) { + return; + } + + ABTS_STR_EQUAL(tc, "sqlite3", apr_dbd_name(driver)); + + rv = apr_dbd_open(driver, pool, "data/sqlite3.db", &handle); + ABTS_ASSERT(tc, "failed to open sqlite3 database", rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, handle); + if (!handle) { + return; + } + + test_dbd_generic(tc, handle, driver); +} +#endif + +abts_suite *testdbd(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + + abts_run_test(suite, test_dbd_init, NULL); + +#if APU_HAVE_SQLITE2 + abts_run_test(suite, test_dbd_sqlite2, NULL); +#endif + +#if APU_HAVE_SQLITE3 + abts_run_test(suite, test_dbd_sqlite3, NULL); +#endif + return suite; +} diff --git a/test/testdbm.c b/test/testdbm.c new file mode 100644 index 0000000..4f6becb --- /dev/null +++ b/test/testdbm.c @@ -0,0 +1,221 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_dbm.h" +#include "apr_uuid.h" +#include "apr_strings.h" +#include "abts.h" +#include "testutil.h" + +#define NUM_TABLE_ROWS 1024 + +typedef struct { + apr_datum_t key; + apr_datum_t val; + int deleted; + int visited; +} dbm_table_t; + +static dbm_table_t *generate_table(void) +{ + unsigned int i; + apr_uuid_t uuid; + dbm_table_t *table = apr_pcalloc(p, sizeof(*table) * NUM_TABLE_ROWS); + + for (i = 0; i < NUM_TABLE_ROWS/2; i++) { + apr_uuid_get(&uuid); + table[i].key.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data)); + table[i].key.dsize = sizeof(uuid.data); + table[i].val.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH + 1); + table[i].val.dsize = APR_UUID_FORMATTED_LENGTH + 1; + apr_uuid_format(table[i].val.dptr, &uuid); + } + + for (; i < NUM_TABLE_ROWS; i++) { + apr_uuid_get(&uuid); + table[i].val.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data)); + table[i].val.dsize = sizeof(uuid.data); + table[i].key.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH + 1); + table[i].key.dsize = APR_UUID_FORMATTED_LENGTH + 1; + apr_uuid_format(table[i].key.dptr, &uuid); + } + + return table; +} + +static void test_dbm_store(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + apr_status_t rv; + unsigned int i = NUM_TABLE_ROWS - 1; + + for (; i >= NUM_TABLE_ROWS/2; i--) { + rv = apr_dbm_store(db, table[i].key, table[i].val); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + table[i].deleted = FALSE; + } + + for (i = 0; i < NUM_TABLE_ROWS/2; i++) { + rv = apr_dbm_store(db, table[i].key, table[i].val); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + table[i].deleted = FALSE; + } +} + +static void test_dbm_fetch(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + apr_status_t rv; + unsigned int i; + apr_datum_t val; + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + memset(&val, 0, sizeof(val)); + rv = apr_dbm_fetch(db, table[i].key, &val); + if (!table[i].deleted) { + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, table[i].val.dsize, val.dsize); + ABTS_INT_EQUAL(tc, 0, memcmp(table[i].val.dptr, val.dptr, val.dsize)); + apr_dbm_freedatum(db, val); + } else { + ABTS_INT_EQUAL(tc, 0, val.dsize); + } + } +} + +static void test_dbm_delete(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + apr_status_t rv; + unsigned int i; + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + /* XXX: random */ + if (i & 1) + continue; + rv = apr_dbm_delete(db, table[i].key); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + table[i].deleted = TRUE; + } +} + +static void test_dbm_exists(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + unsigned int i; + int cond; + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + cond = apr_dbm_exists(db, table[i].key); + if (table[i].deleted) { + ABTS_TRUE(tc, cond == 0); + } else { + ABTS_TRUE(tc, cond != 0); + } + } +} + +static void test_dbm_traversal(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + apr_status_t rv; + unsigned int i; + apr_datum_t key; + + rv = apr_dbm_firstkey(db, &key); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + do { + if (key.dptr == NULL || key.dsize == 0) + break; + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + if (table[i].key.dsize != key.dsize) + continue; + if (memcmp(table[i].key.dptr, key.dptr, key.dsize)) + continue; + ABTS_INT_EQUAL(tc, 0, table[i].deleted); + ABTS_INT_EQUAL(tc, 0, table[i].visited); + table[i].visited++; + } + + rv = apr_dbm_nextkey(db, &key); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } while (1); + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + if (table[i].deleted) + continue; + ABTS_INT_EQUAL(tc, 1, table[i].visited); + table[i].visited = 0; + } +} + +static void test_dbm(abts_case *tc, void *data) +{ + apr_dbm_t *db; + apr_status_t rv; + dbm_table_t *table; + const char *type = data; + const char *file = apr_pstrcat(p, "data/test-", type, NULL); + + rv = apr_dbm_open_ex(&db, type, file, APR_DBM_RWCREATE, APR_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + table = generate_table(); + + test_dbm_store(tc, db, table); + test_dbm_fetch(tc, db, table); + test_dbm_delete(tc, db, table); + test_dbm_exists(tc, db, table); + test_dbm_traversal(tc, db, table); + + apr_dbm_close(db); + + rv = apr_dbm_open_ex(&db, type, file, APR_DBM_READONLY, APR_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + test_dbm_exists(tc, db, table); + test_dbm_traversal(tc, db, table); + test_dbm_fetch(tc, db, table); + + apr_dbm_close(db); +} + +abts_suite *testdbm(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APU_HAVE_GDBM + abts_run_test(suite, test_dbm, "gdbm"); +#endif +#if APU_HAVE_NDBM + abts_run_test(suite, test_dbm, "ndbm"); +#endif +#if APU_HAVE_SDBM + abts_run_test(suite, test_dbm, "sdbm"); +#endif +#if APU_HAVE_DB + abts_run_test(suite, test_dbm, "db"); +#endif + + return suite; +} diff --git a/test/testldap.c b/test/testldap.c new file mode 100644 index 0000000..4f4fef9 --- /dev/null +++ b/test/testldap.c @@ -0,0 +1,250 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /* Setup: + * - Create or edit the file data/host.data and add an + * ldap server DN. Multiple DNs may be listed on + * a single line. + * - Copy the server certificates to the data/ directory. + * All DER type certificates must have the .der extention. + * All BASE64 or PEM certificates must have the .b64 + * extension. All certificate files copied to the /data + * directory will be added to the ldap certificate store. + */ + + /* This test covers the following three types of connections: + * - Unsecure ldap:// + * - Secure ldaps:// + * - Secure ldap://+Start_TLS + * + * - (TBD) Mutual authentication + * + * There are other variations that should be tested: + * - All of the above with multiple redundant LDAP servers + * This can be done by listing more than one server DN + * in the host.data file. The DNs should all be listed + * on one line separated by a space. + * - All of the above with multiple certificates + * If more than one certificate is found in the data/ + * directory, each certificate found will be added + * to the certificate store. + * - All of the above on alternate ports + * An alternate port can be specified as part of the + * host in the host.data file. The ":port" should + * follow each DN listed. Default is 389 and 636. + * - Secure connections with mutual authentication + */ + +#include "testutil.h" + +#include "apr.h" +#include "apr_general.h" +#include "apr_ldap.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_strings.h" +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#define APR_WANT_STDIO +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#define DIRNAME "data" +#define FILENAME DIRNAME "/host.data" +#define CERTFILEDER DIRNAME "/*.der" +#define CERTFILEB64 DIRNAME "/*.b64" + +#if APR_HAS_LDAP + +static char ldap_host[256]; + +static int get_ldap_host(void) +{ + apr_status_t rv; + apr_file_t *thefile = NULL; + char *ptr; + + ldap_host[0] = '\0'; + rv = apr_file_open(&thefile, FILENAME, + APR_FOPEN_READ, + APR_UREAD | APR_UWRITE | APR_GREAD, p); + if (rv != APR_SUCCESS) { + return 0; + } + + rv = apr_file_gets(ldap_host, sizeof(ldap_host), thefile); + if (rv != APR_SUCCESS) { + return 0; + } + + ptr = strstr (ldap_host, "\r\n"); + if (ptr) { + *ptr = '\0'; + } + apr_file_close(thefile); + + return 1; + +} + +static int add_ldap_certs(abts_case *tc) +{ + apr_status_t status; + apr_dir_t *thedir; + apr_finfo_t dirent; + apr_ldap_err_t *result = NULL; + + if ((status = apr_dir_open(&thedir, DIRNAME, p)) == APR_SUCCESS) { + apr_ldap_opt_tls_cert_t *cert = (apr_ldap_opt_tls_cert_t *)apr_pcalloc(p, sizeof(apr_ldap_opt_tls_cert_t)); + + do { + status = apr_dir_read(&dirent, APR_FINFO_MIN | APR_FINFO_NAME, thedir); + if (APR_STATUS_IS_INCOMPLETE(status)) { + continue; /* ignore un-stat()able files */ + } + else if (status != APR_SUCCESS) { + break; + } + + if (strstr(dirent.name, ".der")) { + cert->type = APR_LDAP_CA_TYPE_DER; + cert->path = apr_pstrcat (p, DIRNAME, "/", dirent.name, NULL); + apr_ldap_set_option(p, NULL, APR_LDAP_OPT_TLS_CERT, (void *)cert, &result); + ABTS_TRUE(tc, result->rc == LDAP_SUCCESS); + } + if (strstr(dirent.name, ".b64")) { + cert->type = APR_LDAP_CA_TYPE_BASE64; + cert->path = apr_pstrcat (p, DIRNAME, "/", dirent.name, NULL); + apr_ldap_set_option(p, NULL, APR_LDAP_OPT_TLS_CERT, (void *)cert, &result); + ABTS_TRUE(tc, result->rc == LDAP_SUCCESS); + } + + } while (1); + + apr_dir_close(thedir); + } + return 0; +} + +static void test_ldap_connection(abts_case *tc, LDAP *ldap) +{ + int version = LDAP_VERSION3; + int failures, result; + + /* always default to LDAP V3 */ + ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &version); + + for (failures=0; failures<10; failures++) + { + result = ldap_simple_bind_s(ldap, + (char *)NULL, + (char *)NULL); + if (LDAP_SERVER_DOWN != result) + break; + } + + ABTS_TRUE(tc, result == LDAP_SUCCESS); + if (result != LDAP_SUCCESS) { + abts_log_message("%s\n", ldap_err2string(result)); + } + + ldap_unbind_s(ldap); + + return; +} + +static void test_ldap(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + LDAP *ldap; + apr_ldap_err_t *result = NULL; + + + ABTS_ASSERT(tc, "failed to get host", ldap_host[0] != '\0'); + + apr_ldap_init(pool, &ldap, + ldap_host, LDAP_PORT, + APR_LDAP_NONE, &(result)); + + ABTS_TRUE(tc, ldap != NULL); + ABTS_PTR_NOTNULL(tc, result); + + if (result->rc == LDAP_SUCCESS) { + test_ldap_connection(tc, ldap); + } +} + +static void test_ldaps(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + LDAP *ldap; + apr_ldap_err_t *result = NULL; + + apr_ldap_init(pool, &ldap, + ldap_host, LDAPS_PORT, + APR_LDAP_SSL, &(result)); + + ABTS_TRUE(tc, ldap != NULL); + ABTS_PTR_NOTNULL(tc, result); + + if (result->rc == LDAP_SUCCESS) { + add_ldap_certs(tc); + + test_ldap_connection(tc, ldap); + } +} + +static void test_ldap_tls(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + LDAP *ldap; + apr_ldap_err_t *result = NULL; + + apr_ldap_init(pool, &ldap, + ldap_host, LDAP_PORT, + APR_LDAP_STARTTLS, &(result)); + + ABTS_TRUE(tc, ldap != NULL); + ABTS_PTR_NOTNULL(tc, result); + + if (result->rc == LDAP_SUCCESS) { + add_ldap_certs(tc); + + test_ldap_connection(tc, ldap); + } +} + +#endif /* APR_HAS_LDAP */ + +abts_suite *testldap(abts_suite *suite) +{ +#if APR_HAS_LDAP + apr_ldap_err_t *result = NULL; + suite = ADD_SUITE(suite); + + apr_ldap_ssl_init(p, NULL, 0, &result); + + if (get_ldap_host()) { + abts_run_test(suite, test_ldap, NULL); + abts_run_test(suite, test_ldaps, NULL); + abts_run_test(suite, test_ldap_tls, NULL); + } +#endif /* APR_HAS_LDAP */ + + return suite; +} + diff --git a/test/testmd4.c b/test/testmd4.c new file mode 100644 index 0000000..53a3361 --- /dev/null +++ b/test/testmd4.c @@ -0,0 +1,119 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* This is derived from material copyright RSA Data Security, Inc. + * Their notice is reproduced below in its entirety. + * + * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All + * rights reserved. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "apr_errno.h" +#include "apr_md4.h" +#include "apr_file_io.h" + +#include "abts.h" +#include "testutil.h" + +static struct { + const char *string; + const char *md4sum; +} md4sums[] = +{ +/* +* Taken from the old md4 test suite. +* MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0 +* MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24 +* MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d +* MD4 ("message digest") = d9130a8164549fe818874806e1c7014b +* MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9 +* MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") +* MD4 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536 +* +*/ + {"", + "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0"}, + {"a", + "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb\x24"}, + {"abc", + "\xa4\x48\x01\x7a\xaf\x21\xd8\x52\x5f\xc1\x0a\xe8\x7a\xa6\x72\x9d"}, + {"message digest", + "\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01\x4b"}, + {"abcdefghijklmnopqrstuvwxyz", + "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd\xee\xa8\xed\x63\xdf\x41\x2d\xa9"}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "\x04\x3f\x85\x82\xf2\x41\xdb\x35\x1c\xe6\x27\xe1\x53\xe7\xf0\xe4"}, + {"12345678901234567890123456789012345678901234567890123456789012345678901234567890", + "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19\x9c\x3e\x7b\x16\x4f\xcc\x05\x36"} +}; + +static int num_sums = sizeof(md4sums) / sizeof(md4sums[0]); +static int count; + +#if 0 +static int MDStringComp(const void *string, const void *sum) +{ + apr_md4_ctx_t context; + unsigned char digest[APR_MD4_DIGESTSIZE]; + unsigned int len = strlen(string); + + apr_md4_init(&context); + apr_md4_update(&context, (unsigned char *)string, len); + apr_md4_final(digest, &context); + return (memcmp(digest, sum, APR_MD4_DIGESTSIZE)); + +} +#endif + +static void test_md4sum(abts_case *tc, void *data) +{ + apr_md4_ctx_t context; + unsigned char digest[APR_MD4_DIGESTSIZE]; + const void *string = md4sums[count].string; + const void *sum = md4sums[count].md4sum; + unsigned int len = strlen(string); + + ABTS_ASSERT(tc, "apr_md4_init", (apr_md4_init(&context) == 0)); + ABTS_ASSERT(tc, "apr_md4_update", + (apr_md4_update(&context, + (unsigned char *)string, len) == 0)); + + ABTS_ASSERT(tc, "apr_md4_final", (apr_md4_final(digest, &context) ==0)); + ABTS_ASSERT(tc, "check for correct md4 digest", + (memcmp(digest, sum, APR_MD4_DIGESTSIZE) == 0)); +} + +abts_suite *testmd4(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + for (count=0; count < num_sums; count++) { + abts_run_test(suite, test_md4sum, NULL); + } + + return suite; +} diff --git a/test/testmd5.c b/test/testmd5.c new file mode 100644 index 0000000..4e13da2 --- /dev/null +++ b/test/testmd5.c @@ -0,0 +1,103 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "apr_md5.h" +#include "apr_xlate.h" +#include "apr_general.h" + +#include "abts.h" +#include "testutil.h" + +static struct { + const char *string; + const char *digest; +} md5sums[] = +{ + {"Jeff was here!", + "\xa5\x25\x8a\x89\x11\xb2\x9d\x1f\x81\x75\x96\x3b\x60\x94\x49\xc0"}, + {"01234567890aBcDeFASDFGHJKLPOIUYTR" + "POIUYTREWQZXCVBN LLLLLLLLLLLLLLL", + "\xd4\x1a\x06\x2c\xc5\xfd\x6f\x24\x67\x68\x56\x7c\x40\x8a\xd5\x69"}, + {"111111118888888888888888*******%%%%%%%%%%#####" + "142134u8097289720432098409289nkjlfkjlmn,m.. ", + "\xb6\xea\x5b\xe8\xca\x45\x8a\x33\xf0\xf1\x84\x6f\xf9\x65\xa8\xe1"}, + {"01234567890aBcDeFASDFGHJKLPOIUYTR" + "POIUYTREWQZXCVBN LLLLLLLLLLLLLLL" + "01234567890aBcDeFASDFGHJKLPOIUYTR" + "POIUYTREWQZXCVBN LLLLLLLLLLLLLLL" + "1", + "\xd1\xa1\xc0\x97\x8a\x60\xbb\xfb\x2a\x25\x46\x9d\xa5\xae\xd0\xb0"} +}; + +static int num_sums = sizeof(md5sums) / sizeof(md5sums[0]); +static int count; + +static void test_md5sum(abts_case *tc, void *data) +{ + apr_md5_ctx_t context; + unsigned char digest[APR_MD5_DIGESTSIZE]; + const void *string = md5sums[count].string; + const void *sum = md5sums[count].digest; + unsigned int len = strlen(string); + + ABTS_ASSERT(tc, "apr_md5_init", (apr_md5_init(&context) == 0)); + ABTS_ASSERT(tc, "apr_md5_update", + (apr_md5_update(&context, string, len) == 0)); + ABTS_ASSERT(tc, "apr_md5_final", (apr_md5_final(digest, &context) + == 0)); + ABTS_ASSERT(tc, "check for correct md5 digest", + (memcmp(digest, sum, APR_MD5_DIGESTSIZE) == 0)); +} + +static void test_md5sum_unaligned(abts_case *tc, void *data) +{ + apr_md5_ctx_t context; + const char *string = "abcdefghijklmnopqrstuvwxyz01234" + "abcdefghijklmnopqrstuvwxyz01234" + "abcdefghijklmnopqrstuvwxyz01234" + "abcdefghijklmnopqrstuvwxyz01234_"; + const char *sum = + "\x93\x17\x22\x78\xee\x30\x82\xb3\xeb\x95\x33\xec\xea\x78\xb7\x89"; + unsigned char digest[APR_MD5_DIGESTSIZE]; + unsigned int i; + + ABTS_ASSERT(tc, "apr_md5_init", (apr_md5_init(&context) == 0)); + for (i = 0; i < 10; i++) { + ABTS_ASSERT(tc, "apr_md5_update", + (apr_md5_update(&context, string, strlen(string)) == 0)); + string++; + } + ABTS_ASSERT(tc, "apr_md5_final", (apr_md5_final(digest, &context) + == 0)); + ABTS_ASSERT(tc, "check for correct md5 digest of unaligned data", + (memcmp(digest, sum, APR_MD5_DIGESTSIZE) == 0)); +} + +abts_suite *testmd5(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + for (count=0; count < num_sums; count++) { + abts_run_test(suite, test_md5sum, NULL); + } + abts_run_test(suite, test_md5sum_unaligned, NULL); + + return suite; +} diff --git a/test/testmemcache.c b/test/testmemcache.c new file mode 100644 index 0000000..c65381e --- /dev/null +++ b/test/testmemcache.c @@ -0,0 +1,626 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testutil.h" +#include "apr.h" +#include "apu.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_memcache.h" +#include "apr_network_io.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for exit() */ +#endif + +#define HOST "localhost" +#define PORT 11211 + +/* the total number of items to use for set/get testing */ +#define TDATA_SIZE 3000 + +/* some smaller subset of TDATA_SIZE used for multiget testing */ +#define TDATA_SET 100 + +/* our custom hash function just returns this all the time */ +#define HASH_FUNC_RESULT 510 + +/* all keys will be prefixed with this */ +const char prefix[] = "testmemcache"; + +/* text for values we store */ +const char txt[] = +"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis at" +"lacus in ligula hendrerit consectetuer. Vestibulum tristique odio" +"iaculis leo. In massa arcu, ultricies a, laoreet nec, hendrerit non," +"neque. Nulla sagittis sapien ac risus. Morbi ligula dolor, vestibulum" +"nec, viverra id, placerat dapibus, arcu. Curabitur egestas feugiat" +"tellus. Donec dignissim. Nunc ante. Curabitur id lorem. In mollis" +"tortor sit amet eros auctor dapibus. Proin nulla sem, tristique in," +"convallis id, iaculis feugiat cras amet."; + +/* + * this datatype is for our custom server determination function. this might + * be useful if you don't want to rely on simply hashing keys to determine + * where a key belongs, but instead want to write something fancy, or use some + * other kind of configuration data, i.e. a hash plus some data about a + * namespace, or whatever. see my_server_func, and test_memcache_user_funcs + * for the examples. + */ +typedef struct { + const char *someval; + apr_uint32_t which_server; +} my_hash_server_baton; + + +/* this could do something fancy and return some hash result. + * for simplicity, just return the same value, so we can test it later on. + * if you wanted to use some external hashing library or functions for + * consistent hashing, for example, this would be a good place to do it. + */ +static apr_uint32_t my_hash_func(void *baton, const char *data, + apr_size_t data_len) +{ + + return HASH_FUNC_RESULT; +} + +/* + * a fancy function to determine which server to use given some kind of data + * and a hash value. this example actually ignores the hash value itself + * and pulls some number from the *baton, which is a struct that has some + * kind of meaningful stuff in it. + */ +static apr_memcache_server_t *my_server_func(void *baton, + apr_memcache_t *mc, + const apr_uint32_t hash) +{ + apr_memcache_server_t *ms = NULL; + my_hash_server_baton *mhsb = (my_hash_server_baton *)baton; + + if(mc->ntotal == 0) { + return NULL; + } + + if(mc->ntotal < mhsb->which_server) { + return NULL; + } + + ms = mc->live_servers[mhsb->which_server - 1]; + + return ms; +} + +apr_uint16_t firsttime = 0; +static int randval(apr_uint32_t high) +{ + apr_uint32_t i = 0; + double d = 0; + + if (firsttime == 0) { + srand((unsigned) (getpid())); + firsttime = 1; + } + + d = (double) rand() / ((double) RAND_MAX + 1); + i = (int) (d * (high - 0 + 1)); + + return i > 0 ? i : 1; +} + +/* + * general test to make sure we can create the memcache struct and add + * some servers, but not more than we tell it we can add + */ + +static void test_memcache_create(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server, *s; + apr_uint32_t max_servers = 10; + apr_uint32_t i; + apr_uint32_t hash; + + rv = apr_memcache_create(pool, max_servers, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + for (i = 1; i <= max_servers; i++) { + apr_port_t port; + + port = PORT + i; + rv = + apr_memcache_server_create(pool, HOST, PORT + i, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + s = apr_memcache_find_server(memcache, HOST, port); + ABTS_PTR_EQUAL(tc, server, s); + + rv = apr_memcache_disable_server(memcache, s); + ABTS_ASSERT(tc, "server disable failed", rv == APR_SUCCESS); + + rv = apr_memcache_enable_server(memcache, s); + ABTS_ASSERT(tc, "server enable failed", rv == APR_SUCCESS); + + hash = apr_memcache_hash(memcache, prefix, strlen(prefix)); + ABTS_ASSERT(tc, "hash failed", hash > 0); + + s = apr_memcache_find_server_hash(memcache, hash); + ABTS_PTR_NOTNULL(tc, s); + } + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add should have failed", rv != APR_SUCCESS); + +} + +/* install our own custom hashing and server selection routines. */ + +static int create_test_hash(apr_pool_t *p, apr_hash_t *h) +{ + int i; + + for (i = 0; i < TDATA_SIZE; i++) { + char *k, *v; + + k = apr_pstrcat(p, prefix, apr_itoa(p, i), NULL); + v = apr_pstrndup(p, txt, randval((apr_uint32_t)strlen(txt))); + + apr_hash_set(h, k, APR_HASH_KEY_STRING, v); + } + + return i; +} + +static void test_memcache_user_funcs(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *found; + apr_uint32_t max_servers = 10; + apr_uint32_t hres; + apr_uint32_t i; + my_hash_server_baton *baton = + apr_pcalloc(pool, sizeof(my_hash_server_baton)); + + rv = apr_memcache_create(pool, max_servers, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + /* as noted above, install our custom hash function, and call + * apr_memcache_hash. the return value should be our predefined number, + * and our function just ignores the other args, for simplicity. + */ + memcache->hash_func = my_hash_func; + + hres = apr_memcache_hash(memcache, "whatever", sizeof("whatever") - 1); + ABTS_INT_EQUAL(tc, HASH_FUNC_RESULT, hres); + + /* add some servers */ + for(i = 1; i <= 10; i++) { + apr_memcache_server_t *ms; + + rv = apr_memcache_server_create(pool, HOST, i, 0, 1, 1, 60, &ms); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, ms); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + } + + /* + * set 'which_server' in our server_baton to find the third server + * which should have the same port. + */ + baton->which_server = 3; + memcache->server_func = my_server_func; + memcache->server_baton = baton; + found = apr_memcache_find_server_hash(memcache, 0); + ABTS_ASSERT(tc, "wrong server found", found->port == baton->which_server); +} + +/* test non data related commands like stats and version */ +static void test_memcache_meta(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_memcache_stats_t *stats; + char *result; + apr_status_t rv; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + apr_memcache_version(server, pool, &result); + ABTS_PTR_NOTNULL(tc, result); + + apr_memcache_stats(server, p, &stats); + ABTS_PTR_NOTNULL(tc, stats); + + ABTS_STR_NEQUAL(tc, stats->version, result, 5); + + /* + * no way to know exactly what will be in most of these, so + * just make sure there is something. + */ + + ABTS_ASSERT(tc, "pid", stats->pid >= 0); + ABTS_ASSERT(tc, "time", stats->time >= 0); + /* ABTS_ASSERT(tc, "pointer_size", stats->pointer_size >= 0); */ + ABTS_ASSERT(tc, "rusage_user", stats->rusage_user >= 0); + ABTS_ASSERT(tc, "rusage_system", stats->rusage_system >= 0); + + ABTS_ASSERT(tc, "curr_items", stats->curr_items >= 0); + ABTS_ASSERT(tc, "total_items", stats->total_items >= 0); + ABTS_ASSERT(tc, "bytes", stats->bytes >= 0); + + ABTS_ASSERT(tc, "curr_connections", stats->curr_connections >= 0); + ABTS_ASSERT(tc, "total_connections", stats->total_connections >= 0); + ABTS_ASSERT(tc, "connection_structures", + stats->connection_structures >= 0); + + ABTS_ASSERT(tc, "cmd_get", stats->cmd_get >= 0); + ABTS_ASSERT(tc, "cmd_set", stats->cmd_set >= 0); + ABTS_ASSERT(tc, "get_hits", stats->get_hits >= 0); + ABTS_ASSERT(tc, "get_misses", stats->get_misses >= 0); + + /* ABTS_ASSERT(tc, "evictions", stats->evictions >= 0); */ + + ABTS_ASSERT(tc, "bytes_read", stats->bytes_read >= 0); + ABTS_ASSERT(tc, "bytes_written", stats->bytes_written >= 0); + ABTS_ASSERT(tc, "limit_maxbytes", stats->limit_maxbytes >= 0); + + /* ABTS_ASSERT(tc, "threads", stats->threads >= 0); */ +} + +/* test add and replace calls */ + +static void test_memcache_addreplace(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_hash_t *tdata; + apr_hash_index_t *hi; + char *result; + apr_size_t len; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + tdata = apr_hash_make(p); + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + /* doesn't exist yet, fail */ + rv = apr_memcache_replace(memcache, key, v, strlen(v) - 1, 0, 27); + ABTS_ASSERT(tc, "replace should have failed", rv != APR_SUCCESS); + + /* doesn't exist yet, succeed */ + rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27); + ABTS_ASSERT(tc, "add failed", rv == APR_SUCCESS); + + /* exists now, succeed */ + rv = apr_memcache_replace(memcache, key, "new", sizeof("new") - 1, 0, 27); + ABTS_ASSERT(tc, "replace failed", rv == APR_SUCCESS); + + /* make sure its different */ + rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + ABTS_STR_NEQUAL(tc, result, "new", 3); + + /* exists now, fail */ + rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27); + ABTS_ASSERT(tc, "add should have failed", rv != APR_SUCCESS); + + /* clean up */ + rv = apr_memcache_delete(memcache, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } +} + +/* basic tests of the increment and decrement commands */ +static void test_memcache_incrdecr(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_uint32_t new; + char *result; + apr_size_t len; + apr_uint32_t i; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + rv = apr_memcache_set(memcache, prefix, "271", sizeof("271") - 1, 0, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + + for( i = 1; i <= TDATA_SIZE; i++) { + apr_uint32_t expect; + + rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + + expect = i + atoi(result); + + rv = apr_memcache_incr(memcache, prefix, i, &new); + ABTS_ASSERT(tc, "incr failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, expect, new); + + rv = apr_memcache_decr(memcache, prefix, i, &new); + ABTS_ASSERT(tc, "decr failed", rv == APR_SUCCESS); + ABTS_INT_EQUAL(tc, atoi(result), new); + + } + + rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, 271, atoi(result)); + + rv = apr_memcache_delete(memcache, prefix, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); +} + +/* test the multiget functionality */ +static void test_memcache_multiget(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_pool_t *tmppool; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_hash_t *tdata, *values; + apr_hash_index_t *hi; + apr_uint32_t i; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + values = apr_hash_make(p); + tdata = apr_hash_make(p); + + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + } + + apr_pool_create(&tmppool, pool); + for (i = 0; i < TDATA_SET; i++) + apr_memcache_add_multget_key(pool, + apr_pstrcat(pool, prefix, + apr_itoa(pool, i), NULL), + &values); + + rv = apr_memcache_multgetp(memcache, + tmppool, + pool, + values); + + ABTS_ASSERT(tc, "multgetp failed", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "multgetp returned too few results", + apr_hash_count(values) == TDATA_SET); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + const char *key; + + apr_hash_this(hi, &k, NULL, NULL); + key = k; + + rv = apr_memcache_delete(memcache, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } + +} + +/* test setting and getting */ + +static void test_memcache_setget(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_hash_t *tdata; + apr_hash_index_t *hi; + char *result; + apr_size_t len; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + tdata = apr_hash_make(pool); + + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + } + + rv = apr_memcache_getp(memcache, pool, "nothere3423", &result, &len, NULL); + + ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + const char *key; + + apr_hash_this(hi, &k, NULL, NULL); + key = k; + + rv = apr_memcache_delete(memcache, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } +} + +/* use apr_socket stuff to see if there is in fact a memcached server + * running on PORT. + */ +static apr_status_t check_mc(void) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_socket_t *sock = NULL; + apr_sockaddr_t *sa; + struct iovec vec[2]; + apr_size_t written; + char buf[128]; + apr_size_t len; + + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, pool); + if(rv != APR_SUCCESS) { + return rv; + } + + rv = apr_sockaddr_info_get(&sa, HOST, APR_INET, PORT, 0, pool); + if(rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(sock, 1 * APR_USEC_PER_SEC); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_connect(sock, sa); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(sock, -1); + if (rv != APR_SUCCESS) { + return rv; + } + + vec[0].iov_base = "version"; + vec[0].iov_len = sizeof("version") - 1; + + vec[1].iov_base = "\r\n"; + vec[1].iov_len = sizeof("\r\n") -1; + + rv = apr_socket_sendv(sock, vec, 2, &written); + if (rv != APR_SUCCESS) { + return rv; + } + + len = sizeof(buf); + rv = apr_socket_recv(sock, buf, &len); + if(rv != APR_SUCCESS) { + return rv; + } + + if(strncmp(buf, "VERSION", sizeof("VERSION")-1) != 0) { + rv = APR_EGENERAL; + } + + apr_socket_close(sock); + return rv; +} + +abts_suite *testmemcache(abts_suite * suite) +{ + apr_status_t rv; + suite = ADD_SUITE(suite); + /* check for a running memcached on the typical port before + * trying to run the tests. succeed if we don't find one. + */ + rv = check_mc(); + if (rv == APR_SUCCESS) { + abts_run_test(suite, test_memcache_create, NULL); + abts_run_test(suite, test_memcache_user_funcs, NULL); + abts_run_test(suite, test_memcache_meta, NULL); + abts_run_test(suite, test_memcache_setget, NULL); + abts_run_test(suite, test_memcache_multiget, NULL); + abts_run_test(suite, test_memcache_addreplace, NULL); + abts_run_test(suite, test_memcache_incrdecr, NULL); + } + else { + abts_log_message("Error %d occurred attempting to reach memcached " + "on %s:%d. Skipping apr_memcache tests...", + rv, HOST, PORT); + } + + return suite; +} diff --git a/test/testpass.c b/test/testpass.c new file mode 100644 index 0000000..2a27a8f --- /dev/null +++ b/test/testpass.c @@ -0,0 +1,217 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "apr_errno.h" +#include "apr_strings.h" +#include "apr_file_io.h" +#include "apr_thread_pool.h" +#include "apr_md5.h" +#include "apr_sha1.h" + +#include "abts.h" +#include "testutil.h" + +#if defined(WIN32) || defined(BEOS) || defined(NETWARE) +#define CRYPT_ALGO_SUPPORTED 0 +#else +#define CRYPT_ALGO_SUPPORTED 1 +#endif + +#if defined __GLIBC_PREREQ +#if __GLIBC_PREREQ(2,7) +#define GLIBCSHA_ALGO_SUPPORTED +#endif +#endif + +#if CRYPT_ALGO_SUPPORTED + +static struct { + const char *password; + const char *hash; +} passwords[] = +{ +/* + passwords and hashes created with Apache's htpasswd utility like this: + + htpasswd -c -b passwords pass1 pass1 + htpasswd -b passwords pass2 pass2 + htpasswd -b passwords pass3 pass3 + htpasswd -b passwords pass4 pass4 + htpasswd -b passwords pass5 pass5 + htpasswd -b passwords pass6 pass6 + htpasswd -b passwords pass7 pass7 + htpasswd -b passwords pass8 pass8 + (insert Perl one-liner to convert to initializer :) ) + */ + {"pass1", "1fWDc9QWYCWrQ"}, + {"pass2", "1fiGx3u7QoXaM"}, + {"pass3", "1fzijMylTiwCs"}, + {"pass4", "nHUYc8U2UOP7s"}, + {"pass5", "nHpETGLGPwAmA"}, + {"pass6", "nHbsbWmJ3uyhc"}, + {"pass7", "nHQ3BbF0Y9vpI"}, + {"pass8", "nHZA1rViSldQk"} +}; +static int num_passwords = sizeof(passwords) / sizeof(passwords[0]); + +static void test_crypt(abts_case *tc, void *data) +{ + int i; + + for (i = 0; i < num_passwords; i++) { + apr_assert_success(tc, "check for valid password", + apr_password_validate(passwords[i].password, + passwords[i].hash)); + } +} + +#if APR_HAS_THREADS + +static void * APR_THREAD_FUNC testing_thread(apr_thread_t *thd, + void *data) +{ + abts_case *tc = data; + int i; + + for (i = 0; i < 100; i++) { + test_crypt(tc, NULL); + } + + return APR_SUCCESS; +} + +#define NUM_THR 20 + +/* test for threadsafe crypt() */ +static void test_threadsafe(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_thread_pool_t *thrp; + + rv = apr_thread_pool_create(&thrp, NUM_THR/2, NUM_THR, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < NUM_THR; i++) { + rv = apr_thread_pool_push(thrp, testing_thread, tc, 0, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + apr_thread_pool_destroy(thrp); +} +#endif + +#endif /* CRYPT_ALGO_SUPPORTED */ + +static void test_shapass(abts_case *tc, void *data) +{ + const char *pass = "hellojed"; + const char *pass2 = "hellojed2"; + char hash[100]; + + apr_sha1_base64(pass, strlen(pass), hash); + + apr_assert_success(tc, "SHA1 password validated", + apr_password_validate(pass, hash)); + APR_ASSERT_FAILURE(tc, "wrong SHA1 password should not validate", + apr_password_validate(pass2, hash)); +} + +static void test_md5pass(abts_case *tc, void *data) +{ + const char *pass = "hellojed", *salt = "sardine"; + const char *pass2 = "hellojed2"; + char hash[100]; + + apr_md5_encode(pass, salt, hash, sizeof hash); + + apr_assert_success(tc, "MD5 password validated", + apr_password_validate(pass, hash)); + APR_ASSERT_FAILURE(tc, "wrong MD5 password should not validate", + apr_password_validate(pass2, hash)); +} + +#ifdef GLIBCSHA_ALGO_SUPPORTED + +static struct { + const char *password; + const char *hash; +} glibc_sha_pws[] = { + /* SHA256 */ + { "secret1", "$5$0123456789abcdef$SFX.CooXBS8oXsbAPgU/UyiCodhrLQ19sBgvcA3Zh1D" }, + { "secret2", "$5$rounds=100000$0123456789abcdef$dLXfO5m4d.xv8G66kpz2LyL0.Mi5wjLlH0m7rtgyhyB" }, + /* SHA512 */ + { "secret3", "$6$0123456789abcdef$idOsOfoWwnCQkJm9hd2hxS4NnEs9nBA9poOFXsvtrYSoSHaOToCfyUoZwKe.ZCZnq7D95tGVoi2jxZZMyVwTL1" }, + { "secret4", "$6$rounds=100000$0123456789abcdef$ZiAMjbeA.iIGTWxq2oks9Bvz9sfxaoGPgAtpwimPEwFwkSNMTK7lLwABzzldds/n4UgCQ16HqawPrCrePr4YX1" }, + { NULL, NULL } +}; + +static void test_glibc_shapass(abts_case *tc, void *data) +{ + int i = 0; + while (glibc_sha_pws[i].password) { + apr_assert_success(tc, "check for valid glibc crypt-sha password", + apr_password_validate(glibc_sha_pws[i].password, + glibc_sha_pws[i].hash)); + i++; + } +} +#endif + +static void test_bcryptpass(abts_case *tc, void *data) +{ + const char *pass = "hellojed"; + const char *pass2 = "hellojed2"; + unsigned char salt[] = "sardine_sardine"; + char hash[100]; + const char *hash2 = "$2a$08$qipUJiI9fySUN38hcbz.lucXvAmtgowKOWYtB9y3CXyl6lTknruou"; + const char *pass3 = "foobar"; + + apr_assert_success(tc, "bcrypt encode password", + apr_bcrypt_encode(pass, 5, salt, sizeof(salt), hash, + sizeof(hash))); + + apr_assert_success(tc, "bcrypt password validated", + apr_password_validate(pass, hash)); + APR_ASSERT_FAILURE(tc, "wrong bcrypt password should not validate", + apr_password_validate(pass2, hash)); + apr_assert_success(tc, "bcrypt password validated", + apr_password_validate(pass3, hash2)); +} + + +abts_suite *testpass(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if CRYPT_ALGO_SUPPORTED + abts_run_test(suite, test_crypt, NULL); +#if APR_HAS_THREADS + abts_run_test(suite, test_threadsafe, NULL); +#endif +#endif /* CRYPT_ALGO_SUPPORTED */ + abts_run_test(suite, test_shapass, NULL); + abts_run_test(suite, test_md5pass, NULL); + abts_run_test(suite, test_bcryptpass, NULL); +#ifdef GLIBCSHA_ALGO_SUPPORTED + abts_run_test(suite, test_glibc_shapass, NULL); +#endif + + return suite; +} diff --git a/test/testqueue.c b/test/testqueue.c new file mode 100644 index 0000000..8f71775 --- /dev/null +++ b/test/testqueue.c @@ -0,0 +1,135 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apu.h" +#include "apr_queue.h" +#include "apr_thread_pool.h" +#include "apr_time.h" +#include "abts.h" +#include "testutil.h" + +#if APR_HAS_THREADS + +#define NUMBER_CONSUMERS 3 +#define CONSUMER_ACTIVITY 4 +#define NUMBER_PRODUCERS 4 +#define PRODUCER_ACTIVITY 5 +#define QUEUE_SIZE 100 + +static apr_queue_t *queue; + +static void * APR_THREAD_FUNC consumer(apr_thread_t *thd, void *data) +{ + long sleeprate; + abts_case *tc = data; + apr_status_t rv; + void *v; + + sleeprate = 1000000/CONSUMER_ACTIVITY; + apr_sleep((rand() % 4) * 1000000); /* sleep random seconds */ + + while (1) + { + rv = apr_queue_pop(queue, &v); + + if (rv == APR_EINTR) + continue; + + if (rv == APR_EOF) + break; + + ABTS_TRUE(tc, v == NULL); + ABTS_TRUE(tc, rv == APR_SUCCESS); + + apr_sleep(sleeprate); /* sleep this long to acheive our rate */ + } + + return NULL; +} + +static void * APR_THREAD_FUNC producer(apr_thread_t *thd, void *data) +{ + long sleeprate; + abts_case *tc = data; + apr_status_t rv; + + sleeprate = 1000000/PRODUCER_ACTIVITY; + apr_sleep((rand() % 4) * 1000000); /* sleep random seconds */ + + while (1) + { + rv = apr_queue_push(queue, NULL); + + if (rv == APR_EINTR) + continue; + + if (rv == APR_EOF) + break; + + ABTS_TRUE(tc, rv == APR_SUCCESS); + + apr_sleep(sleeprate); /* sleep this long to acheive our rate */ + } + + return NULL; +} + +static void test_queue_producer_consumer(abts_case *tc, void *data) +{ + unsigned int i; + apr_status_t rv; + apr_thread_pool_t *thrp; + + /* XXX: non-portable */ + srand((unsigned int)apr_time_now()); + + rv = apr_queue_create(&queue, QUEUE_SIZE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_thread_pool_create(&thrp, 0, NUMBER_CONSUMERS + NUMBER_PRODUCERS, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < NUMBER_CONSUMERS; i++) { + rv = apr_thread_pool_push(thrp, consumer, tc, 0, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + for (i = 0; i < NUMBER_PRODUCERS; i++) { + rv = apr_thread_pool_push(thrp, producer, tc, 0, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + apr_sleep(5000000); /* sleep 5 seconds */ + + rv = apr_queue_term(queue); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_thread_pool_destroy(thrp); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +#endif /* APR_HAS_THREADS */ + +abts_suite *testqueue(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APR_HAS_THREADS + abts_run_test(suite, test_queue_producer_consumer, NULL); +#endif /* APR_HAS_THREADS */ + + return suite; +} diff --git a/test/testredis.c b/test/testredis.c new file mode 100644 index 0000000..830c09a --- /dev/null +++ b/test/testredis.c @@ -0,0 +1,552 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testutil.h" +#include "apr.h" +#include "apu.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_redis.h" +#include "apr_network_io.h" + +#include <stdio.h> +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for exit() */ +#endif + +#define HOST "localhost" +#define PORT 6379 + +/* the total number of items to use for set/get testing */ +#define TDATA_SIZE 3000 + +/* some smaller subset of TDATA_SIZE used for multiget testing */ +#define TDATA_SET 100 + +/* our custom hash function just returns this all the time */ +#define HASH_FUNC_RESULT 510 + +/* all keys will be prefixed with this */ +static const char prefix[] = "testredis"; + +/* text for values we store */ +static const char txt[] = +"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis at" +"lacus in ligula hendrerit consectetuer. Vestibulum tristique odio" +"iaculis leo. In massa arcu, ultricies a, laoreet nec, hendrerit non," +"neque. Nulla sagittis sapien ac risus. Morbi ligula dolor, vestibulum" +"nec, viverra id, placerat dapibus, arcu. Curabitur egestas feugiat" +"tellus. Donec dignissim. Nunc ante. Curabitur id lorem. In mollis" +"tortor sit amet eros auctor dapibus. Proin nulla sem, tristique in," +"convallis id, iaculis feugiat cras amet."; + +/* + * this datatype is for our custom server determination function. this might + * be useful if you don't want to rely on simply hashing keys to determine + * where a key belongs, but instead want to write something fancy, or use some + * other kind of configuration data, i.e. a hash plus some data about a + * namespace, or whatever. see my_server_func, and test_redis_user_funcs + * for the examples. + */ +typedef struct { + const char *someval; + apr_uint32_t which_server; +} my_hash_server_baton; + + +/* this could do something fancy and return some hash result. + * for simplicity, just return the same value, so we can test it later on. + * if you wanted to use some external hashing library or functions for + * consistent hashing, for example, this would be a good place to do it. + */ +static apr_uint32_t my_hash_func(void *baton, const char *data, + apr_size_t data_len) +{ + + return HASH_FUNC_RESULT; +} + +/* + * a fancy function to determine which server to use given some kind of data + * and a hash value. this example actually ignores the hash value itself + * and pulls some number from the *baton, which is a struct that has some + * kind of meaningful stuff in it. + */ +static apr_redis_server_t *my_server_func(void *baton, + apr_redis_t *mc, + const apr_uint32_t hash) +{ + apr_redis_server_t *ms = NULL; + my_hash_server_baton *mhsb = (my_hash_server_baton *)baton; + + if(mc->ntotal == 0) { + return NULL; + } + + if(mc->ntotal < mhsb->which_server) { + return NULL; + } + + ms = mc->live_servers[mhsb->which_server - 1]; + + return ms; +} + +static apr_uint16_t firsttime = 0; +static int randval(apr_uint32_t high) +{ + apr_uint32_t i = 0; + double d = 0; + + if (firsttime == 0) { + srand((unsigned) (getpid())); + firsttime = 1; + } + + d = (double) rand() / ((double) RAND_MAX + 1); + i = (int) (d * (high - 0 + 1)); + + return i > 0 ? i : 1; +} + +/* + * general test to make sure we can create the redis struct and add + * some servers, but not more than we tell it we can add + */ + +static void test_redis_create(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *server, *s; + apr_uint32_t max_servers = 10; + apr_uint32_t i; + apr_uint32_t hash; + + rv = apr_redis_create(pool, max_servers, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + for (i = 1; i <= max_servers; i++) { + apr_port_t port; + + port = PORT + i; + rv = + apr_redis_server_create(pool, HOST, PORT + i, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + s = apr_redis_find_server(redis, HOST, port); + ABTS_PTR_EQUAL(tc, server, s); + + rv = apr_redis_disable_server(redis, s); + ABTS_ASSERT(tc, "server disable failed", rv == APR_SUCCESS); + + rv = apr_redis_enable_server(redis, s); + ABTS_ASSERT(tc, "server enable failed", rv == APR_SUCCESS); + + hash = apr_redis_hash(redis, prefix, strlen(prefix)); + ABTS_ASSERT(tc, "hash failed", hash > 0); + + s = apr_redis_find_server_hash(redis, hash); + ABTS_PTR_NOTNULL(tc, s); + } + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add should have failed", rv != APR_SUCCESS); + +} + +/* install our own custom hashing and server selection routines. */ + +static int create_test_hash(apr_pool_t *p, apr_hash_t *h) +{ + int i; + + for (i = 0; i < TDATA_SIZE; i++) { + char *k, *v; + + k = apr_pstrcat(p, prefix, apr_itoa(p, i), NULL); + v = apr_pstrndup(p, txt, randval((apr_uint32_t)strlen(txt))); + + apr_hash_set(h, k, APR_HASH_KEY_STRING, v); + } + + return i; +} + +static void test_redis_user_funcs(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *found; + apr_uint32_t max_servers = 10; + apr_uint32_t hres; + apr_uint32_t i; + my_hash_server_baton *baton = + apr_pcalloc(pool, sizeof(my_hash_server_baton)); + + rv = apr_redis_create(pool, max_servers, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + /* as noted above, install our custom hash function, and call + * apr_redis_hash. the return value should be our predefined number, + * and our function just ignores the other args, for simplicity. + */ + redis->hash_func = my_hash_func; + + hres = apr_redis_hash(redis, "whatever", sizeof("whatever") - 1); + ABTS_INT_EQUAL(tc, HASH_FUNC_RESULT, hres); + + /* add some servers */ + for(i = 1; i <= 10; i++) { + apr_redis_server_t *ms; + + rv = apr_redis_server_create(pool, HOST, i, 0, 1, 1, 60, 60, &ms); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, ms); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + } + + /* + * set 'which_server' in our server_baton to find the third server + * which should have the same port. + */ + baton->which_server = 3; + redis->server_func = my_server_func; + redis->server_baton = baton; + found = apr_redis_find_server_hash(redis, 0); + ABTS_ASSERT(tc, "wrong server found", found->port == baton->which_server); +} + +/* test non data related commands like stats and version */ +static void test_redis_meta(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_redis_t *redis; + apr_redis_server_t *server; + apr_redis_stats_t *stats; + char *result; + apr_status_t rv; + + rv = apr_redis_create(pool, 1, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + apr_redis_version(server, pool, &result); + ABTS_PTR_NOTNULL(tc, result); + + apr_redis_stats(server, p, &stats); + ABTS_PTR_NOTNULL(tc, stats); + + /* + * no way to know exactly what will be in most of these, so + * just make sure there is something. + */ + ABTS_ASSERT(tc, "major", stats->major >= 1); + ABTS_ASSERT(tc, "minor", stats->minor >= 0); + ABTS_ASSERT(tc, "patch", stats->patch >= 0); + ABTS_ASSERT(tc, "process_id", stats->process_id >= 0); + ABTS_ASSERT(tc, "uptime_in_seconds", stats->uptime_in_seconds >= 0); + ABTS_ASSERT(tc, "arch_bits", stats->arch_bits >= 0); + ABTS_ASSERT(tc, "connected_clients", stats->connected_clients >= 0); + ABTS_ASSERT(tc, "blocked_clients", stats->blocked_clients >= 0); + ABTS_ASSERT(tc, "maxmemory", stats->maxmemory >= 0); + ABTS_ASSERT(tc, "used_memory", stats->used_memory >= 0); + ABTS_ASSERT(tc, "total_system_memory", stats->total_system_memory >= 0); + ABTS_ASSERT(tc, "total_connections_received", stats->total_connections_received >= 0); + ABTS_ASSERT(tc, "total_commands_processed", stats->total_commands_processed >= 0); + ABTS_ASSERT(tc, "total_net_input_bytes", stats->total_net_input_bytes >= 0); + ABTS_ASSERT(tc, "total_net_output_bytes", stats->total_net_output_bytes >= 0); + ABTS_ASSERT(tc, "keyspace_hits", stats->keyspace_hits >= 0); + ABTS_ASSERT(tc, "keyspace_misses", stats->keyspace_misses >= 0); + ABTS_ASSERT(tc, "role", stats->role >= 0); + ABTS_ASSERT(tc, "connected_slaves", stats->connected_slaves >= 0); + ABTS_ASSERT(tc, "used_cpu_sys", stats->used_cpu_sys >= 0); + ABTS_ASSERT(tc, "used_cpu_user", stats->used_cpu_user >= 0); + ABTS_ASSERT(tc, "cluster_enabled", stats->cluster_enabled >= 0); +} + + +/* basic tests of the increment and decrement commands */ +static void test_redis_incrdecr(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *server; + apr_uint32_t new; + char *result; + apr_size_t len; + apr_uint32_t i; + + rv = apr_redis_create(pool, 1, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + rv = apr_redis_set(redis, prefix, "271", sizeof("271") - 1, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + + for( i = 1; i <= TDATA_SIZE; i++) { + apr_uint32_t expect; + + rv = apr_redis_getp(redis, pool, prefix, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + + expect = i + atoi(result); + + rv = apr_redis_incr(redis, prefix, i, &new); + ABTS_ASSERT(tc, "incr failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, expect, new); + + rv = apr_redis_decr(redis, prefix, i, &new); + ABTS_ASSERT(tc, "decr failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, atoi(result), new); + + } + + rv = apr_redis_getp(redis, pool, prefix, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, 271, atoi(result)); + + rv = apr_redis_delete(redis, prefix, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); +} + + +/* test setting and getting */ + +static void test_redis_setget(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *server; + apr_hash_t *tdata; + apr_hash_index_t *hi; + char *result; + apr_size_t len; + + rv = apr_redis_create(pool, 1, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + tdata = apr_hash_make(pool); + + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + rv = apr_redis_set(redis, key, v, strlen(v), 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + rv = apr_redis_getp(redis, pool, key, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + } + + rv = apr_redis_getp(redis, pool, "nothere3423", &result, &len, NULL); + + ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + const char *key; + + apr_hash_this(hi, &k, NULL, NULL); + key = k; + + rv = apr_redis_delete(redis, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } +} + +/* test setting and getting */ + +static void test_redis_setexget(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *server; + apr_hash_t *tdata; + apr_hash_index_t *hi; + char *result; + apr_size_t len; + + rv = apr_redis_create(pool, 1, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + tdata = apr_hash_make(pool); + + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + rv = apr_redis_ping(server); + ABTS_ASSERT(tc, "ping failed", rv == APR_SUCCESS); + rv = apr_redis_setex(redis, key, v, strlen(v), 10, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + rv = apr_redis_getp(redis, pool, key, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + } + + rv = apr_redis_getp(redis, pool, "nothere3423", &result, &len, NULL); + + ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + const char *key; + + apr_hash_this(hi, &k, NULL, NULL); + key = k; + + rv = apr_redis_delete(redis, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } +} + +/* use apr_socket stuff to see if there is in fact a Redis server + * running on PORT. + */ +static apr_status_t check_redis(void) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_socket_t *sock = NULL; + apr_sockaddr_t *sa; + struct iovec vec[2]; + apr_size_t written; + char buf[128]; + apr_size_t len; + + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, pool); + if(rv != APR_SUCCESS) { + return rv; + } + + rv = apr_sockaddr_info_get(&sa, HOST, APR_INET, PORT, 0, pool); + if(rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(sock, 1 * APR_USEC_PER_SEC); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_connect(sock, sa); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(sock, -1); + if (rv != APR_SUCCESS) { + return rv; + } + + vec[0].iov_base = "PING"; + vec[0].iov_len = sizeof("PING") - 1; + + vec[1].iov_base = "\r\n"; + vec[1].iov_len = sizeof("\r\n") -1; + + rv = apr_socket_sendv(sock, vec, 2, &written); + if (rv != APR_SUCCESS) { + return rv; + } + + len = sizeof(buf); + rv = apr_socket_recv(sock, buf, &len); + if(rv != APR_SUCCESS) { + return rv; + } + if(strncmp(buf, "+PONG", sizeof("+PONG")-1) != 0) { + rv = APR_EGENERAL; + } + + apr_socket_close(sock); + return rv; +} + +abts_suite *testredis(abts_suite * suite) +{ + apr_status_t rv; + suite = ADD_SUITE(suite); + /* check for a running redis on the typical port before + * trying to run the tests. succeed if we don't find one. + */ + rv = check_redis(); + if (rv == APR_SUCCESS) { + abts_run_test(suite, test_redis_create, NULL); + abts_run_test(suite, test_redis_user_funcs, NULL); + abts_run_test(suite, test_redis_meta, NULL); + abts_run_test(suite, test_redis_setget, NULL); + abts_run_test(suite, test_redis_setexget, NULL); + /* abts_run_test(suite, test_redis_multiget, NULL); */ + abts_run_test(suite, test_redis_incrdecr, NULL); + } + else { + abts_log_message("Error %d occurred attempting to reach Redis " + "on %s:%d. Skipping apr_redis tests...", + rv, HOST, PORT); + } + + return suite; +} diff --git a/test/testreslist.c b/test/testreslist.c new file mode 100644 index 0000000..eef848f --- /dev/null +++ b/test/testreslist.c @@ -0,0 +1,311 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "apr_general.h" +#include "apu.h" +#include "apr_reslist.h" +#include "apr_thread_pool.h" + +#if APR_HAVE_TIME_H +#include <time.h> +#endif /* APR_HAVE_TIME_H */ + +#include "abts.h" +#include "testutil.h" + +#if APR_HAS_THREADS + +#define RESLIST_MIN 3 +#define RESLIST_SMAX 10 +#define RESLIST_HMAX 20 +#define RESLIST_TTL APR_TIME_C(35000) /* 35 ms */ +#define CONSUMER_THREADS 25 +#define CONSUMER_ITERATIONS 100 +#define CONSTRUCT_SLEEP_TIME APR_TIME_C(25000) /* 25 ms */ +#define DESTRUCT_SLEEP_TIME APR_TIME_C(10000) /* 10 ms */ +#define WORK_DELAY_SLEEP_TIME APR_TIME_C(15000) /* 15 ms */ + +typedef struct { + apr_interval_time_t sleep_upon_construct; + apr_interval_time_t sleep_upon_destruct; + int c_count; + int d_count; +} my_parameters_t; + +typedef struct { + int id; +} my_resource_t; + +/* Linear congruential generator */ +static apr_uint32_t lgc(apr_uint32_t a) +{ + apr_uint64_t z = a; + z *= 279470273; + z %= APR_UINT64_C(4294967291); + return (apr_uint32_t)z; +} + +static apr_status_t my_constructor(void **resource, void *params, + apr_pool_t *pool) +{ + my_resource_t *res; + my_parameters_t *my_params = params; + + /* Create some resource */ + res = apr_palloc(pool, sizeof(*res)); + res->id = my_params->c_count++; + + /* Sleep for awhile, to simulate construction overhead. */ + apr_sleep(my_params->sleep_upon_construct); + + /* Set the resource so it can be managed by the reslist */ + *resource = res; + return APR_SUCCESS; +} + +static apr_status_t my_destructor(void *resource, void *params, + apr_pool_t *pool) +{ + my_resource_t *res = resource; + my_parameters_t *my_params = params; + res->id = my_params->d_count++; + + apr_sleep(my_params->sleep_upon_destruct); + + return APR_SUCCESS; +} + +typedef struct { + int tid; + abts_case *tc; + apr_reslist_t *reslist; + apr_interval_time_t work_delay_sleep; +} my_thread_info_t; + +/* MAX_UINT * .95 = 2**32 * .95 = 4080218931u */ +#define PERCENT95th 4080218931u + +static void * APR_THREAD_FUNC resource_consuming_thread(apr_thread_t *thd, + void *data) +{ + int i; + apr_uint32_t chance; + void *vp; + apr_status_t rv; + my_resource_t *res; + my_thread_info_t *thread_info = data; + apr_reslist_t *rl = thread_info->reslist; + +#if APR_HAS_RANDOM + apr_generate_random_bytes((void*)&chance, sizeof(chance)); +#else + chance = (apr_uint32_t)(apr_time_now() % APR_TIME_C(4294967291)); +#endif + + for (i = 0; i < CONSUMER_ITERATIONS; i++) { + rv = apr_reslist_acquire(rl, &vp); + ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv); + res = vp; + apr_sleep(thread_info->work_delay_sleep); + + /* simulate a 5% chance of the resource being bad */ + chance = lgc(chance); + if ( chance < PERCENT95th ) { + rv = apr_reslist_release(rl, res); + ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv); + } else { + rv = apr_reslist_invalidate(rl, res); + ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv); + } + } + + return APR_SUCCESS; +} + +static void test_timeout(abts_case *tc, apr_reslist_t *rl) +{ + apr_status_t rv; + my_resource_t *resources[RESLIST_HMAX]; + void *vp; + int i; + + apr_reslist_timeout_set(rl, 1000); + + /* deplete all possible resources from the resource list + * so that the next call will block until timeout is reached + * (since there are no other threads to make a resource + * available) + */ + + for (i = 0; i < RESLIST_HMAX; i++) { + rv = apr_reslist_acquire(rl, (void**)&resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + /* next call will block until timeout is reached */ + rv = apr_reslist_acquire(rl, &vp); + ABTS_TRUE(tc, APR_STATUS_IS_TIMEUP(rv)); + + /* release the resources; otherwise the destroy operation + * will blow + */ + for (i = 0; i < RESLIST_HMAX; i++) { + rv = apr_reslist_release(rl, resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } +} + +static void test_shrinking(abts_case *tc, apr_reslist_t *rl) +{ + apr_status_t rv; + my_resource_t *resources[RESLIST_HMAX]; + my_resource_t *res; + void *vp; + int i; + int sleep_time = RESLIST_TTL / RESLIST_HMAX; + + /* deplete all possible resources from the resource list */ + for (i = 0; i < RESLIST_HMAX; i++) { + rv = apr_reslist_acquire(rl, (void**)&resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + /* Free all resources above RESLIST_SMAX - 1 */ + for (i = RESLIST_SMAX - 1; i < RESLIST_HMAX; i++) { + rv = apr_reslist_release(rl, resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + for (i = 0; i < RESLIST_HMAX; i++) { + rv = apr_reslist_acquire(rl, &vp); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + res = vp; + apr_sleep(sleep_time); + rv = apr_reslist_release(rl, res); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + apr_sleep(sleep_time); + + /* + * Now free the remaining elements. This should trigger the shrinking of + * the list + */ + for (i = 0; i < RESLIST_SMAX - 1; i++) { + rv = apr_reslist_release(rl, resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } +} + +static void test_reslist(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_reslist_t *rl; + my_parameters_t *params; + apr_thread_pool_t *thrp; + my_thread_info_t thread_info[CONSUMER_THREADS]; + + rv = apr_thread_pool_create(&thrp, CONSUMER_THREADS/2, CONSUMER_THREADS, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Create some parameters that will be passed into each + * constructor and destructor call. */ + params = apr_pcalloc(p, sizeof(*params)); + params->sleep_upon_construct = CONSTRUCT_SLEEP_TIME; + params->sleep_upon_destruct = DESTRUCT_SLEEP_TIME; + + /* We're going to want 10 blocks of data from our target rmm. */ + rv = apr_reslist_create(&rl, RESLIST_MIN, RESLIST_SMAX, RESLIST_HMAX, + RESLIST_TTL, my_constructor, my_destructor, + params, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < CONSUMER_THREADS; i++) { + thread_info[i].tid = i; + thread_info[i].tc = tc; + thread_info[i].reslist = rl; + thread_info[i].work_delay_sleep = WORK_DELAY_SLEEP_TIME; + rv = apr_thread_pool_push(thrp, resource_consuming_thread, + &thread_info[i], 0, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + rv = apr_thread_pool_destroy(thrp); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + test_timeout(tc, rl); + + test_shrinking(tc, rl); + ABTS_INT_EQUAL(tc, RESLIST_SMAX, params->c_count - params->d_count); + + rv = apr_reslist_destroy(rl); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_reslist_no_ttl(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_reslist_t *rl; + my_parameters_t *params; + my_resource_t *res; + + /* Parameters (sleep not used) */ + params = apr_pcalloc(p, sizeof(*params)); + + rv = apr_reslist_create(&rl, + /*no min*/0, /*no smax*/0, /*max*/1, /*no ttl*/0, + my_constructor, my_destructor, params, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Acquire/contruct one resource */ + rv = apr_reslist_acquire(rl, (void **)&res); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 0, res->id); + + /* Release it before next check */ + rv = apr_reslist_release(rl, res); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Re-acquire/release: the resource should be the same */ + rv = apr_reslist_acquire(rl, (void **)&res); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 0, res->id); + + /* Release it before cleanup */ + rv = apr_reslist_release(rl, res); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_reslist_destroy(rl); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, params->d_count, 1); +} + +#endif /* APR_HAS_THREADS */ + +abts_suite *testreslist(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APR_HAS_THREADS + abts_run_test(suite, test_reslist, NULL); + abts_run_test(suite, test_reslist_no_ttl, NULL); +#endif + + return suite; +} diff --git a/test/testrmm.c b/test/testrmm.c new file mode 100644 index 0000000..4f8fb5e --- /dev/null +++ b/test/testrmm.c @@ -0,0 +1,191 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr_shm.h" +#include "apr_rmm.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_time.h" +#include "abts.h" +#include "testutil.h" + +#if APR_HAS_SHARED_MEMORY + +#define FRAG_SIZE 80 +#define FRAG_COUNT 10 +#define SHARED_SIZE (apr_size_t)(FRAG_SIZE * FRAG_COUNT * sizeof(char*)) + +static void test_rmm(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_pool_t *pool; + apr_shm_t *shm; + apr_rmm_t *rmm; + apr_size_t size, fragsize; + apr_rmm_off_t *off, off2; + int i; + void *entity; + + rv = apr_pool_create(&pool, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* We're going to want 10 blocks of data from our target rmm. */ + size = SHARED_SIZE + apr_rmm_overhead_get(FRAG_COUNT + 1); + rv = apr_shm_create(&shm, size, NULL, pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + rv = apr_rmm_init(&rmm, NULL, apr_shm_baseaddr_get(shm), size, pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + /* Creating each fragment of size fragsize */ + fragsize = SHARED_SIZE / FRAG_COUNT; + off = apr_palloc(pool, FRAG_COUNT * sizeof(apr_rmm_off_t)); + for (i = 0; i < FRAG_COUNT; i++) { + off[i] = apr_rmm_malloc(rmm, fragsize); + } + + /* Checking for out of memory allocation */ + off2 = apr_rmm_malloc(rmm, FRAG_SIZE * FRAG_COUNT); + ABTS_TRUE(tc, !off2); + + /* Checking each fragment for address alignment */ + for (i = 0; i < FRAG_COUNT; i++) { + char *c = apr_rmm_addr_get(rmm, off[i]); + apr_size_t sc = (apr_size_t)c; + + ABTS_TRUE(tc, !!off[i]); + ABTS_TRUE(tc, !(sc & 7)); + } + + /* Setting each fragment to a unique value */ + for (i = 0; i < FRAG_COUNT; i++) { + int j; + char **c = apr_rmm_addr_get(rmm, off[i]); + for (j = 0; j < FRAG_SIZE; j++, c++) { + *c = apr_itoa(pool, i + j); + } + } + + /* Checking each fragment for its unique value */ + for (i = 0; i < FRAG_COUNT; i++) { + int j; + char **c = apr_rmm_addr_get(rmm, off[i]); + for (j = 0; j < FRAG_SIZE; j++, c++) { + char *d = apr_itoa(pool, i + j); + ABTS_STR_EQUAL(tc, d, *c); + } + } + + /* Freeing each fragment */ + for (i = 0; i < FRAG_COUNT; i++) { + rv = apr_rmm_free(rmm, off[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + /* Creating one large segment */ + off[0] = apr_rmm_calloc(rmm, SHARED_SIZE); + + /* Setting large segment */ + for (i = 0; i < FRAG_COUNT * FRAG_SIZE; i++) { + char **c = apr_rmm_addr_get(rmm, off[0]); + c[i] = apr_itoa(pool, i); + } + + /* Freeing large segment */ + rv = apr_rmm_free(rmm, off[0]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Creating each fragment of size fragsize */ + for (i = 0; i < FRAG_COUNT; i++) { + off[i] = apr_rmm_malloc(rmm, fragsize); + } + + /* Freeing each fragment backwards */ + for (i = FRAG_COUNT - 1; i >= 0; i--) { + rv = apr_rmm_free(rmm, off[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + /* Creating one large segment (again) */ + off[0] = apr_rmm_calloc(rmm, SHARED_SIZE); + + /* Freeing large segment */ + rv = apr_rmm_free(rmm, off[0]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Checking realloc */ + off[0] = apr_rmm_calloc(rmm, SHARED_SIZE - 100); + off[1] = apr_rmm_calloc(rmm, 100); + ABTS_TRUE(tc, !!off[0]); + ABTS_TRUE(tc, !!off[1]); + + entity = apr_rmm_addr_get(rmm, off[1]); + rv = apr_rmm_free(rmm, off[0]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + { + unsigned char *c = entity; + + /* Fill in the region; the first half with zereos, which will + * likely catch the apr_rmm_realloc offset calculation bug by + * making it think the old region was zero length. */ + for (i = 0; i < 100; i++) { + c[i] = (i < 50) ? 0 : i; + } + } + + /* now we can realloc off[1] and get many more bytes */ + off[0] = apr_rmm_realloc(rmm, entity, SHARED_SIZE - 100); + ABTS_TRUE(tc, !!off[0]); + + { + unsigned char *c = apr_rmm_addr_get(rmm, off[0]); + + /* fill in the region */ + for (i = 0; i < 100; i++) { + ABTS_TRUE(tc, c[i] == (i < 50 ? 0 : i)); + } + } + + rv = apr_rmm_destroy(rmm); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_shm_destroy(shm); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + apr_pool_destroy(pool); +} + +#endif /* APR_HAS_SHARED_MEMORY */ + +abts_suite *testrmm(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APR_HAS_SHARED_MEMORY + abts_run_test(suite, test_rmm, NULL); +#endif + + return suite; +} diff --git a/test/testsiphash.c b/test/testsiphash.c new file mode 100644 index 0000000..58321ad --- /dev/null +++ b/test/testsiphash.c @@ -0,0 +1,148 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "apr_siphash.h" + +#include "abts.h" +#include "testutil.h" + +/* + * Wrapped test vectors from the authors, see + * https://131002.net/siphash/siphash24.c + */ +typedef unsigned char u8; +#define crypto_auth apr_siphash24_auth + +#define MAXLEN 64 + +/* + SipHash-2-4 output with + k = 00 01 02 ... + and + in = (empty string) + in = 00 (1 byte) + in = 00 01 (2 bytes) + in = 00 01 02 (3 bytes) + ... + in = 00 01 02 ... 3e (63 bytes) +*/ +static const u8 vectors[MAXLEN][8] = +{ + { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, }, + { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, }, + { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, }, + { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, }, + { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, }, + { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, }, + { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, }, + { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, }, + { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, }, + { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, }, + { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, }, + { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, }, + { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, }, + { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, }, + { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, }, + { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, }, + { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, }, + { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, }, + { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, }, + { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, }, + { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, }, + { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, }, + { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, }, + { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, }, + { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, }, + { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, }, + { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, }, + { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, }, + { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, }, + { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, }, + { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, }, + { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, }, + { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, }, + { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, }, + { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, }, + { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, }, + { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, }, + { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, }, + { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, }, + { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, }, + { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, }, + { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, }, + { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, }, + { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, }, + { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, }, + { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, }, + { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, }, + { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, }, + { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, }, + { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, }, + { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, }, + { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, }, + { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, }, + { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, }, + { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, }, + { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, }, + { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, }, + { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, }, + { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, }, + { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, }, + { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, }, + { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, }, + { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, }, + { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, } +}; + +static int test_vectors(void) +{ + u8 in[MAXLEN], out[8], k[16]; + int i; + int ok = 1; + + for( i = 0; i < 16; ++i ) k[i] = i; + + for( i = 0; i < MAXLEN; ++i ) + { + in[i] = i; + crypto_auth( out, in, i, k ); + + if ( memcmp( out, vectors[i], 8 ) ) + { + printf( "test vector failed for %d bytes\n", i ); + ok = 0; + } + } + + return ok; +} + +static void test_siphash_vectors(abts_case *tc, void *data) +{ + ABTS_ASSERT(tc, "SipHash-2-4 test vectors", test_vectors()); +} + +abts_suite *testsiphash(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_siphash_vectors, NULL); + + return suite; +} diff --git a/test/teststrmatch.c b/test/teststrmatch.c new file mode 100644 index 0000000..b6a4a12 --- /dev/null +++ b/test/teststrmatch.c @@ -0,0 +1,92 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testutil.h" + +#include "apr.h" +#include "apr_general.h" +#include "apr_strmatch.h" +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#define APR_WANT_STDIO +#define APR_WANT_STRFUNC +#include "apr_want.h" + +static void test_str(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + const apr_strmatch_pattern *pattern; + const apr_strmatch_pattern *pattern_nocase; + const apr_strmatch_pattern *pattern_onechar; + const apr_strmatch_pattern *pattern_zero; + const char *match = NULL; + const char *input1 = "string that contains a patterN..."; + const char *input2 = "string that contains a pattern..."; + const char *input3 = "pattern at the start of a string"; + const char *input4 = "string that ends with a pattern"; + const char *input5 = "patter\200n not found, negative chars in input"; + const char *input6 = "patter\200n, negative chars, contains pattern..."; + + pattern = apr_strmatch_precompile(pool, "pattern", 1); + ABTS_PTR_NOTNULL(tc, pattern); + + pattern_nocase = apr_strmatch_precompile(pool, "pattern", 0); + ABTS_PTR_NOTNULL(tc, pattern_nocase); + + pattern_onechar = apr_strmatch_precompile(pool, "g", 0); + ABTS_PTR_NOTNULL(tc, pattern_onechar); + + pattern_zero = apr_strmatch_precompile(pool, "", 0); + ABTS_PTR_NOTNULL(tc, pattern_zero); + + match = apr_strmatch(pattern, input1, strlen(input1)); + ABTS_PTR_EQUAL(tc, NULL, match); + + match = apr_strmatch(pattern, input2, strlen(input2)); + ABTS_PTR_EQUAL(tc, input2 + 23, match); + + match = apr_strmatch(pattern_onechar, input1, strlen(input1)); + ABTS_PTR_EQUAL(tc, input1 + 5, match); + + match = apr_strmatch(pattern_zero, input1, strlen(input1)); + ABTS_PTR_EQUAL(tc, input1, match); + + match = apr_strmatch(pattern_nocase, input1, strlen(input1)); + ABTS_PTR_EQUAL(tc, input1 + 23, match); + + match = apr_strmatch(pattern, input3, strlen(input3)); + ABTS_PTR_EQUAL(tc, input3, match); + + match = apr_strmatch(pattern, input4, strlen(input4)); + ABTS_PTR_EQUAL(tc, input4 + 24, match); + + match = apr_strmatch(pattern, input5, strlen(input5)); + ABTS_PTR_EQUAL(tc, NULL, match); + + match = apr_strmatch(pattern, input6, strlen(input6)); + ABTS_PTR_EQUAL(tc, input6 + 35, match); +} + +abts_suite *teststrmatch(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_str, NULL); + + return suite; +} + diff --git a/test/testuri.c b/test/testuri.c new file mode 100644 index 0000000..4c5405a --- /dev/null +++ b/test/testuri.c @@ -0,0 +1,331 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "testutil.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_uri.h" + +struct aup_test { + const char *uri; + apr_status_t rv; + const char *scheme; + const char *hostinfo; + const char *user; + const char *password; + const char *hostname; + const char *port_str; + const char *path; + const char *query; + const char *fragment; + apr_port_t port; +}; + +struct aup_test aup_tests[] = +{ + { "http://[/::1]/index.html", APR_EGENERAL }, + { "http://[", APR_EGENERAL }, + { "http://[?::1]/index.html", APR_EGENERAL }, + + { + "http://127.0.0.1:9999/asdf.html", + 0, "http", "127.0.0.1:9999", NULL, NULL, "127.0.0.1", "9999", "/asdf.html", NULL, NULL, 9999 + }, + { + "http://127.0.0.1:9999a/asdf.html", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "http://[::127.0.0.1]:9999/asdf.html", + 0, "http", "[::127.0.0.1]:9999", NULL, NULL, "::127.0.0.1", "9999", "/asdf.html", NULL, NULL, 9999 + }, + { + "http://[::127.0.0.1]:9999a/asdf.html", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "/error/include/top.html", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/error/include/top.html", NULL, NULL, 0 + }, + { + "/error/include/../contact.html.var", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/error/include/../contact.html.var", NULL, NULL, 0 + }, + { + "/", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/", NULL, NULL, 0 + }, + { + "/manual/", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/manual/", NULL, NULL, 0 + }, + { + "/cocoon/developing/graphics/Using%20Databases-label_over.jpg", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/cocoon/developing/graphics/Using%20Databases-label_over.jpg", NULL, NULL, 0 + }, + { + "http://sonyamt:garbage@127.0.0.1/filespace/", + 0, "http", "sonyamt:garbage@127.0.0.1", "sonyamt", "garbage", "127.0.0.1", NULL, "/filespace/", NULL, NULL, 0 + }, + { + "http://sonyamt:garbage@[fe80::1]/filespace/", + 0, "http", "sonyamt:garbage@[fe80::1]", "sonyamt", "garbage", "fe80::1", NULL, "/filespace/", NULL, NULL, 0 + }, + { + "http://sonyamt@[fe80::1]/filespace/?arg1=store", + 0, "http", "sonyamt@[fe80::1]", "sonyamt", NULL, "fe80::1", NULL, "/filespace/", "arg1=store", NULL, 0 + }, + { + "http://localhost", + 0, "http", "localhost", NULL, NULL, "localhost", NULL, NULL, NULL, NULL, 0 + }, + { + "//www.apache.org/", + 0, NULL, "www.apache.org", NULL, NULL, "www.apache.org", NULL, "/", NULL, NULL, 0 + }, + { + "file:image.jpg", + 0, "file", NULL, NULL, NULL, NULL, NULL, "image.jpg", NULL, NULL, 0 + }, + { + "file:/image.jpg", + 0, "file", NULL, NULL, NULL, NULL, NULL, "/image.jpg", NULL, NULL, 0 + }, + { + "file:///image.jpg", + 0, "file", "", NULL, NULL, "", NULL, "/image.jpg", NULL, NULL, 0 + }, + { + "file:///tmp/photos/image.jpg", + 0, "file", "", NULL, NULL, "", NULL, "/tmp/photos/image.jpg", NULL, NULL, 0 + }, + { + "file:./image.jpg", + 0, "file", NULL, NULL, NULL, NULL, NULL, "./image.jpg", NULL, NULL, 0 + }, + { + "file:../photos/image.jpg", + 0, "file", NULL, NULL, NULL, NULL, NULL, "../photos/image.jpg", NULL, NULL, 0 + }, + { + "file+ssh-2:../photos/image.jpg", + 0, "file+ssh-2", NULL, NULL, NULL, NULL, NULL, "../photos/image.jpg", NULL, NULL, 0 + }, + { + "script/foo.js", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "script/foo.js", NULL, NULL, 0 + }, + { + "../foo2.js", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "../foo2.js", NULL, NULL, 0 + }, + { + "foo3.js", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "foo3.js", NULL, NULL, 0 + }, + { + "_foo/bar", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "_foo/bar", NULL, NULL, 0 + }, + { + "_foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "2foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + ".foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "-foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "+foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "::/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + ":/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + ":foo", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + ":", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "@localhost::8080", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, +}; + +struct uph_test { + const char *hostinfo; + apr_status_t rv; + const char *hostname; + const char *port_str; + apr_port_t port; +}; + +struct uph_test uph_tests[] = +{ + { + "www.ibm.com:443", + 0, "www.ibm.com", "443", 443 + }, + { + "[fe80::1]:443", + 0, "fe80::1", "443", 443 + }, + { + "127.0.0.1:443", + 0, "127.0.0.1", "443", 443 + }, + { + "127.0.0.1", + APR_EGENERAL, NULL, NULL, 0 + }, + { + "[fe80:80", + APR_EGENERAL, NULL, NULL, 0 + }, + { + "fe80::80]:443", + APR_EGENERAL, NULL, NULL, 0 + } +}; + +#if 0 +static void show_info(apr_status_t rv, apr_status_t expected, const apr_uri_t *info) +{ + if (rv != expected) { + fprintf(stderr, " actual rv: %d expected rv: %d\n", rv, expected); + } + else { + fprintf(stderr, + " scheme: %s\n" + " hostinfo: %s\n" + " user: %s\n" + " password: %s\n" + " hostname: %s\n" + " port_str: %s\n" + " path: %s\n" + " query: %s\n" + " fragment: %s\n" + " hostent: %p\n" + " port: %u\n" + " is_initialized: %u\n" + " dns_looked_up: %u\n" + " dns_resolved: %u\n", + info->scheme, info->hostinfo, info->user, info->password, + info->hostname, info->port_str, info->path, info->query, + info->fragment, info->hostent, info->port, info->is_initialized, + info->dns_looked_up, info->dns_resolved); + } +} +#endif + +static void test_aup(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_uri_t info; + struct aup_test *t; + const char *s = NULL; + + for (i = 0; i < sizeof(aup_tests) / sizeof(aup_tests[0]); i++) { + char msg[256]; + + memset(&info, 0, sizeof(info)); + t = &aup_tests[i]; + rv = apr_uri_parse(p, t->uri, &info); + apr_snprintf(msg, sizeof msg, "uri '%s': rv=%d not %d", t->uri, + rv, t->rv); + ABTS_ASSERT(tc, msg, rv == t->rv); + if (t->rv == APR_SUCCESS) { + ABTS_STR_EQUAL(tc, t->scheme, info.scheme); + ABTS_STR_EQUAL(tc, t->hostinfo, info.hostinfo); + ABTS_STR_EQUAL(tc, t->user, info.user); + ABTS_STR_EQUAL(tc, t->password, info.password); + ABTS_STR_EQUAL(tc, t->hostname, info.hostname); + ABTS_STR_EQUAL(tc, t->port_str, info.port_str); + ABTS_STR_EQUAL(tc, t->path, info.path); + ABTS_STR_EQUAL(tc, t->query, info.query); + ABTS_STR_EQUAL(tc, t->user, info.user); + ABTS_INT_EQUAL(tc, t->port, info.port); + + s = apr_uri_unparse(p, &info, APR_URI_UNP_REVEALPASSWORD); + ABTS_STR_EQUAL(tc, t->uri, s); + + s = apr_uri_unparse(p, &info, APR_URI_UNP_OMITSITEPART); + apr_uri_parse(p, s, &info); + ABTS_STR_EQUAL(tc, info.scheme, NULL); + ABTS_STR_EQUAL(tc, info.hostinfo, NULL); + ABTS_STR_EQUAL(tc, info.user, NULL); + ABTS_STR_EQUAL(tc, info.password, NULL); + ABTS_STR_EQUAL(tc, info.hostname, NULL); + ABTS_STR_EQUAL(tc, info.port_str, NULL); + ABTS_STR_EQUAL(tc, info.path, t->path); + ABTS_STR_EQUAL(tc, info.query, t->query); + ABTS_STR_EQUAL(tc, info.user, NULL); + ABTS_INT_EQUAL(tc, info.port, 0); + } + } +} + +static void test_uph(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_uri_t info; + struct uph_test *t; + + for (i = 0; i < sizeof(uph_tests) / sizeof(uph_tests[0]); i++) { + memset(&info, 0, sizeof(info)); + t = &uph_tests[i]; + rv = apr_uri_parse_hostinfo(p, t->hostinfo, &info); + ABTS_INT_EQUAL(tc, t->rv, rv); + if (t->rv == APR_SUCCESS) { + ABTS_STR_EQUAL(tc, t->hostname, info.hostname); + ABTS_STR_EQUAL(tc, t->port_str, info.port_str); + ABTS_INT_EQUAL(tc, t->port, info.port); + } + } +} + +abts_suite *testuri(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_aup, NULL); + abts_run_test(suite, test_uph, NULL); + + return suite; +} + diff --git a/test/testutil.c b/test/testutil.c new file mode 100644 index 0000000..e5f8460 --- /dev/null +++ b/test/testutil.c @@ -0,0 +1,60 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "abts.h" +#include "testutil.h" +#include "apr_pools.h" + +apr_pool_t *p; + +void apr_assert_success(abts_case* tc, const char* context, apr_status_t rv) +{ + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, context); + } + + if (rv != APR_SUCCESS) { + char buf[STRING_MAX], ebuf[128]; + sprintf(buf, "%s (%d): %s\n", context, rv, + apr_strerror(rv, ebuf, sizeof ebuf)); + ABTS_FAIL(tc, buf); + } +} + +void apr_assert_failure(abts_case* tc, const char* context, apr_status_t rv, + int lineno) +{ + if (rv == APR_ENOTIMPL) { + abts_not_impl(tc, context, lineno); + } else if (rv == APR_SUCCESS) { + char buf[STRING_MAX]; + sprintf(buf, "%s (%d): expected failure, got success\n", context, rv); + abts_fail(tc, buf, lineno); + } +} + +void initialize(void) { + if (apr_initialize() != APR_SUCCESS) { + abort(); + } + atexit(apr_terminate); + + apr_pool_create(&p, NULL); + apr_pool_tag(p, "apr-util global test pool"); +} diff --git a/test/testutil.h b/test/testutil.h new file mode 100644 index 0000000..eaa7e75 --- /dev/null +++ b/test/testutil.h @@ -0,0 +1,73 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr_pools.h" +#include "abts.h" + +#ifndef APR_TEST_UTIL +#define APR_TEST_UTIL + +/* XXX FIXME */ +#ifdef WIN32 +#define EXTENSION ".exe" +#elif NETWARE +#define EXTENSION ".nlm" +#else +#define EXTENSION +#endif + +#define STRING_MAX 8096 + +/* Some simple functions to make the test apps easier to write and + * a bit more consistent... + */ + +extern apr_pool_t *p; + +/* Assert that RV is an APR_SUCCESS value; else fail giving strerror + * for RV and CONTEXT message. */ +void apr_assert_success(abts_case* tc, const char *context, apr_status_t rv); + +void apr_assert_failure(abts_case* tc, const char *context, + apr_status_t rv, int lineno); +#define APR_ASSERT_FAILURE(tc, ctxt, rv) \ + apr_assert_failure(tc, ctxt, rv, __LINE__) + + +void initialize(void); + +abts_suite *teststrmatch(abts_suite *suite); +abts_suite *testuri(abts_suite *suite); +abts_suite *testuuid(abts_suite *suite); +abts_suite *testbuckets(abts_suite *suite); +abts_suite *testpass(abts_suite *suite); +abts_suite *testmd4(abts_suite *suite); +abts_suite *testmd5(abts_suite *suite); +abts_suite *testcrypto(abts_suite *suite); +abts_suite *testldap(abts_suite *suite); +abts_suite *testdbd(abts_suite *suite); +abts_suite *testdate(abts_suite *suite); +abts_suite *testmemcache(abts_suite *suite); +abts_suite *testredis(abts_suite *suite); +abts_suite *testreslist(abts_suite *suite); +abts_suite *testqueue(abts_suite *suite); +abts_suite *testxml(abts_suite *suite); +abts_suite *testxlate(abts_suite *suite); +abts_suite *testrmm(abts_suite *suite); +abts_suite *testdbm(abts_suite *suite); +abts_suite *testsiphash(abts_suite *suite); + +#endif /* APR_TEST_INCLUDES */ diff --git a/test/testutildll.dsp b/test/testutildll.dsp new file mode 100644 index 0000000..9c90a16 --- /dev/null +++ b/test/testutildll.dsp @@ -0,0 +1,270 @@ +# Microsoft Developer Studio Project File - Name="testutildll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=testutildll - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testutildll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testutildll.mak" CFG="testutildll - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testutildll - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "testutildll - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE "testutildll - Win32 Release9x" (based on "Win32 (x86) External Target") +!MESSAGE "testutildll - Win32 Debug9x" (based on "Win32 (x86) External Target") +!MESSAGE "testutildll - x64 Release" (based on "Win32 (x86) External Target") +!MESSAGE "testutildll - x64 Debug" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "testutildll - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=Release OUTDIR=Release MODEL=dynamic all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "Release\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=Release OUTDIR=Release MODEL=dynamic all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "Release\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutildll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=Debug OUTDIR=Debug MODEL=dynamic _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "Debug\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=Debug OUTDIR=Debug MODEL=dynamic _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "Debug\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutildll - Win32 Release9x" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Release OUTDIR=9x\Release MODEL=dynamic all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "9x\Release\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Release OUTDIR=9x\Release MODEL=dynamic all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "9x\Release\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutildll - Win32 Debug9x" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Debug OUTDIR=9x\Debug MODEL=dynamic _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "9x\Debug\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Debug OUTDIR=9x\Debug MODEL=dynamic _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "9x\Debug\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutildll - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Release OUTDIR=x64\Release MODEL=dynamic all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "x64\Release\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Release OUTDIR=x64\Release MODEL=dynamic all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "x64\Release\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutildll - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Debug OUTDIR=x64\Debug MODEL=dynamic _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "x64\Debug\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Debug OUTDIR=x64\Debug MODEL=dynamic _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "x64\Debug\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "testutildll - Win32 Release" +# Name "testutildll - Win32 Debug" +# Name "testutildll - Win32 Release9x" +# Name "testutildll - Win32 Debug9x" +# Name "testutildll - x64 Release" +# Name "testutildll - x64 Debug" +# Begin Group "testall Source Files" + +# PROP Default_Filter ".c" +# Begin Source File + +SOURCE=.\abts.c +# End Source File +# Begin Source File + +SOURCE=.\abts.h +# End Source File +# Begin Source File + +SOURCE=.\abts_tests.h +# End Source File +# Begin Source File + +SOURCE=.\testbuckets.c +# End Source File +# Begin Source File + +SOURCE=.\testdate.c +# End Source File +# Begin Source File + +SOURCE=.\testdbd.c +# End Source File +# Begin Source File + +SOURCE=.\testdbm.c +# End Source File +# Begin Source File + +SOURCE=.\testldap.c +# End Source File +# Begin Source File + +SOURCE=.\testmd4.c +# End Source File +# Begin Source File + +SOURCE=.\testmd5.c +# End Source File +# Begin Source File + +SOURCE=.\testmemcache.c +# End Source File +# Begin Source File + +SOURCE=.\testpass.c +# End Source File +# Begin Source File + +SOURCE=.\testqueue.c +# End Source File +# Begin Source File + +SOURCE=.\testreslist.c +# End Source File +# Begin Source File + +SOURCE=.\testrmm.c +# End Source File +# Begin Source File + +SOURCE=.\teststrmatch.c +# End Source File +# Begin Source File + +SOURCE=.\testuri.c +# End Source File +# Begin Source File + +SOURCE=.\testutil.c +# End Source File +# Begin Source File + +SOURCE=.\testuuid.c +# End Source File +# Begin Source File + +SOURCE=.\testxlate.c +# End Source File +# Begin Source File + +SOURCE=.\testxml.c +# End Source File +# End Group +# Begin Group "Other Source Files" + +# PROP Default_Filter ".c" +# Begin Source File + +SOURCE=.\dbd.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Makefile.win +# End Source File +# End Target +# End Project diff --git a/test/testutillib.dsp b/test/testutillib.dsp new file mode 100644 index 0000000..6df114c --- /dev/null +++ b/test/testutillib.dsp @@ -0,0 +1,270 @@ +# Microsoft Developer Studio Project File - Name="testutillib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=testutillib - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testutillib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testutillib.mak" CFG="testutillib - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testutillib - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "testutillib - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE "testutillib - Win32 Release9x" (based on "Win32 (x86) External Target") +!MESSAGE "testutillib - Win32 Debug9x" (based on "Win32 (x86) External Target") +!MESSAGE "testutillib - x64 Release" (based on "Win32 (x86) External Target") +!MESSAGE "testutillib - x64 Debug" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "testutillib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=LibR OUTDIR=LibR MODEL=static all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "LibR\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=LibR OUTDIR=LibR MODEL=static all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "LibR\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutillib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=LibD OUTDIR=LibD MODEL=static _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "LibD\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=LibD OUTDIR=LibD MODEL=static _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "LibD\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutillib - Win32 Release9x" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibR OUTDIR=9x\LibR MODEL=static all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "9x\LibR\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibR OUTDIR=9x\LibR MODEL=static all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "9x\LibR\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutillib - Win32 Debug9x" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibD OUTDIR=9x\LibD MODEL=static _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "9x\LibD\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibD OUTDIR=9x\LibD MODEL=static _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "9x\LibD\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutillib - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibR OUTDIR=x64\LibR MODEL=static all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "x64\LibR\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibR OUTDIR=x64\LibR MODEL=static all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "x64\LibR\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testutillib - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibD OUTDIR=x64\LibD MODEL=static _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "x64\LibD\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibD OUTDIR=x64\LibD MODEL=static _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "x64\LibD\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "testutillib - Win32 Release" +# Name "testutillib - Win32 Debug" +# Name "testutillib - Win32 Release9x" +# Name "testutillib - Win32 Debug9x" +# Name "testutillib - x64 Release" +# Name "testutillib - x64 Debug" +# Begin Group "testall Source Files" + +# PROP Default_Filter ".c" +# Begin Source File + +SOURCE=.\abts.c +# End Source File +# Begin Source File + +SOURCE=.\abts.h +# End Source File +# Begin Source File + +SOURCE=.\abts_tests.h +# End Source File +# Begin Source File + +SOURCE=.\testbuckets.c +# End Source File +# Begin Source File + +SOURCE=.\testdate.c +# End Source File +# Begin Source File + +SOURCE=.\testdbd.c +# End Source File +# Begin Source File + +SOURCE=.\testdbm.c +# End Source File +# Begin Source File + +SOURCE=.\testldap.c +# End Source File +# Begin Source File + +SOURCE=.\testmd4.c +# End Source File +# Begin Source File + +SOURCE=.\testmd5.c +# End Source File +# Begin Source File + +SOURCE=.\testmemcache.c +# End Source File +# Begin Source File + +SOURCE=.\testpass.c +# End Source File +# Begin Source File + +SOURCE=.\testqueue.c +# End Source File +# Begin Source File + +SOURCE=.\testreslist.c +# End Source File +# Begin Source File + +SOURCE=.\testrmm.c +# End Source File +# Begin Source File + +SOURCE=.\teststrmatch.c +# End Source File +# Begin Source File + +SOURCE=.\testuri.c +# End Source File +# Begin Source File + +SOURCE=.\testutil.c +# End Source File +# Begin Source File + +SOURCE=.\testuuid.c +# End Source File +# Begin Source File + +SOURCE=.\testxlate.c +# End Source File +# Begin Source File + +SOURCE=.\testxml.c +# End Source File +# End Group +# Begin Group "Other Source Files" + +# PROP Default_Filter ".c" +# Begin Source File + +SOURCE=.\dbd.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Makefile.win +# End Source File +# End Target +# End Project diff --git a/test/testuuid.c b/test/testuuid.c new file mode 100644 index 0000000..f33adde --- /dev/null +++ b/test/testuuid.c @@ -0,0 +1,56 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testutil.h" +#include "apr_general.h" +#include "apr_uuid.h" + +static void test_uuid_parse(abts_case *tc, void *data) +{ + apr_uuid_t uuid; + apr_uuid_t uuid2; + char buf[APR_UUID_FORMATTED_LENGTH + 1]; + + apr_uuid_get(&uuid); + apr_uuid_format(buf, &uuid); + + apr_uuid_parse(&uuid2, buf); + ABTS_ASSERT(tc, "parse produced a different UUID", + memcmp(&uuid, &uuid2, sizeof(uuid)) == 0); +} + +static void test_gen2(abts_case *tc, void *data) +{ + apr_uuid_t uuid; + apr_uuid_t uuid2; + + /* generate two of them quickly */ + apr_uuid_get(&uuid); + apr_uuid_get(&uuid2); + + ABTS_ASSERT(tc, "generated the same UUID twice", + memcmp(&uuid, &uuid2, sizeof(uuid)) != 0); +} + +abts_suite *testuuid(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_uuid_parse, NULL); + abts_run_test(suite, test_gen2, NULL); + + return suite; +} diff --git a/test/testxlate.c b/test/testxlate.c new file mode 100644 index 0000000..6981eff --- /dev/null +++ b/test/testxlate.c @@ -0,0 +1,134 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_xlate.h" +#include "abts.h" +#include "testutil.h" + +#if APR_HAS_XLATE + +static const char test_utf8[] = "Edelwei\xc3\x9f"; +static const char test_utf7[] = "Edelwei+AN8-"; +static const char test_latin1[] = "Edelwei\xdf"; +static const char test_latin2[] = "Edelwei\xdf"; + +static void test_conversion(abts_case *tc, apr_xlate_t *convset, + const char *inbuf, const char *expected) +{ + static char buf[1024]; + apr_size_t inbytes_left = strlen(inbuf); + apr_size_t outbytes_left = sizeof(buf) - 1; + apr_status_t rv; + + rv = apr_xlate_conv_buffer(convset, inbuf, &inbytes_left, buf, &outbytes_left); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + rv = apr_xlate_conv_buffer(convset, NULL, NULL, buf + sizeof(buf) - + outbytes_left - 1, &outbytes_left); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + buf[sizeof(buf) - outbytes_left - 1] = '\0'; + + ABTS_STR_EQUAL(tc, expected, buf); +} + +static void one_test(abts_case *tc, const char *cs1, const char *cs2, + const char *str1, const char *str2, + apr_pool_t *pool) +{ + apr_status_t rv; + apr_xlate_t *convset; + + rv = apr_xlate_open(&convset, cs2, cs1, pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + test_conversion(tc, convset, str1, str2); + + rv = apr_xlate_close(convset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +#if APU_HAVE_APR_ICONV +/* it is a bug if iconv_open() fails */ +static int is_transform_supported(abts_case *tc, const char *cs1, + const char *cs2, apr_pool_t *pool) { + return 1; +} +#else +/* some iconv implementations don't support all tested transforms; + * example: 8859-1 <-> 8859-2 using native Solaris iconv + */ +static int is_transform_supported(abts_case *tc, const char *cs1, + const char *cs2, apr_pool_t *pool) { + apr_status_t rv; + apr_xlate_t *convset; + + rv = apr_xlate_open(&convset, cs2, cs1, pool); + if (rv != APR_SUCCESS) { + return 0; + } + + rv = apr_xlate_close(convset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + return 1; +} +#endif + +static void test_transformation(abts_case *tc, void *data) +{ + /* 1. Identity transformation: UTF-8 -> UTF-8 */ + one_test(tc, "UTF-8", "UTF-8", test_utf8, test_utf8, p); + + /* 2. UTF-8 <-> ISO-8859-1 */ + one_test(tc, "UTF-8", "ISO-8859-1", test_utf8, test_latin1, p); + one_test(tc, "ISO-8859-1", "UTF-8", test_latin1, test_utf8, p); + + /* 3. ISO-8859-1 <-> ISO-8859-2, identity */ + if (is_transform_supported(tc, "ISO-8859-1", "ISO-8859-2", p)) { + one_test(tc, "ISO-8859-1", "ISO-8859-2", test_latin1, test_latin2, p); + } + if (is_transform_supported(tc, "ISO-8859-2", "ISO-8859-1", p)) { + one_test(tc, "ISO-8859-2", "ISO-8859-1", test_latin2, test_latin1, p); + } + + /* 4. Transformation using charset aliases */ + one_test(tc, "UTF-8", "UTF-7", test_utf8, test_utf7, p); + one_test(tc, "UTF-7", "UTF-8", test_utf7, test_utf8, p); +} + +#endif /* APR_HAS_XLATE */ + +abts_suite *testxlate(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APR_HAS_XLATE + abts_run_test(suite, test_transformation, NULL); +#endif + + return suite; +} diff --git a/test/testxml.c b/test/testxml.c new file mode 100644 index 0000000..eed1067 --- /dev/null +++ b/test/testxml.c @@ -0,0 +1,205 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr.h" +#include "apr_general.h" +#include "apr_xml.h" +#include "abts.h" +#include "testutil.h" + +static apr_status_t create_dummy_file_error(abts_case *tc, apr_pool_t *p, + apr_file_t **fd) +{ + int i; + apr_status_t rv; + apr_off_t off = 0L; + char template[] = "data/testxmldummyerrorXXXXXX"; + + rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE | + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return rv; + + rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<maryx>" + "<had a=\"little\"/><lamb/>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < 5000; i++) { + rv = apr_file_puts("<hmm roast=\"lamb\" " + "for=\"dinner\">yummy</hmm>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + rv = apr_file_puts("</mary>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_seek(*fd, APR_SET, &off); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + return rv; +} + +static apr_status_t create_dummy_file(abts_case *tc, apr_pool_t *p, + apr_file_t **fd) +{ + int i; + apr_status_t rv; + apr_off_t off = 0L; + char template[] = "data/testxmldummyXXXXXX"; + + rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE | + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return rv; + + rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<mary>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < 5000; i++) { + rv = apr_file_puts("<hmm roast=\"lamb\" " + "for=\"dinner <>=\">yummy</hmm>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + rv = apr_file_puts("</mary>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_seek(*fd, APR_SET, &off); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + return rv; +} + +static void dump_xml(abts_case *tc, apr_xml_elem *e, int level) +{ + apr_xml_attr *a; + apr_xml_elem *ec; + + if (level == 0) { + ABTS_STR_EQUAL(tc, "mary", e->name); + } else { + ABTS_STR_EQUAL(tc, "hmm", e->name); + } + + if (e->attr) { + a = e->attr; + ABTS_PTR_NOTNULL(tc, a); + ABTS_STR_EQUAL(tc, "for", a->name); + ABTS_STR_EQUAL(tc, "dinner <>=", a->value); + a = a->next; + ABTS_PTR_NOTNULL(tc, a); + ABTS_STR_EQUAL(tc, "roast", a->name); + ABTS_STR_EQUAL(tc, "lamb", a->value); + } + if (e->first_child) { + ec = e->first_child; + while (ec) { + dump_xml(tc, ec, level + 1); + ec = ec->next; + } + } +} + +static void test_xml_parser(abts_case *tc, void *data) +{ + apr_file_t *fd; + apr_xml_parser *parser; + apr_xml_doc *doc; + apr_status_t rv; + + rv = create_dummy_file(tc, p, &fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + dump_xml(tc, doc->root, 0); + + rv = apr_file_close(fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = create_dummy_file_error(tc, p, &fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000); + ABTS_TRUE(tc, rv != APR_SUCCESS); +} + +static void test_billion_laughs(abts_case *tc, void *data) +{ + apr_file_t *fd; + apr_xml_parser *parser; + apr_xml_doc *doc; + apr_status_t rv; + + rv = apr_file_open(&fd, "data/billion-laughs.xml", + APR_FOPEN_READ, 0, p); + apr_assert_success(tc, "open billion-laughs.xml", rv); + + /* Don't test for return value; if it returns, chances are the bug + * is fixed or the machine has insane amounts of RAM. */ + apr_xml_parse_file(p, &parser, &doc, fd, 2000); + + apr_file_close(fd); +} + +static void test_CVE_2009_3720_alpha(abts_case *tc, void *data) +{ + apr_xml_parser *xp; + apr_xml_doc *doc; + apr_status_t rv; + + xp = apr_xml_parser_create(p); + + rv = apr_xml_parser_feed(xp, "\0\r\n", 3); + if (rv == APR_SUCCESS) + apr_xml_parser_done(xp, &doc); +} + +static void test_CVE_2009_3720_beta(abts_case *tc, void *data) +{ + apr_xml_parser *xp; + apr_xml_doc *doc; + apr_status_t rv; + + xp = apr_xml_parser_create(p); + + rv = apr_xml_parser_feed(xp, "<?xml version\xc2\x85='1.0'?>\r\n", 25); + if (rv == APR_SUCCESS) + apr_xml_parser_done(xp, &doc); +} + +abts_suite *testxml(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_xml_parser, NULL); + abts_run_test(suite, test_billion_laughs, NULL); + abts_run_test(suite, test_CVE_2009_3720_alpha, NULL); + abts_run_test(suite, test_CVE_2009_3720_beta, NULL); + + return suite; +} |