Package org.eurekastreams.commons.client

Source Code of org.eurekastreams.commons.client.ActionProcessorImplTest

/*
* Copyright (c) 2009-2011 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.commons.client;

import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertSame;

import java.io.Serializable;
import java.util.logging.Logger;

import org.eurekastreams.commons.exceptions.SessionException;
import org.eurekastreams.server.testing.ParamInterceptor;
import org.eurekastreams.server.testing.TestHelper;
import org.jmock.Expectations;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Before;
import org.junit.Test;

import com.google.gwt.user.client.rpc.AsyncCallback;

/**
* Tests ActionProcessorImpl.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ActionProcessorImplTest
{
    /** Used for mocking objects. */
    private final JUnit4Mockery context = new JUnit4Mockery()
    {
        {
            setImposteriser(ClassImposteriser.INSTANCE);
        }
    };

    /** Test data: action key. */
    private static final String ACTION1 = "action1";

    /** Test data: action key. */
    private static final String ACTION2 = "action2";

    /** Test data: action key. */
    private static final String ACTION3 = "action3";

    /** Test data: action key. */
    private static final String ACTION4 = "action4";

    /** Test data: session ID. */
    private static final String SESSION_ID1 = "ABDEDB373";

    /** Test data: session ID. */
    private static final String SESSION_ID2 = "3983ABEDCFED";

    /** Action parameter. */
    private final Serializable param1 = context.mock(Serializable.class, "param1");

    /** Action parameter. */
    private final Serializable param2 = context.mock(Serializable.class, "param2");

    /** Action result. */
    private final Serializable result1 = context.mock(Serializable.class, "result1");

    /** Action result. */
    private final Serializable result2 = context.mock(Serializable.class, "result2");

    /** ActionRPCServiceAsync. */
    private final ActionRPCServiceAsync service = context.mock(ActionRPCServiceAsync.class);

    /** Fixture: session established callback. */
    private final AsyncCallback sessionCb = context.mock(AsyncCallback.class, "sessionCb");

    /** Fixture: action callback. */
    private final AsyncCallback actionCb1 = context.mock(AsyncCallback.class, "actionCb1");

    /** Fixture: action callback. */
    private final AsyncCallback actionCb2 = context.mock(AsyncCallback.class, "actionCb2");

    /** Parameter interceptor. */
    private final ParamInterceptor paramInt = new ParamInterceptor();

    /** Fixture: log. */
    private final Logger log = context.mock(Logger.class, "log");

    /** SUT. */
    private ActionProcessor sut;

    /*
     * Note: Many of the app callbacks are mocked to throw exceptions. This is done just to test the exception paths and
     * insure that a ill-behaved callback doesn't interfere with the proper behavior of the SUT.
     */

    /**
     * Test setup.
     *
     * @throws NoSuchFieldException
     *             Only if SUT changes its log.
     * @throws IllegalAccessException
     *             Shouldn't.
     * @throws IllegalArgumentException
     *             Shouldn't.
     */
    @Before
    public final void setUp() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException
    {
        sut = new ActionProcessorImpl(service, sessionCb);
        TestHelper.setPrivateField(sut, "log", log);
        context.checking(new Expectations()
        {
            {
                // mock logger and ignore log calls to keep errors from spilling into the output and looking like
                // something actually went wrong. Would be ideal if the mock could be configured to ignore any
                // trace/debug logging, but have expectations that some other logging would be done (but without
                // specifying exactly which logging method is used) when a callback throws an exception.
                ignoring(log);
            }
        });
    }

    /**
     * Tests a normal startup sequence: send 2 messages before a session is established, everything succeeds.
     */
    @Test
    public void testNormalStartup()
    {
        sut.setQueueRequests(true);
        sut.makeRequest(ACTION1, param1, actionCb1);
        sut.makeRequest(ACTION2, param2, actionCb2);

        context.checking(new Expectations()
        {
            {
                oneOf(service).establishSession(with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        sut.setQueueRequests(false);
        context.assertIsSatisfied();

        AsyncCallback<String> serviceSessionCb = (AsyncCallback<String>) paramInt.getParam(0);
        context.checking(new Expectations()
        {
            {
                oneOf(sessionCb).onSuccess(SESSION_ID1);
                will(throwException(new RuntimeException("Naughty callback")));

                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });

        serviceSessionCb.onSuccess(SESSION_ID1);
        context.assertIsSatisfied();

        ActionRequest[] requests = (ActionRequest[]) paramInt.getParam(0);
        AsyncCallback serviceExecCb = (AsyncCallback) paramInt.getParam(1);

        assertEquals(2, requests.length);
        assertEquals(ACTION1, requests[0].getActionKey());
        assertSame(param1, requests[0].getParam());
        assertEquals(SESSION_ID1, requests[0].getSessionId());
        assertEquals(ACTION2, requests[1].getActionKey());
        assertSame(param2, requests[1].getParam());
        assertEquals(SESSION_ID1, requests[1].getSessionId());

        ActionRequest[] results = new ActionRequest[] { new ActionResponse(requests[0], result1),
                new ActionResponse(requests[1], result2) };

        context.checking(new Expectations()
        {
            {
                oneOf(actionCb1).onSuccess(with(same(result1)));
                will(throwException(new RuntimeException("Naughty callback")));
                oneOf(actionCb2).onSuccess(with(same(result2)));
                will(throwException(new RuntimeException("Naughty callback")));
            }
        });

        serviceExecCb.onSuccess(results);
        context.assertIsSatisfied();
    }

    /**
     * Tests losing a session and re-establishing it. Test adds an extra wrinkle by having the service reject the first
     * attempt to re-establish.
     *
     * @throws IllegalAccessException
     *             Shouldn't.
     * @throws IllegalArgumentException
     *             Shouldn't.
     * @throws NoSuchFieldException
     *             Only if test is out of date.
     * @throws SecurityException
     *             Shouldn't.
     */
    @Test
    public void testLoseSession() throws IllegalArgumentException, IllegalAccessException, SecurityException,
            NoSuchFieldException
    {
        // cheat and set the session ID directly in the SUT to set up the initial state
        TestHelper.setPrivateField(sut, "sessionId", SESSION_ID1);

        // -- try to make request, but service will throw session exception --
        context.checking(new Expectations()
        {
            {
                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        sut.makeRequest(ACTION1, param1, actionCb1);
        context.assertIsSatisfied();

        // -- SUT should ask service to establish new session --
        ActionRequest[] requests = (ActionRequest[]) paramInt.getParam(0);
        AsyncCallback serviceExecCb = (AsyncCallback) paramInt.getParam(1);

        context.checking(new Expectations()
        {
            {
                oneOf(service).establishSession(with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        serviceExecCb.onSuccess(new ActionRequest[] { new ActionResponse(requests[0], new SessionException()) });
        context.assertIsSatisfied();

        // -- service replies with error. SUT should notify app --
        AsyncCallback<String> serviceSessionCb = (AsyncCallback<String>) paramInt.getParam(0);
        final Exception ex = new Exception("Can it handle it?");
        context.checking(new Expectations()
        {
            {
                oneOf(sessionCb).onFailure(with(equal(ex)));
                will(throwException(new RuntimeException("Naughty callback")));
            }
        });
        serviceSessionCb.onFailure(ex);
        context.assertIsSatisfied();

        // -- app asks SUT to try again --
        context.checking(new Expectations()
        {
            {
                oneOf(service).establishSession(with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        sut.fireQueuedRequests();
        context.assertIsSatisfied();

        // -- service replies with success. SUT should notify app and then send the messages --
        serviceSessionCb = (AsyncCallback<String>) paramInt.getParam(0);
        context.checking(new Expectations()
        {
            {
                oneOf(sessionCb).onSuccess(SESSION_ID2);
                will(throwException(new RuntimeException("Naughty callback")));

                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        serviceSessionCb.onSuccess(SESSION_ID2);
        context.assertIsSatisfied();

        requests = (ActionRequest[]) paramInt.getParam(0);

        assertEquals(1, requests.length);
        assertEquals(ACTION1, requests[0].getActionKey());
        assertSame(param1, requests[0].getParam());
        assertEquals(SESSION_ID2, requests[0].getSessionId());
    }

    /**
     * Tests session loss when multiple requests are out at once.
     *
     * @throws NoSuchFieldException
     *             Shouldn't.
     * @throws IllegalAccessException
     *             Shouldn't.
     * @throws IllegalArgumentException
     *             Shouldn't.
     */
    @Test
    public void testMultipleOutstandingRequests() throws IllegalArgumentException, IllegalAccessException,
            NoSuchFieldException
    {
        // cheat and set the session ID directly in the SUT to set up the initial state
        TestHelper.setPrivateField(sut, "sessionId", SESSION_ID1);

        final Serializable param01 = context.mock(Serializable.class, "param01");
        final Serializable param02 = context.mock(Serializable.class, "param02");
        final Serializable param03 = context.mock(Serializable.class, "param03");
        final Serializable param04 = context.mock(Serializable.class, "param04");
        final Serializable result01 = context.mock(Serializable.class, "result01");
        final Serializable result02 = context.mock(Serializable.class, "result02");
        final Serializable result03 = context.mock(Serializable.class, "result03");
        final Serializable result04 = context.mock(Serializable.class, "result04");
        final AsyncCallback actionCb01 = context.mock(AsyncCallback.class, "actionCb01");
        final AsyncCallback actionCb02 = context.mock(AsyncCallback.class, "actionCb02");
        final AsyncCallback actionCb03 = context.mock(AsyncCallback.class, "actionCb03");
        final AsyncCallback actionCb04 = context.mock(AsyncCallback.class, "actionCb04");
        final ParamInterceptor paramInt01 = new ParamInterceptor();
        final ParamInterceptor paramInt02 = new ParamInterceptor();
        final ParamInterceptor paramInt03 = new ParamInterceptor();
        final ParamInterceptor paramInt04 = new ParamInterceptor();

        // -- send out a few requests --
        context.checking(new Expectations()
        {
            {
                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt01);
                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt02);
                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt03);
                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt04);
            }
        });
        sut.makeRequest(ACTION1, param01, actionCb01);
        sut.makeRequest(ACTION2, param02, actionCb02);
        sut.makeRequest(ACTION3, param03, actionCb03);
        sut.makeRequest(ACTION4, param04, actionCb04);
        context.assertIsSatisfied();

        // -- make 1, 2, 4 fail with a session exception; 3 will succeed. once all are back, SUT should request session.
        // out of order on purpose. --
        // 1 fails
        ((AsyncCallback) paramInt01.getParam(1)).onSuccess(new ActionRequest[] { new ActionResponse(
                ((ActionRequest[]) paramInt01.getParam(0))[0], new SessionException()) });
        // 4 fails
        ((AsyncCallback) paramInt04.getParam(1)).onSuccess(new ActionRequest[] { new ActionResponse(
                ((ActionRequest[]) paramInt04.getParam(0))[0], new SessionException()) });
        // 3 succeeds
        context.checking(new Expectations()
        {
            {
                oneOf(actionCb03).onSuccess(with(same(result03)));
            }
        });
        ((AsyncCallback) paramInt03.getParam(1)).onSuccess(new ActionRequest[] { new ActionResponse(
                ((ActionRequest[]) paramInt03.getParam(0))[0], result03) });
        context.assertIsSatisfied();
        // 2 fails. since it's the last outstanding, the return will trigger re-establishment
        context.checking(new Expectations()
        {
            {
                oneOf(service).establishSession(with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        ((AsyncCallback) paramInt02.getParam(1)).onSuccess(new ActionRequest[] { new ActionResponse(
                ((ActionRequest[]) paramInt02.getParam(0))[0], new SessionException()) });
        context.assertIsSatisfied();

        // -- establishing new session should send request for all 3 that failed in one message --
        context.checking(new Expectations()
        {
            {
                oneOf(sessionCb).onSuccess(SESSION_ID2);
                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        ((AsyncCallback) paramInt.getParam(0)).onSuccess(SESSION_ID2);
        context.assertIsSatisfied();

        ActionRequest[] requests = (ActionRequest[]) paramInt.getParam(0);

        assertEquals(3, requests.length);
        assertEquals(ACTION1, requests[0].getActionKey());
        assertSame(param01, requests[0].getParam());
        assertEquals(SESSION_ID2, requests[0].getSessionId());
        assertEquals(ACTION2, requests[1].getActionKey());
        assertSame(param02, requests[1].getParam());
        assertEquals(SESSION_ID2, requests[1].getSessionId());
        assertEquals(ACTION4, requests[2].getActionKey());
        assertSame(param04, requests[2].getParam());
        assertEquals(SESSION_ID2, requests[2].getSessionId());

        // -- reply to all messages to insure callbacks working --

        context.checking(new Expectations()
        {
            {
                oneOf(actionCb01).onSuccess(with(same(result01)));
                oneOf(actionCb02).onSuccess(with(same(result02)));
                oneOf(actionCb04).onSuccess(with(same(result04)));
            }
        });
        ActionRequest[] results = new ActionRequest[] { new ActionResponse(requests[0], result01),
                new ActionResponse(requests[1], result02), new ActionResponse(requests[2], result04) };
        ((AsyncCallback) paramInt.getParam(1)).onSuccess(results);
        context.assertIsSatisfied();
    }

    /**
     * Tests that callbacks are not required. Use same basic scenario as startup test.
     *
     * @throws NoSuchFieldException
     *             Only if SUT changes its log.
     * @throws IllegalAccessException
     *             Shouldn't.
     * @throws IllegalArgumentException
     *             Shouldn't.
     */
    @Test
    public void testNoCallbacks() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException
    {
        sut = new ActionProcessorImpl(service, null);
        TestHelper.setPrivateField(sut, "log", log);

        // -- send over messages with no session set. SUT should request a session --
        sut.setQueueRequests(true);
        sut.makeRequest(ACTION1, param1, null);
        sut.makeRequest(ACTION2, param2, null);
        context.checking(new Expectations()
        {
            {
                oneOf(service).establishSession(with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        sut.setQueueRequests(false);
        context.assertIsSatisfied();

        // -- have server reject the request --
        ((AsyncCallback) paramInt.getParam(0)).onFailure(new Exception());

        // -- make SUT try again --
        context.checking(new Expectations()
        {
            {
                oneOf(service).establishSession(with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        sut.fireQueuedRequests();
        context.assertIsSatisfied();

        // -- accept this time. SUT should send messages --
        context.checking(new Expectations()
        {
            {
                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        ((AsyncCallback) paramInt.getParam(0)).onSuccess(SESSION_ID1);
        context.assertIsSatisfied();

        // -- reply to messages - one success and one failure --
        ActionRequest[] requests = (ActionRequest[]) paramInt.getParam(0);
        ActionRequest[] results = new ActionRequest[] { new ActionResponse(requests[0], new Exception()),
                new ActionResponse(requests[1], result2) };
        ((AsyncCallback) paramInt.getParam(1)).onSuccess(results);

        // -- try to send messages; there should be none. --
        sut.fireQueuedRequests();
    }

    /**
     * Tests some additional session establishment request cases, such as exceptions trying to send a message, and
     * sending multiple session requests.
     *
     * @throws IllegalAccessException
     *             Shouldn't.
     * @throws IllegalArgumentException
     *             Shouldn't.
     * @throws NoSuchFieldException
     *             Only if test is out of date.
     * @throws SecurityException
     *             Shouldn't.
     */
    @Test
    public void testSomeAdditionalSessionRequestCases() throws IllegalArgumentException, IllegalAccessException,
            SecurityException, NoSuchFieldException
    {
        // cheat and set the session ID directly in the SUT to set up the initial state
        TestHelper.setPrivateField(sut, "sessionId", SESSION_ID1);

        // -- try to make request, but service will throw session exception --
        context.checking(new Expectations()
        {
            {
                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        sut.makeRequest(ACTION1, param1, actionCb1);
        context.assertIsSatisfied();

        // -- return a session exception - SUT should ask service to establish new session, but have service throw an
        // exception - SUT should tell app --
        ActionRequest[] requests = (ActionRequest[]) paramInt.getParam(0);
        AsyncCallback serviceExecCb = (AsyncCallback) paramInt.getParam(1);

        final Exception ex1 = new RuntimeException("What will it do?");
        context.checking(new Expectations()
        {
            {
                oneOf(service).establishSession(with(any(AsyncCallback.class)));
                will(throwException(ex1));

                oneOf(sessionCb).onFailure(with(equal(ex1)));
            }
        });
        serviceExecCb.onSuccess(new ActionRequest[] { new ActionResponse(requests[0], new SessionException()) });
        context.assertIsSatisfied();

        // -- app asks SUT to try again --
        context.checking(new Expectations()
        {
            {
                oneOf(service).establishSession(with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        sut.fireQueuedRequests();
        context.assertIsSatisfied();

        // -- app gets impatient and asks SUT to try again again - SUT should do nothing --
        sut.fireQueuedRequests();

        // -- service replies with success. SUT should notify app and then send the messages --
        AsyncCallback<String> serviceSessionCb = (AsyncCallback<String>) paramInt.getParam(0);
        context.checking(new Expectations()
        {
            {
                oneOf(sessionCb).onSuccess(SESSION_ID2);

                oneOf(service).execute((ActionRequest[]) with(anything()), with(any(AsyncCallback.class)));
                will(paramInt);
            }
        });
        serviceSessionCb.onSuccess(SESSION_ID2);
        context.assertIsSatisfied();

        requests = (ActionRequest[]) paramInt.getParam(0);

        assertEquals(1, requests.length);
        assertEquals(ACTION1, requests[0].getActionKey());
        assertSame(param1, requests[0].getParam());
        assertEquals(SESSION_ID2, requests[0].getSessionId());


        // -- server replies with wrong id - SUT should do nothing. --
        ActionResponse result = new ActionResponse(requests[0], "Ha ha!");
        result.setId((result.getId() + 9) * 9);
        ((AsyncCallback) paramInt.getParam(1)).onSuccess(new ActionRequest[] { result
                 });
    }

    /**
     * Concrete class for testing.
     */
    static class ActionResponse implements ActionRequest
    {
        /** id. */
        int id;
        /** actionKey. */
        String actionKey;
        /** param. */
        Serializable param;
        /** response. */
        Serializable response;
        /** sessionId. */
        String sessionId;

        /**
         * Quasi-copy constructor (behaves generally like the server).
         *
         * @param orig
         *            Request to "clone".
         * @param inResponse
         *            Response.
         */
        public ActionResponse(final ActionRequest orig, final Serializable inResponse)
        {
            id = orig.getId();
            actionKey = orig.getActionKey();
            response = inResponse;
            sessionId = orig.getSessionId();
        }

        /**
         * @return the id
         */
        public int getId()
        {
            return id;
        }

        /**
         * @param inId
         *            the id to set
         */
        public void setId(final int inId)
        {
            id = inId;
        }

        /**
         * @return the actionKey
         */
        public String getActionKey()
        {
            return actionKey;
        }

        /**
         * @param inActionKey
         *            the actionKey to set
         */
        public void setActionKey(final String inActionKey)
        {
            actionKey = inActionKey;
        }

        /**
         * @return the param
         */
        public Serializable getParam()
        {
            return param;
        }

        /**
         * @param inParam
         *            the param to set
         */
        public void setParam(final Serializable inParam)
        {
            param = inParam;
        }

        /**
         * @return the response
         */
        public Serializable getResponse()
        {
            return response;
        }

        /**
         * @param inResponse
         *            the response to set
         */
        public void setResponse(final Serializable inResponse)
        {
            response = inResponse;
        }

        /**
         * @return the sessionId
         */
        public String getSessionId()
        {
            return sessionId;
        }

        /**
         * @param inSessionId
         *            the sessionId to set
         */
        public void setSessionId(final String inSessionId)
        {
            sessionId = inSessionId;
        }
    }

}
TOP

Related Classes of org.eurekastreams.commons.client.ActionProcessorImplTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.