]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
replay file.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 9 Feb 2007 13:46:11 +0000 (13:46 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 9 Feb 2007 13:46:11 +0000 (13:46 +0000)
git-svn-id: file:///svn/unbound/trunk@85 be551aaa-1e26-0410-a405-d3ace91eadb9

configure.ac
doc/Changelog
testcode/replay.c
testcode/replay.h
testcode/testbound.c

index f8d48d292396709c6ee896abf58658088c7d1b58..ae44ee5d6fd135d273459c2a82ad3d294781748e 100644 (file)
@@ -360,7 +360,12 @@ AC_CHECK_FUNCS([event_base_free]) # only in libevent 1.2 and later
 AC_CHECK_LIB(socket, socket)
 AC_CHECK_LIB(nsl, inet_pton)
 
+AC_FUNC_CHOWN
+AC_FUNC_FORK
 AC_FUNC_MALLOC
+AC_TYPE_SIGNAL
+AC_FUNC_FSEEKO
+AC_SYS_LARGEFILE
 
 #AC_REPLACE_FUNCS(snprintf)
 #AC_REPLACE_FUNCS(strlcpy)
@@ -434,6 +439,10 @@ AH_BOTTOM([
 #else /* !HAVE_ATTR_UNUSED */
 #  define ATTR_UNUSED(x)  x
 #endif /* !HAVE_ATTR_UNUSED */
+#ifndef HAVE_FSEEKO
+#define fseeko fseek
+#define ftello ftell
+#endif /* HAVE_FSEEKO */
 
 #include "ldns/ldns.h"
 
index 607b61c7f6cd0e7bed7e92087c32b38a583d24a7..1036ec3e5a02ebda1eb77291844e64f707459d04 100644 (file)
@@ -1,3 +1,6 @@
+9 February 2007: Wouter
+       - replay file reading.
+
 8 February 2007: Wouter
        - added tcp test.
        - replay storage.
index 3eb5fc4fbceb88e5239debdfccc0f78128da57c9..82c304edf9aace4d3e1e273b50c2dd211a6ea162 100644 (file)
  */
 
 #include "config.h"
+#include "util/log.h"
 #include "testcode/replay.h"
+#include "testcode/ldns-testpkts.h"
+
+/** max length of lines in file */
+#define MAX_LINE_LEN 10240
+
+/** parse keyword in string. true if found, false if not.
+ * if found, the line is advanced to after the keyword. */
+static int parse_keyword(char** line, char* keyword)
+{
+       size_t len = (size_t)strlen(keyword);
+       if(strncmp(*line, keyword, len) == 0) {
+               *line += len;
+               return 1;
+       }
+       return 0;
+}
+
+/** delete moment */
+static void
+replay_moment_delete(struct replay_moment* mom)
+{
+       if(!mom)
+               return;
+       if(mom->match) {
+               delete_entry(mom->match);
+       }
+       free(mom);
+}
+
+/** delete range */
+static void
+replay_range_delete(struct replay_range* rng)
+{
+       if(!rng)
+               return;
+       delete_entry(rng->match);
+       free(rng);
+}
+
+/** 
+ * Read a range from file. 
+ * @param remain: Rest of line (after RANGE keyword).
+ * @param in: file to read from.
+ * @param lineno: incremented as lines are read.
+ * @param line: line buffer.
+ * @param ttl: for readentry
+ * @param or: for readentry
+ * @param prev: for readentry
+ * @return: range object to add to list, or NULL on error.
+ */
+static struct replay_range*
+replay_range_read(char* remain, FILE* in, int* lineno, char* line,
+       uint16_t* ttl, ldns_rdf** or, ldns_rdf** prev)
+{
+       struct replay_range* rng = (struct replay_range*)malloc(
+               sizeof(struct replay_range));
+       off_t pos;
+       char *parse;
+       struct entry* entry;
+       if(!rng)
+               return NULL;
+       memset(rng, 0, sizeof(*rng));
+       /* read time range */
+       if(sscanf(remain, " %d %d", &rng->start_step, &rng->end_step)!=2) {
+               log_err("Could not read time range: %s", line);
+               free(rng);
+               return NULL;
+       }
+       /* read entries */
+       pos = ftello(in);
+       while(fgets(line, MAX_LINE_LEN-1, in)) {
+               (*lineno)++;
+               parse = line;
+               while(isspace(*parse))
+                       parse++;
+               if(!*parse || *parse == ';')
+                       continue;
+               if(parse_keyword(&parse, "RANGE_END")) {
+                       return rng;
+               }
+               /* set position before line; read entry */
+               (*lineno)--;
+               fseeko(in, pos, SEEK_SET);
+               entry = read_entry(in, "datafile", lineno, ttl, or, prev);
+               if(!entry)
+                       fatal_exit("%d: bad entry", *lineno);
+               entry->next = rng->match;
+               rng->match = entry;
+
+               pos = ftello(in);
+       }
+       replay_range_delete(rng);
+       return NULL;
+}
+
+/** 
+ * Read a replay moment 'STEP' from file. 
+ * @param remain: Rest of line (after STEP keyword).
+ * @param in: file to read from.
+ * @param lineno: incremented as lines are read.
+ * @param ttl: for readentry
+ * @param or: for readentry
+ * @param prev: for readentry
+ * @return: range object to add to list, or NULL on error.
+ */
+static struct replay_moment*
+replay_moment_read(char* remain, FILE* in, int* lineno, 
+       uint16_t* ttl, ldns_rdf** or, ldns_rdf** prev)
+{
+       struct replay_moment* mom = (struct replay_moment*)malloc(
+               sizeof(struct replay_moment));
+       int skip = 0;
+       int readentry = 0;
+       if(!mom)
+               return NULL;
+       memset(mom, 0, sizeof(*mom));
+       if(sscanf(remain, " %d%n", &mom->time_step, &skip) != 1) {
+               log_err("%d: cannot read value: %s", *lineno, remain);
+               free(mom);
+               return NULL;
+       }
+       remain += skip;
+       while(isspace(*remain))
+               remain++;
+       if(parse_keyword(&remain, "NOTHING")) {
+               mom->evt_type = repevt_nothing;
+       } else if(parse_keyword(&remain, "QUERY")) {
+               mom->evt_type = repevt_front_query;
+               readentry = 1;
+       } else if(parse_keyword(&remain, "CHECK_ANSWER")) {
+               mom->evt_type = repevt_front_reply;
+               readentry = 1;
+       } else if(parse_keyword(&remain, "CHECK_OUT_QUERY")) {
+               mom->evt_type = repevt_back_query;
+               readentry = 1;
+       } else if(parse_keyword(&remain, "REPLY")) {
+               mom->evt_type = repevt_back_reply;
+               readentry = 1;
+       } else if(parse_keyword(&remain, "TIMEOUT")) {
+               mom->evt_type = repevt_timeout;
+       } else if(parse_keyword(&remain, "ERROR")) {
+               mom->evt_type = repevt_back_query;
+       } else {
+               log_err("%d: unknown event type %s", *lineno, remain);
+               free(mom);
+               return NULL;
+       }
+
+       if(readentry) {
+               mom->match = read_entry(in, "datafile", lineno, ttl, or, prev);
+               free(mom);
+               if(!mom->match)
+                       return NULL;
+       }
+
+       return mom;
+}
+
+/** makes scenario with title on rest of line. */
+static struct replay_scenario*
+make_scenario(char* line)
+{
+       struct replay_scenario* scen;
+       while(isspace(*line))
+               line++;
+       if(!*line) {
+               log_err("scenario: no title given");
+               return NULL;
+       }
+       scen = (struct replay_scenario*)malloc(sizeof(struct replay_scenario));
+       if(!scen)
+               return NULL;
+       memset(scen, 0, sizeof(*scen));
+       scen->title = strdup(line);
+       if(!scen->title) {
+               free(scen);
+               return NULL;
+       }
+       return scen;
+}
+
 struct replay_scenario* 
 replay_scenario_read(FILE* in)
 {
+       char line[MAX_LINE_LEN];
+       char *parse;
+       int lineno = 0;
+       struct replay_scenario* scen = NULL;
+       uint16_t ttl = 3600;
+       ldns_rdf* or = NULL;
+       ldns_rdf* prev = NULL;
+       line[MAX_LINE_LEN-1]=0;
+
+       while(fgets(line, sizeof(line)-1, in)) {
+               parse=line;
+               lineno++;
+               while(isspace(*parse))
+                       parse++;
+               if(!*parse) 
+                       continue; /* empty line */
+               if(parse_keyword(&parse, ";"))
+                       continue; /* comment */
+               if(parse_keyword(&parse, "SCENARIO_BEGIN")) {
+                       scen = make_scenario(parse);
+                       if(!scen)
+                               fatal_exit("%d: could not make scen", lineno);
+                       continue;
+               } 
+               if(!scen)
+                       fatal_exit("%d: expected SCENARIO", lineno);
+               if(parse_keyword(&parse, "RANGE_BEGIN")) {
+                       struct replay_range* newr = replay_range_read(
+                               parse, in, &lineno, line, &ttl, &or, &prev);
+                       if(!newr)
+                               fatal_exit("%d: bad range", lineno);
+                       newr->next_range = scen->range_list;
+                       scen->range_list = newr;
+               } else if(parse_keyword(&parse, "STEP")) {
+                       struct replay_moment* mom = replay_moment_read(
+                               parse, in, &lineno, &ttl, &or, &prev);
+                       if(!mom)
+                               fatal_exit("%d: bad moment", lineno);
+                       if(scen->mom_last)
+                               scen->mom_last->mom_next = mom;
+                       else    scen->mom_first = mom;
+                       scen->mom_last = mom;
+               } else if(parse_keyword(&parse, "SCENARIO_END")) {
+                       return scen;
+               }
+       }
+       replay_scenario_delete(scen);
        return NULL;
 }
 
 void 
 replay_scenario_delete(struct replay_scenario* scen)
 {
+       struct replay_moment* mom, *momn;
+       struct replay_range* rng, *rngn;
+       if(!scen)
+               return;
+       if(scen->title)
+               free(scen->title);
+       mom = scen->mom_first;
+       while(mom) {
+               momn = mom->mom_next;
+               replay_moment_delete(mom);
+               mom = momn;
+       }
+       rng = scen->range_list;
+       while(rng) {
+               rngn = rng->next_range;
+               replay_range_delete(rng);
+               rng = rngn;
+       }
+       free(scen);
 }
index 79eaf77c62c6775c1061112c17946875842b349c..9694266e8cc3f3ec65d664c9c2553350fb1a043a 100644 (file)
  * File format for replay files.
  *
  * ; comment line.
- * SCENARIO_BEGIN 
- * TITLE name_of_scenario
- * RANGE start_time end_time
+ * SCENARIO_BEGIN name_of_scenario
+ * RANGE_BEGIN start_time end_time
  *    match_entries
- * END_RANGE
+ * RANGE_END
  * ; more RANGE items.
  * ; go to the next moment
  * STEP time_step event_type
@@ -63,9 +62,8 @@
  *
  *
  * ; Example file
- * SCENARIO_BEGIN
- * TITLE Example scenario
- * RANGE 0 100
+ * SCENARIO_BEGIN Example scenario
+ * RANGE_BEGIN 0 100
  *   ENTRY_BEGIN
  *   ; precoded answers to queries.
  *   ENTRY_END
@@ -105,7 +103,7 @@ struct entry;
  */
 struct replay_scenario {
        /** name of replay scenario. malloced string. */
-       const char* title;
+       char* title;
 
        /** The list of replay moments. Linked list. Time increases in list. */
        struct replay_moment* mom_first;
@@ -133,7 +131,7 @@ struct replay_moment {
         * The replay time step number. Starts at 0, time is incremented 
         * every time the fake select() is run. 
         */
-       size_t time_step;
+       int time_step;
        /** Next replay moment in list of replay moments. */
        struct replay_moment* mom_next;
 
@@ -152,7 +150,7 @@ struct replay_moment {
                /** test fails if query to the network does not match */
                repevt_back_query,
                /** an error happens to outbound query */
-               repevt_error,
+               repevt_error
        } evt_type;
 
        /** The sent packet must match this. Incoming events, the data. */
@@ -168,9 +166,9 @@ struct replay_moment {
  */
 struct replay_range {
        /** time range when this is valid. Including start and end step. */
-       size_t start_step;
+       int start_step;
        /** end step of time range. */
-       size_t end_step;
+       int end_step;
 
        /** Matching list */
        struct entry* match;
index 3348717fd96ba03bf0a2481e4e37558ba249acc8..2d276b09dae74e811ffd736d028b1997652c1549 100644 (file)
@@ -39,7 +39,8 @@
  */
 
 #include "config.h"
-#include "ldns-testpkts.h"
+#include "testcode/ldns-testpkts.h"
+#include "testcode/replay.h"
 
 /** 
  * include the main program from the unbound daemon.
@@ -116,6 +117,27 @@ echo_cmdline(int argc, char* argv[])
        }
        printf("\n");
 }
+
+/** read playback file */
+static struct replay_scenario* 
+setup_playback(const char* filename)
+{
+       struct replay_scenario* scen = NULL;
+       if(filename) {
+               FILE *in = fopen(filename, "r");
+               if(!in) {
+                       perror(filename);
+                       exit(1);
+               }
+               scen = replay_scenario_read(in);
+               fclose(in);
+               if(!scen)
+                       fatal_exit("Could not read: %s", filename);
+       }
+       else fatal_exit("need a playback file (-p)");
+       printf("Scenario: %s\n", scen->title);
+       return scen;
+}
        
 /**
  * Main unit test program. Setup, teardown and report errors.
@@ -131,7 +153,7 @@ main(int argc, char* argv[])
        char* playback_file = NULL;
        int init_optind = optind;
        char* init_optarg = optarg;
-       struct entry* matched_answers = NULL;
+       struct replay_scenario* scen = NULL;
 
        printf("Start of %s testbound program.\n", PACKAGE_STRING);
        /* determine commandline options for the daemon */
@@ -160,8 +182,7 @@ main(int argc, char* argv[])
        }
 
        /* setup test environment */
-       if(playback_file)
-               matched_answers = read_datafile(playback_file);
+       scen = setup_playback(playback_file);
        /* init fake event backend */
 
        pass_argv[pass_argc] = NULL;
@@ -174,6 +195,7 @@ main(int argc, char* argv[])
        /* run the normal daemon */
        res = daemon_main(pass_argc, pass_argv);
 
+       replay_scenario_delete(scen);
        for(c=1; c<pass_argc; c++)
                free(pass_argv[c]);
        return res;