/*
* Copyright 2016 higherfrequencytrading.com
*
* 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 net.openhft.chronicle.engine.mit;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.IntConsumer;
import java.util.stream.IntStream;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
public class TestUtils {
/**
* Calculates the runtime in nanoseconds from the given start time in nanoseconds.
* Prints the runtime in nanos, millis and seconds.
*
* @param startTimeInNanoseconds Start time in nanos.
* @return Runtime in nanos.
*/
public static long calculateAndPrintRuntime(long startTimeInNanoseconds) {
return calculateAndPrintRuntime(startTimeInNanoseconds, 1);
}
public static long calculateAndPrintRuntime(long startTimeInNanoseconds, int count) {
long endNanoTime = System.nanoTime();
return printRuntime(endNanoTime - startTimeInNanoseconds, count);
}
public static long printRuntime(long runtimeNanoSeconds, int count) {
double runtimeMilliseconds = (double) runtimeNanoSeconds / 1000000.0;
double runtimeSeconds = runtimeMilliseconds / 1000.0;
System.out.printf("For %,d tests, Runtime: %,d nanoseconds | %.1f milliseconds | %.3f seconds%s%n",
count, runtimeNanoSeconds / count, runtimeMilliseconds / count, runtimeSeconds / count, count > 1 ? " average" : "");
return runtimeNanoSeconds / count;
}
/**
* Run the test code the configured number of times and verify that the average runtime is less than or equal
* to the given max runtime.
*
* @param testToRun Test code to run configured number of times.
* @param noOfRuns Runs.
* @param maxRuntimeInNanos Max runtime.
*/
public static void runMultipleTimesAndVerifyAvgRuntime(@NotNull Runnable testToRun, int noOfRuns, long maxRuntimeInNanos) {
runMultipleTimesAndVerifyAvgRuntime(x -> {
}, testToRun, noOfRuns, maxRuntimeInNanos);
}
public static void runMultipleTimesAndVerifyAvgRuntime(@NotNull IntConsumer setup, @NotNull Runnable testToRun, int noOfRuns, long maxRuntimeInNanos) {
@NotNull AtomicLong totalTime = new AtomicLong();
// one warmup.
IntStream.range(0, noOfRuns).forEach(e -> {
setup.accept(e);
long start = System.nanoTime();
testToRun.run();
long delta = System.nanoTime() - start;
// System.out.println(delta/1e9+" secs");
totalTime.addAndGet(delta);
});
long runtimeInNanos = printRuntime(totalTime.get(), noOfRuns);
Assert.assertTrue(runtimeInNanos + " > " + maxRuntimeInNanos, runtimeInNanos <= maxRuntimeInNanos);
}
/**
* Loads the given file into a string.
*
* @param fileName Name of the resource to load.
* @return String value of the text file.
* @throws IOException
*/
public static String loadSystemResourceFileToString(String fileName) throws IOException, URISyntaxException {
URL testFileUrl = ClassLoader.getSystemResource(fileName);
URI testFileUri = testFileUrl.toURI();
@NotNull final StringBuilder stringBuilder = new StringBuilder();
Files.lines(Paths.get(testFileUri)).forEach(stringBuilder::append);
return stringBuilder.toString();
}
/**
* Loads the given system resource and assumes it is a csv file with a key and value column. These key/value pairs
* are loaded into a map.
*
* @param resourcePath Path to resource file that is to be loaded into a map.
* @return Map loaded with key/value pairs from the resource file.
* @throws IOException
* @throws URISyntaxException
*/
@NotNull
public static Map<String, Double> loadSystemResourceKeyValueCsvFileToMap(String resourcePath) throws IOException, URISyntaxException {
URL testFileUrl = ClassLoader.getSystemResource(resourcePath);
URI testFileUri = testFileUrl.toURI();
@NotNull Map<String, Double> results = new HashMap<>();
Files.lines(Paths.get(testFileUri)).forEach(x -> {
@NotNull String[] strings = x.split(",");
results.put(strings[0], Double.parseDouble(strings[1]));
});
return results;
}
/**
* @param extension
* @param stringToWrite
* @throws IOException
*/
public static void saveTestFileToDisk(String extension, @NotNull String stringToWrite) throws IOException {
Files.write(Paths.get("./test" + extension), stringToWrite.getBytes(ISO_8859_1));
}
public static void deleteTestFile(String extension) throws IOException {
deleteFile(Paths.get("./test" + extension).toString());
}
public static void deleteFile(@NotNull String path) {
try {
Files.deleteIfExists(Paths.get(path));
} catch (Exception e) {
System.err.println(String.format("Failed to delete file '%s'. Exception: %s", path, e));
}
}
public static void createDirectoryIfNotExists(@NotNull String directoryName) {
@NotNull File directory = new File(directoryName);
if (!directory.exists()) {
System.out.println("Creating directory: " + directoryName);
boolean result = false;
try {
directory.mkdir();
result = true;
} catch (SecurityException se) {
System.out.println("Could not create directory '%s'.");
}
if (result) {
System.out.println("DIR created");
}
}
}
/**
* @param mapName Name of map
* @param counter Counter to be used for key
* @return Generated value based on map name and counter
*/
public static String getValue(String mapName, int counter) {
return String.format("Val-%s-%s", mapName, counter);
}
/**
* @param mapName Name of map
* @param counter Counter to be used for key
* @return Generated key based on map name and counter
*/
public static String getKey(String mapName, int counter) {
return String.format("%s-%s", mapName, counter);
}
}