<commit_before>package bisq.apitest;

import bisq.common.config.BisqHelpFormatter;
import bisq.common.util.Utilities;

import java.io.IOException;

import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;

import static bisq.apitest.config.BisqAppConfig.*;
import static java.lang.String.format;
import static java.lang.System.err;
import static java.lang.System.exit;
import static java.lang.System.out;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;



import bisq.apitest.config.ApiTestConfig;
import bisq.apitest.config.BisqAppConfig;
import bisq.apitest.linux.BisqApp;
import bisq.apitest.linux.BitcoinDaemon;

@Slf4j
public class Scaffold {

    public static final int EXIT_SUCCESS = 0;
    public static final int EXIT_FAILURE = 1;

    final ApiTestConfig config;

    @Nullable
    private SetupTask bitcoindTask;
    @Nullable
    private Future<SetupTask.Status> bitcoindTaskFuture;
    @Nullable
    private SetupTask seedNodeTask;
    @Nullable
    private Future<SetupTask.Status> seedNodeTaskFuture;
    @Nullable
    private SetupTask arbNodeTask;
    @Nullable
    private Future<SetupTask.Status> arbNodeTaskFuture;
    @Nullable
    private SetupTask aliceNodeTask;
    @Nullable
    private Future<SetupTask.Status> aliceNodeTaskFuture;
    @Nullable
    private SetupTask bobNodeTask;
    @Nullable
    private Future<SetupTask.Status> bobNodeTaskFuture;

    private final ExecutorService executor;

    public Scaffold(String[] args) {
        this(new ApiTestConfig(args));
    }

    public Scaffold(ApiTestConfig config) {
        verifyNotWindows();
        this.config = config;
        this.executor = Executors.newFixedThreadPool(config.numSetupTasks);
        if (config.helpRequested) {
            config.printHelp(out,
                    new BisqHelpFormatter(
                            "Bisq ApiTest",
                            "bisq-apitest",
                            "0.1.0"));
            exit(EXIT_SUCCESS);
        }
    }


    public Scaffold setUp() {
        try {
            // Start each background process from an executor, then add a shutdown hook.
            CountDownLatch countdownLatch = new CountDownLatch(config.numSetupTasks);
            startBackgroundProcesses(executor, countdownLatch);
            installShutdownHook();

            // Wait for all submitted startup tasks to decrement the count of the latch.
            Objects.requireNonNull(countdownLatch).await();

            // Verify each startup task's future is done.
            verifyStartupCompleted();

        } catch (Throwable ex) {
            err.println("Fault: An unexpected error occurred. " +
                    "Please file a report at https://bisq.network/issues");
            ex.printStackTrace(err);
            exit(EXIT_FAILURE);
        }
        return this;
    }

    public ApiTestConfig getConfig() {
        return config;
    }

    public void tearDown() {
        if (!executor.isTerminated()) {
            try {
                log.info("Shutting down executor service ...");
                executor.shutdownNow();
                executor.awaitTermination(config.numSetupTasks * 2000, MILLISECONDS);
                SetupTask[] orderedTasks = new SetupTask[]{bobNodeTask, aliceNodeTask, arbNodeTask, seedNodeTask, bitcoindTask};
                Arrays.stream(orderedTasks).filter(t -> t != null && t.getLinuxProcess() != null).forEachOrdered(t -> {
                    try {
                        t.getLinuxProcess().shutdown();
                        MILLISECONDS.sleep(1500);
                    } catch (IOException | InterruptedException ex) {
                        throw new IllegalStateException(ex);
                    }
                });
                log.info("Teardown complete");
            } catch (Exception ex) {
                throw new IllegalStateException(ex);
            }
        }
    }

