mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-21 06:11:46 -04:00
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:
parent
15a1fe8a36
commit
88578bed10
539 changed files with 27629 additions and 8178 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue