Package org.voltdb.regressionsuites

Source Code of org.voltdb.regressionsuites.TestMaliciousClientSuite

/* This file is part of VoltDB.
* Copyright (C) 2008-2014 VoltDB Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

package org.voltdb.regressionsuites;

import java.nio.channels.SocketChannel;
import java.util.ArrayList;

import junit.framework.Test;

import org.voltdb.BackendTarget;
import org.voltdb.benchmark.tpcc.TPCCProjectBuilder;
import org.voltdb_testprocs.regressionsuites.malicious.GoSleep;

public class TestMaliciousClientSuite extends RegressionSuite {

    // procedures used by these tests
    static final Class<?>[] PROCEDURES = {
        GoSleep.class
    };

    /**
     * Constructor needed for JUnit. Should just pass on parameters to superclass.
     * @param name The name of the method to test. This is just passed to the superclass.
     */
    public TestMaliciousClientSuite(String name) {
        super(name);
    }

    @org.junit.Test
    public void testManyClientsComingAndGoing() throws Exception {
        for (int ii = 0; ii < 2000; ii++) {
            ArrayList<SocketChannel> channels = new ArrayList<SocketChannel>();
            for (int zz = 0; zz < 100; zz++) {
                channels.add(getClientChannel(true));
            }
            for (SocketChannel sc : channels) {
                sc.close();
            }
            System.out.printf("Ran through testManyClientsComingAndGoing loop %d times.\n", ii);
            System.out.flush();
        }
    }
