mardi 29 octobre 2013

TestNG merge data provider

TestNG merge data provider

This article presents a technique to enhance TestNG data provider. The goal is to implement a generic tool for merging data provider and feeding the test with those merged data.
Therefore, we must pass the list of data provider we want to merged,  to a the merging tool
We implement::
  • A tool for merging TestNG dataprovider : CustomDataProvider.mergeDataProvider().
  • An annotation DataProviderArguments for passing arguments to mergeDataProvider().
  • A sample of test SampleOfUsageOfDataProvider which is using a merged dataprovider.

CustomDataProvider.mergeDataProvider

This is the so called 'merging tool', it is wrapped as data provider because it is more handy to call it from a test case.

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.testng.annotations.DataProvider;

/**
 * this method merge 2 or more data providers. It takes care of the combination.
 * for example :
 * zeroOne_DataProvider = |  1 , 0   |
 *                       |  1 , 1   |
 *
 * addresses_DataProvider =   | 127.0.0.1 |
 *                  | fe80::8cf6:17ea:939b:7291 |
 *                 
 * resultDataProvider=   |127.0.0.1 , 1 , 0   |
 *                       |127.0.0.1 , 1 , 1   |
 *                       |fe80::8cf6:17ea:939b:7291 , 1 , 0   |
 *                       |fe80::8cf6:17ea:939b:7291 , 1 , 1   |
 *                      
 *
 *
 * Sample of usage:
 * @Test(dataProviderClass = CustomDataProvider.class, dataProvider = "mergeDataProvider")
 * @DataProviderArguments({
 *            "DataProviders,
zeroOne_DataProvider",
 *             "
DataProviders,addresses_DataProvider" })
 *
 */
public class CustomDataProviders {

    /**
     * This method implements the merge DataProvider
     */
    @DataProvider(name = "mergeDataProvider")
    public static Object[][] mergeDataProvider(Method testMethod) throws Exception {

        CustomDataProviders customDataProviders = new CustomDataProviders();
        List<DataProviderLocation> listOfDataProviderLocation = customDataProviders
                .resolveDataProviderMergeArguments(testMethod);

        Object[][] totalDataProvider = new Object[0][0];

        for (DataProviderLocation dataProviderLocation : listOfDataProviderLocation) {
            Object[][] dataProviderToAdd = customDataProviders.retrieveDataProvider(dataProviderLocation);
            totalDataProvider = customDataProviders.merge(totalDataProvider, dataProviderToAdd);
        }
        return totalDataProvider;
    }

    /**
     * Implementation of the logic to take care of the combination
     */
    private Object[][] merge(Object[][] dataProvider1, Object[][] dataProvider2) throws Exception {

        int numberOfData1 = dataProvider1.length;

        if (numberOfData1 == 0) {
            return dataProvider2;
        }
        int numberOfParamters1 = dataProvider1[0].length;

        int numberOfData2 = dataProvider2.length;
        if (numberOfData2 == 0) {
            return dataProvider1;
        }
        int numberOfParamters2 = dataProvider2[0].length;

        Object[][] resultDataProvider = new String[numberOfData1 * numberOfData2][numberOfParamters1
                + numberOfParamters2];
        int currentRowRP = 0;
        for (int i = 0; i < numberOfData1; i++) {
            for (int j = 0; j < numberOfData2; j++) {

                for (int k = 0; k < numberOfParamters1; k++) {
                    resultDataProvider[currentRowRP][k] = dataProvider1[i][k];
                }
                for (int l = 0; l < numberOfParamters2; l++) {
                    resultDataProvider[currentRowRP][numberOfParamters1 + l] = dataProvider2[j][l];
                }
                currentRowRP++;
            }
        }
        return resultDataProvider;
    }

