general rebase in order to update payment methods and desktop app

Co-authored-by: Alva Swanson <alvasw@protonmail.com>
Co-authored-by: andyheko <haoen.ko@gmail.com>
Co-authored-by: Bisq GitHub Admin <51445974+bisq-github-admin-3@users.noreply.github.com>
Co-authored-by: BtcContributor <79100296+BtcContributor@users.noreply.github.com>
Co-authored-by: cd2357 <cd2357@users.noreply.github.com>
Co-authored-by: chimp1984 <chimp1984@gmx.com>
Co-authored-by: Chris Beams <chris@beams.io>
Co-authored-by: Christoph Atteneder <christoph.atteneder@gmail.com>
Co-authored-by: Devin Bileck <603793+devinbileck@users.noreply.github.com>
Co-authored-by: ghubstan <36207203+ghubstan@users.noreply.github.com>
Co-authored-by: Huey <hueydane@gmail.com>
Co-authored-by: Jakub Loucký <jakub.loucky@outlook.cz>
Co-authored-by: jmacxx <47253594+jmacxx@users.noreply.github.com>
Co-authored-by: KanoczTomas <tomas.kanocz@cnl.sk>
Co-authored-by: m52go <735155+m52go@users.noreply.github.com>
Co-authored-by: Marcus0x <marcus0x@xrhodium.org>
Co-authored-by: MarnixCroes <93143998+MarnixCroes@users.noreply.github.com>
Co-authored-by: Martin Harrigan <martinharrigan@gmail.com>
Co-authored-by: MwithM <50149324+MwithM@users.noreply.github.com>
Co-authored-by: sqrrm <sqrrm@users.noreply.github.com>
Co-authored-by: Stan <36207203+ghubstan@users.noreply.github.com>
Co-authored-by: Stephan Oeste <emzy@emzy.de>
Co-authored-by: Steven Barclay <stejbac@gmail.com>
Co-authored-by: WAT <shiido.it@gmail.com>
Co-authored-by: wiz <j@wiz.biz>
Co-authored-by: xyzmaker123 <84982606+xyzmaker123@users.noreply.github.com>
This commit is contained in:
woodser 2022-05-26 13:42:10 -04:00
parent 15a1fe8a36
commit 88578bed10
539 changed files with 27629 additions and 8178 deletions

View file

