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
......@@ -1578,6 +1578,310 @@ int test_update_by_uas(struct context *ctx)
END();
}
int cancel_when_pracked(CONDITION_PARAMS);
int alert_call(CONDITION_PARAMS);
int test_180rel_cancel1(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-10.6: CANCEL after PRACK\n");
/* Test for 100rel:
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<-------180---------|
|-------PRACK------->|
|<-------200---------|
| |
|------CANCEL------->|
|<------200 OK-------|
| |
|<-------487---------|
|--------ACK-------->|
| |
*/
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
nua_set_params(ctx->a.nua,
NUTAG_EARLY_MEDIA(1),
NUTAG_ONLY183_100REL(0),
TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
nua_set_params(ctx->b.nua,
NUTAG_EARLY_MEDIA(1),
NUTAG_ONLY183_100REL(0),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
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),
TAG_END());
run_ab_until(ctx, -1, cancel_when_pracked, -1, alert_call);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
PROCEEDING -(C3+C4)-> TERMINATED: nua_r_invite, 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); /* 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(is_answer_recv(e->data->e_tags));
TEST_1(!is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_cancel);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 487);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
Option A:
EARLY -(S10)-> TERMINATED: nua_i_cancel, nua_i_state
Option B:
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
READY -(T1)-> TERMINATED: nua_i_bye, 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));
/* Responded with 180 Ringing */
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(is_answer_sent(e->data->e_tags));
/* 180 is PRACKed */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
/* Does not have effect on call state */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
free_events_in_list(ctx, b->events);
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-10.6: PASSED\n");
END();
}
int cancel_when_pracked(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_prack)
CANCEL(ep, call, nh, TAG_END());
switch (callstate(tags)) {
case nua_callstate_proceeding:
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
return 1;
default:
return 0;
}
}
int test_180rel_cancel2(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-10.7: CANCEL after 100rel 180\n");
/* Test for 100rel:
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<-------180---------|
|-------PRACK------->|
|<-------200---------|
| |
|------CANCEL------->|
|<------200 OK-------|
| |
|<-------487---------|
|--------ACK-------->|
| |
*/
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
nua_set_params(ctx->a.nua,
NUTAG_EARLY_MEDIA(1),
NUTAG_ONLY183_100REL(0),
TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
nua_set_params(ctx->b.nua,
NUTAG_EARLY_MEDIA(1),
NUTAG_ONLY183_100REL(0),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
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),
TAG_END());
run_ab_until(ctx, -1, cancel_when_ringing, -1, accept_pracked2);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
PROCEEDING -(C3+C4)-> TERMINATED: nua_r_invite, 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); /* 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(is_answer_recv(e->data->e_tags));
TEST_1(!is_offer_sent(e->data->e_tags));
#define NEXT_SKIP_PRACK_CANCEL() \
do { TEST_1(e = e->next); } \
while (e->data->e_event == nua_r_prack || e->data->e_event == nua_r_cancel)
NEXT_SKIP_PRACK_CANCEL();
TEST_E(e->data->e_event, nua_r_invite);
if (e->data->e_status == 487) {
TEST(e->data->e_status, 487);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
TEST_1(!e->next);
}
else {
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_ready);
BYE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
NEXT_SKIP_PRACK_CANCEL(); TEST_E(e->data->e_event, nua_r_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);
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
Option A:
EARLY -(S10)-> TERMINATED: nua_i_cancel, nua_i_state
Option B:
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
READY -(T1)-> TERMINATED: nua_i_bye, 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));
/* Responded with 180 Ringing */
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(is_answer_sent(e->data->e_tags));
/* 180 is PRACKed */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
/* Does not have effect on call state */
if (e->next->data->e_event == nua_i_cancel) {
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
}
else {
/* Respond with 200 OK */
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_offer_answer_done(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
TEST_1(!is_offer_answer_done(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_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
}
free_events_in_list(ctx, b->events);
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-10.7: PASSED\n");
END();
}
int test_100rel(struct context *ctx)
{
......@@ -1589,6 +1893,8 @@ int test_100rel(struct context *ctx)
retval = test_preconditions(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_preconditions2(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_update_by_uas(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_180rel_cancel1(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_180rel_cancel2(ctx); RETURN_ON_SINGLE_FAILURE(retval);
nua_set_params(ctx->a.nua,
NUTAG_EARLY_MEDIA(0),
......@@ -1612,3 +1918,4 @@ int test_100rel(struct context *ctx)
return retval;
}
......@@ -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;