/servers/sip-presence/xdm/server/tests/src/test/java/org/openxdm/xcap/client/test/subscription/SubscribeDocumentTest.java
Java | 586 lines | 375 code | 118 blank | 93 comment | 38 complexity | 87b592edbd33da42f52990633269e725 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
- /*
- * JBoss, Home of Professional Open Source
- * Copyright 2011, Red Hat, Inc. and individual contributors
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
- package org.openxdm.xcap.client.test.subscription;
- import static org.junit.Assert.assertTrue;
- import gov.nist.javax.sip.Utils;
- import java.io.IOException;
- import java.io.StringReader;
- import java.net.URI;
- import java.net.URISyntaxException;
- import java.text.ParseException;
- import java.util.ArrayList;
- import java.util.Properties;
- import java.util.concurrent.Semaphore;
- import javax.management.InstanceNotFoundException;
- import javax.management.MBeanException;
- import javax.management.MalformedObjectNameException;
- import javax.management.ReflectionException;
- import javax.naming.NamingException;
- import javax.sip.ClientTransaction;
- import javax.sip.Dialog;
- import javax.sip.DialogTerminatedEvent;
- import javax.sip.IOExceptionEvent;
- import javax.sip.InvalidArgumentException;
- import javax.sip.ListeningPoint;
- import javax.sip.RequestEvent;
- import javax.sip.ResponseEvent;
- import javax.sip.SipException;
- import javax.sip.SipFactory;
- import javax.sip.SipListener;
- import javax.sip.SipProvider;
- import javax.sip.SipStack;
- import javax.sip.TimeoutEvent;
- import javax.sip.TransactionTerminatedEvent;
- import javax.sip.address.Address;
- import javax.sip.address.AddressFactory;
- import javax.sip.address.SipURI;
- import javax.sip.header.CSeqHeader;
- import javax.sip.header.CallIdHeader;
- import javax.sip.header.ContactHeader;
- import javax.sip.header.EventHeader;
- import javax.sip.header.FromHeader;
- import javax.sip.header.HeaderFactory;
- import javax.sip.header.MaxForwardsHeader;
- import javax.sip.header.SubscriptionStateHeader;
- import javax.sip.header.ToHeader;
- import javax.sip.header.ViaHeader;
- import javax.sip.message.MessageFactory;
- import javax.sip.message.Request;
- import javax.xml.bind.JAXBContext;
- import javax.xml.bind.JAXBException;
- import junit.framework.JUnit4TestAdapter;
- import org.apache.commons.httpclient.HttpException;
- import org.apache.log4j.Logger;
- import org.junit.After;
- import org.junit.Before;
- import org.junit.Test;
- import org.mobicents.xcap.client.XcapResponse;
- import org.mobicents.xcap.client.uri.DocumentSelectorBuilder;
- import org.mobicents.xcap.client.uri.UriBuilder;
- import org.openxdm.xcap.client.test.AbstractXDMJunitTest;
- import org.openxdm.xcap.client.test.ServerConfiguration;
- import org.openxdm.xcap.common.xcapdiff.DocumentType;
- import org.openxdm.xcap.common.xcapdiff.XcapDiff;
- /**
- * first puts a new doc through xcap then subscribes it through sip, etag from xcap put response and notify must match.
- * Then update document through xcap and a notify with old and new etag should arrive.
- * Finally delete document and a notify with old etag should arrive.
- * Unsubscribe to clean up.
- */
- public class SubscribeDocumentTest extends AbstractXDMJunitTest implements SipListener {
-
- private static Logger logger = Logger.getLogger(SubscribeDocumentTest.class);
-
- public static junit.framework.Test suite() {
- return new JUnit4TestAdapter(SubscribeDocumentTest.class);
- }
-
- protected enum Tests {
- test1,
- test2,
- test3,
- test4
- }
- protected Tests testRunning;
-
- protected String subscriberUsername = "eduardo";
- protected String domain = "openxdm.org";
- protected String subscriberSipUri = "sip:"+subscriberUsername+"@" + domain;
-
- protected SipProvider sipProvider;
- protected AddressFactory addressFactory;
- protected MessageFactory messageFactory;
- protected HeaderFactory headerFactory;
- protected SipStack sipStack;
- protected ContactHeader contactHeader;
- protected String notifierPort;
- protected String transport;
- protected ListeningPoint listeningPoint;
-
- protected Dialog subscriberDialog;
- protected String subscriberToTag;
-
- protected String newEtag;
- protected String previousEtag;
-
- // a sempahore to control processing using async events
- protected Semaphore semaphore = new Semaphore(1);
-
- protected String getDocumentSelector() {
- return DocumentSelectorBuilder.getUserDocumentSelectorBuilder(appUsage.getAUID(),user,documentName).toPercentEncodedString();
- }
-
- protected URI getDocumentXcapURI() throws URISyntaxException {
- // create uri to put doc
- UriBuilder uriBuilder = new UriBuilder()
- .setSchemeAndAuthority("http://"+ServerConfiguration.SERVER_HOST+":"+ServerConfiguration.SERVER_PORT)
- .setXcapRoot(ServerConfiguration.SERVER_XCAP_ROOT+"/")
- .setDocumentSelector(getDocumentSelector());
- return uriBuilder.toURI();
- }
-
- protected String getTest1XcapContent() {
- return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
- "<resource-lists xmlns=\"urn:ietf:params:xml:ns:resource-lists\">" +
- "<list>" +
- "<entry uri=\""+appUsage.getAUID()+"/users/"+user+"/"+documentName+"\"/>" +
- "</list>" +
- "</resource-lists>";
- }
-
- protected void sendTest1XcapRequest() throws IOException, URISyntaxException {
- // ensure doc does not exists
- client.delete(getDocumentXcapURI(),getAssertedUserIdHeaders(client.getHeaderFactory(), user),null);
- // send put request and get response
- XcapResponse putResponse = client.put(getDocumentXcapURI(),appUsage.getMimetype(),getTest1XcapContent(),getAssertedUserIdHeaders(client.getHeaderFactory(), user),null);
- // check put response
- assertTrue("Put response must exists",putResponse != null);
- assertTrue("Put response code should be 200 or 201",putResponse.getCode() == 201 || putResponse.getCode() == 200);
- // set initial etag
- newEtag = putResponse.getETag();
- }
-
- protected void sendTest2XcapRequest() throws IOException, URISyntaxException {
- String content =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
- "<resource-lists xmlns=\"urn:ietf:params:xml:ns:resource-lists\">" +
- "<list/>" +
- "</resource-lists>";
-
- // send put request and get response
- XcapResponse putResponse = client.put(getDocumentXcapURI(),appUsage.getMimetype(),content,getAssertedUserIdHeaders(client.getHeaderFactory(), user),null);
-
- // check put response
- assertTrue("Put response must exists",putResponse != null);
- assertTrue("Put response code should be 200",putResponse.getCode() == 200);
-
- // set etags
- previousEtag = newEtag;
- newEtag = putResponse.getETag();
- }
-
- protected void sendTest3XcapRequest() throws IOException, URISyntaxException {
-
- // send put request and get response
- XcapResponse deleteResponse = client.delete(getDocumentXcapURI(),getAssertedUserIdHeaders(client.getHeaderFactory(), user),null);
-
- // set previous etag
- previousEtag = newEtag;
-
- // check put response
- assertTrue("Delete response must exists",deleteResponse != null);
- assertTrue("Delete response code should be 200",deleteResponse.getCode() == 200);
- }
- /**
- * puts a new doc through xcap, store etag of response and then subscribes doc through sip
- * @throws InvalidArgumentException
- * @throws ParseException
- * @throws SipException
- * @throws URISyntaxException
- */
- @Test
- public void test() throws HttpException, IOException, JAXBException, InterruptedException, ParseException, InvalidArgumentException, SipException, URISyntaxException {
-
- // set test state machine
- testRunning = Tests.test1;
-
- sendTest1XcapRequest();
-
- // send subscribe
- sendInitialSubscribe();
-
- // let's wait for test to succeed or timeout
- synchronized (this) {
- this.wait(15000);
- }
-
-
-
- assertTrue("Test timer expired (15 secs)",passed);
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private void sendInitialSubscribe() throws ParseException, InvalidArgumentException, SipException {
- // create >From Header
- Address address = addressFactory.createAddress(subscriberSipUri);
- FromHeader fromHeader = headerFactory.createFromHeader(
- address, Utils.getInstance().generateTag());
- // create To Header
- ToHeader toHeader = headerFactory.createToHeader(address,
- null);
- // Create ViaHeaders
- ArrayList viaHeaders = new ArrayList();
- int port = sipProvider.getListeningPoint(transport).getPort();
- ViaHeader viaHeader = headerFactory.createViaHeader(ServerConfiguration.SERVER_HOST,
- port, transport, null);
- viaHeaders.add(viaHeader);
- // Create a new CallId header
- CallIdHeader callIdHeader = sipProvider.getNewCallId();
- // Create a new Cseq header
- CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L,
- Request.SUBSCRIBE);
- // Create a new MaxForwardsHeader
- MaxForwardsHeader maxForwards = headerFactory
- .createMaxForwardsHeader(70);
- // Create the request.
- Request request = messageFactory.createRequest(address.getURI(),
- Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader,
- toHeader, viaHeaders, maxForwards);
-
- // Create contact headers
- SipURI contactURI = addressFactory.createSipURI(subscriberUsername, listeningPoint.getIPAddress());
- contactURI.setTransportParam(transport);
- contactURI.setPort(port);
- // add the contact address.
- Address contactAddress = addressFactory.createAddress(contactURI);
- // create and save contact header
- contactHeader = headerFactory.createContactHeader(contactAddress);
- request.addHeader(contactHeader);
- // add route
- request.addHeader(headerFactory.createRouteHeader(addressFactory
- .createAddress("<sip:"+ServerConfiguration.SERVER_HOST+":" + notifierPort
- + ";transport=" + transport + ";lr>")));
-
- // Create an event header for the subscription.
- EventHeader eventHeader = headerFactory.createEventHeader("xcap-diff");
- eventHeader.setParameter("diff-processing", "aggregate");
- request.addHeader(eventHeader);
- // add content
- request.setContent(getTest1XcapContent(), headerFactory.createContentTypeHeader("application", "resource-lists+xml"));
-
- // create the client transaction.
- ClientTransaction clientTransaction = sipProvider.getNewClientTransaction(request);
- // save the dialog
- this.subscriberDialog = clientTransaction.getDialog();
-
- // send the request out.
- clientTransaction.sendRequest();
-
- }
-
- protected XcapDiff processNotify(RequestEvent requestEvent) throws ParseException, SipException, InvalidArgumentException, JAXBException {
-
- Request notify = requestEvent.getRequest();
-
- javax.sip.message.Response response = messageFactory.createResponse(200, notify);
- // SHOULD add a Contact
- ContactHeader contact = (ContactHeader) contactHeader.clone();
- ((SipURI)contact.getAddress().getURI()).setParameter( "id", "sub" );
- response.addHeader( contact );
- requestEvent.getServerTransaction().sendResponse(response);
- SubscriptionStateHeader subscriptionState = (SubscriptionStateHeader) requestEvent.getRequest().getHeader(SubscriptionStateHeader.NAME);
- assertTrue("subscription not active", subscriptionState.getState().equalsIgnoreCase(SubscriptionStateHeader.ACTIVE));
-
- // unmarshall content
- StringReader stringReader = new StringReader(new String(requestEvent.getRequest().getRawContent()));
- XcapDiff xcapDiff = (XcapDiff) jaxbContext.createUnmarshaller().unmarshal(stringReader);
-
- assertTrue("unexpected xcap root in xcap diff",xcapDiff.getXcapRoot().equals("http://"+ServerConfiguration.SERVER_HOST+":"+ServerConfiguration.SERVER_PORT+ServerConfiguration.SERVER_XCAP_ROOT+"/"));
- stringReader.close();
-
- return xcapDiff;
- }
-
- /*
- * etag from xcap put response and notify must match.
- */
- protected void processTest1Notify(RequestEvent requestEvent) throws JAXBException, ParseException, SipException, InvalidArgumentException {
- XcapDiff xcapDiff = processNotify(requestEvent);
- assertTrue("not a single document element inside xcap diff document received", xcapDiff.getDocumentOrElementOrAttribute().size() == 1 && xcapDiff.getDocumentOrElementOrAttribute().get(0) instanceof DocumentType);
- DocumentType documentType = (DocumentType) xcapDiff.getDocumentOrElementOrAttribute().get(0);
- assertTrue("doc selector is not "+getDocumentSelector(), documentType.getSel() != null && documentType.getSel().equals(getDocumentSelector()));
- assertTrue("previous etag is set", documentType.getPreviousEtag() == null || documentType.getPreviousEtag().equals(""));
- assertTrue("new etag ("+documentType.getNewEtag()+") doesn't match one received in XCAP PUT response ("+newEtag+")", documentType.getNewEtag() != null && documentType.getNewEtag().equals(newEtag));
- }
- // ---- TEST 2
-
- private void doTest2() throws InterruptedException, HttpException, IOException, URISyntaxException {
- testRunning = Tests.test2;
- sendTest2XcapRequest();
- }
- protected void processTest2Notify(RequestEvent requestEvent) throws ParseException, SipException, InvalidArgumentException, JAXBException {
- XcapDiff xcapDiff = processNotify(requestEvent);
- assertTrue("not a single document element inside xcap diff document received", xcapDiff.getDocumentOrElementOrAttribute().size() == 1 && xcapDiff.getDocumentOrElementOrAttribute().get(0) instanceof DocumentType);
- DocumentType documentType = (DocumentType) xcapDiff.getDocumentOrElementOrAttribute().get(0);
- assertTrue("doc selector is not "+getDocumentSelector(), documentType.getSel() != null && documentType.getSel().equals(getDocumentSelector()));
- assertTrue("previous etag ("+documentType.getPreviousEtag()+") doesn't match one received in first XCAP PUT response ("+previousEtag+")", documentType.getPreviousEtag() != null && documentType.getPreviousEtag().equals(previousEtag));
- assertTrue("new etag ("+documentType.getNewEtag()+") doesn't match one received in XCAP PUT response ("+newEtag+")", documentType.getNewEtag() != null && documentType.getNewEtag().equals(newEtag));
- }
-
- // ---- TEST 3
-
- private void doTest3() throws InterruptedException, HttpException, IOException, URISyntaxException {
- testRunning = Tests.test3;
- sendTest3XcapRequest();
- }
- protected void processTest3Notify(RequestEvent requestEvent) throws ParseException, SipException, InvalidArgumentException, JAXBException {
- XcapDiff xcapDiff = processNotify(requestEvent);
- assertTrue("not a single document element inside xcap diff document received", xcapDiff.getDocumentOrElementOrAttribute().size() == 1 && xcapDiff.getDocumentOrElementOrAttribute().get(0) instanceof DocumentType);
- DocumentType documentType = (DocumentType) xcapDiff.getDocumentOrElementOrAttribute().get(0);
- assertTrue("doc selector is not "+getDocumentSelector(), documentType.getSel() != null && documentType.getSel().equals(getDocumentSelector()));
- assertTrue("previous etag doesn't match one received in second XCAP PUT response", documentType.getPreviousEtag() != null && documentType.getPreviousEtag().equals(previousEtag));
- assertTrue("new etag is not null", documentType.getNewEtag() == null);
- }
- // ---- TEST 4
-
- private void doTest4() throws ParseException, SipException, InvalidArgumentException {
- testRunning = Tests.test4;
- unsubscribe();
- }
- private void unsubscribe() throws ParseException, SipException, InvalidArgumentException {
-
- Request request = this.subscriberDialog
- .createRequest(Request.SUBSCRIBE);
- ToHeader toHeader = (ToHeader)request.getHeader(ToHeader.NAME);
- if (toHeader.getTag() == null) {
- toHeader.setTag(subscriberToTag);
- }
-
- // Create a new MaxForwardsHeader
- request.setHeader(headerFactory
- .createMaxForwardsHeader(70));
- // Create an event header for the subscription.
- EventHeader eventHeader = headerFactory.createEventHeader("xcap-diff");
- eventHeader.setParameter("diff-processing", "aggregate");
- request.addHeader(eventHeader);
- // add expires header
- request.setExpires(headerFactory.createExpiresHeader(0));
- // create client transaction
- ClientTransaction clientTransaction = sipProvider.getNewClientTransaction(request);
- // send request
- clientTransaction.sendRequest();
- }
-
- protected void processTest4Notify(RequestEvent requestEvent) throws ParseException, SipException, InvalidArgumentException, JAXBException {
-
- Request notify = requestEvent.getRequest();
-
- javax.sip.message.Response response = messageFactory.createResponse(200, notify);
- // SHOULD add a Contact
- ContactHeader contact = (ContactHeader) contactHeader.clone();
- ((SipURI)contact.getAddress().getURI()).setParameter( "id", "sub" );
- response.addHeader( contact );
- requestEvent.getServerTransaction().sendResponse(response);
-
- SubscriptionStateHeader subscriptionState = (SubscriptionStateHeader) requestEvent.getRequest().getHeader(SubscriptionStateHeader.NAME);
- assertTrue("subscription didn't terminate", subscriptionState.getState().equalsIgnoreCase(SubscriptionStateHeader.TERMINATED));
-
- }
-
- // --- METHODS TO PROCESS SIP REQUESTS AND RESPONSES
-
- public void processRequest(RequestEvent requestEvent) {
-
- System.out.println("Request rcvd {\n"+requestEvent.getRequest()+"\n}");
-
- Request request = requestEvent.getRequest();
-
- if (request.getMethod().equals(Request.NOTIFY)) {
-
- try {
- switch (testRunning) {
- case test1:
- processTest1Notify(requestEvent);
- semaphore.acquire();
- doTest2();
- semaphore.release();
- break;
- case test2:
- semaphore.acquire();
- processTest2Notify(requestEvent);
- doTest3();
- semaphore.release();
- break;
- case test3:
- processTest3Notify(requestEvent);
- doTest4();
- break;
-
- case test4:
- processTest4Notify(requestEvent);
- setTestResult(true);
- break;
- default:
- System.err.println("unknown test");
- setTestResult(false);
- }
- }
- catch(Exception e) {
- e.printStackTrace();
- setTestResult(false);
- }
-
- }
- }
- public void processResponse(ResponseEvent responseReceivedEvent) {
-
- System.out.println("Response received:\n" + responseReceivedEvent.getResponse());
- assertTrue("received response to subscribe which signals that subscription was not approved", responseReceivedEvent.getResponse().getStatusCode() == 200);
- if (subscriberToTag == null) {
- subscriberToTag = ((ToHeader)responseReceivedEvent.getResponse().getHeader(ToHeader.NAME)).getTag();
- }
- }
-
- // --- UNUSED SIP LISTENER METHODS
-
- public void processDialogTerminated(DialogTerminatedEvent arg0) {
- // TODO Auto-generated method stub
-
- }
- public void processIOException(IOExceptionEvent arg0) {
- throw new RuntimeException("processIOException(IOExceptionEvent"+arg0+")");
- }
- public void processTimeout(TimeoutEvent arg0) {
- throw new RuntimeException("processTimeout(TimeoutEvent="+arg0+")");
-
- }
- public void processTransactionTerminated(TransactionTerminatedEvent arg0) {
- // TODO Auto-generated method stub
-
- }
- // ---- TEST setup/cleanup
-
- @Before
- public void runBefore() throws IOException, InterruptedException, MalformedObjectNameException, InstanceNotFoundException, NullPointerException, MBeanException, ReflectionException, NamingException {
-
- super.user = subscriberSipUri;
-
- super.runBefore();
-
- try {
- // init sip stack
- notifierPort = "5060";
- transport = "udp";
- SipFactory sipFactory = SipFactory.getInstance();
- sipFactory.setPathName("gov.nist");
- Properties properties = new Properties();
- properties.setProperty("javax.sip.USE_ROUTER_FOR_ALL_URIS", "false");
- properties.setProperty("javax.sip.STACK_NAME", "subscriber");
- properties.setProperty("gov.nist.javax.sip.DEBUG_LOG",
- "subscriberdebug.txt");
- properties.setProperty("gov.nist.javax.sip.SERVER_LOG",
- "subscriberlog.txt");
- properties.setProperty("javax.sip.FORKABLE_EVENTS", "foo");
- // Set to 0 in your production code for max speed.
- // You need 16 for logging traces. 32 for debug + traces.
- // Your code will limp at 32 but it is best for debugging.
- properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "0");
- sipStack = sipFactory.createSipStack(properties);
- logger.info("createSipStack " + sipStack);
- headerFactory = sipFactory.createHeaderFactory();
- addressFactory = sipFactory.createAddressFactory();
- messageFactory = sipFactory.createMessageFactory();
-
- this.listeningPoint = sipStack.createListeningPoint(ServerConfiguration.SERVER_HOST, 6060,
- transport);
- sipProvider = sipStack.createSipProvider(listeningPoint);
- sipProvider.addSipListener(this);
- }
- catch (Exception e) {
- throw new RuntimeException("Unable to start sip stack. Exception msg: "+e.getMessage());
- }
- }
-
- @After
- public void runAfter() throws IOException, InstanceNotFoundException, MBeanException, ReflectionException {
-
- super.runAfter();
-
- try {
- sipProvider.removeSipListener(this);
- sipStack.deleteSipProvider(sipProvider);
- sipStack.deleteListeningPoint(listeningPoint);
- sipStack.stop();
- }
- catch (Exception e) {
- throw new RuntimeException("Unable to stop sip stack. Exception msg: "+e.getMessage());
- }
- }
-
- private boolean passed = false;
- /**
- * sets test result
- * @param result
- */
- protected void setTestResult(boolean result) {
- passed = result;
- synchronized (this) {
-
- this.notifyAll();
- }
- }
-
- // ------ JAXB resource lists and xcap diff context
-
- protected static final JAXBContext jaxbContext = initJAXBContext();
- private static JAXBContext initJAXBContext() {
- try {
- return JAXBContext.newInstance(
- "org.openxdm.xcap.common.xcapdiff" +
- ":org.openxdm.xcap.client.appusage.resourcelists.jaxb");
- } catch (JAXBException e) {
- logger.error("failed to create jaxb context");
- return null;
- }
- }
- }