All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.swirlds.test.framework.config.TestConfigBuilder Maven / Gradle / Ivy

/*
 * Copyright (C) 2023 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.swirlds.test.framework.config;

import com.swirlds.common.config.ConfigUtils;
import com.swirlds.common.config.singleton.ConfigurationHolder;
import com.swirlds.common.threading.locks.AutoClosableLock;
import com.swirlds.common.threading.locks.Locks;
import com.swirlds.common.threading.locks.locked.Locked;
import com.swirlds.config.api.ConfigData;
import com.swirlds.config.api.Configuration;
import com.swirlds.config.api.ConfigurationBuilder;
import com.swirlds.config.api.converter.ConfigConverter;
import com.swirlds.config.api.source.ConfigSource;
import com.swirlds.config.api.validation.ConfigValidator;
import com.swirlds.config.extensions.sources.SimpleConfigSource;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.util.Objects;
import java.util.Set;

/**
 * Helper for use the config in test and change the config for specific tests. Instance can be used per class or per
 * test.
 */
public class TestConfigBuilder {

    private static final String SWIRLDS_PACKAGE = "com.swirlds";
    private static final String HEDERA_PACKAGE = "com.hedera";

    private final AutoClosableLock configLock = Locks.createAutoLock();

    private Configuration configuration = null;

    private final ConfigurationBuilder builder;

    /**
     * Creates a new instance and automatically registers all config data records (see {@link ConfigData}) on classpath
     * / modulepath that are part of the packages {@code com.swirlds} and {@code com.hedera} (see {@link ConfigUtils}).
     */
    public TestConfigBuilder() {
        this(true);
    }

    /**
     * Creates a new instance and automatically registers all given config data records. This call will not do a class
     * scan for config data records on classpath / modulepath like some of the other constructors do.
     *
     * @param dataTypes
     */
    public TestConfigBuilder(@Nullable final Class dataTypes) {
        this(false);
        if (dataTypes != null) {
            this.builder.withConfigDataTypes(dataTypes);
        }
    }

    /**
     * Creates a new instance and automatically registers all config data records (see {@link ConfigData}) on classpath
     * / modulepath that are part of the packages {@code com.swirlds} and {@code com.hedera} (see {@link ConfigUtils})
     * if the {@code registerAllTypes} param is true.
     *
     * @param registerAllTypes if true all config data records on classpath will automatically be registered
     */
    public TestConfigBuilder(final boolean registerAllTypes) {
        if (registerAllTypes) {
            this.builder = ConfigUtils.scanAndRegisterAllConfigTypes(
                    ConfigurationBuilder.create(), Set.of(SWIRLDS_PACKAGE, HEDERA_PACKAGE));
        } else {
            this.builder = ConfigurationBuilder.create();
        }
    }

    /**
     * Sets the value for the config.
     *
     * @param propertyName name of the property
     * @param value        the value
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public TestConfigBuilder withValue(@NonNull final String propertyName, @Nullable final String value) {
        return withSource(new SimpleConfigSource(propertyName, value));
    }

    /**
     * Sets the value for the config.
     *
     * @param propertyName name of the property
     * @param value        the value
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public TestConfigBuilder withValue(@NonNull final String propertyName, final int value) {
        return withSource(new SimpleConfigSource(propertyName, value));
    }

    /**
     * Sets the value for the config.
     *
     * @param propertyName name of the property
     * @param value        the value
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public TestConfigBuilder withValue(@NonNull final String propertyName, final double value) {
        return withSource(new SimpleConfigSource(propertyName, value));
    }

    /**
     * Sets the value for the config.
     *
     * @param propertyName name of the property
     * @param value        the value
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public TestConfigBuilder withValue(@NonNull final String propertyName, final long value) {
        return withSource(new SimpleConfigSource(propertyName, value));
    }

    /**
     * Sets the value for the config.
     *
     * @param propertyName name of the property
     * @param value        the value
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public TestConfigBuilder withValue(@NonNull final String propertyName, final boolean value) {
        return withSource(new SimpleConfigSource(propertyName, value));
    }

    /**
     * Sets the value for the config.
     *
     * @param propertyName name of the property
     * @param value        the value
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public TestConfigBuilder withValue(@NonNull final String propertyName, @NonNull final Object value) {
        Objects.requireNonNull(value, "value must not be null");
        return withSource(new SimpleConfigSource(propertyName, value.toString()));
    }

    /**
     * This method returns the {@link Configuration} instance. If the method is called for the first time the
     * {@link Configuration} instance will be created. All values that have been set (see
     * {@link #withValue(String, int)}) methods will be part of the config. Next to this the config will support all
     * config data record types (see {@link ConfigData}) that are on the classpath.
     *
     * @return the created configuration
     */
    @NonNull
    public Configuration getOrCreateConfig() {
        try (final Locked ignore = configLock.lock()) {
            if (configuration == null) {
                configuration = builder.build();
                ConfigurationHolder.getInstance().setConfiguration(configuration);
            }
            return configuration;
        }
    }

    private void checkConfigState() {
        try (final Locked ignore = configLock.lock()) {
            if (configuration != null) {
                throw new IllegalStateException("Configuration already created!");
            }
        }
    }

    /**
     * Adds the given config source to the builder
     *
     * @param configSource the config source that will be added
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public TestConfigBuilder withSource(@NonNull final ConfigSource configSource) {
        checkConfigState();
        builder.withSource(configSource);
        return this;
    }

    /**
     * Adds the given config converter to the builder
     *
     * @param converter the config converter that will be added
     * @param        the type of the config converter
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public  TestConfigBuilder withConverter(@NonNull final ConfigConverter converter) {
        checkConfigState();
        builder.withConverter(converter);
        return this;
    }

    /**
     * Adds the given config validator to the builder
     *
     * @param validator the config validator that will be added
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public TestConfigBuilder withValidator(@NonNull final ConfigValidator validator) {
        checkConfigState();
        builder.withValidator(validator);
        return this;
    }

    /**
     * Adds the given config data type to the builder
     *
     * @param type the config data type that will be added
     * @param   the type of the config data type
     * @return the {@link TestConfigBuilder} instance (for fluent API)
     */
    @NonNull
    public  TestConfigBuilder withConfigDataType(@NonNull final Class type) {
        checkConfigState();
        builder.withConfigDataType(type);
        return this;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy