Package de.javakaffee.web.msm.integration

Source Code of de.javakaffee.web.msm.integration.TestUtils

/*
* Copyright 2009 Martin Grotzke
*
* 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 de.javakaffee.web.msm.integration;

import static de.javakaffee.web.msm.Configurations.NODE_AVAILABILITY_CACHE_TTL_KEY;
import static de.javakaffee.web.msm.integration.TestUtils.Predicates.elementAt;
import static de.javakaffee.web.msm.integration.TestUtils.Predicates.notNull;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.Currency;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.LogManager;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;

import net.spy.memcached.MemcachedClient;

import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.core.StandardService;
import org.apache.catalina.loader.WebappLoader;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.apache.juli.logging.LogFactory;
import org.jboss.netty.buffer.ChannelBuffers;
import org.testng.Assert;
import org.testng.annotations.DataProvider;

import com.thimbleware.jmemcached.CacheElement;
import com.thimbleware.jmemcached.CacheImpl;
import com.thimbleware.jmemcached.Key;
import com.thimbleware.jmemcached.LocalCacheElement;
import com.thimbleware.jmemcached.MemCacheDaemon;
import com.thimbleware.jmemcached.storage.hash.ConcurrentLinkedHashMap;
import com.thimbleware.jmemcached.storage.hash.ConcurrentLinkedHashMap.EvictionPolicy;

import de.javakaffee.web.msm.MemcachedBackupSession;
import de.javakaffee.web.msm.MemcachedSessionService;

/**
* Integration test utils.
*
* @param <T> The type of {@link TomcatBuilder}, returned by {@link #tomcatBuilder()}.
*
* @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a>
*/
public abstract class TestUtils<T extends TomcatBuilder<?>> {

    private static final String CONTEXT_PATH = "/";
    private static final String DEFAULT_HOST = "localhost";

    protected static final String PASSWORD = "secret";
    protected static final String USER_NAME = "testuser";
    protected static final String ROLE_NAME = "test";

    public static final String STICKYNESS_PROVIDER = "stickynessProvider";
    public static final String BOOLEAN_PROVIDER = "booleanProvider";

    static {
        initLogConfig(TestUtils.class);
        System.setProperty(NODE_AVAILABILITY_CACHE_TTL_KEY, "50");
    }

    public static void initLogConfig(@SuppressWarnings("rawtypes") final Class<? extends TestUtils> clazz) {
        final URL loggingProperties = clazz.getResource("/logging.properties");
        try {
            System.setProperty("java.util.logging.config.file", new File(loggingProperties.toURI()).getAbsolutePath());
        } catch (final Exception e) {
            // we don't have a plain file (e.g. the case for msm-kryo-serializer etc), so we can skip reading the config
            return;
        }
        try {
            LogManager.getLogManager().readConfiguration();
        } catch (final Exception e) {
            LogFactory.getLog( TestUtils.class ).error("Could not init logging configuration.", e);
        }
    }

    /**
     * Login using form based auth and return the session id.
     */
    public static String loginWithForm(final DefaultHttpClient client, final int tcPort) throws IOException, HttpException {
        final Response tc1Response1 = get( client, tcPort, null );
        final String sessionId = tc1Response1.getSessionId();
        assertNotNull( sessionId );
        assertTrue(tc1Response1.getContent().contains("j_security_check"), "/j_security_check not found, app is not properly initialized");

        final Map<String, String> params = new HashMap<String, String>();
        params.put( LoginServlet.J_USERNAME, TestUtils.USER_NAME );
        params.put( LoginServlet.J_PASSWORD, TestUtils.PASSWORD );
        final Response tc1Response2 = post( client, tcPort, "/j_security_check", sessionId, params );
        assertEquals(tc1Response2.getSessionId(), sessionId);
        new RuntimeException("err").printStackTrace();
        assertEquals( tc1Response2.get( TestServlet.ID ), sessionId );

        return tc1Response2.getSessionId();
    }

