diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..766368c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +# Base openjdk:11 +FROM openjdk:11 + +# Add X-Road Test Client jar to container +ADD src/target/x-road-test-client-*.jar test-client.jar + +# Entry with exec +ENTRYPOINT exec java $JAVA_OPTS -jar /test-client.jar \ No newline at end of file diff --git a/README.md b/README.md index 43dd75c..0e21021 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,19 @@ # X-Road Test Client -X-Road Test Client is a testing tool and load generator for X-Road 6 and X-Road 7. The implementation is based on [XRd4J](https://github.com/nordic-institute/xrd4j) library. +X-Road Test Client is a testing tool and load generator for X-Road 6 and X-Road 7. The implementation is based on the [XRd4J](https://github.com/nordic-institute/xrd4j) library. -By default Test Client calls `testService` service of [X-Road Test Service](https://github.com/nordic-institute/X-Road-test-service) project according to given parameters that include: message body size, message attachment size, response body size, response attachment size, number of client threads, interval between messages, number of messages to be sent per client and maximum run time per client. A random String is used as a payload and the same String is used in all the requests in a single execution. However, unique message ID is automatically generated for each request. +By default Test Client calls `testService` service of [X-Road Test Service](https://github.com/nordic-institute/X-Road-test-service) project according to given parameters that include: + +- message body size +- message attachment size +- response body size +- response attachment size +- number of client threads +- interval between messages +- number of messages to be sent per client +- maximum run time per client. + +A random String is used as a payload and the same String is used in all the requests in a single execution. However, unique message ID is automatically generated for each request. ### Customization @@ -18,13 +29,17 @@ https://github.com/nordic-institute/X-Road-test-service#installation ### Try It Out -If you already have access to [X-Road Test Service](https://github.com/nordic-institute/X-Road-test-service)'s `testService` service, the fastest and easiest way to try out the application is to [download](https://github.com/petkivim/x-road-test-client/releases/download/v0.0.7/x-road-test-client-0.0.7.jar) the executable jar version (`x-road-test-client-0.0.7.jar`), copy `settings.properties` and `clients.properties` configuration files in the same directory with the jar file, modify the default configuration (Security Server or X-Road Test Service URL/IP: `settings.properties` => `proxy.url`) and finally run the jar: `java -jar x-road-test-client-0.0.7.jar`. +If you already have access to [X-Road Test Service](https://github.com/nordic-institute/X-Road-test-service)'s `testService` service, the fastest and easiest way to try out the application is to [download](https://github.com/petkivim/x-road-test-client/releases/download/v0.0.8/x-road-test-client-0.0.8.jar) the executable jar version (`x-road-test-client-0.0.8.jar`), copy `settings.properties` and `clients.properties` configuration files in the same directory (specified by the system property `propertiesDirectory`), modify the default configuration (Security Server or X-Road Test Service URL/IP: `settings.properties` => `proxy.url`) and finally run the jar: + +```bash +java -jar -DpropertiesDirectory=/my/custom/path x-road-test-client-0.0.8.jar +``` ### Configuration Test Client has three configuration files: `settings.properties`, `clients.properties` and `log4j.xml`. -By default Test Client uses the configuration files that are packaged inside the jar file. It's possible to override the default configuration copying one or all the configuration files (`settings.properties`, `clients.properties`, `log4j.xml`) and placing them in the same directory with the jar file. When the jar file is run it first looks for the configuration files from the working directory, and for the configuration files that can can not be found it uses the default configuration. For example, it's possible to override `settings.properties` and `clients.properties` placing modified versions in the same directory with the jar file, but use the default configuration for logging. +By default, Test Client uses the configuration files that are packaged inside the jar file. It's possible to override the default configuration copying one or all the configuration files (`settings.properties`, `clients.properties`, `log4j.xml`) and placing them in the same directory that's specified using the system property `propertiesDirectory`. When the jar file is run, it first looks for the configuration files from the `propertiesDirectory` directory, and for the configuration files that can can not be found it uses the default configuration. For example, it's possible to override `settings.properties` and `clients.properties` placing modified versions in the `propertiesDirectory` directory, but use the default configuration for logging. #### settings.properties @@ -76,7 +91,7 @@ By default Test Client uses the configuration files that are packaged inside the **Example** -``` +```properties # Security server URL/IP proxy.url=http://123.456.78.9/ # Number of thread executors @@ -130,7 +145,7 @@ thread.request.maxtime=0 **Example** -``` +```properties # Client ID: instance.memberClass.member.subsystem client=NIIS-TEST.GOV.123456-7.TestClient # Request body size (character cnt) @@ -169,7 +184,7 @@ By default all the output generated by Test Client is printed on console. The de **Default configuration** -``` +```xml @@ -212,3 +227,35 @@ By default all the output generated by Test Client is printed on console. The de ### Building the code Test Client uses Maven as the build management tool. Instructions for [building the code](documentation/Building-the-code.md) with Maven and [setting up a development environment](documentation/Setting-up-development-environment.md) can be found in the documentation. + +### Docker + +You can create a Docker image to run X-Road Test Client inside a container, using the provided Dockerfile. +Before building the image, build the jar file inside `src` directory + +```bash +mvn clean install +``` +If you have not built the jar, building the Docker image will fail with message +```bash +Step 2 : ADD src/target/x-road-test-client-*.jar test-client.jar +No source files were specified +``` + +While you are in the project root directory, build the image using the `docker build` command. The `-t` parameter gives your image a tag, so you can run it more easily later. Don’t forget the `.` command, which tells the `docker build` command to look in the current directory for a file called Dockerfile. + +```bash +docker build -t x-road-test-client . +``` + +After building the image, you can run X-Road Test Client: + +```bash +docker run --rm x-road-test-client +``` + +If customized configuration files are used, the host directory containing the configuration files must be mounted as a data directory. In addition, the directory containing the configuration files inside the container must be set using `JAVA_OPTS` and `propertiesDirectory` property. + +```bash +docker run --rm -v /host/dir/conf:/my/conf -e "JAVA_OPTS=-DpropertiesDirectory=/my/conf" x-road-test-client +``` diff --git a/src/src/main/java/com/pkrete/xroadtestclient/util/ApplicationHelper.java b/src/src/main/java/com/pkrete/xroadtestclient/util/ApplicationHelper.java index 2152872..b676a1a 100644 --- a/src/src/main/java/com/pkrete/xroadtestclient/util/ApplicationHelper.java +++ b/src/src/main/java/com/pkrete/xroadtestclient/util/ApplicationHelper.java @@ -67,10 +67,10 @@ public static String getJarPath() { */ public static void configureLog4j() { LOG.debug("Configure Log4J."); - String path = ApplicationHelper.getJarPath(); - String filePath = path + Constants.LOG4J_SETTINGS_FILE; + String dir = System.getProperty(Constants.PROPERTIES_DIR_PARAM_NAME); + String filePath = dir + "/" + Constants.LOG4J_SETTINGS_FILE; File logConf = new File(filePath); - if (logConf.exists()) { + if (dir != null && logConf.exists()) { DOMConfigurator.configure(logConf.getAbsolutePath()); LOG.debug("Logging configuration loaded from {}", logConf.getAbsolutePath()); } else { diff --git a/src/src/main/java/com/pkrete/xroadtestclient/util/Constants.java b/src/src/main/java/com/pkrete/xroadtestclient/util/Constants.java index b6a290c..dc8f500 100644 --- a/src/src/main/java/com/pkrete/xroadtestclient/util/Constants.java +++ b/src/src/main/java/com/pkrete/xroadtestclient/util/Constants.java @@ -7,8 +7,8 @@ */ public final class Constants { - public static final String GENERAL_SETTINGS_FILE = "settings.properties"; - public static final String CLIENT_SETTINGS_FILE = "clients.properties"; + public static final String GENERAL_SETTINGS_FILE = "/settings.properties"; + public static final String CLIENT_SETTINGS_FILE = "/clients.properties"; public static final String LOG4J_SETTINGS_FILE = "log4j.xml"; public static final String CLIENT = "client"; public static final String CLIENT_REQ_BODY_SIZE = "client.requestBodySize"; @@ -18,6 +18,8 @@ public final class Constants { public static final String SERVICE = "service"; public static final String SERVICE_NAMESPACE = "service.namespace"; + public static final String PROPERTIES_DIR_PARAM_NAME = "propertiesDirectory"; + /** * Constructs and initializes a new Constants object. Should never be used. */ diff --git a/src/src/main/java/com/pkrete/xroadtestclient/util/PropertiesLoader.java b/src/src/main/java/com/pkrete/xroadtestclient/util/PropertiesLoader.java index 4758e15..3e38cae 100644 --- a/src/src/main/java/com/pkrete/xroadtestclient/util/PropertiesLoader.java +++ b/src/src/main/java/com/pkrete/xroadtestclient/util/PropertiesLoader.java @@ -16,7 +16,6 @@ public final class PropertiesLoader { private static final Logger LOG = LoggerFactory.getLogger(PropertiesLoader.class); - private static final String DELIMITER = "/"; private static Properties generalSettings; private static Properties clientSettings; @@ -58,9 +57,9 @@ public static Properties loadClientSettings() { } /** - * Loads properties from a file with the given filename. First the file - * searched from the same directory with the jar file and then from class - * path. + * Loads properties from a file with the given filename. First the file is + * searched from the directory defined by the "propertiesDirectory" property + * and then from class path. * * @param fileName name of the file to be searched * @return properties loaded from the file @@ -68,8 +67,9 @@ public static Properties loadClientSettings() { private static Properties load(String fileName) { LOG.debug("Load settings."); Properties settings; - String path = ApplicationHelper.getJarPath() + fileName; - if (new File(path).exists()) { + String dir = System.getProperty(Constants.PROPERTIES_DIR_PARAM_NAME); + String path = dir + fileName; + if (dir != null && new File(path).exists()) { settings = PropertiesUtil.getInstance().load(path, false); if (settings != null) { LOG.debug("Settings loaded from file \"{}\".", path); @@ -77,9 +77,8 @@ private static Properties load(String fileName) { } } LOG.debug("No external settings file was found from path \"{}\".", path); - path = DELIMITER + fileName; - settings = PropertiesUtil.getInstance().load(path); - LOG.debug("Settings loaded from file \"{}\".", path); + settings = PropertiesUtil.getInstance().load(fileName); + LOG.debug("Settings loaded from file \"{}\".", fileName); return settings; } } diff --git a/src/src/main/java/com/pkrete/xroadtestclient/util/StatisticsCollector.java b/src/src/main/java/com/pkrete/xroadtestclient/util/StatisticsCollector.java index d23a5b4..4feebc3 100644 --- a/src/src/main/java/com/pkrete/xroadtestclient/util/StatisticsCollector.java +++ b/src/src/main/java/com/pkrete/xroadtestclient/util/StatisticsCollector.java @@ -153,6 +153,9 @@ public List getSortedResults() { */ public Double getMedian() { List sortedResults = this.getSortedResults(); + if (sortedResults.size() == 0) { + return 0.0; + } int middle = sortedResults.size() / 2; if (sortedResults.size() % 2 == 1) { return (double) sortedResults.get(middle);