org.opentestsystem.shared.test.standalone.LoadTestPackageRunner.java Source code

Java tutorial

Introduction

Here is the source code for org.opentestsystem.shared.test.standalone.LoadTestPackageRunner.java

Source

/*******************************************************************************
 * Educational Online Test Delivery System 
 * Copyright (c) 2014 American Institutes for Research
 *   
 * Distributed under the AIR Open Source License, Version 1.0 
 * See accompanying file AIR-License-1_0.txt or at
 * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf
 ******************************************************************************/
package org.opentestsystem.shared.test.standalone;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.InvalidPropertiesFormatException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.opentestsystem.shared.test.api.InteractionContext;
import org.opentestsystem.shared.test.api.cooperation.Chorus;
import org.opentestsystem.shared.test.api.user.FirstPersonInteractiveUser;
import org.opentestsystem.shared.test.listener.LifecycleResourceCombiner;
import org.opentestsystem.shared.test.statistics.InteractionTimingRecord;
import org.opentestsystem.shared.test.statistics.TimingRecordSummarizer;
import org.opentestsystem.shared.test.statistics.TimingRecordSummarizerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.util.StringUtils;

public class LoadTestPackageRunner {
    public static final String OPTION_NAME_HELP = "help";
    public static final String OPTION_NAME_CONTEXT_CONFIG = "context-config";
    public static final String OPTION_DEFAULT_CONTEXT_CONFIG = "classpath://load-test-context.xml";
    public static final String OPTION_NAME_CONTEXT_PROPERTIES = "context-properties";
    public static final String OPTION_DEFAULT_CONTEXT_PROPERTIES = "";
    public static final String OPTION_NAME_SPRING_PROFILES = "spring-profiles";
    public static final String OPTION_DEFAULT_SPRING_PROFILES = "";

    private static final Logger _logger = LoggerFactory.getLogger(LoadTestPackageRunner.class);

    private ApplicationContext _applicationContext = null;
    private LifecycleResourceCombiner _lifecycleResources = null;
    private Map<String, FirstPersonInteractiveUser<?, ?>> _users = null;

    public void setApplicationContext(ApplicationContext applicationContext) {
        _applicationContext = applicationContext;
    }

    public ApplicationContext getApplicationContext() {
        return _applicationContext;
    }

    public static void main(String[] args) {
        new LoadTestPackageRunner().main_(args);
    }