    public static String makeRequest( final HttpClient client, final int port, final String rsessionId ) throws IOException,
            HttpException {
        // System.out.println( port + " >>>>>>>>>>>>>>>>>> Client Starting >>>>>>>>>>>>>>>>>>>>");
        String responseSessionId;
        final HttpGet method = new HttpGet("http://"+ DEFAULT_HOST +":"+ port + CONTEXT_PATH);
        if ( rsessionId != null ) {
            method.setHeader( "Cookie", "JSESSIONID=" + rsessionId );
        }

        // System.out.println( "cookies: " + method.getParams().getCookiePolicy() );
        //method.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
        final HttpResponse response = client.execute( method );

        if ( response.getStatusLine().getStatusCode() != 200 ) {
            throw new RuntimeException( "GET did not return status 200, but " + response.getStatusLine() );
        }

        // System.out.println( ">>>>>>>>>>: " + method.getResponseBodyAsString() );
        responseSessionId = getSessionIdFromResponse( response );
        // System.out.println( "response cookie: " + responseSessionId );

        // We must consume the content so that the connection will be released
        EntityUtils.consume(response.getEntity());

        return responseSessionId == null ? rsessionId : responseSessionId;
    }

    public static Response get( final DefaultHttpClient client, final int port, final String rsessionId )
        throws IOException, HttpException {
        return get( client, port, null, rsessionId );
    }

    public static Response get( final DefaultHttpClient client, final int port, final String rsessionId,
            final Credentials credentials )
        throws IOException, HttpException {
        return get( client, port, null, rsessionId, null, null, credentials );
    }

    public static Response get( final DefaultHttpClient client, final int port, final String path, final String rsessionId ) throws IOException,
            HttpException {
        return get( client, port, path, rsessionId, null, null, null );
    }

    public static Response get( final DefaultHttpClient client, final int port, final String path, final String rsessionId,
            final Map<String, String> params ) throws IOException,
            HttpException {
        return get( client, port, path, rsessionId, null, params, null );
    }

    public static Response get( final DefaultHttpClient client, final int port, final String path, final String rsessionId,
            final SessionTrackingMode sessionTrackingMode,
            final Map<String, String> params,
            final Credentials credentials ) throws IOException,
            HttpException {
        // System.out.println( port + " >>>>>>>>>>>>>>>>>> Client Starting >>>>>>>>>>>>>>>>>>>>");
        String url = getUrl( port, path );
        if ( params != null && !params.isEmpty() ) {
            url += toQueryString( params );
        }
        if ( rsessionId != null && sessionTrackingMode == SessionTrackingMode.URL ) {
            url += ";jsessionid=" + rsessionId;
        }
        final HttpGet method = new HttpGet( url );
        if ( rsessionId != null && sessionTrackingMode == SessionTrackingMode.COOKIE ) {
            method.setHeader( "Cookie", "JSESSIONID=" + rsessionId );
        }

        final HttpResponse response = credentials == null
            ? client.execute( method )
            : executeRequestWithAuth( client, method, credentials );

        if ( response.getStatusLine().getStatusCode() != 200 ) {
            throw new RuntimeException( "GET "+ path +" did not return status 200, but " + response.getStatusLine() );
        }

        return readResponse( rsessionId, response );
    }

    private static String getUrl( final int port, String path ) throws IllegalArgumentException {
        // we assume the context_path is "/"
        if ( path != null && !path.startsWith( "/" ) ) {
            // but we can also fix this
            path = CONTEXT_PATH + path;
        }
        return "http://"+ DEFAULT_HOST +":"+ port + ( path != null ? path : CONTEXT_PATH );
    }

    /**
     * @param params
     * @return
     */
    private static String toQueryString( final Map<String, String> params ) {
        final StringBuilder sb = new StringBuilder();
        sb.append( "?" );
        for ( final Iterator<Entry<String, String>> iterator = params.entrySet().iterator(); iterator.hasNext(); ) {
            final Entry<String, String> entry = iterator.next();
            sb.append( entry.getKey() ).append( "=" ).append( entry.getValue() );
            if ( iterator.hasNext() ) {
                sb.append( "&" );
            }
        }
        final String qs = sb.toString();
        return qs;
    }

    private static HttpResponse executeRequestWithAuth( final DefaultHttpClient client, final HttpUriRequest method,
            final Credentials credentials ) throws IOException, ClientProtocolException {
        client.getCredentialsProvider().setCredentials( AuthScope.ANY, credentials );

        final BasicHttpContext localcontext = new BasicHttpContext();

        // Generate BASIC scheme object and stick it to the local
        // execution context
        final BasicScheme basicAuth = new BasicScheme();
        localcontext.setAttribute( "preemptive-auth", basicAuth );

        // System.out.println( "cookies: " + method.getParams().getCookiePolicy() );
        //method.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
        return client.execute( method, localcontext );
    }

