Line data Source code
1 : /*
2 : Authors:
3 : Jakub Hrozek <jhrozek@redhat.com>
4 :
5 : Copyright (C) 2014 Red Hat
6 :
7 : SSSD tests: Common responder code tests
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include <talloc.h>
24 : #include <tevent.h>
25 : #include <errno.h>
26 : #include <popt.h>
27 :
28 : #include "tests/cmocka/common_mock.h"
29 : #include "tests/cmocka/common_mock_resp.h"
30 :
31 : #define TESTS_PATH "tp_" BASE_FILE_STEM
32 : #define TEST_CONF_DB "test_responder_conf.ldb"
33 : #define TEST_DOM_NAME "responder_test"
34 : #define TEST_ID_PROVIDER "ldap"
35 :
36 : #define NAME "username"
37 :
38 : static void
39 : mock_sss_dp_done(struct tevent_context *ev,
40 : struct tevent_immediate *imm,
41 : void *pvt);
42 :
43 : errno_t
44 3 : sss_dp_issue_request(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx,
45 : const char *strkey, struct sss_domain_info *dom,
46 : dbus_msg_constructor msg_create, void *pvt,
47 : struct tevent_req *nreq)
48 : {
49 : struct tevent_immediate *imm;
50 :
51 3 : imm = tevent_create_immediate(rctx->ev);
52 3 : if (imm == NULL) {
53 0 : return ENOMEM;
54 : }
55 3 : tevent_schedule_immediate(imm, rctx->ev, mock_sss_dp_done, nreq);
56 3 : return EOK;
57 : }
58 :
59 : static void
60 3 : mock_sss_dp_done(struct tevent_context *ev,
61 : struct tevent_immediate *imm,
62 : void *pvt)
63 : {
64 : struct tevent_req *req;
65 :
66 3 : talloc_free(imm);
67 3 : req = talloc_get_type(pvt, struct tevent_req);
68 3 : tevent_req_done(req);
69 3 : }
70 :
71 : errno_t
72 3 : sss_dp_req_recv(TALLOC_CTX *mem_ctx,
73 : struct tevent_req *sidereq,
74 : dbus_uint16_t *dp_err,
75 : dbus_uint32_t *dp_ret,
76 : char **err_msg)
77 : {
78 3 : return EOK;
79 : }
80 :
81 : struct parse_inp_test_ctx {
82 : struct sss_test_ctx *tctx;
83 : struct resp_ctx *rctx;
84 : };
85 :
86 5 : static int parse_inp_test_setup(void **state)
87 : {
88 : struct parse_inp_test_ctx *parse_inp_ctx;
89 : int ret;
90 :
91 5 : assert_true(leak_check_setup());
92 5 : parse_inp_ctx = talloc_zero(global_talloc_context, struct parse_inp_test_ctx);
93 5 : assert_non_null(parse_inp_ctx);
94 :
95 5 : parse_inp_ctx->tctx = create_dom_test_ctx(parse_inp_ctx, TESTS_PATH,
96 : TEST_CONF_DB, TEST_DOM_NAME,
97 : TEST_ID_PROVIDER, NULL);
98 5 : assert_non_null(parse_inp_ctx->tctx);
99 :
100 10 : parse_inp_ctx->rctx = mock_rctx(parse_inp_ctx,
101 5 : parse_inp_ctx->tctx->ev,
102 5 : parse_inp_ctx->tctx->dom,
103 : parse_inp_ctx);
104 5 : assert_non_null(parse_inp_ctx->rctx);
105 :
106 : /* Testing the request race condition should be a special case */
107 5 : gettimeofday(&parse_inp_ctx->rctx->get_domains_last_call, NULL);
108 :
109 : /* sysdb_master_domain_update sets the view name, if we do not call it
110 : * here we get a leak check warning when sysdb_master_domain_update is
111 : * called later while processing the tests. */
112 5 : ret = sysdb_master_domain_update(parse_inp_ctx->tctx->dom);
113 5 : assert_int_equal(ret, EOK);
114 :
115 5 : check_leaks_push(parse_inp_ctx);
116 5 : *state = parse_inp_ctx;
117 5 : return 0;
118 : }
119 :
120 5 : static int parse_inp_test_teardown(void **state)
121 : {
122 5 : struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state,
123 : struct parse_inp_test_ctx);
124 :
125 5 : assert_true(check_leaks_pop(parse_inp_ctx) == true);
126 :
127 5 : talloc_free(parse_inp_ctx);
128 5 : assert_true(leak_check_teardown());
129 5 : return 0;
130 : }
131 :
132 : int __real_sss_parse_name_for_domains(TALLOC_CTX *memctx,
133 : struct sss_domain_info *domains,
134 : const char *default_domain,
135 : const char *orig, char **domain, char **name);
136 :
137 5 : int __wrap_sss_parse_name_for_domains(TALLOC_CTX *memctx,
138 : struct sss_domain_info *domains,
139 : const char *default_domain,
140 : const char *orig, char **domain, char **name)
141 : {
142 5 : enum sss_test_wrapper_call wtype = sss_mock_type(enum sss_test_wrapper_call);
143 : errno_t ret;
144 :
145 5 : if (wtype == WRAP_CALL_REAL) {
146 3 : return __real_sss_parse_name_for_domains(memctx, domains,
147 : default_domain, orig,
148 : domain, name);
149 : }
150 :
151 2 : ret = sss_mock_type(errno_t);
152 2 : return ret;
153 : }
154 :
155 3 : void parse_inp_simple_done(struct tevent_req *req)
156 : {
157 : errno_t ret;
158 3 : struct parse_inp_test_ctx *parse_inp_ctx =
159 3 : tevent_req_callback_data(req, struct parse_inp_test_ctx);
160 3 : char *name = NULL;
161 3 : char *domname = NULL;
162 :
163 3 : ret = sss_parse_inp_recv(req, parse_inp_ctx, &name, &domname);
164 3 : assert_int_equal(ret, EOK);
165 :
166 3 : test_ev_done(parse_inp_ctx->tctx, EOK);
167 3 : talloc_free(req);
168 :
169 3 : assert_string_equal(name, NAME);
170 3 : assert_null(domname);
171 3 : talloc_free(name);
172 3 : }
173 :
174 1 : void parse_inp_simple(void **state)
175 : {
176 1 : struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state,
177 : struct parse_inp_test_ctx);
178 : struct tevent_req *req;
179 : errno_t ret;
180 :
181 1 : will_return(__wrap_sss_parse_name_for_domains, WRAP_CALL_REAL);
182 :
183 1 : req = sss_parse_inp_send(parse_inp_ctx, parse_inp_ctx->rctx, NAME);
184 1 : assert_non_null(req);
185 1 : tevent_req_set_callback(req, parse_inp_simple_done, parse_inp_ctx);
186 :
187 1 : ret = test_ev_loop(parse_inp_ctx->tctx);
188 1 : assert_int_equal(ret, EOK);
189 1 : }
190 :
191 1 : void parse_inp_call_dp(void **state)
192 : {
193 1 : struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state,
194 : struct parse_inp_test_ctx);
195 : struct tevent_req *req;
196 : errno_t ret;
197 :
198 : /* First call will indicate we need to go to DP */
199 1 : will_return(__wrap_sss_parse_name_for_domains, WRAP_CALL_WRAPPER);
200 1 : will_return(__wrap_sss_parse_name_for_domains, EAGAIN);
201 : /* The second one will succeed as the domains are up-to-date */
202 1 : will_return(__wrap_sss_parse_name_for_domains, WRAP_CALL_REAL);
203 :
204 1 : req = sss_parse_inp_send(parse_inp_ctx, parse_inp_ctx->rctx, NAME);
205 1 : assert_non_null(req);
206 1 : tevent_req_set_callback(req, parse_inp_simple_done, parse_inp_ctx);
207 :
208 1 : ret = test_ev_loop(parse_inp_ctx->tctx);
209 1 : assert_int_equal(ret, EOK);
210 1 : }
211 :
212 1 : void parse_inp_call_attach(void **state)
213 : {
214 1 : struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state,
215 : struct parse_inp_test_ctx);
216 : struct tevent_req *req;
217 : errno_t ret;
218 :
219 : /* simulate responder startup */
220 1 : parse_inp_ctx->rctx->get_domains_last_call.tv_sec = 0;
221 :
222 : /* The first parse wouldn't be called, the second one will succeed
223 : * as the domains are up-to-date */
224 1 : will_return(__wrap_sss_parse_name_for_domains, WRAP_CALL_REAL);
225 :
226 1 : req = sss_parse_inp_send(parse_inp_ctx, parse_inp_ctx->rctx, NAME);
227 1 : assert_non_null(req);
228 1 : tevent_req_set_callback(req, parse_inp_simple_done, parse_inp_ctx);
229 :
230 1 : ret = test_ev_loop(parse_inp_ctx->tctx);
231 1 : assert_int_equal(ret, EOK);
232 1 : }
233 :
234 1 : void parse_inp_neg_done(struct tevent_req *req)
235 : {
236 : errno_t ret;
237 1 : struct parse_inp_test_ctx *parse_inp_ctx =
238 1 : tevent_req_callback_data(req, struct parse_inp_test_ctx);
239 1 : char *name = NULL;
240 1 : char *domname = NULL;
241 :
242 1 : ret = sss_parse_inp_recv(req, parse_inp_ctx, &name, &domname);
243 1 : assert_int_equal(ret, ERR_INPUT_PARSE);
244 1 : test_ev_done(parse_inp_ctx->tctx, EOK);
245 1 : talloc_free(req);
246 :
247 1 : assert_null(name);
248 1 : assert_null(domname);
249 1 : }
250 :
251 1 : void parse_inp_call_neg(void **state)
252 : {
253 1 : struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state,
254 : struct parse_inp_test_ctx);
255 : struct tevent_req *req;
256 : errno_t ret;
257 :
258 : /* Simulate an error */
259 1 : will_return(__wrap_sss_parse_name_for_domains, WRAP_CALL_WRAPPER);
260 1 : will_return(__wrap_sss_parse_name_for_domains, EINVAL);
261 :
262 1 : req = sss_parse_inp_send(parse_inp_ctx, parse_inp_ctx->rctx, NAME);
263 1 : assert_non_null(req);
264 1 : tevent_req_set_callback(req, parse_inp_neg_done, parse_inp_ctx);
265 :
266 1 : ret = test_ev_loop(parse_inp_ctx->tctx);
267 1 : assert_int_equal(ret, EOK);
268 1 : }
269 :
270 : struct sss_nc_ctx {
271 : struct parse_inp_test_ctx *pctx;
272 : };
273 :
274 1 : errno_t sss_ncache_reset_repopulate_permanent(struct resp_ctx *rctx,
275 : struct sss_nc_ctx *dummy_ncache_ptr)
276 : {
277 1 : test_ev_done(dummy_ncache_ptr->pctx->tctx, EOK);
278 1 : return EOK;
279 : }
280 :
281 1 : void test_schedule_get_domains_task(void **state)
282 : {
283 1 : struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state,
284 : struct parse_inp_test_ctx);
285 : errno_t ret;
286 : struct sss_nc_ctx *dummy_ncache_ptr;
287 :
288 1 : dummy_ncache_ptr = talloc(parse_inp_ctx, struct sss_nc_ctx);
289 1 : assert_non_null(dummy_ncache_ptr);
290 1 : dummy_ncache_ptr->pctx = parse_inp_ctx;
291 :
292 2 : ret = schedule_get_domains_task(dummy_ncache_ptr,
293 1 : parse_inp_ctx->rctx->ev,
294 : parse_inp_ctx->rctx,
295 : dummy_ncache_ptr);
296 1 : assert_int_equal(ret, EOK);
297 :
298 1 : ret = test_ev_loop(parse_inp_ctx->tctx);
299 1 : assert_int_equal(ret, EOK);
300 1 : talloc_free(dummy_ncache_ptr);
301 1 : }
302 :
303 1 : int main(int argc, const char *argv[])
304 : {
305 : int rv;
306 1 : int no_cleanup = 0;
307 : poptContext pc;
308 : int opt;
309 7 : struct poptOption long_options[] = {
310 : POPT_AUTOHELP
311 5 : SSSD_DEBUG_OPTS
312 : {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0,
313 1 : _("Do not delete the test database after a test run"), NULL },
314 : POPT_TABLEEND
315 : };
316 :
317 1 : const struct CMUnitTest tests[] = {
318 : cmocka_unit_test_setup_teardown(parse_inp_simple,
319 : parse_inp_test_setup,
320 : parse_inp_test_teardown),
321 : cmocka_unit_test_setup_teardown(parse_inp_call_dp,
322 : parse_inp_test_setup,
323 : parse_inp_test_teardown),
324 : cmocka_unit_test_setup_teardown(parse_inp_call_attach,
325 : parse_inp_test_setup,
326 : parse_inp_test_teardown),
327 : cmocka_unit_test_setup_teardown(parse_inp_call_neg,
328 : parse_inp_test_setup,
329 : parse_inp_test_teardown),
330 : cmocka_unit_test_setup_teardown(test_schedule_get_domains_task,
331 : parse_inp_test_setup,
332 : parse_inp_test_teardown),
333 : };
334 :
335 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
336 1 : debug_level = SSSDBG_INVALID;
337 :
338 1 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
339 1 : while((opt = poptGetNextOpt(pc)) != -1) {
340 : switch(opt) {
341 : default:
342 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
343 : poptBadOption(pc, 0), poptStrerror(opt));
344 0 : poptPrintUsage(pc, stderr, 0);
345 0 : return 1;
346 : }
347 : }
348 1 : poptFreeContext(pc);
349 :
350 1 : DEBUG_CLI_INIT(debug_level);
351 :
352 : /* Even though normally the tests should clean up after themselves
353 : * they might not after a failed run. Remove the old db to be sure */
354 1 : tests_set_cwd();
355 1 : test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
356 1 : test_dom_suite_setup(TESTS_PATH);
357 :
358 1 : rv = cmocka_run_group_tests(tests, NULL, NULL);
359 1 : if (rv == 0 && !no_cleanup) {
360 1 : test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
361 : }
362 1 : return rv;
363 : }
|