diff --git a/server/src/main/java/com/hedera/block/server/config/ServerMappedConfigSourceInitializer.java b/server/src/main/java/com/hedera/block/server/config/ServerMappedConfigSourceInitializer.java index 1b441de09..7d23f2e31 100644 --- a/server/src/main/java/com/hedera/block/server/config/ServerMappedConfigSourceInitializer.java +++ b/server/src/main/java/com/hedera/block/server/config/ServerMappedConfigSourceInitializer.java @@ -33,9 +33,13 @@ public final class ServerMappedConfigSourceInitializer { new ConfigMapping("persistence.storage.type", "PERSISTENCE_STORAGE_TYPE"), new ConfigMapping("service.delayMillis", "SERVICE_DELAY_MILLIS"), new ConfigMapping("mediator.ringBufferSize", "MEDIATOR_RING_BUFFER_SIZE"), + new ConfigMapping("mediator.type", "MEDIATOR_TYPE"), new ConfigMapping("notifier.ringBufferSize", "NOTIFIER_RING_BUFFER_SIZE"), + new ConfigMapping("producer.type", "PRODUCER_TYPE"), new ConfigMapping("server.maxMessageSizeBytes", "SERVER_MAX_MESSAGE_SIZE_BYTES"), - new ConfigMapping("server.port", "SERVER_PORT")); + new ConfigMapping("server.port", "SERVER_PORT"), + new ConfigMapping("prometheus.endpointEnabled", "PROMETHEUS_ENDPOINT_ENABLED"), + new ConfigMapping("prometheus.endpointPortNumber", "PROMETHEUS_ENDPOINT_PORT_NUMBER")); private ServerMappedConfigSourceInitializer() {} diff --git a/server/src/test/java/com/hedera/block/server/config/ServerMappedConfigSourceInitializerTest.java b/server/src/test/java/com/hedera/block/server/config/ServerMappedConfigSourceInitializerTest.java index 47b86af65..7c0bdfb72 100644 --- a/server/src/test/java/com/hedera/block/server/config/ServerMappedConfigSourceInitializerTest.java +++ b/server/src/test/java/com/hedera/block/server/config/ServerMappedConfigSourceInitializerTest.java @@ -35,9 +35,13 @@ class ServerMappedConfigSourceInitializerTest { new ConfigMapping("persistence.storage.type", "PERSISTENCE_STORAGE_TYPE"), new ConfigMapping("service.delayMillis", "SERVICE_DELAY_MILLIS"), new ConfigMapping("mediator.ringBufferSize", "MEDIATOR_RING_BUFFER_SIZE"), + new ConfigMapping("mediator.type", "MEDIATOR_TYPE"), new ConfigMapping("notifier.ringBufferSize", "NOTIFIER_RING_BUFFER_SIZE"), + new ConfigMapping("producer.type", "PRODUCER_TYPE"), new ConfigMapping("server.maxMessageSizeBytes", "SERVER_MAX_MESSAGE_SIZE_BYTES"), new ConfigMapping("server.port", "SERVER_PORT"), + new ConfigMapping("prometheus.endpointEnabled", "PROMETHEUS_ENDPOINT_ENABLED"), + new ConfigMapping("prometheus.endpointPortNumber", "PROMETHEUS_ENDPOINT_PORT_NUMBER") }; private static MappedConfigSource toTest; diff --git a/simulator/build.gradle.kts b/simulator/build.gradle.kts index e7bbf9b6c..61d9da975 100644 --- a/simulator/build.gradle.kts +++ b/simulator/build.gradle.kts @@ -44,6 +44,34 @@ testModuleInfo { requires("com.google.protobuf") } +// Task to run simulator in Publisher mode +tasks.register("runPublisher") { + description = "Run the simulator in Publisher mode" + group = "application" + + mainClass = application.mainClass + mainModule = application.mainModule + classpath = sourceSets["main"].runtimeClasspath + + environment("BLOCK_STREAM_SIMULATOR_MODE", "PUBLISHER") + environment("PROMETHEUS_ENDPOINT_ENABLED", "true") + environment("PROMETHEUS_ENDPOINT_PORT_NUMBER", "9998") +} + +// Task to run simulator in Consumer mode +tasks.register("runConsumer") { + description = "Run the simulator in Consumer mode" + group = "application" + + mainClass = application.mainClass + mainModule = application.mainModule + classpath = sourceSets["main"].runtimeClasspath + + environment("BLOCK_STREAM_SIMULATOR_MODE", "CONSUMER") + environment("PROMETHEUS_ENDPOINT_ENABLED", "true") + environment("PROMETHEUS_ENDPOINT_PORT_NUMBER", "9997") +} + tasks.register("untarTestBlockStream") { description = "Untar the test block stream data" group = "build" diff --git a/simulator/src/main/java/com/hedera/block/simulator/BlockStreamSimulator.java b/simulator/src/main/java/com/hedera/block/simulator/BlockStreamSimulator.java index a4a63c9dd..f0b66e09a 100644 --- a/simulator/src/main/java/com/hedera/block/simulator/BlockStreamSimulator.java +++ b/simulator/src/main/java/com/hedera/block/simulator/BlockStreamSimulator.java @@ -19,6 +19,7 @@ import static com.hedera.block.common.constants.StringsConstants.APPLICATION_PROPERTIES; import static java.lang.System.Logger.Level.INFO; +import com.hedera.block.simulator.config.SimulatorMappedConfigSourceInitializer; import com.hedera.block.simulator.exception.BlockSimulatorParsingException; import com.swirlds.config.api.Configuration; import com.swirlds.config.api.ConfigurationBuilder; @@ -50,6 +51,7 @@ public static void main(final String[] args) LOGGER.log(INFO, "Starting Block Stream Simulator!"); final ConfigurationBuilder configurationBuilder = ConfigurationBuilder.create() + .withSource(SimulatorMappedConfigSourceInitializer.getMappedConfigSource()) .withSource(SystemEnvironmentConfigSource.getInstance()) .withSource(SystemPropertiesConfigSource.getInstance()) .withSource(new ClasspathFileConfigSource(Path.of(APPLICATION_PROPERTIES))) diff --git a/simulator/src/main/java/com/hedera/block/simulator/config/SimulatorMappedConfigSourceInitializer.java b/simulator/src/main/java/com/hedera/block/simulator/config/SimulatorMappedConfigSourceInitializer.java new file mode 100644 index 000000000..33f1fb54f --- /dev/null +++ b/simulator/src/main/java/com/hedera/block/simulator/config/SimulatorMappedConfigSourceInitializer.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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 com.hedera.block.simulator.config; + +import com.swirlds.config.extensions.sources.ConfigMapping; +import com.swirlds.config.extensions.sources.MappedConfigSource; +import com.swirlds.config.extensions.sources.SystemEnvironmentConfigSource; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.List; + +/** + * A class that extends {@link MappedConfigSource} in order to have project-relevant initialization. + */ +public final class SimulatorMappedConfigSourceInitializer { + private static final List MAPPINGS = List.of( + // gRPC configuration + new ConfigMapping("grpc.serverAddress", "GRPC_SERVER_ADDRESS"), + new ConfigMapping("grpc.port", "GRPC_PORT"), + + // Block stream configuration + new ConfigMapping("blockStream.simulatorMode", "BLOCK_STREAM_SIMULATOR_MODE"), + new ConfigMapping("blockStream.delayBetweenBlockItems", "BLOCK_STREAM_DELAY_BETWEEN_BLOCK_ITEMS"), + new ConfigMapping("blockStream.maxBlockItemsToStream", "BLOCK_STREAM_MAX_BLOCK_ITEMS_TO_STREAM"), + new ConfigMapping("blockStream.streamingMode", "BLOCK_STREAM_STREAMING_MODE"), + new ConfigMapping("blockStream.millisecondsPerBlock", "BLOCK_STREAM_MILLISECONDS_PER_BLOCK"), + new ConfigMapping("blockStream.blockItemsBatchSize", "BLOCK_STREAM_BLOCK_ITEMS_BATCH_SIZE"), + + // Block generator configuration + new ConfigMapping("generator.generationMode", "GENERATOR_GENERATION_MODE"), + new ConfigMapping("generator.folderRootPath", "GENERATOR_FOLDER_ROOT_PATH"), + new ConfigMapping("generator.managerImplementation", "GENERATOR_MANAGER_IMPLEMENTATION"), + new ConfigMapping("generator.paddedLength", "GENERATOR_PADDED_LENGTH"), + new ConfigMapping("generator.fileExtension", "GENERATOR_FILE_EXTENSION"), + new ConfigMapping("generator.startBlockNumber", "GENERATOR_START_BLOCK_NUMBER"), + new ConfigMapping("generator.endBlockNumber", "GENERATOR_END_BLOCK_NUMBER"), + + // Prometheus configuration + new ConfigMapping("prometheus.endpointEnabled", "PROMETHEUS_ENDPOINT_ENABLED"), + new ConfigMapping("prometheus.endpointPortNumber", "PROMETHEUS_ENDPOINT_PORT_NUMBER")); + + private SimulatorMappedConfigSourceInitializer() {} + + /** + * This method constructs, initializes and returns a new instance of {@link MappedConfigSource} + * which internally uses {@link SystemEnvironmentConfigSource} and maps relevant config keys to + * other keys so that they could be used within the application + * + * @return newly constructed fully initialized {@link MappedConfigSource} + */ + @NonNull + public static MappedConfigSource getMappedConfigSource() { + final MappedConfigSource config = new MappedConfigSource(SystemEnvironmentConfigSource.getInstance()); + MAPPINGS.forEach(config::addMapping); + return config; + } +} diff --git a/simulator/src/test/java/com/hedera/block/simulator/config/SimulatorMappedConfigSourceInitializerTest.java b/simulator/src/test/java/com/hedera/block/simulator/config/SimulatorMappedConfigSourceInitializerTest.java new file mode 100644 index 000000000..343a59410 --- /dev/null +++ b/simulator/src/test/java/com/hedera/block/simulator/config/SimulatorMappedConfigSourceInitializerTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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 com.hedera.block.simulator.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.swirlds.config.extensions.sources.ConfigMapping; +import com.swirlds.config.extensions.sources.MappedConfigSource; +import java.lang.reflect.Field; +import java.util.Queue; +import java.util.function.Predicate; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class SimulatorMappedConfigSourceInitializerTest { + private static final ConfigMapping[] SUPPORTED_MAPPINGS = { + // gRPC configuration + new ConfigMapping("grpc.serverAddress", "GRPC_SERVER_ADDRESS"), + new ConfigMapping("grpc.port", "GRPC_PORT"), + + // Block stream configuration + new ConfigMapping("blockStream.simulatorMode", "BLOCK_STREAM_SIMULATOR_MODE"), + new ConfigMapping("blockStream.delayBetweenBlockItems", "BLOCK_STREAM_DELAY_BETWEEN_BLOCK_ITEMS"), + new ConfigMapping("blockStream.maxBlockItemsToStream", "BLOCK_STREAM_MAX_BLOCK_ITEMS_TO_STREAM"), + new ConfigMapping("blockStream.streamingMode", "BLOCK_STREAM_STREAMING_MODE"), + new ConfigMapping("blockStream.millisecondsPerBlock", "BLOCK_STREAM_MILLISECONDS_PER_BLOCK"), + new ConfigMapping("blockStream.blockItemsBatchSize", "BLOCK_STREAM_BLOCK_ITEMS_BATCH_SIZE"), + + // Block generator configuration + new ConfigMapping("generator.generationMode", "GENERATOR_GENERATION_MODE"), + new ConfigMapping("generator.folderRootPath", "GENERATOR_FOLDER_ROOT_PATH"), + new ConfigMapping("generator.managerImplementation", "GENERATOR_MANAGER_IMPLEMENTATION"), + new ConfigMapping("generator.paddedLength", "GENERATOR_PADDED_LENGTH"), + new ConfigMapping("generator.fileExtension", "GENERATOR_FILE_EXTENSION"), + new ConfigMapping("generator.startBlockNumber", "GENERATOR_START_BLOCK_NUMBER"), + new ConfigMapping("generator.endBlockNumber", "GENERATOR_END_BLOCK_NUMBER"), + + // Prometheus configuration + new ConfigMapping("prometheus.endpointEnabled", "PROMETHEUS_ENDPOINT_ENABLED"), + new ConfigMapping("prometheus.endpointPortNumber", "PROMETHEUS_ENDPOINT_PORT_NUMBER") + }; + private static MappedConfigSource toTest; + + @BeforeAll + static void setUp() { + toTest = SimulatorMappedConfigSourceInitializer.getMappedConfigSource(); + } + + /** + * This test aims to fail if we have added or removed any {@link ConfigMapping} that will be + * initialized by the {@link SimulatorMappedConfigSourceInitializer#getMappedConfigSource()} + * without reflecting it here in the test. The purpose is to bring attention to any changes to + * the developer so we can make sure we are aware of them in order to be sure we require the + * change. This test is more to bring attention than to test actual logic. So if this fails, we + * either change the {@link #SUPPORTED_MAPPINGS} here or the {@link + * SimulatorMappedConfigSourceInitializer#MAPPINGS} to make this pass. + */ + @Test + void test_VerifyAllSupportedMappingsAreAddedToInstance() throws ReflectiveOperationException { + final Queue actual = extractConfigMappings(); + + assertEquals(SUPPORTED_MAPPINGS.length, actual.size()); + + for (final ConfigMapping current : SUPPORTED_MAPPINGS) { + final Predicate predicate = + cm -> current.mappedName().equals(cm.mappedName()) + && current.originalName().equals(cm.originalName()); + assertTrue( + actual.stream().anyMatch(predicate), + () -> "when testing for: [%s] it is not contained in mappings of the actual initialized object %s" + .formatted(current, actual)); + } + } + + private static Queue extractConfigMappings() throws ReflectiveOperationException { + final Field configMappings = MappedConfigSource.class.getDeclaredField("configMappings"); + try { + configMappings.setAccessible(true); + return (Queue) configMappings.get(toTest); + } finally { + configMappings.setAccessible(false); + } + } +}