LCOV - code coverage report
Current view: top level - source3/smbd/notifyd - test_notifyd.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 113 146 77.4 %
Date: 2024-04-21 15:09:00 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       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.
       6             :  *
       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.
      11             :  *
      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/>.
      14             :  */
      15             : 
      16             : #include "replace.h"
      17             : #include "fcn_wait.h"
      18             : #include "notifyd.h"
      19             : #include "notifyd_db.h"
      20             : #include "messages.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"
      29             : 
      30             : struct fcn_test_state {
      31             :         struct tevent_req *fcn_req;
      32             :         bool got_trigger;
      33             : };
      34             : 
      35             : static void fcn_test_done(struct tevent_req *subreq);
      36             : 
      37           2 : static struct tevent_req *fcn_test_send(
      38             :         TALLOC_CTX *mem_ctx,
      39             :         struct tevent_context *ev,
      40             :         struct messaging_context *msg_ctx,
      41             :         struct server_id notifyd,
      42             :         const char *fcn_path,
      43             :         uint32_t fcn_filter,
      44             :         uint32_t fcn_subdir_filter,
      45             :         const char *trigger_path,
      46             :         uint32_t trigger_action,
      47             :         uint32_t trigger_filter)
      48             : {
      49           2 :         struct tevent_req *req = NULL;
      50           2 :         struct fcn_test_state *state = NULL;
      51           0 :         struct notify_trigger_msg msg;
      52           0 :         struct iovec iov[2];
      53           0 :         NTSTATUS status;
      54             : 
      55           2 :         req = tevent_req_create(mem_ctx, &state, struct fcn_test_state);
      56           2 :         if (req == NULL) {
      57           0 :                 return NULL;
      58             :         }
      59             : 
      60           2 :         state->fcn_req = fcn_wait_send(
      61             :                 state,
      62             :                 ev,
      63             :                 msg_ctx,
      64             :                 notifyd,
      65             :                 fcn_path,
      66             :                 fcn_filter,
      67             :                 fcn_subdir_filter);
      68           2 :         if (tevent_req_nomem(state->fcn_req, req)) {
      69           0 :                 return tevent_req_post(req, ev);
      70             :         }
      71           2 :         tevent_req_set_callback(state->fcn_req, fcn_test_done, req);
      72             : 
      73           2 :         msg = (struct notify_trigger_msg) {
      74           2 :                 .when = timespec_current(),
      75             :                 .action = trigger_action,
      76             :                 .filter = trigger_filter,
      77             :         };
      78           2 :         iov[0] = (struct iovec) {
      79             :                 .iov_base = &msg,
      80             :                 .iov_len = offsetof(struct notify_trigger_msg, path),
      81             :         };
      82           2 :         iov[1] = (struct iovec) {
      83             :                 .iov_base = discard_const_p(char, trigger_path),
      84           2 :                 .iov_len = strlen(trigger_path)+1,
      85             :         };
      86             : 
      87           2 :         status = messaging_send_iov(
      88             :                 msg_ctx,
      89             :                 notifyd,
      90             :                 MSG_SMB_NOTIFY_TRIGGER,
      91             :                 iov,
      92             :                 ARRAY_SIZE(iov),
      93             :                 NULL,
      94             :                 0);
      95           2 :         if (tevent_req_nterror(req, status)) {
      96           0 :                 return tevent_req_post(req, ev);
      97             :         }
      98             : 
      99           2 :         return req;
     100             : }
     101             : 
     102           4 : static void fcn_test_done(struct tevent_req *subreq)
     103             : {
     104           4 :         struct tevent_req *req = tevent_req_callback_data(
     105             :                 subreq, struct tevent_req);
     106           4 :         struct fcn_test_state *state = tevent_req_data(
     107             :                 req, struct fcn_test_state);
     108           0 :         NTSTATUS status;
     109           0 :         bool ok;
     110             : 
     111           4 :         SMB_ASSERT(subreq == state->fcn_req);
     112             : 
     113           4 :         status = fcn_wait_recv(subreq, NULL, NULL, NULL, NULL);
     114             : 
     115           4 :         if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) {
     116           2 :                 TALLOC_FREE(subreq);
     117           2 :                 state->fcn_req = NULL;
     118           2 :                 tevent_req_done(req);
     119           2 :                 return;
     120             :         }
     121             : 
     122           2 :         if (tevent_req_nterror(req, status)) {
     123           0 :                 TALLOC_FREE(subreq);
     124           0 :                 state->fcn_req = NULL;
     125           0 :                 return;
     126             :         }
     127             : 
     128           2 :         state->got_trigger = true;
     129             : 
     130           2 :         ok = tevent_req_cancel(subreq);
     131           2 :         if (!ok) {
     132           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     133           0 :                 return;
     134             :         }
     135             : }
     136             : 
     137           2 : static NTSTATUS fcn_test_recv(struct tevent_req *req, bool *got_trigger)
     138             : {
     139           2 :         struct fcn_test_state *state = tevent_req_data(
     140             :                 req, struct fcn_test_state);
     141           0 :         NTSTATUS status;
     142             : 
     143           2 :         if (tevent_req_is_nterror(req, &status)) {
     144           0 :                 return status;
     145             :         }
     146           2 :         if (got_trigger != NULL) {
     147           2 :                 *got_trigger = state->got_trigger;
     148             :         }
     149             : 
     150           2 :         return NT_STATUS_OK;
     151             : }
     152             : 
     153           2 : static NTSTATUS fcn_test(
     154             :         struct messaging_context *msg_ctx,
     155             :         struct server_id notifyd,
     156             :         const char *fcn_path,
     157             :         uint32_t fcn_filter,
     158             :         uint32_t fcn_subdir_filter,
     159             :         const char *trigger_path,
     160             :         uint32_t trigger_action,
     161             :         uint32_t trigger_filter,
     162             :         bool *got_trigger)
     163             : {
     164           2 :         struct tevent_context *ev = NULL;
     165           2 :         struct tevent_req *req = NULL;
     166           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     167             : 
     168           2 :         ev = samba_tevent_context_init(msg_ctx);
     169           2 :         if (ev == NULL) {
     170           0 :                 goto fail;
     171             :         }
     172           2 :         req = fcn_test_send(
     173             :                 ev,
     174             :                 ev,
     175             :                 msg_ctx,
     176             :                 notifyd,
     177             :                 fcn_path,
     178             :                 fcn_filter,
     179             :                 fcn_subdir_filter,
     180             :                 trigger_path,
     181             :                 trigger_action,
     182             :                 trigger_filter);
     183           2 :         if (req == NULL) {
     184           0 :                 goto fail;
     185             :         }
     186           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     187           0 :                 goto fail;
     188             :         }
     189           2 :         status = fcn_test_recv(req, got_trigger);
     190           2 : fail:
     191           2 :         TALLOC_FREE(ev);
     192           2 :         return status;
     193             : }
     194             : 
     195           2 : static bool test_notifyd_trigger1(struct torture_context *tctx)
     196             : {
     197           2 :         struct messaging_context *msg_ctx = NULL;
     198           2 :         struct server_id_db *names = NULL;
     199           0 :         struct server_id notifyd;
     200           0 :         NTSTATUS status;
     201           2 :         bool got_trigger = false;
     202           0 :         bool ok;
     203             : 
     204             :         /*
     205             :          * Basic filechangenotify test: Wait for /home, trigger on
     206             :          * /home/foo, check an event was received
     207             :          */
     208             : 
     209           2 :         lp_load_global(tctx->lp_ctx->szConfigFile);
     210             : 
     211           2 :         msg_ctx = messaging_init(tctx, tctx->ev);
     212           2 :         torture_assert_not_null(tctx, msg_ctx, "messaging_init");
     213             : 
     214           2 :         names = messaging_names_db(msg_ctx);
     215           2 :         ok = server_id_db_lookup_one(names, "notify-daemon", &notifyd);
     216           2 :         torture_assert(tctx, ok, "server_id_db_lookup_one");
     217             : 
     218           2 :         status = fcn_test(
     219             :                 msg_ctx,
     220             :                 notifyd,
     221             :                 "/home",
     222             :                 UINT32_MAX,
     223             :                 UINT32_MAX,
     224             :                 "/home/foo",
     225             :                 UINT32_MAX,
     226             :                 UINT32_MAX,
     227             :                 &got_trigger);
     228           2 :         torture_assert_ntstatus_ok(tctx, status, "fcn_test");
     229           2 :         torture_assert(tctx, got_trigger, "got_trigger");
     230             : 
     231           2 :         return true;
     232             : }
     233             : 
     234             : struct notifyd_have_state {
     235             :         struct server_id self;
     236             :         bool found;
     237             : };
     238             : 
     239           2 : static bool notifyd_have_fn(
     240             :         const char *path,
     241             :         struct server_id server,
     242             :         const struct notify_instance *instance,
     243             :         void *private_data)
     244             : {
     245           2 :         struct notifyd_have_state *state = private_data;
     246           2 :         state->found |= server_id_equal(&server, &state->self);
     247           2 :         return true;
     248             : }
     249             : 
     250           4 : static bool notifyd_have_self(struct messaging_context *msg_ctx)
     251             : {
     252           4 :         struct notifyd_have_state state = {
     253           4 :                 .self = messaging_server_id(msg_ctx),
     254             :         };
     255           0 :         NTSTATUS status;
     256             : 
     257           4 :         status = notify_walk(msg_ctx, notifyd_have_fn, &state);
     258           4 :         if (!NT_STATUS_IS_OK(status)) {
     259           0 :                 return false;
     260             :         }
     261           4 :         return state.found;
     262             : }
     263             : 
     264           2 : static bool test_notifyd_dbtest1(struct torture_context *tctx)
     265             : {
     266           2 :         struct tevent_context *ev = tctx->ev;
     267           2 :         struct messaging_context *msg_ctx = NULL;
     268           2 :         struct tevent_req *req = NULL;
     269           2 :         struct server_id_db *names = NULL;
     270           0 :         struct server_id notifyd;
     271           0 :         NTSTATUS status;
     272           0 :         bool ok;
     273             : 
     274             :         /*
     275             :          * Make sure fcn_wait_send adds us to the notifyd internal
     276             :          * database and that cancelling the fcn request removes us
     277             :          * again.
     278             :          */
     279             : 
     280           2 :         lp_load_global(tctx->lp_ctx->szConfigFile);
     281             : 
     282           2 :         msg_ctx = messaging_init(tctx, ev);
     283           2 :         torture_assert_not_null(tctx, msg_ctx, "messaging_init");
     284             : 
     285           2 :         names = messaging_names_db(msg_ctx);
     286           2 :         ok = server_id_db_lookup_one(names, "notify-daemon", &notifyd);
     287           2 :         torture_assert(tctx, ok, "server_id_db_lookup_one");
     288             : 
     289           2 :         req = fcn_wait_send(
     290             :                 msg_ctx, ev, msg_ctx, notifyd, "/x", UINT32_MAX, UINT32_MAX);
     291           2 :         torture_assert_not_null(tctx, req, "fcn_wait_send");
     292             : 
     293           2 :         ok = notifyd_have_self(msg_ctx);
     294           2 :         torture_assert(tctx, ok, "notifyd_have_self");
     295             : 
     296           2 :         ok = tevent_req_cancel(req);
     297           2 :         torture_assert(tctx, ok, "tevent_req_cancel");
     298             : 
     299           2 :         ok = tevent_req_poll(req, ev);
     300           2 :         torture_assert(tctx, ok, "tevent_req_poll");
     301             : 
     302           2 :         status = fcn_wait_recv(req, NULL, NULL, NULL, NULL);
     303           2 :         torture_assert_ntstatus_equal(
     304             :                 tctx, status, NT_STATUS_CANCELLED, "fcn_wait_recv");
     305           2 :         TALLOC_FREE(req);
     306             : 
     307           2 :         ok = notifyd_have_self(msg_ctx);
     308           2 :         torture_assert(tctx, !ok, "tevent_req_poll");
     309           2 :         TALLOC_FREE(msg_ctx);
     310             : 
     311           2 :         return true;
     312             : }
     313             : 
     314             : NTSTATUS torture_notifyd_init(TALLOC_CTX *mem_ctx);
     315        2354 : NTSTATUS torture_notifyd_init(TALLOC_CTX *mem_ctx)
     316             : {
     317        2354 :         struct torture_suite *suite = NULL;
     318        2354 :         struct torture_tcase *tcase = NULL;
     319         125 :         bool ok;
     320             : 
     321        2354 :         suite = torture_suite_create(mem_ctx, "notifyd");
     322        2354 :         if (suite == NULL) {
     323           0 :                 goto fail;
     324             :         }
     325             : 
     326        2354 :         tcase = torture_suite_add_simple_test(
     327             :                 suite, "trigger1", test_notifyd_trigger1);
     328        2354 :         if (tcase == NULL) {
     329           0 :                 goto fail;
     330             :         }
     331             : 
     332        2354 :         tcase = torture_suite_add_simple_test(
     333             :                 suite, "dbtest1", test_notifyd_dbtest1);
     334        2354 :         if (tcase == NULL) {
     335           0 :                 goto fail;
     336             :         }
     337        2354 :         suite->description = "notifyd unit tests";
     338             : 
     339        2354 :         ok = torture_register_suite(mem_ctx, suite);
     340        2354 :         if (!ok) {
     341           0 :                 goto fail;
     342             :         }
     343        2354 :         return NT_STATUS_OK;
     344           0 : fail:
     345           0 :         TALLOC_FREE(suite);
     346           0 :         return NT_STATUS_NO_MEMORY;
     347             : }

Generated by: LCOV version 1.14