Line data Source code
1 : /*
2 : Copyright (C) 2015 Red Hat
3 :
4 : This program is free software; you can redistribute it and/or modify
5 : it under the terms of the GNU General Public License as published by
6 : the Free Software Foundation; either version 3 of the License, or
7 : (at your option) any later version.
8 :
9 : This program is distributed in the hope that it will be useful,
10 : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : GNU General Public License for more details.
13 :
14 : You should have received a copy of the GNU General Public License
15 : along with this program. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include <talloc.h>
19 : #include <tevent.h>
20 : #include <errno.h>
21 : #include <popt.h>
22 : #include <time.h>
23 :
24 : #include "providers/dp_backend.h"
25 : #include "tests/cmocka/common_mock.h"
26 : #include "tests/cmocka/common_mock_be.h"
27 : #include "tests/common.h"
28 :
29 : #define TESTS_PATH "tests_dp_be"
30 : #define TEST_CONF_DB "test_dp_be_conf.ldb"
31 : #define TEST_DOM_NAME "dp_be_test"
32 : #define TEST_ID_PROVIDER "ldap"
33 :
34 : #define OFFLINE_TIMEOUT 2
35 : #define AS_STR(param) (#param)
36 :
37 : static TALLOC_CTX *global_mock_context = NULL;
38 : static bool global_timer_added;
39 :
40 : struct tevent_timer *__real__tevent_add_timer(struct tevent_context *ev,
41 : TALLOC_CTX *mem_ctx,
42 : struct timeval next_event,
43 : tevent_timer_handler_t handler,
44 : void *private_data,
45 : const char *handler_name,
46 : const char *location);
47 :
48 2 : struct tevent_timer *__wrap__tevent_add_timer(struct tevent_context *ev,
49 : TALLOC_CTX *mem_ctx,
50 : struct timeval next_event,
51 : tevent_timer_handler_t handler,
52 : void *private_data,
53 : const char *handler_name,
54 : const char *location)
55 : {
56 2 : global_timer_added = true;
57 :
58 2 : return __real__tevent_add_timer(ev, mem_ctx, next_event,
59 : handler, private_data, handler_name,
60 : location);
61 : }
62 :
63 :
64 : struct test_ctx {
65 : struct sss_test_ctx *tctx;
66 : struct be_ctx *be_ctx;
67 : };
68 :
69 3 : static int test_setup(void **state)
70 : {
71 3 : struct test_ctx *test_ctx = NULL;
72 3 : struct sss_test_conf_param params[] = {
73 : { "offline_timeout", AS_STR(OFFLINE_TIMEOUT) },
74 : { NULL, NULL }, /* Sentinel */
75 : };
76 :
77 3 : assert_true(leak_check_setup());
78 3 : global_mock_context = talloc_new(global_talloc_context);
79 3 : assert_non_null(global_mock_context);
80 :
81 3 : test_ctx = talloc_zero(global_talloc_context, struct test_ctx);
82 3 : assert_non_null(test_ctx);
83 :
84 3 : test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH,
85 : TEST_CONF_DB, TEST_DOM_NAME,
86 : TEST_ID_PROVIDER, params);
87 3 : assert_non_null(test_ctx->tctx);
88 :
89 3 : test_ctx->be_ctx = mock_be_ctx(test_ctx, test_ctx->tctx);
90 3 : assert_non_null(test_ctx->be_ctx);
91 :
92 6 : test_ctx->be_ctx->domain->subdomains = named_domain(test_ctx,
93 : "subdomains",
94 3 : test_ctx->be_ctx->domain);
95 3 : assert_non_null(test_ctx->be_ctx->domain->subdomains);
96 :
97 3 : *state = test_ctx;
98 :
99 3 : return 0;
100 : }
101 :
102 3 : static int test_teardown(void **state)
103 : {
104 3 : talloc_zfree(*state);
105 3 : assert_true(leak_check_teardown());
106 3 : return 0;
107 : }
108 :
109 8 : static void assert_domain_state(struct sss_domain_info *dom,
110 : enum sss_domain_state expected_state)
111 : {
112 : enum sss_domain_state dom_state;
113 :
114 8 : dom_state = sss_domain_get_state(dom);
115 8 : assert_int_equal(dom_state, expected_state);
116 8 : }
117 :
118 1 : static void test_mark_subdom_offline_check(struct tevent_context *ev,
119 : struct tevent_timer *te,
120 : struct timeval current_time,
121 : void *pvt)
122 : {
123 1 : struct test_ctx *test_ctx = talloc_get_type(pvt, struct test_ctx);
124 :
125 1 : assert_domain_state(test_ctx->be_ctx->domain->subdomains,
126 : DOM_ACTIVE);
127 :
128 1 : test_ctx->tctx->done = true;
129 1 : test_ctx->tctx->error = EOK;
130 1 : }
131 :
132 1 : static void test_mark_dom_offline(void **state)
133 : {
134 1 : struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
135 :
136 1 : assert_domain_state(test_ctx->be_ctx->domain, DOM_ACTIVE);
137 1 : assert_false(be_is_offline(test_ctx->be_ctx));
138 :
139 1 : be_mark_dom_offline(test_ctx->be_ctx->domain, test_ctx->be_ctx);
140 :
141 1 : assert_true(be_is_offline(test_ctx->be_ctx));
142 1 : assert_domain_state(test_ctx->be_ctx->domain, DOM_ACTIVE);
143 1 : }
144 :
145 1 : static void test_mark_subdom_offline(void **state)
146 : {
147 : struct timeval tv;
148 1 : struct tevent_timer *check_ev = NULL;
149 1 : struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
150 : errno_t ret;
151 :
152 1 : assert_domain_state(test_ctx->be_ctx->domain->subdomains,
153 : DOM_ACTIVE);
154 1 : assert_false(be_is_offline(test_ctx->be_ctx));
155 :
156 1 : global_timer_added = false;
157 1 : be_mark_dom_offline(test_ctx->be_ctx->domain->subdomains, test_ctx->be_ctx);
158 1 : assert_domain_state(test_ctx->be_ctx->domain->subdomains,
159 : DOM_INACTIVE);
160 :
161 : /* A timer must be added that resets the state back */
162 1 : assert_true(global_timer_added);
163 :
164 : /* Global offline state must not change */
165 1 : assert_false(be_is_offline(test_ctx->be_ctx));
166 :
167 : /* Make sure we don't add a second timer */
168 1 : global_timer_added = false;
169 1 : be_mark_dom_offline(test_ctx->be_ctx->domain->subdomains, test_ctx->be_ctx);
170 1 : assert_domain_state(test_ctx->be_ctx->domain->subdomains,
171 : DOM_INACTIVE);
172 1 : assert_false(global_timer_added);
173 :
174 : /* Wait for the internal timer to reset our subdomain back */
175 1 : tv = tevent_timeval_current_ofs(OFFLINE_TIMEOUT + 1, 0);
176 :
177 1 : check_ev = tevent_add_timer(test_ctx->tctx->ev, test_ctx, tv,
178 : test_mark_subdom_offline_check,
179 : test_ctx);
180 1 : if (check_ev == NULL) {
181 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot create timer\n");
182 0 : return;
183 : }
184 :
185 1 : ret = test_ev_loop(test_ctx->tctx);
186 1 : assert_int_equal(ret, EOK);
187 : }
188 :
189 1 : static void test_mark_subdom_offline_disabled(void **state)
190 : {
191 1 : struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx);
192 :
193 1 : sss_domain_set_state(test_ctx->be_ctx->domain->subdomains, DOM_DISABLED);
194 1 : assert_domain_state(test_ctx->be_ctx->domain->subdomains,
195 : DOM_DISABLED);
196 :
197 1 : be_mark_dom_offline(test_ctx->be_ctx->domain->subdomains, test_ctx->be_ctx);
198 1 : assert_domain_state(test_ctx->be_ctx->domain->subdomains,
199 : DOM_DISABLED);
200 1 : }
201 :
202 1 : int main(int argc, const char *argv[])
203 : {
204 : poptContext pc;
205 : int opt;
206 : int rv;
207 1 : int no_cleanup = 0;
208 7 : struct poptOption long_options[] = {
209 : POPT_AUTOHELP
210 5 : SSSD_DEBUG_OPTS
211 : {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0,
212 1 : _("Do not delete the test database after a test run"), NULL },
213 : POPT_TABLEEND
214 : };
215 :
216 1 : const struct CMUnitTest tests[] = {
217 : cmocka_unit_test_setup_teardown(test_mark_dom_offline,
218 : test_setup,
219 : test_teardown),
220 : cmocka_unit_test_setup_teardown(test_mark_subdom_offline,
221 : test_setup,
222 : test_teardown),
223 : cmocka_unit_test_setup_teardown(test_mark_subdom_offline_disabled,
224 : test_setup,
225 : test_teardown),
226 : };
227 :
228 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
229 1 : debug_level = SSSDBG_INVALID;
230 :
231 1 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
232 1 : while((opt = poptGetNextOpt(pc)) != -1) {
233 : switch(opt) {
234 : default:
235 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
236 : poptBadOption(pc, 0), poptStrerror(opt));
237 0 : poptPrintUsage(pc, stderr, 0);
238 0 : return 1;
239 : }
240 : }
241 1 : poptFreeContext(pc);
242 :
243 1 : DEBUG_CLI_INIT(debug_level);
244 :
245 : /* Even though normally the tests should clean up after themselves
246 : * they might not after a failed run. Remove the old db to be sure */
247 1 : tests_set_cwd();
248 1 : test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
249 1 : test_dom_suite_setup(TESTS_PATH);
250 :
251 1 : rv = cmocka_run_group_tests(tests, NULL, NULL);
252 1 : if (rv == 0 && !no_cleanup) {
253 1 : test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
254 : }
255 1 : return rv;
256 :
257 : return cmocka_run_group_tests(tests, NULL, NULL);
258 : }
|