in src/main/java/com/awslabs/aws/greengrass/provisioner/implementations/helpers/BasicGroupTestHelper.java [85:334]
public void execute(TestArguments testArguments) {
GreengrassGroupName greengrassGroupName = ImmutableGreengrassGroupName.builder().groupName(testArguments.groupName).build();
LocalDateTime testStartLocalDateTime = LocalDateTime.now();
if (testArguments.deviceUnderTest == null) {
throw new RuntimeException("No device specified");
}
Optional<String> optionalUrlForDeviceTester = Optional.empty();
if (SystemUtils.IS_OS_WINDOWS) optionalUrlForDeviceTester = Optional.of(WINDOWS_DEVICE_TESTER_URL);
if (SystemUtils.IS_OS_MAC) optionalUrlForDeviceTester = Optional.of(MAC_DEVICE_TESTER_URL);
if (SystemUtils.IS_OS_LINUX) optionalUrlForDeviceTester = Optional.of(LINUX_DEVICE_TESTER_URL);
if (!optionalUrlForDeviceTester.isPresent()) {
throw new RuntimeException("Could not determine host operating system");
}
String urlForDeviceTester = optionalUrlForDeviceTester.get();
Optional<GroupInformation> optionalGroupInformation = v2GreengrassHelper.getGroupInformation(greengrassGroupName).findFirst();
if (!optionalGroupInformation.isPresent()) {
throw new RuntimeException(String.join("", "Group [", testArguments.groupName, "] not found"));
}
GroupInformation groupInformation = optionalGroupInformation.get();
File deviceTesterDirectory = null;
// Download and extract the tester or use the existing one
if (testArguments.deviceTesterLocation != null) {
// It is downloaded already
File deviceTesterLocation = new File(testArguments.deviceTesterLocation);
if (!deviceTesterLocation.exists()) {
throw new RuntimeException(String.format("Device Tester could not be found at the specified location [%s]", testArguments.deviceTesterLocation));
}
if (deviceTesterLocation.isFile()) {
// It's the archive, we need to extract it
deviceTesterDirectory = Try.of(() -> extractDeviceTester(deviceTesterLocation)).get();
}
} else {
File deviceTesterZip = Try.of(() -> ioHelper.getTempFile("devicetester", "zip")).get();
log.info("Downloading Device Tester to [{}] ...", deviceTesterZip.getAbsolutePath());
// CloudFront requires the referer to be filled in
Try.run(() -> ioHelper.download(urlForDeviceTester, deviceTesterZip, Optional.of("https://aws.amazon.com/greengrass/device-tester/"))).get();
deviceTesterDirectory = Try.of(() -> extractDeviceTester(deviceTesterZip)).get();
}
// Create the <AWS Account #>.<Region>.CoreAndGroupInfo.json file for /var/lib/GGQ on the device
log.info("Download and extraction of Device Tester is complete");
// Connect to the device under test via SSH
Session session = null;
try {
session = sshHelper.getSshSession(testArguments.deviceUnderTest,
testArguments.user,
SSH_CONNECTED_MESSAGE,
SSH_TIMED_OUT_MESSAGE,
SSH_CONNECTION_REFUSED_MESSAGE,
SSH_ERROR_MESSAGE,
SSH_TIMEOUT_IN_MINUTES,
TimeUnit.MINUTES);
// Create a final version of this variable so it can be used in lambdas
final Session finalSession = session;
// Clear out the GGQ directory
if (testArguments.clean) {
log.info("Cleaning the {} directory", VAR_LIB_GGQ);
Try.of(() -> ioHelper.runCommand(finalSession, String.join(" ", "sudo rm -rf", VAR_LIB_GGQ))).get();
} else if (testArguments.generateConfig) {
log.info("Generating the {} config", VAR_LIB_GGQ);
// Copy the <AWS Account #>.<Region>.CoreAndGroupInfo.json to /var/lib/GGQ on the device
Try.of(() -> ioHelper.runCommand(finalSession, String.join(" ", "sudo mkdir -p", VAR_LIB_GGQ))).get();
Try.of(() -> ioHelper.runCommand(finalSession, String.join(" ", "sudo chmod 777", VAR_LIB_GGQ))).get();
File coreAndGroupInfoJsonTemp = Try.of(() -> ioHelper.getTempFile("CoreAndGroupInfoJson", "tmp")).get();
coreAndGroupInfoJsonTemp.deleteOnExit();
String coreAndGroupInfoJson = generateCoreAndGroupInfoJson(groupInformation);
ioHelper.writeFile(coreAndGroupInfoJsonTemp, coreAndGroupInfoJson.getBytes());
String remoteCoreAndGroupInfoFilename = String.join("/",
VAR_LIB_GGQ,
String.join(".",
iamHelper.getAccountId().getId(),
awsHelper.getCurrentRegion().toString(),
"CoreAndGroupInfo",
"json"));
Try.run(() -> ioHelper.sendFile(finalSession, coreAndGroupInfoJsonTemp.getAbsolutePath(), remoteCoreAndGroupInfoFilename)).get();
} else {
log.info("Not cleaning or generating the config in {}", VAR_LIB_GGQ);
}
// Stop Greengrass if it is running already
log.info("Stopping Greengrass if it is running");
Try.of(() -> ioHelper.runCommand(finalSession, "sudo systemctl stop greengrass")).get();
Try.of(() -> ioHelper.runCommand(finalSession, "/greengrass/ggc/core/greengrassd stop")).get();
// Create the config.json for the local configs directory
String localConfigJson = createLocalConfigJson();
// Create the device.json for the local configs directory
String localDeviceJson = createLocalDeviceJson(testArguments.deviceUnderTest, testArguments.user, testArguments.privateKeyPath, testArguments.architecture);
List<File> topLevelFiles = List.of(deviceTesterDirectory.listFiles());
if (topLevelFiles.size() != 1) {
throw new RuntimeException("Extracted more files than expected, could not find configs directory");
}
deviceTesterDirectory = topLevelFiles.single();
Path configsPath = deviceTesterDirectory.toPath().resolve("configs");
if (!configsPath.toFile().exists()) {
throw new RuntimeException("Could not find configs directory");
}
// Copy config.json to the local configs directory
ioHelper.writeFile(configsPath.resolve("config.json").toAbsolutePath().toString(), localConfigJson.getBytes());
// Copy device.json to the local configs directory
ioHelper.writeFile(configsPath.resolve("device.json").toAbsolutePath().toString(), localDeviceJson.getBytes());
Path deviceTesterPath = deviceTesterDirectory.toPath();
// Look for all of the binaries in subdirectories and make them executable
Try.of(() -> java.nio.file.Files.walk(deviceTesterPath.resolve("tests"))).get()
.map(path -> path.toAbsolutePath().toString())
.filter(path -> path.matches(".*/bin/[^/]+$"))
.forEach(ioHelper::makeExecutable);
// Execute some cleanup commands to prevent test failures
// Prevent "File exists" error on ipd_test_1 and ipd_test_2 if the test ran previously
Try.of(() -> ioHelper.runCommand(finalSession, "sudo ip address del 172.0.0.2/32 dev lo")).get();
// Find the binary and execute it
List<File> mainExecutables = List.of(deviceTesterDirectory.toPath().resolve("bin").toFile().listFiles());
if (mainExecutables.size() != 1) {
throw new RuntimeException("Could not locate the Device Tester binary");
}
File mainExecutable = mainExecutables.single();
ioHelper.makeExecutable(mainExecutable.getAbsolutePath());
File executionDirectory = mainExecutable.getParentFile().getParentFile();
List<String> deviceTesterAndArguments = List.of(
String.join("", "./bin/", mainExecutable.getName()),
"run-suite",
"--suite-id",
"GGQ_1",
"--pool-id",
DEVICE_POOL_ID);
ProcessBuilder deviceTesterProcessBuilder = processHelper.getProcessBuilder(deviceTesterAndArguments.asJava())
.directory(executionDirectory);
Instant testStart = Instant.now();
java.util.HashMap<String, Try> testStatus = new java.util.HashMap<>();
java.util.List<String> reportLocations = new ArrayList<>();
// Kill any existing proxies left over from previous runs
killRemoteProcessesBySearchString(finalSession, PROXY_SEARCH_STRING);
// Kill any existing daemons left over from previous runs
killRemoteProcessesBySearchString(finalSession, DAEMON_SEARCH_STRING);
// Kill any existing tail commands we may have started in previous runs
killRemoteProcessesBySearchString(finalSession, TAIL_FOLLOW_COMMAND);
// Remove the existing runtime.log
Try.of(() -> ioHelper.runCommand(finalSession, String.join(" ", "sudo rm -f", FULL_RUNTIME_LOG_PATH))).get();
// Start device tester
Optional<Integer> exitVal = processHelper.getOutputFromProcess(log, deviceTesterProcessBuilder, true,
Optional.of(stdoutLogMessage -> handleLogMessage(stdoutLogMessage, testStatus, reportLocations)),
Optional.of(stderrLogMessage -> handleLogMessage(stderrLogMessage, testStatus, reportLocations)));
Instant testEnd = Instant.now();
Duration testDuration = Duration.between(testStart, testEnd);
log.info("Test duration: [{}]", testDuration);
exitVal.ifPresent(this::logIfDeviceTesterExitedWithError);
java.util.List<String> testNames = testStatus.entrySet()
.stream()
.map(Map.Entry::getKey)
.collect(Collectors.toList());
java.util.List<String> passingTests = testStatus.entrySet()
.stream()
.filter(entry -> entry.getValue().isSuccess())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
java.util.List<String> failingTests = testStatus.entrySet()
.stream()
.filter(entry -> entry.getValue().isFailure())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
if (testNames.size() == 0) {
log.error("No tests executed");
} else {
log.info("Tests executed: ");
testNames.stream().forEach(log::info);
}
if (passingTests.size() == 0) {
log.error("No tests passed");
} else {
log.info("Tests passed: ");
passingTests.forEach(log::info);
}
if (failingTests.size() == 0) {
log.info("No tests failed");
} else {
log.warn("Tests failed: ");
failingTests.forEach(log::warn);
}
// Move the results to the requested location
String groupName = testArguments.groupName;
String outputDirectory = String.join("/", testArguments.outputDirectory,
String.join("-", groupName, testStartLocalDateTime.toString()));
reportLocations.stream().findFirst().ifPresent(path ->
Try.run(() -> moveParentDirectory(path, outputDirectory))
.onFailure(Throwable::printStackTrace)
.get());
} finally {
safeDisconnect(session);
}
}