@ -17,10 +17,15 @@
package bisq.apitest;
import java.io.File;
import lombok.extern.slf4j.Slf4j;
import static bisq.apitest.Scaffold.EXIT_FAILURE;
import static bisq.apitest.Scaffold.EXIT_SUCCESS;
import static bisq.apitest.config.ApiTestRateMeterInterceptorConfig.appendCallRateMeteringConfigPathOpt;
import static bisq.apitest.config.ApiTestRateMeterInterceptorConfig.getTestRateMeterInterceptorConfig;
import static bisq.apitest.config.ApiTestRateMeterInterceptorConfig.hasCallRateMeteringConfigPathOpt;
import static java.lang.System.err;
import static java.lang.System.exit;
@ -32,7 +37,7 @@ import bisq.apitest.config.ApiTestConfig;
* ApiTestMain is a placeholder for the gradle build file, which requires a valid
* 'mainClassName' property in the :apitest subproject configuration.
*
* It does has some uses:
* It has some uses:
*
* It can be used to print test scaffolding options: bisq-apitest --help.
*
@ -41,19 +46,23 @@ import bisq.apitest.config.ApiTestConfig;
* It can be used to run the regtest environment for release testing:
* bisq-test --shutdownAfterTests=false
*
* All method, scenario and end to end tests are found in the test sources folder.
* All method, scenario and end-to-end tests are found in the test sources folder.
*
* Requires bitcoind v0.19, v0.20, or v0.21.
* Requires bitcoind v0.19 - v22.
*/
@Slf4j
public class ApiTestMain {
public static void main(String[] args) {
new ApiTestMain().execute(args);
if (!hasCallRateMeteringConfigPathOpt(args))
new ApiTestMain().execute(getAppendedArgs(args));
else
new ApiTestMain().execute(args);
}
public void execute(@SuppressWarnings("unused") String[] args) {
public void execute(String[] args) {
try {
log.info("Configuring test harness with options:\n\t{}", String.join("\n\t", args));
Scaffold scaffold = new Scaffold(args).setUp();
ApiTestConfig config = scaffold.config;
@ -77,4 +86,9 @@ public class ApiTestMain {
exit(EXIT_FAILURE);
}
}
private static String[] getAppendedArgs(String[] args) {
File rateMeterInterceptorConfig = getTestRateMeterInterceptorConfig();
return appendCallRateMeteringConfigPathOpt(args, rateMeterInterceptorConfig);
}
}

View file

@ -160,6 +160,7 @@ public class Scaffold {
try {
log.info("Shutting down executor service ...");
executor.shutdownNow();
//noinspection ResultOfMethodCallIgnored
executor.awaitTermination(config.supportingApps.size() * 2000L, MILLISECONDS);
SetupTask[] orderedTasks = new SetupTask[]{
@ -189,7 +190,7 @@ public class Scaffold {
MILLISECONDS.sleep(1000);
if (p.hasShutdownExceptions()) {
// We log shutdown exceptions, but do not throw any from here
// because all of the background instances must be shut down.
// because all the background instances must be shut down.
p.logExceptions(p.getShutdownExceptions(), log);
// We cache only the 1st shutdown exception and move on to the
@ -221,6 +222,9 @@ public class Scaffold {
}
private void installCallRateMeteringConfiguration(String dataDir) throws IOException, InterruptedException {
if (config.callRateMeteringConfigPath.isEmpty())
return;
File testRateMeteringFile = new File(config.callRateMeteringConfigPath);
if (!testRateMeteringFile.exists())
throw new FileNotFoundException(
@ -289,49 +293,49 @@ public class Scaffold {
startBisqApp(bobdesktop, executor, countdownLatch);
}
private void startBisqApp(HavenoAppConfig havenoAppConfig,
private void startBisqApp(HavenoAppConfig HavenoAppConfig,
ExecutorService executor,
CountDownLatch countdownLatch)
throws IOException, InterruptedException {
HavenoProcess bisqProcess = createBisqProcess(havenoAppConfig);
switch (havenoAppConfig) {
HavenoProcess HavenoProcess = createHavenoProcess(HavenoAppConfig);
switch (HavenoAppConfig) {
case seednode:
seedNodeTask = new SetupTask(bisqProcess, countdownLatch);
seedNodeTask = new SetupTask(HavenoProcess, countdownLatch);
seedNodeTaskFuture = executor.submit(seedNodeTask);
break;
case arbdaemon:
case arbdesktop:
arbNodeTask = new SetupTask(bisqProcess, countdownLatch);
arbNodeTask = new SetupTask(HavenoProcess, countdownLatch);
arbNodeTaskFuture = executor.submit(arbNodeTask);
break;
case alicedaemon:
case alicedesktop:
aliceNodeTask = new SetupTask(bisqProcess, countdownLatch);
aliceNodeTask = new SetupTask(HavenoProcess, countdownLatch);
aliceNodeTaskFuture = executor.submit(aliceNodeTask);
break;
case bobdaemon:
case bobdesktop:
bobNodeTask = new SetupTask(bisqProcess, countdownLatch);
bobNodeTask = new SetupTask(HavenoProcess, countdownLatch);
bobNodeTaskFuture = executor.submit(bobNodeTask);
break;
default:
throw new IllegalStateException("Unknown HavenoAppConfig " + havenoAppConfig.name());
throw new IllegalStateException("Unknown HavenoAppConfig " + HavenoAppConfig.name());
}
log.info("Giving {} ms for {} to initialize ...", config.bisqAppInitTime, havenoAppConfig.appName);
log.info("Giving {} ms for {} to initialize ...", config.bisqAppInitTime, HavenoAppConfig.appName);
MILLISECONDS.sleep(config.bisqAppInitTime);
if (bisqProcess.hasStartupExceptions()) {
bisqProcess.logExceptions(bisqProcess.getStartupExceptions(), log);
throw new IllegalStateException(bisqProcess.getStartupExceptions().get(0));
if (HavenoProcess.hasStartupExceptions()) {
HavenoProcess.logExceptions(HavenoProcess.getStartupExceptions(), log);
throw new IllegalStateException(HavenoProcess.getStartupExceptions().get(0));
}
}
private HavenoProcess createBisqProcess(HavenoAppConfig havenoAppConfig)
private HavenoProcess createHavenoProcess(HavenoAppConfig HavenoAppConfig)
throws IOException, InterruptedException {
HavenoProcess bisqProcess = new HavenoProcess(havenoAppConfig, config);
bisqProcess.verifyAppNotRunning();
bisqProcess.verifyAppDataDirInstalled();
return bisqProcess;
HavenoProcess HavenoProcess = new HavenoProcess(HavenoAppConfig, config);
HavenoProcess.verifyAppNotRunning();
HavenoProcess.verifyAppDataDirInstalled();
return HavenoProcess;
}
private void verifyStartupCompleted()

View file

@ -56,6 +56,8 @@ public class ApiTestConfig {
// Global constants
public static final String BTC = "BTC";
public static final String EUR = "EUR";
public static final String USD = "USD";
public static final String XMR = "XMR";
public static final String ARBITRATOR = "arbitrator";
public static final String MEDIATOR = "mediator";
@ -149,7 +151,7 @@ public class ApiTestConfig {
ArgumentAcceptingOptionSpec<String> configFileOpt =
parser.accepts(CONFIG_FILE, format("Specify configuration file. " +
"Relative paths will be prefixed by %s location.", userDir))
"Relative paths will be prefixed by %s location.", userDir))
.withRequiredArg()
.ofType(String.class)
.defaultsTo(DEFAULT_CONFIG_FILE_NAME);
@ -206,55 +208,55 @@ public class ApiTestConfig {
ArgumentAcceptingOptionSpec<Boolean> runSubprojectJarsOpt =
parser.accepts(RUN_SUBPROJECT_JARS,
"Run subproject build jars instead of full build jars")
"Run subproject build jars instead of full build jars")
.withRequiredArg()
.ofType(Boolean.class)
.defaultsTo(false);
ArgumentAcceptingOptionSpec<Long> bisqAppInitTimeOpt =
parser.accepts(BISQ_APP_INIT_TIME,
"Amount of time (ms) to wait on a Bisq instance's initialization")
"Amount of time (ms) to wait on a Bisq instance's initialization")
.withRequiredArg()
.ofType(Long.class)
.defaultsTo(5000L);
ArgumentAcceptingOptionSpec<Boolean> skipTestsOpt =
parser.accepts(SKIP_TESTS,
"Start apps, but skip tests")
"Start apps, but skip tests")
.withRequiredArg()
.ofType(Boolean.class)
.defaultsTo(false);
ArgumentAcceptingOptionSpec<Boolean> shutdownAfterTestsOpt =
parser.accepts(SHUTDOWN_AFTER_TESTS,
"Terminate all processes after tests")
"Terminate all processes after tests")
.withRequiredArg()
.ofType(Boolean.class)
.defaultsTo(true);
ArgumentAcceptingOptionSpec<String> supportingAppsOpt =
parser.accepts(SUPPORTING_APPS,
"Comma delimited list of supporting apps (bitcoind,seednode,arbdaemon,...")
"Comma delimited list of supporting apps (bitcoind,seednode,arbdaemon,...")
.withRequiredArg()
.ofType(String.class)
.defaultsTo("bitcoind,seednode,arbdaemon,alicedaemon,bobdaemon");
ArgumentAcceptingOptionSpec<String> callRateMeteringConfigPathOpt =
parser.accepts(CALL_RATE_METERING_CONFIG_PATH,
"Install a ratemeters.json file to configure call rate metering interceptors")
"Install a ratemeters.json file to configure call rate metering interceptors")
.withRequiredArg()
.defaultsTo(EMPTY);
ArgumentAcceptingOptionSpec<Boolean> enableBisqDebuggingOpt =
parser.accepts(ENABLE_BISQ_DEBUGGING,
"Start Bisq apps with remote debug options")
"Start Bisq apps with remote debug options")
.withRequiredArg()
.ofType(Boolean.class)
.defaultsTo(false);
ArgumentAcceptingOptionSpec<Boolean> registerDisputeAgentsOpt =
parser.accepts(REGISTER_DISPUTE_AGENTS,
"Register dispute agents in arbitration daemon")
"Register dispute agents in arbitration daemon")
.withRequiredArg()
.ofType(Boolean.class)
.defaultsTo(true);

View file

@ -0,0 +1,70 @@
package bisq.apitest.config;
import java.io.File;
import static bisq.apitest.config.ApiTestConfig.CALL_RATE_METERING_CONFIG_PATH;
import static bisq.proto.grpc.DisputeAgentsGrpc.getRegisterDisputeAgentMethod;
import static bisq.proto.grpc.GetVersionGrpc.getGetVersionMethod;
import static java.lang.System.arraycopy;
import static java.util.Arrays.stream;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import bisq.daemon.grpc.GrpcVersionService;
import bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig;
public class ApiTestRateMeterInterceptorConfig {
public static File getTestRateMeterInterceptorConfig() {
GrpcServiceRateMeteringConfig.Builder builder = new GrpcServiceRateMeteringConfig.Builder();
builder.addCallRateMeter(GrpcVersionService.class.getSimpleName(),
getGetVersionMethod().getFullMethodName(),
1,
SECONDS);
// Only GrpcVersionService is @VisibleForTesting, so we need to
// hardcode other grpcServiceClassName parameter values used in
// builder.addCallRateMeter(...).
builder.addCallRateMeter("GrpcDisputeAgentsService",
getRegisterDisputeAgentMethod().getFullMethodName(),
10, // Same as default.
SECONDS);
// Define rate meters for non-existent method 'disabled', to override other grpc
// services' default rate meters -- defined in their rateMeteringInterceptor()
// methods.
String[] serviceClassNames = new String[]{
"GrpcGetTradeStatisticsService",
"GrpcHelpService",
"GrpcOffersService",
"GrpcPaymentAccountsService",
"GrpcPriceService",
"GrpcTradesService",
"GrpcWalletsService"
};
for (String service : serviceClassNames) {
builder.addCallRateMeter(service, "disabled", 1, MILLISECONDS);
}
File file = builder.build();
file.deleteOnExit();
return file;
}
public static boolean hasCallRateMeteringConfigPathOpt(String[] args) {
return stream(args).anyMatch(a -> a.contains("--" + CALL_RATE_METERING_CONFIG_PATH));
}
public static String[] appendCallRateMeteringConfigPathOpt(String[] args, File rateMeterInterceptorConfig) {
String[] rateMeteringConfigPathOpt = new String[]{
"--" + CALL_RATE_METERING_CONFIG_PATH + "=" + rateMeterInterceptorConfig.getAbsolutePath()
};
if (args.length == 0) {
return rateMeteringConfigPathOpt;
} else {
String[] appendedOpts = new String[args.length + 1];
arraycopy(args, 0, appendedOpts, 0, args.length);
arraycopy(rateMeteringConfigPathOpt, 0, appendedOpts, args.length, rateMeteringConfigPathOpt.length);
return appendedOpts;
}
}
}

View file

@ -108,7 +108,7 @@ abstract class AbstractLinuxProcess implements LinuxProcess {
File bitcoindExecutable = Paths.get(config.bitcoinPath, "bitcoind").toFile();
if (!bitcoindExecutable.exists() || !bitcoindExecutable.canExecute())
throw new IllegalStateException(format("'%s' cannot be found or executed.%n"
+ "A bitcoin-core v0.19, v0.20, or v0.21 installation is required," +
+ "A bitcoin-core v0.19 - v22 installation is required," +
" and the 'bitcoinPath' must be configured in 'apitest.properties'",
bitcoindExecutable.getAbsolutePath()));

View file

@ -24,7 +24,7 @@ import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import static bisq.apitest.config.ApiTestConfig.BASH_PATH_VALUE;
import static java.lang.management.ManagementFactory.getRuntimeMXBean;
@ -33,7 +33,9 @@ import static java.lang.management.ManagementFactory.getRuntimeMXBean;
public class BashCommand {
private int exitStatus = -1;
@Nullable
private String output;
@Nullable
private String error;
private final String command;
@ -92,6 +94,7 @@ public class BashCommand {
}
// TODO return Optional<String>
@Nullable
public String getOutput() {
return this.output;
}
@ -101,7 +104,6 @@ public class BashCommand {
return this.error;
}
@NotNull
private List<String> tokenizeSystemCommand() {
return new ArrayList<>() {{
add(BASH_PATH_VALUE);

View file

@ -57,15 +57,13 @@ class SystemCommandExecutor {
private ThreadedStreamHandler errorStreamHandler;
public SystemCommandExecutor(final List<String> cmdOptions) {
if (log.isDebugEnabled())
log.debug("cmd options {}", cmdOptions.toString());
if (cmdOptions.isEmpty())
throw new IllegalStateException("No command params specified.");
if (cmdOptions.contains("sudo"))
throw new IllegalStateException("'sudo' commands are prohibited.");
log.trace("System cmd options {}", cmdOptions);
this.cmdOptions = cmdOptions;
}