    /**
     * Retrieves DataProvider object using a DataProviderLocation
     */
    private Object[][] retrieveDataProvider(DataProviderLocation dataProviderLocation) throws Exception {

        // using reflection to call the method with the same name as the Data Provider
        Method method = dataProviderLocation.getDataproviderClass().getMethod(
                dataProviderLocation.getDataProviderName());
        return (Object[][]) method.invoke(dataProviderLocation.getDataproviderClass());
    }

    /**
     * Converts the DataProviderArguments annotation into a List<DataProviderLocation>
     */
    private List<DataProviderLocation> resolveDataProviderMergeArguments(Method testMethod) throws Exception {

        if (testMethod == null)
            throw new IllegalArgumentException("Test Method context cannot be null.");

        DataProviderArguments args = testMethod.getAnnotation(DataProviderArguments.class);
        if (args == null)
            throw new IllegalArgumentException("Test Method context has no DataProviderArguments annotation.");
        if (args.value() == null || args.value().length == 0)
            throw new IllegalArgumentException("Test Method context has a malformed DataProviderArguments annotation.");
        ArrayList<DataProviderLocation> arguments = new ArrayList<DataProviderLocation>();
        for (int i = 0; i < args.value().length; i++) {
            String[] parts = args.value()[i].split(",");
            arguments.add(this.new DataProviderLocation(parts[0], parts[1]));
        }
        return arguments;
    }

    /**
     * inner class which defined a data provider location
     */
    private class DataProviderLocation {

        private Class<?> dataproviderClass;
        private String dataProviderName;

        public DataProviderLocation(String dataproviderClassName, String dataProviderName)
                throws ClassNotFoundException {

            super();
            this.dataproviderClass = Class.forName(dataproviderClassName);
            this.dataProviderName = dataProviderName;
        }

        public Class<?> getDataproviderClass() {

            return dataproviderClass;
        }

        public String getDataProviderName() {

            return dataProviderName;
        }
    }
}


DataProviderArguments

