diff options
| author | Andrew Tridgell <tridge@samba.org> | 2008-02-12 12:56:30 +1100 | 
|---|---|---|
| committer | Andrew Tridgell <tridge@samba.org> | 2008-02-12 12:56:30 +1100 | 
| commit | f7bcc15bf8acc157dde8a9895773a0dd03ca6cfb (patch) | |
| tree | 0bf64d4b2b2183183062392c3f7fd713134af575 | |
| parent | ccc27e681cbd6283513b929d58f2ebce35e6658b (diff) | |
| parent | e84cd8d38bcb6756c5066c7c75f3220a15e5ad1b (diff) | |
| download | samba-f7bcc15bf8acc157dde8a9895773a0dd03ca6cfb.tar.gz samba-f7bcc15bf8acc157dde8a9895773a0dd03ca6cfb.tar.bz2 samba-f7bcc15bf8acc157dde8a9895773a0dd03ca6cfb.zip  | |
Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-test
(This used to be commit 3beaa04ef73ca21925d41745b30b6bbaadb7b939)
| -rw-r--r-- | source4/lib/ldb/Makefile.in | 3 | ||||
| -rw-r--r-- | source4/lib/ldb/configure.ac | 4 | ||||
| -rw-r--r-- | source4/lib/ldb/ldb.mk | 21 | ||||
| -rwxr-xr-x | source4/lib/ldb/setup.py | 15 | ||||
| -rwxr-xr-x | source4/lib/ldb/tests/python/api.py | 3 | ||||
| -rw-r--r-- | source4/lib/tdb/Makefile.in | 6 | ||||
| -rw-r--r-- | source4/lib/tdb/configure.ac | 5 | ||||
| -rw-r--r-- | source4/lib/tdb/python/tests/simple.py | 5 | ||||
| -rwxr-xr-x | source4/lib/tdb/setup.py | 11 | ||||
| -rw-r--r-- | source4/lib/tdb/tdb.mk | 25 | ||||
| -rw-r--r-- | source4/samba4-knownfail | 2 | ||||
| -rwxr-xr-x | source4/selftest/samba4_tests.sh | 5 | ||||
| -rwxr-xr-x | source4/setup/tests/blackbox_provision.sh | 39 | ||||
| -rw-r--r-- | testprogs/ejs/samba3sam.js | 1255 | 
14 files changed, 1352 insertions, 47 deletions
diff --git a/source4/lib/ldb/Makefile.in b/source4/lib/ldb/Makefile.in index 738ffe1adb..d3e027425b 100644 --- a/source4/lib/ldb/Makefile.in +++ b/source4/lib/ldb/Makefile.in @@ -19,6 +19,7 @@ SWIG = swig  EXTRA_OBJ=@EXTRA_OBJ@  TESTS=test-tdb.sh @TESTS@  PACKAGE_VERSION = @PACKAGE_VERSION@ +PYTHON_CONFIG = @PYTHON_CONFIG@  tdbdir = @tdbdir@  ldbdir = $(srcdir)  tallocdir = @tallocdir@ @@ -121,7 +122,7 @@ distclean:: clean  realdistclean:: distclean  	rm -f configure.in include/config.h.in -check:: test +check:: test @PYTHON_CHECK_TARGET@  check-soloading: sample_module.$(SHLIBEXT)  	LDB_MODULES_PATH=$(builddir) $(srcdir)/tests/test-soloading.sh diff --git a/source4/lib/ldb/configure.ac b/source4/lib/ldb/configure.ac index 176cef0f3e..4d9444ad10 100644 --- a/source4/lib/ldb/configure.ac +++ b/source4/lib/ldb/configure.ac @@ -78,14 +78,18 @@ AC_LIBREPLACE_MDLD_FLAGS  AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR  AC_PATH_PROGS([PYTHON_CONFIG], [python2.6-config python2.5-config python2.4-config python-config]) +AC_PATH_PROGS([PYTHON], [python2.6 python2.5 python2.4 python])  PYTHON_BUILD_TARGET="build-python"  PYTHON_INSTALL_TARGET="install-python" +PYTHON_CHECK_TARGET="check-python"  AC_SUBST(PYTHON_BUILD_TARGET)  AC_SUBST(PYTHON_INSTALL_TARGET) +AC_SUBST(PYTHON_CHECK_TARGET)  if test -z "$PYTHON_CONFIG"; then  	PYTHON_BUILD_TARGET=""	 +	PYTHON_CHECK_TARGET=""  	PYTHON_INSTALL_TARGET=""	  fi diff --git a/source4/lib/ldb/ldb.mk b/source4/lib/ldb/ldb.mk index b9aa24b276..ec4c34f6d8 100644 --- a/source4/lib/ldb/ldb.mk +++ b/source4/lib/ldb/ldb.mk @@ -65,18 +65,25 @@ examples/ldifreader: examples/ldifreader.o $(LIBS)  	$(CC) -o examples/ldifreader examples/ldifreader.o $(LIB_FLAGS)  # Python bindings -build-python:: lib/libldb.$(SHLIBEXT) ldb_wrap.c -	$(ldbdir)/setup.py build +build-python:: _ldb.$(SHLIBEXT) + +ldb_wrap.o: $(ldbdir)/ldb_wrap.c +	$(CC) -c $(ldbdir)/ldb_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` +	 +_ldb.$(SHLIBEXT): $(LIBS) ldb_wrap.o +	$(SHLD) $(SHLD_FLAGS) -o _ldb.$(SHLIBEXT) ldb_wrap.o $(LIB_FLAGS)  install-python:: build-python -	$(ldbdir)/setup.py install --prefix=$(DESTDIR)$(prefix) +	mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` \ +		$(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` +	cp $(ldbdir)/ldb.py $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` +	cp _ldb.$(SHLIBEXT) $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"`  install-swig::  	cp ldb.i `$(SWIG) -swiglib`  check-python:: build-python -	# FIXME: This isn't portable -	LD_LIBRARY_PATH=lib PYTHONPATH=.:build/lib.linux-i686-2.4/ trial tests/python/api.py +	LD_LIBRARY_PATH=lib PYTHONPATH=.:$(ldbdir) $(PYTHON) $(ldbdir)/tests/python/api.py -clean-python:: -	$(ldbdir)/setup.py clean +clean:: +	rm -f _ldb.$(SHLIBEXT) diff --git a/source4/lib/ldb/setup.py b/source4/lib/ldb/setup.py deleted file mode 100755 index b04f3b09f1..0000000000 --- a/source4/lib/ldb/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/python -from distutils.core import setup -from distutils.extension import Extension - -setup(name="ldb", -      version="1.0", -      url="http://ldb.samba.org/", -      author="LDB Developers", -      author_email="ldb@samba.org", -      license="LGPLv3", -      keywords=["ldap","ldb","db","ldif"], -      py_modules=["ldb"], -      ext_modules=[Extension('_ldb', ['ldb_wrap.c'], include_dirs=['include'], -                             library_dirs=["lib"], libraries=['ldb'])], -      ) diff --git a/source4/lib/ldb/tests/python/api.py b/source4/lib/ldb/tests/python/api.py index d5346c30b0..5f3f727b5d 100755 --- a/source4/lib/ldb/tests/python/api.py +++ b/source4/lib/ldb/tests/python/api.py @@ -418,3 +418,6 @@ class ModuleTests(unittest.TestCase):      def test_register_module(self):          ldb.register_module(ExampleModule()) +if __name__ == '__main__': +    import unittest +    unittest.TestProgram() diff --git a/source4/lib/tdb/Makefile.in b/source4/lib/tdb/Makefile.in index 9730dffe60..8c79f6e24c 100644 --- a/source4/lib/tdb/Makefile.in +++ b/source4/lib/tdb/Makefile.in @@ -22,8 +22,12 @@ PACKAGE_VERSION = @PACKAGE_VERSION@  PICFLAG = @PICFLAG@  SHLIBEXT = @SHLIBEXT@  SWIG = swig +PYTHON = @PYTHON@ +PYTHON_CONFIG = @PYTHON_CONFIG@  PYTHON_BUILD_TARGET = @PYTHON_BUILD_TARGET@  PYTHON_INSTALL_TARGET = @PYTHON_INSTALL_TARGET@ +PYTHON_CHECK_TARGET = @PYTHON_CHECK_TARGET@ +LIB_PATH_VAR = @LIB_PATH_VAR@  tdbdir = @tdbdir@  TDB_OBJ = @TDB_OBJ@ @LIBREPLACEOBJ@ @@ -39,7 +43,7 @@ $(SOLIB): $(TDB_OBJ)  check: test -test::  +test:: $(PYTHON_CHECK_TARGET)  installcheck:: test install  clean:: diff --git a/source4/lib/tdb/configure.ac b/source4/lib/tdb/configure.ac index 5747107f38..9b16a82c33 100644 --- a/source4/lib/tdb/configure.ac +++ b/source4/lib/tdb/configure.ac @@ -11,15 +11,20 @@ AC_LD_PICFLAG  AC_LD_SHLIBEXT  AC_LIBREPLACE_SHLD  AC_LIBREPLACE_SHLD_FLAGS +AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR  m4_include(libtdb.m4)  AC_PATH_PROGS([PYTHON_CONFIG], [python2.6-config python2.5-config python2.4-config python-config]) +AC_PATH_PROGS([PYTHON], [python2.6 python2.5 python2.4 python])  PYTHON_BUILD_TARGET="build-python"  PYTHON_INSTALL_TARGET="install-python" +PYTHON_CHECK_TARGET="check-python"  AC_SUBST(PYTHON_BUILD_TARGET)  AC_SUBST(PYTHON_INSTALL_TARGET) +AC_SUBST(PYTHON_CHECK_TARGET)  if test -z "$PYTHON_CONFIG"; then  	PYTHON_BUILD_TARGET=""  	PYTHON_INSTALL_TARGET="" +	PYTHON_CHECK_TARGET=""  fi  AC_OUTPUT(Makefile tdb.pc) diff --git a/source4/lib/tdb/python/tests/simple.py b/source4/lib/tdb/python/tests/simple.py index 1cc51aea07..94407b6398 100644 --- a/source4/lib/tdb/python/tests/simple.py +++ b/source4/lib/tdb/python/tests/simple.py @@ -142,3 +142,8 @@ class SimpleTdbTests(TestCase):          self.assertEquals(0, len(self.tdb))          self.tdb["entry"] = "value"          self.assertEquals(1, len(self.tdb)) + + +if __name__ == '__main__': +    import unittest +    unittest.TestProgram() diff --git a/source4/lib/tdb/setup.py b/source4/lib/tdb/setup.py deleted file mode 100755 index 8be0c67e0b..0000000000 --- a/source4/lib/tdb/setup.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/python -from distutils.core import setup -from distutils.extension import Extension - -setup(name='tdb', -      version='1.0', -      url="http://tdb.samba.org/", -      py_modules=["tdb"], -      ext_modules=[Extension('_tdb', ['tdb_wrap.c'], include_dirs=['include'], -          library_dirs=["."], libraries=['tdb'])], -) diff --git a/source4/lib/tdb/tdb.mk b/source4/lib/tdb/tdb.mk index d6118dd38f..fe77a0492d 100644 --- a/source4/lib/tdb/tdb.mk +++ b/source4/lib/tdb/tdb.mk @@ -33,25 +33,32 @@ clean::  	rm -f $(SONAME) $(SOLIB) libtdb.a libtdb.$(SHLIBEXT)  	rm -f $(ALL_PROGS) tdb.pc -build-python:: libtdb.$(SHLIBEXT) tdb_wrap.c -	$(tdbdir)/setup.py build +build-python:: _tdb.$(SHLIBEXT)  + +tdb_wrap.o: $(tdbdir)/tdb_wrap.c +	$(CC) -c $(tdbdir)/tdb_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` + +_tdb.$(SHLIBEXT): libtdb.$(SHLIBEXT) tdb_wrap.o +	$(SHLD) $(SHLD_FLAGS) -o $@ tdb_wrap.o -L. -ltdb `$(PYTHON_CONFIG) --libs`  install:: installdirs installbin installheaders installlibs \  		  $(PYTHON_INSTALL_TARGET) -installpython:: build-python -	./setup.py install --prefix=$(DESTDIR)$(prefix) +install-python:: build-python +	mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` \ +		$(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` +	cp $(tdbdir)/tdb.py $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` +	cp _tdb.$(SHLIBEXT) $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"`  check-python:: build-python -	# FIXME: Should be more portable: -	LD_LIBRARY_PATH=. PYTHONPATH=.:build/lib.linux-i686-2.4 trial python/tests/simple.py +	$(LIB_PATH_VAR)=. PYTHONPATH=".:$(tdbdir)" $(PYTHON) $(tdbdir)/python/tests/simple.py  install-swig::  	mkdir -p $(DESTDIR)`$(SWIG) -swiglib`  	cp tdb.i $(DESTDIR)`$(SWIG) -swiglib` -clean-python:: -	./setup.py clean +clean:: +	rm -f _tdb.$(SHLIBEXT)  installdirs::  	mkdir -p $(DESTDIR)$(bindir) @@ -77,5 +84,3 @@ libtdb.$(SHLIBEXT): $(SOLIB)  $(SONAME): $(SOLIB)  	ln -fs $< $@ - - diff --git a/source4/samba4-knownfail b/source4/samba4-knownfail index cf5f97ca74..ab03145354 100644 --- a/source4/samba4-knownfail +++ b/source4/samba4-knownfail @@ -35,4 +35,4 @@ BASE-CHARSET.*.Testing partial surrogate  .*NET-API-DELSHARE.*				# DelShare isn't implemented yet  RAP.*netservergetinfo  kinit with pkinit # fails with: salt type 3 not supported - +samba4.blackbox.provision.py.reprovision # Fails with entry already exists diff --git a/source4/selftest/samba4_tests.sh b/source4/selftest/samba4_tests.sh index fba9e8603e..c90373e446 100755 --- a/source4/selftest/samba4_tests.sh +++ b/source4/selftest/samba4_tests.sh @@ -262,6 +262,8 @@ done  DATADIR=$samba4srcdir/../testdata +plantest "js.samba3sam" none $SCRIPTDIR/samba3sam.js $CONFIGURATION `pwd` $DATADIR/samba3/ +  # Domain Member Tests  plantest "RPC-ECHO against member server with local creds" member $VALGRIND $smb4torture ncacn_np:"\$NETBIOSNAME" -U"\$NETBIOSNAME/\$USERNAME"%"\$PASSWORD" RPC-ECHO "$*" @@ -327,5 +329,6 @@ then  	rm -rf $PREFIX/upgrade  	plantest "blackbox.upgrade" none $PYTHON setup/upgrade.py $CONFIGURATION --targetdir=$PREFIX/upgrade ../testdata/samba3 ../testdata/samba3/smb.conf  	rm -rf $PREFIX/provision -	plantest "blackbox.provision.py" none $PYTHON ./setup/provision.py $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/provision +	mkdir $PREFIX/provision +	plantest "blackbox.provision.py" none PYTHON="$PYTHON" $samba4srcdir/setup/tests/blackbox_provision.sh "$PREFIX/provision" "$CONFIGURATION"   fi diff --git a/source4/setup/tests/blackbox_provision.sh b/source4/setup/tests/blackbox_provision.sh new file mode 100755 index 0000000000..57b11eae5f --- /dev/null +++ b/source4/setup/tests/blackbox_provision.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +if [ $# -lt 2 ]; then +cat <<EOF +Usage: blackbox_provision.sh PREFIX CONFIGURATION +EOF +exit 1; +fi + +PREFIX="$1" +CONFIGURATION="$2" +shift 2 + +testit() { +	name="$1" +	shift +	cmdline="$*" +	echo "test: $name" +	$cmdline +	status=$? +	if [ x$status = x0 ]; then +		echo "success: $name" +	else +		echo "failure: $name" +		failed=`expr $failed + 1` +	fi +	return $status +} + +testit "simple" $PYTHON ./setup/provision.py $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir=$PREFIX/simple + +reprovision() { +	$PYTHON ./setup/provision.py $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir="$PREFIX/reprovision" +	$PYTHON ./setup/provision.py $CONFIGURATION --domain=FOO --realm=foo.example.com --targetdir="$PREFIX/reprovision" +} + +testit "reprovision" reprovision + +exit $failed diff --git a/testprogs/ejs/samba3sam.js b/testprogs/ejs/samba3sam.js new file mode 100644 index 0000000000..e5639b8ec8 --- /dev/null +++ b/testprogs/ejs/samba3sam.js @@ -0,0 +1,1255 @@ +#!/usr/bin/env smbscript +/* +  (C) Jelmer Vernooij <jelmer@samba.org> 2005 +  (C) Martin Kuehl <mkhl@samba.org> 2006 +  Published under the GNU GPL +  Sponsored by Google Summer of Code + */ + +var sys; +var options = GetOptions(ARGV, "POPT_AUTOHELP", "POPT_COMMON_SAMBA"); +if (options == undefined) { +	println("Failed to parse options"); +	return -1; +} + +libinclude("base.js"); + +if (options.ARGV.length != 2) { +	println("Usage: samba3sam.js <TESTDIR> <DATADIR>"); +	return -1; +} + +var prefix = options.ARGV[0]; +var datadir = options.ARGV[1]; + +function setup_data(obj, ldif) +{ +	assert(ldif != undefined); +	ldif = substitute_var(ldif, obj); +	assert(ldif != undefined); +	var ok = obj.db.add(ldif); +	assert(ok.error == 0); +} + +function setup_modules(ldb, s3, s4, ldif) +{ +	assert(ldif != undefined); +	ldif = substitute_var(ldif, s4); +	assert(ldif != undefined); +	var ok = ldb.add(ldif); +	assert(ok.error == 0); + +	var ldif = " +dn: @MAP=samba3sam +@FROM: " + s4.BASEDN + " +@TO: sambaDomainName=TESTS," + s3.BASEDN + " + +dn: @MODULES +@LIST: rootdse,paged_results,server_sort,extended_dn,asq,samldb,password_hash,operational,objectguid,rdn_name,samba3sam,partition + +dn: @PARTITION +partition: " + s4.BASEDN + ":" + s4.url + " +partition: " + s3.BASEDN + ":" + s3.url + " +replicateEntries: @SUBCLASSES +replicateEntries: @ATTRIBUTES +replicateEntries: @INDEXLIST +"; +	var ok = ldb.add(ldif); +	assert(ok.error == 0); +} + +function test_s3sam_search(ldb) +{ +	println("Looking up by non-mapped attribute"); +	var msg = ldb.search("(cn=Administrator)"); +	assert(msg.error == 0); +	assert(msg.msgs.length == 1); +	assert(msg.msgs[0].cn == "Administrator"); + +	println("Looking up by mapped attribute"); +	var msg = ldb.search("(name=Backup Operators)"); +	assert(msg.error == 0); +	assert(msg.msgs.length == 1); +	assert(msg.msgs[0].name == "Backup Operators"); + +	println("Looking up by old name of renamed attribute"); +	var msg = ldb.search("(displayName=Backup Operators)"); +	assert(msg.msgs.length == 0); + +	println("Looking up mapped entry containing SID"); +	var msg = ldb.search("(cn=Replicator)"); +	assert(msg.error == 0); +	assert(msg.msgs.length == 1); +	println(msg.msgs[0].dn); +	assert(msg.msgs[0].dn == "cn=Replicator,ou=Groups,dc=vernstok,dc=nl"); +	assert(msg.msgs[0].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552"); + +	println("Checking mapping of objectClass"); +	var oc = msg.msgs[0].objectClass; +	assert(oc != undefined); +	for (var i in oc) { +		assert(oc[i] == "posixGroup" || oc[i] == "group"); +	} + +	println("Looking up by objectClass"); +	var msg = ldb.search("(|(objectClass=user)(cn=Administrator))"); +	assert(msg.error == 0); +	assert(msg.msgs.length == 2); +	for (var i = 0; i < msg.msgs.length; i++) { +		assert((msg.msgs[i].dn == "unixName=Administrator,ou=Users,dc=vernstok,dc=nl") || +		       (msg.msgs[i].dn == "unixName=nobody,ou=Users,dc=vernstok,dc=nl")); +	} +} + +function test_s3sam_modify(ldb, s3) +{ +	var msg, ok; +	println("Adding a record that will be fallbacked"); +	ok = ldb.add(" +dn: cn=Foo +foo: bar +blah: Blie +cn: Foo +showInAdvancedViewOnly: TRUE +"); +	if (ok.error != 0) { +		println(ok.errstr); +		assert(ok.error == 0); +	} + +	println("Checking for existence of record (local)"); +	/* TODO: This record must be searched in the local database, which is currently only supported for base searches +	 * msg = ldb.search("(cn=Foo)", new Array('foo','blah','cn','showInAdvancedViewOnly')); +	 * TODO: Actually, this version should work as well but doesn't... +	 *  +	 */ +	var attrs =  new Array('foo','blah','cn','showInAdvancedViewOnly'); +	msg = ldb.search("(cn=Foo)", "cn=Foo", ldb.LDB_SCOPE_BASE, attrs); +	assert(msg.error == 0); +	assert(msg.msgs.length == 1); +	assert(msg.msgs[0].showInAdvancedViewOnly == "TRUE"); +	assert(msg.msgs[0].foo == "bar"); +	assert(msg.msgs[0].blah == "Blie"); + +	println("Adding record that will be mapped"); +	ok = ldb.add(" +dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl +objectClass: user +unixName: bin +sambaUnicodePwd: geheim +cn: Niemand +"); +	if (ok.error != 0) { +		println(ok.errstr); +		assert(ok.error == 0); +	} +	assert(ok.error == 0); + +	println("Checking for existence of record (remote)"); +	msg = ldb.search("(unixName=bin)", new Array('unixName','cn','dn', 'sambaUnicodePwd')); +	assert(msg.error == 0); +	assert(msg.msgs.length == 1); +	assert(msg.msgs[0].cn == "Niemand");  +	assert(msg.msgs[0].sambaUnicodePwd == "geheim"); + +	println("Checking for existence of record (local && remote)"); +	msg = ldb.search("(&(unixName=bin)(sambaUnicodePwd=geheim))", new Array('unixName','cn','dn', 'sambaUnicodePwd')); +	assert(msg.error == 0); +	assert(msg.msgs.length == 1);		// TODO: should check with more records +	assert(msg.msgs[0].cn == "Niemand"); +	assert(msg.msgs[0].unixName == "bin"); +	assert(msg.msgs[0].sambaUnicodePwd == "geheim"); + +	println("Checking for existence of record (local || remote)"); +	msg = ldb.search("(|(unixName=bin)(sambaUnicodePwd=geheim))", new Array('unixName','cn','dn', 'sambaUnicodePwd')); +	println("got " + msg.msgs.length + " replies"); +	assert(msg.error == 0); +	assert(msg.msgs.length == 1);		// TODO: should check with more records +	assert(msg.msgs[0].cn == "Niemand"); +	assert(msg.msgs[0].unixName == "bin" || msg.msgs[0].sambaUnicodePwd == "geheim"); + +	println("Checking for data in destination database"); +	msg = s3.db.search("(cn=Niemand)"); +	assert(msg.error == 0); +	assert(msg.msgs.length >= 1); +	assert(msg.msgs[0].sambaSID == "S-1-5-21-4231626423-2410014848-2360679739-2001"); +	assert(msg.msgs[0].displayName == "Niemand"); + +	println("Adding attribute..."); +	ok = ldb.modify(" +dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl +changetype: modify +add: description +description: Blah +"); +	if (ok.error != 0) { +		println(ok.errstr); +		assert(ok.error == 0); +	} +	assert(ok.error == 0); + +	println("Checking whether changes are still there..."); +	msg = ldb.search("(cn=Niemand)"); +	assert(msg.error == 0); +	assert(msg.msgs.length >= 1); +	assert(msg.msgs[0].cn == "Niemand"); +	assert(msg.msgs[0].description == "Blah"); + +	println("Modifying attribute..."); +	ok = ldb.modify(" +dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl +changetype: modify +replace: description +description: Blie +"); +		if (ok.error != 0) { +			println(ok.errstr); +			assert(ok.error == 0); +		} +	assert(ok.error == 0); + +	println("Checking whether changes are still there..."); +	msg = ldb.search("(cn=Niemand)"); +	assert(msg.error == 0); +	assert(msg.msgs.length >= 1); +	assert(msg.msgs[0].description == "Blie"); + +	println("Deleting attribute..."); +	ok = ldb.modify(" +dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl +changetype: modify +delete: description +"); +	if (ok.error != 0) { +		println(ok.errstr); +		assert(ok.error == 0); +	} +	assert(ok.error == 0); + +	println("Checking whether changes are no longer there..."); +	msg = ldb.search("(cn=Niemand)"); +	assert(msg.error == 0); +	assert(msg.msgs.length >= 1); +	assert(msg.msgs[0].description == undefined); + +	println("Renaming record..."); +	ok = ldb.rename("cn=Niemand,cn=Users,dc=vernstok,dc=nl", "cn=Niemand2,cn=Users,dc=vernstok,dc=nl"); +	assert(ok.error == 0); + +	println("Checking whether DN has changed..."); +	msg = ldb.search("(cn=Niemand2)"); +	assert(msg.error == 0); +	assert(msg.msgs.length == 1); +	assert(msg.msgs[0].dn == "cn=Niemand2,cn=Users,dc=vernstok,dc=nl"); + +	println("Deleting record..."); +	ok = ldb.del("cn=Niemand2,cn=Users,dc=vernstok,dc=nl"); +	if (ok.error != 0) { +		println(ok.errstr); +		assert(ok.error == 0); +	} + +	println("Checking whether record is gone..."); +	msg = ldb.search("(cn=Niemand2)"); +	assert(msg.error == 0); +	assert(msg.msgs.length == 0); +} + +function test_map_search(ldb, s3, s4) +{ +	println("Running search tests on mapped data"); +	var res; +	var dn; +	var attrs; + + +	var ldif = " +dn: " + "sambaDomainName=TESTS," + s3.BASEDN + " +objectclass: sambaDomain +objectclass: top +sambaSID: S-1-5-21-4231626423-2410014848-2360679739 +sambaNextRid: 2000 +sambaDomainName: TESTS" +	ldif = substitute_var(ldif, s3); +	assert(ldif != undefined); +	var ok = s3.db.add(ldif); +	assert(ok.error == 0); + +	printf("Add a set of split records"); +	var ldif = " +dn: " + s4.dn("cn=X") + " +objectClass: user +cn: X +codePage: x +revision: x +dnsHostName: x +nextRid: y +lastLogon: x +description: x +objectSid: S-1-5-21-4231626423-2410014848-2360679739-552 +primaryGroupID: 1-5-21-4231626423-2410014848-2360679739-512 + +dn: " + s4.dn("cn=Y") + " +objectClass: top +cn: Y +codePage: x +revision: x +dnsHostName: y +nextRid: y +lastLogon: y +description: x + +dn: " + s4.dn("cn=Z") + " +objectClass: top +cn: Z +codePage: x +revision: y +dnsHostName: z +nextRid: y +lastLogon: z +description: y +"; + +	ldif = substitute_var(ldif, s4); +	assert(ldif != undefined); +	var ok = ldb.add(ldif); +	if (ok.error != 0) { +		println(ok.errstr); +		assert(ok.error == 0); +	} + +	println("Add a set of remote records"); + +	var ldif = " +dn: " + s3.dn("cn=A") + " +objectClass: posixAccount +cn: A +sambaNextRid: x +sambaBadPasswordCount: x +sambaLogonTime: x +description: x +sambaSID: S-1-5-21-4231626423-2410014848-2360679739-552 +sambaPrimaryGroupSID: S-1-5-21-4231626423-2410014848-2360679739-512 + +dn: " + s3.dn("cn=B") + " +objectClass: top +cn:B +sambaNextRid: x +sambaBadPasswordCount: x +sambaLogonTime: y +description: x + +dn: " + s3.dn("cn=C") + " +objectClass: top +cn: C +sambaNextRid: x +sambaBadPasswordCount: y +sambaLogonTime: z +description: y +"; +	ldif = substitute_var(ldif, s3); +	assert(ldif != undefined); +	var ok = s3.db.add(ldif); +	assert(ok.error == 0); + +	println("Testing search by DN"); + +	/* Search remote record by local DN */ +	dn = s4.dn("cn=A"); +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "x"); + +	/* Search remote record by remote DN */ +	dn = s3.dn("cn=A"); +	attrs = new Array("dnsHostName", "lastLogon", "sambaLogonTime"); +	res = s3.db.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == undefined); +	assert(res.msgs[0].sambaLogonTime == "x"); + +	/* Search split record by local DN */ +	dn = s4.dn("cn=X"); +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].dnsHostName == "x"); +	assert(res.msgs[0].lastLogon == "x"); + +	/* Search split record by remote DN */ +	dn = s3.dn("cn=X"); +	attrs = new Array("dnsHostName", "lastLogon", "sambaLogonTime"); +	res = s3.db.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == undefined); +	assert(res.msgs[0].sambaLogonTime == "x"); + +	println("Testing search by attribute"); + +	/* Search by ignored attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(revision=x)", NULL, ldb. SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 2); +	assert(res.msgs[0].dn == s4.dn("cn=Y")); +	assert(res.msgs[0].dnsHostName == "y"); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=X")); +	assert(res.msgs[1].dnsHostName == "x"); +	assert(res.msgs[1].lastLogon == "x"); + +	/* Search by kept attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(description=y)", NULL, ldb. SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 2); +	assert(res.msgs[0].dn == s4.dn("cn=Z")); +	assert(res.msgs[0].dnsHostName == "z"); +	assert(res.msgs[0].lastLogon == "z"); +	assert(res.msgs[1].dn == s4.dn("cn=C")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "z"); + +	/* Search by renamed attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(badPwdCount=x)", NULL, ldb. SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 2); +	assert(res.msgs[0].dn == s4.dn("cn=B")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=A")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "x"); + +	/* Search by converted attribute */ +	attrs = new Array("dnsHostName", "lastLogon", "objectSid"); +	/* TODO: +	   Using the SID directly in the parse tree leads to conversion +	   errors, letting the search fail with no results. +	res = ldb.search("(objectSid=S-1-5-21-4231626423-2410014848-2360679739-552)", NULL, ldb. SCOPE_DEFAULT, attrs); +	*/ +	res = ldb.search("(objectSid=*)", NULL, ldb. SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 3); +	assert(res.msgs[0].dn == s4.dn("cn=X")); +	assert(res.msgs[0].dnsHostName == "x"); +	assert(res.msgs[0].lastLogon == "x"); +	assert(res.msgs[0].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552"); +	assert(res.msgs[1].dn == s4.dn("cn=A")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "x"); +	assert(res.msgs[1].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552"); + +	/* Search by generated attribute */ +	/* In most cases, this even works when the mapping is missing +	 * a `convert_operator' by enumerating the remote db. */ +	attrs = new Array("dnsHostName", "lastLogon", "primaryGroupID"); +	res = ldb.search("(primaryGroupID=512)", NULL, ldb. SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == s4.dn("cn=A")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "x"); +	assert(res.msgs[0].primaryGroupID == "512"); + +	/* TODO: There should actually be two results, A and X.  The +	 * primaryGroupID of X seems to get corrupted somewhere, and the +	 * objectSid isn't available during the generation of remote (!) data, +	 * which can be observed with the following search.  Also note that Xs +	 * objectSid seems to be fine in the previous search for objectSid... */ +	/* +	res = ldb.search("(primaryGroupID=*)", NULL, ldb. SCOPE_DEFAULT, attrs); +	println(res.msgs.length + " results found"); +	for (i=0;i<res.msgs.length;i++) { +		for (obj in res.msgs[i]) { +			println(obj + ": " + res.msgs[i][obj]); +		} +		println("---"); +	} +	*/ + +	/* Search by remote name of renamed attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(sambaBadPasswordCount=*)", "", ldb. SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 0); + +	/* Search by objectClass */ +	attrs = new Array("dnsHostName", "lastLogon", "objectClass"); +	res = ldb.search("(objectClass=user)", NULL, ldb. SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 2); +	assert(res.msgs[0].dn == s4.dn("cn=X")); +	assert(res.msgs[0].dnsHostName == "x"); +	assert(res.msgs[0].lastLogon == "x"); +	assert(res.msgs[0].objectClass != undefined); +	assert(res.msgs[0].objectClass[0] == "user");  +	assert(res.msgs[1].dn == s4.dn("cn=A")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "x"); +	assert(res.msgs[1].objectClass != undefined); +	assert(res.msgs[1].objectClass[0] == "user"); + +	/* Prove that the objectClass is actually used for the search */ +	res = ldb.search("(|(objectClass=user)(badPwdCount=x))", NULL, ldb. SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 3); +	assert(res.msgs[0].dn == s4.dn("cn=B")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[0].objectClass != undefined); +	for (i=0;i<res.msgs[0].objectClass.length;i++) { +		assert(res.msgs[0].objectClass[i] != "user"); +	} +	assert(res.msgs[1].dn == s4.dn("cn=X")); +	assert(res.msgs[1].dnsHostName == "x"); +	assert(res.msgs[1].lastLogon == "x"); +	assert(res.msgs[1].objectClass != undefined); +	assert(res.msgs[1].objectClass[0] == "user"); +	assert(res.msgs[2].dn == s4.dn("cn=A")); +	assert(res.msgs[2].dnsHostName == undefined); +	assert(res.msgs[2].lastLogon == "x"); +	assert(res.msgs[2].objectClass != undefined); +	assert(res.msgs[2].objectClass[0] == "user"); + +	println("Testing search by parse tree"); + +	/* Search by conjunction of local attributes */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(&(codePage=x)(revision=x))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 2); +	assert(res.msgs[0].dn == s4.dn("cn=Y")); +	assert(res.msgs[0].dnsHostName == "y"); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=X")); +	assert(res.msgs[1].dnsHostName == "x"); +	assert(res.msgs[1].lastLogon == "x"); + +	/* Search by conjunction of remote attributes */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(&(lastLogon=x)(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 2); +	assert(res.msgs[0].dn == s4.dn("cn=X")); +	assert(res.msgs[0].dnsHostName == "x"); +	assert(res.msgs[0].lastLogon == "x"); +	assert(res.msgs[1].dn == s4.dn("cn=A")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "x"); +	 +	/* Search by conjunction of local and remote attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(&(codePage=x)(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 2); +	assert(res.msgs[0].dn == s4.dn("cn=Y")); +	assert(res.msgs[0].dnsHostName == "y"); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=X")); +	assert(res.msgs[1].dnsHostName == "x"); +	assert(res.msgs[1].lastLogon == "x"); + +	/* Search by conjunction of local and remote attribute w/o match */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(&(codePage=x)(nextRid=x))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 0); +	res = ldb.search("(&(revision=x)(lastLogon=z))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 0); + +	/* Search by disjunction of local attributes */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(|(revision=x)(dnsHostName=x))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 2); +	assert(res.msgs[0].dn == s4.dn("cn=Y")); +	assert(res.msgs[0].dnsHostName == "y"); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=X")); +	assert(res.msgs[1].dnsHostName == "x"); +	assert(res.msgs[1].lastLogon == "x"); + +	/* Search by disjunction of remote attributes */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(|(badPwdCount=x)(lastLogon=x))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 3); +	assert(res.msgs[0].dn == s4.dn("cn=B")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=X")); +	assert(res.msgs[1].dnsHostName == "x"); +	assert(res.msgs[1].lastLogon == "x"); +	assert(res.msgs[2].dn == s4.dn("cn=A")); +	assert(res.msgs[2].dnsHostName == undefined); +	assert(res.msgs[2].lastLogon == "x"); + +	/* Search by disjunction of local and remote attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(|(revision=x)(lastLogon=y))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 3); +	assert(res.msgs[0].dn == s4.dn("cn=Y")); +	assert(res.msgs[0].dnsHostName == "y"); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=B")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "y"); +	assert(res.msgs[2].dn == s4.dn("cn=X")); +	assert(res.msgs[2].dnsHostName == "x"); +	assert(res.msgs[2].lastLogon == "x"); + +	/* Search by disjunction of local and remote attribute w/o match */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(|(codePage=y)(nextRid=z))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 0); + +	/* Search by negated local attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(!(revision=x))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 5); +	assert(res.msgs[0].dn == s4.dn("cn=B")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=A")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "x"); +	assert(res.msgs[2].dn == s4.dn("cn=Z")); +	assert(res.msgs[2].dnsHostName == "z"); +	assert(res.msgs[2].lastLogon == "z"); +	assert(res.msgs[3].dn == s4.dn("cn=C")); +	assert(res.msgs[3].dnsHostName == undefined); +	assert(res.msgs[3].lastLogon == "z"); + +	/* Search by negated remote attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(!(description=x))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 3); +	assert(res.msgs[0].dn == s4.dn("cn=Z")); +	assert(res.msgs[0].dnsHostName == "z"); +	assert(res.msgs[0].lastLogon == "z"); +	assert(res.msgs[1].dn == s4.dn("cn=C")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "z"); + +	/* Search by negated conjunction of local attributes */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(!(&(codePage=x)(revision=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 5); +	assert(res.msgs[0].dn == s4.dn("cn=B")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=A")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "x"); +	assert(res.msgs[2].dn == s4.dn("cn=Z")); +	assert(res.msgs[2].dnsHostName == "z"); +	assert(res.msgs[2].lastLogon == "z"); +	assert(res.msgs[3].dn == s4.dn("cn=C")); +	assert(res.msgs[3].dnsHostName == undefined); +	assert(res.msgs[3].lastLogon == "z"); + +	/* Search by negated conjunction of remote attributes */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(!(&(lastLogon=x)(description=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 5); +	assert(res.msgs[0].dn == s4.dn("cn=Y")); +	assert(res.msgs[0].dnsHostName == "y"); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=B")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "y"); +	assert(res.msgs[2].dn == s4.dn("cn=Z")); +	assert(res.msgs[2].dnsHostName == "z"); +	assert(res.msgs[2].lastLogon == "z"); +	assert(res.msgs[3].dn == s4.dn("cn=C")); +	assert(res.msgs[3].dnsHostName == undefined); +	assert(res.msgs[3].lastLogon == "z"); + +	/* Search by negated conjunction of local and remote attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(!(&(codePage=x)(description=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 5); +	assert(res.msgs[0].dn == s4.dn("cn=B")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=A")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "x"); +	assert(res.msgs[2].dn == s4.dn("cn=Z")); +	assert(res.msgs[2].dnsHostName == "z"); +	assert(res.msgs[2].lastLogon == "z"); +	assert(res.msgs[3].dn == s4.dn("cn=C")); +	assert(res.msgs[3].dnsHostName == undefined); +	assert(res.msgs[3].lastLogon == "z"); + +	/* Search by negated disjunction of local attributes */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(!(|(revision=x)(dnsHostName=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs[0].dn == s4.dn("cn=B")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=A")); +	assert(res.msgs[1].dnsHostName == undefined); +	assert(res.msgs[1].lastLogon == "x"); +	assert(res.msgs[2].dn == s4.dn("cn=Z")); +	assert(res.msgs[2].dnsHostName == "z"); +	assert(res.msgs[2].lastLogon == "z"); +	assert(res.msgs[3].dn == s4.dn("cn=C")); +	assert(res.msgs[3].dnsHostName == undefined); +	assert(res.msgs[3].lastLogon == "z"); + +	/* Search by negated disjunction of remote attributes */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(!(|(badPwdCount=x)(lastLogon=x)))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 4); +	assert(res.msgs[0].dn == s4.dn("cn=Y")); +	assert(res.msgs[0].dnsHostName == "y"); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=Z")); +	assert(res.msgs[1].dnsHostName == "z"); +	assert(res.msgs[1].lastLogon == "z"); +	assert(res.msgs[2].dn == s4.dn("cn=C")); +	assert(res.msgs[2].dnsHostName == undefined); +	assert(res.msgs[2].lastLogon == "z"); + +	/* Search by negated disjunction of local and remote attribute */ +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(!(|(revision=x)(lastLogon=y)))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 4); +	assert(res.msgs[0].dn == s4.dn("cn=A")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "x"); +	assert(res.msgs[1].dn == s4.dn("cn=Z")); +	assert(res.msgs[1].dnsHostName == "z"); +	assert(res.msgs[1].lastLogon == "z"); +	assert(res.msgs[2].dn == s4.dn("cn=C")); +	assert(res.msgs[2].dnsHostName == undefined); +	assert(res.msgs[2].lastLogon == "z"); + +	println("Search by complex parse tree"); +	attrs = new Array("dnsHostName", "lastLogon"); +	res = ldb.search("(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 6); +	assert(res.msgs[0].dn == s4.dn("cn=B")); +	assert(res.msgs[0].dnsHostName == undefined); +	assert(res.msgs[0].lastLogon == "y"); +	assert(res.msgs[1].dn == s4.dn("cn=X")); +	assert(res.msgs[1].dnsHostName == "x"); +	assert(res.msgs[1].lastLogon == "x"); +	assert(res.msgs[2].dn == s4.dn("cn=A")); +	assert(res.msgs[2].dnsHostName == undefined); +	assert(res.msgs[2].lastLogon == "x"); +	assert(res.msgs[3].dn == s4.dn("cn=Z")); +	assert(res.msgs[3].dnsHostName == "z"); +	assert(res.msgs[3].lastLogon == "z"); +	assert(res.msgs[4].dn == s4.dn("cn=C")); +	assert(res.msgs[4].dnsHostName == undefined); +	assert(res.msgs[4].lastLogon == "z"); + +	/* Clean up */ +	var dns = new Array(); +	dns[0] = s4.dn("cn=A"); +	dns[1] = s4.dn("cn=B"); +	dns[2] = s4.dn("cn=C"); +	dns[3] = s4.dn("cn=X"); +	dns[4] = s4.dn("cn=Y"); +	dns[5] = s4.dn("cn=Z"); +	for (i=0;i<dns.length;i++) { +		var ok = ldb.del(dns[i]); +		assert(ok.error == 0); +	} +} + +function test_map_modify(ldb, s3, s4) +{ +	println("Running modification tests on mapped data"); + +	var ldif; +	var attrs; +	var dn, dn2; +	var res; +	var ok; + +	println("Testing modification of local records"); + +	/* Add local record */ +	dn = "cn=test,dc=idealx,dc=org"; +	ldif = " +dn: " + dn + " +cn: test +foo: bar +revision: 1 +description: test +"; +	ok = ldb.add(ldif); +	assert(ok.error == 0); +	/* Check it's there */ +	attrs = new Array("foo", "revision", "description"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].foo == "bar"); +	assert(res.msgs[0].revision == "1"); +	assert(res.msgs[0].description == "test"); +	/* Check it's not in the local db */ +	res = s4.db.search("(cn=test)", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 0); +	/* Check it's not in the remote db */ +	res = s3.db.search("(cn=test)", NULL, ldb.SCOPE_DEFAULT, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 0); + +	/* Modify local record */ +	ldif = " +dn: " + dn + " +replace: foo +foo: baz +replace: description +description: foo +"; +	ok = ldb.modify(ldif); +	assert(ok.error == 0); +	/* Check in local db */ +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].foo == "baz"); +	assert(res.msgs[0].revision == "1"); +	assert(res.msgs[0].description == "foo"); + +	/* Rename local record */ +	dn2 = "cn=toast,dc=idealx,dc=org"; +	ok = ldb.rename(dn, dn2); +	assert(ok.error == 0); +	/* Check in local db */ +	res = ldb.search("", dn2, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn2); +	assert(res.msgs[0].foo == "baz"); +	assert(res.msgs[0].revision == "1"); +	assert(res.msgs[0].description == "foo"); + +	/* Delete local record */ +	ok = ldb.del(dn2); +	assert(ok.error == 0); +	/* Check it's gone */ +	res = ldb.search("", dn2, ldb.SCOPE_BASE); +	assert(res.error == 0); +	assert(res.msgs.length == 0); + +	println("Testing modification of remote records"); + +	/* Add remote record */ +	dn = s4.dn("cn=test"); +	dn2 = s3.dn("cn=test"); +	ldif = " +dn: " + dn2 + " +cn: test +description: foo +sambaBadPasswordCount: 3 +sambaNextRid: 1001 +"; +	ok = s3.db.add(ldif); +	assert(ok.error == 0); +	/* Check it's there */ +	attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid"); +	res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn2); +	assert(res.msgs[0].description == "foo"); +	assert(res.msgs[0].sambaBadPasswordCount == "3"); +	assert(res.msgs[0].sambaNextRid == "1001"); +	/* Check in mapped db */ +	attrs = new Array("description", "badPwdCount", "nextRid"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == "foo"); +	assert(res.msgs[0].badPwdCount == "3"); +	assert(res.msgs[0].nextRid == "1001"); +	/* Check in local db */ +	res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 0); + +	/* Modify remote data of remote record */ +	ldif = " +dn: " + dn + " +replace: description +description: test +replace: badPwdCount +badPwdCount: 4 +"; +	ok = ldb.modify(ldif); +	/* Check in mapped db */ +	attrs = new Array("description", "badPwdCount", "nextRid"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].badPwdCount == "4"); +	assert(res.msgs[0].nextRid == "1001"); +	/* Check in remote db */ +	attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid"); +	res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn2); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].sambaBadPasswordCount == "4"); +	assert(res.msgs[0].sambaNextRid == "1001"); + +	/* Rename remote record */ +	dn2 = s4.dn("cn=toast"); +	ok = ldb.rename(dn, dn2); +	assert(ok.error == 0); +	/* Check in mapped db */ +	dn = dn2; +	attrs = new Array("description", "badPwdCount", "nextRid"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].badPwdCount == "4"); +	assert(res.msgs[0].nextRid == "1001"); +	/* Check in remote db */ +	dn2 = s3.dn("cn=toast"); +	attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid"); +	res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn2); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].sambaBadPasswordCount == "4"); +	assert(res.msgs[0].sambaNextRid == "1001"); + +	/* Delete remote record */ +	ok = ldb.del(dn); +	assert(ok.error == 0); +	/* Check in mapped db */ +	res = ldb.search("", dn, ldb.SCOPE_BASE); +	assert(res.error == 0); +	assert(res.msgs.length == 0); +	/* Check in remote db */ +	res = s3.db.search("", dn2, ldb.SCOPE_BASE); +	assert(res.error == 0); +	assert(res.msgs.length == 0); + +	/* Add remote record (same as before) */ +	dn = s4.dn("cn=test"); +	dn2 = s3.dn("cn=test"); +	ldif = " +dn: " + dn2 + " +cn: test +description: foo +sambaBadPasswordCount: 3 +sambaNextRid: 1001 +"; +	ok = s3.db.add(ldif); +	assert(ok.error == 0); + +	/* Modify local data of remote record */ +	ldif = " +dn: " + dn + " +add: revision +revision: 1 +replace: description +description: test +"; +	ok = ldb.modify(ldif); +	/* Check in mapped db */ +	attrs = new Array("revision", "description"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].revision == "1"); +	/* Check in remote db */ +	res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn2); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].revision == undefined); +	/* Check in local db */ +	res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == undefined); +	assert(res.msgs[0].revision == "1"); + +	/* Delete (newly) split record */ +	ok = ldb.del(dn); +	assert(ok.error == 0); + +	println("Testing modification of split records"); + +	/* Add split record */ +	dn = s4.dn("cn=test"); +	dn2 = s3.dn("cn=test"); +	ldif = " +dn: " + dn + " +cn: test +description: foo +badPwdCount: 3 +nextRid: 1001 +revision: 1 +"; +	ok = ldb.add(ldif); +	assert(ok.error == 0); +	/* Check it's there */ +	attrs = new Array("description", "badPwdCount", "nextRid", "revision"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == "foo"); +	assert(res.msgs[0].badPwdCount == "3"); +	assert(res.msgs[0].nextRid == "1001"); +	assert(res.msgs[0].revision == "1"); +	/* Check in local db */ +	res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == undefined); +	assert(res.msgs[0].badPwdCount == undefined); +	assert(res.msgs[0].nextRid == undefined); +	assert(res.msgs[0].revision == "1"); +	/* Check in remote db */ +	attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid", "revision"); +	res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn2); +	assert(res.msgs[0].description == "foo"); +	assert(res.msgs[0].sambaBadPasswordCount == "3"); +	assert(res.msgs[0].sambaNextRid == "1001"); +	assert(res.msgs[0].revision == undefined); + +	/* Modify of split record */ +	ldif = " +dn: " + dn + " +replace: description +description: test +replace: badPwdCount +badPwdCount: 4 +replace: revision +revision: 2 +"; +	ok = ldb.modify(ldif); +	assert(ok.error == 0); +	/* Check in mapped db */ +	attrs = new Array("description", "badPwdCount", "nextRid", "revision"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].badPwdCount == "4"); +	assert(res.msgs[0].nextRid == "1001"); +	assert(res.msgs[0].revision == "2"); +	/* Check in local db */ +	res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == undefined); +	assert(res.msgs[0].badPwdCount == undefined); +	assert(res.msgs[0].nextRid == undefined); +	assert(res.msgs[0].revision == "2"); +	/* Check in remote db */ +	attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid", "revision"); +	res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn2); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].sambaBadPasswordCount == "4"); +	assert(res.msgs[0].sambaNextRid == "1001"); +	assert(res.msgs[0].revision == undefined); + +	/* Rename split record */ +	dn2 = s4.dn("cn=toast"); +	ok = ldb.rename(dn, dn2); +	assert(ok.error == 0); +	/* Check in mapped db */ +	dn = dn2; +	attrs = new Array("description", "badPwdCount", "nextRid", "revision"); +	res = ldb.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].badPwdCount == "4"); +	assert(res.msgs[0].nextRid == "1001"); +	assert(res.msgs[0].revision == "2"); +	/* Check in local db */ +	res = s4.db.search("", dn, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn); +	assert(res.msgs[0].description == undefined); +	assert(res.msgs[0].badPwdCount == undefined); +	assert(res.msgs[0].nextRid == undefined); +	assert(res.msgs[0].revision == "2"); +	/* Check in remote db */ +	dn2 = s3.dn("cn=toast"); +	attrs = new Array("description", "sambaBadPasswordCount", "sambaNextRid", "revision"); +	res = s3.db.search("", dn2, ldb.SCOPE_BASE, attrs); +	assert(res.error == 0); +	assert(res.msgs.length == 1); +	assert(res.msgs[0].dn == dn2); +	assert(res.msgs[0].description == "test"); +	assert(res.msgs[0].sambaBadPasswordCount == "4"); +	assert(res.msgs[0].sambaNextRid == "1001"); +	assert(res.msgs[0].revision == undefined); + +	/* Delete split record */ +	ok = ldb.del(dn); +	assert(ok.error == 0); +	/* Check in mapped db */ +	res = ldb.search("", dn, ldb.SCOPE_BASE); +	assert(res.error == 0); +	assert(res.msgs.length == 0); +	/* Check in local db */ +	res = s4.db.search("", dn, ldb.SCOPE_BASE); +	assert(res.error == 0); +	assert(res.msgs.length == 0); +	/* Check in remote db */ +	res = s3.db.search("", dn2, ldb.SCOPE_BASE); +	assert(res.error == 0); +	assert(res.msgs.length == 0); +} + +function make_dn(rdn) +{ +	return rdn + ",sambaDomainName=TESTS," + this.BASEDN; +} + +function make_s4dn(rdn) +{ +	return rdn + "," + this.BASEDN; +} + +var ldb = ldb_init(); + +sys = sys_init(); +var ldbfile = prefix + "/" + "test.ldb"; +var ldburl = "tdb://" + ldbfile; + +var samba4 = new Object("samba4 partition info"); +samba4.file = prefix + "/" + "samba4.ldb"; +samba4.url = "tdb://" + samba4.file; +samba4.BASEDN = "dc=vernstok,dc=nl"; +samba4.db = ldb_init(); +samba4.dn = make_s4dn; + +var samba3 = new Object("samba3 partition info"); +samba3.file = prefix + "/" + "samba3.ldb"; +samba3.url = "tdb://" + samba3.file; +samba3.BASEDN = "cn=Samba3Sam"; +samba3.db = ldb_init(); +samba3.dn = make_dn; + +var templates = new Object("templates partition info"); +templates.file = prefix + "/" + "templates.ldb"; +templates.url = "tdb://" + templates.file; +templates.BASEDN = "cn=templates"; +templates.db = ldb_init(); + +sys.unlink(ldbfile); +sys.unlink(samba3.file); +sys.unlink(templates.file); +sys.unlink(samba4.file); + +var ok = ldb.connect(ldburl); +assert(ok); +var ok = samba3.db.connect(samba3.url); +assert(ok); +var ok = templates.db.connect(templates.url); +assert(ok); +var ok = samba4.db.connect(samba4.url); +assert(ok); + +setup_data(samba3, sys.file_load(datadir + "/" + "samba3.ldif")); +setup_data(templates, sys.file_load(datadir + "/" + "provision_samba3sam_templates.ldif")); +setup_modules(ldb, samba3, samba4, sys.file_load(datadir + "/" + "provision_samba3sam.ldif")); + +ldb = ldb_init(); +var ok = ldb.connect(ldburl); +assert(ok); + +test_s3sam_search(ldb); +test_s3sam_modify(ldb, samba3); + +sys.unlink(ldbfile); +sys.unlink(samba3.file); +sys.unlink(templates.file); +sys.unlink(samba4.file); + +ldb = ldb_init(); +var ok = ldb.connect(ldburl); +assert(ok); +samba3.db = ldb_init(); +var ok = samba3.db.connect(samba3.url); +assert(ok); +templates.db = ldb_init(); +var ok = templates.db.connect(templates.url); +assert(ok); +samba4.db = ldb_init(); +var ok = samba4.db.connect(samba4.url); +assert(ok); + +setup_data(templates, sys.file_load(datadir + "/" + "provision_samba3sam_templates.ldif")); +setup_modules(ldb, samba3, samba4, sys.file_load(datadir + "provision_samba3sam.ldif")); + +ldb = ldb_init(); +var ok = ldb.connect(ldburl); +assert(ok); + +test_map_search(ldb, samba3, samba4); +test_map_modify(ldb, samba3, samba4); + +sys.unlink(ldbfile); +sys.unlink(samba3.file); +sys.unlink(samba4.file); + +return 0;  | 
