From 1b4b03720c409b183debe0e0532b1009301e9cb2 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Sun, 19 Nov 2017 22:47:00 +0100
Subject: [PATCH 82/83] CACHE_REQ: Use the domain-locator request to only
search domains where the entry was found
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Uses the internal cache_req interface around the getAccountDomain to only
search the domain returned by the cache_req_locate_domain_recv() request.
If that request returns that no domain matched, all domains (belonging
to the currently processed main domain) are skipped by setting the
per-type negative cache.
if a domain is reported as containing an object, all domains except that
one are marked with the negative cache entries.
Resolves:
https://pagure.io/SSSD/sssd/issue/3468
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
(cherry picked from commit f2a5e29f063f9d623c1336d76f4b2bc500c1a5e2)
---
src/responder/common/cache_req/cache_req.c | 402 +++++-
src/responder/common/cache_req/cache_req_domain.h | 1 +
src/tests/cmocka/test_responder_cache_req.c | 1373 +++++++++++++++++++++
3 files changed, 1758 insertions(+), 18 deletions(-)
diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
index 110df561101be538e3f0496addfa2e14e42ea918..ad9bc040dd999a205713141e6a1512e47b69c45e 100644
--- a/src/responder/common/cache_req/cache_req.c
+++ b/src/responder/common/cache_req/cache_req.c
@@ -363,6 +363,53 @@ static void cache_req_global_ncache_add(struct cache_req *cr)
return;
}
+static bool cache_req_check_acct_domain_lookup_type(struct cache_req *cr,
+ struct sss_domain_info *dom)
+{
+ struct sss_domain_info *head;
+ int nret;
+
+ head = get_domains_head(dom);
+ if (head == NULL) {
+ return false;
+ }
+
+ nret = sss_ncache_check_domain_locate_type(cr->rctx->ncache,
+ head,
+ cr->plugin->name);
+ if (nret == ENOENT) {
+ return true;
+ }
+ return false;
+}
+
+static errno_t cache_req_set_acct_domain_lookup_type(struct cache_req *cr,
+ struct sss_domain_info *dom)
+{
+ struct sss_domain_info *head;
+
+ head = get_domains_head(dom);
+ if (head == NULL) {
+ return EINVAL;
+ }
+
+ return sss_ncache_set_domain_locate_type(cr->rctx->ncache,
+ head,
+ cr->plugin->name);
+}
+
+static void cache_req_domain_set_locate_flag(struct cache_req_domain *domains,
+ struct cache_req *cr)
+{
+ struct cache_req_domain *crd_iter;
+
+ DLIST_FOR_EACH(crd_iter, domains) {
+ if (cache_req_check_acct_domain_lookup_type(cr, crd_iter->domain)) {
+ crd_iter->locate_domain = true;
+ }
+ }
+}
+
static bool
cache_req_assume_upn(struct cache_req *cr)
{
@@ -391,6 +438,227 @@ cache_req_assume_upn(struct cache_req *cr)
return true;
}
+struct cache_req_locate_dom_state {
+ /* input data */
+ struct tevent_context *ev;
+ struct cache_req *cr;
+ struct cache_req_domain *req_domains;
+
+ /* Return values in case the first cache lookup succeeds */
+ struct ldb_result *result;
+ bool dp_success;
+};
+
+static void cache_req_locate_dom_cache_done(struct tevent_req *subreq);
+static void cache_req_locate_dom_done(struct tevent_req *subreq);
+static void cache_req_locate_dom_mark_neg_all(
+ struct cache_req_locate_dom_state *state);
+static void cache_req_locate_dom_mark_neg_domains(
+ struct cache_req_locate_dom_state *state,
+ const char *found_domain_name);
+
+static struct tevent_req *cache_req_locate_dom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cache_req *cr,
+ struct cache_req_domain *req_domains)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct cache_req_locate_dom_state *state = NULL;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cache_req_locate_dom_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+ state->ev = ev;
+ state->cr = cr;
+ state->req_domains = req_domains;
+
+ /* It is wasteful to run the domain locator request if the results are
+ * present in the cache, because the domain locator always contacts
+ * the DP. Therefore, first run a cache-only search and only if the
+ * requested data is not available, run the locator
+ *
+ * FIXME - this could be optimized further if we are running the
+ * second iteration with cache_first, then we don't need to search
+ * again
+ */
+ subreq = cache_req_search_send(state,
+ state->ev,
+ state->cr,
+ false, /* Don't bypass cache */
+ true); /* Do bypass DP */
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+ tevent_req_set_callback(subreq, cache_req_locate_dom_cache_done, req);
+
+ return req;
+
+immediately:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void cache_req_locate_dom_cache_done(struct tevent_req *subreq)
+{
+ struct cache_req_locate_dom_state *state = NULL;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_locate_dom_state);
+
+ ret = cache_req_search_recv(state, subreq, &state->result, &state->dp_success);
+ talloc_zfree(subreq);
+
+ switch (ret) {
+ case EOK:
+ /* Just finish the request and let the caller handle the result */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Result found in the cache\n");
+ tevent_req_done(req);
+ return;
+ case ENOENT:
+ /* Not cached and locator was requested, run the locator
+ * DP request plugin
+ */
+ subreq = cache_req_locate_domain_send(state,
+ state->ev,
+ state->cr);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, cache_req_locate_dom_done, req);
+ return;
+ default:
+ DEBUG(SSSDBG_OP_FAILURE,
+ "cache_req_search_recv returned [%d]: %s\n", ret, sss_strerror(ret));
+ break;
+ }
+
+ tevent_req_error(req, ret);
+ return;
+}
+
+static void cache_req_locate_dom_done(struct tevent_req *subreq)
+{
+ struct cache_req_locate_dom_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+ char *found_domain_name;
+ int nret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_locate_dom_state);
+
+ ret = cache_req_locate_domain_recv(state, subreq, &found_domain_name);
+ talloc_zfree(subreq);
+ switch (ret) {
+ case ERR_GET_ACCT_DOM_NOT_SUPPORTED:
+ nret = cache_req_set_acct_domain_lookup_type(state->cr,
+ state->cr->domain);
+ if (nret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failed to disable domain locating functionality for %s\n",
+ state->cr->plugin->name);
+ }
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Disabled domain locating functionality for %s\n",
+ state->cr->plugin->name);
+ break;
+ case ERR_NOT_FOUND:
+ cache_req_locate_dom_mark_neg_all(state);
+ break;
+ case EOK:
+ cache_req_locate_dom_mark_neg_domains(state, found_domain_name);
+ break;
+ default:
+ /* We explicitly ignore errors here */
+ break;
+ }
+
+ tevent_req_done(req);
+ return;
+}
+
+static void cache_req_locate_dom_mark_neg_all(
+ struct cache_req_locate_dom_state *state)
+{
+ struct cache_req_domain *iter;
+
+ DLIST_FOR_EACH(iter, state->req_domains) {
+ if (get_domains_head(state->cr->domain) != get_domains_head(iter->domain)) {
+ /* Only add to negative cache for domains from the same "main"
+ * domain" */
+ continue;
+ }
+ cache_req_search_ncache_add_to_domain(state->cr, iter->domain);
+ }
+}
+
+static void cache_req_locate_dom_mark_neg_domains(
+ struct cache_req_locate_dom_state *state,
+ const char *found_domain_name)
+{
+ struct sss_domain_info *found_domain;
+ struct cache_req_domain *iter;
+
+ found_domain = find_domain_by_name(get_domains_head(state->cr->domain),
+ found_domain_name,
+ true);
+ if (found_domain == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot find domain %s\n", found_domain_name);
+ return;
+ }
+
+ /* Set negcache in all subdomains of the one being examined
+ * except the found one */
+ DLIST_FOR_EACH(iter, state->req_domains) {
+ if (strcasecmp(found_domain_name,
+ iter->domain->name) == 0) {
+ continue;
+ }
+
+ if (get_domains_head(found_domain) != get_domains_head(iter->domain)) {
+ /* Don't set negative cache for domains outside the main
+ * domain/subdomain tree b/c the locator request is not
+ * authoritative for them
+ */
+ continue;
+ }
+ cache_req_search_ncache_add_to_domain(state->cr, iter->domain);
+ }
+}
+
+static errno_t cache_req_locate_dom_cache_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct ldb_result **_result,
+ bool *_dp_success)
+{
+ struct cache_req_locate_dom_state *state;
+
+ state = tevent_req_data(req, struct cache_req_locate_dom_state);
+
+ if (_dp_success != NULL) {
+ *_dp_success = state->dp_success;
+ }
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (_result != NULL) {
+ *_result = talloc_steal(mem_ctx, state->result);
+ }
+
+ return EOK;
+}
+
struct cache_req_search_domains_state {
/* input data */
struct tevent_context *ev;
@@ -398,6 +666,7 @@ struct cache_req_search_domains_state {
/* work data */
struct cache_req_domain *cr_domain;
+ struct cache_req_domain *req_domains;
struct sss_domain_info *selected_domain;
struct cache_req_result **results;
size_t num_results;
@@ -408,6 +677,10 @@ struct cache_req_search_domains_state {
};
static errno_t cache_req_search_domains_next(struct tevent_req *req);
+static errno_t cache_req_handle_result(struct tevent_req *req,
+ struct ldb_result *result);
+
+static void cache_req_search_domains_locate_done(struct tevent_req *subreq);
static void cache_req_search_domains_done(struct tevent_req *subreq);
@@ -417,6 +690,7 @@ cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
struct cache_req *cr,
struct cache_req_domain *cr_domain,
bool check_next,
+ bool first_iteration,
bool bypass_cache,
bool bypass_dp)
{
@@ -435,11 +709,23 @@ cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
state->cr = cr;
state->cr_domain = cr_domain;
+ state->req_domains = cr_domain;
state->check_next = check_next;
state->dp_success = true;
state->bypass_cache = bypass_cache;
state->bypass_dp = bypass_dp;
+ if (cr->plugin->dp_get_domain_send_fn != NULL
+ && ((state->check_next && cr_domain->next != NULL)
+ || (state->bypass_cache && !first_iteration))) {
+ /* If the request is not qualified with a domain name AND
+ * there are multiple domains to search OR if this is the second
+ * pass during the "check-cache-first" schema, it makes sense
+ * to try to run the domain-locator plugin
+ */
+ cache_req_domain_set_locate_flag(cr_domain, cr);
+ }
+
ret = cache_req_search_domains_next(req);
if (ret == EAGAIN) {
return req;
@@ -510,12 +796,23 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
return ret;
}
+ if (state->cr_domain->locate_domain) {
+ subreq = cache_req_locate_dom_send(state,
+ state->ev,
+ cr,
+ state->req_domains);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(subreq, cache_req_search_domains_locate_done, req);
+ return EAGAIN;
+ }
+
subreq = cache_req_search_send(state, state->ev, cr,
state->bypass_cache, state->bypass_dp);
if (subreq == NULL) {
return ENOMEM;
}
-
tevent_req_set_callback(subreq, cache_req_search_domains_done, req);
/* we will continue with the following domain the next time */
@@ -549,6 +846,89 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
return ENOENT;
}
+static void cache_req_search_domains_locate_done(struct tevent_req *subreq)
+{
+ struct cache_req_search_domains_state *state;
+ struct ldb_result *result = NULL;
+ struct tevent_req *req;
+ bool dp_success;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct cache_req_search_domains_state);
+
+ ret = cache_req_locate_dom_cache_recv(state, subreq, &result, &dp_success);
+ talloc_zfree(subreq);
+
+ /* Remember if any DP request fails, but here it shouldn't matter
+ * as the only DP request that should realistically happen is midpoint
+ * refresh */
+ state->dp_success = !dp_success ? false : state->dp_success;
+
+ /* Don't locate the domain again */
+ state->cr_domain->locate_domain = false;
+
+ switch (ret) {
+ case EOK:
+ if (result != NULL) {
+ /* Handle result as normally */
+ ret = cache_req_handle_result(req, result);
+ if (ret != EAGAIN) {
+ goto done;
+ }
+ }
+ break;
+ default:
+ /* Some serious error has happened. Finish. */
+ goto done;
+ }
+
+ /* This is a domain less search, continue with the next domain. */
+ ret = cache_req_search_domains_next(req);
+
+done:
+ switch (ret) {
+ case EOK:
+ tevent_req_done(req);
+ break;
+ case EAGAIN:
+ break;
+ default:
+ tevent_req_error(req, ret);
+ break;
+ }
+ return;
+}
+
+static errno_t cache_req_handle_result(struct tevent_req *req,
+ struct ldb_result *result)
+{
+ struct cache_req_search_domains_state *state;
+ errno_t ret;
+
+ state = tevent_req_data(req, struct cache_req_search_domains_state);
+
+ /* We got some data from this search. Save it. */
+ ret = cache_req_create_and_add_result(state,
+ state->cr,
+ state->selected_domain,
+ result,
+ state->cr->data->name.lookup,
+ &state->results,
+ &state->num_results);
+ if (ret != EOK) {
+ /* We were unable to save data. */
+ return ret;
+ }
+
+ if (!state->check_next || !state->cr->plugin->search_all_domains) {
+ /* We are not interested in more results. */
+ return EOK;
+ }
+
+ return EAGAIN;
+}
+
static void cache_req_search_domains_done(struct tevent_req *subreq)
{
struct cache_req_search_domains_state *state;
@@ -568,25 +948,10 @@ static void cache_req_search_domains_done(struct tevent_req *subreq)
switch (ret) {
case EOK:
- /* We got some data from this search. Save it. */
- ret = cache_req_create_and_add_result(state,
- state->cr,
- state->selected_domain,
- result,
- state->cr->data->name.lookup,
- &state->results,
- &state->num_results);
- if (ret != EOK) {
- /* We were unable to save data. */
+ ret = cache_req_handle_result(req, result);
+ if (ret != EAGAIN) {
goto done;
}
-
- if (!state->check_next || !state->cr->plugin->search_all_domains) {
- /* We are not interested in more results. */
- ret = EOK;
- goto done;
- }
-
break;
case ENOENT:
if (state->check_next == false) {
@@ -1030,6 +1395,7 @@ cache_req_search_domains(struct tevent_req *req,
subreq = cache_req_search_domains_send(state, state->ev, state->cr,
cr_domain, check_next,
+ state->first_iteration,
bypass_cache, bypass_dp);
if (subreq == NULL) {
return ENOMEM;
diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h
index ebdc71dd635d5d8a5d06e30e96c5d4101b6d98bf..5769b6aee309d9ba3edd5bb73a3cef6dc3193fdc 100644
--- a/src/responder/common/cache_req/cache_req_domain.h
+++ b/src/responder/common/cache_req/cache_req_domain.h
@@ -26,6 +26,7 @@
struct cache_req_domain {
struct sss_domain_info *domain;
bool fqnames;
+ bool locate_domain;
struct cache_req_domain *prev;
struct cache_req_domain *next;
diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
index f075480a019e476407a3081a795c3c289455aca8..0ee0070d0c9fbb89020f522b2f7613f1076a8cbb 100644
--- a/src/tests/cmocka/test_responder_cache_req.c
+++ b/src/tests/cmocka/test_responder_cache_req.c
@@ -27,6 +27,7 @@
#include "tests/cmocka/common_mock_resp.h"
#include "db/sysdb.h"
#include "responder/common/cache_req/cache_req.h"
+#include "db/sysdb_private.h" /* new_subdomain() */
#define TESTS_PATH "tp_" BASE_FILE_STEM
#define TEST_CONF_DB "test_responder_cache_req_conf.ldb"
@@ -63,6 +64,11 @@ struct test_group {
test_multi_domain_setup, \
test_multi_domain_teardown)
+#define new_subdomain_test(test) \
+ cmocka_unit_test_setup_teardown(test_ ## test, \
+ test_subdomain_setup, \
+ test_subdomain_teardown)
+
#define run_cache_req(ctx, send_fn, done_fn, dom, crp, lookup, expret) do { \
TALLOC_CTX *req_mem_ctx; \
struct tevent_req *req; \
@@ -110,6 +116,7 @@ struct cache_req_test_ctx {
struct sss_test_ctx *tctx;
struct resp_ctx *rctx;
struct sss_nc_ctx *ncache;
+ struct sss_domain_info *subdomain;
struct cache_req_result *result;
bool dp_called;
@@ -120,6 +127,8 @@ struct cache_req_test_ctx {
bool create_user2;
bool create_group1;
bool create_group2;
+ bool create_subgroup1;
+ bool create_subuser1;
};
const char *domains[] = {"responder_cache_req_test_a",
@@ -128,6 +137,8 @@ const char *domains[] = {"responder_cache_req_test_a",
"responder_cache_req_test_d",
NULL};
+const char *subdomain_name = "responder_cache_req_test_a_sub";
+
struct cli_protocol_version *register_cli_protocol_version(void)
{
static struct cli_protocol_version version[] = {
@@ -487,6 +498,26 @@ __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx,
prepare_group(ctx->tctx->dom, &groups[1], 1000, time(NULL));
}
+ if (ctx->create_subgroup1) {
+ struct sss_domain_info *domain = NULL;
+
+ domain = find_domain_by_name(ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], 1000, time(NULL));
+ }
+
+ if (ctx->create_subuser1) {
+ struct sss_domain_info *domain = NULL;
+
+ domain = find_domain_by_name(ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], 1000, time(NULL));
+ }
+
return test_req_succeed_send(mem_ctx, rctx->ev);
}
@@ -581,6 +612,67 @@ static int test_multi_domain_teardown(void **state)
return 0;
}
+static int test_subdomain_setup(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ int ret;
+ const char *const testdom[4] = { subdomain_name, "TEST_A.SUB", "test_a", "S-3" };
+
+ assert_true(leak_check_setup());
+
+ test_dom_suite_setup(TESTS_PATH);
+
+ test_ctx = talloc_zero(global_talloc_context, struct cache_req_test_ctx);
+ assert_non_null(test_ctx);
+ *state = test_ctx;
+
+ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB,
+ TEST_DOM_NAME, TEST_ID_PROVIDER, NULL);
+ assert_non_null(test_ctx->tctx);
+
+ test_ctx->rctx = mock_rctx(test_ctx, test_ctx->tctx->ev,
+ test_ctx->tctx->dom, NULL);
+ assert_non_null(test_ctx->rctx);
+
+ ret = sss_ncache_init(test_ctx, 10, 0, &test_ctx->ncache);
+ assert_int_equal(ret, EOK);
+
+ test_ctx->subdomain = new_subdomain(test_ctx, test_ctx->tctx->dom,
+ testdom[0], testdom[1], testdom[2], testdom[3],
+ false, false, NULL, NULL, 0,
+ test_ctx->tctx->confdb);
+ assert_non_null(test_ctx->subdomain);
+
+ ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
+ testdom[0], testdom[1], testdom[2], testdom[3],
+ false, false, NULL, 0, NULL);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_update_subdomains(test_ctx->tctx->dom,
+ test_ctx->tctx->confdb);
+ assert_int_equal(ret, EOK);
+
+ *state = test_ctx;
+ check_leaks_push(test_ctx);
+ return 0;
+}
+
+static int test_subdomain_teardown(void **state)
+{
+ struct cache_req_test_ctx *test_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ talloc_zfree(test_ctx->result);
+ talloc_zfree(test_ctx->rctx->cr_domains);
+
+ assert_true(check_leaks_pop(test_ctx));
+ talloc_zfree(test_ctx);
+ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
+ assert_true(leak_check_teardown());
+ return 0;
+}
+
void test_user_by_name_multiple_domains_found(void **state)
{
struct cache_req_test_ctx *test_ctx = NULL;
@@ -974,6 +1066,7 @@ void test_user_by_id_multiple_domains_found(void **state)
/* Mock values. */
will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
will_return_always(sss_dp_req_recv, 0);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
/* Test. */
run_user_by_id(test_ctx, NULL, 0, ERR_OK);
@@ -990,12 +1083,317 @@ void test_user_by_id_multiple_domains_notfound(void **state)
/* Mock values. */
will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
will_return_always(sss_dp_req_recv, 0);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
/* Test. */
run_user_by_id(test_ctx, NULL, 0, ENOENT);
assert_true(test_ctx->dp_called);
}
+void test_user_by_id_multiple_domains_locator_cache_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], 1000, time(NULL));
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
+
+ will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, EOK);
+
+ /* Test. */
+ run_user_by_id(test_ctx, NULL, 0, ERR_OK);
+ /* Even though the locator tells us to skip all domains except d, the domains
+ * are standalone and the result of the locator request is only valid within
+ * the subdomains
+ */
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_user_by_id_multiple_domains_locator_cache_expired(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], -1000, time(NULL));
+
+ will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, EOK);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
+
+ /* Test. */
+ run_user_by_id(test_ctx, NULL, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_user_by_id_sub_domains_locator_cache_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], 1000, time(NULL));
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_user_by_id(test_ctx, NULL, 0, ERR_OK);
+
+ /* Even though the ID is present in the last domain,
+ * we're not calling sss_dp_get_account_send,
+ * because the locator will cause cache_req to skip
+ * all domains except _d
+ */
+ assert_false(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_user_by_id_sub_domains_locator_cache_expired(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], -1000, time(NULL));
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_user_by_id(test_ctx, NULL, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_user_by_id_sub_domains_locator_cache_midpoint(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], 50, time(NULL) - 26);
+
+ /* Note - DP will only be called once and we're not waiting
+ * for the results (so, we're not mocking _recv)
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_user_by_id(test_ctx, NULL, 50, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_user_by_id_sub_domains_locator_missing_found(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ test_ctx->create_subuser1 = true;
+ run_user_by_id(test_ctx, NULL, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_user_by_id_sub_domains_locator_missing_notfound(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND);
+
+ /* Test. */
+ run_user_by_id(test_ctx, NULL, 0, ENOENT);
+ assert_false(test_ctx->dp_called);
+}
+
+void test_user_by_id_sub_domains_locator_cache_expired_two_calls(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ test_ctx->create_subuser1 = true;
+ prepare_user(domain, &users[0], -1000, time(NULL));
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_user_by_id(test_ctx, NULL, 0, ERR_OK);
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ /* Request the same user again */
+ test_ctx->tctx->done = false;
+ talloc_zfree(test_ctx->result);
+
+ run_user_by_id(test_ctx, NULL, 0, ERR_OK);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
void test_user_by_id_cache_valid(void **state)
{
struct cache_req_test_ctx *test_ctx = NULL;
@@ -1332,6 +1730,7 @@ void test_group_by_id_multiple_domains_found(void **state)
/* Mock values. */
will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
will_return_always(sss_dp_req_recv, 0);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
/* Test. */
run_group_by_id(test_ctx, NULL, 0, ERR_OK);
@@ -1348,12 +1747,318 @@ void test_group_by_id_multiple_domains_notfound(void **state)
/* Mock values. */
will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
will_return_always(sss_dp_req_recv, 0);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
/* Test. */
run_group_by_id(test_ctx, NULL, 0, ENOENT);
assert_true(test_ctx->dp_called);
}
+void test_group_by_id_multiple_domains_locator_cache_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], 1000, time(NULL));
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
+
+ will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, EOK);
+
+ /* Test. */
+ run_group_by_id(test_ctx, NULL, 0, ERR_OK);
+
+ /* Even though the locator tells us to skip all domains except d, the domains
+ * are standalone and the result of the locator request is only valid within
+ * the subdomains
+ */
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_group_by_id_multiple_domains_locator_cache_expired(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], -1000, time(NULL));
+
+ will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, EOK);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
+
+ /* Test. */
+ run_group_by_id(test_ctx, NULL, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_group_by_id_sub_domains_locator_cache_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], 1000, time(NULL));
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_group_by_id(test_ctx, NULL, 0, ERR_OK);
+
+ /* Even though the ID is present in the last domain,
+ * we're not calling sss_dp_get_account_send,
+ * because the locator will cause cache_req to skip
+ * all domains except _d
+ */
+ assert_false(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_group_by_id_sub_domains_locator_cache_expired(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], -1000, time(NULL));
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_group_by_id(test_ctx, NULL, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_group_by_id_sub_domains_locator_cache_midpoint(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], 50, time(NULL) - 26);
+
+ /* Note - DP will only be called once and we're not waiting
+ * for the results (so, we're not mocking _recv)
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_group_by_id(test_ctx, NULL, 50, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_group_by_id_sub_domains_locator_missing_found(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ test_ctx->create_subgroup1 = true;
+ run_group_by_id(test_ctx, NULL, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_group_by_id_sub_domains_locator_missing_notfound(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND);
+
+ /* Test. */
+ run_group_by_id(test_ctx, NULL, 0, ENOENT);
+ assert_false(test_ctx->dp_called);
+}
+
+void test_group_by_id_sub_domains_locator_cache_expired_two_calls(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ test_ctx->create_subgroup1 = true;
+ prepare_group(domain, &groups[0], -1000, time(NULL));
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_group_by_id(test_ctx, NULL, 0, ERR_OK);
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ /* Request the same group again */
+ test_ctx->tctx->done = false;
+ talloc_zfree(test_ctx->result);
+
+ run_group_by_id(test_ctx, NULL, 0, ERR_OK);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
void test_group_by_id_cache_valid(void **state)
{
struct cache_req_test_ctx *test_ctx = NULL;
@@ -2311,6 +3016,7 @@ void test_object_by_id_user_multiple_domains_found(void **state)
/* Mock values. */
will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
will_return_always(sss_dp_req_recv, 0);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
/* Test. */
run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
@@ -2328,6 +3034,7 @@ void test_object_by_id_user_multiple_domains_notfound(void **state)
/* Mock values. */
will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
will_return_always(sss_dp_req_recv, 0);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
/* Test. */
run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT);
@@ -2476,6 +3183,7 @@ void test_object_by_id_group_multiple_domains_found(void **state)
/* Mock values. */
will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
will_return_always(sss_dp_req_recv, 0);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
/* Test. */
run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
@@ -2493,12 +3201,641 @@ void test_object_by_id_group_multiple_domains_notfound(void **state)
/* Mock values. */
will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
will_return_always(sss_dp_req_recv, 0);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
/* Test. */
run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT);
assert_true(test_ctx->dp_called);
}
+void test_object_by_id_user_multiple_domains_locator_cache_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], 1000, time(NULL));
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
+
+ will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, EOK);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
+ /* Even though the locator tells us to skip all domains except d, the domains
+ * are standalone and the result of the locator request is only valid within
+ * the subdomains
+ */
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_user_multiple_domains_locator_cache_expired(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], -1000, time(NULL));
+
+ will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, EOK);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_user_sub_domains_locator_cache_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], 1000, time(NULL));
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
+
+ /* Even though the ID is present in the last domain,
+ * we're not calling sss_dp_get_account_send,
+ * because the locator will cause cache_req to skip
+ * all domains except _d
+ */
+ assert_false(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_user_sub_domains_locator_cache_expired(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], -1000, time(NULL));
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_user_sub_domains_locator_cache_midpoint(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_user(domain, &users[0], 50, time(NULL) - 26);
+
+ /* Note - DP will only be called once and we're not waiting
+ * for the results (so, we're not mocking _recv)
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 50, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_user_sub_domains_locator_missing_found(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ test_ctx->create_subuser1 = true;
+ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_user_sub_domains_locator_missing_notfound(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND);
+
+ /* The test won't even ask the DP for the object, just iterate
+ * over the domains using the negative cache and quit
+ */
+ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT);
+ assert_false(test_ctx->dp_called);
+}
+
+void test_object_by_id_user_sub_domains_locator_cache_expired_two_calls(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup user. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ test_ctx->create_subuser1 = true;
+ prepare_user(domain, &users[0], -1000, time(NULL));
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, EOK);
+ assert_true(test_ctx->dp_called);
+ check_user(test_ctx, &users[0], domain);
+
+ /* Request the same user again */
+ test_ctx->tctx->done = false;
+ talloc_zfree(test_ctx->result);
+
+ run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, EOK);
+ check_user(test_ctx, &users[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_group_multiple_domains_locator_cache_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], 1000, time(NULL));
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
+
+ will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, EOK);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
+ /* Even though the locator tells us to skip all domains except d, the domains
+ * are standalone and the result of the locator request is only valid within
+ * the subdomains
+ */
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_group_multiple_domains_locator_cache_expired(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], -1000, time(NULL));
+
+ will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, EOK);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+ will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_group_sub_domains_locator_cache_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], 1000, time(NULL));
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
+
+ /* Even though the ID is present in the last domain,
+ * we're not calling sss_dp_get_account_send,
+ * because the locator will cause cache_req to skip
+ * all domains except _d
+ */
+ assert_false(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_group_sub_domains_locator_cache_expired(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], -1000, time(NULL));
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_group_sub_domains_locator_cache_midpoint(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ prepare_group(domain, &groups[0], 50, time(NULL) - 26);
+
+ /* Note - DP will only be called once and we're not waiting
+ * for the results (so, we're not mocking _recv)
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 50, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_group_sub_domains_locator_missing_found(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ test_ctx->create_subgroup1 = true;
+ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
+
+ assert_true(test_ctx->dp_called);
+
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
+void test_object_by_id_group_sub_domains_locator_missing_notfound(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND);
+
+ /* The test won't even ask the DP for the object, just iterate
+ * over the domains using the negative cache and quit
+ */
+ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT);
+ assert_false(test_ctx->dp_called);
+}
+
+void test_object_by_id_group_sub_domains_locator_cache_expired_two_calls(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ const char *locator_domain;
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
+ locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
+ assert_non_null(locator_domain);
+
+ /* Setup group. */
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ subdomain_name,
+ true);
+ assert_non_null(domain);
+ test_ctx->create_subgroup1 = true;
+ prepare_group(domain, &groups[0], -1000, time(NULL));
+
+ /* Note - DP will only be called once (so, we're not using will_return_always)
+ * because the locator will tell us which domain to look into. For the recv
+ * function, we use always b/c internally it mocks several values.
+ */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ will_return_always(sss_dp_req_recv, 0);
+
+ will_return(sss_dp_get_account_domain_recv, EOK);
+ will_return(sss_dp_get_account_domain_recv, locator_domain);
+
+ /* Test. */
+ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, EOK);
+ assert_true(test_ctx->dp_called);
+ check_group(test_ctx, &groups[0], domain);
+
+ /* Request the same group again */
+ test_ctx->tctx->done = false;
+ talloc_zfree(test_ctx->result);
+
+ run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, EOK);
+ check_group(test_ctx, &groups[0], domain);
+
+ talloc_free(tmp_ctx);
+}
+
int main(int argc, const char *argv[])
{
poptContext pc;
@@ -2557,6 +3894,24 @@ int main(int argc, const char *argv[])
new_multi_domain_test(group_by_id_multiple_domains_found),
new_multi_domain_test(group_by_id_multiple_domains_notfound),
+ new_multi_domain_test(group_by_id_multiple_domains_locator_cache_valid),
+ new_multi_domain_test(group_by_id_multiple_domains_locator_cache_expired),
+ new_subdomain_test(group_by_id_sub_domains_locator_cache_valid),
+ new_subdomain_test(group_by_id_sub_domains_locator_cache_expired),
+ new_subdomain_test(group_by_id_sub_domains_locator_cache_midpoint),
+ new_subdomain_test(group_by_id_sub_domains_locator_missing_found),
+ new_subdomain_test(group_by_id_sub_domains_locator_missing_notfound),
+ new_subdomain_test(group_by_id_sub_domains_locator_cache_expired_two_calls),
+
+ new_multi_domain_test(user_by_id_multiple_domains_locator_cache_valid),
+ new_multi_domain_test(user_by_id_multiple_domains_locator_cache_expired),
+ new_subdomain_test(user_by_id_sub_domains_locator_cache_valid),
+ new_subdomain_test(user_by_id_sub_domains_locator_cache_expired),
+ new_subdomain_test(user_by_id_sub_domains_locator_cache_midpoint),
+ new_subdomain_test(user_by_id_sub_domains_locator_missing_found),
+ new_subdomain_test(user_by_id_sub_domains_locator_missing_notfound),
+ new_subdomain_test(user_by_id_sub_domains_locator_cache_expired_two_calls),
+
new_single_domain_test(user_by_recent_filter_valid),
new_single_domain_test(users_by_recent_filter_valid),
new_single_domain_test(group_by_recent_filter_valid),
@@ -2603,6 +3958,24 @@ int main(int argc, const char *argv[])
new_single_domain_test(object_by_id_group_missing_notfound),
new_multi_domain_test(object_by_id_group_multiple_domains_found),
new_multi_domain_test(object_by_id_group_multiple_domains_notfound),
+
+ new_multi_domain_test(object_by_id_user_multiple_domains_locator_cache_valid),
+ new_multi_domain_test(object_by_id_user_multiple_domains_locator_cache_expired),
+ new_subdomain_test(object_by_id_user_sub_domains_locator_cache_valid),
+ new_subdomain_test(object_by_id_user_sub_domains_locator_cache_expired),
+ new_subdomain_test(object_by_id_user_sub_domains_locator_cache_midpoint),
+ new_subdomain_test(object_by_id_user_sub_domains_locator_missing_found),
+ new_subdomain_test(object_by_id_user_sub_domains_locator_missing_notfound),
+ new_subdomain_test(object_by_id_user_sub_domains_locator_cache_expired_two_calls),
+
+ new_multi_domain_test(object_by_id_group_multiple_domains_locator_cache_valid),
+ new_multi_domain_test(object_by_id_group_multiple_domains_locator_cache_expired),
+ new_subdomain_test(object_by_id_group_sub_domains_locator_cache_valid),
+ new_subdomain_test(object_by_id_group_sub_domains_locator_cache_expired),
+ new_subdomain_test(object_by_id_group_sub_domains_locator_cache_midpoint),
+ new_subdomain_test(object_by_id_group_sub_domains_locator_missing_found),
+ new_subdomain_test(object_by_id_group_sub_domains_locator_missing_notfound),
+ new_subdomain_test(object_by_id_group_sub_domains_locator_cache_expired_two_calls),
};
/* Set debug level to invalid value so we can deside if -d 0 was used. */
--
2.14.3