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(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"

View file

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

View file

@ -40,14 +40,262 @@
*/
#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);
}

View file

@ -42,11 +42,10 @@
* 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;

View 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.
@ -117,6 +118,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.
* @param argc: arg count.
@ -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;