public void execute()

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);
        }
    }