feat(raft-library): reject even n_peers in raft_init; add test_raft_init_even_peers_returns_einval
This commit is contained in:
parent
fd9933c9d0
commit
becf6ee765
2 changed files with 48 additions and 6 deletions
|
|
@ -15,6 +15,11 @@ int raft_init(raft_state_t *s, const raft_config_t *cfg)
|
||||||
/* Validate required callbacks and n_peers before touching *s */
|
/* Validate required callbacks and n_peers before touching *s */
|
||||||
if (cfg->n_peers < 1)
|
if (cfg->n_peers < 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
/* Even cluster sizes (>1) have no fault-tolerance advantage over the next
|
||||||
|
* smaller odd size and can mislead operators into thinking split-brain is
|
||||||
|
* impossible. Reject to prevent misconfiguration. */
|
||||||
|
if (cfg->n_peers > 1 && cfg->n_peers % 2 == 0)
|
||||||
|
return -EINVAL;
|
||||||
if (!cfg->cbs)
|
if (!cfg->cbs)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!cfg->cbs->on_send_vote_request)
|
if (!cfg->cbs->on_send_vote_request)
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,7 @@ static void test_raft_init_null_become_leader_returns_einval(void)
|
||||||
cbs.on_become_leader = NULL;
|
cbs.on_become_leader = NULL;
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
cfg.n_peers = 2; cfg.self_idx = 0; cfg.cbs = &cbs;
|
cfg.n_peers = 3; cfg.self_idx = 0; cfg.cbs = &cbs;
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +273,7 @@ static void test_raft_init_null_become_follower_returns_einval(void)
|
||||||
cbs.on_become_follower = NULL;
|
cbs.on_become_follower = NULL;
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
cfg.n_peers = 2; cfg.self_idx = 0; cfg.cbs = &cbs;
|
cfg.n_peers = 3; cfg.self_idx = 0; cfg.cbs = &cbs;
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
||||||
}
|
}
|
||||||
|
|
@ -288,7 +288,7 @@ static void test_raft_init_null_persist_returns_einval(void)
|
||||||
cbs.on_persist = NULL;
|
cbs.on_persist = NULL;
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
cfg.n_peers = 2; cfg.self_idx = 0; cfg.cbs = &cbs;
|
cfg.n_peers = 3; cfg.self_idx = 0; cfg.cbs = &cbs;
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
||||||
}
|
}
|
||||||
|
|
@ -303,7 +303,7 @@ static void test_raft_init_null_schedule_timeout_returns_einval(void)
|
||||||
cbs.on_schedule_timeout = NULL;
|
cbs.on_schedule_timeout = NULL;
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
cfg.n_peers = 2; cfg.self_idx = 0; cfg.cbs = &cbs;
|
cfg.n_peers = 3; cfg.self_idx = 0; cfg.cbs = &cbs;
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
||||||
}
|
}
|
||||||
|
|
@ -318,7 +318,7 @@ static void test_raft_init_null_cancel_timeout_returns_einval(void)
|
||||||
cbs.on_cancel_timeout = NULL;
|
cbs.on_cancel_timeout = NULL;
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
cfg.n_peers = 2; cfg.self_idx = 0; cfg.cbs = &cbs;
|
cfg.n_peers = 3; cfg.self_idx = 0; cfg.cbs = &cbs;
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
||||||
}
|
}
|
||||||
|
|
@ -333,11 +333,47 @@ static void test_raft_init_null_start_election_after_delay_returns_einval(void)
|
||||||
cbs.on_start_election_after_delay = NULL;
|
cbs.on_start_election_after_delay = NULL;
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
cfg.n_peers = 2; cfg.self_idx = 0; cfg.cbs = &cbs;
|
cfg.n_peers = 3; cfg.self_idx = 0; cfg.cbs = &cbs;
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* n_peers even (>1) → -EINVAL: even-sized clusters have no fault-tolerance
|
||||||
|
* advantage over the next-smaller odd cluster; reject to prevent misconfiguration. */
|
||||||
|
static void test_raft_init_even_peers_returns_einval(void)
|
||||||
|
{
|
||||||
|
raft_state_t s;
|
||||||
|
raft_callbacks_t cbs = make_full_cbs();
|
||||||
|
raft_config_t cfg;
|
||||||
|
|
||||||
|
memset(&s, 0xAB, sizeof(s));
|
||||||
|
|
||||||
|
/* n_peers=2: even, >1 → must fail */
|
||||||
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
|
cfg.n_peers = 2;
|
||||||
|
cfg.self_idx = 0;
|
||||||
|
cfg.cbs = &cbs;
|
||||||
|
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
||||||
|
|
||||||
|
/* n_peers=4: even, >1 → must fail */
|
||||||
|
cfg.n_peers = 4;
|
||||||
|
TEST_ASSERT_EQUAL_INT(-EINVAL, raft_init(&s, &cfg));
|
||||||
|
|
||||||
|
/* n_peers=1: single-node is always valid (odd by convention) */
|
||||||
|
cfg.n_peers = 1;
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, raft_init(&s, &cfg));
|
||||||
|
|
||||||
|
/* n_peers=3: odd, >1 → must succeed */
|
||||||
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
|
cfg.n_peers = 3;
|
||||||
|
cfg.self_idx = 0;
|
||||||
|
cfg.cbs = &cbs;
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, raft_init(&s, &cfg));
|
||||||
|
|
||||||
|
/* s must NOT be unchanged after valid inits above */
|
||||||
|
TEST_ASSERT_EQUAL_INT(RAFT_FOLLOWER, s.role);
|
||||||
|
}
|
||||||
|
|
||||||
/* n_peers == 0 → -EINVAL */
|
/* n_peers == 0 → -EINVAL */
|
||||||
static void test_raft_init_zero_peers_returns_einval(void)
|
static void test_raft_init_zero_peers_returns_einval(void)
|
||||||
{
|
{
|
||||||
|
|
@ -2849,6 +2885,7 @@ void test_raft(void)
|
||||||
RUN_TEST(test_raft_init_null_schedule_timeout_returns_einval);
|
RUN_TEST(test_raft_init_null_schedule_timeout_returns_einval);
|
||||||
RUN_TEST(test_raft_init_null_cancel_timeout_returns_einval);
|
RUN_TEST(test_raft_init_null_cancel_timeout_returns_einval);
|
||||||
RUN_TEST(test_raft_init_null_start_election_after_delay_returns_einval);
|
RUN_TEST(test_raft_init_null_start_election_after_delay_returns_einval);
|
||||||
|
RUN_TEST(test_raft_init_even_peers_returns_einval);
|
||||||
RUN_TEST(test_raft_init_zero_peers_returns_einval);
|
RUN_TEST(test_raft_init_zero_peers_returns_einval);
|
||||||
RUN_TEST(test_raft_init_success_fields);
|
RUN_TEST(test_raft_init_success_fields);
|
||||||
RUN_TEST(test_raft_init_default_election_timeout);
|
RUN_TEST(test_raft_init_default_election_timeout);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue