replay file.

git-svn-id: file:///svn/unbound/trunk@85 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-02-09 13:46:11 +00:00
parent f6561f2f00
commit 2ebbe7e9d5
5 changed files with 296 additions and 16 deletions

View 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(socket, socket)
AC_CHECK_LIB(nsl, inet_pton) AC_CHECK_LIB(nsl, inet_pton)
AC_FUNC_CHOWN
AC_FUNC_FORK
AC_FUNC_MALLOC AC_FUNC_MALLOC
AC_TYPE_SIGNAL
AC_FUNC_FSEEKO
AC_SYS_LARGEFILE
#AC_REPLACE_FUNCS(snprintf) #AC_REPLACE_FUNCS(snprintf)
#AC_REPLACE_FUNCS(strlcpy) #AC_REPLACE_FUNCS(strlcpy)
@ -434,6 +439,10 @@ AH_BOTTOM([
#else /* !HAVE_ATTR_UNUSED */ #else /* !HAVE_ATTR_UNUSED */
# define ATTR_UNUSED(x) x # define ATTR_UNUSED(x) x
#endif /* !HAVE_ATTR_UNUSED */ #endif /* !HAVE_ATTR_UNUSED */
#ifndef HAVE_FSEEKO
#define fseeko fseek
#define ftello ftell
#endif /* HAVE_FSEEKO */
#include "ldns/ldns.h" #include "ldns/ldns.h"

View file

@ -1,3 +1,6 @@
9 February 2007: Wouter
- replay file reading.
8 February 2007: Wouter 8 February 2007: Wouter
- added tcp test. - added tcp test.
- replay storage. - replay storage.

View file

@ -40,14 +40,262 @@
*/ */
#include "config.h" #include "config.h"
#include "util/log.h"
#include "testcode/replay.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* struct replay_scenario*
replay_scenario_read(FILE* in) 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; return NULL;
} }
void void
replay_scenario_delete(struct replay_scenario* scen) 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);
} }

View file

@ -42,11 +42,10 @@
* File format for replay files. * File format for replay files.
* *
* ; comment line. * ; comment line.
* SCENARIO_BEGIN * SCENARIO_BEGIN name_of_scenario
* TITLE name_of_scenario * RANGE_BEGIN start_time end_time
* RANGE start_time end_time
* match_entries * match_entries
* END_RANGE * RANGE_END
* ; more RANGE items. * ; more RANGE items.
* ; go to the next moment * ; go to the next moment
* STEP time_step event_type * STEP time_step event_type
@ -63,9 +62,8 @@
* *
* *
* ; Example file * ; Example file
* SCENARIO_BEGIN * SCENARIO_BEGIN Example scenario
* TITLE Example scenario * RANGE_BEGIN 0 100
* RANGE 0 100
* ENTRY_BEGIN * ENTRY_BEGIN
* ; precoded answers to queries. * ; precoded answers to queries.
* ENTRY_END * ENTRY_END
@ -105,7 +103,7 @@ struct entry;
*/ */
struct replay_scenario { struct replay_scenario {
/** name of replay scenario. malloced string. */ /** name of replay scenario. malloced string. */
const char* title; char* title;
/** The list of replay moments. Linked list. Time increases in list. */ /** The list of replay moments. Linked list. Time increases in list. */
struct replay_moment* mom_first; struct replay_moment* mom_first;
@ -133,7 +131,7 @@ struct replay_moment {
* The replay time step number. Starts at 0, time is incremented * The replay time step number. Starts at 0, time is incremented
* every time the fake select() is run. * every time the fake select() is run.
*/ */
size_t time_step; int time_step;
/** Next replay moment in list of replay moments. */ /** Next replay moment in list of replay moments. */
struct replay_moment* mom_next; struct replay_moment* mom_next;
@ -152,7 +150,7 @@ struct replay_moment {
/** test fails if query to the network does not match */ /** test fails if query to the network does not match */
repevt_back_query, repevt_back_query,
/** an error happens to outbound query */ /** an error happens to outbound query */
repevt_error, repevt_error
} evt_type; } evt_type;
/** The sent packet must match this. Incoming events, the data. */ /** The sent packet must match this. Incoming events, the data. */
@ -168,9 +166,9 @@ struct replay_moment {
*/ */
struct replay_range { struct replay_range {
/** time range when this is valid. Including start and end step. */ /** time range when this is valid. Including start and end step. */
size_t start_step; int start_step;
/** end step of time range. */ /** end step of time range. */
size_t end_step; int end_step;
/** Matching list */ /** Matching list */
struct entry* match; struct entry* match;

View file

@ -39,7 +39,8 @@
*/ */
#include "config.h" #include "config.h"
#include "ldns-testpkts.h" #include "testcode/ldns-testpkts.h"
#include "testcode/replay.h"
/** /**
* include the main program from the unbound daemon. * include the main program from the unbound daemon.
@ -116,6 +117,27 @@ echo_cmdline(int argc, char* argv[])
} }
printf("\n"); 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. * Main unit test program. Setup, teardown and report errors.
@ -131,7 +153,7 @@ main(int argc, char* argv[])
char* playback_file = NULL; char* playback_file = NULL;
int init_optind = optind; int init_optind = optind;
char* init_optarg = optarg; char* init_optarg = optarg;
struct entry* matched_answers = NULL; struct replay_scenario* scen = NULL;
printf("Start of %s testbound program.\n", PACKAGE_STRING); printf("Start of %s testbound program.\n", PACKAGE_STRING);
/* determine commandline options for the daemon */ /* determine commandline options for the daemon */
@ -160,8 +182,7 @@ main(int argc, char* argv[])
} }
/* setup test environment */ /* setup test environment */
if(playback_file) scen = setup_playback(playback_file);
matched_answers = read_datafile(playback_file);
/* init fake event backend */ /* init fake event backend */
pass_argv[pass_argc] = NULL; pass_argv[pass_argc] = NULL;
@ -174,6 +195,7 @@ main(int argc, char* argv[])
/* run the normal daemon */ /* run the normal daemon */
res = daemon_main(pass_argc, pass_argv); res = daemon_main(pass_argc, pass_argv);
replay_scenario_delete(scen);
for(c=1; c<pass_argc; c++) for(c=1; c<pass_argc; c++)
free(pass_argv[c]); free(pass_argv[c]);
return res; return res;