void
test_cloning_with_log_message(gchar *msg)
{
  LogMessage *original_log_message, *log_message, *cloned_log_message;
  regex_t bad_hostname;
  GSockAddr *addr = g_sockaddr_inet_new("10.10.10.10", 1010);
  LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;

  testcase_begin("Testing log message cloning; msg='%s'", msg);

  parse_options.flags = LP_SYSLOG_PROTOCOL;
  parse_options.bad_hostname = &bad_hostname;

  original_log_message = log_msg_new(msg, strlen(msg), addr, &parse_options);
  log_message = log_msg_new(msg, strlen(msg), addr, &parse_options);

  log_msg_set_tag_by_name(log_message, "newtag");
  path_options.ack_needed = FALSE;

  cloned_log_message = log_msg_clone_cow(log_message, &path_options);
  assert_log_messages_equal(cloned_log_message, original_log_message);

  set_new_log_message_attributes(cloned_log_message);

  assert_log_messages_equal(log_message, original_log_message);
  assert_new_log_message_attributes(cloned_log_message);
  assert_log_message_has_tag(cloned_log_message, "newtag");

  log_msg_unref(cloned_log_message);
  log_msg_unref(log_message);
  log_msg_unref(original_log_message);

  testcase_end();
}
Beispiel #2
0
LogMessage *
create_empty_message(void)
{
  LogMessage *msg;
  char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép";
  GSockAddr *saddr;

  saddr = g_sockaddr_inet_new("10.11.12.13", 1010);
  msg = log_msg_new(msg_str, strlen(msg_str), saddr, &parse_options);
  g_sockaddr_unref(saddr);
  log_msg_set_match(msg, 0, "whole-match", -1);
  log_msg_set_match(msg, 1, "first-match", -1);
  log_msg_set_tag_by_name(msg, "alma");
  log_msg_set_tag_by_name(msg, "korte");
  log_msg_clear_tag_by_name(msg, "narancs");
  log_msg_set_tag_by_name(msg, "citrom");
  msg->rcptid = 555;
  msg->host_id = 0xcafebabe;

  /* fix some externally or automatically defined values */
  log_msg_set_value(msg, LM_V_HOST_FROM, "kismacska", -1);
  msg->timestamps[LM_TS_RECVD].tv_sec = 1139684315;
  msg->timestamps[LM_TS_RECVD].tv_usec = 639000;
  msg->timestamps[LM_TS_RECVD].zone_offset = get_local_timezone_ofs(1139684315);

  return msg;
}
Beispiel #3
0
loglinesType *
testcase_get_logmessages(gchar *logs)
{
    int i, len;
    loglinesType *self;
    gchar **input_lines;
    gchar *logline;
    GSockAddr *addr = g_sockaddr_inet_new("10.10.10.10", 1010);
    LogMessage *msg;

    self = g_new(loglinesType, 1);
    self->logmessages = g_ptr_array_sized_new(10);
    self->num_of_logs = 0;

    input_lines = g_strsplit(logs, "\n", 0);

    for (i = 0; input_lines[i]; ++i)
    {
        logline = g_strdup_printf("Jul 29 06:25:41 vav zorp/inter_http[27940]: %s", input_lines[i]);
        len = strlen(logline);
        if (logline[len-1] == '\n')
            logline[len-1] = 0;

        msg = log_msg_new(logline, len, addr, &parse_options);
        g_ptr_array_add(self->logmessages, msg);
        ++(self->num_of_logs);
        g_free(logline);
    }

    msg_format_options_destroy(&parse_options);

    return self;
}
Beispiel #4
0
static gboolean
log_reader_handle_line(LogReader *self, const guchar *line, gint length, GSockAddr *saddr)
{
  LogMessage *m;
  LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
  gint i;
  
  msg_debug("Incoming log entry", 
            evt_tag_printf("line", "%.*s", length, line),
            NULL);
  /* use the current time to get the time zone offset */
  m = log_msg_new((gchar *) line, length,
                  saddr,
                  &self->options->parse_options);
  
  if (!m->saddr && self->peer_addr)
    {
      m->saddr = g_sockaddr_ref(self->peer_addr);
    }

  if (self->options->tags)
    {
      for (i = 0; i < self->options->tags->len; i++)
        {
          log_msg_set_tag_by_id(m, g_array_index(self->options->tags, LogTagId, i));
        }
    }

  log_msg_set_tag_by_id(m, self->super.options->source_group_tag);

  log_pipe_queue(&self->super.super, m, &path_options);
  return log_source_free_to_send(&self->super);
}
static LogMessage *
create_test_message (void)
{
  const gchar *log_message = "<15>Sep  4 15:03:55 localhost test-program[3086]: some random message";

  return log_msg_new(log_message, strlen(log_message), NULL, &parse_options);
}
Beispiel #6
0
LogMessage *
parse_log_message(gchar *raw_message_str, gint parse_flags, gchar *bad_hostname_re)
{
  LogMessage *message;
  GSockAddr *addr = g_sockaddr_inet_new("10.10.10.10", 1010);
  regex_t bad_hostname;

  parse_options.flags = parse_flags;
  parse_options.sdata_param_value_max = 255;

  if (bad_hostname_re)
    {
      assert_gint(regcomp(&bad_hostname, bad_hostname_re, REG_NOSUB | REG_EXTENDED), 0,
                  "Unexpected failure of regcomp(); bad_hostname_re='%s'", bad_hostname_re);
      parse_options.bad_hostname = &bad_hostname;
    }

  message = log_msg_new(raw_message_str, strlen(raw_message_str), addr, &parse_options);

  if (bad_hostname_re)
    {
      regfree(parse_options.bad_hostname);
      parse_options.bad_hostname = NULL;
    }

  simulate_log_readers_effect_on_timezone_offset(message);
  return message;
}
Beispiel #7
0
gpointer
threaded_feed(gpointer st)
{
  LogQueue *q = (LogQueue *) st;
  char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: árvíztűrőtükörfúrógép";
  gint i;
  LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
  LogMessage *msg;

  for (i = 0; i < 100000; i++)
    {
      msg = log_msg_new(msg_str, strlen(msg_str), g_sockaddr_inet_new("10.10.10.10", 1010), 0, NULL, -1);
      log_msg_add_ack(msg, &path_options);
      msg->ack_func = test_ack;

      g_static_mutex_lock(&threaded_lock);
      if (!log_queue_push_tail(q, msg, &path_options))
        {
          fprintf(stderr, "Queue unable to consume enough messages: %d\n", fed_messages);
          return GUINT_TO_POINTER(1);
        }
      g_static_mutex_unlock(&threaded_lock);
    }
  return NULL;
}
Beispiel #8
0
LogMessage *
construct_log_message(void)
{
  const gchar *raw_msg = "foo";
  LogMessage *msg;

  msg = log_msg_new(raw_msg, strlen(raw_msg), NULL, &parse_options);
  log_msg_set_value(msg, LM_V_HOST, raw_msg, -1);
  return msg;
}
LogMessage *
create_message(void)
{
  LogMessage *msg;
  const gchar *text = "<134>1 2009-10-16T11:51:56+02:00 exchange.macartney.esbjerg MSExchange_ADAccess 20208 _MSGID_ [origin ip=\"exchange.macartney.esbjerg\"][meta sequenceId=\"191732\" sysUpTime=\"68807696\"][[email protected] Data=\"MSEXCHANGEOWAAPPPOOL.CONFIG\\\" -W \\\"\\\" -M 1 -AP \\\"MSEXCHANGEOWAAPPPOOL5244fileserver.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 mail.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 maindc.macartney.esbjerg CD- 1 6 6 0 0 1 1 6 1 \"][[email protected] Keyword=\"Classic\"] ApplicationMSExchangeADAccess: message";

  msg = log_msg_new(text, strlen(text), NULL, &parse_options);
  log_msg_set_tag_by_name(msg, "almafa");
  return msg;
}
static LogMessage *
kmsg_parse_message(const gchar *raw_message_str)
{
  LogMessage *message;
  GSockAddr *addr = g_sockaddr_inet_new("10.10.10.10", 1010);

  message = log_msg_new(raw_message_str, strlen(raw_message_str), addr, &parse_options);

  g_sockaddr_unref(addr);
  return message;
}
Beispiel #11
0
int
testcase_replace(const gchar *log, const gchar *re, gchar *replacement, const gchar *expected_result, const gint matcher_flags, LogMatcher *m)
{
  LogMessage *msg;
  LogTemplate *r;
  gchar *result;
  gssize length;
  gchar buf[1024];
  gssize msglen;
  NVHandle nonasciiz = log_msg_get_value_handle("NON-ASCIIZ");
  const gchar *value;
  GSockAddr *sa;

  sa = g_sockaddr_inet_new("10.10.10.10", 1010);
  msg = log_msg_new(log, strlen(log), sa, &parse_options);
  g_sockaddr_unref(sa);

  /* NOTE: we test how our matchers cope with non-zero terminated values. We don't change message_len, only the value */

  g_snprintf(buf, sizeof(buf), "%sAAAAAAAAAAAA", log_msg_get_value(msg, LM_V_MESSAGE, &msglen));
  log_msg_set_value(msg, log_msg_get_value_handle("MESSAGE2"), buf, -1);

  /* add a non-zero terminated indirect value which contains the whole message */
  log_msg_set_value_indirect(msg, nonasciiz, log_msg_get_value_handle("MESSAGE2"), 0, 0, msglen);

  log_matcher_set_flags(m, matcher_flags);

  log_matcher_compile(m, re);

  r = log_template_new(configuration, NULL);
  log_template_compile(r, replacement, NULL);

  NVTable *nv_table = nv_table_ref(msg->payload);
  value = log_msg_get_value(msg, nonasciiz, &msglen);
  result = log_matcher_replace(m, msg, nonasciiz, value, msglen, r, &length);
  value = log_msg_get_value(msg, nonasciiz, &msglen);
  nv_table_unref(nv_table);

  if (strncmp(result ? result : value, expected_result, result ? length : msglen) != 0)
    {
      fprintf(stderr, "Testcase failure. pattern=%s, result=%.*s, expected=%s\n", re, (gint) length, result ? result : value, expected_result);
      exit(1);
    }

  g_free(result);

  log_template_unref(r);
  log_matcher_unref(m);
  log_msg_unref(msg);
  return 0;
}
gboolean
evaluate_testcase(const gchar *msg,
                  FilterExprNode *filter_node)
{
  LogMessage *log_msg;
  gboolean result;

  assert_not_null(filter_node, "Constructing an in-list filter");
  log_msg = log_msg_new(msg, strlen(msg), NULL, &parse_options);
  result = filter_expr_eval(filter_node, log_msg);

  log_msg_unref(log_msg);
  filter_expr_unref(filter_node);
  return result;
}
gpointer
threaded_feed(gpointer args)
{
  LogQueue *q = args;
  char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: árvíztűrőtükörfúrógép";
  gint msg_len = strlen(msg_str);
  gint i;
  LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
  LogMessage *msg, *tmpl;
  GTimeVal start, end;
  GSockAddr *sa;
  glong diff;

  iv_init();
  
  /* emulate main loop for LogQueue */
  main_loop_worker_thread_start(NULL);

  sa = g_sockaddr_inet_new("10.10.10.10", 1010);
  tmpl = log_msg_new(msg_str, msg_len, sa, &parse_options);
  g_sockaddr_unref(sa);

  g_get_current_time(&start);
  for (i = 0; i < MESSAGES_PER_FEEDER; i++)
    {
      msg = log_msg_clone_cow(tmpl, &path_options);
      log_msg_add_ack(msg, &path_options);
      msg->ack_func = test_ack;

      log_queue_push_tail(q, msg, &path_options);
      
      if ((i & 0xFF) == 0)
        main_loop_worker_invoke_batch_callbacks();
    }
  main_loop_worker_invoke_batch_callbacks();
  g_get_current_time(&end);
  diff = g_time_val_diff(&end, &start);
  g_static_mutex_lock(&tlock);
  sum_time += diff;
  g_static_mutex_unlock(&tlock);
  log_msg_unref(tmpl);
  iv_deinit();
  main_loop_worker_thread_stop();
  return NULL;
}
Beispiel #14
0
void
stardate_assert(const gchar *msg_str, const int precision, const gchar *expected)
{

  LogMessage *logmsg = log_msg_new(msg_str, strlen(msg_str), NULL, &parse_options);

  char *template_command;
  int ret_val;
  if (precision == -1)
    ret_val = asprintf(&template_command, "$(stardate $UNIXTIME)");
  else
    ret_val = asprintf(&template_command, "$(stardate --digits %d $UNIXTIME)", precision);

  assert_false(ret_val == -1, "Memory allocation failed in asprintf.");
  assert_template_format_msg(template_command, expected, logmsg);
  free(template_command);

  log_msg_unref(logmsg);
}
void
test_value_pairs_walk_prefix_data(GlobalConfig *cfg)
{
  ValuePairs *vp;
  LogMessage *msg;
  const char* value = "value";

  log_template_options_init(&template_options, cfg);
  msg_format_options_init(&parse_options, cfg);

  vp = value_pairs_new();
  value_pairs_add_glob_pattern(vp, "root.*", TRUE);
  msg = log_msg_new("test", 4, NULL, &parse_options);

  log_msg_set_value_by_name(msg, "root.test.alma", value, strlen(value));
  log_msg_set_value_by_name(msg, "root.test.korte", value, strlen(value));

  value_pairs_walk(vp, test_vp_obj_start, test_vp_value, test_vp_obj_stop, msg, 0, LTZ_LOCAL, &template_options, NULL);
  value_pairs_unref(vp);
  log_msg_unref(msg);
};
Beispiel #16
0
LogMessage *
create_sample_message(void)
{
  LogMessage *msg;
  char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép";
  GSockAddr *saddr;

  saddr = g_sockaddr_inet_new("10.11.12.13", 1010);
  msg = log_msg_new(msg_str, strlen(msg_str), saddr, &parse_options);
  g_sockaddr_unref(saddr);
  log_msg_set_value_by_name(msg, "APP.VALUE", "value", -1);
  log_msg_set_value_by_name(msg, "APP.STRIP1", "     value", -1);
  log_msg_set_value_by_name(msg, "APP.STRIP2", "value     ", -1);
  log_msg_set_value_by_name(msg, "APP.STRIP3", "     value     ", -1);
  log_msg_set_value_by_name(msg, "APP.STRIP4", "value", -1);
  log_msg_set_value_by_name(msg, "APP.STRIP5", "", -1);
  log_msg_set_value_by_name(msg, "APP.QVALUE", "\"value\"", -1);
  log_msg_set_value_by_name(msg, ".unix.uid", "1000", -1);
  log_msg_set_value_by_name(msg, ".unix.gid", "1000", -1);
  log_msg_set_value_by_name(msg, ".unix.cmd", "command", -1);
  log_msg_set_value_by_name(msg, ".json.foo", "bar", -1);
  log_msg_set_value_by_name(msg, ".json.sub.value1", "subvalue1", -1);
  log_msg_set_value_by_name(msg, ".json.sub.value2", "subvalue2", -1);
  log_msg_set_value_by_name(msg, "escaping", "binary stuff follows \"\xad árvíztűrőtükörfúrógép", -1);
  log_msg_set_match(msg, 0, "whole-match", -1);
  log_msg_set_match(msg, 1, "first-match", -1);
  log_msg_set_tag_by_name(msg, "alma");
  log_msg_set_tag_by_name(msg, "korte");
  log_msg_clear_tag_by_name(msg, "narancs");
  log_msg_set_tag_by_name(msg, "citrom");
  msg->rcptid = 555;

  /* fix some externally or automatically defined values */
  log_msg_set_value(msg, LM_V_HOST_FROM, "kismacska", -1);
  msg->timestamps[LM_TS_RECVD].tv_sec = 1139684315;
  msg->timestamps[LM_TS_RECVD].tv_usec = 639000;
  msg->timestamps[LM_TS_RECVD].zone_offset = get_local_timezone_ofs(1139684315);

  return msg;
}
void
feed_some_messages(LogQueue **q, int n)
{
  LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
  LogMessage *msg;
  gint i;

  path_options.ack_needed = (*q)->use_backlog;
  for (i = 0; i < n; i++)
    {
      char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: árvíztűrőtükörfúrógép";
      GSockAddr *sa;

      sa = g_sockaddr_inet_new("10.10.10.10", 1010);
      msg = log_msg_new(msg_str, strlen(msg_str), sa, &parse_options);
      g_sockaddr_unref(sa);
      log_msg_add_ack(msg, &path_options);
      msg->ack_func = test_ack;
      log_queue_push_tail((*q), msg, &path_options);
      fed_messages++;
    }

}
Beispiel #18
0
int
testcase_match(const gchar *log, const gchar *pattern, gint matcher_flags, gboolean expected_result, LogMatcher *m)
{
  LogMessage *msg;
  gboolean result;
  gchar buf[1024];
  NVHandle nonasciiz = log_msg_get_value_handle("NON-ASCIIZ");
  gssize msglen;
  const gchar *value;
  GSockAddr *sa;

  sa = g_sockaddr_inet_new("10.10.10.10", 1010);
  msg = log_msg_new(log, strlen(log), sa, &parse_options);
  g_sockaddr_unref(sa);

  g_snprintf(buf, sizeof(buf), "%sAAAAAAAAAAAA", log_msg_get_value(msg, LM_V_MESSAGE, &msglen));
  log_msg_set_value(msg, log_msg_get_value_handle("MESSAGE2"), buf, -1);

  /* add a non-zero terminated indirect value which contains the whole message */
  log_msg_set_value_indirect(msg, nonasciiz, log_msg_get_value_handle("MESSAGE2"), 0, 0, msglen);
  log_matcher_set_flags(m, matcher_flags);

  log_matcher_compile(m, pattern);

  value = log_msg_get_value(msg, nonasciiz, &msglen);
  result = log_matcher_match(m, msg, nonasciiz, value, msglen);

  if (result != expected_result)
    {
      fprintf(stderr, "Testcase match failure. pattern=%s, result=%d, expected=%d\n", pattern, result, expected_result);
      exit(1);
    }

  log_matcher_unref(m);
  log_msg_unref(msg);
  return 0;
}
LogMessage *
init_msg(gchar *msg_string, gboolean use_syslog_protocol)
{
  LogMessage *msg;
  GSockAddr *sa;

  if (use_syslog_protocol)
    parse_options.flags |= LP_SYSLOG_PROTOCOL;
  else
    parse_options.flags &= ~LP_SYSLOG_PROTOCOL;
  sa = g_sockaddr_inet_new("10.10.10.10", 1010);
  msg = log_msg_new(msg_string, strlen(msg_string), sa, &parse_options);
  g_sockaddr_unref(sa);
  log_msg_set_value_by_name(msg, "APP.VALUE", "value", 5);
  log_msg_set_match(msg, 0, "whole-match", 11);
  log_msg_set_match(msg, 1, "first-match", 11);

  /* fix some externally or automatically defined values */
  log_msg_set_value(msg, LM_V_HOST_FROM, "kismacska", 9);
  msg->timestamps[LM_TS_RECVD].tv_sec = 1139684315;
  msg->timestamps[LM_TS_RECVD].tv_usec = 639000;
  msg->timestamps[LM_TS_RECVD].zone_offset = get_local_timezone_ofs(1139684315);
  return msg;
}
Beispiel #20
0
void
feed_some_messages(LogQueue **q, int n, gboolean flow_control)
{
  LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
  LogMessage *msg;
  gint i;

  path_options.flow_control = flow_control;
  for (i = 0; i < n; i++)
    {
      char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: árvíztűrőtükörfúrógép";

      msg = log_msg_new(msg_str, strlen(msg_str), g_sockaddr_inet_new("10.10.10.10", 1010), 0, NULL, -1, 0xFFFF);
      log_msg_add_ack(msg, &path_options);
      msg->ack_func = test_ack;
      if (!log_queue_push_tail((*q), msg, &path_options))
        {
          fprintf(stderr, "Queue unable to consume enough messages: %d\n", fed_messages);
          exit(1);
        }
      fed_messages++;
    }

}
Beispiel #21
0
static gboolean
log_reader_handle_line(LogReader *self, const guchar *line, gint length, GSockAddr *saddr)
{
  LogMessage *m;
  LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
  
  msg_debug("Incoming log entry", 
            evt_tag_printf("line", "%.*s", length, line),
            NULL);
  /* use the current time to get the time zone offset */
  m = log_msg_new((gchar *) line, length,
                  saddr,
                  &self->options->parse_options);

  log_msg_refcache_start_producer(m);
  if (!m->saddr && self->peer_addr)
    {
      m->saddr = g_sockaddr_ref(self->peer_addr);
    }

  log_pipe_queue(&self->super.super, m, &path_options);
  log_msg_refcache_stop();
  return log_source_free_to_send(&self->super);
}
Beispiel #22
0
int
testcase(gchar *msg,
         gint parse_flags, /* LP_NEW_PROTOCOL */
         gchar *bad_hostname_re,
         gint expected_pri,
         guint expected_version,
         unsigned long expected_stamps_sec,
         unsigned long expected_stamps_usec,
         unsigned long expected_stamps_ofs,
         const gchar *expected_host,
         const gchar *expected_msg,
         const gchar *expected_program,
         const gchar *expected_sd_str,
         const gchar *expected_process_id,
         const gchar *expected_message_id
         )
{
  LogMessage *logmsg, *cloned;
  time_t now;
  regex_t bad_hostname;
  GSockAddr *addr = g_sockaddr_inet_new("10.10.10.10", 1010);
  gchar logmsg_addr[256], cloned_addr[256];
  LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
  GString *sd_str = g_string_sized_new(0);

  if (bad_hostname_re)
    TEST_ASSERT(regcomp(&bad_hostname, bad_hostname_re, REG_NOSUB | REG_EXTENDED) == 0, "%d", 0, 0);

  parse_options.flags = parse_flags;
  parse_options.bad_hostname = &bad_hostname;
  logmsg = log_msg_new(msg, strlen(msg), addr, &parse_options);
  TEST_ASSERT(logmsg->pri == expected_pri, "%d", logmsg->pri, expected_pri);
  if (expected_stamps_sec)
    {
      if (expected_stamps_sec != 1)
        {
            TEST_ASSERT(logmsg->timestamps[LM_TS_STAMP].time.tv_sec == expected_stamps_sec, "%d", (int) logmsg->timestamps[LM_TS_STAMP].time.tv_sec, (int) expected_stamps_sec);
          }
        TEST_ASSERT(logmsg->timestamps[LM_TS_STAMP].time.tv_usec == expected_stamps_usec, "%d", (int) logmsg->timestamps[LM_TS_STAMP].time.tv_usec, (int) expected_stamps_usec);
        TEST_ASSERT(logmsg->timestamps[LM_TS_STAMP].zone_offset == expected_stamps_ofs, "%d", (int) logmsg->timestamps[LM_TS_STAMP].zone_offset, (int) expected_stamps_ofs);
    }
  else
    {
      time(&now);
      TEST_ASSERT(absolute_value(logmsg->timestamps[LM_TS_STAMP].time.tv_sec - now) < 1, "%d", 0, 0);
    }
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_HOST, NULL), expected_host) == 0, "%s", log_msg_get_value(logmsg, LM_V_HOST, NULL), expected_host);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_PROGRAM, NULL), expected_program) == 0, "%s", log_msg_get_value(logmsg, LM_V_PROGRAM, NULL), expected_program);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_MESSAGE, NULL), expected_msg) == 0, "%s", log_msg_get_value(logmsg, LM_V_MESSAGE, NULL), expected_msg);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_PID, NULL), expected_process_id) == 0, "%s", log_msg_get_value(logmsg, LM_V_PID, NULL), expected_process_id);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_MSGID, NULL), expected_message_id) == 0, "%s", log_msg_get_value(logmsg, LM_V_MSGID, NULL), expected_message_id);

  /* SD elements */
  log_msg_format_sdata(logmsg, sd_str);
  TEST_ASSERT(strcmp(sd_str->str, expected_sd_str) == 0, "%s", sd_str->str, expected_sd_str);

  /* check if the sockaddr matches */
  g_sockaddr_format(logmsg->saddr, logmsg_addr, sizeof(logmsg_addr), GSA_FULL);

  path_options.flow_control = FALSE;
  cloned = log_msg_clone_cow(logmsg, &path_options);

  g_sockaddr_format(cloned->saddr, cloned_addr, sizeof(cloned_addr), GSA_FULL);
  TEST_ASSERT(strcmp(logmsg_addr, cloned_addr) == 0, "%s", cloned_addr, logmsg_addr);

  TEST_ASSERT(logmsg->pri == cloned->pri, "%d", logmsg->pri, cloned->pri);
  TEST_ASSERT(logmsg->timestamps[LM_TS_STAMP].time.tv_sec == cloned->timestamps[LM_TS_STAMP].time.tv_sec, "%d", (int) logmsg->timestamps[LM_TS_STAMP].time.tv_sec, (int) cloned->timestamps[LM_TS_STAMP].time.tv_sec);
  TEST_ASSERT(logmsg->timestamps[LM_TS_STAMP].time.tv_usec == cloned->timestamps[LM_TS_STAMP].time.tv_usec, "%d", (int) logmsg->timestamps[LM_TS_STAMP].time.tv_usec, (int) cloned->timestamps[LM_TS_STAMP].time.tv_usec);
  TEST_ASSERT(logmsg->timestamps[LM_TS_STAMP].zone_offset == cloned->timestamps[LM_TS_STAMP].zone_offset, "%d", (int) logmsg->timestamps[LM_TS_STAMP].zone_offset, (int) cloned->timestamps[LM_TS_STAMP].zone_offset);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_HOST, NULL), log_msg_get_value(cloned, LM_V_HOST, NULL)) == 0, "%s", log_msg_get_value(logmsg, LM_V_HOST, NULL), log_msg_get_value(cloned, LM_V_HOST, NULL));
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_PROGRAM, NULL), log_msg_get_value(cloned, LM_V_PROGRAM, NULL)) == 0, "%s", log_msg_get_value(logmsg, LM_V_PROGRAM, NULL), log_msg_get_value(cloned, LM_V_PROGRAM, NULL));
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_MESSAGE, NULL), log_msg_get_value(cloned, LM_V_MESSAGE, NULL)) == 0, "%s", log_msg_get_value(logmsg, LM_V_MESSAGE, NULL), log_msg_get_value(cloned, LM_V_MESSAGE, NULL));
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_PID, NULL), log_msg_get_value(cloned, LM_V_PID, NULL)) == 0, "%s", log_msg_get_value(logmsg, LM_V_PID, NULL), log_msg_get_value(cloned, LM_V_PID, NULL));
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_MSGID, NULL), log_msg_get_value(cloned, LM_V_MSGID, NULL)) == 0, "%s", log_msg_get_value(logmsg, LM_V_MSGID, NULL), log_msg_get_value(cloned, LM_V_MSGID, NULL));

  /* SD elements */
  log_msg_format_sdata(cloned, sd_str);
  TEST_ASSERT(strcmp(sd_str->str, expected_sd_str) == 0, "%s", sd_str->str, expected_sd_str);


  log_msg_set_value(cloned, LM_V_HOST, "newhost", -1);
  log_msg_set_value(cloned, LM_V_HOST_FROM, "newhost", -1);
  log_msg_set_value(cloned, LM_V_MESSAGE, "newmsg", -1);
  log_msg_set_value(cloned, LM_V_PROGRAM, "newprogram", -1);
  log_msg_set_value(cloned, LM_V_PID, "newpid", -1);
  log_msg_set_value(cloned, LM_V_MSGID, "newmsgid", -1);
  log_msg_set_value(cloned, LM_V_SOURCE, "newsource", -1);
  log_msg_set_value(cloned, log_msg_get_value_handle("newvalue"), "newvalue", -1);

  /* retest values in original logmsg */

  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_HOST, NULL), expected_host) == 0, "%s", log_msg_get_value(logmsg, LM_V_HOST, NULL), expected_host);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_PROGRAM, NULL), expected_program) == 0, "%s", log_msg_get_value(logmsg, LM_V_PROGRAM, NULL), expected_program);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_MESSAGE, NULL), expected_msg) == 0, "%s", log_msg_get_value(logmsg, LM_V_MESSAGE, NULL), expected_msg);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_PID, NULL), expected_process_id) == 0, "%s", log_msg_get_value(logmsg, LM_V_PID, NULL), expected_process_id);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_MSGID, NULL), expected_message_id) == 0, "%s", log_msg_get_value(logmsg, LM_V_MSGID, NULL), expected_message_id);
  TEST_ASSERT(strcmp(log_msg_get_value(logmsg, LM_V_SOURCE, NULL), "") == 0, "%s", log_msg_get_value(logmsg, LM_V_SOURCE, NULL), "");

  /* check newly set values in cloned */

  TEST_ASSERT(strcmp(log_msg_get_value(cloned, LM_V_HOST, NULL), "newhost") == 0, "%s", log_msg_get_value(cloned, LM_V_HOST, NULL), "newhost");
  TEST_ASSERT(strcmp(log_msg_get_value(cloned, LM_V_HOST_FROM, NULL), "newhost") == 0, "%s", log_msg_get_value(cloned, LM_V_HOST_FROM, NULL), "newhost");
  TEST_ASSERT(strcmp(log_msg_get_value(cloned, LM_V_PROGRAM, NULL), "newprogram") == 0, "%s", log_msg_get_value(cloned, LM_V_PROGRAM, NULL), "newprogram");
  TEST_ASSERT(strcmp(log_msg_get_value(cloned, LM_V_MESSAGE, NULL), "newmsg") == 0, "%s", log_msg_get_value(cloned, LM_V_MESSAGE, NULL), "newmsg");
  TEST_ASSERT(strcmp(log_msg_get_value(cloned, LM_V_PID, NULL), "newpid") == 0, "%s", log_msg_get_value(cloned, LM_V_PID, NULL), "newpid");
  TEST_ASSERT(strcmp(log_msg_get_value(cloned, LM_V_MSGID, NULL), "newmsgid") == 0, "%s", log_msg_get_value(cloned, LM_V_MSGID, NULL), "newmsgid");
  TEST_ASSERT(strcmp(log_msg_get_value(cloned, LM_V_SOURCE, NULL), "newsource") == 0, "%s", log_msg_get_value(cloned, LM_V_SOURCE, NULL), "newsource");

  log_msg_unref(cloned);
  log_msg_unref(logmsg);
  g_string_free(sd_str, TRUE);
  return 0;
}
int
testcase(gchar *msg, guint parse_flags, gint max_columns, guint32 flags, gchar *delimiters, gchar *quotes, gchar *null_value, gchar *first_value, ...)
{
  LogMessage *logmsg;
  LogColumnParser *p;
  gchar *expected_value;
  gint i;
  va_list va;
  NVTable *nvtable;

  const gchar *column_array[] =
  {
    "C1",
    "C2",
    "C3",
    "C4",
    "C5",
    "C6",
    "C7",
    "C8",
    "C9",
    "C10",
    "C11",
    "C12",
    "C13",
    "C14",
    "C15",
    "C16",
    "C17",
    "C18",
    "C19",
    "C20",
    "C21",
    "C22",
    "C23",
    "C24",
    "C25",
    "C26",
    "C27",
    "C28",
    "C29",
    "C30",
    NULL
  };
  gboolean success;

  if (max_columns != -1)
    {
      g_assert(max_columns < (sizeof(column_array) / sizeof(column_array[0])));

      column_array[max_columns] = NULL;
    }

  parse_options.flags = parse_flags;
  logmsg = log_msg_new(msg, strlen(msg), NULL, &parse_options);

  p = log_csv_parser_new();
  log_csv_parser_set_flags(p, flags);
  log_column_parser_set_columns(p, string_array_to_list(column_array));
  if (delimiters)
    log_csv_parser_set_delimiters(p, delimiters);
  if (quotes)
    log_csv_parser_set_quote_pairs(p, quotes);
  if (null_value)
    log_csv_parser_set_null_value(p, null_value);

  nvtable = nv_table_ref(logmsg->payload);
  success = log_parser_process(&p->super, &logmsg, NULL, log_msg_get_value(logmsg, LM_V_MESSAGE, NULL), -1);
  nv_table_unref(nvtable);

  if (success && !first_value)
    {
      fprintf(stderr, "unexpected match; msg=%s\n", msg);
      exit(1);
    }
  if (!success && first_value)
    {
      fprintf(stderr, "unexpected non-match; msg=%s\n", msg);
      exit(1);
    }
  log_pipe_unref(&p->super.super);

  va_start(va, first_value);
  expected_value = first_value;
  i = 0;
  while (expected_value && column_array[i])
    {
      const gchar *value;
      gssize value_len;

      value = log_msg_get_value(logmsg, log_msg_get_value_handle(column_array[i]), &value_len);

      if (expected_value && expected_value[0])
        {
          TEST_ASSERT(value && value[0], "expected value set, but no actual value");
          TEST_ASSERT(strlen(expected_value) == value_len, "value length doesn't match actual length");
          TEST_ASSERT(strncmp(value, expected_value, value_len) == 0, "value does not match expected value");
        }
      else
        {
          TEST_ASSERT(!(value && value[0]), "expected unset, but actual value present");
        }

      expected_value = va_arg(va, char *);
      i++;
    }

  log_msg_unref(logmsg);
  return 1;
}