Commit 831e5faf authored by Pekka Pessi's avatar Pekka Pessi

test_nua: added test cases for graceful termination

Sending un-SUBSCRIBE upon an error response to SUBSCRIBE, BYE to an error
response to PRACK.

darcs-hash:20070226185507-55b16-e86da5b3daf11e72aafe4630c3d3577316be5ae5.gz
parent 1269836a
......@@ -101,24 +101,17 @@ int accept_pracked2(CONDITION_PARAMS)
save_event_in_list(ctx, event, ep, call);
switch (event) {
case nua_i_prack:
if (200 <= status && status < 300) {
RESPOND(ep, call, nh, SIP_200_OK,
NUTAG_INCLUDE_EXTRA_SDP(1),
TAG_END());
ep->next_condition = until_ready;
}
default:
break;
}
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
TAG_END());
RESPOND(ep, call, nh, SIP_200_OK,
NUTAG_INCLUDE_EXTRA_SDP(1),
TAG_END());
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
......@@ -552,6 +545,8 @@ int ringing_pracked(CONDITION_PARAMS)
}
}
int respond_483_to_prack(CONDITION_PARAMS);
int test_183rel(struct context *ctx)
{
BEGIN();
......@@ -661,29 +656,109 @@ int test_183rel(struct context *ctx)
if (print_headings)
printf("TEST NUA-10.2.1: PASSED\n");
/* Test for graceful termination by client because 483 sent to PRACK */
if (print_headings)
printf("TEST NUA-10.2.2: terminate call\n");
printf("TEST NUA-10.2.2: graceful termination because PRACK fails\n");
BYE(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
nua_set_hparams(b_call->nh, NUTAG_APPL_METHOD("PRACK"),
NUTAG_AUTOANSWER(0), TAG_END());
run_b_until(ctx, nua_r_set_params, NULL);
/* B transitions:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
INVITE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, respond_483_to_prack);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> TERMINATING: nua_r_invite, nua_i_state,
nua_r_prack, nua_i_state
TERMINATING -(T1)-> TERMINATED: nua_r_invite, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
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, 183);
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(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(e->data->e_status, 483);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminating);
{
int bye = 1, cancel = 1, invite = 1;
while (bye || cancel || invite) {
TEST_1(e = e->next);
if (e->data->e_event == nua_r_bye) {
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);
bye = 0;
}
else if (e->data->e_event == nua_r_invite) {
TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 487);
invite = 0;
}
else if (e->data->e_event == nua_r_cancel) {
TEST_E(e->data->e_event, nua_r_cancel);
TEST_1(e->data->e_status == 200 || e->data->e_status == 481);
cancel = 0;
}
}
}
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
/* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
TEST(e->data->e_status, 200);
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, nua_respond(to PRACK)
EARLY -(S3b)-> 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_terminated); /* TERMINATED */
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
TEST_1(is_offer_recv(e->data->e_tags));
/* Responded with 183 Session Progress */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(e->data->e_status, 183);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(is_answer_sent(e->data->e_tags));
/* 183 is PRACKed, PRACK is responded with 483 */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
/* Client terminates the call
- we may (it is received before BYE) or may not (received after BYE)
get CANCEL request
*/
TEST_1(e = e->next);
if (e->data->e_event == nua_i_cancel) {
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_ready);
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);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
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;
......@@ -694,6 +769,39 @@ int test_183rel(struct context *ctx)
END();
}
int respond_483_to_prack(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
switch (event) {
case nua_i_prack:
if (status <= 200) {
RESPOND(ep, call, nh, 483, "Foo",
NUTAG_WITH_THIS(nua),
TAG_END());
}
default:
break;
}
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
TAG_END());
return 0;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
}
/*
X ringing_updated ep
|-------INVITE------>|
......@@ -1918,4 +2026,3 @@ int test_100rel(struct context *ctx)
return retval;
}
......@@ -200,12 +200,15 @@ int test_message(struct context *ctx)
/* Events:
nua_message(), nua_i_message, nua_r_message
*/
TEST_1(e = a->specials->head); TEST_E(e->data->e_event, nua_i_message);
TEST_1(e = a->specials->head);
while (e->data->e_event == nua_i_outbound)
e = e->next;
TEST_E(e->data->e_event, nua_i_message);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subject && sip->sip_subject->g_string);
TEST_S(sip->sip_subject->g_string, "NUA-11.2");
TEST_1(!e->next);
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_message);
TEST(e->data->e_status, 200);
TEST_1(!e->next);
......@@ -570,7 +573,10 @@ int test_subscribe_notify(struct context *ctx)
tagi_t const *n_tags, *r_tags;
if (print_headings)
printf("TEST NUA-11.4: establishing subscription without notifier\n");
printf("TEST NUA-11.4: notifier server using nua_notify()\n");
if (print_headings)
printf("TEST NUA-11.4.1: establishing subscription\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
......@@ -630,7 +636,7 @@ int test_subscribe_notify(struct context *ctx)
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.4: PASSED\n");
printf("TEST NUA-11.4.1: PASSED\n");
/* ---------------------------------------------------------------------- */
......@@ -643,7 +649,7 @@ int test_subscribe_notify(struct context *ctx)
| |
*/
if (print_headings)
printf("TEST NUA-11.5: send NOTIFY\n");
printf("TEST NUA-11.4.2: send NOTIFY\n");
/* Update presence data */
......@@ -683,7 +689,7 @@ int test_subscribe_notify(struct context *ctx)
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.5: PASSED\n");
printf("TEST NUA-11.4.2: PASSED\n");
/* ---------------------------------------------------------------------- */
......@@ -698,7 +704,7 @@ int test_subscribe_notify(struct context *ctx)
| |
*/
if (print_headings)
printf("TEST NUA-11.6: un-SUBSCRIBE\n");
printf("TEST NUA-11.4.3: un-SUBSCRIBE\n");
UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
......@@ -755,11 +761,217 @@ int test_subscribe_notify(struct context *ctx)
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-11.6: PASSED\n");
printf("TEST NUA-11.4.3: PASSED\n");
if (print_headings)
printf("TEST NUA-11.4: PASSED\n");
END();
}
/* ---------------------------------------------------------------------- */
/* Subscriber gracefully terminates dialog upon 483 */
static
size_t change_status_to_483(void *a, void *message, size_t len);
int save_until_notified_and_responded_twice(CONDITION_PARAMS);
int save_until_notify_responded_twice(CONDITION_PARAMS);
int test_subscribe_notify_graceful(struct context *ctx)
{
if (!ctx->nat)
return 0;
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
sip_t const *sip;
tagi_t const *n_tags, *r_tags;
struct nat_filter *f;
if (print_headings)
printf("TEST NUA-11.5.1: establishing subscription\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
SIPTAG_EVENT_STR("presence"),
SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
TAG_END());
run_ab_until(ctx, -1, save_until_notified_and_responded,
-1, accept_and_notify);
/* Client events:
nua_subscribe(), nua_i_notify/nua_r_subscribe
*/
TEST_1(e = a->events->head);
if (e->data->e_event == nua_i_notify) {
TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
n_tags = e->data->e_tags;
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
}
else {
TEST_E(e->data->e_event, nua_r_subscribe);
TEST(e->data->e_status, 202);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
n_tags = e->data->e_tags;
}
TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
TEST_1(sip->sip_content_type);
TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "pending");
TEST_1(sip->sip_subscription_state->ss_expires);
TEST_1(tl_find(n_tags, nutag_substate));
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_pending);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
/* Server events: nua_i_subscribe, nua_r_notify */
TEST_1(e = b->events->head);
TEST_E(e->data->e_event, nua_i_subscribe);
TEST_E(e->data->e_status, 100);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.5.1: PASSED\n");
if (print_headings)
printf("TEST NUA-11.5.2: terminate gracefully upon 483\n");
TEST_1(f = test_nat_add_filter(ctx->nat,
change_status_to_483, NULL,
nat_inbound));
SUBSCRIBE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, save_until_notified_and_responded_twice,
-1, save_until_notify_responded_twice);
#if 0
/* Client events:
nua_unsubscribe(), nua_i_notify/nua_r_unsubscribe
*/
TEST_1(e = a->events->head);
if (e->data->e_event == nua_i_notify) {
TEST_E(e->data->e_event, nua_i_notify);
n_tags = e->data->e_tags;
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_event);
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
TEST_1(!sip->sip_subscription_state->ss_expires);
TEST_1(tl_find(n_tags, nutag_substate));
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_unsubscribe);
TEST(e->data->e_status, 200);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
}
else {
TEST_E(e->data->e_event, nua_r_unsubscribe);
TEST(e->data->e_status, 200);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
}
TEST_1(!e->next);
/* Notifier events: nua_r_notify */
TEST_1(e = b->events->head);
TEST_E(e->data->e_event, nua_i_subscribe);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(tl_find(e->data->e_tags, nutag_substate));
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
nua_substate_terminated);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST_1(e->data->e_status >= 200);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
#endif
free_events_in_list(ctx, a->events);
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;
test_nat_remove_filter(ctx->nat, f);
if (print_headings)
printf("TEST NUA-11.5.2: PASSED\n");
END();
}
static
size_t change_status_to_483(void *a, void *message, size_t len)
{
(void)a;
if (strncmp("SIP/2.0 2", message, 9) == 0) {
memcpy(message, "SIP/2.0 483", 11);
}
return len;
}
int save_until_notified_and_responded_twice(CONDITION_PARAMS)
{
save_event_in_list(ctx, event, ep, call);
if (event == nua_i_notify) {
if (ep->flags.bit0)
ep->flags.bit1 = 1;
ep->flags.bit0 = 1;
}
if (event == nua_r_subscribe || event == nua_r_unsubscribe) {
if (status >= 300)
return 1;
else if (status >= 200) {
if (ep->flags.bit2)
ep->flags.bit3 = 1;
ep->flags.bit2 = 1;
}
}
return ep->flags.bit0 && ep->flags.bit1 && ep->flags.bit2 && ep->flags.bit3;
}
int save_until_notify_responded_twice(CONDITION_PARAMS)
{
save_event_in_list(ctx, event, ep, call);
if (event == nua_r_notify) {
if (ep->flags.bit0)
ep->flags.bit1 = 1;
ep->flags.bit0 = 1;
}
return ep->flags.bit0 && ep->flags.bit1;
}
/* ---------------------------------------------------------------------- */
/* Unsolicited NOTIFY */
......@@ -937,9 +1149,10 @@ int accept_notify(CONDITION_PARAMS)
int test_simple(struct context *ctx)
{
return
/* test_message(ctx)
|| */ test_publish(ctx)
test_message(ctx)
|| test_publish(ctx)
|| test_subscribe_notify(ctx)
|| test_subscribe_notify_graceful(ctx)
|| test_newsub_notify(ctx)
;
}
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