//
//    /*
//     * Expect a variety of failure conditions like OOMm out of file descriptors etc.
//     * In reality this test doesn't do a good a job of checking that resources are being freed on the server. The main
//     * goal is to crash the server process one way or another via this behavior.
//     *
//     * This test can only be run to around 500 harassments. After that the server OOMs, but not because it isn't
//     * removing the data associated with old clients correctly. After a certain amount of pressure
//     * it stops detecting that client have disconnected and isn't removing them as fast as they connect.
//     */
//    @org.junit.Test(timeout=600000)
//    public void testManyClientsQueuingAndLeaving() throws Exception {
//        System.gc();
//        System.out.println("Have " + (Runtime.getRuntime().freeMemory() / 1024) + "kb available");
//        final ThreadLocal<ConnectionUtil.ExecutorPair> m_executors = new ThreadLocal<ConnectionUtil.ExecutorPair>() {
//            @Override
//            protected ConnectionUtil.ExecutorPair initialValue() {
//                return new ConnectionUtil.ExecutorPair();
//            }
//        };
//        final ExecutorService executor = Executors.newFixedThreadPool( 4, new ThreadFactory() {
//            private int harasserCount = 0;
//            @Override
//            public Thread newThread(Runnable r) {
//                return new Thread(Thread.currentThread().getThreadGroup(), r, "Harasser " + harasserCount++, 131072);
//            }
//        });
//
//        int numHarassments = 2000;
//        final int numRequests = 4000;
//        ArrayList<Future<Object>> harassments = new ArrayList<Future<Object>>();
//        for (int ii = 0; ii < numHarassments; ii++) {
//            harassments.add(executor.submit(new Callable<Object>() {
//
//                @Override
//                public Object call() throws Exception {
//                    final SocketChannel sc = getClientChannel(true);
//                    final ArrayList<Future<Long>> requests = new ArrayList<Future<Long>>();
//                    final ExecutorService m_executor = m_executors.get().m_writeExecutor;
//                    for (int ii = 0; ii < numRequests; ii++) {
//                        requests.add(ConnectionUtil.sendInvocation( m_executor, sc, "GoSleep", 0, 1, null));
//                    }
//                    for (Future<Long> request : requests) {
//                        request.get();
//                    }
//                    sc.close();
//                    return null;
//                }
//            }));
//        }
//
//        int harassmentsComplete = 0;
//        for (Future<Object> harassment : harassments) {
//            harassmentsComplete++;
//            if (harassmentsComplete % 100 == 0) {
//                System.out.println("Completed " + harassmentsComplete + " harassments with "
//                        + (Runtime.getRuntime().freeMemory() /1024) + " kb free memory");
//            }
//            harassment.get();
//        }
//
//        executor.shutdown();
//        executor.awaitTermination( 1, TimeUnit.DAYS);
//    }
//
//    /**
//     * Test for backpressure generated by the DTXN because there are too many transactions in flight
//     * @throws Exception
//     */
//    public void testDTXNBackPressure() throws Exception {
//        System.gc();
//        System.out.println("Start the test with " + Runtime.getRuntime().freeMemory() + " free");
//        byte junkData[] = new byte[2048];
//        long numRequests = 40000;
//        long sleepTime = 20000;
//        final ArrayDeque<Future<Long>> pendingRequests = new ArrayDeque<Future<Long>>();
//        final ArrayDeque<Future<ClientResponse>> pendingResponses = new ArrayDeque<Future<ClientResponse>>();
//        final ArrayDeque<SocketChannel> connections = new ArrayDeque<SocketChannel>();
//        for (int ii = 0; ii < 4; ii++) {
//            final SocketChannel channel = getClientChannel();
//            connections.add(channel);
//        }
//
//        /**
//         * Queue a request and and the read for the response.
//         * The parameter to GoSleep will cause the first invocation to not return
//         * for a while.
//         * Most of these invocations should never make it into the server due
//         * to DTXN backpressure
//         */
//        for (int ii = 0; ii < numRequests; ii++) {
//            final SocketChannel channel = connections.poll();
//            pendingRequests.offer(ConnectionUtil.sendInvocation(channel, "GoSleep", ii == 0 ? sleepTime : 0, 0, junkData));
//            pendingResponses.offer(ConnectionUtil.readResponse(channel));
//            connections.offer(channel);
//        }
//        System.out.println("Sent " + numRequests + " requests with the first requesting a sleep of " +
//                (sleepTime / 1000) + " seconds");
//
//        /**
//         * Give the TCP stack time to transfer as many invocations as the server will accept
//         */
//        Thread.sleep(10000);
//
//        System.out.println("Slept 10 seconds so the server could transfer invocations");
//
//        /**
//         * Count the number of requests that didn't make it onto the wire due to backpressure
//         */
//        long pendingRequestCount = 0;
//        Future<Long> f = null;
//        while ( (f = pendingRequests.poll()) != null) {
//            if (!f.isDone()) {
//                pendingRequestCount++;
//            } else {
//                f.get();
//            }
//        }
//        pendingRequests.clear();
//
//        System.out.println("Counted " + pendingRequestCount + " requests that didn't make it on the wire");
//
//        /**
//         * The number should be quite large
//         */
//        assertTrue(pendingRequestCount > 30000);
//
//        /**
//         * Now ensure that the backpressure condition can end by waiting for all the responses.
//         */
//        long responseCount = 0;
//        int lastPercentComplete = 0;
//        Future<ClientResponse> response = null;
//        while ( (response = pendingResponses.poll()) != null) {
//            response.get();
//            responseCount++;
//            int percentComplete = (int)Math.floor((responseCount / (double)numRequests) * 100);
//            if (percentComplete > lastPercentComplete) {
//                lastPercentComplete = percentComplete;
//                if (lastPercentComplete % 5 == 0) {
//                    System.out.println(lastPercentComplete + "% complete reading responses with " +  Runtime.getRuntime().freeMemory() + " free");
//                }
//            }
//        }
//
//        System.out.println("Read all the responses for the transactions that couldn't previously make it on the wire");
//
//        assertEquals(responseCount, numRequests);
//
//        /**
//         * Now queue and read another round just to prove it still works
//         */
//        for (final SocketChannel channel : connections) {
//            ConnectionUtil.sendInvocation(channel, "GoSleep", 0).get();
//        }
//
//        for (final SocketChannel channel : connections) {
//            ConnectionUtil.readResponse(channel).get();
//        }
//
//        System.out.println("Was able to queue and read across the other 4 connections");
//    }
//
//    /**
//     * Can't get this to pass reliably
//     */
////    /**
////     * Test for backpressure because a client is not reading his responses. This is difficult because
////     * the server will boot connections that don't read. Only the individual rude client should be blocked.
////     * A polite client should still be able to work.
////     * @throws Exception
////     */
////    public void testIndividualClientBackPressure() throws Exception {
////        System.gc();
////        final ArrayDeque<Future<Long>> pendingRudeRequests = new ArrayDeque<Future<Long>>();
////        final ArrayDeque<Future<Long>> pendingPoliteRequests = new ArrayDeque<Future<Long>>();
////        final ArrayDeque<Future<ClientResponse>> pendingRudeResponses = new ArrayDeque<Future<ClientResponse>>();
////        final ArrayDeque<Future<ClientResponse>> pendingPoliteResponses = new ArrayDeque<Future<ClientResponse>>();
////        final SocketChannel rudeChannel = getClientChannel();
////        /**
////         * Makes it easier to control when data is pulled from the remote side. This value would be
////         * tuned very large otherwise.
////         */
////        rudeChannel.socket().setReceiveBufferSize(16384);
////        System.out.println("Rude channel is called " + rudeChannel.socket().getLocalSocketAddress());
////        final SocketChannel politeChannel = getClientChannel();
////        System.out.println("Polite channel is called " + politeChannel.socket().getLocalSocketAddress());
////        final int numRequests = 15000;
////        final int sleepTime = 0;
////        int rudeReadsSent = 0;
////
////        /**
////         * Send a ton of invocations on the rude channel that will complete immediately and return a relatively large
////         * result table to help fill I/O buffers.
////         */
////        for (int ii = 0; ii < numRequests; ii++) {
////            pendingRudeRequests.add(ConnectionUtil.sendInvocation(rudeChannel, "GoSleep", sleepTime, 1, null));
////            if (ii % 600 == 0) {
////                pendingRudeResponses.add(ConnectionUtil.readResponse(rudeChannel));
////                rudeReadsSent++;
////            }
////        }
////
////        System.out.println("Sent " + numRequests + " requests with the first requesting a sleep of " +
////                (sleepTime / 1000) + " seconds and " + rudeReadsSent + " reads sent to avoid getting booted");
////
////        /**
////         * Give the server time to finish processing the previous requests.
////         */
////        for(int ii = 0; ii < 100; ii++) {
////            Thread.sleep(100);
////            for (int zz = 0; zz < 10; zz++) {
////                pendingRudeResponses.add(ConnectionUtil.readResponse(rudeChannel));
////                rudeReadsSent++;
////            }
////        }
////
////        System.out.println("Slept 10 seconds so the server could transfer invocations and sent " + rudeReadsSent +
////                " reads to avoid getting booted");
////
////        /**
////         * Count the number of requests that didn't make it onto the wire due to backpressure
////         */
////        long pendingRequestCount = 0;
////        for (Future<Long> f : pendingRudeRequests) {
////            if (!f.isDone()) {
////                pendingRequestCount++;
////            } else {
////                f.get();
////            }
////        }
////
////        System.out.println("Counted " + pendingRequestCount + " requests that didn't make it on the wire");
////
////        /**
////         * The number should be quite large
////         */
////        assertTrue(pendingRequestCount > 0);
////
////        System.out.println("Using a  polite channel to send " + numRequests);
////        /**
////         * Now use the polite channel to send requests. These should have no trouble going through the system since
////         * this is also queuing the reads for the responses.
////         */
////        for (int ii = 0; ii < numRequests; ii++) {
////            pendingPoliteRequests.add(ConnectionUtil.sendInvocation(politeChannel, "GoSleep", sleepTime, 0, null));
////            pendingPoliteResponses.add(ConnectionUtil.readResponse(politeChannel));
////            if (ii % 600 == 0) {
////                pendingRudeResponses.add(ConnectionUtil.readResponse(rudeChannel));
////                rudeReadsSent++;
////                Thread.yield();
////            }
////        }
////
////        int numPoliteResponses = 0;
////        int lastPercentPoliteResponses = 0;
////        int rudeReadsSentHere = 0;
////        long startTime = System.currentTimeMillis() - 100;
////        System.out.println("Waiting for all polite requests and responses to make it on the wire");
////        Future<Long> request = null;
////        while ((request = pendingPoliteRequests.poll()) != null) {
////            request.get();
////            pendingPoliteResponses.poll().get();
////            numPoliteResponses++;
////            int percentComplete = (int)Math.floor((numPoliteResponses / (double)numRequests) * 100);
////            if (percentComplete > lastPercentPoliteResponses) {
////                lastPercentPoliteResponses = percentComplete;
////                if (lastPercentPoliteResponses % 10 == 0) {
////                    System.out.println(lastPercentPoliteResponses + "% complete reading polite responses");
////                    System.out.println("Free memory " + Runtime.getRuntime().freeMemory());
////                }
////            }
////
////            final long now = System.currentTimeMillis();
////            if (now - startTime > 100) {
////                //System.out.println("Sending rude reads " + now);
////                startTime = now;
////                for (int zz = 0; zz < 10; zz++) {
////                    pendingRudeResponses.add(ConnectionUtil.readResponse(rudeChannel));
////                    rudeReadsSentHere++;
////                }
////            }
////        }
////
////        rudeReadsSent += rudeReadsSentHere;
////        System.out.println("All polite requests and responses made it onto the wire and had to send " + rudeReadsSentHere +
////                " rude reads to avoid getting booted");
////
////        System.out.println("Queuing reads for all rude requests");
////        /**
////         * Now make sure that if the rude channel becomes polite it can get everything through
////         */
////        for (; rudeReadsSent < numRequests; rudeReadsSent++) {
////            pendingRudeResponses.add(ConnectionUtil.readResponse(rudeChannel));
////        }
////
////        int numRudeRequests = 0;
////        int lastPercentRudeRequests = 0;
////        while ((request = pendingRudeRequests.poll()) != null) {
////            request.get();
////            pendingRudeResponses.poll().get();
////            numRudeRequests++;
////            int percentComplete = (int)Math.floor((numRudeRequests / (double)numRequests) * 100);
////            if (percentComplete > lastPercentRudeRequests) {
////                lastPercentRudeRequests = percentComplete;
////                if (lastPercentRudeRequests % 10 == 0) {
////                    System.out.println(lastPercentRudeRequests + "% complete sending rude requests and receiving rude responses");
////                    System.out.println("Free memory " + Runtime.getRuntime().freeMemory());
////                }
////            }
////        }
////        pendingRudeRequests.clear();
////    }
//
//    /**
//     * Check that the server enforces a limit on the maximum number of connections
//     * @throws Exception
//     */
//    public void testMaxNumConnections() throws Exception {
//        final ExecutorService executor = Executors.newFixedThreadPool( 8, new ThreadFactory() {
//            private int harasserCount = 0;
//            @Override
//            public Thread newThread(Runnable r) {
//                return new Thread(Thread.currentThread().getThreadGroup(), r, "Harasser " + harasserCount++, 131072);
//            }
//        });
//
//        ArrayList<Future<SocketChannel>> attempts = new ArrayList<Future<SocketChannel>>();
//
//        final int connectionsToAttempt = 20000;
//        for (int ii = 0; ii < connectionsToAttempt; ii++) {
//            attempts.add(executor.submit(new Callable<SocketChannel>() {
//                @Override
//                public SocketChannel call() throws Exception {
//                    return getClientChannel(true);
//                }
//            }));
//        }
//
//        for (Future<SocketChannel> attempt : attempts) {
//            try {
//                attempt.get();
//            } catch (Exception e) {
//
//            }
//        }
//
//        int successfulAttempts = 0;
//        for (Future<SocketChannel> attempt : attempts) {
//            try {
//                final SocketChannel sc = attempt.get();
//                successfulAttempts++;
//                sc.close();
//            } catch (Exception e) {
//
//            }
//        }
//
//        executor.shutdown();
//        executor.awaitTermination(1, TimeUnit.DAYS);
//        assertTrue(successfulAttempts < 10000);
//        System.out.println("Had " + successfulAttempts + " successful connection attempts");
//    }

    /**
     * Build a list of the tests that will be run when TestTPCCSuite gets run by JUnit.
     * Use helper classes that are part of the RegressionSuite framework.
     * This particular class runs all tests on the the local JNI backend with both
     * one and two partition configurations, as well as on the hsql backend.
     *
     * @return The TestSuite containing all the tests to be run.
     */
    static public Test suite() {
        // the suite made here will all be using the tests from this class
        MultiConfigSuiteBuilder builder = new MultiConfigSuiteBuilder(TestMaliciousClientSuite.class);

        // build up a project builder for the workload
        TPCCProjectBuilder project = new TPCCProjectBuilder();
        project.addDefaultSchema();
        project.addDefaultPartitioning();
        project.addProcedures(PROCEDURES);

        boolean success;

        /////////////////////////////////////////////////////////////
        // CONFIG #1: 1 Local Site/Partitions running on JNI backend
        /////////////////////////////////////////////////////////////

        // get a server config for the native backend with one sites/partitions
        VoltServerConfig config = new LocalCluster("malicious-onesite.jar", 1, 1, 0, BackendTarget.NATIVE_EE_JNI);

        // build the jarfile
        success = config.compile(project);
        assertTrue(success);

        // add this config to the set of tests to run
        builder.addServerConfig(config);

        /////////////////////////////////////////////////////////////
        // CONFIG #2: Local Cluster (of processes)
        /////////////////////////////////////////////////////////////

        config = new LocalCluster("malicious-cluster.jar", 2, 3, 1, BackendTarget.NATIVE_EE_JNI);
        success = config.compile(project);
        assertTrue(success);
        builder.addServerConfig(config);

        return builder;
    }
}
TOP

Related Classes of org.voltdb.regressionsuites.TestMaliciousClientSuite

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.