This annotation define parameters passed to a given Data provider. In this example, parameter is a array of String. 

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 *
 *
 * Warning: Those arguments should map to a data provider :
 * -defined statically
 * -with the same name for the method and the data provider annotation
 *
 * For example:
 * @DataProvider(name = "unsupportedWantBacks")
 *     public static Object[][] unsupportedWantBacks() {
 *
 * Sample of usage:
 * @Test(dataProviderClass = CustomDataProvider.class, dataProvider = "mergeDataProvider")
 * @DataProviderArguments({
 *            "com.automation.va.utils.dataProvider.ListOfDataProvider,va_addresses",
 *             "com.automation.va.tests.scvp.ScvpStats,unsupportedWantBacks" })
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface DataProviderArguments {

    String[] value();
}

SampleOfUsageOfDataProvider 

This code is an example of call made to the 'merging' tool
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class SampleOfUsageOfDataProvider {

    @DataProvider(name = "wrongCredentials")
    public static Object[][] wrongCredentials() {

        return new Object[][] {
                new Object[] {
                        "",
                        "" },
                new Object[] {
                        "proxyUsername",
                        "wrongPassword" },
                new Object[] {
                        "wrongUsername",
                        "proxyPassword" } };
    }

    @DataProvider(name = "addresses")
    public static Object[][] addresses() {

        return new Object[][] {
                new Object[] { "localhost" },
                new Object[] { "127.0.0.1" } };
    }

    @Test(dataProviderClass = CustomDataProviders.class, dataProvider = "mergeDataProvider")
    @DataProviderArguments({ "SampleOfUsageOfDataProvider,wrongCredentials" })
    public void basic1(String username, String password) throws Exception {

        System.out.println("done");
    }

    @Test(dataProviderClass = CustomDataProviders.class, dataProvider = "mergeDataProvider")
    @DataProviderArguments({"SampleOfUsageOfDataProvider,va_addresses",       "SampleOfUsageOfDataProvider,wrongCredentials" })
    public void basic2(String address, String username, String password) throws Exception {

        System.out.println("done");
    }
}

mercredi 23 octobre 2013

Java Http Forwarder

Java Http forwarder

This java code snippet is the an implementation of an http forwarder.
This implementation is binded to the local  Ipv6 address and forward all the incoming http request to the "forward URL".


import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

/**
 * Description
 * This classic is a basic http server which is listening on an IPV6 address. It is designed to forward request to any URL.
 *
 *
 */
public class HttpForwarder implements Runnable {

    private String listeningAddress;
    private int listeningPort;
    private String ForwardUrl;

    private boolean useHttps;

    public HttpForwarder(String listeningAddress, String listeningPort, String forwardUrl) throws Exception {

        super();
        this.listeningAddress = listeningAddress;
        if (listeningPort.startsWith("s")) {
            this.listeningPort = Integer.parseInt(listeningPort.substring(1));
            this.useHttps = true;
        } else {
            this.listeningPort = Integer.parseInt(listeningPort);
            this.useHttps = false;
        }
        this.ForwardUrl = forwardUrl;

    }

    public void run() {

        System.setProperty("java.net.preferIPv4Stack", "false");
        System.setProperty("java.net.preferIPv6Stack", "true");
        System.setProperty("java.net.preferIPv6Addresses", "true");
        try {
            InetAddress address = InetAddress.getByName(listeningAddress);
            ServerSocket serverSocket = new ServerSocket(listeningPort, 100, address);

            System.out.println("run " + listeningAddress + ":" + listeningPort + " " + ForwardUrl);
            while (true) {
                System.out.println("waiting");
                Socket clientSocket = serverSocket.accept();
                System.out.println("received");
                InputStream request = clientSocket.getInputStream();
                OutputStream response = clientSocket.getOutputStream();
                copyStream(forwardHttpRequest(request), response);
                request.close();
                response.flush();
                response.close();
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {

        String forwraderIP = "fe80::9cb3:10af:447d:8aba";
        String listOfPort = "8080,s8081,8089,s13333";
        String VAServerUrl = "10.130.57.164";

        if (args.length != 3 && args.length != 0) {
            System.err
                    .println("usage HttpForwarder fe80::2c52:a37a:3be1:868a 8080,s8081,28081 http://vatest.lab.dubl.axway.int");
            System.err.println("or without parameter for the default built in values");
            System.exit(-1);
        } else if (args.length == 3) {
            forwraderIP = args[0];
            listOfPort = args[1];
            VAServerUrl = args[2];
        }
        String[] arrayOfPort = listOfPort.split(",");
        for (String port : arrayOfPort) {
            new Thread(new HttpForwarder(forwraderIP, port, VAServerUrl)).start();
        }

    }

    public InputStream forwardHttpRequest(InputStream requestToForward) throws Exception {

        Socket forwardSocket = createForwardSocket();
        copyStream(requestToForward, forwardSocket.getOutputStream());

        // get response
        InputStream responseToForward = forwardSocket.getInputStream();
        System.out.println(forwardSocket);
        return responseToForward;

    }

    public Socket createForwardSocket() throws Exception {

        Socket forwardSocket = null;
        if (useHttps) {
            SSLSocket sslSocket = null;
            XTrustProvider.install();
            SSLSocketFactory mySSLSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            sslSocket = (SSLSocket) mySSLSocketFactory.createSocket(ForwardUrl, this.listeningPort);
            sslSocket.startHandshake();
            forwardSocket = sslSocket;

        } else {
            forwardSocket = new Socket(ForwardUrl, this.listeningPort);
        }
        forwardSocket.setKeepAlive(true);
        return forwardSocket;
    }

    public static void copyStream(InputStream input, OutputStream output) throws Exception {

        // wait to get the full request
        Thread.sleep(1 * 1000);

        int bytesRead;
        byte[] buffer = new byte[1024 * 10];// the buffer size may need to be changed
        System.out.println("input.available() " + input.available());
        bytesRead = input.read(buffer, 0, input.available());
        output.write(buffer, 0, bytesRead);
    }
}