Skip to content
This repository has been archived by the owner on Jan 10, 2021. It is now read-only.

Configure integration tests #14

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,19 @@ Some features will be not sufficiently tested and will only be enabled if you ad
--seedNodes=localhost:8000 --btcNodes=localhost:18445 --baseCurrencyNetwork=BTC_REGTEST --logLevel=info
--useDevPrivilegeKeys=true --bitcoinRegtestHost=NONE --myAddress=172.17.0.1:8003
--enableHttpApiExperimentalFeatures"

## Integration tests

Integration tests leverage Docker and run in headless mode. First you need to build docker images for the api:

cd api
docker-compose build
../gradlew testIntegration

IntelliJ Idea has awesome integration so just right click on `api/src/testIntegration` directory and select
`Debug All Tests`.

### Integration tests logging

Due to Travis log length limitations the log level is set to WARN, but if you need to see more details locally
go to `ContainerFactory` class and set `ENV_LOG_LEVEL_VALUE` property to `debug`.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
Expand All @@ -54,7 +55,7 @@ public UserEndpoint(ApiPasswordManager apiPasswordManager) {
@Operation(summary = "Change password")
@POST
@Path("/password")
public void changePassword(@Suspended AsyncResponse asyncResponse, @Valid ChangePassword data) {
public void changePassword(@Suspended AsyncResponse asyncResponse, @NotNull @Valid ChangePassword data) {
UserThread.execute(() -> {
try {
apiPasswordManager.changePassword(data.oldPassword, data.newPassword);
Expand Down
30 changes: 30 additions & 0 deletions api/src/testIntegration/java/bisq/api/http/ApiTestHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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.api.http;

@SuppressWarnings("WeakerAccess")
public final class ApiTestHelper {

public static void waitForAllServicesToBeReady() throws InterruptedException {
// TODO it would be nice to expose endpoint that would respond with 200
// PaymentMethod initializes it's static values after all services get initialized
int ALL_SERVICES_INITIALIZED_DELAY = 5000;
Thread.sleep(ALL_SERVICES_INITIALIZED_DELAY);
}

}
101 changes: 101 additions & 0 deletions api/src/testIntegration/java/bisq/api/http/ContainerFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* 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.api.http;

import org.arquillian.cube.docker.impl.client.config.Await;
import org.arquillian.cube.docker.impl.client.containerobject.dsl.Container;
import org.arquillian.cube.docker.impl.client.containerobject.dsl.ContainerBuilder;

@SuppressWarnings("WeakerAccess")
public final class ContainerFactory {

public static final String BITCOIN_NODE_CONTAINER_NAME = "bisq-api-bitcoin-node";
public static final String BITCOIN_NODE_HOST_NAME = "bitcoin";
public static final String SEED_NODE_CONTAINER_NAME = "bisq-seednode";
public static final String SEED_NODE_HOST_NAME = SEED_NODE_CONTAINER_NAME;
public static final String SEED_NODE_ADDRESS = SEED_NODE_HOST_NAME + ":8000";
public static final String CONTAINER_NAME_PREFIX = "bisq-api-";
public static final String API_IMAGE = "bisq/api";
public static final String ENV_NODE_PORT_KEY = "NODE_PORT";
public static final String ENV_ENABLE_HTTP_API_EXPERIMENTAL_FEATURES_KEY = "ENABLE_HTTP_API_EXPERIMENTAL_FEATURES";
public static final String ENV_HTTP_API_HOST_KEY = "HTTP_API_HOST";
public static final String ENV_HTTP_API_HOST_VALUE = "0.0.0.0";
public static final String ENV_USE_DEV_PRIVILEGE_KEYS_KEY = "USE_DEV_PRIVILEGE_KEYS";
public static final String ENV_USE_DEV_PRIVILEGE_KEYS_VALUE = "true";
public static final String ENV_USE_LOCALHOST_FOR_P2P_KEY = "USE_LOCALHOST_FOR_P2P";
public static final String ENV_USE_LOCALHOST_FOR_P2P_VALUE = "true";
public static final String ENV_BASE_CURRENCY_NETWORK_KEY = "BASE_CURRENCY_NETWORK";
public static final String ENV_BASE_CURRENCY_NETWORK_VALUE = "BTC_REGTEST";
public static final String ENV_BITCOIN_REGTEST_HOST_KEY = "BITCOIN_REGTEST_HOST";
public static final String ENV_BITCOIN_REGTEST_HOST_VALUE = "LOCALHOST";
public static final String ENV_BTC_NODES_KEY = "BTC_NODES";
public static final String ENV_BTC_NODES_VALUE = "bitcoin:18444";
public static final String ENV_SEED_NODES_KEY = "SEED_NODES";
public static final String ENV_SEED_NODES_VALUE = SEED_NODE_ADDRESS;
public static final String ENV_LOG_LEVEL_KEY = "LOG_LEVEL";
public static final String ENV_LOG_LEVEL_VALUE = "warn";

@SuppressWarnings("WeakerAccess")
public static ContainerBuilder.ContainerOptionsBuilder createApiContainerBuilder(String nameSuffix, String portBinding, int nodePort, boolean linkToSeedNode, boolean linkToBitcoin, boolean enableExperimentalFeatures) {
ContainerBuilder.ContainerOptionsBuilder containerOptionsBuilder = Container.withContainerName(CONTAINER_NAME_PREFIX + nameSuffix)
.fromImage(API_IMAGE)
.withPortBinding(portBinding)
.withEnvironment(ENV_NODE_PORT_KEY, nodePort)
.withEnvironment(ENV_HTTP_API_HOST_KEY, ENV_HTTP_API_HOST_VALUE)
.withEnvironment(ENV_ENABLE_HTTP_API_EXPERIMENTAL_FEATURES_KEY, enableExperimentalFeatures)
.withEnvironment(ENV_USE_DEV_PRIVILEGE_KEYS_KEY, ENV_USE_DEV_PRIVILEGE_KEYS_VALUE)
blabno marked this conversation as resolved.
Show resolved Hide resolved
.withAwaitStrategy(getAwaitStrategy());
if (linkToSeedNode) {
containerOptionsBuilder.withLink(SEED_NODE_CONTAINER_NAME);
}
if (linkToBitcoin) {
containerOptionsBuilder.withLink(BITCOIN_NODE_CONTAINER_NAME, BITCOIN_NODE_HOST_NAME);
}
return withRegtestEnv(containerOptionsBuilder);
}

public static Await getAwaitStrategy() {
Await awaitStrategy = new Await();
awaitStrategy.setStrategy("polling");
int sleepPollingTime = 250;
awaitStrategy.setIterations(60000 / sleepPollingTime);
awaitStrategy.setSleepPollingTime(sleepPollingTime);
return awaitStrategy;
}

public static Container createApiContainer(String nameSuffix, String portBinding, int nodePort, boolean linkToSeedNode, boolean linkToBitcoin, boolean enableExperimentalFeatures) {
Container container = createApiContainerBuilder(nameSuffix, portBinding, nodePort, linkToSeedNode, linkToBitcoin, enableExperimentalFeatures).build();
container.getCubeContainer().setKillContainer(true);
return container;
}

public static Container createApiContainer(String nameSuffix, String portBinding, int nodePort, boolean linkToSeedNode, boolean linkToBitcoin) {
return createApiContainer(nameSuffix, portBinding, nodePort, linkToSeedNode, linkToBitcoin, true);
}

public static ContainerBuilder.ContainerOptionsBuilder withRegtestEnv(ContainerBuilder.ContainerOptionsBuilder builder) {
return builder
.withEnvironment(ENV_USE_LOCALHOST_FOR_P2P_KEY, ENV_USE_LOCALHOST_FOR_P2P_VALUE)
.withEnvironment(ENV_BASE_CURRENCY_NETWORK_KEY, ENV_BASE_CURRENCY_NETWORK_VALUE)
.withEnvironment(ENV_BITCOIN_REGTEST_HOST_KEY, ENV_BITCOIN_REGTEST_HOST_VALUE)
.withEnvironment(ENV_BTC_NODES_KEY, ENV_BTC_NODES_VALUE)
.withEnvironment(ENV_SEED_NODES_KEY, ENV_SEED_NODES_VALUE)
.withEnvironment(ENV_LOG_LEVEL_KEY, ENV_LOG_LEVEL_VALUE);
}

}
73 changes: 73 additions & 0 deletions api/src/testIntegration/java/bisq/api/http/SwaggerIT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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.api.http;

import org.junit.Test;
import org.junit.runner.RunWith;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;



import org.arquillian.cube.docker.impl.client.containerobject.dsl.Container;
import org.arquillian.cube.docker.impl.client.containerobject.dsl.DockerContainer;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence;

@RunWith(Arquillian.class)
public class SwaggerIT {

@DockerContainer
private Container alice = ContainerFactory.createApiContainer("alice", "8081->8080", 3333, false, false);

@InSequence(1)
@Test
public void getDocs_always_returns200() {
given().
port(getAlicePort()).
//
when().
get("/docs").
//
then().
statusCode(200).
and().body(containsString("Swagger UI"))
;
}

@InSequence(1)
@Test
public void getOpenApiJson_always_returns200() {
given().
port(getAlicePort()).
//
when().
get("/openapi.json").
//
then().
statusCode(200).
and().body("info.title", equalTo("Bisq HTTP API"));
}

private int getAlicePort() {
return alice.getBindPort(8080);
}

}
Loading