mirror of
https://github.com/samba-team/samba.git
synced 2025-03-10 12:58:35 +03:00
Compare commits
12 Commits
4fcdb01808
...
5ad1a93107
Author | SHA1 | Date | |
---|---|---|---|
|
5ad1a93107 | ||
|
d8b7712c53 | ||
|
4fa67dee9a | ||
|
2a7e74898a | ||
|
781057b3ca | ||
|
77ad9096d0 | ||
|
df3f7be326 | ||
|
9754980b03 | ||
|
9aefaa9dc9 | ||
|
0031a82478 | ||
|
4f57365a1e | ||
|
9a332b4feb |
@ -31,6 +31,9 @@
|
||||
|
||||
#undef strcasecmp
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_LDB
|
||||
|
||||
static int ldb_eval_transitive_filter_helper(TALLOC_CTX *mem_ctx,
|
||||
struct ldb_context *ldb,
|
||||
const char *attr,
|
||||
|
@ -38,6 +38,9 @@
|
||||
#include "../lib/util/asn1.h"
|
||||
#include "lib/util/smb_strtox.h"
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_LDB
|
||||
|
||||
/*
|
||||
use ndr_print_* to convert a NDR formatted blob to a ldif formatted blob
|
||||
|
||||
|
@ -926,7 +926,7 @@ char *ldb_dn_alloc_linearized(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
|
||||
|
||||
static bool ldb_dn_casefold_internal(struct ldb_dn *dn)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i, j;
|
||||
int ret;
|
||||
|
||||
if ( ! dn || dn->invalid) return false;
|
||||
@ -954,18 +954,24 @@ static bool ldb_dn_casefold_internal(struct ldb_dn *dn)
|
||||
&(dn->components[i].value),
|
||||
&(dn->components[i].cf_value));
|
||||
if (ret != 0) {
|
||||
goto failed;
|
||||
goto failed_1;
|
||||
}
|
||||
}
|
||||
|
||||
dn->valid_case = true;
|
||||
|
||||
return true;
|
||||
|
||||
failed:
|
||||
for (i = 0; i < dn->comp_num; i++) {
|
||||
LDB_FREE(dn->components[i].cf_name);
|
||||
LDB_FREE(dn->components[i].cf_value.data);
|
||||
failed_1:
|
||||
/*
|
||||
* Although we try to always initialise .cf_name and .cf.value.data to
|
||||
* NULL, we want to avoid TALLOC_FREEing the values we have not just
|
||||
* set here.
|
||||
*/
|
||||
TALLOC_FREE(dn->components[i].cf_name);
|
||||
failed:
|
||||
for (j = 0; j < i; i++) {
|
||||
TALLOC_FREE(dn->components[j].cf_name);
|
||||
TALLOC_FREE(dn->components[j].cf_value.data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1056,13 +1062,15 @@ int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn)
|
||||
if (base->linearized && dn->linearized && dn->special == base->special) {
|
||||
/* try with a normal compare first, if we are lucky
|
||||
* we will avoid exploding and casefolding */
|
||||
int dif;
|
||||
dif = strlen(dn->linearized) - strlen(base->linearized);
|
||||
if (dif < 0) {
|
||||
return dif;
|
||||
size_t len_dn = strlen(dn->linearized);
|
||||
size_t len_base = strlen(base->linearized);
|
||||
|
||||
if (len_dn < len_base) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(base->linearized,
|
||||
&dn->linearized[dif]) == 0) {
|
||||
&dn->linearized[len_dn - len_base]) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -1165,6 +1173,7 @@ int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1)
|
||||
}
|
||||
|
||||
if (( ! dn0->valid_case) || ( ! dn1->valid_case)) {
|
||||
bool ok0, ok1;
|
||||
if (dn0->linearized && dn1->linearized) {
|
||||
/* try with a normal compare first, if we are lucky
|
||||
* we will avoid exploding and casefolding */
|
||||
@ -1172,15 +1181,20 @@ int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! ldb_dn_casefold_internal(dn0)) {
|
||||
/*
|
||||
* If a DN can't casefold, it goes to the end.
|
||||
*/
|
||||
ok0 = ldb_dn_casefold_internal(dn0);
|
||||
ok1 = ldb_dn_casefold_internal(dn1);
|
||||
if (! ok0) {
|
||||
if (! ok1) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( ! ldb_dn_casefold_internal(dn1)) {
|
||||
if (! ok1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1294,19 +1294,23 @@ int ldb_filter_attrs_in_place(struct ldb_message *msg,
|
||||
keep_all = true;
|
||||
}
|
||||
|
||||
if (keep_all) {
|
||||
return LDB_SUCCESS;
|
||||
}
|
||||
/*
|
||||
* Find the intersection between the msg elements and attrs.
|
||||
*
|
||||
* TODO, maybe: use a faster algorithm when (n * m) is too large.
|
||||
*/
|
||||
for (i = 0; i < msg->num_elements; i++) {
|
||||
bool found = false;
|
||||
unsigned int j;
|
||||
|
||||
if (keep_all) {
|
||||
found = true;
|
||||
} else {
|
||||
for (j = 0; attrs[j]; j++) {
|
||||
int cmp = ldb_attr_cmp(msg->elements[i].name, attrs[j]);
|
||||
if (cmp == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
for (j = 0; attrs[j]; j++) {
|
||||
int cmp = ldb_attr_cmp(msg->elements[i].name, attrs[j]);
|
||||
if (cmp == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,7 +339,8 @@ static int ldb_kv_modified(struct ldb_module *module, struct ldb_dn *dn)
|
||||
/* only allow modifies inside a transaction, otherwise the
|
||||
* ldb is unsafe */
|
||||
if (ldb_kv->kv_ops->transaction_active(ldb_kv) == false) {
|
||||
ldb_set_errstring(ldb_module_get_ctx(module), "ltdb modify without transaction");
|
||||
ldb_set_errstring(ldb_module_get_ctx(module),
|
||||
"ldb_kv modify without transaction");
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
@ -1497,8 +1498,8 @@ static int ldb_kv_rename(struct ldb_kv_context *ctx)
|
||||
* exists, so we can return this error to the caller with an
|
||||
* unmodified DB
|
||||
*
|
||||
* Even in GUID index mode we use ltdb_key_dn() as we are
|
||||
* trying to figure out if this is just a case rename
|
||||
* Even in GUID index mode we use ldb_kv_key_dn() as we are
|
||||
* trying to figure out if this is just a case rename.
|
||||
*/
|
||||
key = ldb_kv_key_dn(msg, req->op.rename.newdn);
|
||||
if (!key.data) {
|
||||
@ -1634,7 +1635,7 @@ static int ldb_kv_prepare_commit(struct ldb_module *module)
|
||||
|
||||
if (!ldb_kv->kv_ops->transaction_active(ldb_kv)) {
|
||||
ldb_set_errstring(ldb_module_get_ctx(module),
|
||||
"ltdb_prepare_commit() called "
|
||||
"ldb_kv_prepare_commit() called "
|
||||
"without transaction active");
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
@ -2081,8 +2082,10 @@ static int ldb_kv_handle_request(struct ldb_module *module,
|
||||
|
||||
ac->timeout_timeval = tv;
|
||||
|
||||
/* set a spy so that we do not try to use the request context
|
||||
* if it is freed before ltdb_callback fires */
|
||||
/*
|
||||
* Set a spy so that we do not try to use the request context
|
||||
* if it is freed before ldb_kv_callback fires.
|
||||
*/
|
||||
ac->spy = talloc(req, struct ldb_kv_req_spy);
|
||||
if (NULL == ac->spy) {
|
||||
talloc_free(ac);
|
||||
@ -2167,7 +2170,7 @@ int ldb_kv_init_store(struct ldb_kv_private *ldb_kv,
|
||||
talloc_steal(ldb_kv->module, ldb_kv);
|
||||
|
||||
if (ldb_kv_cache_load(ldb_kv->module) != 0) {
|
||||
ldb_asprintf_errstring(ldb, "Unable to load ltdb cache "
|
||||
ldb_asprintf_errstring(ldb, "Unable to load ldb_kv cache "
|
||||
"records for backend '%s'", name);
|
||||
talloc_free(ldb_kv->module);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
|
@ -328,7 +328,7 @@ static int ldb_kv_baseinfo_init(struct ldb_module *module)
|
||||
struct ldb_val val;
|
||||
int ret;
|
||||
/* the initial sequence number must be different from the one
|
||||
set in ltdb_cache_free(). Thanks to Jon for pointing this
|
||||
set in ldb_kv_cache_free(). Thanks to Jon for pointing this
|
||||
out. */
|
||||
const char *initial_sequence_number = "1";
|
||||
|
||||
@ -476,8 +476,10 @@ int ldb_kv_cache_load(struct ldb_module *module)
|
||||
ldb_kv->pack_format_version = LDB_PACKING_FORMAT;
|
||||
ldb_kv->target_pack_format_version = LDB_PACKING_FORMAT;
|
||||
|
||||
/* error handling for ltdb_baseinfo_init() is by
|
||||
looking for the record again. */
|
||||
/*
|
||||
* error handling for ldb_kv_baseinfo_init() is by
|
||||
* looking for the record again.
|
||||
*/
|
||||
ldb_kv_baseinfo_init(module);
|
||||
|
||||
} else if (r != LDB_SUCCESS) {
|
||||
@ -527,7 +529,7 @@ int ldb_kv_cache_load(struct ldb_module *module)
|
||||
}
|
||||
|
||||
/*
|
||||
* ltdb_attributes_unload() calls internally talloc_free() on
|
||||
* ldb_kv_attributes_unload() calls internally talloc_free() on
|
||||
* any non-fixed elements in ldb->schema.attributes.
|
||||
*
|
||||
* NOTE WELL: This is per-ldb, not per module, so overwrites
|
||||
|
478
lib/ldb/tests/python/index_transparency.py
Normal file
478
lib/ldb/tests/python/index_transparency.py
Normal file
@ -0,0 +1,478 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Exhaustively test variations of search expressions on LDB database
|
||||
# with a variety of backends and index options, asserting that all
|
||||
# database variants give the same results.
|
||||
#
|
||||
# With the SKIP_SLOW_TESTS environment variable set (which is used by
|
||||
# `make test`) only unary and binary expressions will be run.
|
||||
# Otherwise ternary expressions are also run, which is a lot slower
|
||||
# (by unary, binary, ternary, I mean e.g. "(a=1)", "(&(a=1)(b=2))",
|
||||
# "(|(&(a=1)(b=2))(c=3))", respectively).
|
||||
#
|
||||
# These tests also emit some timing information, comparing the
|
||||
# performance of the various databases.
|
||||
|
||||
import os
|
||||
import time
|
||||
from itertools import product
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, "bin/python")
|
||||
import ldb
|
||||
import shutil
|
||||
|
||||
from api_base import (
|
||||
TDB_PREFIX,
|
||||
MDB_PREFIX,
|
||||
tempdir,
|
||||
LdbBaseTest,
|
||||
)
|
||||
|
||||
HAVE_LMDB = (os.getenv('HAVE_LMDB') == '1')
|
||||
SKIP_SLOW_TESTS = True if os.getenv('SKIP_SLOW_TESTS') else False
|
||||
|
||||
|
||||
def DynamicTestCase(cls):
|
||||
"""If a class is decorated with @DynamicTestCase, its
|
||||
setUpDynamicTestCases() method will be called *before* the
|
||||
setUpClass() method. At this time it can add test methods to
|
||||
the class (it is too late to do this in setUpClass).
|
||||
"""
|
||||
cls.setUpDynamicTestCases()
|
||||
return cls
|
||||
|
||||
|
||||
class SearchTestBase(LdbBaseTest):
|
||||
prefix = TDB_PREFIX
|
||||
unary_filters = ()
|
||||
binary_filters = ()
|
||||
ternary_filters = ()
|
||||
non_existent_attrs = ''
|
||||
non_existent_values = ''
|
||||
|
||||
@classmethod
|
||||
def add_index(cls, db, portion=1, guid=True):
|
||||
attrs = ["a", "b", "c", "ou"]
|
||||
attrs = attrs[:int(len(attrs) * portion)]
|
||||
index = {
|
||||
"dn": "@INDEXLIST",
|
||||
"@IDXONE": "1",
|
||||
"@IDXATTR": attrs,
|
||||
}
|
||||
|
||||
if guid:
|
||||
index["@IDXGUID"] = "objectUUID"
|
||||
index["@IDX_DN_GUID"] = "GUID"
|
||||
|
||||
db.add(index)
|
||||
|
||||
@classmethod
|
||||
def add(cls, msg):
|
||||
for db in cls.dbs:
|
||||
db.add(msg)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super().tearDownClass()
|
||||
print(f"\n{cls}")
|
||||
for t, db in zip(cls.times, cls.dbs):
|
||||
print(f"{t} {db}")
|
||||
db.disconnect()
|
||||
shutil.rmtree(cls.testdir)
|
||||
|
||||
@classmethod
|
||||
def setUpDynamicTestCases(cls):
|
||||
cls.testdir = tempdir()
|
||||
|
||||
options = ["modules:rdn_name"]
|
||||
|
||||
cls.times = []
|
||||
cls.dbs = []
|
||||
cls.filenames = []
|
||||
for name, prefix, index_args in cls.databases:
|
||||
flags = 0
|
||||
if prefix == MDB_PREFIX:
|
||||
if not HAVE_LMDB:
|
||||
print("skipping MDB test: we have no LMDB")
|
||||
continue
|
||||
flags |= ldb.FLG_NOSYNC
|
||||
|
||||
filename = os.path.join(cls.testdir, f"{name}.ldb")
|
||||
url = prefix + filename
|
||||
|
||||
db = ldb.Ldb(url, flags=flags, options=options)
|
||||
if index_args is not None:
|
||||
cls.add_index(db, *index_args)
|
||||
|
||||
cls.dbs.append(db)
|
||||
cls.times.append(0.0)
|
||||
cls.filenames.append(filename)
|
||||
|
||||
cls.add({"dn": "@ATTRIBUTES", "DC": "CASE_INSENSITIVE"})
|
||||
|
||||
cls.add({"dn": "DC=TOP",
|
||||
"name": b"top",
|
||||
"objectUUID": b" top of dn tower"})
|
||||
|
||||
# what follows will add a number of OUs with a mix of
|
||||
# attributes. The 16 byte GUID of the OU (in the "objectUUID" field,
|
||||
# not objectGUID, which has special handling) is a text string
|
||||
# describing what attributes the OU should have.
|
||||
#
|
||||
# For example, ' 87 aZ bY cXYZ' says this is "ou87" with
|
||||
# attribute 'a' having the values 'Z', attribute 'b' having
|
||||
# the value 'Y' and 'c' having the values 'X', 'Y', and 'Z'.
|
||||
#
|
||||
# 'name' is always unique. Sometimes 'name' will equal 'ou',
|
||||
# but sometimes it will be different ("ou number 87").
|
||||
#
|
||||
# We use a crappy LCG to spread the values around, with each
|
||||
# attribute/value pair having around a 25% chance of occurring
|
||||
# on any particular ou.
|
||||
#
|
||||
# The cls.attr_sets are effectively a python level index that
|
||||
# should behave identically to the LDB index. That is,
|
||||
#
|
||||
# cls.attr_sets['bY'] & cls.attr_sets['cZ']
|
||||
#
|
||||
# should refer to the same OUs as a '(&(b=Y)(c=Z)' search.
|
||||
|
||||
ou = 0
|
||||
cls.guids = []
|
||||
|
||||
# cls.attr_sets are not actually used in the tests, but are
|
||||
# useful if you ever want to debug the tests.
|
||||
cls.attr_sets = {f'{x}{y}': set() for x, y in product(cls.attrs,
|
||||
cls.values)}
|
||||
|
||||
s = 0
|
||||
for ou in range(cls.n_objects):
|
||||
ou_attrs = {}
|
||||
guid = f'{ou:3} '
|
||||
for i in range(len(cls.attrs)):
|
||||
s = (s * 321 + ou + 1) & 0xffff
|
||||
k = cls.attrs[i]
|
||||
b = s & (s // 9)
|
||||
v = []
|
||||
ou_attrs[k] = v
|
||||
for j in range(len(cls.values)):
|
||||
if b & (1 << j):
|
||||
c = cls.values[j]
|
||||
v.append(c)
|
||||
cls.attr_sets[k + c].add(ou)
|
||||
if v:
|
||||
guid += f'{k}{"".join(v):3}'
|
||||
else:
|
||||
guid += ' '
|
||||
|
||||
if len(guid) != 16:
|
||||
# with up to 1000 objects:
|
||||
# 2 attrs -> 12 chars
|
||||
# 3 attrs -> 16 chars
|
||||
# 4 attrs -> 20 chars
|
||||
#
|
||||
# a truncated guid will always be unique because of
|
||||
# the OU number at the start.
|
||||
guid = (guid + '_' * 12)[:16]
|
||||
|
||||
name = (f"ou{ou}" if (ou % 3) else f"OU number {ou}").encode()
|
||||
cls.guids.append(guid)
|
||||
|
||||
guid = guid.encode()
|
||||
if len(guid) != 16:
|
||||
raise ValueError(f"GUID should be 16 bytes, "
|
||||
f"not {len(guid)} ('{guid}')")
|
||||
|
||||
msg = {"dn": f"OU=ou{ou},DC=TOP",
|
||||
"name": name,
|
||||
"objectUUID": guid
|
||||
}
|
||||
for k, v in ou_attrs.items():
|
||||
if v:
|
||||
msg[k] = v
|
||||
|
||||
cls.add(msg)
|
||||
|
||||
# This is how you could see how the attributes are distributed:
|
||||
#
|
||||
# from itertools import pairwise
|
||||
# for a in cls.attr_sets:
|
||||
# print(f"{a}: {len(cls.attr_sets[a])}: {sorted(cls.attr_sets[a])}")
|
||||
# for a, b in pairwise(cls.attr_sets):
|
||||
# print(f"{a}&{b}: {sorted(cls.attr_sets[a] &cls.attr_sets[b])}")
|
||||
|
||||
# If we wanted to compare the database at the end to the
|
||||
# database at the beginning (i.e. ensuring that search has no
|
||||
# side-effects), we could do something like:
|
||||
#
|
||||
# shutil.copy(cls.filenames[0], cls.filenames[0] + '.initial')
|
||||
|
||||
# add a non-existent attribute or values into some searches
|
||||
attrs = cls.attrs + cls.non_existent_attrs
|
||||
values = cls.values + cls.non_existent_values
|
||||
fn = "test_filter"
|
||||
|
||||
for scope_name, scope in cls.scopes:
|
||||
for base in cls.bases:
|
||||
if scope != ldb.SCOPE_SUBTREE and base is None:
|
||||
continue
|
||||
for f in cls.unary_filters:
|
||||
for k, v in product(attrs, values):
|
||||
filter = f.format(k1=k, v1=v)
|
||||
name = f"{scope_name}-{base}-{filter}"
|
||||
cls.generate_dynamic_test(fn, name, base, scope, filter)
|
||||
|
||||
for f in cls.binary_filters:
|
||||
for k1, v1, k2, v2 in product(attrs, values,
|
||||
attrs, values):
|
||||
filter = f.format(k1=k1, v1=v1, k2=k2, v2=v2)
|
||||
name = f"{scope_name}-{base}-{filter}"
|
||||
cls.generate_dynamic_test(fn, name, base, scope,
|
||||
filter)
|
||||
|
||||
if SKIP_SLOW_TESTS:
|
||||
# avoiding ternary tests saves a lot of time. in
|
||||
# autobuild we run with --skip-slow-tests, which
|
||||
# sets this variable.
|
||||
continue
|
||||
|
||||
for f in cls.ternary_filters:
|
||||
for k1, v1, k2, v2, k3, v3 in product(attrs, values,
|
||||
attrs, values,
|
||||
attrs, values,
|
||||
):
|
||||
filter = f.format(k1=k1, v1=v1,
|
||||
k2=k2, v2=v2,
|
||||
k3=k3, v3=v3)
|
||||
name = f"{scope_name}-{base}-{filter}"
|
||||
cls.generate_dynamic_test(fn, name, base, scope,
|
||||
filter)
|
||||
|
||||
@classmethod
|
||||
def generate_dynamic_test(cls, fnname, suffix, *args, doc=None):
|
||||
# adapted from samba.tests.TestCase
|
||||
# (../../../../python/samba/tests/__init__.py)
|
||||
# which ldb tests don't currently use.
|
||||
#
|
||||
# A difference here is that we ignore duplicates, while the
|
||||
# samba.tests version will raise an exception.
|
||||
|
||||
attr = "%s_%s" % (fnname, suffix)
|
||||
if hasattr(cls, attr):
|
||||
return
|
||||
|
||||
def fn(self):
|
||||
getattr(self, "_%s_with_args" % fnname)(*args)
|
||||
fn.__doc__ = doc
|
||||
setattr(cls, attr, fn)
|
||||
|
||||
def _test_filter_with_args(self, *args, **kwargs):
|
||||
"""Search in all the database, asserting that the result is the same.
|
||||
"""
|
||||
results = []
|
||||
|
||||
for i, db in enumerate(self.dbs):
|
||||
start = time.time()
|
||||
r = db.search(*args, **kwargs)
|
||||
self.times[i] += time.time() - start
|
||||
results.append(r)
|
||||
|
||||
first = results[0]
|
||||
rest = results[1:]
|
||||
|
||||
if first is None:
|
||||
for r in rest:
|
||||
self.assertIsNone(r)
|
||||
return None
|
||||
|
||||
# converting the results into sorted lists allows python
|
||||
# comparison to work.
|
||||
first_ = sorted(first)
|
||||
for i, r in enumerate(rest):
|
||||
self.assertEqual(len(first), len(r),
|
||||
f"{i + 1}: {self.dbs[i + 1]}")
|
||||
r_ = sorted(r)
|
||||
self.assertEqual(first_, r_)
|
||||
|
||||
return first
|
||||
|
||||
|
||||
@DynamicTestCase
|
||||
class SearchTest(SearchTestBase):
|
||||
n_objects = 100
|
||||
attrs = 'abc'
|
||||
values = 'XYZ'
|
||||
non_existent_attrs = 'M'
|
||||
non_existent_values = 'm'
|
||||
|
||||
databases = (
|
||||
#['tdb-unindexed', TDB_PREFIX, None],
|
||||
['tdb-indexed-dn', TDB_PREFIX, (1, False)],
|
||||
['tdb-half-indexed', TDB_PREFIX, (0.5,)],
|
||||
['tdb-indexed-guid', TDB_PREFIX, ()],
|
||||
['mdb-indexed', MDB_PREFIX, ()],
|
||||
)
|
||||
|
||||
scopes = (('base', ldb.SCOPE_BASE),
|
||||
('subtree', ldb.SCOPE_SUBTREE),
|
||||
('onelevel', ldb.SCOPE_ONELEVEL))
|
||||
|
||||
bases = (None,
|
||||
'DC=TOP',
|
||||
'OU=OU7,DC=TOP'
|
||||
)
|
||||
|
||||
unary_filters = ("(&({k1}={v1})({k1}={v1}))",
|
||||
"({k1}={v1}*)",
|
||||
"({k1}=*)",
|
||||
"({k1}=*{v1}*)",
|
||||
"(!({k1}={v1}))",
|
||||
)
|
||||
|
||||
binary_filters = ("(&({k1}={v1})({k2}={v2}))",
|
||||
"(|({k1}={v1})({k2}={v2}))",
|
||||
"(|({k1}={v1})(!({k2}={v2})))",
|
||||
"(&(!({k1}={v1}))({k2}={v2}))",
|
||||
)
|
||||
|
||||
ternary_filters = ("(&({k1}={v1})({k2}={v2})({k3}={v3}))",
|
||||
"(|({k1}={v1})({k2}={v2})({k3}={v3}))",
|
||||
"(|({k1}={v1})(!(|({k2}={v2})({k3}={v3}))))",
|
||||
"(&(!({k1}={v1}))(&({k2}={v2})({k3}={v3})))",
|
||||
"(&({k1}={v1})(|({k2}={v2})({k3}={v3})))",
|
||||
)
|
||||
|
||||
|
||||
@DynamicTestCase
|
||||
class SearchTestFewObjects(SearchTestBase):
|
||||
n_objects = 5
|
||||
attrs = 'abc'
|
||||
values = 'XYZ'
|
||||
non_existent_attrs = 'M'
|
||||
non_existent_values = 'm'
|
||||
|
||||
databases = (
|
||||
#['tdb-unindexed', TDB_PREFIX, None],
|
||||
['tdb-indexed-dn', TDB_PREFIX, (1, False)],
|
||||
['tdb-half-indexed', TDB_PREFIX, (0.5,)],
|
||||
['tdb-indexed-guid', TDB_PREFIX, ()],
|
||||
['mdb-indexed', MDB_PREFIX, ()],
|
||||
)
|
||||
|
||||
scopes = (('base', ldb.SCOPE_BASE),
|
||||
('subtree', ldb.SCOPE_SUBTREE),
|
||||
('onelevel', ldb.SCOPE_ONELEVEL))
|
||||
|
||||
bases = (None,
|
||||
'DC=TOP',
|
||||
'OU=OU7,DC=TOP'
|
||||
)
|
||||
|
||||
unary_filters = ("(&({k1}={v1})({k1}={v1}))",
|
||||
"({k1}={v1}*)",
|
||||
"({k1}=*{v1}*)",
|
||||
"(!({k1}={v1}))",
|
||||
"(!({k1}=*))",
|
||||
)
|
||||
|
||||
binary_filters = ("(&({k1}={v1})({k2}={v2}))",
|
||||
"(|({k1}={v1})({k2}={v2}))",
|
||||
"(|({k1}={v1})(!({k2}={v2})))",
|
||||
"(&(!({k1}={v1}))({k2}={v2}))",
|
||||
)
|
||||
|
||||
ternary_filters = ("(&({k1}={v1})({k2}={v2})({k3}={v3}))",
|
||||
"(|({k1}={v1})({k2}={v2})({k3}={v3}))",
|
||||
"(|({k1}={v1})(!(|({k2}={v2})({k3}={v3}))))",
|
||||
"(&(!({k1}={v1}))(&({k2}={v2})({k3}={v3})))",
|
||||
"(&({k1}={v1})(|({k2}={v2})({k3}={v3})))",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@DynamicTestCase
|
||||
class SearchTestManyAttrs(SearchTestBase):
|
||||
n_objects = 50
|
||||
attrs = 'abcdefghijklm'
|
||||
values = 'PQ'
|
||||
|
||||
databases = (
|
||||
['tdb-unindexed', TDB_PREFIX, None],
|
||||
['tdb-indexed-dn', TDB_PREFIX, (1, False)],
|
||||
['tdb-half-indexed', TDB_PREFIX, (0.5,)],
|
||||
['tdb-indexed-guid', TDB_PREFIX, ()],
|
||||
['mdb-indexed', MDB_PREFIX, ()],
|
||||
)
|
||||
|
||||
scopes = (('base', ldb.SCOPE_BASE),
|
||||
('subtree', ldb.SCOPE_SUBTREE),
|
||||
('onelevel', ldb.SCOPE_ONELEVEL))
|
||||
|
||||
bases = (None,
|
||||
'DC=TOP',
|
||||
'OU=OU7,DC=TOP'
|
||||
)
|
||||
|
||||
unary_filters = ("(&({k1}={v1})({k1}={v1}))",
|
||||
"({k1}={v1}*)",
|
||||
"({k1}=*{v1}*)",
|
||||
"(!({k1}={v1}))",
|
||||
"(!({k1}=*))",
|
||||
)
|
||||
|
||||
binary_filters = ("(&({k1}={v1})({k2}={v2}))",
|
||||
"(|({k1}={v1})(!({k2}={v2})))",
|
||||
"(&(!({k1}={v1}))({k2}={v2}))",
|
||||
)
|
||||
|
||||
ternary_filters = ("(&({k1}={v1})({k2}={v2})({k3}={v3}))",
|
||||
)
|
||||
|
||||
|
||||
@DynamicTestCase
|
||||
class GreaterAndLessThanSearchTest(SearchTestBase):
|
||||
n_objects = 50
|
||||
attrs = 'abc'
|
||||
values = '13'
|
||||
non_existent_attrs = 'M'
|
||||
non_existent_values = '2' # between the real ones
|
||||
|
||||
databases = (
|
||||
#['tdb-unindexed', TDB_PREFIX, None],
|
||||
['tdb-indexed-dn', TDB_PREFIX, (1, False)],
|
||||
['tdb-half-indexed', TDB_PREFIX, (0.5,)],
|
||||
['tdb-indexed-guid', TDB_PREFIX, ()],
|
||||
['mdb-indexed', MDB_PREFIX, ()],
|
||||
)
|
||||
|
||||
scopes = (('base', ldb.SCOPE_BASE),
|
||||
('subtree', ldb.SCOPE_SUBTREE),
|
||||
('onelevel', ldb.SCOPE_ONELEVEL))
|
||||
|
||||
bases = ('DC=TOP',
|
||||
'OU=OU7,DC=TOP'
|
||||
)
|
||||
|
||||
unary_filters = ("(&({k1}>={v1})({k1}<={v1}))",
|
||||
"({k1}<={v1}*)",
|
||||
"({k1}>=*{v1}*)",
|
||||
"(!({k1}>={v1}))",
|
||||
)
|
||||
|
||||
binary_filters = ("(&({k1}>={v1})({k2}<={v2}))",
|
||||
"(|({k1}={v1})({k2}>={v2}))",
|
||||
"(|({k1}<={v1})(!({k2}={v2})))",
|
||||
"(&(!({k1}>={v1}))({k2}={v2}))",
|
||||
)
|
||||
|
||||
ternary_filters = ("(&({k1}>={v1})({k2}>={v2})({k3}>={v3}))",
|
||||
"(|({k1}<={v1})({k2}>={v2})({k3}<={v3}))",
|
||||
"(|({k1}={v1})(!(|({k2}>={v2})({k3}={v3}))))",
|
||||
"(&(!({k1}={v1}))(&({k2}<={v2})({k3}={v3})))",
|
||||
"(&({k1}>={v1})(|({k2}={v2})({k3}<={v3})))",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.TestProgram()
|
@ -245,6 +245,9 @@ class Command(object):
|
||||
elif ldb_ecode == ERR_INSUFFICIENT_ACCESS_RIGHTS:
|
||||
self._print_error("User has insufficient access rights")
|
||||
force_traceback = False
|
||||
elif ldb_emsg == "Operation unavailable without authentication":
|
||||
self._print_error(ldb_emsg)
|
||||
force_traceback = False
|
||||
else:
|
||||
self._print_error(message, ldb_emsg, 'ldb')
|
||||
|
||||
|
@ -672,18 +672,27 @@ sub provision_raw_prepare($$$$$$$$$$$$$$)
|
||||
push (@provision_options, "OPENSSL_FORCE_FIPS_MODE=1");
|
||||
}
|
||||
|
||||
if (defined($ENV{GDB_PROVISION})) {
|
||||
push (@provision_options, "gdb --args");
|
||||
if (!defined($ENV{PYTHON})) {
|
||||
push (@provision_options, "env");
|
||||
push (@provision_options, "python");
|
||||
if (defined($ENV{GDB_PROVISION}) ||
|
||||
defined($ENV{RR_PROVISION}) ||
|
||||
defined($ENV{PY_DEV_PROVISION}) ||
|
||||
defined($ENV{VALGRIND_PROVISION})) {
|
||||
if (defined($ENV{GDB_PROVISION})) {
|
||||
push (@provision_options, "gdb --args");
|
||||
}
|
||||
if (defined($ENV{RR_PROVISION})) {
|
||||
push (@provision_options, "rr");
|
||||
}
|
||||
if (defined($ENV{VALGRIND_PROVISION})) {
|
||||
push (@provision_options, "valgrind");
|
||||
}
|
||||
}
|
||||
if (defined($ENV{VALGRIND_PROVISION})) {
|
||||
push (@provision_options, "valgrind");
|
||||
if (!defined($ENV{PYTHON})) {
|
||||
push (@provision_options, "env");
|
||||
push (@provision_options, "python");
|
||||
push (@provision_options, "env");
|
||||
push (@provision_options, "python");
|
||||
}
|
||||
if (defined($ENV{PY_DEV_PROVISION})) {
|
||||
# makes Python more likely to emit warnings
|
||||
# and debug info.
|
||||
push (@provision_options, "-X dev");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,12 @@ planpythontestsuite("none", "repack",
|
||||
extra_path=['lib/ldb/tests/python'],
|
||||
environ={'HAVE_LMDB': str(int(have_lmdb))})
|
||||
|
||||
planpythontestsuite("none", "index_transparency",
|
||||
name="ldb.python.index_transparency",
|
||||
extra_path=['lib/ldb/tests/python'],
|
||||
environ={'SKIP_SLOW_TESTS': '1',
|
||||
'HAVE_LMDB': str(int(have_lmdb))})
|
||||
|
||||
# LDB tests for standalone operation, in the tr_TR.UTF-8 to cover
|
||||
# dotless i locales, see
|
||||
# https://bugzilla.samba.org/show_bug.cgi?id=15248
|
||||
|
Loading…
x
Reference in New Issue
Block a user