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

Fix required opt validation bugs in CLI #5274

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d60c0dd
Display buyer's cost in api's gettrade output
ghubstan Feb 26, 2021
e2bb64d
Merge branch 'master' into 01-show-cost-in-trade-output
ghubstan Feb 27, 2021
e5291e9
Use the logger of the gRPC service throwing an exception
ghubstan Feb 27, 2021
e5a0a39
Permit some gRPC excptions to be logged only as warning
ghubstan Feb 27, 2021
320e63c
Log 'trade not found' a warning instead of full stack trace
ghubstan Feb 27, 2021
98ff6cf
Fix test bug
ghubstan Feb 27, 2021
e8d1f03
Clean up call rate meter config file in test teardown
ghubstan Feb 27, 2021
f90d2ce
Fix test bug
ghubstan Feb 27, 2021
6b2c386
Fix call rate metering interceptor bug
ghubstan Feb 28, 2021
675ce98
Make test call rate = default call rate
ghubstan Feb 28, 2021
7249509
No need to wait, default+test call rate > 2x / second
ghubstan Feb 28, 2021
3feacf4
Remove unused import
ghubstan Feb 28, 2021
3bbefff
Adjust mainnet bats test to default rate meter interceptors
ghubstan Feb 28, 2021
b618776
Wait 3 secs after removing password (for wallet save)
ghubstan Feb 28, 2021
19aed84
Fix getunusedbsqaddress test
ghubstan Feb 28, 2021
3f84246
Improve interceptor's rate metering key definition and lookup
ghubstan Feb 28, 2021
392c0f5
Fix CLI number opt validation, improve server-not-up msg
ghubstan Mar 1, 2021
2473ff6
Fix tx-fee-rate formatting (and math) bug in cli/CurrencyFormat
ghubstan Mar 2, 2021
8590c67
Remove warning supression
ghubstan Mar 2, 2021
e0bf773
Add link to api-beta-test-guide.md
ghubstan Mar 3, 2021
a2000bd
Explain how to manually register test dispute agents
ghubstan Mar 3, 2021
cfaa539
Fix opt validation bugs in CLI
ghubstan Mar 4, 2021
62ff79d
Update cli getoffers smoke test to posix style opts
ghubstan Mar 5, 2021
d01a7b7
Improve required-argument opt validation
ghubstan Mar 5, 2021
304781c
Add jupiter test support to :cli subproject
ghubstan Mar 5, 2021
9c12b31
Add new cli option parser test
ghubstan Mar 5, 2021
a13ef79
Handle require-arg options missing the = sign
ghubstan Mar 5, 2021
70da6d1
Parse args in opts test, no exception = pass
ghubstan Mar 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apitest/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
- [build-run.md](build-run.md): Build and run API tests at the command line and from Intellij.
- [test-categories.md](test-categories.md): How to categorize a test case as `method`, `scenario` or `e2e`.
- [regtest-port-conflicts.md](regtest-port-conflicts.md): Avoid port conflicts when running multiple bitcoin-core apps in regtest mode.
- [api-beta-test-guide.md](api-beta-test-guide.md): How to run the test harness and tutorial script, and beta test the API with the new CLI.
19 changes: 19 additions & 0 deletions apitest/docs/api-beta-test-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,25 @@ CLI command unless you change the server’s `–apiPort=<listening-port>`. In
`9998`, Bob’s is `9999`. When you manually test the Api using the test harness, be aware of the port numbers being
used in the CLI commands, so you know which server (Bob’s or Alice’s) the CLI is sending requests to.

### Registering Test Dispute Agents

If you ran the `trade-simulation.sh` script in your currently running test harness, dispute agents have
already been registered in the arbitration node, and you can run any of the commands described in the following
sections.

