mirror of https://github.com/hyperledger/besu
[Refactor] - Extract websocket options to a new class (#6461)
Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>pull/6466/head
parent
11b6c31272
commit
317d2ac6f4
@ -0,0 +1,266 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.cli.options.stable; |
||||
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.DEFAULT_RPC_APIS; |
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.VALID_APIS; |
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration.DEFAULT_WEBSOCKET_PORT; |
||||
|
||||
import org.hyperledger.besu.cli.DefaultCommandValues; |
||||
import org.hyperledger.besu.cli.custom.RpcAuthFileValidator; |
||||
import org.hyperledger.besu.cli.util.CommandLineUtils; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; |
||||
|
||||
import java.io.File; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.function.Predicate; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import com.google.common.base.Strings; |
||||
import org.slf4j.Logger; |
||||
import picocli.CommandLine; |
||||
|
||||
/** This class represents the WebSocket options for the RPC. */ |
||||
public class RpcWebsocketOptions { |
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-authentication-jwt-algorithm"}, |
||||
description = |
||||
"Encryption algorithm used for Websockets JWT public key. Possible values are ${COMPLETION-CANDIDATES}" |
||||
+ " (default: ${DEFAULT-VALUE})", |
||||
arity = "1") |
||||
private final JwtAlgorithm rpcWebsocketsAuthenticationAlgorithm = |
||||
DefaultCommandValues.DEFAULT_JWT_ALGORITHM; |
||||
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-enabled"}, |
||||
description = "Set to start the JSON-RPC WebSocket service (default: ${DEFAULT-VALUE})") |
||||
private final Boolean isRpcWsEnabled = false; |
||||
|
||||
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-host"}, |
||||
paramLabel = DefaultCommandValues.MANDATORY_HOST_FORMAT_HELP, |
||||
description = "Host for JSON-RPC WebSocket service to listen on (default: ${DEFAULT-VALUE})", |
||||
arity = "1") |
||||
private String rpcWsHost; |
||||
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-port"}, |
||||
paramLabel = DefaultCommandValues.MANDATORY_PORT_FORMAT_HELP, |
||||
description = "Port for JSON-RPC WebSocket service to listen on (default: ${DEFAULT-VALUE})", |
||||
arity = "1") |
||||
private final Integer rpcWsPort = DEFAULT_WEBSOCKET_PORT; |
||||
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-max-frame-size"}, |
||||
description = |
||||
"Maximum size in bytes for JSON-RPC WebSocket frames (default: ${DEFAULT-VALUE}). If this limit is exceeded, the websocket will be disconnected.", |
||||
arity = "1") |
||||
private final Integer rpcWsMaxFrameSize = DefaultCommandValues.DEFAULT_WS_MAX_FRAME_SIZE; |
||||
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-max-active-connections"}, |
||||
description = |
||||
"Maximum number of WebSocket connections allowed for JSON-RPC (default: ${DEFAULT-VALUE}). Once this limit is reached, incoming connections will be rejected.", |
||||
arity = "1") |
||||
private final Integer rpcWsMaxConnections = DefaultCommandValues.DEFAULT_WS_MAX_CONNECTIONS; |
||||
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-api", "--rpc-ws-apis"}, |
||||
paramLabel = "<api name>", |
||||
split = " {0,1}, {0,1}", |
||||
arity = "1..*", |
||||
description = |
||||
"Comma separated list of APIs to enable on JSON-RPC WebSocket service (default: ${DEFAULT-VALUE})") |
||||
private final List<String> rpcWsApis = DEFAULT_RPC_APIS; |
||||
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-api-methods-no-auth", "--rpc-ws-api-method-no-auth"}, |
||||
paramLabel = "<api name>", |
||||
split = " {0,1}, {0,1}", |
||||
arity = "1..*", |
||||
description = |
||||
"Comma separated list of RPC methods to exclude from RPC authentication services, RPC WebSocket authentication must be enabled") |
||||
private final List<String> rpcWsApiMethodsNoAuth = new ArrayList<String>(); |
||||
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-authentication-enabled"}, |
||||
description = |
||||
"Require authentication for the JSON-RPC WebSocket service (default: ${DEFAULT-VALUE})") |
||||
private final Boolean isRpcWsAuthenticationEnabled = false; |
||||
|
||||
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-authentication-credentials-file"}, |
||||
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP, |
||||
description = |
||||
"Storage file for JSON-RPC WebSocket authentication credentials (default: ${DEFAULT-VALUE})", |
||||
arity = "1") |
||||
private String rpcWsAuthenticationCredentialsFile = null; |
||||
|
||||
@CommandLine.Option( |
||||
names = {"--rpc-ws-authentication-jwt-public-key-file"}, |
||||
paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP, |
||||
description = "JWT public key file for JSON-RPC WebSocket authentication", |
||||
arity = "1") |
||||
private final File rpcWsAuthenticationPublicKeyFile = null; |
||||
|
||||
/** |
||||
* Validates the WebSocket options. |
||||
* |
||||
* @param logger Logger instance |
||||
* @param commandLine CommandLine instance |
||||
* @param configuredApis Predicate for configured APIs |
||||
*/ |
||||
public void validate( |
||||
final Logger logger, final CommandLine commandLine, final Predicate<String> configuredApis) { |
||||
checkOptionDependencies(logger, commandLine); |
||||
|
||||
if (!rpcWsApis.stream().allMatch(configuredApis)) { |
||||
final List<String> invalidWsApis = new ArrayList<>(rpcWsApis); |
||||
invalidWsApis.removeAll(VALID_APIS); |
||||
throw new CommandLine.ParameterException( |
||||
commandLine, |
||||
"Invalid value for option '--rpc-ws-api': invalid entries found " + invalidWsApis); |
||||
} |
||||
|
||||
final boolean validWsApiMethods = |
||||
rpcWsApiMethodsNoAuth.stream().allMatch(RpcMethod::rpcMethodExists); |
||||
|
||||
if (!validWsApiMethods) { |
||||
throw new CommandLine.ParameterException( |
||||
commandLine, |
||||
"Invalid value for option '--rpc-ws-api-methods-no-auth', options must be valid RPC methods"); |
||||
} |
||||
|
||||
if (isRpcWsAuthenticationEnabled |
||||
&& rpcWsAuthenticationCredentialsFile(commandLine) == null |
||||
&& rpcWsAuthenticationPublicKeyFile == null) { |
||||
throw new CommandLine.ParameterException( |
||||
commandLine, |
||||
"Unable to authenticate JSON-RPC WebSocket endpoint without a supplied credentials file or authentication public key file"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Checks the dependencies of the WebSocket options. |
||||
* |
||||
* @param logger Logger instance |
||||
* @param commandLine CommandLine instance |
||||
*/ |
||||
private void checkOptionDependencies(final Logger logger, final CommandLine commandLine) { |
||||
CommandLineUtils.checkOptionDependencies( |
||||
logger, |
||||
commandLine, |
||||
"--rpc-ws-enabled", |
||||
!isRpcWsEnabled, |
||||
List.of( |
||||
"--rpc-ws-api", |
||||
"--rpc-ws-apis", |
||||
"--rpc-ws-api-method-no-auth", |
||||
"--rpc-ws-api-methods-no-auth", |
||||
"--rpc-ws-host", |
||||
"--rpc-ws-port", |
||||
"--rpc-ws-max-frame-size", |
||||
"--rpc-ws-max-active-connections", |
||||
"--rpc-ws-authentication-enabled", |
||||
"--rpc-ws-authentication-credentials-file", |
||||
"--rpc-ws-authentication-public-key-file", |
||||
"--rpc-ws-authentication-jwt-algorithm")); |
||||
|
||||
if (isRpcWsAuthenticationEnabled) { |
||||
CommandLineUtils.checkOptionDependencies( |
||||
logger, |
||||
commandLine, |
||||
"--rpc-ws-authentication-public-key-file", |
||||
rpcWsAuthenticationPublicKeyFile == null, |
||||
List.of("--rpc-ws-authentication-jwt-algorithm")); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a WebSocket configuration based on the WebSocket options. |
||||
* |
||||
* @param hostsAllowlist List of allowed hosts |
||||
* @param defaultHostAddress Default host address |
||||
* @param wsTimoutSec WebSocket timeout in seconds |
||||
* @return WebSocketConfiguration instance |
||||
*/ |
||||
public WebSocketConfiguration webSocketConfiguration( |
||||
final List<String> hostsAllowlist, final String defaultHostAddress, final Long wsTimoutSec) { |
||||
final WebSocketConfiguration webSocketConfiguration = WebSocketConfiguration.createDefault(); |
||||
webSocketConfiguration.setEnabled(isRpcWsEnabled); |
||||
webSocketConfiguration.setHost( |
||||
Strings.isNullOrEmpty(rpcWsHost) ? defaultHostAddress : rpcWsHost); |
||||
webSocketConfiguration.setPort(rpcWsPort); |
||||
webSocketConfiguration.setMaxFrameSize(rpcWsMaxFrameSize); |
||||
webSocketConfiguration.setMaxActiveConnections(rpcWsMaxConnections); |
||||
webSocketConfiguration.setRpcApis(rpcWsApis); |
||||
webSocketConfiguration.setRpcApisNoAuth( |
||||
rpcWsApiMethodsNoAuth.stream().distinct().collect(Collectors.toList())); |
||||
webSocketConfiguration.setAuthenticationEnabled(isRpcWsAuthenticationEnabled); |
||||
webSocketConfiguration.setAuthenticationCredentialsFile(rpcWsAuthenticationCredentialsFile); |
||||
webSocketConfiguration.setHostsAllowlist(hostsAllowlist); |
||||
webSocketConfiguration.setAuthenticationPublicKeyFile(rpcWsAuthenticationPublicKeyFile); |
||||
webSocketConfiguration.setAuthenticationAlgorithm(rpcWebsocketsAuthenticationAlgorithm); |
||||
webSocketConfiguration.setTimeoutSec(wsTimoutSec); |
||||
return webSocketConfiguration; |
||||
} |
||||
|
||||
/** |
||||
* Validates the authentication credentials file for the WebSocket. |
||||
* |
||||
* @param commandLine CommandLine instance |
||||
* @return Filename of the authentication credentials file |
||||
*/ |
||||
private String rpcWsAuthenticationCredentialsFile(final CommandLine commandLine) { |
||||
final String filename = rpcWsAuthenticationCredentialsFile; |
||||
|
||||
if (filename != null) { |
||||
RpcAuthFileValidator.validate(commandLine, filename, "WS"); |
||||
} |
||||
return filename; |
||||
} |
||||
|
||||
/** |
||||
* Returns the list of APIs for the WebSocket. |
||||
* |
||||
* @return List of APIs |
||||
*/ |
||||
public List<String> getRpcWsApis() { |
||||
return rpcWsApis; |
||||
} |
||||
|
||||
/** |
||||
* Checks if the WebSocket service is enabled. |
||||
* |
||||
* @return Boolean indicating if the WebSocket service is enabled |
||||
*/ |
||||
public Boolean isRpcWsEnabled() { |
||||
return isRpcWsEnabled; |
||||
} |
||||
|
||||
/** |
||||
* Returns the port for the WebSocket service. |
||||
* |
||||
* @return Port number |
||||
*/ |
||||
public Integer getRpcWsPort() { |
||||
return rpcWsPort; |
||||
} |
||||
} |
@ -0,0 +1,249 @@ |
||||
/* |
||||
* Copyright Hyperledger Besu Contributors. |
||||
* |
||||
* 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. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.cli.options; |
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8; |
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.ETH; |
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.NET; |
||||
import static org.mockito.Mockito.verify; |
||||
import static org.mockito.Mockito.verifyNoInteractions; |
||||
|
||||
import org.hyperledger.besu.cli.CommandTestAbstract; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; |
||||
|
||||
import java.io.IOException; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
import org.junit.jupiter.api.extension.ExtendWith; |
||||
import org.mockito.Mockito; |
||||
import org.mockito.junit.jupiter.MockitoExtension; |
||||
|
||||
@ExtendWith(MockitoExtension.class) |
||||
public class RpcWebsocketOptionsTest extends CommandTestAbstract { |
||||
|
||||
@Test |
||||
public void rpcWsApiPropertyMustBeUsed() { |
||||
final CommandTestAbstract.TestBesuCommand command = |
||||
parseCommand("--rpc-ws-enabled", "--rpc-ws-api", "ETH, NET"); |
||||
|
||||
assertThat(command).isNotNull(); |
||||
verify(mockRunnerBuilder).webSocketConfiguration(wsRpcConfigArgumentCaptor.capture()); |
||||
verify(mockRunnerBuilder).build(); |
||||
|
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().getRpcApis()) |
||||
.containsExactlyInAnyOrder(ETH.name(), NET.name()); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsHostAndPortOptionMustBeUsed() { |
||||
final String host = "1.2.3.4"; |
||||
final int port = 1234; |
||||
parseCommand("--rpc-ws-enabled", "--rpc-ws-host", host, "--rpc-ws-port", String.valueOf(port)); |
||||
|
||||
verify(mockRunnerBuilder).webSocketConfiguration(wsRpcConfigArgumentCaptor.capture()); |
||||
verify(mockRunnerBuilder).build(); |
||||
|
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().getHost()).isEqualTo(host); |
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().getPort()).isEqualTo(port); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsMaxFrameSizePropertyMustBeUsed() { |
||||
final int maxFrameSize = 65535; |
||||
parseCommand("--rpc-ws-max-frame-size", String.valueOf(maxFrameSize)); |
||||
|
||||
verify(mockRunnerBuilder).webSocketConfiguration(wsRpcConfigArgumentCaptor.capture()); |
||||
verify(mockRunnerBuilder).build(); |
||||
|
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().getMaxFrameSize()).isEqualTo(maxFrameSize); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsMaxActiveConnectionsPropertyMustBeUsed() { |
||||
final int maxConnections = 99; |
||||
parseCommand("--rpc-ws-max-active-connections", String.valueOf(maxConnections)); |
||||
|
||||
verify(mockRunnerBuilder).webSocketConfiguration(wsRpcConfigArgumentCaptor.capture()); |
||||
verify(mockRunnerBuilder).build(); |
||||
|
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().getMaxActiveConnections()) |
||||
.isEqualTo(maxConnections); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsRpcEnabledPropertyMustBeUsed() { |
||||
parseCommand("--rpc-ws-enabled"); |
||||
|
||||
verify(mockRunnerBuilder).webSocketConfiguration(wsRpcConfigArgumentCaptor.capture()); |
||||
verify(mockRunnerBuilder).build(); |
||||
|
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().isEnabled()).isTrue(); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void webSocketAuthenticationAlgorithmIsConfigured() { |
||||
parseCommand("--rpc-ws-authentication-jwt-algorithm", "ES256"); |
||||
|
||||
verify(mockRunnerBuilder).webSocketConfiguration(wsRpcConfigArgumentCaptor.capture()); |
||||
verify(mockRunnerBuilder).build(); |
||||
|
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().getAuthenticationAlgorithm()) |
||||
.isEqualTo(JwtAlgorithm.ES256); |
||||
} |
||||
|
||||
@Test |
||||
public void wsAuthenticationPublicKeyIsConfigured() throws IOException { |
||||
final Path publicKey = Files.createTempFile("public_key", ""); |
||||
parseCommand("--rpc-ws-authentication-jwt-public-key-file", publicKey.toString()); |
||||
|
||||
verify(mockRunnerBuilder).webSocketConfiguration(wsRpcConfigArgumentCaptor.capture()); |
||||
verify(mockRunnerBuilder).build(); |
||||
|
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().getAuthenticationPublicKeyFile().getPath()) |
||||
.isEqualTo(publicKey.toString()); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsHostAndMayBeLocalhost() { |
||||
final String host = "localhost"; |
||||
parseCommand("--rpc-ws-enabled", "--rpc-ws-host", host); |
||||
|
||||
verify(mockRunnerBuilder).webSocketConfiguration(wsRpcConfigArgumentCaptor.capture()); |
||||
verify(mockRunnerBuilder).build(); |
||||
|
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().getHost()).isEqualTo(host); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsHostAndMayBeIPv6() { |
||||
final String host = "2600:DB8::8545"; |
||||
parseCommand("--rpc-ws-enabled", "--rpc-ws-host", host); |
||||
|
||||
verify(mockRunnerBuilder).webSocketConfiguration(wsRpcConfigArgumentCaptor.capture()); |
||||
verify(mockRunnerBuilder).build(); |
||||
|
||||
assertThat(wsRpcConfigArgumentCaptor.getValue().getHost()).isEqualTo(host); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsNoAuthApiMethodsCannotBeInvalid() { |
||||
parseCommand("--rpc-ws-enabled", "--rpc-ws-api-methods-no-auth", "invalid"); |
||||
|
||||
Mockito.verifyNoInteractions(mockRunnerBuilder); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)) |
||||
.contains( |
||||
"Invalid value for option '--rpc-ws-api-methods-no-auth', options must be valid RPC methods"); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsApisPropertyWithInvalidEntryMustDisplayError() { |
||||
parseCommand("--rpc-ws-api", "ETH,BOB,TEST"); |
||||
|
||||
Mockito.verifyNoInteractions(mockRunnerBuilder); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
|
||||
assertThat(commandErrorOutput.toString(UTF_8).trim()) |
||||
.contains("Invalid value for option '--rpc-ws-api': invalid entries found [BOB, TEST]"); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsOptionsRequiresServiceToBeEnabled() { |
||||
parseCommand( |
||||
"--rpc-ws-api", |
||||
"ETH,NET", |
||||
"--rpc-ws-host", |
||||
"0.0.0.0", |
||||
"--rpc-ws-port", |
||||
"1234", |
||||
"--rpc-ws-max-active-connections", |
||||
"77", |
||||
"--rpc-ws-max-frame-size", |
||||
"65535"); |
||||
|
||||
verifyOptionsConstraintLoggerCall( |
||||
"--rpc-ws-enabled", |
||||
"--rpc-ws-host", |
||||
"--rpc-ws-port", |
||||
"--rpc-ws-api", |
||||
"--rpc-ws-max-active-connections", |
||||
"--rpc-ws-max-frame-size"); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void rpcWsOptionsRequiresServiceToBeEnabledToml() throws IOException { |
||||
final Path toml = |
||||
createTempFile( |
||||
"toml", |
||||
"rpc-ws-api=[\"ETH\", \"NET\"]\n" |
||||
+ "rpc-ws-host=\"0.0.0.0\"\n" |
||||
+ "rpc-ws-port=1234\n" |
||||
+ "rpc-ws-max-active-connections=77\n" |
||||
+ "rpc-ws-max-frame-size=65535\n"); |
||||
|
||||
parseCommand("--config-file", toml.toString()); |
||||
|
||||
verifyOptionsConstraintLoggerCall( |
||||
"--rpc-ws-enabled", |
||||
"--rpc-ws-host", |
||||
"--rpc-ws-port", |
||||
"--rpc-ws-api", |
||||
"--rpc-ws-max-active-connections", |
||||
"--rpc-ws-max-frame-size"); |
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
public void wsAuthenticationWithoutRequiredConfiguredOptionsMustFail() { |
||||
parseCommand("--rpc-ws-enabled", "--rpc-ws-authentication-enabled"); |
||||
|
||||
verifyNoInteractions(mockRunnerBuilder); |
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty(); |
||||
assertThat(commandErrorOutput.toString(UTF_8)) |
||||
.contains( |
||||
"Unable to authenticate JSON-RPC WebSocket endpoint without a supplied credentials file or authentication public key file"); |
||||
} |
||||
} |
Loading…
Reference in new issue