>From 8479a0a88e80c7025b411d6390276b6c97f3488f Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mon, 23 Jun 2014 19:07:59 +0200 Subject: [PATCH 6/6] TESTS: Add more tests for nested groups processing Adds unit test for basic group retrieval functionality as well as for testing duplicate members in the LDAP group entry. These unit tests exercise code added in patch a47cb2e08e4004179d2a6b5f9a9340200270fbd0 --- src/responder/ifp/ifp_iface_generated.c | 460 ++++++++++++++++---------------- src/tests/cmocka/test_nested_groups.c | 266 +++++++++++++++++- 2 files changed, 495 insertions(+), 231 deletions(-) diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c index 20ad563733c2774cdd8e73924e00c2f0b608c67e..62a21e911030c0c5fd1a700804cd01ebba186141 100644 --- a/src/responder/ifp/ifp_iface_generated.c +++ b/src/responder/ifp/ifp_iface_generated.c @@ -356,103 +356,6 @@ const struct sbus_method_meta infopipe_component__methods[] = { { NULL, } }; -/* invokes GetAll for the 'org.freedesktop.sssd.infopipe.Components' interface */ -static int invoke_infopipe_component_get_all(struct sbus_request *dbus_req, void *function_ptr) -{ - struct sbus_interface *intf = dbus_req->intf; - const struct sbus_property_meta *property; - DBusMessage *reply; - dbus_bool_t dbret; - DBusMessageIter iter; - DBusMessageIter iter_dict; - int ret; - const char * s_prop_val; - const char * s_out_val; - void (*s_handler)(struct sbus_request *, void *data, const char * *); - bool b_prop_val; - dbus_bool_t b_out_val; - void (*b_handler)(struct sbus_request *, void *data, bool *); - uint32_t u_prop_val; - uint32_t u_out_val; - void (*u_handler)(struct sbus_request *, void *data, uint32_t *); - const char * *as_prop_val; - int as_prop_len; - const char * *as_out_val; - void (*as_handler)(struct sbus_request *, void *data, const char * * *, int *); - - reply = dbus_message_new_method_return(dbus_req->message); - if (!reply) return ENOMEM; - dbus_message_iter_init_append(reply, &iter); - dbret = dbus_message_iter_open_container( - &iter, DBUS_TYPE_ARRAY, - DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING - DBUS_TYPE_STRING_AS_STRING - DBUS_TYPE_VARIANT_AS_STRING - DBUS_DICT_ENTRY_END_CHAR_AS_STRING, - &iter_dict); - if (!dbret) return ENOMEM; - - property = sbus_meta_find_property(intf->vtable->meta, "name"); - if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { - s_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); - if (s_handler) { - (s_handler)(dbus_req, dbus_req->intf->instance_data, &s_prop_val); - s_out_val = s_prop_val == NULL ? "" : s_prop_val; - ret = sbus_add_variant_to_dict(&iter_dict, "name", DBUS_TYPE_STRING, &s_out_val); - if (ret != EOK) return ret; - } - } - - property = sbus_meta_find_property(intf->vtable->meta, "debug_level"); - if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { - u_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); - if (u_handler) { - (u_handler)(dbus_req, dbus_req->intf->instance_data, &u_prop_val); - u_out_val = u_prop_val; - ret = sbus_add_variant_to_dict(&iter_dict, "debug_level", DBUS_TYPE_UINT32, &u_out_val); - if (ret != EOK) return ret; - } - } - - property = sbus_meta_find_property(intf->vtable->meta, "enabled"); - if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { - b_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); - if (b_handler) { - (b_handler)(dbus_req, dbus_req->intf->instance_data, &b_prop_val); - b_out_val = b_prop_val; - ret = sbus_add_variant_to_dict(&iter_dict, "enabled", DBUS_TYPE_BOOLEAN, &b_out_val); - if (ret != EOK) return ret; - } - } - - property = sbus_meta_find_property(intf->vtable->meta, "type"); - if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { - s_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); - if (s_handler) { - (s_handler)(dbus_req, dbus_req->intf->instance_data, &s_prop_val); - s_out_val = s_prop_val == NULL ? "" : s_prop_val; - ret = sbus_add_variant_to_dict(&iter_dict, "type", DBUS_TYPE_STRING, &s_out_val); - if (ret != EOK) return ret; - } - } - - property = sbus_meta_find_property(intf->vtable->meta, "providers"); - if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { - as_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); - if (as_handler) { - (as_handler)(dbus_req, dbus_req->intf->instance_data, &as_prop_val, &as_prop_len); - as_out_val = as_prop_val; - ret = sbus_add_array_as_variant_to_dict(&iter_dict, "providers", DBUS_TYPE_STRING, (uint8_t*)as_out_val, as_prop_len, sizeof(const char *)); - if (ret != EOK) return ret; - } - } - - dbret = dbus_message_iter_close_container(&iter, &iter_dict); - if (!dbret) return ENOMEM; - - return sbus_request_finish(dbus_req, reply); -} - /* property info for org.freedesktop.sssd.infopipe.Components */ const struct sbus_property_meta infopipe_component__properties[] = { { @@ -503,6 +406,103 @@ const struct sbus_property_meta infopipe_component__properties[] = { { NULL, } }; +/* invokes GetAll for the 'org.freedesktop.sssd.infopipe.Components' interface */ +static int invoke_infopipe_component_get_all(struct sbus_request *dbus_req, void *function_ptr) +{ + DBusMessage *reply; + dbus_bool_t dbret; + DBusMessageIter iter; + DBusMessageIter iter_dict; + int ret; + struct sbus_interface *intf = dbus_req->intf; + const struct sbus_property_meta *property; + const char * s_prop_val; + const char * s_out_val; + void (*s_handler)(struct sbus_request *, void *data, const char * *); + bool b_prop_val; + dbus_bool_t b_out_val; + void (*b_handler)(struct sbus_request *, void *data, bool *); + uint32_t u_prop_val; + uint32_t u_out_val; + void (*u_handler)(struct sbus_request *, void *data, uint32_t *); + const char * *as_prop_val; + int as_prop_len; + const char * *as_out_val; + void (*as_handler)(struct sbus_request *, void *data, const char * * *, int *); + + reply = dbus_message_new_method_return(dbus_req->message); + if (!reply) return ENOMEM; + dbus_message_iter_init_append(reply, &iter); + dbret = dbus_message_iter_open_container( + &iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &iter_dict); + if (!dbret) return ENOMEM; + + property = sbus_meta_find_property(intf->vtable->meta, "name"); + if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { + s_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); + if (s_handler) { + (s_handler)(dbus_req, dbus_req->intf->instance_data, &s_prop_val); + s_out_val = s_prop_val == NULL ? "" : s_prop_val; + ret = sbus_add_variant_to_dict(&iter_dict, "name", DBUS_TYPE_STRING, &s_out_val); + if (ret != EOK) return ret; + } + } + + property = sbus_meta_find_property(intf->vtable->meta, "debug_level"); + if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { + u_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); + if (u_handler) { + (u_handler)(dbus_req, dbus_req->intf->instance_data, &u_prop_val); + u_out_val = u_prop_val; + ret = sbus_add_variant_to_dict(&iter_dict, "debug_level", DBUS_TYPE_UINT32, &u_out_val); + if (ret != EOK) return ret; + } + } + + property = sbus_meta_find_property(intf->vtable->meta, "enabled"); + if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { + b_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); + if (b_handler) { + (b_handler)(dbus_req, dbus_req->intf->instance_data, &b_prop_val); + b_out_val = b_prop_val; + ret = sbus_add_variant_to_dict(&iter_dict, "enabled", DBUS_TYPE_BOOLEAN, &b_out_val); + if (ret != EOK) return ret; + } + } + + property = sbus_meta_find_property(intf->vtable->meta, "type"); + if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { + s_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); + if (s_handler) { + (s_handler)(dbus_req, dbus_req->intf->instance_data, &s_prop_val); + s_out_val = s_prop_val == NULL ? "" : s_prop_val; + ret = sbus_add_variant_to_dict(&iter_dict, "type", DBUS_TYPE_STRING, &s_out_val); + if (ret != EOK) return ret; + } + } + + property = sbus_meta_find_property(intf->vtable->meta, "providers"); + if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) { + as_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get); + if (as_handler) { + (as_handler)(dbus_req, dbus_req->intf->instance_data, &as_prop_val, &as_prop_len); + as_out_val = as_prop_val; + ret = sbus_add_array_as_variant_to_dict(&iter_dict, "providers", DBUS_TYPE_STRING, (uint8_t*)as_out_val, as_prop_len, sizeof(const char *)); + if (ret != EOK) return ret; + } + } + + dbret = dbus_message_iter_close_container(&iter, &iter_dict); + if (!dbret) return ENOMEM; + + return sbus_request_finish(dbus_req, reply); +} + /* interface info for org.freedesktop.sssd.infopipe.Components */ const struct sbus_interface_meta infopipe_component_meta = { "org.freedesktop.sssd.infopipe.Components", /* name */ @@ -512,16 +512,147 @@ const struct sbus_interface_meta infopipe_component_meta = { invoke_infopipe_component_get_all, /* GetAll invoker */ }; +/* property info for org.freedesktop.sssd.infopipe.Domains */ +const struct sbus_property_meta infopipe_domain__properties[] = { + { + "name", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_name), + invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "provider", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_provider), + invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "primary_servers", /* name */ + "as", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_primary_servers), + invoke_get_as, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "backup_servers", /* name */ + "as", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_backup_servers), + invoke_get_as, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "min_id", /* name */ + "u", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_min_id), + invoke_get_u, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "max_id", /* name */ + "u", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_max_id), + invoke_get_u, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "realm", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_realm), + invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "forest", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_forest), + invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "login_format", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_login_format), + invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "fully_qualified_name_format", /* name */ + "s", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_fully_qualified_name_format), + invoke_get_s, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "enumerable", /* name */ + "b", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_enumerable), + invoke_get_b, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "use_fully_qualified_names", /* name */ + "b", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_use_fully_qualified_names), + invoke_get_b, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "subdomain", /* name */ + "b", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_subdomain), + invoke_get_b, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { + "parent_domain", /* name */ + "o", /* type */ + SBUS_PROPERTY_READABLE, + offsetof(struct infopipe_domain, infopipe_domain_get_parent_domain), + invoke_get_o, + 0, /* not writable */ + NULL, /* no invoker */ + }, + { NULL, } +}; + /* invokes GetAll for the 'org.freedesktop.sssd.infopipe.Domains' interface */ static int invoke_infopipe_domain_get_all(struct sbus_request *dbus_req, void *function_ptr) { - struct sbus_interface *intf = dbus_req->intf; - const struct sbus_property_meta *property; DBusMessage *reply; dbus_bool_t dbret; DBusMessageIter iter; DBusMessageIter iter_dict; int ret; + struct sbus_interface *intf = dbus_req->intf; + const struct sbus_property_meta *property; const char * s_prop_val; const char * s_out_val; void (*s_handler)(struct sbus_request *, void *data, const char * *); @@ -711,137 +842,6 @@ static int invoke_infopipe_domain_get_all(struct sbus_request *dbus_req, void *f return sbus_request_finish(dbus_req, reply); } -/* property info for org.freedesktop.sssd.infopipe.Domains */ -const struct sbus_property_meta infopipe_domain__properties[] = { - { - "name", /* name */ - "s", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_name), - invoke_get_s, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "provider", /* name */ - "s", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_provider), - invoke_get_s, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "primary_servers", /* name */ - "as", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_primary_servers), - invoke_get_as, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "backup_servers", /* name */ - "as", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_backup_servers), - invoke_get_as, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "min_id", /* name */ - "u", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_min_id), - invoke_get_u, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "max_id", /* name */ - "u", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_max_id), - invoke_get_u, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "realm", /* name */ - "s", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_realm), - invoke_get_s, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "forest", /* name */ - "s", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_forest), - invoke_get_s, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "login_format", /* name */ - "s", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_login_format), - invoke_get_s, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "fully_qualified_name_format", /* name */ - "s", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_fully_qualified_name_format), - invoke_get_s, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "enumerable", /* name */ - "b", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_enumerable), - invoke_get_b, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "use_fully_qualified_names", /* name */ - "b", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_use_fully_qualified_names), - invoke_get_b, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "subdomain", /* name */ - "b", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_subdomain), - invoke_get_b, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { - "parent_domain", /* name */ - "o", /* type */ - SBUS_PROPERTY_READABLE, - offsetof(struct infopipe_domain, infopipe_domain_get_parent_domain), - invoke_get_o, - 0, /* not writable */ - NULL, /* no invoker */ - }, - { NULL, } -}; - /* interface info for org.freedesktop.sssd.infopipe.Domains */ const struct sbus_interface_meta infopipe_domain_meta = { "org.freedesktop.sssd.infopipe.Domains", /* name */ diff --git a/src/tests/cmocka/test_nested_groups.c b/src/tests/cmocka/test_nested_groups.c index bf678c2b2025e54e6ed50b8b33fe41a78ffec007..463d66efbbde28934d54cc71365b32b0c7fbbee1 100644 --- a/src/tests/cmocka/test_nested_groups.c +++ b/src/tests/cmocka/test_nested_groups.c @@ -44,6 +44,7 @@ * same tests cases for several search base scenarios */ #define OBJECT_BASE_DN "cn=objects,dc=test,dc=com" #define GROUP_BASE_DN "cn=groups," OBJECT_BASE_DN +#define USER_BASE_DN "cn=users," OBJECT_BASE_DN struct nested_groups_test_ctx { struct sss_test_ctx *tctx; @@ -114,11 +115,270 @@ static void nested_groups_test_one_group_no_members(void **state) assert_true(rootgroup == test_ctx->groups[0]); } +static void nested_groups_test_one_group_unique_members(void **state) +{ + struct nested_groups_test_ctx *test_ctx = NULL; + struct sysdb_attrs *rootgroup = NULL; + struct tevent_req *req = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + errno_t ret; + const char *name; + const char *users[] = { "cn=user1,"USER_BASE_DN, + "cn=user2,"USER_BASE_DN, + NULL }; + const struct sysdb_attrs *user1_reply[2] = { NULL }; + const struct sysdb_attrs *user2_reply[2] = { NULL }; + + test_ctx = talloc_get_type_abort(*state, struct nested_groups_test_ctx); + + /* mock return values */ + rootgroup = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, 1000, + "rootgroup", users); + + user1_reply[0] = mock_sysdb_user(test_ctx, USER_BASE_DN, 2001, "user1"); + assert_non_null(user1_reply[0]); + will_return(sdap_get_generic_recv, 1); + will_return(sdap_get_generic_recv, user1_reply); + + user2_reply[0] = mock_sysdb_user(test_ctx, USER_BASE_DN, 2002, "user2"); + assert_non_null(user2_reply[0]); + will_return(sdap_get_generic_recv, 1); + will_return(sdap_get_generic_recv, user2_reply); + + sss_will_return_always(sdap_has_deref_support, false); + + /* run test, check for memory leaks */ + req_mem_ctx = talloc_new(global_talloc_context); + assert_non_null(req_mem_ctx); + check_leaks_push(req_mem_ctx); + + req = sdap_nested_group_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->sdap_domain, test_ctx->sdap_opts, + test_ctx->sdap_handle, rootgroup); + assert_non_null(req); + tevent_req_set_callback(req, nested_groups_test_done, test_ctx); + + ret = test_ev_loop(test_ctx->tctx); + assert_true(check_leaks_pop(req_mem_ctx) == true); + talloc_zfree(req_mem_ctx); + + /* check return code */ + assert_int_equal(ret, ERR_OK); + + /* Check the users */ + assert_int_equal(test_ctx->num_users, 2); + assert_int_equal(test_ctx->num_groups, 1); + + ret = sysdb_attrs_get_string(test_ctx->users[0], SYSDB_NAME, &name); + assert_int_equal(ret, ERR_OK); + assert_string_equal(name, "user1"); + + ret = sysdb_attrs_get_string(test_ctx->users[1], SYSDB_NAME, &name); + assert_int_equal(ret, ERR_OK); + assert_string_equal(name, "user2"); +} + +static void nested_groups_test_one_group_dup_users(void **state) +{ + struct nested_groups_test_ctx *test_ctx = NULL; + struct sysdb_attrs *rootgroup = NULL; + struct tevent_req *req = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + errno_t ret; + const char *name; + const char *users[] = { "cn=user1,"USER_BASE_DN, + "cn=user1,"USER_BASE_DN, + NULL }; + const struct sysdb_attrs *user1_reply[2] = { NULL }; + const struct sysdb_attrs *user2_reply[2] = { NULL }; + + test_ctx = talloc_get_type_abort(*state, struct nested_groups_test_ctx); + + /* mock return values */ + rootgroup = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, 1000, + "rootgroup", users); + + user1_reply[0] = mock_sysdb_user(test_ctx, USER_BASE_DN, 2001, "user1"); + assert_non_null(user1_reply[0]); + will_return(sdap_get_generic_recv, 1); + will_return(sdap_get_generic_recv, user1_reply); + + user2_reply[0] = mock_sysdb_user(test_ctx, USER_BASE_DN, 2001, "user1"); + assert_non_null(user2_reply[0]); + will_return(sdap_get_generic_recv, 1); + will_return(sdap_get_generic_recv, user2_reply); + + sss_will_return_always(sdap_has_deref_support, false); + + /* run test, check for memory leaks */ + req_mem_ctx = talloc_new(global_talloc_context); + assert_non_null(req_mem_ctx); + check_leaks_push(req_mem_ctx); + + req = sdap_nested_group_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->sdap_domain, test_ctx->sdap_opts, + test_ctx->sdap_handle, rootgroup); + assert_non_null(req); + tevent_req_set_callback(req, nested_groups_test_done, test_ctx); + + ret = test_ev_loop(test_ctx->tctx); + assert_true(check_leaks_pop(req_mem_ctx) == true); + talloc_zfree(req_mem_ctx); + + /* check return code */ + assert_int_equal(ret, ERR_OK); + + /* Check the users */ + assert_int_equal(test_ctx->num_users, 1); + assert_int_equal(test_ctx->num_groups, 1); + + ret = sysdb_attrs_get_string(test_ctx->users[0], SYSDB_NAME, &name); + assert_int_equal(ret, ERR_OK); + assert_string_equal(name, "user1"); +} + +static void nested_groups_test_one_group_unique_group_members(void **state) +{ + struct nested_groups_test_ctx *test_ctx = NULL; + struct sysdb_attrs *rootgroup = NULL; + struct tevent_req *req = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + errno_t ret; + const char *name; + const char *groups[] = { "cn=emptygroup1,"GROUP_BASE_DN, + "cn=emptygroup2,"GROUP_BASE_DN, + NULL }; + const struct sysdb_attrs *group1_reply[2] = { NULL }; + const struct sysdb_attrs *group2_reply[2] = { NULL }; + + test_ctx = talloc_get_type_abort(*state, struct nested_groups_test_ctx); + + /* mock return values */ + rootgroup = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, 1000, + "rootgroup", groups); + + group1_reply[0] = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, + 1001, "emptygroup1", NULL); + assert_non_null(group1_reply[0]); + will_return(sdap_get_generic_recv, 1); + will_return(sdap_get_generic_recv, group1_reply); + + group2_reply[0] = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, + 1002, "emptygroup2", NULL); + assert_non_null(group2_reply[0]); + will_return(sdap_get_generic_recv, 1); + will_return(sdap_get_generic_recv, group2_reply); + + sss_will_return_always(sdap_has_deref_support, false); + + /* run test, check for memory leaks */ + req_mem_ctx = talloc_new(global_talloc_context); + assert_non_null(req_mem_ctx); + check_leaks_push(req_mem_ctx); + + req = sdap_nested_group_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->sdap_domain, test_ctx->sdap_opts, + test_ctx->sdap_handle, rootgroup); + assert_non_null(req); + tevent_req_set_callback(req, nested_groups_test_done, test_ctx); + + ret = test_ev_loop(test_ctx->tctx); + assert_true(check_leaks_pop(req_mem_ctx) == true); + talloc_zfree(req_mem_ctx); + + /* check return code */ + assert_int_equal(ret, ERR_OK); + + /* Check the users */ + assert_int_equal(test_ctx->num_users, 0); + assert_int_equal(test_ctx->num_groups, 3); + + ret = sysdb_attrs_get_string(test_ctx->groups[0], SYSDB_NAME, &name); + assert_int_equal(ret, ERR_OK); + assert_string_equal(name, "rootgroup"); + + ret = sysdb_attrs_get_string(test_ctx->groups[1], SYSDB_NAME, &name); + assert_int_equal(ret, ERR_OK); + assert_string_equal(name, "emptygroup2"); + + ret = sysdb_attrs_get_string(test_ctx->groups[2], SYSDB_NAME, &name); + assert_int_equal(ret, ERR_OK); + assert_string_equal(name, "emptygroup1"); +} + +static void nested_groups_test_one_group_dup_group_members(void **state) +{ + struct nested_groups_test_ctx *test_ctx = NULL; + struct sysdb_attrs *rootgroup = NULL; + struct tevent_req *req = NULL; + TALLOC_CTX *req_mem_ctx = NULL; + errno_t ret; + const char *name; + const char *groups[] = { "cn=emptygroup1,"GROUP_BASE_DN, + "cn=emptygroup1,"GROUP_BASE_DN, + NULL }; + const struct sysdb_attrs *group1_reply[2] = { NULL }; + const struct sysdb_attrs *group2_reply[2] = { NULL }; + + test_ctx = talloc_get_type_abort(*state, struct nested_groups_test_ctx); + + /* mock return values */ + rootgroup = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, 1000, + "rootgroup", groups); + + group1_reply[0] = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, + 1001, "emptygroup1", NULL); + assert_non_null(group1_reply[0]); + will_return(sdap_get_generic_recv, 1); + will_return(sdap_get_generic_recv, group1_reply); + + group2_reply[0] = mock_sysdb_group_rfc2307bis(test_ctx, GROUP_BASE_DN, + 1001, "emptygroup1", NULL); + assert_non_null(group2_reply[0]); + will_return(sdap_get_generic_recv, 1); + will_return(sdap_get_generic_recv, group2_reply); + + sss_will_return_always(sdap_has_deref_support, false); + + /* run test, check for memory leaks */ + req_mem_ctx = talloc_new(global_talloc_context); + assert_non_null(req_mem_ctx); + check_leaks_push(req_mem_ctx); + + req = sdap_nested_group_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->sdap_domain, test_ctx->sdap_opts, + test_ctx->sdap_handle, rootgroup); + assert_non_null(req); + tevent_req_set_callback(req, nested_groups_test_done, test_ctx); + + ret = test_ev_loop(test_ctx->tctx); + assert_true(check_leaks_pop(req_mem_ctx) == true); + talloc_zfree(req_mem_ctx); + + /* check return code */ + assert_int_equal(ret, ERR_OK); + + /* Check the users */ + assert_int_equal(test_ctx->num_users, 0); + assert_int_equal(test_ctx->num_groups, 2); + + ret = sysdb_attrs_get_string(test_ctx->groups[0], SYSDB_NAME, &name); + assert_int_equal(ret, ERR_OK); + assert_string_equal(name, "rootgroup"); + + ret = sysdb_attrs_get_string(test_ctx->groups[1], SYSDB_NAME, &name); + assert_int_equal(ret, ERR_OK); + assert_string_equal(name, "emptygroup1"); +} + void nested_groups_test_setup(void **state) { struct nested_groups_test_ctx *test_ctx = NULL; static struct sss_test_conf_param params[] = { { "ldap_schema", "rfc2307bis" }, /* enable nested groups */ + { "ldap_search_base", OBJECT_BASE_DN }, + { "ldap_user_search_base", USER_BASE_DN }, + { "ldap_group_search_base", GROUP_BASE_DN }, { NULL, NULL } }; @@ -163,7 +423,11 @@ int main(int argc, const char *argv[]) }; const UnitTest tests[] = { - new_test(one_group_no_members) + new_test(one_group_no_members), + new_test(one_group_unique_members), + new_test(one_group_dup_users), + new_test(one_group_unique_group_members), + new_test(one_group_dup_group_members), }; /* Set debug level to invalid value so we can deside if -d 0 was used. */ -- 1.9.3