If you have not run the `trade-simulation.sh` script against the test harness, you will need to
manually register dispute agents in the arbitration node before you can initiate a trade. Copy, paste and run
the following CLI commands to register a `mediator` and a `refundagent`. Do not change the commands' port `9997`
option (the test arbitration node's listening port).
```
$ ./bisq-cli --password=xyz --port=9997 registerdisputeagent --dispute-agent-type=mediator
--registration-key=6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a

$ ./bisq-cli --password=xyz --port=9997 registerdisputeagent --dispute-agent-type=refundagent
--registration-key=6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a
```
_Note: The API cannot be used to register dispute agents on nodes connected to `mainnet`._

### CLI Help

Useful information can be found using the CLI’s `--help` option.
Expand Down
22 changes: 20 additions & 2 deletions apitest/scripts/mainnet-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
}

@test "test getversion" {
# Wait 1 second before calling getversion again.
sleep 1
load 'version-parser'
run ./bisq-cli --password=xyz getversion
[ "$status" -eq 0 ]
Expand Down Expand Up @@ -118,6 +120,8 @@
}

@test "test setwalletpassword oldpwd newpwd" {
# Wait 5 seconds before calling setwalletpassword again.
sleep 5
run ./bisq-cli --password=xyz setwalletpassword --wallet-password="a b c" --new-wallet-password="d e f"
[ "$status" -eq 0 ]
echo "actual output: $output" >&2
Expand All @@ -137,7 +141,7 @@
[ "$status" -eq 0 ]
echo "actual output: $output" >&2
[ "$output" = "wallet decrypted" ]
sleep 1
sleep 3
}

@test "test getbalance when wallet available & unlocked with 0 btc balance" {
Expand All @@ -151,7 +155,7 @@
}

@test "test getunusedbsqaddress" {
run ./bisq-cli --password=xyz getfundingaddresses
run ./bisq-cli --password=xyz getunusedbsqaddress
[ "$status" -eq 0 ]
}

Expand All @@ -163,6 +167,8 @@
}

@test "test getaddressbalance bogus address argument" {
# Wait 1 second before calling getaddressbalance again.
sleep 1
run ./bisq-cli --password=xyz getaddressbalance --address=bogus
[ "$status" -eq 1 ]
echo "actual output: $output" >&2
Expand All @@ -187,16 +193,22 @@
}

@test "test getoffers sell eur check return status" {
# Wait 1 second before calling getoffers again.
sleep 1
run ./bisq-cli --password=xyz getoffers --direction=sell --currency-code=eur
[ "$status" -eq 0 ]
}

@test "test getoffers buy eur check return status" {
# Wait 1 second before calling getoffers again.
sleep 1
run ./bisq-cli --password=xyz getoffers --direction=buy --currency-code=eur
[ "$status" -eq 0 ]
}

@test "test getoffers sell gbp check return status" {
# Wait 1 second before calling getoffers again.
sleep 1
run ./bisq-cli --password=xyz getoffers --direction=sell --currency-code=gbp
[ "$status" -eq 0 ]
}
Expand All @@ -216,3 +228,9 @@
[ "${lines[1]}" = "Usage: bisq-cli [options] <method> [params]" ]
# TODO add asserts after help text is modified for new endpoints
}

