mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 23:54:22 +01:00
test/test_state_coverage: --dump-states
Simple code to dump the state transitions into text form. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
#include <ccan/htable/htable_type.h>
|
#include <ccan/htable/htable_type.h>
|
||||||
#include <ccan/hash/hash.h>
|
#include <ccan/hash/hash.h>
|
||||||
#include <ccan/opt/opt.h>
|
#include <ccan/opt/opt.h>
|
||||||
|
#include <ccan/asort/asort.h>
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
static bool record_input_mapping(int b);
|
static bool record_input_mapping(int b);
|
||||||
@@ -17,11 +18,12 @@ static bool record_input_mapping(int b);
|
|||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "gen_state_names.h"
|
#include "gen_state_names.h"
|
||||||
|
|
||||||
|
static bool quick = false;
|
||||||
static bool dot_simplify = false;
|
static bool dot_simplify = false;
|
||||||
static bool dot_enable = false;
|
static bool dot_enable = false;
|
||||||
static bool dot_include_abnormal = false;
|
static bool dot_include_abnormal = false;
|
||||||
static bool dot_include_errors = false;
|
static bool dot_include_errors = false;
|
||||||
static bool dot_include_nops = false;
|
static bool include_nops = false;
|
||||||
static enum state_input *mapping_inputs;
|
static enum state_input *mapping_inputs;
|
||||||
static bool do_decline;
|
static bool do_decline;
|
||||||
|
|
||||||
@@ -159,6 +161,13 @@ struct hist {
|
|||||||
|
|
||||||
/* Edges for the dot graph, if any. */
|
/* Edges for the dot graph, if any. */
|
||||||
struct edge_hash edges;
|
struct edge_hash edges;
|
||||||
|
|
||||||
|
/* For dumping states. */
|
||||||
|
struct state_dump {
|
||||||
|
enum state_input input;
|
||||||
|
enum state next;
|
||||||
|
enum state_input pkt;
|
||||||
|
} **state_dump;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *state_name(enum state s)
|
static const char *state_name(enum state s)
|
||||||
@@ -733,6 +742,35 @@ static void record_output(enum state_input **outputs, enum state_input out)
|
|||||||
(*outputs)[n] = out;
|
(*outputs)[n] = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void record_state(struct state_dump **sd,
|
||||||
|
enum state_input input,
|
||||||
|
enum state newstate,
|
||||||
|
const char *pktstr)
|
||||||
|
{
|
||||||
|
size_t i, n = tal_count(*sd);
|
||||||
|
enum state_input pkt;
|
||||||
|
|
||||||
|
if (!pktstr)
|
||||||
|
pkt = INPUT_NONE;
|
||||||
|
else
|
||||||
|
pkt = input_by_name(pktstr);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if ((*sd)[i].input != input)
|
||||||
|
continue;
|
||||||
|
if ((*sd)[i].next != newstate)
|
||||||
|
continue;
|
||||||
|
if ((*sd)[i].pkt != pkt)
|
||||||
|
continue;
|
||||||
|
/* Duplicate. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tal_resize(sd, n+1);
|
||||||
|
(*sd)[n].input = input;
|
||||||
|
(*sd)[n].next = newstate;
|
||||||
|
(*sd)[n].pkt = pkt;
|
||||||
|
}
|
||||||
|
|
||||||
static bool error_path(enum state_input i, enum state src, enum state dst)
|
static bool error_path(enum state_input i, enum state src, enum state dst)
|
||||||
{
|
{
|
||||||
return state_is_error(dst) || i == PKT_ERROR;
|
return state_is_error(dst) || i == PKT_ERROR;
|
||||||
@@ -886,7 +924,7 @@ static struct trail *try_input(const struct state_data *sdata,
|
|||||||
oldstr = state_name(sdata->state) + 6;
|
oldstr = state_name(sdata->state) + 6;
|
||||||
newstr = state_name(newstate) + 6;
|
newstr = state_name(newstate) + 6;
|
||||||
}
|
}
|
||||||
if (newstr != oldstr || dot_include_nops)
|
if (newstr != oldstr || include_nops)
|
||||||
add_dot(&hist->edges, oldstr, newstr, i, effect->send);
|
add_dot(&hist->edges, oldstr, newstr, i, effect->send);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,6 +943,11 @@ static struct trail *try_input(const struct state_data *sdata,
|
|||||||
input_by_name((const char *)effect->send));
|
input_by_name((const char *)effect->send));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hist->state_dump) {
|
||||||
|
record_state(&hist->state_dump[sdata->state], i, newstate,
|
||||||
|
(const char *)effect->send);
|
||||||
|
}
|
||||||
|
|
||||||
/* Have we been in this overall situation before? */
|
/* Have we been in this overall situation before? */
|
||||||
if (!sithash_update(&hist->sithash, ©)) {
|
if (!sithash_update(&hist->sithash, ©)) {
|
||||||
/*
|
/*
|
||||||
@@ -913,12 +956,12 @@ static struct trail *try_input(const struct state_data *sdata,
|
|||||||
* 2) We get repeated BITCOIN_ANCHOR_OTHERSPEND, OR
|
* 2) We get repeated BITCOIN_ANCHOR_OTHERSPEND, OR
|
||||||
* 3) We pass through NORMAL state.
|
* 3) We pass through NORMAL state.
|
||||||
*
|
*
|
||||||
* And if we're rendering the dot diagram, don't bother.
|
* And if we're being quick, always stop.
|
||||||
*/
|
*/
|
||||||
if (effect->defer != INPUT_NONE
|
if (effect->defer != INPUT_NONE
|
||||||
|| newstate == STATE_NORMAL_LOWPRIO
|
|| newstate == STATE_NORMAL_LOWPRIO
|
||||||
|| i == BITCOIN_ANCHOR_OTHERSPEND
|
|| i == BITCOIN_ANCHOR_OTHERSPEND
|
||||||
|| dot_enable) {
|
|| quick) {
|
||||||
tal_free(effect);
|
tal_free(effect);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1154,12 +1197,24 @@ static void report_trail(const struct trail *t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int state_dump_cmp(const struct state_dump *a,
|
||||||
|
const struct state_dump *b,
|
||||||
|
void *unused)
|
||||||
|
{
|
||||||
|
if (a->input != b->input)
|
||||||
|
return a->input - b->input;
|
||||||
|
if (a->next != b->next)
|
||||||
|
return a->next - b->next;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct state_data a, b;
|
struct state_data a, b;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct hist hist;
|
struct hist hist;
|
||||||
struct trail *t;
|
struct trail *t;
|
||||||
|
bool dump_states = false;
|
||||||
|
|
||||||
err_set_progname(argv[0]);
|
err_set_progname(argv[0]);
|
||||||
|
|
||||||
@@ -1176,12 +1231,15 @@ int main(int argc, char *argv[])
|
|||||||
opt_register_noarg("--dot-include-errors",
|
opt_register_noarg("--dot-include-errors",
|
||||||
opt_set_bool, &dot_include_errors,
|
opt_set_bool, &dot_include_errors,
|
||||||
"Output dot format for error paths");
|
"Output dot format for error paths");
|
||||||
opt_register_noarg("--dot-include-nops",
|
opt_register_noarg("--include-nops",
|
||||||
opt_set_bool, &dot_include_nops,
|
opt_set_bool, &include_nops,
|
||||||
"Output dot format even for inputs which don't change state");
|
"Output even for inputs which don't change state");
|
||||||
opt_register_noarg("--dot-simplify",
|
opt_register_noarg("--dot-simplify",
|
||||||
opt_set_bool, &dot_simplify,
|
opt_set_bool, &dot_simplify,
|
||||||
"Merge high and low priority states");
|
"Merge high and low priority states");
|
||||||
|
opt_register_noarg("--dump-states",
|
||||||
|
opt_set_bool, &dump_states,
|
||||||
|
"Summarize all state transitions");
|
||||||
opt_register_version();
|
opt_register_version();
|
||||||
|
|
||||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||||
@@ -1191,14 +1249,23 @@ int main(int argc, char *argv[])
|
|||||||
opt_usage_exit_fail("--dot-simplify needs --dot/--dot-all");
|
opt_usage_exit_fail("--dot-simplify needs --dot/--dot-all");
|
||||||
if (dot_include_errors && !dot_enable)
|
if (dot_include_errors && !dot_enable)
|
||||||
opt_usage_exit_fail("--dot-include-errors needs --dot/--dot-all");
|
opt_usage_exit_fail("--dot-include-errors needs --dot/--dot-all");
|
||||||
if (dot_include_nops && !dot_enable)
|
if (include_nops && !dot_enable && !dump_states)
|
||||||
opt_usage_exit_fail("--dot-include-nops needs --dot/--dot-all");
|
opt_usage_exit_fail("--include-nops needs --dot/--dot-all/--dump-states");
|
||||||
|
|
||||||
/* Map the inputs tested in each state. */
|
/* Map the inputs tested in each state. */
|
||||||
hist.inputs_per_state = map_inputs();
|
hist.inputs_per_state = map_inputs();
|
||||||
sithash_init(&hist.sithash);
|
sithash_init(&hist.sithash);
|
||||||
hist.outputs = tal_arr(NULL, enum state_input, 0);
|
hist.outputs = tal_arr(NULL, enum state_input, 0);
|
||||||
edge_hash_init(&hist.edges);
|
edge_hash_init(&hist.edges);
|
||||||
|
if (dump_states) {
|
||||||
|
hist.state_dump = tal_arr(NULL, struct state_dump *, STATE_MAX);
|
||||||
|
for (i = 0; i < STATE_MAX; i++)
|
||||||
|
hist.state_dump[i] = tal_arr(hist.state_dump,
|
||||||
|
struct state_dump, 0);
|
||||||
|
} else
|
||||||
|
hist.state_dump = NULL;
|
||||||
|
|
||||||
|
quick = dot_enable || dump_states;
|
||||||
|
|
||||||
/* Initialize universe. */
|
/* Initialize universe. */
|
||||||
sdata_init(&a, &b, STATE_INIT_WITHANCHOR, "A");
|
sdata_init(&a, &b, STATE_INIT_WITHANCHOR, "A");
|
||||||
@@ -1283,5 +1350,29 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
printf("}\n");
|
printf("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dump_states) {
|
||||||
|
for (i = 0; i < STATE_MAX; i++) {
|
||||||
|
size_t j;
|
||||||
|
size_t n = tal_count(hist.state_dump[i]);
|
||||||
|
if (!n)
|
||||||
|
continue;
|
||||||
|
printf("%s:\n", state_name(i) + 6);
|
||||||
|
asort(hist.state_dump[i], n, state_dump_cmp, NULL);
|
||||||
|
for (j = 0; j < n; j++) {
|
||||||
|
if (!include_nops
|
||||||
|
&& hist.state_dump[i][j].next == i)
|
||||||
|
continue;
|
||||||
|
printf("\t%s -> %s",
|
||||||
|
input_name(hist.state_dump[i][j].input),
|
||||||
|
state_name(hist.state_dump[i][j].next)+6);
|
||||||
|
if (hist.state_dump[i][j].pkt != INPUT_NONE)
|
||||||
|
printf(" (%s)",
|
||||||
|
input_name(hist.state_dump[i][j].pkt));
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user