// Basic server functionality test. // Checks that server answers SUBSCRIBES, sends NOTIFY, sends NOTIFY // when content changes. void basicSubscriptionTest() { // Verify that authentication and authorization are // disabled by default. { SipSubscribeServerEventHandler* eventHandler = subServerp->getEventHandler(eventName); CPPUNIT_ASSERT(eventHandler); SipMessage bogusSubscribeRequest; SipMessage bogusSubscribeResponse; CPPUNIT_ASSERT(eventHandler->isAuthenticated(bogusSubscribeRequest, bogusSubscribeResponse)); CPPUNIT_ASSERT(eventHandler->isAuthorized(bogusSubscribeRequest, bogusSubscribeResponse)); } // Send a SUBSCRIBE to the notifier. SipMessage mwiSubscribeRequest; { UtlString c; CallId::getNewCallId(c); mwiSubscribeRequest.setSubscribeData(notifier_aor, // request URI subscriber_name_addr, // From notifier_name_addr, // To c, // Call-Id 0, // CSeq eventName, // Event mwiMimeType, // Accept NULL, // Event id subscriber_name_addr, // Contact NULL, // Route 3600 // Expires ); } CPPUNIT_ASSERT(subscriberUserAgentp->send(mwiSubscribeRequest)); // We should get a 202 response and a NOTIFY request in the queue OsTime messageTimeout(1, 0); // 1 second { const SipMessage* subscribeResponse; const SipMessage* notifyRequest; runListener(incomingClientMsgQueue, *subscriberUserAgentp, messageTimeout, messageTimeout, notifyRequest, subscribeResponse, SIP_OK_CODE, FALSE, 0, NULL); // We should have received a SUBSCRIBE response and a NOTIFY request. CPPUNIT_ASSERT(subscribeResponse); CPPUNIT_ASSERT(notifyRequest); // Check that the response code and CSeq method in the // subscribe response are OK. { CPPUNIT_ASSERT(subscribeResponse->getResponseStatusCode() == SIP_ACCEPTED_CODE); UtlString subscribeMethod; subscribeResponse->getCSeqField(NULL, &subscribeMethod); ASSERT_STR_EQUAL(SIP_SUBSCRIBE_METHOD, subscribeMethod.data()); } // Check that the method in the notify request is OK. { UtlString notifyMethod; notifyRequest->getRequestMethod(¬ifyMethod); ASSERT_STR_EQUAL(SIP_NOTIFY_METHOD, notifyMethod.data()); } // Check that the Event header in the NOTIFY is the same as the // one in the SUBSCRIBE. { UtlString notifyEventHeader; UtlString subscribeEventHeader; notifyRequest->getEventField(notifyEventHeader); mwiSubscribeRequest.getEventField(subscribeEventHeader); ASSERT_STR_EQUAL(subscribeEventHeader, notifyEventHeader); } // The NOTIFY should have no body because none has been published yet. { const HttpBody* bodyPtr = notifyRequest->getBody(); CPPUNIT_ASSERT(bodyPtr == NULL); } // The Contact in the subscribe response should be the notifier. ASSERT_STR_EQUAL(notifier_contact_name_addr, subscribeResponse-> getHeaderValue(0, SIP_CONTACT_FIELD)); // The Contact in the NOTIFY should be the notifier. CPPUNIT_ASSERT(notifyRequest-> getHeaderValue(0, SIP_CONTACT_FIELD)); ASSERT_STR_EQUAL(notifier_contact_name_addr, notifyRequest-> getHeaderValue(0, SIP_CONTACT_FIELD)); } // Publish some content (mwiStateString) for this resourceID { HttpBody* newMwiBodyPtr = new HttpBody(mwiStateString, strlen(mwiStateString), mwiMimeType); SipPublishContentMgr* publishMgr = subServerp->getPublishMgr(eventName); CPPUNIT_ASSERT(publishMgr); publishMgr->publish(notifier_resource_id, eventName, eventName, 1, &newMwiBodyPtr); } // Should get a NOTIFY queued up { const SipMessage* subscribeResponse; const SipMessage* secondNotify; runListener(incomingClientMsgQueue, *subscriberUserAgentp, messageTimeout, messageTimeout, secondNotify, subscribeResponse, SIP_OK_CODE, FALSE, 0, NULL); CPPUNIT_ASSERT(secondNotify); CPPUNIT_ASSERT(subscribeResponse == NULL); // Check that the body of the NOTIFY is what we expect (mwiStateString). { const HttpBody* secondNotifyBody = secondNotify->getBody(); CPPUNIT_ASSERT(secondNotifyBody); ssize_t notifyBodySize; const char* notifyBodyBytes; secondNotifyBody->getBytes(¬ifyBodyBytes, ¬ifyBodySize); CPPUNIT_ASSERT(notifyBodyBytes); ASSERT_STR_EQUAL(mwiStateString, notifyBodyBytes); } // Check that the Dialog Manager reports that the dialog handle is OK. { UtlString secondNotifyDialogHandle; secondNotify->getDialogHandle(secondNotifyDialogHandle); CPPUNIT_ASSERT(!secondNotifyDialogHandle.isNull()); CPPUNIT_ASSERT(dialogMgrp->dialogExists(secondNotifyDialogHandle)); CPPUNIT_ASSERT(dialogMgrp->countDialogs() == 1); } } // Create a new one-time SUBSCRIBE SipMessage oneTimeMwiSubscribeRequest; { UtlString c; CallId::getNewCallId(c); oneTimeMwiSubscribeRequest. setSubscribeData(notifier_aor, // request URI subscriber_name_addr, // From notifier_name_addr, // To c, // Call-Id 0, // CSeq eventName, // Event mwiMimeType, // Accept NULL, // Event id subscriber_name_addr, // Contact NULL, // Route 0 // Expires ); } CPPUNIT_ASSERT(subscriberUserAgentp->send(oneTimeMwiSubscribeRequest)); { const SipMessage* oneTimeNotifyRequest; const SipMessage* oneTimeSubscribeResponse; runListener(incomingClientMsgQueue, *subscriberUserAgentp, messageTimeout, messageTimeout, oneTimeNotifyRequest, oneTimeSubscribeResponse, SIP_OK_CODE, FALSE, 0, NULL); // Validate the one time subscribe response and notify request CPPUNIT_ASSERT(oneTimeSubscribeResponse); CPPUNIT_ASSERT(oneTimeNotifyRequest); { CPPUNIT_ASSERT(oneTimeSubscribeResponse->getResponseStatusCode() == SIP_ACCEPTED_CODE); UtlString oneTimeSubscribeMethod; oneTimeSubscribeResponse->getCSeqField(NULL, &oneTimeSubscribeMethod); ASSERT_STR_EQUAL(SIP_SUBSCRIBE_METHOD, oneTimeSubscribeMethod.data()); UtlString oneTimeSubscribeEventHeader; oneTimeSubscribeResponse->getEventField(oneTimeSubscribeEventHeader); // The Event: header never appears in responses -- see RFC 3265 section 7.2. // The "R" in the "where" column means that "Event" appears only in // requests -- see RFC 3261 table 2 and page 160. ASSERT_STR_EQUAL("", oneTimeSubscribeEventHeader); } { UtlString oneTimeNotifyMethod; oneTimeNotifyRequest->getRequestMethod(&oneTimeNotifyMethod); ASSERT_STR_EQUAL(SIP_NOTIFY_METHOD, oneTimeNotifyMethod.data()); UtlString oneTimeNotifyEventHeader; oneTimeNotifyRequest->getEventField(oneTimeNotifyEventHeader); // The Event: header should appear in the NOTIFY. ASSERT_STR_EQUAL(SIP_EVENT_MESSAGE_SUMMARY, oneTimeNotifyEventHeader); } { const HttpBody* oneTimeBodyPtr = oneTimeNotifyRequest->getBody(); CPPUNIT_ASSERT(oneTimeBodyPtr != NULL); const char* oneTimeBodyString; ssize_t oneTimeNotifyBodySize; oneTimeBodyPtr->getBytes(&oneTimeBodyString, &oneTimeNotifyBodySize); ASSERT_STR_EQUAL(mwiStateString, oneTimeBodyString); } { UtlString oneTimeNotifyDialogHandle; oneTimeNotifyRequest->getDialogHandle(oneTimeNotifyDialogHandle); CPPUNIT_ASSERT(!oneTimeNotifyDialogHandle.isNull()); CPPUNIT_ASSERT(dialogMgrp->dialogExists(oneTimeNotifyDialogHandle)); CPPUNIT_ASSERT(dialogMgrp->countDialogs() == 2); long now = OsDateTime::getSecsSinceEpoch(); subMgrp->removeOldSubscriptions(now + 1); // The one time subscription should get garbage collected // leaving only the persistant 3600 second subscription CPPUNIT_ASSERT(dialogMgrp->countDialogs() == 1); } } }