Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API test harness for Linux & OSX #4366

Merged
merged 88 commits into from Aug 24, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
88b5e9d
Add configuration support
ghubstan Jul 9, 2020
e0c27ee
Add main resource files
ghubstan Jul 9, 2020
77b6878
Add script to get Bisq app pid
ghubstan Jul 9, 2020
c0c75e2
Support starting bitcoin & bisq apps on Linux
ghubstan Jul 9, 2020
ae3b263
Add :apitest main driver, setup task & dummy tests
ghubstan Jul 9, 2020
e9baebc
Add build tasks for installing dao-setup files
ghubstan Jul 9, 2020
2cd80aa
Add subproject :apitest to gradle build file
ghubstan Jul 9, 2020
09929c8
Fix codacy problems
ghubstan Jul 9, 2020
efbaa5b
Fix codacy problems
ghubstan Jul 9, 2020
05d0ce0
Fix codacy problem
ghubstan Jul 9, 2020
ca378cd
Fix error msg spacing
ghubstan Jul 10, 2020
798fde8
Fix error msgs
ghubstan Jul 10, 2020
e61a42d
Remove MaxRAM from DEFAULT_JVM_OPTS
ghubstan Jul 10, 2020
898219a
Assume bitcoin-core is statically linked to berkeley-db
ghubstan Jul 11, 2020
a1e2536
Fix hanging background process problem
ghubstan Jul 11, 2020
8519021
Add line break in front of port config
ghubstan Jul 12, 2020
87525ca
Move test setup scaffolding into new Scaffold class
ghubstan Jul 12, 2020
2c10836
Expose grpc service stubs
ghubstan Jul 12, 2020
ffe376e
Fix codacy problems
ghubstan Jul 12, 2020
390cba1
Fix codacy problem
ghubstan Jul 12, 2020
96cabfb
Support @Skip on test classes and methods
ghubstan Jul 13, 2020
0edcc3b
Add first method test cases
ghubstan Jul 13, 2020
81aeedd
Add MethodTestSuite
ghubstan Jul 13, 2020
8da4646
Update bats version test
ghubstan Jul 13, 2020
db5a685
Make init() method public
ghubstan Jul 13, 2020
65e3370
Add license note, format tearDown(), fix comment
ghubstan Jul 13, 2020
fae661c
Run MethodTestSuite
ghubstan Jul 13, 2020
458d2f3
Add license note
ghubstan Jul 13, 2020
4d5c767
Fix codacy problem
ghubstan Jul 13, 2020
35ff4e5
Delete commented statement
ghubstan Jul 13, 2020
d782e8d
Do not run dummy test from driver
ghubstan Jul 13, 2020
84976fe
Fix varible names
ghubstan Jul 13, 2020
2678b31
Remove test scaffolding logic from ApiTestConfig
ghubstan Jul 13, 2020
486f06b
Refresh dao-setup files in Scaffold setup
ghubstan Jul 13, 2020
e17480a
Remove hacked method tests
ghubstan Jul 13, 2020
080952b
Support @Order-ing of JUnit tests
ghubstan Jul 13, 2020
4f08ec3
Add first JUnit 'method' tests
ghubstan Jul 13, 2020
84af092
Add driver for running method tests
ghubstan Jul 14, 2020
1acf340
Get rid of references to removed @Skip annotation
ghubstan Jul 14, 2020
8ed44b8
Remove @Skip annotaion
ghubstan Jul 14, 2020
45c1a97
Fix codacy problem in bash script
ghubstan Jul 14, 2020
6b738f7
Replace config 'numSetupTasks' with 'supportingApps'
ghubstan Jul 14, 2020
498939a
Allow more time for background app shutdown
ghubstan Jul 14, 2020
5df0b1e
Refactor ApiTestCase class hierarchy
ghubstan Jul 14, 2020
2cf7915
Add wallet protect method tests
ghubstan Jul 14, 2020
28aefc5
Add tests for resetting a wallet password
ghubstan Jul 14, 2020
a00bc4b
Add --bisqAppInitTime=<Long> config option
ghubstan Jul 15, 2020
cf3b545
Fix hardcoded bitcoin.conf property values
ghubstan Jul 15, 2020
d108d89
Fix comment and code styling
ghubstan Jul 15, 2020
c19afeb
Fix 'bitcoind not found' error message
ghubstan Jul 15, 2020
b2417d3
Delete throws clause from method signature
ghubstan Jul 15, 2020
e0ea9db
Fix bitcoind startup error handling
ghubstan Jul 15, 2020
431cbe7
Bump bisqAppInitTime default back up to 5s
ghubstan Jul 15, 2020
4296d96
Remove all sudo related logic from the linux pkg
ghubstan Jul 16, 2020
7d664d9
Do not "killall bitcoind" processes
ghubstan Jul 16, 2020
6edab1a
Create convenient way to call bitcoin-cli from tests
ghubstan Jul 16, 2020
687bcf1
Add FundWalletScenarioTest
ghubstan Jul 16, 2020
2852e3d
Add JUnitHelper to run tests from JUnitCore
ghubstan Jul 16, 2020
5d7133a
Do not subtract fee from 'bitcoin-cli sendtoaddress'
ghubstan Jul 17, 2020
8269a0d
Remove final modifier
ghubstan Jul 17, 2020
f7d8c0e
Do not use bitcoin.conf files
ghubstan Jul 17, 2020
1847da0
Delete unused bitcoin.conf from resources dir
ghubstan Jul 17, 2020
19346bb
Delete all JUnit related class from main sources
ghubstan Jul 19, 2020
7c974b2
Moving GrpcStubs to test sources
ghubstan Jul 19, 2020
bf584c2
Move test cases into subproject test sources
ghubstan Jul 19, 2020
591c8b2
Change :apitest:test task system property name
ghubstan Jul 20, 2020
b4d3ea7
Add comment about Bisq DAO dev environment
ghubstan Jul 20, 2020
999e9ec
Fix @BeforeClass error handling and use jupiter api
ghubstan Jul 20, 2020
13a8396
Remove unnecessary curly braces
ghubstan Jul 20, 2020
cf031e6
Change 'missing bitcoind path' error msg
ghubstan Jul 22, 2020
27ee4b8
Do not leave orphaned processes after failed teardown
ghubstan Jul 27, 2020
e2f00b7
Remove extra whiteline
ghubstan Jul 27, 2020
8bb7e12
Clarify scaffold tear down error handling
ghubstan Jul 28, 2020
685839d
Add fallbackfee param to bitcoind start cmd
ghubstan Aug 12, 2020
176f0b2
Fix BitcoinCli wrapper error handling
ghubstan Aug 13, 2020
9637cc0
Fix test fail() msg
ghubstan Aug 13, 2020
72ff4dc
Use non-default regtest bitcoind -rpcport
ghubstan Aug 15, 2020
e88bdb9
Add regtest-port-conflicts.md doc
ghubstan Aug 15, 2020
12d52e8
Fix port number typo
ghubstan Aug 15, 2020
fc54125
Add build / run / test categories docs
ghubstan Aug 17, 2020
f85ae2b
Explain how to run test cases from Intellij
ghubstan Aug 17, 2020
af7252e
Fix typo
ghubstan Aug 17, 2020
8b081ad
Update README
ghubstan Aug 17, 2020
c3abd4e
Remove white lines
ghubstan Aug 18, 2020
fa11dab
Add punctuation & re-phrase sentence in README
ghubstan Aug 19, 2020
2ba0ee9
Change access modifer
ghubstan Aug 19, 2020
ba8b9cc
Put 'empty' comments inside ignored catch blocks
ghubstan Aug 19, 2020
1de6239
Shorten line length < 120 chars
ghubstan Aug 24, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
255 changes: 10 additions & 245 deletions apitest/src/main/java/bisq/apitest/ApiTestMain.java
Expand Up @@ -17,118 +17,47 @@

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 bisq.apitest.Scaffold.EXIT_FAILURE;
import static bisq.apitest.Scaffold.EXIT_SUCCESS;
import static java.lang.System.err;
import static java.lang.System.exit;
import static java.lang.System.out;
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;

