IGNITE-15486 JUnit configuration extension implemented (#329)
diff --git a/modules/configuration/pom.xml b/modules/configuration/pom.xml
index 2381420..eab28ee 100644
--- a/modules/configuration/pom.xml
+++ b/modules/configuration/pom.xml
@@ -67,6 +67,12 @@
<artifactId>hamcrest-library</artifactId>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
index ff48983..32cdd14 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
@@ -56,7 +56,7 @@
/**
* Class that handles configuration changes, by validating them, passing to storage and listening to storage updates.
*/
-public abstract class ConfigurationChanger {
+public abstract class ConfigurationChanger implements DynamicConfigurationChanger {
/** Thread pool. */
private final ForkJoinPool pool = new ForkJoinPool(2);
@@ -237,13 +237,8 @@
}
}
- /**
- * Changes the configuration.
- *
- * @param source Configuration source to create patch from.
- * @return Future that is completed on change completion.
- */
- public CompletableFuture<Void> change(ConfigurationSource source) {
+ /** {@inheritDoc} */
+ @Override public CompletableFuture<Void> change(ConfigurationSource source) {
return changeInternally(source);
}
@@ -257,13 +252,8 @@
roots.changeFuture.completeExceptionally(new NodeStoppingException());
}
- /**
- * Get root node by root key. Subject to revisiting.
- *
- * @param rootKey Root key.
- * @return Root node.
- */
- public InnerNode getRootNode(RootKey<?, ?> rootKey) {
+ /** {@inheritDoc} */
+ @Override public InnerNode getRootNode(RootKey<?, ?> rootKey) {
return storageRoots.roots.getRoot(rootKey);
}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationNode.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationNode.java
index 8025153..1f0b48c 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationNode.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationNode.java
@@ -46,7 +46,7 @@
protected final RootKey<?, ?> rootKey;
/** Configuration changer instance to get latest value of the root. */
- protected final ConfigurationChanger changer;
+ protected final DynamicConfigurationChanger changer;
/**
* Cached value of current trees root. Useful to determine whether you have the latest configuration value or not.
@@ -70,7 +70,7 @@
* @param rootKey Root key.
* @param changer Configuration changer.
*/
- protected ConfigurationNode(List<String> prefix, String key, RootKey<?, ?> rootKey, ConfigurationChanger changer) {
+ protected ConfigurationNode(List<String> prefix, String key, RootKey<?, ?> rootKey, DynamicConfigurationChanger changer) {
this.keys = ConfigurationUtil.appendKey(prefix, key);
this.key = key;
this.rootKey = rootKey;
diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicConfiguration.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicConfiguration.java
index ebe8538..13f73a1 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicConfiguration.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicConfiguration.java
@@ -52,7 +52,7 @@
List<String> prefix,
String key,
RootKey<?, ?> rootKey,
- ConfigurationChanger changer
+ DynamicConfigurationChanger changer
) {
super(prefix, key, rootKey, changer);
}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicConfigurationChanger.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicConfigurationChanger.java
new file mode 100644
index 0000000..ed3465f
--- /dev/null
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicConfigurationChanger.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.configuration;
+
+import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+
+/**
+ * Interface to provide configuration access to up-to-date configuration trees in {@link DynamicConfiguration},
+ * {@link NamedListConfiguration} and {@link DynamicProperty}.
+ */
+public interface DynamicConfigurationChanger {
+ /**
+ * Changes the configuration.
+ *
+ * @param source Configuration source to create patch from.
+ * @return Future that is completed on change completion.
+ */
+ CompletableFuture<Void> change(ConfigurationSource source);
+
+ /**
+ * Get root node by root key.
+ *
+ * @param rootKey Root key.
+ * @return Root node.
+ */
+ InnerNode getRootNode(RootKey<?, ?> rootKey);
+}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicProperty.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicProperty.java
index 3203c56..21e76ad 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicProperty.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/DynamicProperty.java
@@ -42,7 +42,7 @@
List<String> prefix,
String key,
RootKey<?, ?> rootKey,
- ConfigurationChanger changer
+ DynamicConfigurationChanger changer
) {
super(prefix, key, rootKey, changer);
}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/NamedListConfiguration.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/NamedListConfiguration.java
index bf7c3b0..46156de 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/NamedListConfiguration.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/NamedListConfiguration.java
@@ -58,7 +58,7 @@
List<String> prefix,
String key,
RootKey<?, ?> rootKey,
- ConfigurationChanger changer,
+ DynamicConfigurationChanger changer,
BiFunction<List<String>, String, T> creator
) {
super(prefix, key, rootKey, changer);
diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationAsmGenerator.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationAsmGenerator.java
index 2479744..a78026e 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationAsmGenerator.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationAsmGenerator.java
@@ -61,8 +61,8 @@
import org.apache.ignite.configuration.annotation.InternalConfiguration;
import org.apache.ignite.configuration.annotation.NamedConfigValue;
import org.apache.ignite.configuration.annotation.Value;
-import org.apache.ignite.internal.configuration.ConfigurationChanger;
import org.apache.ignite.internal.configuration.DynamicConfiguration;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
import org.apache.ignite.internal.configuration.DynamicProperty;
import org.apache.ignite.internal.configuration.NamedListConfiguration;
import org.apache.ignite.internal.configuration.TypeUtils;
@@ -141,7 +141,7 @@
/** {@link ConstructableTreeNode#copy()} */
private static final Method COPY;
- /** {@link DynamicConfiguration#DynamicConfiguration(List, String, RootKey, ConfigurationChanger)} */
+ /** {@link DynamicConfiguration#DynamicConfiguration(List, String, RootKey, DynamicConfigurationChanger)} */
private static final Constructor DYNAMIC_CONFIGURATION_CTOR;
/** {@link DynamicConfiguration#add(ConfigurationProperty)} */
@@ -180,7 +180,7 @@
List.class,
String.class,
RootKey.class,
- ConfigurationChanger.class
+ DynamicConfigurationChanger.class
);
DYNAMIC_CONFIGURATION_ADD = DynamicConfiguration.class.getDeclaredMethod(
@@ -231,7 +231,7 @@
*/
public synchronized DynamicConfiguration<?, ?> instantiateCfg(
RootKey<?, ?> rootKey,
- ConfigurationChanger changer
+ DynamicConfigurationChanger changer
) {
SchemaClassesInfo info = schemasInfo.get(rootKey.schemaClass());
@@ -242,7 +242,7 @@
List.class,
String.class,
RootKey.class,
- ConfigurationChanger.class
+ DynamicConfigurationChanger.class
);
assert constructor.canAccess(null);
@@ -994,7 +994,7 @@
arg("prefix", List.class),
arg("key", String.class),
arg("rootKey", RootKey.class),
- arg("changer", ConfigurationChanger.class)
+ arg("changer", DynamicConfigurationChanger.class)
);
BytecodeBlock ctorBody = ctor.getBody()
@@ -1044,7 +1044,7 @@
"$new$" + newIdx++,
typeFromJavaClassName(fieldInfo.cfgClassName),
arg("rootKey", RootKey.class),
- arg("changer", ConfigurationChanger.class),
+ arg("changer", DynamicConfigurationChanger.class),
arg("prefix", List.class),
arg("key", String.class)
);
diff --git a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationUtil.java b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationUtil.java
index e093f12..e435eff 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationUtil.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/util/ConfigurationUtil.java
@@ -54,7 +54,7 @@
/** */
public class ConfigurationUtil {
/** Configuration source that copies values without modifying tham. */
- private static final ConfigurationSource EMPTY_CFG_SRC = new ConfigurationSource() {};
+ static final ConfigurationSource EMPTY_CFG_SRC = new ConfigurationSource() {};
/**
* Replaces all {@code .} and {@code \} characters with {@code \.} and {@code \\} respectively.
diff --git a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/testframework/ConfigurationExtension.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/testframework/ConfigurationExtension.java
new file mode 100644
index 0000000..6fe1d3c
--- /dev/null
+++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/testframework/ConfigurationExtension.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.configuration.testframework;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Parameter;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicReference;
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigObject;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
+import org.apache.ignite.internal.configuration.RootInnerNode;
+import org.apache.ignite.internal.configuration.SuperRoot;
+import org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator;
+import org.apache.ignite.internal.configuration.hocon.HoconConverter;
+import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+import org.apache.ignite.internal.configuration.util.ConfigurationUtil;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+import org.junit.platform.commons.support.AnnotationSupport;
+import org.junit.platform.commons.support.HierarchyTraversalMode;
+
+import static java.util.concurrent.CompletableFuture.completedFuture;
+import static org.apache.ignite.configuration.annotation.ConfigurationType.LOCAL;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * JUnit extension to inject configuration instances into test classes.
+ *
+ * @see InjectConfiguration
+ */
+public class ConfigurationExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {
+ /** JUnit namespace for the extension. */
+ private static final Namespace namespace = Namespace.create(ConfigurationExtension.class);
+
+ /** Key to store {@link ConfigurationAsmGenerator} in {@link ExtensionContext.Store}. */
+ private static final Object CGEN_KEY = new Object();
+
+ /** {@inheritDoc} */
+ @Override public void beforeEach(ExtensionContext context) throws Exception {
+ ConfigurationAsmGenerator cgen = new ConfigurationAsmGenerator();
+
+ context.getStore(namespace).put(CGEN_KEY, cgen);
+
+ Object testInstance = context.getRequiredTestInstance();
+
+ for (Field field : getMatchingFields(testInstance.getClass())) {
+ field.setAccessible(true);
+
+ field.set(testInstance, cfgValue(field.getType(), field.getAnnotation(InjectConfiguration.class), cgen));
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void afterEach(ExtensionContext context) throws Exception {
+ context.getStore(namespace).remove(CGEN_KEY);
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean supportsParameter(
+ ParameterContext parameterContext, ExtensionContext extensionContext
+ ) throws ParameterResolutionException {
+ return parameterContext.isAnnotated(InjectConfiguration.class)
+ && supportType(parameterContext.getParameter().getType());
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object resolveParameter(
+ ParameterContext parameterContext, ExtensionContext extensionContext
+ ) throws ParameterResolutionException {
+ Parameter parameter = parameterContext.getParameter();
+
+ ConfigurationAsmGenerator cgen =
+ extensionContext.getStore(namespace).get(CGEN_KEY, ConfigurationAsmGenerator.class);
+
+ try {
+ return cfgValue(parameter.getType(), parameter.getAnnotation(InjectConfiguration.class), cgen);
+ }
+ catch (ClassNotFoundException classNotFoundException) {
+ throw new ParameterResolutionException(
+ "Cannot find a configuration schema class that matches " + parameter.getType().getCanonicalName(),
+ classNotFoundException
+ );
+ }
+ }
+
+ /**
+ * Instantiates a configuration instance for injection.
+ *
+ * @param type Type of the field or parameter. Class name must end with {@code Configuration}.
+ * @param annotation Annotation present on the field or parameter.
+ * @param cgen Runtime code generator associated with the extension instance.
+ * @return Mock configuration instance.
+ * @throws ClassNotFoundException If corresponding configuration schema class is not found.
+ * @see #supportType(Class)
+ */
+ private static Object cfgValue(
+ Class<?> type,
+ InjectConfiguration annotation,
+ ConfigurationAsmGenerator cgen
+ ) throws ClassNotFoundException {
+ // Trying to find a schema class using configuration naming convention. This code won't work for inner Java
+ // classes, extension is designed to mock actual configurations from public API to configure Ignite components.
+ Class<?> schemaClass = Class.forName(type.getCanonicalName() + "Schema");
+
+ // Internal configuration extensions are not yet supported. This will probably be changed in the future.
+ cgen.compileRootSchema(schemaClass, Map.of());
+
+ // RootKey must be mocked, there's no way to instantiate it using a public constructor.
+ RootKey rootKey = mock(RootKey.class);
+
+ when(rootKey.key()).thenReturn("mock");
+ when(rootKey.type()).thenReturn(LOCAL);
+ when(rootKey.schemaClass()).thenReturn(schemaClass);
+ when(rootKey.internal()).thenReturn(false);
+
+ SuperRoot superRoot = new SuperRoot(s -> new RootInnerNode(rootKey, cgen.instantiateNode(schemaClass)));
+
+ ConfigObject hoconCfg = ConfigFactory.parseString(annotation.value()).root();
+
+ HoconConverter.hoconSource(hoconCfg).descend(superRoot);
+
+ ConfigurationUtil.addDefaults(superRoot);
+
+ // Reference to the super root is required to make DynamicConfigurationChanger#change method atomic.
+ var superRootRef = new AtomicReference<>(superRoot);
+
+ return cgen.instantiateCfg(rootKey, new DynamicConfigurationChanger() {
+ /** {@inheritDoc} */
+ @Override public CompletableFuture<Void> change(ConfigurationSource change) {
+ while (true) {
+ SuperRoot sr = superRootRef.get();
+
+ SuperRoot copy = sr.copy();
+
+ change.descend(copy);
+
+ if (superRootRef.compareAndSet(sr, copy))
+ return completedFuture(null);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public InnerNode getRootNode(RootKey<?, ?> rk) {
+ return superRootRef.get().getRoot(rk);
+ }
+ });
+ }
+
+ /**
+ * Looks for the annotated field inside the given test class.
+ *
+ * @return Annotated fields.
+ */
+ private static List<Field> getMatchingFields(Class<?> testClass) {
+ return AnnotationSupport.findAnnotatedFields(
+ testClass,
+ InjectConfiguration.class,
+ field -> supportType(field.getType()),
+ HierarchyTraversalMode.TOP_DOWN
+ );
+ }
+
+ /**
+ * Checks that instance of the given class can be injected by the extension.
+ *
+ * @param type Field or parameter type.
+ * @return {@code true} if value of the given class can be injected.
+ */
+ private static boolean supportType(Class<?> type) {
+ return type.getCanonicalName().endsWith("Configuration");
+ }
+}
diff --git a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/testframework/ConfigurationExtensionTest.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/testframework/ConfigurationExtensionTest.java
new file mode 100644
index 0000000..922b6f8
--- /dev/null
+++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/testframework/ConfigurationExtensionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.configuration.testframework;
+
+import java.util.concurrent.ExecutionException;
+import org.apache.ignite.internal.configuration.sample.DiscoveryConfiguration;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Test basic scenarios of {@link ConfigurationExtension}.
+ */
+@ExtendWith(ConfigurationExtension.class)
+class ConfigurationExtensionTest {
+ /** Injected field. */
+ @InjectConfiguration
+ private DiscoveryConfiguration fieldCfg;
+
+ /** Test that contains injected parameter. */
+ @Test
+ public void injectConfiguration(
+ @InjectConfiguration("mock.joinTimeout=100") DiscoveryConfiguration paramCfg
+ ) throws ExecutionException, InterruptedException {
+ assertEquals(5000, fieldCfg.joinTimeout().value());
+
+ assertEquals(100, paramCfg.joinTimeout().value());
+
+ paramCfg.change(d -> d.changeJoinTimeout(200));
+
+ assertEquals(200, paramCfg.joinTimeout().value());
+
+ paramCfg.joinTimeout().update(300);
+
+ assertEquals(300, paramCfg.joinTimeout().value());
+ }
+}
diff --git a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/testframework/InjectConfiguration.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/testframework/InjectConfiguration.java
new file mode 100644
index 0000000..d339d1e
--- /dev/null
+++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/testframework/InjectConfiguration.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.ignite.internal.configuration.testframework;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.apache.ignite.internal.configuration.ConfigurationChanger;
+import org.apache.ignite.internal.configuration.ConfigurationRegistry;
+
+/**
+ * Annotation for injecting configuration instances into tests.
+ * <p/>
+ * This annotation should be used on either fields or method parameters of the {@code *Configuration} type.
+ * <p/>
+ * Injected instance is initialized with values passed in {@link #value()}, with schema defaults where explicit initial
+ * values are not found.
+ * <p/>
+ * Although configuration instance is mutable, there's no {@link ConfigurationRegistry} and {@link ConfigurationChanger}
+ * underneath. Listeners don't work either, be aware of that. Main point of the extension is to provide mocks.
+ *
+ * @see ConfigurationExtension
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+public @interface InjectConfiguration {
+ /**
+ * Configuration values to initialize the instance. Has HOCON syntax. Must have a root value {@code mock}.
+ * <p/>
+ * Examples:
+ * <ul>
+ * <li>{@code mock.timeout=1000}</li>
+ * <li>{@code mock{cfg1=50, cfg2=90}}</li>
+ * </ul>
+ * <p/>
+ * Uses only default values by default.
+ *
+ * @return Initial configuration values in HOCON format.
+ */
+ String value() default "mock : {}";
+}
diff --git a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/util/ConfigurationUtilTest.java b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/util/ConfigurationUtilTest.java
index 0f61d65..9df981b 100644
--- a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/util/ConfigurationUtilTest.java
+++ b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/util/ConfigurationUtilTest.java
@@ -36,7 +36,6 @@
import org.apache.ignite.internal.configuration.SuperRoot;
import org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator;
import org.apache.ignite.internal.configuration.storage.TestConfigurationStorage;
-import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
import org.apache.ignite.internal.configuration.tree.ConverterToMapVisitor;
import org.apache.ignite.internal.configuration.tree.InnerNode;
import org.apache.ignite.internal.configuration.tree.TraversableTreeNode;
@@ -52,6 +51,7 @@
import static org.apache.ignite.internal.configuration.tree.NamedListNode.NAME;
import static org.apache.ignite.internal.configuration.tree.NamedListNode.ORDER_IDX;
import static org.apache.ignite.internal.configuration.util.ConfigurationFlattener.createFlattenedUpdatesMap;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.EMPTY_CFG_SRC;
import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.addDefaults;
import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.checkConfigurationType;
import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.collectSchemas;
@@ -642,7 +642,7 @@
SuperRoot originalSuperRoot = superRoot.copy();
// Make a copy of the root insode of the superRoot. This copy will be used for further patching.
- superRoot.construct(ParentConfiguration.KEY.key(), new ConfigurationSource() {}, true);
+ superRoot.construct(ParentConfiguration.KEY.key(), EMPTY_CFG_SRC, true);
// Patch root node.
patch.accept((ParentChange)superRoot.getRoot(ParentConfiguration.KEY));