@ -50,13 +50,15 @@ import java.nio.file.Path;
import java.nio.file.Paths ;
import java.util.Collection ;
import java.util.Collections ;
import java.util.HashSet ;
import java.util.List ;
import java.util.Optional ;
import java.util.stream.Collectors ;
import java.util.stream.Stream ;
import com.google.common.collect.Lists ;
import com.google.common.io.Resources ;
import net.consensys.cava.toml.Toml ;
import net.consensys.cava.toml.TomlParseResult ;
import org.apache.commons.text.StringEscapeUtils ;
import org.junit.Before ;
import org.junit.Ignore ;
@ -65,6 +67,7 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder ;
import org.mockito.ArgumentCaptor ;
import org.mockito.ArgumentMatchers ;
import picocli.CommandLine ;
public class PantheonCommandTest extends CommandTestAbstract {
private final String VALID_NODE_ID =
@ -76,13 +79,13 @@ public class PantheonCommandTest extends CommandTestAbstract {
private static final MetricsConfiguration defaultMetricsConfiguration ;
private static final String GENESIS_CONFIG_TESTDATA = "genesis_config" ;
final String [ ] validENodeStrings = {
private final String [ ] validENodeStrings = {
"enode://" + VALID_NODE_ID + "@192.168.0.1:4567" ,
"enode://" + VALID_NODE_ID + "@192.168.0.2:4567" ,
"enode://" + VALID_NODE_ID + "@192.168.0.3:4567"
} ;
final String [ ] ropstenBootnodes = {
private final String [ ] ropstenBootnodes = {
"enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303" ,
"enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303"
} ;
@ -98,8 +101,7 @@ public class PantheonCommandTest extends CommandTestAbstract {
websocketConf . addRpcApi ( IbftRpcApis . IBFT ) ;
defaultWebSocketConfiguration = websocketConf ;
final MetricsConfiguration metricsConf = MetricsConfiguration . createDefault ( ) ;
defaultMetricsConfiguration = metricsConf ;
defaultMetricsConfiguration = MetricsConfiguration . createDefault ( ) ;
}
@Before
@ -339,6 +341,47 @@ public class PantheonCommandTest extends CommandTestAbstract {
assertThat ( commandErrorOutput . toString ( ) ) . isEmpty ( ) ;
}
@Test
public void tomlThatConfiguresEverything ( ) throws IOException {
assumeTrue ( isFullInstantiation ( ) ) ;
// Load a TOML that configures literally everything
final URL configFile = Resources . getResource ( "everything_config.toml" ) ;
final Path toml = Files . createTempFile ( "toml" , "" ) ;
Files . write ( toml , Resources . toByteArray ( configFile ) ) ;
// Parse it.
final CommandLine . Model . CommandSpec spec = parseCommand ( "--config" , toml . toString ( ) ) ;
final TomlParseResult tomlResult = Toml . parse ( toml ) ;
// Verify we configured everything
final HashSet < CommandLine . Model . OptionSpec > options = new HashSet < > ( spec . options ( ) ) ;
// Except for meta-options
options . remove ( spec . optionsMap ( ) . get ( "--config" ) ) ;
options . remove ( spec . optionsMap ( ) . get ( "--help" ) ) ;
options . remove ( spec . optionsMap ( ) . get ( "--version" ) ) ;
for ( final String tomlKey : tomlResult . keySet ( ) ) {
final CommandLine . Model . OptionSpec optionSpec = spec . optionsMap ( ) . get ( "--" + tomlKey ) ;
assertThat ( optionSpec )
. describedAs ( "Option '%s' should be a configurable option." , tomlKey )
. isNotNull ( ) ;
// Verify TOML stores it by the appropriate type
if ( optionSpec . type ( ) . equals ( Boolean . class ) ) {
tomlResult . getBoolean ( tomlKey ) ;
} else if ( optionSpec . isMultiValue ( ) | | optionSpec . arity ( ) . max > 1 ) {
tomlResult . getArray ( tomlKey ) ;
} else if ( Number . class . isAssignableFrom ( optionSpec . type ( ) ) ) {
tomlResult . getLong ( tomlKey ) ;
} else {
tomlResult . getString ( tomlKey ) ;
}
options . remove ( optionSpec ) ;
}
assertThat ( options . stream ( ) . map ( CommandLine . Model . OptionSpec : : longestName ) ) . isEmpty ( ) ;
}
@Test
public void noOverrideDefaultValuesIfKeyIsNotPresentInConfigFile ( ) throws IOException {
assumeTrue ( isFullInstantiation ( ) ) ;
@ -823,6 +866,21 @@ public class PantheonCommandTest extends CommandTestAbstract {
assertThat ( commandErrorOutput . toString ( ) ) . isEmpty ( ) ;
}
@Test
public void jsonRpcCorsOriginsDoubleCommaFilteredOut ( ) {
final String [ ] origins = { "http://domain1.com" , "https://domain2.com" } ;
parseCommand ( "--rpc-cors-origins" , String . join ( ",," , origins ) ) ;
verify ( mockRunnerBuilder ) . jsonRpcConfiguration ( jsonRpcConfigArgumentCaptor . capture ( ) ) ;
verify ( mockRunnerBuilder ) . build ( ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getCorsAllowedDomains ( ) . toArray ( ) )
. isEqualTo ( origins ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) ) . isEmpty ( ) ;
}
@Test
public void jsonRpcCorsOriginsWithWildcardMustBuildListWithWildcard ( ) {
final String [ ] origins = { "*" } ;
@ -840,14 +898,12 @@ public class PantheonCommandTest extends CommandTestAbstract {
@Test
public void jsonRpcCorsOriginsWithAllMustBuildListWithWildcard ( ) {
final String [ ] origins = { "all" } ;
parseCommand ( "--rpc-cors-origins" , String . join ( "," , origins ) ) ;
parseCommand ( "--rpc-cors-origins" , "all" ) ;
verify ( mockRunnerBuilder ) . jsonRpcConfiguration ( jsonRpcConfigArgumentCaptor . capture ( ) ) ;
verify ( mockRunnerBuilder ) . build ( ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getCorsAllowedDomains ( ) )
. isEqualTo ( Lists . newArrayList ( "*" ) ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getCorsAllowedDomains ( ) ) . containsExactly ( "*" ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) ) . isEmpty ( ) ;
@ -880,27 +936,59 @@ public class PantheonCommandTest extends CommandTestAbstract {
}
@Test
public void jsonRpcCorsOriginsAllWithAnotherDomainMustFail ( ) {
final String [ ] origins = { "http://domain1.com" , "all " } ;
public void jsonRpcCorsOriginsNoneWithAnotherDomainMustFailNoneFirst ( ) {
final String [ ] origins = { "none" , "http://domain1.com " } ;
parseCommand ( "--rpc-cors-origins" , String . join ( "," , origins ) ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Value 'all' can't be used with other domains" ) ;
. contains ( "Value 'none' can't be used with other domains" ) ;
}
@Test
public void jsonRpcCorsOriginsAllWithAnotherDomainMustFail ( ) {
parseCommand ( "--rpc-cors-origins=http://domain1.com,all" ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Values '*' or 'all' can't be used with other domains" ) ;
}
@Test
public void jsonRpcCorsOriginsAllWithAnotherDomainMustFailAsFlags ( ) {
parseCommand ( "--rpc-cors-origins=http://domain1.com" , "--rpc-cors-origins=all" ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Values '*' or 'all' can't be used with other domains" ) ;
}
@Test
public void jsonRpcCorsOriginsWildcardWithAnotherDomainMustFail ( ) {
final String [ ] origins = { "http://domain1.com" , "*" } ;
parseCommand ( "--rpc-cors-origins" , String . join ( "," , origins ) ) ;
parseCommand ( "--rpc-cors-origins=http://domain1.com,*" ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Value 'all' can't be used with other domains" ) ;
. contains ( "Values '*' or 'all' can't be used with other domains" ) ;
}
@Test
public void jsonRpcCorsOriginsWildcardWithAnotherDomainMustFailAsFlags ( ) {
parseCommand ( "--rpc-cors-origins=http://domain1.com" , "--rpc-cors-origins=*" ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Values '*' or 'all' can't be used with other domains" ) ;
}
@Test
@ -915,6 +1003,17 @@ public class PantheonCommandTest extends CommandTestAbstract {
. contains ( "Domain values result in invalid regex pattern" ) ;
}
@Test
public void jsonRpcCorsOriginsEmtyValueFails ( ) {
parseCommand ( "--rpc-cors-origins=" ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Domain cannot be empty string or null string." ) ;
}
@Test
public void jsonRpcHostWhitelistAcceptsSingleArgument ( ) {
parseCommand ( "--host-whitelist" , "a" ) ;
@ -947,6 +1046,38 @@ public class PantheonCommandTest extends CommandTestAbstract {
assertThat ( commandErrorOutput . toString ( ) ) . isEmpty ( ) ;
}
@Test
public void jsonRpcHostWhitelistAcceptsDoubleComma ( ) {
parseCommand ( "--host-whitelist" , "a,,b" ) ;
verify ( mockRunnerBuilder ) . jsonRpcConfiguration ( jsonRpcConfigArgumentCaptor . capture ( ) ) ;
verify ( mockRunnerBuilder ) . build ( ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getHostsWhitelist ( ) . size ( ) ) . isEqualTo ( 2 ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getHostsWhitelist ( ) ) . contains ( "a" , "b" ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getHostsWhitelist ( ) )
. doesNotContain ( "*" , "localhost" ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) ) . isEmpty ( ) ;
}
@Test
public void jsonRpcHostWhitelistAcceptsMultipleFlags ( ) {
parseCommand ( "--host-whitelist=a" , "--host-whitelist=b" ) ;
verify ( mockRunnerBuilder ) . jsonRpcConfiguration ( jsonRpcConfigArgumentCaptor . capture ( ) ) ;
verify ( mockRunnerBuilder ) . build ( ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getHostsWhitelist ( ) . size ( ) ) . isEqualTo ( 2 ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getHostsWhitelist ( ) ) . contains ( "a" , "b" ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getHostsWhitelist ( ) )
. doesNotContain ( "*" , "localhost" ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) ) . isEmpty ( ) ;
}
@Test
public void jsonRpcHostWhitelistStarWithAnotherHostnameMustFail ( ) {
final String [ ] origins = { "friend" , "*" } ;
@ -956,7 +1087,19 @@ public class PantheonCommandTest extends CommandTestAbstract {
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Value '*' can't be used with other hostnames" ) ;
. contains ( "Values '*' or 'all' can't be used with other hostnames" ) ;
}
@Test
public void jsonRpcHostWhitelistStarWithAnotherHostnameMustFailStarFirst ( ) {
final String [ ] origins = { "*" , "friend" } ;
parseCommand ( "--host-whitelist" , String . join ( "," , origins ) ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Values '*' or 'all' can't be used with other hostnames" ) ;
}
@Test
@ -968,7 +1111,56 @@ public class PantheonCommandTest extends CommandTestAbstract {
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Value 'all' can't be used with other hostnames" ) ;
. contains ( "Values '*' or 'all' can't be used with other hostnames" ) ;
}
@Test
public void jsonRpcHostWhitelistWithNoneMustBuildEmptyList ( ) {
final String [ ] origins = { "none" } ;
parseCommand ( "--host-whitelist" , String . join ( "," , origins ) ) ;
verify ( mockRunnerBuilder ) . jsonRpcConfiguration ( jsonRpcConfigArgumentCaptor . capture ( ) ) ;
verify ( mockRunnerBuilder ) . build ( ) ;
assertThat ( jsonRpcConfigArgumentCaptor . getValue ( ) . getHostsWhitelist ( ) ) . isEmpty ( ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) ) . isEmpty ( ) ;
}
@Test
public void jsonRpcHostWhitelistNoneWithAnotherDomainMustFail ( ) {
final String [ ] origins = { "http://domain1.com" , "none" } ;
parseCommand ( "--host-whitelist" , String . join ( "," , origins ) ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Value 'none' can't be used with other hostnames" ) ;
}
@Test
public void jsonRpcHostWhitelistNoneWithAnotherDomainMustFailNoneFirst ( ) {
final String [ ] origins = { "none" , "http://domain1.com" } ;
parseCommand ( "--host-whitelist" , String . join ( "," , origins ) ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Value 'none' can't be used with other hostnames" ) ;
}
@Test
public void jsonRpcHostWhitelistEmptyValueFails ( ) {
parseCommand ( "--host-whitelist=" ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;
assertThat ( commandOutput . toString ( ) ) . isEmpty ( ) ;
assertThat ( commandErrorOutput . toString ( ) )
. contains ( "Hostname cannot be empty string or null string." ) ;
}
@Test
@ -1175,7 +1367,7 @@ public class PantheonCommandTest extends CommandTestAbstract {
}
@Test
public void noSeveralNetworkOptions ( ) throws Exception {
public void noSeveralNetworkOptions ( ) {
parseCommand ( "--goerli" , "--rinkeby" ) ;
verifyZeroInteractions ( mockRunnerBuilder ) ;