/**
* ApiTest Application
*
* Requires bitcoind v0.19.1
* Runs all method tests, scenario tests, and end to end tests (e2e).
*
* Requires bitcoind v0.19.x
*/
@Slf4j
public class ApiTestMain {

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

@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 ApiTestConfig config;

public static void main(String[] args) {
new ApiTestMain().execute(args);
}

public void execute(@SuppressWarnings("unused") String[] args) {
try {
verifyNotWindows();

log.info("Starting...");

config = new ApiTestConfig(args);
if (config.helpRequested) {
config.printHelp(out,
new BisqHelpFormatter(
"Bisq ApiTest",
"bisq-apitest",
"0.1.0"));
exit(EXIT_SUCCESS);
}

// Start each background process from an executor, then add a shutdown hook.
ExecutorService executor = Executors.newFixedThreadPool(config.numSetupTasks);
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();
Scaffold scaffold = new Scaffold(args).setUp();
ApiTestConfig config = scaffold.config;

if (config.skipTests) {
log.info("Skipping tests ...");
} else {
log.info("Run tests now ...");
SECONDS.sleep(3);
new SmokeTestBitcoind(config).runSmokeTest();
new SmokeTestBitcoind(config).run();
}

if (config.shutdownAfterTests) {
log.info("Shutting down executor service ...");
executor.shutdownNow();
executor.awaitTermination(10, SECONDS);
scaffold.tearDown();
exit(EXIT_SUCCESS);
} else {
log.info("Not shutting down executor service ...");
log.info("Test setup processes will run until ^C / kill -15 is rcvd ...");
log.info("Not shutting down scaffolding background processes will run until ^C / kill -15 is rcvd ...");
}

} catch (Throwable ex) {
Expand All @@ -138,168 +67,4 @@ public void execute(@SuppressWarnings("unused") String[] args) {
exit(EXIT_FAILURE);
}
}

// 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
// the background, and in what order.
//
// If config.numSetupTasks = 0, no setup tasks are run. If 1, the bitcoind
// process is started in the background. If 2, bitcoind and seednode.
// If 3, bitcoind, seednode and arbnode are started. If 4, bitcoind, seednode,
// arbnode, and alicenode are started. If 5, bitcoind, seednode, arbnode,
// alicenode and bobnode are started.
//
// This affords an easier way to choose which setup tasks are run, rather than
// commenting and uncommenting code blocks. You have to remember seednode
// depends on bitcoind, arbnode on seednode, and that bob & alice cannot trade
// unless arbnode is running with a registered mediator and refund agent.
if (config.numSetupTasks > 0) {
BitcoinDaemon bitcoinDaemon = new BitcoinDaemon(config);
bitcoinDaemon.verifyBitcoinConfig(true);
bitcoindTask = new SetupTask(bitcoinDaemon, countdownLatch);
bitcoindTaskFuture = executor.submit(bitcoindTask);
SECONDS.sleep(5);
bitcoinDaemon.verifyBitcoindRunning();
}
if (config.numSetupTasks > 1) {
startBisqApp(seednode, executor, countdownLatch);
}
if (config.numSetupTasks > 2) {
startBisqApp(config.runArbNodeAsDesktop ? arbdesktop : arbdaemon, executor, countdownLatch);
}
if (config.numSetupTasks > 3) {
startBisqApp(config.runAliceNodeAsDesktop ? alicedesktop : alicedaemon, executor, countdownLatch);
}
if (config.numSetupTasks > 4) {
startBisqApp(config.runBobNodeAsDesktop ? bobdesktop : bobdaemon, executor, countdownLatch);
}
}

private void startBisqApp(BisqAppConfig bisqAppConfig,
ExecutorService executor,
CountDownLatch countdownLatch)
throws IOException, InterruptedException {

BisqApp bisqApp;
switch (bisqAppConfig) {
case seednode:
bisqApp = createBisqApp(seednode);
seedNodeTask = new SetupTask(bisqApp, countdownLatch);
seedNodeTaskFuture = executor.submit(seedNodeTask);
break;
case arbdaemon:
case arbdesktop:
bisqApp = createBisqApp(config.runArbNodeAsDesktop ? arbdesktop : arbdaemon);
arbNodeTask = new SetupTask(bisqApp, countdownLatch);
arbNodeTaskFuture = executor.submit(arbNodeTask);
break;
case alicedaemon:
case alicedesktop:
bisqApp = createBisqApp(config.runAliceNodeAsDesktop ? alicedesktop : alicedaemon);
aliceNodeTask = new SetupTask(bisqApp, countdownLatch);
aliceNodeTaskFuture = executor.submit(aliceNodeTask);
break;
case bobdaemon:
case bobdesktop:
bisqApp = createBisqApp(config.runBobNodeAsDesktop ? bobdesktop : bobdaemon);
bobNodeTask = new SetupTask(bisqApp, countdownLatch);
bobNodeTaskFuture = executor.submit(bobNodeTask);
break;
default:
throw new IllegalStateException("Unknown Bisq App " + bisqAppConfig.appName);
}
SECONDS.sleep(5);
if (bisqApp.hasStartupExceptions()) {
for (Throwable t : bisqApp.getStartupExceptions()) {
log.error("", t);
}
exit(EXIT_FAILURE);
}
}

private BisqApp createBisqApp(BisqAppConfig bisqAppConfig)
throws IOException, InterruptedException {
BisqApp bisqNode = new BisqApp(bisqAppConfig, config);
bisqNode.verifyAppNotRunning();
bisqNode.verifyAppDataDirInstalled();
return bisqNode;
}

private void verifyStartupCompleted()
throws ExecutionException, InterruptedException {
if (config.numSetupTasks > 0)
verifyStartupCompleted(bitcoindTaskFuture);

if (config.numSetupTasks > 1)
verifyStartupCompleted(seedNodeTaskFuture);

if (config.numSetupTasks > 2)
verifyStartupCompleted(arbNodeTaskFuture);

if (config.numSetupTasks > 3)
verifyStartupCompleted(aliceNodeTaskFuture);

if (config.numSetupTasks > 4)
verifyStartupCompleted(bobNodeTaskFuture);
}

private void verifyStartupCompleted(Future<SetupTask.Status> futureStatus)
throws ExecutionException, InterruptedException {
for (int i = 0; i < 10; i++) {
if (futureStatus.isDone()) {
log.info("{} completed startup at {} {}",
futureStatus.get().getName(),
futureStatus.get().getStartTime().toLocalDate(),
futureStatus.get().getStartTime().toLocalTime());
return;
} else {
// We are giving the thread more time to terminate after the countdown
// latch reached 0. If we are running only bitcoind, we need to be even
// more lenient.
SECONDS.sleep(config.numSetupTasks == 1 ? 2 : 1);
}
}
throw new IllegalStateException(format("%s did not complete startup", futureStatus.get().getName()));
}

private void installShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
log.info("Running shutdown hook ...");
if (bobNodeTask != null && bobNodeTask.getLinuxProcess() != null)
bobNodeTask.getLinuxProcess().shutdown();

SECONDS.sleep(3);

if (aliceNodeTask != null && aliceNodeTask.getLinuxProcess() != null)
aliceNodeTask.getLinuxProcess().shutdown();

SECONDS.sleep(3);

if (arbNodeTask != null && arbNodeTask.getLinuxProcess() != null)
arbNodeTask.getLinuxProcess().shutdown();

SECONDS.sleep(3);

if (seedNodeTask != null && seedNodeTask.getLinuxProcess() != null)
seedNodeTask.getLinuxProcess().shutdown();

SECONDS.sleep(3);

if (bitcoindTask != null && bitcoindTask.getLinuxProcess() != null)
bitcoindTask.getLinuxProcess().shutdown();

} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}));
}

private void verifyNotWindows() {
if (Utilities.isWindows())
throw new IllegalStateException("ApiTest not supported on Windows");
}
}