libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

test_basic_checks.c (8777B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2016, 2024 Evgeny Grin (Karlson2k)
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file test_basic_checks.c
     41  * @brief  test for create, start and destroy
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 #include <stdio.h>
     45 #include <stdlib.h>
     46 #include <string.h>
     47 #include "microhttpd2.h"
     48 #include "mhdt_has_in_name.h"
     49 
     50 /* Helper macros */
     51 
     52 #define ERR_PRINT_LINE() \
     53         ((void) fprintf (stderr, "At the line number %u: ", \
     54                          (unsigned) __LINE__))
     55 
     56 /**
     57  * Check whether SC code is OK, print error if not.
     58  * @warning Do not use function call in the argument
     59  * @param sc the status code to check
     60  */
     61 #define tst_EXPECT_OK(sc) \
     62         ( (MHD_SC_OK == (sc)) ? (! 0) :                                    \
     63           (ERR_PRINT_LINE (),                                              \
     64            ((void) fprintf (stderr, "MHD function failed, returned: %u\n", \
     65                             (unsigned int) (sc))), (0)) )
     66 #if 0
     67 #  define tst_EXPECT_OK(sc) \
     68           ( (MHD_SC_OK == (sc)) ? (! 0) :                            \
     69             (ERR_PRINT_LINE (),                                      \
     70              ((void) fprintf (stderr,                                \
     71                               "MHD function failed, returned: %s\n", \
     72                               MHD_status_code_to_string_lazy (sc))), (0)) )
     73 #endif
     74 
     75 /**
     76  * Check whether SC code is OK, print error if not.
     77  * @warning Do not use function call in the argument
     78  * @param sc the status code to check
     79  */
     80 #define tst_EXPECT_FAIL(sc) \
     81         ( (MHD_SC_OK != (sc)) ? (! 0) : \
     82           (ERR_PRINT_LINE (),           \
     83            ((void) fprintf (stderr, "MHD function unexpectedly succeed.\n")), \
     84            (0)) )
     85 
     86 /**
     87  * Check whether SC code is success/failure as expected, print error if not.
     88  * @warning Do not use function call in the argument
     89  * @param sc the status code to check
     90  * @param expect_ok non-zero if SC should be OK, zero is SC should NOT be OK
     91  */
     92 #define tst_EXPECT_CHECK(sc, expect_ok) \
     93         ((expect_ok) ? tst_EXPECT_OK ((sc)) : tst_EXPECT_FAIL ((sc)))
     94 
     95 
     96 /* The test */
     97 
     98 static int use_start = 0;
     99 
    100 static int use_ipv4 = 0;
    101 
    102 static int use_ipv6 = 0;
    103 
    104 static int use_ip_best = 0;
    105 
    106 static int use_select = 0;
    107 
    108 static int use_poll = 0;
    109 
    110 static int use_epoll = 0;
    111 
    112 static int use_int_thread = 0;
    113 
    114 static int use_thread_per_conn = 0;
    115 
    116 static int use_thread_pool = 0;
    117 
    118 /* Dynamic run-time variables */
    119 
    120 static int err_flag = 0;
    121 
    122 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3) static const struct MHD_Action *
    123 my_req_process (void *cls,
    124                 struct MHD_Request *request,
    125                 const struct MHD_String *path,
    126                 enum MHD_HTTP_Method method,
    127                 uint_fast64_t upload_size)
    128 {
    129   (void)cls;
    130   (void)request;
    131   (void)path;
    132   (void)method;
    133   (void)upload_size;
    134   fprintf (stderr, "Unexpected call of the request callback.\n");
    135   err_flag = !0;
    136   return NULL;
    137 }
    138 
    139 
    140 static struct MHD_Daemon *
    141 test_daemon_create (void)
    142 {
    143   struct MHD_Daemon *d;
    144 
    145   d = MHD_daemon_create (my_req_process, NULL);
    146   if (NULL == d)
    147   {
    148     err_flag = !0;
    149     ERR_PRINT_LINE ();
    150     fprintf (stderr, "MHD_daemon_create() failed, NULL returned.\n");
    151     return NULL;
    152   }
    153   return d;
    154 }
    155 
    156 
    157 static int
    158 test_daemon_setup (struct MHD_Daemon *d,
    159                    int should_succeed)
    160 {
    161   enum MHD_StatusCode sc;
    162   int ret = !0;
    163 
    164   if (use_ipv6)
    165   {
    166     sc = MHD_DAEMON_SET_OPTIONS ( \
    167       d, MHD_D_OPTION_BIND_PORT (MHD_AF_DUAL_v4_OPTIONAL, 0));
    168     if (!tst_EXPECT_CHECK (sc, should_succeed))
    169       ret = 0;
    170   }
    171 
    172   if (use_ipv4)
    173   {
    174     sc = MHD_DAEMON_SET_OPTIONS ( \
    175       d, MHD_D_OPTION_BIND_PORT (MHD_AF_DUAL_v6_OPTIONAL, 0));
    176     if (!tst_EXPECT_CHECK (sc, should_succeed))
    177       ret = 0;
    178   }
    179 
    180   if (use_ip_best)
    181   {
    182     sc = MHD_DAEMON_SET_OPTIONS ( \
    183       d, MHD_D_OPTION_BIND_PORT (MHD_AF_AUTO, 0));
    184     if (!tst_EXPECT_CHECK (sc, should_succeed))
    185       ret = 0;
    186   }
    187 
    188   if (use_select)
    189   {
    190     sc = MHD_DAEMON_SET_OPTIONS ( \
    191       d, MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_SELECT));
    192     if (!tst_EXPECT_CHECK (sc, should_succeed))
    193       ret = 0;
    194   }
    195 
    196   if (use_poll)
    197   {
    198     sc = MHD_DAEMON_SET_OPTIONS ( \
    199       d, MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_POLL));
    200     if (!tst_EXPECT_CHECK (sc, should_succeed))
    201       ret = 0;
    202   }
    203 
    204   if (use_epoll)
    205   {
    206     sc = MHD_DAEMON_SET_OPTIONS ( \
    207       d, MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_EPOLL));
    208     if (!tst_EXPECT_CHECK (sc, should_succeed))
    209       ret = 0;
    210   }
    211 
    212   if (use_int_thread)
    213   {
    214     sc = MHD_DAEMON_SET_OPTIONS ( \
    215       d, MHD_D_OPTION_WORK_MODE (MHD_WM_OPTION_WORKER_THREADS (1)));
    216     if (!tst_EXPECT_CHECK (sc, should_succeed))
    217       ret = 0;
    218   }
    219 
    220   if (use_thread_per_conn)
    221   {
    222     sc = MHD_DAEMON_SET_OPTIONS ( \
    223       d, MHD_D_OPTION_WORK_MODE (MHD_WM_OPTION_THREAD_PER_CONNECTION ()));
    224     if (!tst_EXPECT_CHECK (sc, should_succeed))
    225       ret = 0;
    226   }
    227 
    228   if (use_thread_pool)
    229   {
    230     sc = MHD_DAEMON_SET_OPTIONS ( \
    231       d, MHD_D_OPTION_WORK_MODE (MHD_WM_OPTION_WORKER_THREADS (4)));
    232     if (!tst_EXPECT_CHECK (sc, should_succeed))
    233       ret = 0;
    234   }
    235 
    236   if (!ret)
    237     err_flag = !0;
    238 
    239   return ret;
    240 }
    241 
    242 
    243 static int
    244 test_daemon_start (struct MHD_Daemon *d,
    245                    int should_succeed)
    246 {
    247   enum MHD_StatusCode sc;
    248 
    249   sc = MHD_daemon_start (d);
    250   if (!tst_EXPECT_CHECK (sc, should_succeed))
    251   {
    252     err_flag = !0;
    253     return 0;
    254   }
    255 
    256   return !0;
    257 }
    258 
    259 
    260 static int
    261 test_simple (void)
    262 {
    263   struct MHD_Daemon *d;
    264   int ret = !0;
    265 
    266   err_flag = 0;
    267 
    268   d = test_daemon_create ();
    269   if (NULL == d)
    270     return (ret && !err_flag);
    271 
    272   test_daemon_setup (d, !0);
    273   if (use_start)
    274     test_daemon_start (d, !0);
    275 
    276   test_daemon_setup (d, !use_start);
    277 
    278   if (use_start)
    279     test_daemon_start (d, 0); /* Second "start" should fail */
    280 
    281   MHD_daemon_destroy (d);
    282 
    283   return (ret && !err_flag);
    284 }
    285 
    286 
    287 /**
    288  * Initialise the test data
    289  * @param prog_name the name of the this program
    290  * @return non-zero if succeed,
    291  *         zero if failed
    292  */
    293 static int
    294 init_test (const char *prog_name)
    295 {
    296   if (mhdt_has_in_name (prog_name, "_start"))
    297     use_start = !0;
    298 
    299   if (mhdt_has_in_name (prog_name, "_ipv4"))
    300     use_ipv4 = !0;
    301 
    302   if (mhdt_has_in_name (prog_name, "_ipv6"))
    303     use_ipv6 = !0;
    304 
    305   if (mhdt_has_in_name (prog_name, "_ipbest"))
    306     use_ip_best = !0;
    307 
    308   use_select = mhdt_has_in_name (prog_name, "_select");
    309 
    310   use_poll = mhdt_has_in_name (prog_name, "_poll");
    311 
    312   use_epoll = mhdt_has_in_name (prog_name, "_epoll");
    313 
    314   use_int_thread = mhdt_has_in_name (prog_name, "_int_thread");
    315 
    316   use_thread_per_conn = mhdt_has_in_name (prog_name, "_thread_per_conn");
    317 
    318   use_thread_pool = mhdt_has_in_name (prog_name, "_thread_pool");
    319 
    320   return !0;
    321 }
    322 
    323 
    324 int
    325 main (int argc, char *argv[])
    326 {
    327   unsigned int num_err = 0;
    328   (void)argc;  /* Unused. Silence compiler warning. */
    329 
    330   if (!init_test (argv[0]))
    331   {
    332     fprintf (stderr, "Failed to initialise the test!\n");
    333     return 77;
    334   }
    335 
    336   if (!test_simple ())
    337     ++num_err;
    338 
    339   if (0 != num_err)
    340   {
    341     fprintf (stderr, "Number of failed checks: %u\n", num_err);
    342     return 2;
    343   }
    344 
    345   printf ("All checks succeed.\n");
    346   return 0;
    347 }