    private void main_(String[] args) {
        // Bridge the JUL logging into SLF4J
        SLF4JBridgeHandler.removeHandlersForRootLogger(); // (since SLF4J 1.6.5)
        SLF4JBridgeHandler.install();
        MDC.put("interestingThreadId", "main");

        // Parse arguments
        Options options = new Options();
        options.addOption("h", OPTION_NAME_HELP, false, "Print this message");
        options.addOption("p", OPTION_NAME_CONTEXT_CONFIG, true,
                "URL of Spring context-configuration file that defines the test to run");
        options.addOption("c", OPTION_NAME_CONTEXT_PROPERTIES, true,
                "URL of a file defining properties for the test");
        options.addOption("d", OPTION_NAME_SPRING_PROFILES, true,
                "Names of active Spring profiles, separated by spaces");
        CommandLineParser cliParser = new GnuParser();
        CommandLine cli = null;
        try {
            cli = cliParser.parse(options, args);
        } catch (ParseException e) {
            _logger.error("Unable to parse command line parameters", e);
            System.exit(1);
        }

        if (cli.hasOption(OPTION_NAME_HELP)) {
            new HelpFormatter().printHelp("java -jar shared-test.jar", options);
            System.exit(0);
        }

        String contextConfigUrl = cli.getOptionValue(OPTION_NAME_CONTEXT_CONFIG, OPTION_DEFAULT_CONTEXT_CONFIG);
        String contextPropertiesUrl = cli.getOptionValue(OPTION_NAME_CONTEXT_PROPERTIES,
                OPTION_DEFAULT_CONTEXT_PROPERTIES);
        String springProfilesString = cli.getOptionValue(OPTION_NAME_SPRING_PROFILES,
                OPTION_DEFAULT_SPRING_PROFILES);

        // Configure the Spring context
        GenericXmlApplicationContext context = new GenericXmlApplicationContext();
        if (!StringUtils.isEmpty(springProfilesString)) {
            String[] springProfiles = springProfilesString.split(" ");
            context.getEnvironment().setActiveProfiles(springProfiles);
        }
        if (!StringUtils.isEmpty(contextPropertiesUrl)) {
            Properties p = new Properties();
            try {
                p.loadFromXML(new URL(contextPropertiesUrl).openStream());
            } catch (InvalidPropertiesFormatException e) {
                MDC.put("close", "true");
                _logger.error("Error parsing properties file {}", contextPropertiesUrl, e);
                System.exit(1);
            } catch (MalformedURLException e) {
                MDC.put("close", "true");
                _logger.error("Illegal URL for properties file {}", contextPropertiesUrl, e);
                System.exit(1);
            } catch (IOException e) {
                MDC.put("close", "true");
                _logger.error("IO error reading properties file {}", contextPropertiesUrl, e);
                System.exit(1);
            }
            context.getEnvironment().getPropertySources().addFirst(new PropertiesPropertySource("cmdline", p));
        }
        context.load(contextConfigUrl);
        context.refresh();
        setApplicationContext(context);

        // Get the lifecycle resources
        _lifecycleResources = new LifecycleResourceCombiner();
        _lifecycleResources.setApplicationContext(context);

        // Start lifecycle resources
        try {
            _lifecycleResources.startupBeforeDependencies();
            _lifecycleResources.startupAfterDependencies();
        } catch (Exception e) {
            MDC.put("close", "true");
            _logger.error("Error starting lifecycle resources", e);
            System.exit(1);
        }

        // Get the first-person users
        _users = new HashMap<>();
        for (@SuppressWarnings("rawtypes")
        Entry<String, FirstPersonInteractiveUser> entry_i : context.getBeansOfType(FirstPersonInteractiveUser.class)
                .entrySet()) {
            _users.put(entry_i.getKey(), entry_i.getValue());
        }

        // Start first-person scripts
        for (FirstPersonInteractiveUser<?, ?> user_i : _users.values()) {
            user_i.startScript();
        }

        // Wait for conclusion
        for (FirstPersonInteractiveUser<?, ?> user_i : _users.values()) {
            try {
                user_i.join();
            } catch (InterruptedException e) {
                _logger.error("Interrupted running test");
            }
        }

        // Expand any "chorus" users to get the actual users
        int i = 0;
        List<FirstPersonInteractiveUser<?, ?>> allUsers = new ArrayList<>(_users.values());
        while (i < allUsers.size()) {
            FirstPersonInteractiveUser<?, ?> user_i = allUsers.get(i);
            if (user_i instanceof Chorus) {
                allUsers.remove(i);
                for (FirstPersonInteractiveUser<?, ?> user_j : ((Chorus<?, ?>) user_i)) {
                    allUsers.add(user_j);
                }
            } else {
                i++;
            }
        }

        // Log summary interaction statistics
        TimingRecordSummarizer summarizer = new TimingRecordSummarizerImpl();
        for (FirstPersonInteractiveUser<?, ?> user_i : allUsers) {
            for (InteractionContext<?> context_j : user_i.getInteractionContexts()) {
                for (InteractionTimingRecord record_k : context_j.getTimingRecordHistory()) {
                    summarizer.addObservation(record_k);
                }
            }
        }
        _logger.info("Latency summary:\r\n\r\n" + summarizer.getSummaryAsString());

        // Shut down lifecycle resources
        try {
            _lifecycleResources.shutdownBeforeDependencies();
            _lifecycleResources.shutdownAfterDependencies();
        } catch (Exception e) {
            MDC.put("close", "true");
            _logger.error("Error stopping lifecycle resources", e);
            System.exit(1);
        }
        MDC.put("close", "true");
        System.exit(0);
    }
}