    private static Response readResponse( final String rsessionId, final HttpResponse response ) throws IOException {
        final String responseSessionId = getSessionIdFromResponse( response );
        // System.out.println( "response cookie: " + responseSessionId );

        final StringBuilder sb = new StringBuilder();
        final Map<String, String> keyValues = new LinkedHashMap<String, String>();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader( new InputStreamReader( response.getEntity().getContent() ) );
            String line = null;
            while ( ( line = reader.readLine() ) != null ) {
                sb.append(line);
                final String[] keyValue = line.split( "=" );
                if ( keyValue.length > 0 ) {
                    keyValues.put( keyValue[0], keyValue.length > 1 ? keyValue[1] : null );
                }
            }
        } finally {
            if(reader != null) {
                reader.close();
            }
        }

        return new Response( response, responseSessionId == null ? rsessionId : responseSessionId, responseSessionId, sb.toString(), keyValues );
    }

    public static Response post( final DefaultHttpClient client,
            final int port,
            final String rsessionId,
            final String paramName,
            final String paramValue ) throws IOException, HttpException {
        final Map<String, String> params = new HashMap<String, String>();
        params.put( paramName, paramValue );
        return post( client, port, null, rsessionId, params );
    }

    public static Response post( final DefaultHttpClient client,
            final int port,
            final String path,
            final String rsessionId,
            final Map<String, String> params ) throws IOException, HttpException {
        return post( client, port, path, rsessionId, params, null, true );
    }

    public static Response post( final DefaultHttpClient client,
            final int port,
            final String path,
            final String rsessionId,
            final Map<String, String> params,
            @Nullable final Credentials credentials,
            final boolean followRedirects ) throws IOException, HttpException {
        // System.out.println( port + " >>>>>>>>>>>>>>>>>> Client Starting >>>>>>>>>>>>>>>>>>>>");
        final String baseUri = "http://"+ DEFAULT_HOST +":"+ port;
        final String url = getUrl( port, path );
        final HttpPost method = new HttpPost( url );
        if ( rsessionId != null ) {
            method.setHeader( "Cookie", "JSESSIONID=" + rsessionId );
        }

        method.setEntity( createFormEntity( params ) );

        // For 303 httpclient automatically redirects, so let's prevent this if requested.
        if (!followRedirects) {
            HttpClientParams.setRedirecting(method.getParams(), false);
        }

        // System.out.println( "cookies: " + method.getParams().getCookiePolicy() );
        //method.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
        final HttpResponse response = credentials == null
            ? client.execute( method )
            : executeRequestWithAuth( client, method, credentials );

        final int statusCode = response.getStatusLine().getStatusCode();
        if ( followRedirects && isRedirect(statusCode) ) {
            return redirect( response, client, port, rsessionId, baseUri );
        }

        if ( statusCode != 200 && !(!followRedirects && isRedirect(statusCode)) ) {
            throw new RuntimeException( "POST"+(path != null ? " " + path : "")+" did not return status 200, but " + response.getStatusLine() +
                    "\n" + toString(response.getEntity().getContent()) );
        }

        return readResponse( rsessionId, response );
    }

    public static boolean isRedirect(final int statusCode) {
        return statusCode == 302 || statusCode == 303;
    }

    public static String toString(final InputStream in) {
        final StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader( new InputStreamReader( in ) );
            String line = null;
            while ( ( line = reader.readLine() ) != null ) {
                sb.append(line);
            }
        } catch (final IOException e) {
            throw new RuntimeException(e);
        } finally {
            if(reader != null) {
                try { reader.close(); } catch (final IOException e) {/* ignore */}
            }
        }
        return sb.toString();
    }

    private static Response redirect( final HttpResponse response, final DefaultHttpClient client, final int port,
            final String rsessionId, final String baseUri ) throws IOException, HttpException {
        final String location = response.getFirstHeader( "Location" ).getValue();
        if ( !location.startsWith( baseUri ) ) {
            throw new RuntimeException( "There's s.th. wrong, the location header should start with the base URI " + baseUri +
                    ". The location header: " + location );
        }
        /* consume content so that the connection can be released
         */
        EntityUtils.consume(response.getEntity());

        /* redirect
         */
        final String redirectPath = location.substring( baseUri.length(), location.length() );
        return get( client, port, redirectPath, rsessionId );
    }

    private static UrlEncodedFormEntity createFormEntity( final Map<String, String> params ) throws UnsupportedEncodingException {
        final List<NameValuePair> parameters = new ArrayList <NameValuePair>();
        for( final Map.Entry<String, String> param : params.entrySet() ) {
            parameters.add( new BasicNameValuePair( param.getKey(), param.getValue() ) );
        }
        final UrlEncodedFormEntity entity = new UrlEncodedFormEntity( parameters, HTTP.UTF_8 );
        return entity;
    }

    public static String getSessionIdFromResponse( final HttpResponse response ) {
        final Header cookie = response.getFirstHeader( "Set-Cookie" );
        if ( cookie != null ) {
            for ( final HeaderElement header : cookie.getElements() ) {
                if ( "JSESSIONID".equals( header.getName() ) ) {
                    return header.getValue();
                }
            }
        }
        return null;
    }

    public static StandardContext createContext() {
        final StandardEngine engine = new StandardEngine();
        engine.setService( new StandardService() );

        final StandardContext context = new StandardContext();
        context.setPath( "/" );
        context.setSessionCookiePath( "/" );

        final WebappLoader webappLoader = new WebappLoader() {
            @Override
            public ClassLoader getClassLoader() {
                return Thread.currentThread().getContextClassLoader();
            }
        };
        context.setLoader( webappLoader );

        final StandardHost host = new StandardHost();
        engine.addChild( host );
        host.addChild( context );

        return context;
    }

    public static MemCacheDaemon<? extends CacheElement> createDaemon( final InetSocketAddress address ) throws IOException {
        final MemCacheDaemon<LocalCacheElement> daemon = new MemCacheDaemon<LocalCacheElement>();
        final ConcurrentLinkedHashMap<Key, LocalCacheElement> cacheStorage = ConcurrentLinkedHashMap.create(
                EvictionPolicy.LRU, 100000, 1024*1024 );
        daemon.setCache( new CacheImpl( cacheStorage ) );
        daemon.setAddr( address );
        daemon.setVerbose( true );
        return daemon;
    }

    /**
     * Must create a {@link TomcatBuilder} for the current tomcat version.
     */
    public abstract T tomcatBuilder();

    public static enum LoginType {
        BASIC, FORM
    }

    /**
     * A helper class for a response with a body containing key=value pairs
     * each in one line.
     */
    public static class Response {

        private final String _sessionId;
        private final String _responseSessionId;
        private final String _content;
        private final Map<String, String> _keyValues;
        private final HttpResponse _response;
        public Response( final HttpResponse response, final String sessionId, final String responseSessionId, final String content, final Map<String, String> keyValues ) {
            _response = response;
            _sessionId = sessionId;
            _responseSessionId = responseSessionId;
            _content = content;
            _keyValues = keyValues;
        }
        public int getStatusCode() {
            return _response.getStatusLine().getStatusCode();
        }
        public String getHeader(final String name) {
           final Header header = _response.getFirstHeader(name);
           return header == null ? null : header.getValue();
        }
        public String getSessionId() {
            return _sessionId;
        }
        public String getResponseSessionId() {
            return _responseSessionId;
        }
        public String getContent() {
            return _content;
        }
        public Map<String, String> getKeyValues() {
            return _keyValues;
        }
        public String get( final String key ) {
            return _keyValues.get( key );
        }

    }

    /**
     * Extracts the memcached node id from the provided session id.
     * @param sessionId the session id, that may contain the node id, e.g. as <code>${origsessionid}-${nodeid}</code>
     * @return the extracted node id or <code>null</code>, if no node information was found.
     */
    public static String extractNodeId( final String sessionId ) {
        final int idx = sessionId.lastIndexOf( '-' );
        return idx > -1 ? sessionId.substring( idx + 1 ) : null;
    }

    public static void assertDeepEquals( final Object one, final Object another ) {
        assertDeepEquals( one, another, new IdentityHashMap<Object, Object>() );
    }

    public static void assertDeepEquals( final Object one, final Object another, final Map<Object, Object> alreadyChecked ) {
        if ( one == another ) {
            return;
        }
        if ( one == null && another != null || one != null && another == null ) {
            Assert.fail( "One of both is null: " + one + ", " + another );
        }
        if ( alreadyChecked.containsKey( one ) ) {
            return;
        }
        alreadyChecked.put( one, another );

        Assert.assertEquals( one.getClass(), another.getClass() );
        if ( one.getClass().isPrimitive() || one instanceof String || one instanceof Character || one instanceof Boolean ) {
            Assert.assertEquals( one, another );
            return;
        }

        if ( Map.class.isAssignableFrom( one.getClass() ) ) {
            final Map<?, ?> m1 = (Map<?, ?>) one;
            final Map<?, ?> m2 = (Map<?, ?>) another;
            Assert.assertEquals( m1.size(), m2.size() );
            for ( final Map.Entry<?, ?> entry : m1.entrySet() ) {
                assertDeepEquals( entry.getValue(), m2.get( entry.getKey() ) );
            }
            return;
        }

        if ( Set.class.isAssignableFrom( one.getClass() ) ) {
            final Set<?> m1 = (Set<?>) one;
            final Set<?> m2 = (Set<?>) another;
            Assert.assertEquals( m1.size(), m2.size() );
            final Iterator<?> iter1 = m1.iterator();
            final Iterator<?> iter2 = m2.iterator();
            while( iter1.hasNext() ) {
                assertDeepEquals( iter1.next(), iter2.next() );
            }
            return;
        }

        if ( Number.class.isAssignableFrom( one.getClass() ) ) {
            Assert.assertEquals( ( (Number) one ).longValue(), ( (Number) another ).longValue() );
            return;
        }

        if ( one instanceof Currency ) {
            // Check that the transient field defaultFractionDigits is initialized correctly (that was issue #34)
            final Currency currency1 = ( Currency) one;
            final Currency currency2 = ( Currency) another;
            Assert.assertEquals( currency1.getCurrencyCode(), currency2.getCurrencyCode() );
            Assert.assertEquals( currency1.getDefaultFractionDigits(), currency2.getDefaultFractionDigits() );
        }

        Class<? extends Object> clazz = one.getClass();
        while ( clazz != null ) {
            assertEqualDeclaredFields( clazz, one, another, alreadyChecked );
            clazz = clazz.getSuperclass();
        }

    }

    public static void assertEqualDeclaredFields( final Class<? extends Object> clazz, final Object one, final Object another,
            final Map<Object, Object> alreadyChecked ) {
        for ( final Field field : clazz.getDeclaredFields() ) {
            field.setAccessible( true );
            if ( !Modifier.isTransient( field.getModifiers() ) ) {
                try {
                    assertDeepEquals( field.get( one ), field.get( another ), alreadyChecked );
                } catch ( final IllegalArgumentException e ) {
                    throw new RuntimeException( e );
                } catch ( final IllegalAccessException e ) {
                    throw new RuntimeException( e );
                }
            }
        }
    }

    /**
     * A simple serializable {@link HttpSessionActivationListener} that provides the
     * session id that was passed during {@link #sessionDidActivate(HttpSessionEvent)}
     * via {@link #getSessionDidActivate()}.
     */
    public static final class RecordingSessionActivationListener implements HttpSessionActivationListener, Serializable {

        private static final long serialVersionUID = 1L;

        private transient String _sessionDidActivate;

        @Override
        public void sessionWillPassivate( final HttpSessionEvent se ) {
        }

        @Override
        public void sessionDidActivate( final HttpSessionEvent se ) {
            _sessionDidActivate = se.getSession().getId();
        }

        /**
         * Returns the id of the session that was passed in {@link #sessionDidActivate(HttpSessionEvent)}.
         * @return a session id or <code>null</code>.
         */
        public String getSessionDidActivate() {
            return _sessionDidActivate;
        }

    }

    /**
     * Creates a map from the given keys and values (key1, value1, key2, value2, etc.).
     * @param <T> the type of the keys and values.
     * @param keysAndValues the keys and values, must be an even number of arguments.
     * @return a {@link Map} or null if no argument was given.
     */
    public static <T> Map<T,T> asMap( final T ... keysAndValues ) {
        if ( keysAndValues == null ) {
            return null;
        }
        if ( keysAndValues.length % 2 != 0 ) {
            throw new IllegalArgumentException( "You must provide an even number of arguments as key/value pairs." );
        }

        final Map<T,T> result = new HashMap<T,T>();
        for ( int i = 0; i < keysAndValues.length; i++ ) {
            if ( ( i & 1 ) == 1 ) {
                result.put( keysAndValues[i - 1], keysAndValues[i] );
            }
        }

        return result;
    }

    public static enum SessionTrackingMode {
        COOKIE,
        URL
    }

    public static enum SessionAffinityMode {
        STICKY {
            @Override public boolean isSticky() { return true; }
        },
        NON_STICKY {
            @Override public boolean isSticky() { return false; }
        };

        public abstract boolean isSticky();
    }

    @DataProvider
    public static Object[][] stickynessProvider() {
        return new Object[][] {
                { SessionAffinityMode.STICKY },
                { SessionAffinityMode.NON_STICKY }
        };
    }

    @DataProvider
    public static Object[][] booleanProvider() {
        return new Object[][] {
                { true },
                { false }
        };
    }

    @Nonnull
    public static Key key( @Nonnull final String value ) {
        return new Key( ChannelBuffers.wrappedBuffer( value.getBytes() ) );
    }

    @Nonnull
    public static MemcachedBackupSession createSession( @Nonnull final MemcachedSessionService service ) {
        // return (MemcachedBackupSession) service.getManager().createSession( null );
        final MemcachedBackupSession session = service.createEmptySession();
        session.setNew( true );
        session.setValid( true );
        session.setCreationTime( System.currentTimeMillis() );
        session.setMaxInactiveInterval( 23 );
        session.setId( "foo-n1" );
        return session;
    }


    public static void waitForReconnect( final MemcachedClient client, final int expectedNumServers, final long timeToWait )
            throws InterruptedException, RuntimeException {
        final long start = System.currentTimeMillis();
        while( System.currentTimeMillis() < start + timeToWait ) {
            if ( client.getAvailableServers().size() >= expectedNumServers ) {
                return;
            }
            Thread.sleep( 20 );
        }
        throw new RuntimeException( "MemcachedClient did not reconnect after " + timeToWait + " millis." );
    }

    public static <T,V> T assertNotNullElementWaitingWithProxy(final int elementIndex, final long maxTimeToWait, final T objectToProxy) {
        return assertWaitingWithProxy(elementAt(elementIndex, notNull()), maxTimeToWait, objectToProxy);
    }

    @java.lang.SuppressWarnings("unchecked")
    public static <T,V> T assertWaitingWithProxy(final Predicate<V> predicate, final long maxTimeToWait, final T objectToProxy) {
        final Class<?>[] interfaces = objectToProxy.getClass().getInterfaces();
        return (T) Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(),
                interfaces,
                new InvocationHandler() {
                    @Override
                    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
                        return assertPredicateWaiting(predicate, maxTimeToWait, objectToProxy, method, args);
                    }
                } );
    }

    private static <V> V assertPredicateWaiting(final Predicate<V> predicate, final long maxTimeToWait, final Object obj, final Method method, final Object[] args) throws Exception {
        final long start = System.currentTimeMillis();
        while( System.currentTimeMillis() < start + maxTimeToWait ) {
            @java.lang.SuppressWarnings("unchecked")
            final V result = (V) method.invoke(obj, args);
            if ( predicate.apply(result) ) {
                return result;
            }
            try {
                Thread.sleep( 10 );
            } catch (final InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            }
        }
        throw new AssertionError("Expected not null, actual null.");
    }

    public static interface Predicate<T> {
        /**
         * Applies this predicate to the given object.
         *
         * @param input the input that the predicate should act on
         * @return the value of this predicate when applied to the input {@code t}
         */
        boolean apply(@Nullable T input);
    }

    public static class Predicates {

        private static final Predicate<Object> NOT_NULL = new Predicate<Object>() {
            @Override
            public boolean apply(final Object input) {
                return input != null;
            }
        };
        private static final Predicate<Object> IS_NULL = new Predicate<Object>() {
            @Override
            public boolean apply(final Object input) {
                return input == null;
            }
        };

        /**
         * Returns a predicate that evaluates to {@code true} if the object reference
         * being tested is not null.
         */
        @java.lang.SuppressWarnings("unchecked")
        public static <T> Predicate<T> notNull() {
            return (Predicate<T>) NOT_NULL;
        }

        /**
         * Returns a predicate that evaluates to {@code true} if the object reference
         * being tested is null.
         */
        @java.lang.SuppressWarnings("unchecked")
        public static <T> Predicate<T> isNull() {
            return (Predicate<T>) IS_NULL;
        }

        /**
         * Returns a predicate that evaluates to {@code true} if the object being
         * tested {@code equals()} the given target or both are null.
         */
        public static <T> Predicate<T> equalTo(@Nullable final T target) {
            return (target == null) ? Predicates.<T> isNull()
                    : new Predicate<T>() {
                @Override
                public boolean apply(final T input) {
                    return target.equals(input);
                }
            };
        }

        public static <T> Predicate<T[]> elementAt(final int index, @Nonnull final Predicate<T> elementPredicate) {
            return new Predicate<T[]>() {
                @Override
                public boolean apply(final T[] input) {
                    return input != null && input.length > index && elementPredicate.apply(input[index]);
                }
            };
        }
    }

}
TOP

Related Classes of de.javakaffee.web.msm.integration.TestUtils

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.