2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 3 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "notifyd_db.h"
21 #include "lib/util/server_id.h"
22 #include "lib/util/server_id_db.h"
23 #include "lib/util/tevent_ntstatus.h"
24 #include "lib/torture/torture.h"
25 #include "torture/local/proto.h"
26 #include "lib/param/loadparm.h"
27 #include "source3/param/loadparm.h"
28 #include "source4/torture/smbtorture.h"
30 struct fcn_test_state
{
31 struct tevent_req
*fcn_req
;
35 static void fcn_test_done(struct tevent_req
*subreq
);
37 static struct tevent_req
*fcn_test_send(
39 struct tevent_context
*ev
,
40 struct messaging_context
*msg_ctx
,
41 struct server_id notifyd
,
44 uint32_t fcn_subdir_filter
,
45 const char *trigger_path
,
46 uint32_t trigger_action
,
47 uint32_t trigger_filter
)
49 struct tevent_req
*req
= NULL
;
50 struct fcn_test_state
*state
= NULL
;
51 struct notify_trigger_msg msg
;
55 req
= tevent_req_create(mem_ctx
, &state
, struct fcn_test_state
);
60 state
->fcn_req
= fcn_wait_send(
68 if (tevent_req_nomem(state
->fcn_req
, req
)) {
69 return tevent_req_post(req
, ev
);
71 tevent_req_set_callback(state
->fcn_req
, fcn_test_done
, req
);
73 msg
= (struct notify_trigger_msg
) {
74 .when
= timespec_current(),
75 .action
= trigger_action
,
76 .filter
= trigger_filter
,
78 iov
[0] = (struct iovec
) {
80 .iov_len
= offsetof(struct notify_trigger_msg
, path
),
82 iov
[1] = (struct iovec
) {
83 .iov_base
= discard_const_p(char, trigger_path
),
84 .iov_len
= strlen(trigger_path
)+1,
87 status
= messaging_send_iov(
90 MSG_SMB_NOTIFY_TRIGGER
,
95 if (tevent_req_nterror(req
, status
)) {
96 return tevent_req_post(req
, ev
);
102 static void fcn_test_done(struct tevent_req
*subreq
)
104 struct tevent_req
*req
= tevent_req_callback_data(
105 subreq
, struct tevent_req
);
106 struct fcn_test_state
*state
= tevent_req_data(
107 req
, struct fcn_test_state
);
111 SMB_ASSERT(subreq
== state
->fcn_req
);
113 status
= fcn_wait_recv(subreq
, NULL
, NULL
, NULL
, NULL
);
115 if (NT_STATUS_EQUAL(status
, NT_STATUS_CANCELLED
)) {
117 state
->fcn_req
= NULL
;
118 tevent_req_done(req
);
122 if (tevent_req_nterror(req
, status
)) {
124 state
->fcn_req
= NULL
;
128 state
->got_trigger
= true;
130 ok
= tevent_req_cancel(subreq
);
132 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
137 static NTSTATUS
fcn_test_recv(struct tevent_req
*req
, bool *got_trigger
)
139 struct fcn_test_state
*state
= tevent_req_data(
140 req
, struct fcn_test_state
);
143 if (tevent_req_is_nterror(req
, &status
)) {
146 if (got_trigger
!= NULL
) {
147 *got_trigger
= state
->got_trigger
;
153 static NTSTATUS
fcn_test(
154 struct messaging_context
*msg_ctx
,
155 struct server_id notifyd
,
156 const char *fcn_path
,
158 uint32_t fcn_subdir_filter
,
159 const char *trigger_path
,
160 uint32_t trigger_action
,
161 uint32_t trigger_filter
,
164 struct tevent_context
*ev
= NULL
;
165 struct tevent_req
*req
= NULL
;
166 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
168 ev
= samba_tevent_context_init(msg_ctx
);
186 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
189 status
= fcn_test_recv(req
, got_trigger
);
195 static bool test_notifyd_trigger1(struct torture_context
*tctx
)
197 struct messaging_context
*msg_ctx
= NULL
;
198 struct server_id_db
*names
= NULL
;
199 struct server_id notifyd
;
201 bool got_trigger
= false;
205 * Basic filechangenotify test: Wait for /home, trigger on
206 * /home/foo, check an event was received
209 lp_load_global(tctx
->lp_ctx
->szConfigFile
);
211 msg_ctx
= messaging_init(tctx
, tctx
->ev
);
212 torture_assert_not_null(tctx
, msg_ctx
, "messaging_init");
214 names
= messaging_names_db(msg_ctx
);
215 ok
= server_id_db_lookup_one(names
, "notify-daemon", ¬ifyd
);
216 torture_assert(tctx
, ok
, "server_id_db_lookup_one");
228 torture_assert_ntstatus_ok(tctx
, status
, "fcn_test");
229 torture_assert(tctx
, got_trigger
, "got_trigger");
234 struct notifyd_have_state
{
235 struct server_id self
;
239 static bool notifyd_have_fn(
241 struct server_id server
,
242 const struct notify_instance
*instance
,
245 struct notifyd_have_state
*state
= private_data
;
246 state
->found
|= server_id_equal(&server
, &state
->self
);
250 static bool notifyd_have_self(struct messaging_context
*msg_ctx
)
252 struct notifyd_have_state state
= {
253 .self
= messaging_server_id(msg_ctx
),
257 status
= notify_walk(msg_ctx
, notifyd_have_fn
, &state
);
258 if (!NT_STATUS_IS_OK(status
)) {
264 static bool test_notifyd_dbtest1(struct torture_context
*tctx
)
266 struct tevent_context
*ev
= tctx
->ev
;
267 struct messaging_context
*msg_ctx
= NULL
;
268 struct tevent_req
*req
= NULL
;
269 struct server_id_db
*names
= NULL
;
270 struct server_id notifyd
;
275 * Make sure fcn_wait_send adds us to the notifyd internal
276 * database and that cancelling the fcn request removes us
280 lp_load_global(tctx
->lp_ctx
->szConfigFile
);
282 msg_ctx
= messaging_init(tctx
, ev
);
283 torture_assert_not_null(tctx
, msg_ctx
, "messaging_init");
285 names
= messaging_names_db(msg_ctx
);
286 ok
= server_id_db_lookup_one(names
, "notify-daemon", ¬ifyd
);
287 torture_assert(tctx
, ok
, "server_id_db_lookup_one");
290 msg_ctx
, ev
, msg_ctx
, notifyd
, "/x", UINT32_MAX
, UINT32_MAX
);
291 torture_assert_not_null(tctx
, req
, "fcn_wait_send");
293 ok
= notifyd_have_self(msg_ctx
);
294 torture_assert(tctx
, ok
, "notifyd_have_self");
296 ok
= tevent_req_cancel(req
);
297 torture_assert(tctx
, ok
, "tevent_req_cancel");
299 ok
= tevent_req_poll(req
, ev
);
300 torture_assert(tctx
, ok
, "tevent_req_poll");
302 status
= fcn_wait_recv(req
, NULL
, NULL
, NULL
, NULL
);
303 torture_assert_ntstatus_equal(
304 tctx
, status
, NT_STATUS_CANCELLED
, "fcn_wait_recv");
307 ok
= notifyd_have_self(msg_ctx
);
308 torture_assert(tctx
, !ok
, "tevent_req_poll");
309 TALLOC_FREE(msg_ctx
);
314 NTSTATUS
torture_notifyd_init(TALLOC_CTX
*mem_ctx
);
315 NTSTATUS
torture_notifyd_init(TALLOC_CTX
*mem_ctx
)
317 struct torture_suite
*suite
= NULL
;
318 struct torture_tcase
*tcase
= NULL
;
321 suite
= torture_suite_create(mem_ctx
, "notifyd");
326 tcase
= torture_suite_add_simple_test(
327 suite
, "trigger1", test_notifyd_trigger1
);
332 tcase
= torture_suite_add_simple_test(
333 suite
, "dbtest1", test_notifyd_dbtest1
);
337 suite
->description
= "notifyd unit tests";
339 ok
= torture_register_suite(mem_ctx
, suite
);
346 return NT_STATUS_NO_MEMORY
;