@test "test takeoffer method --help" {
run ./bisq-cli --password=xyz takeoffer --help
[ "$status" -eq 0 ]
[ "${lines[0]}" = "takeoffer" ]
}
12 changes: 6 additions & 6 deletions apitest/scripts/trade-simulation-utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,9 @@ istradepaymentsent() {
MAKER_OR_TAKER="$2"
if [ "$MAKER_OR_TAKER" = "MAKER" ]
then
ANSWER=$(echo "$TRADE_DETAIL" | awk '{print $11}')
else
ANSWER=$(echo "$TRADE_DETAIL" | awk '{print $12}')
else
ANSWER=$(echo "$TRADE_DETAIL" | awk '{print $13}')
fi
commandalert $? "Could not parse istradepaymentsent from trade detail."
echo "$ANSWER"
Expand All @@ -280,9 +280,9 @@ istradepaymentreceived() {
MAKER_OR_TAKER="$2"
if [ "$MAKER_OR_TAKER" = "MAKER" ]
then
ANSWER=$(echo "$TRADE_DETAIL" | awk '{print $12}')
else
ANSWER=$(echo "$TRADE_DETAIL" | awk '{print $13}')
else
ANSWER=$(echo "$TRADE_DETAIL" | awk '{print $14}')
fi
commandalert $? "Could not parse istradepaymentreceived from trade detail."
echo "$ANSWER"
Expand All @@ -293,9 +293,9 @@ istradepayoutpublished() {
MAKER_OR_TAKER="$2"
if [ "$MAKER_OR_TAKER" = "MAKER" ]
then
ANSWER=$(echo "$TRADE_DETAIL" | awk '{print $13}')
else
ANSWER=$(echo "$TRADE_DETAIL" | awk '{print $14}')
else
ANSWER=$(echo "$TRADE_DETAIL" | awk '{print $15}')
fi
commandalert $? "Could not parse istradepayoutpublished from trade detail."
echo "$ANSWER"
Expand Down
54 changes: 48 additions & 6 deletions apitest/src/test/java/bisq/apitest/ApiTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,35 @@

package bisq.apitest;

import java.io.File;
import java.io.IOException;

import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;

import org.junit.jupiter.api.TestInfo;

import static bisq.apitest.config.BisqAppConfig.alicedaemon;
import static bisq.apitest.config.BisqAppConfig.arbdaemon;
import static bisq.apitest.config.BisqAppConfig.bobdaemon;
import static bisq.proto.grpc.DisputeAgentsGrpc.getRegisterDisputeAgentMethod;
import static bisq.proto.grpc.GetVersionGrpc.getGetVersionMethod;
import static java.net.InetAddress.getLoopbackAddress;
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.method.BitcoinCliHelper;
import bisq.cli.GrpcClient;
import bisq.daemon.grpc.GrpcVersionService;
import bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig;

/**
* Base class for all test types: 'method', 'scenario' and 'e2e'.
Expand All @@ -64,6 +72,7 @@
* <p>
* Initial Bob balances & accounts: 10.0 BTC, 1500000.00 BSQ, USD PerfectMoney dummy
*/
@Slf4j
public class ApiTestCase {

protected static Scaffold scaffold;
Expand All @@ -79,12 +88,12 @@ public class ApiTestCase {

public static void setUpScaffold(Enum<?>... supportingApps)
throws InterruptedException, ExecutionException, IOException {
scaffold = new Scaffold(stream(supportingApps).map(Enum::name)
.collect(Collectors.joining(",")))
.setUp();
config = scaffold.config;
bitcoinCli = new BitcoinCliHelper((config));
createGrpcClients();
String[] params = new String[]{
"--supportingApps", stream(supportingApps).map(Enum::name).collect(Collectors.joining(",")),
"--callRateMeteringConfigPath", defaultRateMeterInterceptorConfig().getAbsolutePath(),
"--enableBisqDebugging", "false"
};
setUpScaffold(params);
}

public static void setUpScaffold(String[] params)
Expand Down Expand Up @@ -139,4 +148,37 @@ protected final String testName(TestInfo testInfo) {
? testInfo.getTestMethod().get().getName()
: "unknown test name";
}

protected static File defaultRateMeterInterceptorConfig() {
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

import io.grpc.StatusRuntimeException;

import java.io.File;

import lombok.extern.slf4j.Slf4j;

import org.junit.jupiter.api.AfterAll;
Expand All @@ -34,18 +32,9 @@

import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind;
import static bisq.apitest.config.BisqAppConfig.alicedaemon;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;



import bisq.daemon.grpc.GrpcVersionService;
import bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig;

@Disabled
@Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
Expand All @@ -55,9 +44,7 @@ public class CallRateMeteringInterceptorTest extends MethodTest {

@BeforeAll
public static void setUp() {
File callRateMeteringConfigFile = buildInterceptorConfigFile();
startSupportingApps(callRateMeteringConfigFile,
false,
startSupportingApps(false,
false,
bitcoind, alicedaemon);
}
Expand Down Expand Up @@ -100,30 +87,4 @@ public void testGetVersionCall4IsAllowed() {
public static void tearDown() {
tearDownScaffold();
}

public static File buildInterceptorConfigFile() {
GrpcServiceRateMeteringConfig.Builder builder = new GrpcServiceRateMeteringConfig.Builder();
builder.addCallRateMeter(GrpcVersionService.class.getSimpleName(),
"getVersion",
1,
SECONDS);
builder.addCallRateMeter(GrpcVersionService.class.getSimpleName(),
"shouldNotBreakAnything",
1000,
DAYS);
// Only GrpcVersionService is @VisibleForTesting, so we hardcode the class names.
builder.addCallRateMeter("GrpcOffersService",
"createOffer",
5,
MINUTES);
builder.addCallRateMeter("GrpcOffersService",
"takeOffer",
10,
DAYS);
builder.addCallRateMeter("GrpcTradesService",
"withdrawFunds",
3,
HOURS);
return builder.build();
}
}
3 changes: 3 additions & 0 deletions apitest/src/test/java/bisq/apitest/method/MethodTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ public static void startSupportingApps(boolean registerDisputeAgents,
boolean generateBtcBlock,
Enum<?>... supportingApps) {
try {
// Disable call rate metering where there is no callRateMeteringConfigFile.
File callRateMeteringConfigFile = defaultRateMeterInterceptorConfig();
setUpScaffold(new String[]{
"--supportingApps", toNameList.apply(supportingApps),
"--callRateMeteringConfigPath", callRateMeteringConfigFile.getAbsolutePath(),
"--enableBisqDebugging", "false"
});
doPostStartup(registerDisputeAgents, generateBtcBlock);
Expand Down
12 changes: 10 additions & 2 deletions apitest/src/test/java/bisq/apitest/scenario/StartupTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package bisq.apitest.scenario;

import java.io.File;
import java.io.IOException;

import lombok.extern.slf4j.Slf4j;

Expand All @@ -32,7 +33,7 @@
import static bisq.apitest.config.BisqAppConfig.alicedaemon;
import static bisq.apitest.config.BisqAppConfig.arbdaemon;
import static bisq.apitest.config.BisqAppConfig.seednode;
import static bisq.apitest.method.CallRateMeteringInterceptorTest.buildInterceptorConfigFile;
import static bisq.common.file.FileUtil.deleteFileIfExists;
import static org.junit.jupiter.api.Assertions.fail;


Expand All @@ -48,10 +49,12 @@
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class StartupTest extends MethodTest {

private static File callRateMeteringConfigFile;

@BeforeAll
public static void setUp() {
try {
File callRateMeteringConfigFile = buildInterceptorConfigFile();
callRateMeteringConfigFile = defaultRateMeterInterceptorConfig();
startSupportingApps(callRateMeteringConfigFile,
false,
false,
Expand Down Expand Up @@ -102,6 +105,11 @@ public void testGetCreateOfferHelp() {

@AfterAll
public static void tearDown() {
try {
deleteFileIfExists(callRateMeteringConfigFile);
} catch (IOException ex) {
log.error(ex.getMessage());
}
tearDownScaffold();
}
}
11 changes: 11 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,17 @@ configure(project(':cli')) {
implementation "ch.qos.logback:logback-classic:$logbackVersion"
compileOnly "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion"

testImplementation "org.junit.jupiter:junit-jupiter-api:$jupiterVersion"
testImplementation "org.junit.jupiter:junit-jupiter-params:$jupiterVersion"
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$jupiterVersion")
testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion"
testCompileOnly "org.projectlombok:lombok:$lombokVersion"
testRuntime "javax.annotation:javax.annotation-api:$javaxAnnotationVersion"
}

test {
useJUnitPlatform()
}
}

Expand Down
Loading