[NC-1970] admin_addPeer acceptance test (#651)

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Chris Mckay 6 years ago committed by GitHub
parent d477c5ca58
commit 6d4896944a
  1. 3
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/AcceptanceTestBase.java
  2. 1
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/Condition.java
  3. 44
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/jsonrpc/Admin.java
  4. 10
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java
  5. 6
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonFactoryConfiguration.java
  6. 10
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonFactoryConfigurationBuilder.java
  7. 15
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonNodeFactory.java
  8. 10
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/transaction/PantheonWeb3j.java
  9. 1
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/transaction/Transaction.java
  10. 53
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/jsonrpc/admin/AdminAddPeerAcceptanceTest.java

@ -15,6 +15,7 @@ package tech.pegasys.pantheon.tests.acceptance.dsl;
import tech.pegasys.pantheon.tests.acceptance.dsl.account.Accounts; import tech.pegasys.pantheon.tests.acceptance.dsl.account.Accounts;
import tech.pegasys.pantheon.tests.acceptance.dsl.blockchain.Blockchain; import tech.pegasys.pantheon.tests.acceptance.dsl.blockchain.Blockchain;
import tech.pegasys.pantheon.tests.acceptance.dsl.contract.ContractVerifier; import tech.pegasys.pantheon.tests.acceptance.dsl.contract.ContractVerifier;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Admin;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Clique; import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Clique;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Eth; import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Eth;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Ibft; import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Ibft;
@ -45,6 +46,7 @@ public class AcceptanceTestBase {
protected final Eth eth; protected final Eth eth;
protected final Net net; protected final Net net;
protected final Perm perm; protected final Perm perm;
protected final Admin admin;
protected final PantheonNodeFactory pantheon; protected final PantheonNodeFactory pantheon;
protected final ContractVerifier contractVerifier; protected final ContractVerifier contractVerifier;
protected final WaitConditions wait; protected final WaitConditions wait;
@ -61,6 +63,7 @@ public class AcceptanceTestBase {
cluster = new Cluster(net); cluster = new Cluster(net);
transactions = new Transactions(accounts); transactions = new Transactions(accounts);
perm = new Perm(transactions); perm = new Perm(transactions);
admin = new Admin();
web3 = new Web3(new Web3Transactions()); web3 = new Web3(new Web3Transactions());
pantheon = new PantheonNodeFactory(); pantheon = new PantheonNodeFactory();
contractVerifier = new ContractVerifier(accounts.getPrimaryBenefactor()); contractVerifier = new ContractVerifier(accounts.getPrimaryBenefactor());

@ -14,6 +14,7 @@ package tech.pegasys.pantheon.tests.acceptance.dsl.condition;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node;
@FunctionalInterface
public interface Condition { public interface Condition {
void verify(Node node); void verify(Node node);

@ -0,0 +1,44 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc;
import static org.assertj.core.api.Assertions.assertThat;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import org.web3j.protocol.core.Response;
public class Admin {
private Transaction<Boolean> addPeerTransaction(final String enode) {
return (n) -> {
try {
final Response<Boolean> resp = n.adminAddPeer(enode).send();
assertThat(resp).isNotNull();
assertThat(resp.hasError()).isFalse();
return resp.getResult();
} catch (final IOException e) {
throw new RuntimeException(e);
}
};
}
public Condition addPeer(final String enode) {
return (n) -> {
final Boolean result = n.execute(addPeerTransaction(enode));
assertThat(result).isTrue();
};
}
}

@ -92,7 +92,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
final GenesisConfigProvider genesisConfigProvider, final GenesisConfigProvider genesisConfigProvider,
final int p2pPort, final int p2pPort,
final Boolean p2pEnabled, final Boolean p2pEnabled,
final boolean discovery) final boolean discoveryEnabled)
throws IOException { throws IOException {
this.homeDirectory = Files.createTempDirectory("acctest"); this.homeDirectory = Files.createTempDirectory("acctest");
this.keyPair = KeyPairUtil.loadKeyPair(homeDirectory); this.keyPair = KeyPairUtil.loadKeyPair(homeDirectory);
@ -106,7 +106,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
this.genesisConfigProvider = genesisConfigProvider; this.genesisConfigProvider = genesisConfigProvider;
this.devMode = devMode; this.devMode = devMode;
this.p2pEnabled = p2pEnabled; this.p2pEnabled = p2pEnabled;
this.discoveryEnabled = discovery; this.discoveryEnabled = discoveryEnabled;
LOG.info("Created PantheonNode {}", this.toString()); LOG.info("Created PantheonNode {}", this.toString());
} }
@ -188,7 +188,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
final WebSocketService webSocketService = new WebSocketService(url, true); final WebSocketService webSocketService = new WebSocketService(url, true);
try { try {
webSocketService.connect(); webSocketService.connect();
} catch (ConnectException e) { } catch (final ConnectException e) {
throw new RuntimeException("Error connection to WebSocket endpoint", e); throw new RuntimeException("Error connection to WebSocket endpoint", e);
} }
@ -200,7 +200,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
} }
private void checkIfWebSocketEndpointIsAvailable(final String url) { private void checkIfWebSocketEndpointIsAvailable(final String url) {
WebSocketClient webSocketClient = new WebSocketClient(URI.create(url)); final WebSocketClient webSocketClient = new WebSocketClient(URI.create(url));
// Web3j implementation always invoke the listener (even when one hasn't been set). We are using // Web3j implementation always invoke the listener (even when one hasn't been set). We are using
// this stub implementation to avoid a NullPointerException. // this stub implementation to avoid a NullPointerException.
webSocketClient.setListener( webSocketClient.setListener(
@ -226,7 +226,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
webSocketClient.connect(); webSocketClient.connect();
try { try {
Awaitility.await().atMost(5, TimeUnit.SECONDS).until(webSocketClient::isOpen); Awaitility.await().atMost(5, TimeUnit.SECONDS).until(webSocketClient::isOpen);
} catch (ConditionTimeoutException e) { } catch (final ConditionTimeoutException e) {
throw new WebsocketNotConnectedException(); throw new WebsocketNotConnectedException();
} finally { } finally {
webSocketClient.close(); webSocketClient.close();

@ -28,9 +28,9 @@ class PantheonFactoryConfiguration {
private final MetricsConfiguration metricsConfiguration; private final MetricsConfiguration metricsConfiguration;
private final PermissioningConfiguration permissioningConfiguration; private final PermissioningConfiguration permissioningConfiguration;
private final boolean devMode; private final boolean devMode;
private final Boolean discoveryEnabled;
private final GenesisConfigProvider genesisConfigProvider; private final GenesisConfigProvider genesisConfigProvider;
private final Boolean p2pEnabled; private final Boolean p2pEnabled;
private final boolean discoveryEnabled;
PantheonFactoryConfiguration( PantheonFactoryConfiguration(
final String name, final String name,
@ -42,7 +42,7 @@ class PantheonFactoryConfiguration {
final boolean devMode, final boolean devMode,
final GenesisConfigProvider genesisConfigProvider, final GenesisConfigProvider genesisConfigProvider,
final Boolean p2pEnabled, final Boolean p2pEnabled,
final Boolean discoveryEnabled) { final boolean discoveryEnabled) {
this.name = name; this.name = name;
this.miningParameters = miningParameters; this.miningParameters = miningParameters;
this.jsonRpcConfiguration = jsonRpcConfiguration; this.jsonRpcConfiguration = jsonRpcConfiguration;
@ -83,7 +83,7 @@ class PantheonFactoryConfiguration {
return devMode; return devMode;
} }
public Boolean isDiscoveryEnabled() { public boolean isDiscoveryEnabled() {
return discoveryEnabled; return discoveryEnabled;
} }

@ -35,9 +35,9 @@ public class PantheonFactoryConfigurationBuilder {
private PermissioningConfiguration permissioningConfiguration = private PermissioningConfiguration permissioningConfiguration =
PermissioningConfiguration.createDefault(); PermissioningConfiguration.createDefault();
private boolean devMode = true; private boolean devMode = true;
private Boolean discoveryEnabled = true;
private GenesisConfigProvider genesisConfigProvider = ignore -> Optional.empty(); private GenesisConfigProvider genesisConfigProvider = ignore -> Optional.empty();
private Boolean p2pEnabled = true; private Boolean p2pEnabled = true;
private boolean discoveryEnabled = true;
public PantheonFactoryConfigurationBuilder setName(final String name) { public PantheonFactoryConfigurationBuilder setName(final String name) {
this.name = name; this.name = name;
@ -109,13 +109,13 @@ public class PantheonFactoryConfigurationBuilder {
return this; return this;
} }
public PantheonFactoryConfigurationBuilder setDiscoveryEnabled(final Boolean discoveryEnabled) { public PantheonFactoryConfigurationBuilder setP2pEnabled(final Boolean p2pEnabled) {
this.discoveryEnabled = discoveryEnabled; this.p2pEnabled = p2pEnabled;
return this; return this;
} }
public PantheonFactoryConfigurationBuilder setP2pEnabled(final Boolean p2pEnabled) { public PantheonFactoryConfigurationBuilder setDiscoveryEnabled(final boolean discoveryEnabled) {
this.p2pEnabled = p2pEnabled; this.discoveryEnabled = discoveryEnabled;
return this; return this;
} }

@ -99,6 +99,17 @@ public class PantheonNodeFactory {
.build()); .build());
} }
public PantheonNode createArchiveNodeWithDiscoveryDisabledAndAdmin(final String name)
throws IOException {
return create(
new PantheonFactoryConfigurationBuilder()
.setName(name)
.setJsonRpcConfiguration(jsonRpcConfigWithAdmin())
.webSocketEnabled()
.setDiscoveryEnabled(false)
.build());
}
public PantheonNode createArchiveNodeWithP2pDisabled(final String name) throws IOException { public PantheonNode createArchiveNodeWithP2pDisabled(final String name) throws IOException {
return create( return create(
new PantheonFactoryConfigurationBuilder() new PantheonFactoryConfigurationBuilder()
@ -324,6 +335,10 @@ public class PantheonNodeFactory {
return createJsonRpcConfigWithRpcApiEnabled(RpcApis.PERM); return createJsonRpcConfigWithRpcApiEnabled(RpcApis.PERM);
} }
private JsonRpcConfiguration jsonRpcConfigWithAdmin() {
return createJsonRpcConfigWithRpcApiEnabled(RpcApis.ADMIN);
}
private JsonRpcConfiguration createJsonRpcConfigWithRpcApiEnabled(final RpcApi rpcApi) { private JsonRpcConfiguration createJsonRpcConfigWithRpcApiEnabled(final RpcApi rpcApi) {
final JsonRpcConfiguration jsonRpcConfig = createJsonRpcEnabledConfig(); final JsonRpcConfiguration jsonRpcConfig = createJsonRpcEnabledConfig();
final List<RpcApi> rpcApis = new ArrayList<>(jsonRpcConfig.getRpcApis()); final List<RpcApi> rpcApis = new ArrayList<>(jsonRpcConfig.getRpcApis());

@ -136,4 +136,14 @@ public class PantheonWeb3j extends JsonRpc2_0Web3j {
public static class RemoveNodeResponse extends Response<Boolean> {} public static class RemoveNodeResponse extends Response<Boolean> {}
public static class GetNodesWhitelistResponse extends Response<List<String>> {} public static class GetNodesWhitelistResponse extends Response<List<String>> {}
public static class AdminAddPeerResponse extends Response<Boolean> {}
public Request<?, AdminAddPeerResponse> adminAddPeer(final String enodeAddress) {
return new Request<>(
"admin_addPeer",
Collections.singletonList(enodeAddress),
web3jService,
AdminAddPeerResponse.class);
}
} }

@ -12,6 +12,7 @@
*/ */
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; package tech.pegasys.pantheon.tests.acceptance.dsl.transaction;
@FunctionalInterface
public interface Transaction<T> { public interface Transaction<T> {
T execute(final PantheonWeb3j node); T execute(final PantheonWeb3j node);

@ -0,0 +1,53 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.tests.acceptance.jsonrpc.admin;
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.cluster.Cluster;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class AdminAddPeerAcceptanceTest extends AcceptanceTestBase {
private PantheonNode nodeA;
private PantheonNode nodeB;
private Cluster p2pDisabledCluster;
@Before
public void setUp() throws Exception {
final ClusterConfiguration clusterConfiguration =
new ClusterConfigurationBuilder().setAwaitPeerDiscovery(false).build();
p2pDisabledCluster = new Cluster(clusterConfiguration, net);
nodeA = pantheon.createArchiveNodeWithDiscoveryDisabledAndAdmin("nodeA");
nodeB = pantheon.createArchiveNodeWithDiscoveryDisabledAndAdmin("nodeB");
p2pDisabledCluster.start(nodeA, nodeB);
}
@After
public void tearDown() {
p2pDisabledCluster.stop();
}
@Test
public void adminAddPeerForcesConnection() {
final String nodeBEnode = nodeB.enodeUrl();
nodeA.verify(net.awaitPeerCount(0));
nodeA.verify(admin.addPeer(nodeBEnode));
nodeA.verify(net.awaitPeerCount(1));
nodeB.verify(net.awaitPeerCount(1));
}
}
Loading…
Cancel
Save