    private void installShutdownHook() {
        // A test may shut down background apps, or they may be left running until
        // the jvm is manually shutdown, so we add a shutdown hook for that use case.
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            tearDown();
        }));
    }

    // Starts bitcoind and bisq apps (seednode, arbnode, etc...)
    private void startBackgroundProcesses(ExecutorService executor,
                                          CountDownLatch countdownLatch)
            throws InterruptedException, IOException {
        // The configured number of setup tasks determines which bisq apps are started in<commit_msg>Add license note, format tearDown(), fix comment<commit_after>/*
 * This file is part of Bisq.
 *
 * Bisq is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 *
 * Bisq is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Bisq. If not, see <http://www.gnu.org/licenses/>.
 */

package bisq.apitest;

import bisq.common.config.BisqHelpFormatter;
import bisq.common.util.Utilities;

import java.io.IOException;

import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;

import static bisq.apitest.config.BisqAppConfig.*;
import static java.lang.String.format;
import static java.lang.System.err;
import static java.lang.System.exit;
import static java.lang.System.out;
import static java.util.Arrays.stream;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;



import bisq.apitest.config.ApiTestConfig;
import bisq.apitest.config.BisqAppConfig;
import bisq.apitest.linux.BisqApp;
import bisq.apitest.linux.BitcoinDaemon;

@Slf4j
public class Scaffold {

    public static final int EXIT_SUCCESS = 0;
    public static final int EXIT_FAILURE = 1;

    public final ApiTestConfig config;

    @Nullable
    private SetupTask bitcoindTask;
    @Nullable
    private Future<SetupTask.Status> bitcoindTaskFuture;
    @Nullable
    private SetupTask seedNodeTask;
    @Nullable
    private Future<SetupTask.Status> seedNodeTaskFuture;
    @Nullable
    private SetupTask arbNodeTask;
    @Nullable
    private Future<SetupTask.Status> arbNodeTaskFuture;
    @Nullable
    private SetupTask aliceNodeTask;
    @Nullable
    private Future<SetupTask.Status> aliceNodeTaskFuture;
    @Nullable
    private SetupTask bobNodeTask;
    @Nullable
    private Future<SetupTask.Status> bobNodeTaskFuture;

    private final ExecutorService executor;

    public Scaffold(String[] args) {
        this(new ApiTestConfig(args));
    }

    public Scaffold(ApiTestConfig config) {
        verifyNotWindows();
        this.config = config;
        this.executor = Executors.newFixedThreadPool(config.numSetupTasks);
        if (config.helpRequested) {
            config.printHelp(out,
                    new BisqHelpFormatter(
                            "Bisq ApiTest",
                            "bisq-apitest",
                            "0.1.0"));
            exit(EXIT_SUCCESS);
        }
    }


    public Scaffold setUp() {
        try {
            // Start each background process from an executor, then add a shutdown hook.
            CountDownLatch countdownLatch = new CountDownLatch(config.numSetupTasks);
            startBackgroundProcesses(executor, countdownLatch);
            installShutdownHook();

            // Wait for all submitted startup tasks to decrement the count of the latch.
            Objects.requireNonNull(countdownLatch).await();

            // Verify each startup task's future is done.
            verifyStartupCompleted();

        } catch (Throwable ex) {
            err.println("Fault: An unexpected error occurred. " +
                    "Please file a report at https://bisq.network/issues");
            ex.printStackTrace(err);
            exit(EXIT_FAILURE);
        }
        return this;
    }

    public void tearDown() {
        if (!executor.isTerminated()) {
            try {
                log.info("Shutting down executor service ...");
                executor.shutdownNow();
                executor.awaitTermination(config.numSetupTasks * 2000, MILLISECONDS);

                SetupTask[] orderedTasks = new SetupTask[]{
                        bobNodeTask, aliceNodeTask, arbNodeTask, seedNodeTask, bitcoindTask};
                stream(orderedTasks).filter(t -> t != null && t.getLinuxProcess() != null)
                        .forEachOrdered(t -> {
                            try {
                                t.getLinuxProcess().shutdown();
                                MILLISECONDS.sleep(1000);
                            } catch (IOException | InterruptedException ex) {
                                throw new IllegalStateException(ex);
                            }
                        });

                log.info("Teardown complete");
            } catch (Exception ex) {
                throw new IllegalStateException(ex);
            }
        }
    }

    private void installShutdownHook() {
        // Background apps can be left running until the jvm is manually shutdown,
        // so we add a shutdown hook for that use case.
        Runtime.getRuntime().addShutdownHook(new Thread(this::tearDown));
    }

    // Starts bitcoind and bisq apps (seednode, arbnode, etc...)
    private void startBackgroundProcesses(ExecutorService executor,
                                          CountDownLatch countdownLatch)
            throws InterruptedException, IOException {
        // The configured number of setup tasks determines which bisq apps are started in
{'fraction_non_alphanumeric': 0.082122851988987, 'fraction_numerical': 0.0031330105383081744, 'mean_word_length': 2.3324897184435307, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 19, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7142951', 'n_tokens_mistral': 2847, 'n_tokens_neox': 2758, 'n_words': 740}