libmicrohttpd2

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

test_basic_checks.c (8785B)


      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; (void) request; (void) path; (void) method; (void) upload_size;
    130   fprintf (stderr, "Unexpected call of the request callback.\n");
    131   err_flag = ! 0;
    132   return NULL;
    133 }
    134 
    135 
    136 static struct MHD_Daemon *
    137 test_daemon_create (void)
    138 {
    139   struct MHD_Daemon *d;
    140 
    141   d = MHD_daemon_create (my_req_process, NULL);
    142   if (NULL == d)
    143   {
    144     err_flag = ! 0;
    145     ERR_PRINT_LINE ();
    146     fprintf (stderr, "MHD_daemon_create() failed, NULL returned.\n");
    147     return NULL;
    148   }
    149   return d;
    150 }
    151 
    152 
    153 static int
    154 test_daemon_setup (struct MHD_Daemon *d,
    155                    int should_succeed)
    156 {
    157   enum MHD_StatusCode sc;
    158   int ret = ! 0;
    159 
    160   if (use_ipv6)
    161   {
    162     sc = MHD_DAEMON_SET_OPTIONS ( \
    163       d, MHD_D_OPTION_BIND_PORT (MHD_AF_DUAL_v4_OPTIONAL, 0));
    164     if (! tst_EXPECT_CHECK (sc,should_succeed))
    165       ret = 0;
    166   }
    167 
    168   if (use_ipv4)
    169   {
    170     sc = MHD_DAEMON_SET_OPTIONS ( \
    171       d, MHD_D_OPTION_BIND_PORT (MHD_AF_DUAL_v6_OPTIONAL, 0));
    172     if (! tst_EXPECT_CHECK (sc,should_succeed))
    173       ret = 0;
    174   }
    175 
    176   if (use_ip_best)
    177   {
    178     sc = MHD_DAEMON_SET_OPTIONS ( \
    179       d, MHD_D_OPTION_BIND_PORT (MHD_AF_AUTO, 0));
    180     if (! tst_EXPECT_CHECK (sc,should_succeed))
    181       ret = 0;
    182   }
    183 
    184   if (use_select)
    185   {
    186     sc = MHD_DAEMON_SET_OPTIONS ( \
    187       d, MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_SELECT));
    188     if (! tst_EXPECT_CHECK (sc,should_succeed))
    189       ret = 0;
    190   }
    191 
    192   if (use_poll)
    193   {
    194     sc = MHD_DAEMON_SET_OPTIONS ( \
    195       d, MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_POLL));
    196     if (! tst_EXPECT_CHECK (sc, should_succeed))
    197       ret = 0;
    198   }
    199 
    200   if (use_epoll)
    201   {
    202     sc = MHD_DAEMON_SET_OPTIONS ( \
    203       d, MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_EPOLL));
    204     if (! tst_EXPECT_CHECK (sc,should_succeed))
    205       ret = 0;
    206   }
    207 
    208   if (use_int_thread)
    209   {
    210     sc = MHD_DAEMON_SET_OPTIONS ( \
    211       d, MHD_D_OPTION_WORK_MODE (MHD_WM_OPTION_WORKER_THREADS (1)));
    212     if (! tst_EXPECT_CHECK (sc, should_succeed))
    213       ret = 0;
    214   }
    215 
    216   if (use_thread_per_conn)
    217   {
    218     sc = MHD_DAEMON_SET_OPTIONS ( \
    219       d, MHD_D_OPTION_WORK_MODE (MHD_WM_OPTION_THREAD_PER_CONNECTION ()));
    220     if (! tst_EXPECT_CHECK (sc, should_succeed))
    221       ret = 0;
    222   }
    223 
    224   if (use_thread_pool)
    225   {
    226     sc = MHD_DAEMON_SET_OPTIONS ( \
    227       d, MHD_D_OPTION_WORK_MODE (MHD_WM_OPTION_WORKER_THREADS (4)));
    228     if (! tst_EXPECT_CHECK (sc, should_succeed))
    229       ret = 0;
    230   }
    231 
    232   if (! ret)
    233     err_flag = ! 0;
    234 
    235   return ret;
    236 }
    237 
    238 
    239 static int
    240 test_daemon_start (struct MHD_Daemon *d,
    241                    int should_succeed)
    242 {
    243   enum MHD_StatusCode sc;
    244 
    245   sc = MHD_daemon_start (d);
    246   if (! tst_EXPECT_CHECK (sc,should_succeed))
    247   {
    248     err_flag = ! 0;
    249     return 0;
    250   }
    251 
    252   return ! 0;
    253 }
    254 
    255 
    256 static int
    257 test_simple (void)
    258 {
    259   struct MHD_Daemon *d;
    260   int ret = ! 0;
    261 
    262   err_flag = 0;
    263 
    264   d = test_daemon_create ();
    265   if (NULL == d)
    266     return (ret && ! err_flag);
    267 
    268   test_daemon_setup (d, ! 0);
    269   if (use_start)
    270     test_daemon_start (d, ! 0);
    271 
    272   test_daemon_setup (d, ! use_start);
    273 
    274   if (use_start)
    275     test_daemon_start (d, 0); /* Second "start" should fail */
    276 
    277   MHD_daemon_destroy (d);
    278 
    279   return (ret && ! err_flag);
    280 }
    281 
    282 
    283 /**
    284  * Initialise the test data
    285  * @param prog_name the name of the this program
    286  * @return non-zero if succeed,
    287  *         zero if failed
    288  */
    289 static int
    290 init_test (const char *prog_name)
    291 {
    292   if (mhdt_has_in_name (prog_name, "_start"))
    293     use_start = ! 0;
    294 
    295   if (mhdt_has_in_name (prog_name, "_ipv4"))
    296     use_ipv4 = ! 0;
    297 
    298   if (mhdt_has_in_name (prog_name, "_ipv6"))
    299     use_ipv6 = ! 0;
    300 
    301   if (mhdt_has_in_name (prog_name, "_ipbest"))
    302     use_ip_best = ! 0;
    303 
    304   use_select = mhdt_has_in_name (prog_name, "_select");
    305 
    306   use_poll = mhdt_has_in_name (prog_name, "_poll");
    307 
    308   use_epoll = mhdt_has_in_name (prog_name, "_epoll");
    309 
    310   use_int_thread = mhdt_has_in_name (prog_name, "_int_thread");
    311 
    312   use_thread_per_conn = mhdt_has_in_name (prog_name, "_thread_per_conn");
    313 
    314   use_thread_pool = mhdt_has_in_name (prog_name, "_thread_pool");
    315 
    316   return ! 0;
    317 }
    318 
    319 
    320 int
    321 main (int argc, char *argv[])
    322 {
    323   unsigned int num_err = 0;
    324   (void) argc; /* Unused. Silence compiler warning. */
    325 
    326   if (! init_test (argv[0]))
    327   {
    328     fprintf (stderr, "Failed to initialise the test!\n");
    329     return 77;
    330   }
    331 
    332   if (! test_simple ())
    333     ++num_err;
    334 
    335   if (0 != num_err)
    336   {
    337     fprintf (stderr, "Number of failed checks: %u\n", num_err);
    338     return 2;
    339   }
    340 
    341   printf ("All checks succeed.\n");
    342   return 0;
    343 }