tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

log_test_helpers.c (6248B)


      1 /* Copyright (c) 2015-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 #define LOG_PRIVATE
      4 #include "lib/log/log.h"
      5 #include "test/log_test_helpers.h"
      6 
      7 /**
      8 * \file log_test_helpers.c
      9 * \brief Code to check for expected log messages during testing.
     10 */
     11 
     12 static void mock_saving_logv(int severity, log_domain_mask_t domain,
     13                             const char *funcname, const char *suffix,
     14                             const char *format, va_list ap)
     15  CHECK_PRINTF(5, 0);
     16 
     17 /**
     18 * Smartlist of all the logs we've received since we last set up
     19 * log capture.
     20 */
     21 static smartlist_t *saved_logs = NULL;
     22 
     23 /** Boolean: should we also send messages to the test-runner? */
     24 static int echo_to_real_logs = 1;
     25 
     26 /** Record logs at this level or more severe */
     27 static int record_logs_at_level = LOG_ERR;
     28 
     29 static int saved_log_level = 0;
     30 
     31 /**
     32 * As setup_capture_of_logs, but do not relay log messages into the main
     33 * logging system.
     34 *
     35 * Avoid using this function; use setup_capture_of_logs() instead if you
     36 * can. If you must use this function, then make sure you detect any
     37 * unexpected log messages, and treat them as test failures. */
     38 void
     39 setup_full_capture_of_logs(int new_level)
     40 {
     41  setup_capture_of_logs(new_level);
     42  echo_to_real_logs = 0;
     43 }
     44 
     45 /**
     46 * Temporarily capture all the messages logged at severity <b>new_level</b> or
     47 * higher.
     48 *
     49 * This function does not prevent messages from being sent to the main
     50 * logging system.
     51 */
     52 void
     53 setup_capture_of_logs(int new_level)
     54 {
     55  if (saved_log_level == 0) {
     56    saved_log_level = log_global_min_severity_;
     57  } else {
     58    tor_assert(0);
     59  }
     60 
     61  /* Only change the log_global_min_severity_ if we're making things _more_
     62   * verbose.  Otherwise we could prevent real log messages that the test-
     63   * runner wanted.
     64   */
     65  if (log_global_min_severity_ < new_level)
     66    log_global_min_severity_ = new_level;
     67 
     68  record_logs_at_level = new_level;
     69  mock_clean_saved_logs();
     70  saved_logs = smartlist_new();
     71  MOCK(logv, mock_saving_logv);
     72  echo_to_real_logs = 1;
     73 }
     74 
     75 /**
     76 * Undo setup_capture_of_logs().
     77 *
     78 * This function is safe to call more than once.
     79 */
     80 void
     81 teardown_capture_of_logs(void)
     82 {
     83  UNMOCK(logv);
     84  if (saved_log_level)
     85    log_global_min_severity_ = saved_log_level;
     86  saved_log_level = 0;
     87  mock_clean_saved_logs();
     88 }
     89 
     90 /**
     91 * Clear all messages in mock_saved_logs()
     92 */
     93 void
     94 mock_clean_saved_logs(void)
     95 {
     96  if (!saved_logs)
     97    return;
     98  SMARTLIST_FOREACH(saved_logs, mock_saved_log_entry_t *, m,
     99                    { tor_free(m->generated_msg); tor_free(m); });
    100  smartlist_free(saved_logs);
    101  saved_logs = NULL;
    102 }
    103 
    104 /**
    105 * Return a list of all the messages captured since the last
    106 * setup_[full_]capture_of_logs() call. Each log call is recorded as a
    107 * mock_saved_log_entry_t.
    108 */
    109 const smartlist_t *
    110 mock_saved_logs(void)
    111 {
    112  return saved_logs;
    113 }
    114 
    115 int
    116 mock_saved_log_n_entries(void)
    117 {
    118  return saved_logs ? smartlist_len(saved_logs) : 0;
    119 }
    120 
    121 /**
    122 * Return true iff there is a message recorded by log capture
    123 * that is exactly equal to <b>msg</b>
    124 */
    125 int
    126 mock_saved_log_has_message(const char *msg)
    127 {
    128  if (saved_logs) {
    129    SMARTLIST_FOREACH(saved_logs, mock_saved_log_entry_t *, m,
    130                      {
    131                        if (msg && m->generated_msg &&
    132                            !strcmp(msg, m->generated_msg)) {
    133                          return 1;
    134                        }
    135                      });
    136  }
    137 
    138  return 0;
    139 }
    140 
    141 /**
    142 * Return true iff there is a message recorded by log capture
    143 * that contains <b>msg</b> as a substring.
    144 */
    145 int
    146 mock_saved_log_has_message_containing(const char *msg)
    147 {
    148  if (saved_logs) {
    149    SMARTLIST_FOREACH(saved_logs, mock_saved_log_entry_t *, m,
    150                      {
    151                        if (msg && m->generated_msg &&
    152                            strstr(m->generated_msg, msg)) {
    153                          return 1;
    154                        }
    155                      });
    156  }
    157 
    158  return 0;
    159 }
    160 
    161 /**
    162 * Return true iff there is not a message recorded by log capture
    163 * that contains <b>msg</b> as a substring.
    164 */
    165 int
    166 mock_saved_log_has_message_not_containing(const char *msg)
    167 {
    168  if (saved_logs) {
    169    SMARTLIST_FOREACH(
    170      saved_logs, mock_saved_log_entry_t *, m,
    171      {
    172        if (msg && m->generated_msg && strstr(m->generated_msg, msg))
    173          return 0;
    174      }
    175    );
    176  }
    177 
    178  return 1;
    179 }
    180 
    181 /** Return true iff the saved logs have any messages with <b>severity</b> */
    182 int
    183 mock_saved_log_has_severity(int severity)
    184 {
    185  int has_sev = 0;
    186  if (saved_logs) {
    187    SMARTLIST_FOREACH(saved_logs, mock_saved_log_entry_t *, m,
    188                      {
    189                        if (m->severity == severity) {
    190                          has_sev = 1;
    191                        }
    192                      });
    193  }
    194 
    195  return has_sev;
    196 }
    197 
    198 /** Return true iff the the saved logs have at lease one message */
    199 int
    200 mock_saved_log_has_entry(void)
    201 {
    202  if (saved_logs) {
    203    return smartlist_len(saved_logs) > 0;
    204  }
    205  return 0;
    206 }
    207 
    208 /* Replacement for logv: record the log message, and (maybe) send it
    209 * into the logging system again.
    210 */
    211 static void
    212 mock_saving_logv(int severity, log_domain_mask_t domain,
    213                 const char *funcname, const char *suffix,
    214                 const char *format, va_list ap)
    215 {
    216  char *buf = tor_malloc_zero(10240);
    217  int n;
    218  n = tor_vsnprintf(buf,10240,format,ap);
    219  tor_assert(n < 10240-1);
    220  buf[n]='\n';
    221  buf[n+1]='\0';
    222 
    223  if (echo_to_real_logs) {
    224    tor_log(severity, domain|LD_NO_MOCK, "%s", buf);
    225  }
    226 
    227  if (severity > record_logs_at_level) {
    228    tor_free(buf);
    229    return;
    230  }
    231 
    232  if (!saved_logs)
    233    saved_logs = smartlist_new();
    234 
    235  mock_saved_log_entry_t *e = tor_malloc_zero(sizeof(mock_saved_log_entry_t));
    236  e->severity = severity;
    237  e->funcname = funcname;
    238  e->suffix = suffix;
    239  e->format = format;
    240  e->generated_msg = tor_strdup(buf);
    241  tor_free(buf);
    242 
    243  smartlist_add(saved_logs, e);
    244 }
    245 
    246 void
    247 mock_dump_saved_logs(void)
    248 {
    249  if (saved_logs == NULL) {
    250    puts("  Captured logs: NULL");
    251    return;
    252  }
    253 
    254  puts("  Captured logs:");
    255  SMARTLIST_FOREACH_BEGIN(saved_logs, const mock_saved_log_entry_t *, m) {
    256    printf("% 5d. %s: %s\n", m_sl_idx + 1,
    257           log_level_to_string(m->severity),
    258           escaped(m->generated_msg));
    259  } SMARTLIST_FOREACH_END(m);
    260 }