27 March 2007: Wouter
- added test for cache and not cached answers, in testbound replays.
+ - testbound can give config file and commandline options from the
+ replay file to unbound.
+ - created test that checks if items drop out of the cache.
26 March 2007: Wouter
- config settings for slab hash message cache.
}
struct replay_scenario*
-replay_scenario_read(FILE* in, const char* name)
+replay_scenario_read(FILE* in, const char* name, int* lineno)
{
char line[MAX_LINE_LEN];
char *parse;
- int lineno = 0;
struct replay_scenario* scen = NULL;
uint16_t ttl = 3600;
ldns_rdf* or = NULL;
while(fgets(line, MAX_LINE_LEN-1, in)) {
parse=line;
- lineno++;
+ (*lineno)++;
while(isspace(*parse))
parse++;
if(!*parse)
if(parse_keyword(&parse, "SCENARIO_BEGIN")) {
scen = make_scenario(parse);
if(!scen)
- fatal_exit("%d: could not make scen", lineno);
+ fatal_exit("%d: could not make scen", *lineno);
continue;
}
if(!scen)
- fatal_exit("%d: expected SCENARIO", lineno);
+ fatal_exit("%d: expected SCENARIO", *lineno);
if(parse_keyword(&parse, "RANGE_BEGIN")) {
struct replay_range* newr = replay_range_read(parse,
- in, name, &lineno, line, &ttl, &or, &prev);
+ in, name, lineno, line, &ttl, &or, &prev);
if(!newr)
- fatal_exit("%d: bad range", lineno);
+ 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, name, &lineno, &ttl, &or, &prev);
+ in, name, lineno, &ttl, &or, &prev);
if(!mom)
- fatal_exit("%d: bad moment", lineno);
+ fatal_exit("%d: bad moment", *lineno);
if(scen->mom_last &&
scen->mom_last->time_step >= mom->time_step)
- fatal_exit("%d: time goes backwards", lineno);
+ fatal_exit("%d: time goes backwards", *lineno);
if(scen->mom_last)
scen->mom_last->mom_next = mom;
else scen->mom_first = mom;
* Read a replay scenario from the file.
* @param in: file to read from.
* @param name: name to print in errors.
+ * @param lineno: incremented for every line read.
* @return: Scenario. NULL if no scenario read.
*/
-struct replay_scenario* replay_scenario_read(FILE* in, const char* name);
+struct replay_scenario* replay_scenario_read(FILE* in, const char* name,
+ int* lineno);
/**
* Delete scenario.
#include "daemon/unbound.c"
#undef main
+/** maximum line length for lines in the replay file. */
+#define MAX_LINE_LEN 1024
+
/** give commandline usage for testbound. */
static void
testbound_usage()
echo_cmdline(int argc, char* argv[])
{
int i;
- printf("testbound is starting:");
+ fprintf(stderr, "testbound is starting:");
for(i=0; i<argc; i++) {
- printf(" [%s]", argv[i]);
+ fprintf(stderr, " [%s]", argv[i]);
+ }
+ fprintf(stderr, "\n");
+}
+
+/** process config elements */
+static void
+setup_config(FILE* in, char* configfile, int* lineno,
+ int* pass_argc, char* pass_argv[])
+{
+ char line[MAX_LINE_LEN];
+ char* parse;
+ FILE* cfg;
+ sprintf(configfile, "/tmp/testbound_cfg_%u.tmp", (unsigned)getpid());
+ add_opts("-c", pass_argc, pass_argv);
+ add_opts(configfile, pass_argc, pass_argv);
+ cfg = fopen(configfile, "w");
+ if(!cfg) fatal_exit("could not open %s: %s",
+ configfile, strerror(errno));
+ line[MAX_LINE_LEN-1] = 0;
+ while(fgets(line, MAX_LINE_LEN-1, in)) {
+ parse = line;
+ (*lineno)++;
+ while(isspace(*parse))
+ parse++;
+ if(!*parse || parse[0] == ';')
+ continue;
+ if(strncmp(parse, "COMMANDLINE", 11) == 0) {
+ parse[strlen(parse)-1] = 0; /* strip off \n */
+ add_opts(parse+11, pass_argc, pass_argv);
+ continue;
+ }
+ if(strncmp(parse, "CONFIG_END", 10) == 0) {
+ fclose(cfg);
+ return;
+ }
+ fputs(line, cfg);
}
- printf("\n");
+ fatal_exit("No CONFIG_END in input file");
+
}
/** read playback file */
static struct replay_scenario*
-setup_playback(const char* filename)
+setup_playback(const char* filename, char* configfile,
+ int* pass_argc, char* pass_argv[])
{
struct replay_scenario* scen = NULL;
+ int lineno = 0;
+
if(filename) {
FILE *in = fopen(filename, "r");
if(!in) {
perror(filename);
exit(1);
}
- scen = replay_scenario_read(in, filename);
+ setup_config(in, configfile, &lineno, pass_argc, pass_argv);
+ scen = replay_scenario_read(in, filename, &lineno);
fclose(in);
if(!scen)
fatal_exit("Could not read: %s", filename);
int init_optind = optind;
char* init_optarg = optarg;
struct replay_scenario* scen = NULL;
+ char cfgfile[128];
log_init(NULL);
log_info("Start of %s testbound program.", PACKAGE_STRING);
}
/* setup test environment */
- scen = setup_playback(playback_file);
+ scen = setup_playback(playback_file, cfgfile, &pass_argc, pass_argv);
/* init fake event backend */
fake_event_init(scen);
/* run the normal daemon */
res = daemon_main(pass_argc, pass_argv);
+ unlink(cfgfile);
fake_event_cleanup();
for(c=1; c<pass_argc; c++)
free(pass_argv[c]);
; This is a comment.
+; config options go here.
+CONFIG_END
SCENARIO_BEGIN Sample of a valid query
RANGE_BEGIN 0 100
; This is a comment.
+; config options go here.
+CONFIG_END
SCENARIO_BEGIN Query receives answer from the cache
+; config options go here.
+CONFIG_END
SCENARIO_BEGIN Forwarder and an error happens on server query.
STEP 1 QUERY
ENTRY_BEGIN
--- /dev/null
+; This is a comment.
+; config options go here.
+; extremely small cache to force dropping old records.
+server:
+ msg-cache-size: 1 # one whole byte!
+ msg-cache-slabs: 1
+CONFIG_END
+
+SCENARIO_BEGIN Old answer is dropped from the cache
+
+STEP 1 QUERY
+ENTRY_BEGIN
+ SECTION QUESTION
+ www.example.com. IN A
+ENTRY_END
+; the query is sent to the forwarder - no cache yet.
+STEP 2 CHECK_OUT_QUERY
+ENTRY_BEGIN
+ MATCH qname qtype opcode
+ SECTION QUESTION
+ www.example.com. IN A
+ENTRY_END
+STEP 3 REPLY
+ENTRY_BEGIN
+ MATCH opcode qtype qname
+ ADJUST copy_id
+ REPLY QR RD RA NOERROR
+ SECTION QUESTION
+ www.example.com. IN A
+ SECTION ANSWER
+ www.example.com. IN A 10.20.30.40
+ SECTION AUTHORITY
+ www.example.com. IN NS ns.example.com.
+ SECTION ADDITIONAL
+ ns.example.com. IN A 10.20.30.50
+ENTRY_END
+STEP 4 CHECK_ANSWER
+ENTRY_BEGIN
+ MATCH opcode qname qtype
+ SECTION QUESTION
+ www.example.com. IN A
+ SECTION ANSWER
+ www.example.com. IN A 10.20.30.40
+ENTRY_END
+
+; another query to force the cache to drop the example.com entry.
+STEP 11 QUERY
+ENTRY_BEGIN
+ SECTION QUESTION
+ www.example.net. IN A
+ENTRY_END
+; the query is sent to the forwarder - no cache yet.
+STEP 12 CHECK_OUT_QUERY
+ENTRY_BEGIN
+ MATCH qname qtype opcode
+ SECTION QUESTION
+ www.example.net. IN A
+ENTRY_END
+STEP 13 REPLY
+ENTRY_BEGIN
+ MATCH opcode qtype qname
+ ADJUST copy_id
+ REPLY QR RD RA NOERROR
+ SECTION QUESTION
+ www.example.net. IN A
+ SECTION ANSWER
+ www.example.net. IN A 10.20.30.40
+ SECTION AUTHORITY
+ www.example.net. IN NS ns.example.net.
+ SECTION ADDITIONAL
+ ns.example.net. IN A 10.20.30.50
+ENTRY_END
+STEP 14 CHECK_ANSWER
+ENTRY_BEGIN
+ MATCH opcode qname qtype
+ SECTION QUESTION
+ www.example.net. IN A
+ SECTION ANSWER
+ www.example.net. IN A 10.20.30.40
+ENTRY_END
+
+
+; query, same as first, but it fell out of the cache.
+STEP 21 QUERY
+ENTRY_BEGIN
+ SECTION QUESTION
+ www.example.com. IN A
+ENTRY_END
+STEP 22 CHECK_OUT_QUERY
+ENTRY_BEGIN
+ MATCH qname qtype opcode
+ SECTION QUESTION
+ www.example.com. IN A
+ENTRY_END
+STEP 23 REPLY
+ENTRY_BEGIN
+ MATCH opcode qtype qname
+ ADJUST copy_id
+ REPLY QR RD RA NOERROR
+ SECTION QUESTION
+ www.example.com. IN A
+ SECTION ANSWER
+ www.example.com. IN A 10.20.30.40
+ SECTION AUTHORITY
+ www.example.com. IN NS ns.example.com.
+ SECTION ADDITIONAL
+ ns.example.com. IN A 10.20.30.50
+ENTRY_END
+STEP 24 CHECK_ANSWER
+ENTRY_BEGIN
+ MATCH opcode qname qtype
+ SECTION QUESTION
+ www.example.com. IN A
+ SECTION ANSWER
+ www.example.com. IN A 10.20.30.40
+ENTRY_END
+
+SCENARIO_END
; This is a comment.
+; can set commandline options using something like this:
+; COMMANDLINE -v
+; here config file options:
+server:
+ msg-cache-size: 1024
+CONFIG_END
+
SCENARIO_BEGIN Query receives answer not from the cache
STEP 1 QUERY
+; config options go here.
+CONFIG_END
SCENARIO_BEGIN Forwarder and a timeout happens on server query.
STEP 1 QUERY
ENTRY_BEGIN
+; config options go here.
+CONFIG_END
SCENARIO_BEGIN Sample of a valid query
; query responses from authority servers.