Commit f823e523 authored by Pekka Pessi's avatar Pekka Pessi

test_nua: added tests for corner cases

- dropping call in inconvenient times
- INVITE glare
- queueing re-INVITEs

darcs-hash:20070214202150-55b16-8466bad2111638f1e8bfb8c50dfce6d65a4903b2.gz
parent 78a20726
This diff is collapsed.
......@@ -467,7 +467,7 @@ int test_call_hold(struct context *ctx)
*/
if (print_headings)
printf("TEST NUA-7.6: re-INVITE without auto-ack\n");
printf("TEST NUA-7.6.1: re-INVITE without auto-ack\n");
/* Turn off auto-ack */
nua_set_hparams(b_call->nh, NUTAG_AUTOACK(0), TAG_END());
......@@ -517,7 +517,7 @@ int test_call_hold(struct context *ctx)
free_events_in_list(ctx, a->events);
if (print_headings)
printf("TEST NUA-7.6: PASSED\n");
printf("TEST NUA-7.6.1: PASSED\n");
/* ---------------------------------------------------------------------- */
......@@ -528,7 +528,7 @@ int test_call_hold(struct context *ctx)
*/
if (print_headings)
printf("TEST NUA-7.6: terminate call\n");
printf("TEST NUA-7.6.2: terminate call\n");
BYE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
......@@ -555,7 +555,7 @@ int test_call_hold(struct context *ctx)
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-7.6: PASSED\n");
printf("TEST NUA-7.6.2: PASSED\n");
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
......@@ -725,9 +725,6 @@ int test_reinvite(struct context *ctx)
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-7.8: PASSED\n");
END();
}
......@@ -784,6 +781,211 @@ int ringing_until_terminated(CONDITION_PARAMS)
}
}
/* ======================================================================== */
int accept_and_attempt_reinvite(CONDITION_PARAMS);
int until_ready2(CONDITION_PARAMS);
/* test_reinvite2 message sequence looks like this:
A B
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
| |
| /-INVITE-|
| \---900->|
| |
|<--------200--------|
|---------ACK------->|
: :
: queue INVITE :
: :
|-----re-INVITE----->|
|<--------200--------|
|---------ACK------->|
|-----re-INVITE----->|
|<--------200--------|
|---------ACK------->|
: :
: glare :
: :
|-----re-INVITE----->|
|<----re-INVITE------|
|<--------491--------|
|---------491------->|
|---------ACK------->|
|<--------ACK--------|
: :
|---------BYE------->|
|<--------200--------|
*/
int test_reinvite2(struct context *ctx)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
if (print_headings)
printf("TEST NUA-7.8.1: Test re-INVITE glare\n");
a_call->sdp = "m=audio 5008 RTP/AVP 0 8\n";
b_call->sdp = "m=audio 5010 RTP/AVP 8\n";
TEST_1(a_call->nh =
nua_handle(a->nua, a_call,
SIPTAG_FROM_STR("Alice <sip:alice@example.com>"),
SIPTAG_TO(b->to),
TAG_END()));
INVITE(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
SOATAG_USER_SDP_STR(a_call->sdp),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_and_attempt_reinvite);
TEST_1(nua_handle_has_active_call(a_call->nh));
TEST_1(nua_handle_has_active_call(b_call->nh));
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
/* Check that we can queue INVITEs */
INVITE(a, a_call, a_call->nh, TAG_END());
INVITE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_ready2, -1, until_ready2);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
/* Check that INVITE glare works */
INVITE(a, a_call, a_call->nh, TAG_END());
INVITE(b, b_call, b_call->nh, TAG_END());
a->flags.n = 0, b->flags.n = 0;
run_ab_until(ctx, -1, until_ready2, -1, until_ready2);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-7.8.1: PASSED\n");
/* ---------------------------------------------------------------------- */
/*
A B
|---------BYE------->|
|<--------200--------|
*/
if (print_headings)
printf("TEST NUA-7.8.2: terminate call\n");
BYE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
/*
Transitions of A:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
/* Transitions of B:
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_bye);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-7.8.2: PASSED\n");
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
END();
}
int accept_and_attempt_reinvite(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
if (event == nua_i_prack) {
INVITE(ep, call, nh, TAG_END());
RESPOND(ep, call, nh, SIP_200_OK,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
TAG_END());
}
else switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
SIPTAG_REQUIRE_STR("100rel"),
TAG_END());
return 0;
case nua_callstate_early:
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
return 0;
}
/*
X INVITE
| |
|-------INVITE------>|
|<--------200--------|
|---------ACK------->|
*/
int until_ready2(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
if (event == nua_r_invite && status == 491) {
if (ep == &ctx->a && ++ctx->b.flags.n >= 2) ctx->b.running = 0;
if (ep == &ctx->b && ++ctx->a.flags.n >= 2) ctx->a.running = 0;
}
switch (callstate(tags)) {
case nua_callstate_ready:
return ++ep->flags.n >= 2;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
}
int test_reinvites(struct context *ctx)
{
int retval = 0;
......@@ -794,7 +996,10 @@ int test_reinvites(struct context *ctx)
retval = test_call_hold(ctx);
if (retval == 0)
retval |= test_reinvite(ctx);
retval = test_reinvite(ctx);
if (retval == 0)
retval = test_reinvite2(ctx);
if (print_headings && retval == 0)
printf("TEST NUA-7: PASSED\n");
......
......@@ -118,6 +118,8 @@ int cancel_when_ringing(CONDITION_PARAMS)
case nua_callstate_proceeding:
CANCEL(ep, call, nh, TAG_END());
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
return 1;
default:
......@@ -673,6 +675,82 @@ int test_call_destroy_4(struct context *ctx)
END();
}
/* Destroy when one INVITE is queued. */
int test_call_destroy_5(struct context *ctx)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
if (print_headings)
printf("TEST NUA-5.7: destroy when re-INVITE is queued\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
INVITE(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
NUTAG_AUTOACK(0),
SOATAG_USER_SDP_STR(a_call->sdp),
TAG_END());
INVITE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, destroy_when_completed);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), ...
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
TEST_1(is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 180);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
TEST_1(is_answer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 481);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state ... DESTROY
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
TEST(e->data->e_status, 100);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
TEST_1(is_offer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
TEST_1(is_answer_sent(e->data->e_tags));
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-5.7: PASSED\n");
END();
}
int test_call_destroy(struct context *ctx)
{
struct endpoint *a = &ctx->a, *b = &ctx->b;
......@@ -685,10 +763,12 @@ int test_call_destroy(struct context *ctx)
test_call_destroy_1(ctx) ||
test_call_destroy_2(ctx) ||
test_call_destroy_3(ctx) ||
test_call_destroy_4(ctx);
test_call_destroy_4(ctx) ||
test_call_destroy_5(ctx);
}
/* ======================================================================== */
/* Early BYE
A B
......@@ -731,12 +811,27 @@ int bye_when_ringing(CONDITION_PARAMS)
}
}
int bye_when_completing(CONDITION_PARAMS);
static int ack_sent = 0;
size_t count_acks(void *message, size_t len)
{
if (strncasecmp(message, "ACK sip:", 8) == 0)
ack_sent++;
return len;
}
int test_early_bye(struct context *ctx)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
struct nat_filter *f = NULL;
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
if (print_headings)
printf("TEST NUA-6.1: BYE call when ringing\n");
......@@ -806,6 +901,119 @@ int test_early_bye(struct context *ctx)
if (print_headings)
printf("TEST NUA-6.1: PASSED\n");
/* Early BYE 2
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
|<-------200---------|
| |
|--------BYE-------->|
|<------200 OK-------|
|--------ACK-------->|
| |
| |
*/
if (print_headings)
printf("TEST NUA-6.2: BYE call when completing\n");
if (ctx->nat)
TEST_1(f = test_nat_add_filter(ctx->nat, count_acks, nat_outbound));
ack_sent = 0;
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
INVITE(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
SOATAG_USER_SDP_STR(a_call->sdp),
NUTAG_AUTOACK(0),
TAG_END());
run_ab_until(ctx, -1, bye_when_completing, -1, accept_until_terminated);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel()
PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), nua_i_state
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_calling);
TEST_1(is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 180);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completing);
TEST_1(e = e->next);
TEST_E(e->data->e_event, nua_r_bye); TEST(e->data->e_status, 200);
TEST_1(e->data->e_msg);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
if (ctx->nat) {
while (ack_sent == 0)
su_root_step(ctx->root, 100);
TEST_1(ack_sent > 0);
TEST_1(test_nat_remove_filter(ctx->nat, f) == 0);
}
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
TEST(e->data->e_status, 100);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
TEST_1(is_offer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* EARLY */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-6.2: PASSED\n");
END();
}
int bye_when_completing(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_completing:
ack_sent = 0;
BYE(ep, call, nh, TAG_END());
return 0;
case nua_callstate_terminated:
return 1;
default:
return 0;
}
}
......@@ -166,12 +166,11 @@ struct context
struct eventlist specials[1];
/* State flags for complex scenarios */
union {
struct {
unsigned bit0:1, bit1:1, bit2:1, bit3:1;
unsigned bit4:1, bit5:1, bit6:1, bit7:1;
} b;
struct {
unsigned n;
unsigned bit0:1, bit1:1, bit2:1, bit3:1;
unsigned bit4:1, bit5:1, bit6:1, bit7:1;
unsigned :0;
} flags;
} a, b, c;
......@@ -215,6 +214,7 @@ int save_until_special(CONDITION_PARAMS);
int until_terminated(CONDITION_PARAMS);
int until_ready(CONDITION_PARAMS);
int accept_call(CONDITION_PARAMS);
int cancel_when_ringing(CONDITION_PARAMS);
int accept_notify(CONDITION_PARAMS);
......
......@@ -272,21 +272,21 @@ void run_abc_until(struct context *ctx,
a->last_event = -1;
a->running = a_condition != NULL && a_condition != save_events;
a->running |= a_event != -1;
a->flags.n = 0;
memset(&a->flags, 0, sizeof a->flags);
b->next_event = b_event;
b->next_condition = b_condition;
b->last_event = -1;
b->running = b_condition != NULL && b_condition != save_events;
b->running |= b_event != -1;
b->flags.n = 0;
memset(&b->flags, 0, sizeof b->flags);
c->next_event = c_event;
c->next_condition = c_condition;
c->last_event = -1;
c->running = c_condition != NULL && c_condition != save_events;
c->running |= c_event != -1;
c->flags.n = 0;
memset(&c->flags, 0, sizeof c->flags);
for (; a->running || b->running || c->running;) {
su_root_step(ctx->root, 1000);
......
......@@ -64,15 +64,15 @@ int save_until_notified(CONDITION_PARAMS)
int save_until_notified_and_responded(CONDITION_PARAMS)
{
save_event_in_list(ctx, event, ep, call);
if (event == nua_i_notify) ep->flags.b.bit0 = 1;
if (event == nua_i_notify) ep->flags.bit0 = 1;
if (event == nua_r_subscribe || event == nua_r_unsubscribe) {
if (status >= 300)
return 1;
else if (status >= 200)
ep->flags.b.bit1 = 1;
ep->flags.bit1 = 1;
}
return ep->flags.b.bit0 && ep->flags.b.bit1;
return ep->flags.bit0 && ep->flags.bit1;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment