blob: 7af2979b574fbf812fd4f0c8298acb297c2ee128 [file] [log] [blame]
/*
* 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.notifications;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.ignite.configuration.annotation.ConfigurationType.LOCAL;
import static org.apache.ignite.internal.configuration.notifications.ConfigurationListenerTestUtils.checkContainsListeners;
import static org.apache.ignite.internal.configuration.notifications.ConfigurationListenerTestUtils.checkEqualsListeners;
import static org.apache.ignite.internal.configuration.notifications.ConfigurationListenerTestUtils.configListener;
import static org.apache.ignite.internal.configuration.notifications.ConfigurationListenerTestUtils.configNamedListenerOnCreate;
import static org.apache.ignite.internal.configuration.notifications.ConfigurationListenerTestUtils.configNamedListenerOnDelete;
import static org.apache.ignite.internal.configuration.notifications.ConfigurationListenerTestUtils.configNamedListenerOnRename;
import static org.apache.ignite.internal.configuration.notifications.ConfigurationListenerTestUtils.configNamedListenerOnUpdate;
import static org.apache.ignite.internal.configuration.notifications.ConfigurationListenerTestUtils.doNothingConsumer;
import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import org.apache.ignite.configuration.ConfigurationListenOnlyException;
import org.apache.ignite.configuration.NamedConfigurationTree;
import org.apache.ignite.configuration.annotation.Config;
import org.apache.ignite.configuration.annotation.ConfigValue;
import org.apache.ignite.configuration.annotation.ConfigurationRoot;
import org.apache.ignite.configuration.annotation.NamedConfigValue;
import org.apache.ignite.configuration.annotation.PolymorphicConfig;
import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
import org.apache.ignite.configuration.annotation.PolymorphicId;
import org.apache.ignite.configuration.annotation.Value;
import org.apache.ignite.configuration.notifications.ConfigurationListener;
import org.apache.ignite.configuration.notifications.ConfigurationNamedListListener;
import org.apache.ignite.configuration.notifications.ConfigurationNotificationEvent;
import org.apache.ignite.internal.configuration.ConfigurationRegistry;
import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator;
import org.apache.ignite.internal.configuration.storage.TestConfigurationStorage;
import org.apache.ignite.internal.configuration.validation.TestConfigurationValidator;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
* Class for testing notification of listeners for a {@link NamedConfigurationTree#any}.
*/
public class ConfigurationAnyListenerTest {
/**
* Root configuration schema.
*/
@ConfigurationRoot(rootName = "root", type = LOCAL)
public static class RootConfigurationSchema {
/** Nested child configuration. */
@ConfigValue
public FirstSubConfigurationSchema child;
/** Nested named child configuration. */
@NamedConfigValue
public FirstSubConfigurationSchema elements;
@NamedConfigValue
public PolyAnyConfigurationSchema polyNamed;
}
/**
* First sub-configuration schema.
*/
@Config
public static class FirstSubConfigurationSchema {
/** String value. */
@Value(hasDefault = true)
public String str = "default";
/** Nested child configuration. */
@ConfigValue
public SecondSubConfigurationSchema child2;
/** Nested named child configuration. */
@NamedConfigValue
public SecondSubConfigurationSchema elements2;
}
/**
* Second sub-configuration schema.
*/
@Config
public static class SecondSubConfigurationSchema {
/** Integer value. */
@Value(hasDefault = true)
public int intVal = 10;
}
/**
* Polymorphic configuration schema.
*/
@PolymorphicConfig
public static class PolyAnyConfigurationSchema {
@PolymorphicId
public String type;
@Value
public int intVal;
}
/**
* First extension of {@link PolyAnyConfigurationSchema}.
*/
@PolymorphicConfigInstance("first")
public static class FirstPolyAnyConfigurationSchema extends PolyAnyConfigurationSchema {
@Value
public String strVal;
}
/**
* Second extension of {@link PolyAnyConfigurationSchema}.
*/
@PolymorphicConfigInstance("second")
public static class SecondPolyAnyConfigurationSchema extends PolyAnyConfigurationSchema {
@Value
public String strVal;
}
/** Configuration generator. */
private ConfigurationTreeGenerator generator;
/** Configuration registry. */
private ConfigurationRegistry registry;
/** Root configuration. */
private RootConfiguration rootConfig;
/** Notification events. */
private final List<String> events = new CopyOnWriteArrayList<>();
/**
* Before each.
*/
@BeforeEach
public void before() throws Exception {
generator = new ConfigurationTreeGenerator(
List.of(RootConfiguration.KEY),
List.of(),
List.of(FirstPolyAnyConfigurationSchema.class, SecondPolyAnyConfigurationSchema.class)
);
registry = new ConfigurationRegistry(
List.of(RootConfiguration.KEY),
new TestConfigurationStorage(LOCAL),
generator,
new TestConfigurationValidator()
);
assertThat(registry.startAsync(), willCompleteSuccessfully());
rootConfig = registry.getConfiguration(RootConfiguration.KEY);
// Add "regular" listeners.
rootConfig.listen(configListener(ctx -> events.add("root")));
rootConfig.child().listen(configListener(ctx -> events.add("root.child")));
rootConfig.child().str().listen(configListener(ctx -> events.add("root.child.str")));
rootConfig.child().child2().listen(configListener(ctx -> events.add("root.child.child2")));
rootConfig.child().child2().intVal().listen(configListener(ctx -> events.add("root.child.child2.i")));
rootConfig.elements().listen(configListener(ctx -> events.add("root.elements")));
rootConfig.elements().listenElements(configNamedListenerOnCreate(ctx -> events.add("root.elements.onCrt")));
rootConfig.elements().listenElements(configNamedListenerOnUpdate(ctx -> events.add("root.elements.onUpd")));
rootConfig.elements().listenElements(configNamedListenerOnRename(ctx -> events.add("root.elements.onRen")));
rootConfig.elements().listenElements(configNamedListenerOnDelete(ctx -> events.add("root.elements.onDel")));
rootConfig.elements().change(c -> c.create("0", doNothingConsumer())).get(1, SECONDS);
FirstSubConfiguration childCfg = this.rootConfig.elements().get("0");
childCfg.listen(configListener(ctx -> events.add("root.elements.0")));
childCfg.str().listen(configListener(ctx -> events.add("root.elements.0.str")));
childCfg.child2().listen(configListener(ctx -> events.add("root.elements.0.child2")));
childCfg.child2().intVal().listen(configListener(ctx -> events.add("root.elements.0.child2.i")));
NamedConfigurationTree<SecondSubConfiguration, SecondSubView, SecondSubChange> elements2 = childCfg.elements2();
elements2.listen(configListener(ctx -> events.add("root.elements.0.elements2")));
elements2.listenElements(configNamedListenerOnCreate(ctx -> events.add("root.elements.0.elements2.onCrt")));
elements2.listenElements(configNamedListenerOnUpdate(ctx -> events.add("root.elements.0.elements2.onUpd")));
elements2.listenElements(configNamedListenerOnRename(ctx -> events.add("root.elements.0.elements2.onRen")));
elements2.listenElements(configNamedListenerOnDelete(ctx -> events.add("root.elements.0.elements2.onDel")));
elements2.change(c -> c.create("0", doNothingConsumer())).get(1, SECONDS);
SecondSubConfiguration child2 = elements2.get("0");
child2.listen(configListener(ctx -> events.add("root.elements.0.elements2.0")));
child2.intVal().listen(configListener(ctx -> events.add("root.elements.0.elements2.0.i")));
// Adding "any" listeners.
FirstSubConfiguration anyChild = rootConfig.elements().any();
anyChild.listen(configListener(ctx -> events.add("root.elements.any")));
anyChild.str().listen(configListener(ctx -> events.add("root.elements.any.str")));
anyChild.child2().listen(configListener(ctx -> events.add("root.elements.any.child2")));
anyChild.child2().intVal().listen(configListener(ctx -> events.add("root.elements.any.child2.i")));
NamedConfigurationTree<SecondSubConfiguration, SecondSubView, SecondSubChange> anyEl2 = anyChild.elements2();
anyEl2.listen(configListener(ctx -> events.add("root.elements.any.elements2")));
anyEl2.listenElements(configNamedListenerOnCreate(ctx -> events.add("root.elements.any.elements2.onCrt")));
anyEl2.listenElements(configNamedListenerOnUpdate(ctx -> events.add("root.elements.any.elements2.onUpd")));
anyEl2.listenElements(configNamedListenerOnRename(ctx -> events.add("root.elements.any.elements2.onRen")));
anyEl2.listenElements(configNamedListenerOnDelete(ctx -> events.add("root.elements.any.elements2.onDel")));
SecondSubConfiguration anyChild2 = anyEl2.any();
anyChild2.listen(configListener(ctx -> events.add("root.elements.any.elements2.any")));
anyChild2.intVal().listen(configListener(ctx -> events.add("root.elements.any.elements2.any.i")));
childCfg.elements2().any().listen(configListener(ctx -> events.add("root.elements.0.elements2.any")));
childCfg.elements2().any().intVal().listen(configListener(ctx -> events.add("root.elements.0.elements2.any.i")));
}
@AfterEach
public void after() {
assertThat(registry.stopAsync(), willCompleteSuccessfully());
generator.close();
}
@Test
void testNoGetOrUpdateConfigValueForAny() throws Exception {
FirstSubConfiguration any0 = rootConfig.elements().any();
assertThrows(ConfigurationListenOnlyException.class, () -> any0.value());
assertThrows(ConfigurationListenOnlyException.class, () -> any0.change(doNothingConsumer()));
assertThrows(ConfigurationListenOnlyException.class, () -> any0.str().value());
assertThrows(ConfigurationListenOnlyException.class, () -> any0.str().update(""));
assertThrows(ConfigurationListenOnlyException.class, () -> any0.child2().value());
assertThrows(ConfigurationListenOnlyException.class, () -> any0.child2().change(doNothingConsumer()));
assertThrows(ConfigurationListenOnlyException.class, () -> any0.child2().intVal().value());
assertThrows(ConfigurationListenOnlyException.class, () -> any0.child2().intVal().update(100));
assertThrows(ConfigurationListenOnlyException.class, () -> any0.elements2().value());
assertThrows(ConfigurationListenOnlyException.class, () -> any0.elements2().change(doNothingConsumer()));
assertThrows(ConfigurationListenOnlyException.class, () -> any0.elements2().get("test"));
SecondSubConfiguration any1 = any0.elements2().any();
assertThrows(ConfigurationListenOnlyException.class, () -> any1.value());
assertThrows(ConfigurationListenOnlyException.class, () -> any1.change(doNothingConsumer()));
assertThrows(ConfigurationListenOnlyException.class, () -> any1.intVal().value());
assertThrows(ConfigurationListenOnlyException.class, () -> any1.intVal().update(200));
rootConfig.elements().change(c0 -> c0.create("test", c1 -> c1.changeStr("foo"))).get(1, SECONDS);
SecondSubConfiguration any2 = rootConfig.elements().get("test").elements2().any();
assertThrows(ConfigurationListenOnlyException.class, () -> any2.value());
assertThrows(ConfigurationListenOnlyException.class, () -> any2.change(doNothingConsumer()));
assertThrows(ConfigurationListenOnlyException.class, () -> any2.intVal().value());
assertThrows(ConfigurationListenOnlyException.class, () -> any2.intVal().update(300));
}
@Test
void testNoAnyListenerNotification() throws Exception {
checkEqualsListeners(
() -> rootConfig.child().change(c -> c.changeStr("x").changeChild2(c0 -> c0.changeIntVal(100))),
List.of(
"root",
"root.child",
"root.child.str",
"root.child.child2",
"root.child.child2.i"
),
events
);
}
@Test
void testAnyListenerNotificationOnCreate() throws Exception {
checkEqualsListeners(
() -> rootConfig.elements()
.change(c -> c.create("1", c0 -> c0.changeElements2(c1 -> c1.create("2", doNothingConsumer())))),
List.of(
"root",
"root.elements",
"root.elements.onCrt",
//
"root.elements.any",
"root.elements.any.str",
//
"root.elements.any.child2",
"root.elements.any.child2.i",
//
"root.elements.any.elements2",
"root.elements.any.elements2.onCrt",
"root.elements.any.elements2.any",
"root.elements.any.elements2.any.i"
),
events
);
checkEqualsListeners(
() -> rootConfig.elements().get("0").elements2().change(c -> c.create("1", doNothingConsumer())),
List.of(
"root",
"root.elements",
"root.elements.onUpd",
//
"root.elements.any",
"root.elements.0",
//
"root.elements.any.elements2",
"root.elements.0.elements2",
"root.elements.any.elements2.onCrt",
"root.elements.0.elements2.onCrt",
//
"root.elements.any.elements2.any",
"root.elements.0.elements2.any",
"root.elements.any.elements2.any.i",
"root.elements.0.elements2.any.i"
),
events
);
checkEqualsListeners(
() -> rootConfig.elements().get("1").elements2().change(c -> c.create("3", doNothingConsumer())),
List.of(
"root",
"root.elements",
"root.elements.onUpd",
//
"root.elements.any",
"root.elements.any.elements2",
"root.elements.any.elements2.onCrt",
//
"root.elements.any.elements2.any",
"root.elements.any.elements2.any.i"
),
events
);
}
@Test
void testAnyListenerNotificationOnRename() throws Exception {
checkEqualsListeners(
() -> rootConfig.elements().get("0").elements2().change(c -> c.rename("0", "0x")),
List.of(
"root",
"root.elements",
"root.elements.onUpd",
//
"root.elements.any",
"root.elements.0",
//
"root.elements.any.elements2",
"root.elements.0.elements2",
//
"root.elements.any.elements2.onRen",
"root.elements.0.elements2.onRen"
),
events
);
rootConfig.elements()
.change(c -> c.create("1", c0 -> c0.changeElements2(c1 -> c1.create("2", doNothingConsumer()))))
.get(1, SECONDS);
checkEqualsListeners(
() -> rootConfig.elements().get("1").elements2().change(c -> c.rename("2", "2x")),
List.of(
"root",
"root.elements",
"root.elements.onUpd",
//
"root.elements.any",
"root.elements.any.elements2",
"root.elements.any.elements2.onRen"
),
events
);
}
@Test
void testAnyListenerNotificationOnDelete() throws Exception {
checkEqualsListeners(
() -> rootConfig.elements().get("0").elements2().change(c -> c.delete("0")),
List.of(
"root",
"root.elements",
"root.elements.onUpd",
//
"root.elements.any",
"root.elements.0",
//
"root.elements.any.elements2",
"root.elements.0.elements2",
//
"root.elements.any.elements2.onDel",
"root.elements.0.elements2.onDel",
//
"root.elements.any.elements2.any",
"root.elements.0.elements2.0"
),
events
);
rootConfig.elements()
.change(c -> c.create("1", c0 -> c0.changeElements2(c1 -> c1.create("2", doNothingConsumer()))))
.get(1, SECONDS);
checkEqualsListeners(
() -> rootConfig.elements().get("1").elements2().change(c -> c.delete("2")),
List.of(
"root",
"root.elements",
"root.elements.onUpd",
//
"root.elements.any",
"root.elements.any.elements2",
"root.elements.any.elements2.onDel",
"root.elements.any.elements2.any"
),
events
);
}
@Test
void testAnyListenerNotificationForLeaf() throws Exception {
checkEqualsListeners(
() -> rootConfig.elements().get("0").str().update("x"),
List.of(
"root",
"root.elements",
"root.elements.onUpd",
//
"root.elements.any",
"root.elements.0",
//
"root.elements.any.str",
"root.elements.0.str"
),
events
);
checkEqualsListeners(
() -> rootConfig.elements().get("0").elements2().get("0").intVal().update(200),
List.of(
"root",
"root.elements",
"root.elements.onUpd",
//
"root.elements.any",
"root.elements.0",
//
"root.elements.any.elements2",
"root.elements.0.elements2",
"root.elements.any.elements2.onUpd",
"root.elements.0.elements2.onUpd",
//
"root.elements.any.elements2.any",
"root.elements.0.elements2.any",
"root.elements.0.elements2.0",
//
"root.elements.any.elements2.any.i",
"root.elements.0.elements2.any.i",
"root.elements.0.elements2.0.i"
),
events
);
rootConfig.elements()
.change(c -> c.create("1", c0 -> c0.changeElements2(c1 -> c1.create("2", doNothingConsumer()))))
.get(1, SECONDS);
checkEqualsListeners(
() -> rootConfig.elements().get("1").elements2().get("2").intVal().update(200),
List.of(
"root",
"root.elements",
"root.elements.onUpd",
//
"root.elements.any",
"root.elements.any.elements2",
"root.elements.any.elements2.onUpd",
"root.elements.any.elements2.any",
"root.elements.any.elements2.any.i"
),
events
);
}
@Test
void testAnyStopListen() throws Exception {
ConfigurationListener<FirstSubView> listener0 = configListener(ctx -> events.add("root.elements.any2"));
ConfigurationNamedListListener<SecondSubView> listener1 = configNamedListenerOnUpdate(
ctx -> events.add("root.elements.any2.elements2.onUpd")
);
rootConfig.elements().any().listen(listener0);
rootConfig.elements().any().elements2().listenElements(listener1);
checkContainsListeners(
() -> rootConfig.elements().get("0").elements2().get("0").intVal().update(Integer.MAX_VALUE),
events,
List.of(
"root.elements.any",
"root.elements.any2",
"root.elements.any2.elements2.onUpd"
),
List.of()
);
rootConfig.elements().any().stopListen(listener0);
rootConfig.elements().any().elements2().stopListenElements(listener1);
checkContainsListeners(
() -> rootConfig.elements().get("0").elements2().get("0").intVal().update(Integer.MIN_VALUE),
events,
List.of("root.elements.any"),
List.of("root.elements.any2", "root.elements.any2.elements2.onUpd")
);
}
@Test
void testAnyGetConfigFromNotificationEventOnCreate() throws Exception {
String key0 = UUID.randomUUID().toString();
String key1 = UUID.randomUUID().toString();
rootConfig.elements().any().listen(configListener(ctx -> {
assertNotNull(ctx.newValue(FirstSubView.class));
assertEquals(key0, ctx.newName(FirstSubView.class));
}));
rootConfig.elements().change(c -> c.create(key0, doNothingConsumer())).get(1, SECONDS);
Consumer<ConfigurationNotificationEvent<SecondSubView>> assertions = ctx -> {
assertNotNull(ctx.newValue(FirstSubView.class));
assertEquals(key0, ctx.newName(FirstSubView.class));
assertNotNull(ctx.newValue(SecondSubView.class));
assertEquals(key1, ctx.newName(SecondSubView.class));
};
rootConfig.elements().any().elements2().listenElements(configNamedListenerOnCreate(assertions));
rootConfig.elements().any().elements2().any().listen(configListener(assertions));
rootConfig.elements().get(key0).elements2().change(c -> c.create(key1, doNothingConsumer())).get(1, SECONDS);
}
@Test
void testAnyGetConfigFromNotificationEventOnRename() throws Exception {
String key0 = UUID.randomUUID().toString();
String oldKey1 = UUID.randomUUID().toString();
String newKey1 = UUID.randomUUID().toString();
rootConfig.elements().any().listen(configListener(ctx -> {
assertNotNull(ctx.newValue(FirstSubView.class));
assertEquals(key0, ctx.newName(FirstSubView.class));
}));
rootConfig.elements()
.change(c -> c.create(key0, c1 -> c1.changeElements2(c2 -> c2.create(oldKey1, doNothingConsumer()))))
.get(1, SECONDS);
Consumer<ConfigurationNotificationEvent<SecondSubView>> assertions = ctx -> {
assertNotNull(ctx.newValue(FirstSubView.class));
assertEquals(key0, ctx.newName(FirstSubView.class));
assertNotNull(ctx.newValue(SecondSubView.class));
assertEquals(oldKey1, ctx.oldName(SecondSubView.class));
assertEquals(newKey1, ctx.newName(SecondSubView.class));
};
rootConfig.elements().get(key0).elements2().listenElements(configNamedListenerOnRename(assertions));
rootConfig.elements().any().elements2().listenElements(configNamedListenerOnRename(assertions));
rootConfig.elements().get(key0).elements2().change(c -> c.rename(oldKey1, newKey1)).get(1, SECONDS);
}
@Test
void testAnyGetConfigFromNotificationEventOnDelete() throws Exception {
String key0 = UUID.randomUUID().toString();
String key1 = UUID.randomUUID().toString();
rootConfig.elements().any().listen(configListener(ctx -> {
assertNotNull(ctx.newValue(FirstSubView.class));
assertEquals(key0, ctx.newName(FirstSubView.class));
}));
rootConfig.elements()
.change(c -> c.create(key0, c1 -> c1.changeElements2(c2 -> c2.create(key1, doNothingConsumer()))))
.get(1, SECONDS);
Consumer<ConfigurationNotificationEvent<SecondSubView>> assertions = ctx -> {
assertNotNull(ctx.newValue(FirstSubView.class));
assertEquals(key0, ctx.newName(FirstSubView.class));
assertNotNull(ctx.oldValue(SecondSubView.class));
assertNull(ctx.newValue(SecondSubView.class));
assertEquals(key1, ctx.oldName(SecondSubView.class));
assertNull(ctx.newName(SecondSubView.class));
};
rootConfig.elements().any().elements2().listenElements(configNamedListenerOnDelete(assertions));
rootConfig.elements().get(key0).elements2().listenElements(configNamedListenerOnDelete(assertions));
rootConfig.elements().any().elements2().any().listen(configListener(assertions));
rootConfig.elements().get(key0).elements2().any().listen(configListener(assertions));
rootConfig.elements().get(key0).elements2().change(c -> c.delete(key1)).get(1, SECONDS);
}
@Test
void testAnyGetConfigFromNotificationEventOnUpdate() throws Exception {
String key0 = UUID.randomUUID().toString();
String key1 = UUID.randomUUID().toString();
int newVal = Integer.MAX_VALUE;
rootConfig.elements()
.change(c -> c.create(key0, c1 -> c1.changeElements2(c2 -> c2.create(key1, doNothingConsumer()))))
.get(1, SECONDS);
Consumer<ConfigurationNotificationEvent<SecondSubView>> assertions = ctx -> {
assertNotNull(ctx.newValue(FirstSubView.class));
assertEquals(key0, ctx.newName(FirstSubView.class));
SecondSubView second = ctx.newValue(SecondSubView.class);
assertNotNull(second);
assertEquals(key1, ctx.newName(SecondSubView.class));
assertEquals(newVal, second.intVal());
};
rootConfig.elements().any().elements2().listenElements(configNamedListenerOnUpdate(assertions));
rootConfig.elements().any().elements2().any().listen(configListener(assertions));
rootConfig.elements().get(key0).elements2().any().listen(configListener(assertions));
rootConfig.elements().get(key0).elements2().get(key1).intVal().update(newVal).get(1, SECONDS);
}
@Test
void testAnyCreateNamedPolymorphicConfig() throws Exception {
AtomicBoolean invokeListener = new AtomicBoolean();
rootConfig.polyNamed().any().listen(configListener(ctx -> {
invokeListener.set(true);
assertInstanceOf(FirstPolyAnyView.class, ctx.newValue());
assertInstanceOf(PolyAnyView.class, ctx.newValue());
assertNull(ctx.oldValue());
assertEquals("0", ctx.newName(PolyAnyView.class));
assertEquals("0", ctx.newName(FirstPolyAnyView.class));
assertNull(ctx.newName(SecondPolyAnyView.class));
assertInstanceOf(PolyAnyView.class, ctx.newValue(PolyAnyView.class));
assertInstanceOf(FirstPolyAnyView.class, ctx.newValue(FirstPolyAnyView.class));
assertNull(ctx.newValue(SecondPolyAnyView.class));
}));
rootConfig.polyNamed()
.change(c -> c.create("0", c1 -> c1.convert(FirstPolyAnyChange.class).changeStrVal("0").changeIntVal(0)))
.get(1, SECONDS);
assertTrue(invokeListener.get());
}
@Test
void testAnyUpdateNamedPolymorphicConfig() throws Exception {
rootConfig.polyNamed()
.change(c -> c.create("0", c1 -> c1.convert(FirstPolyAnyChange.class).changeStrVal("0").changeIntVal(0)))
.get(1, SECONDS);
AtomicBoolean invokeListener = new AtomicBoolean();
rootConfig.polyNamed().any().listen(configListener(ctx -> {
invokeListener.set(true);
assertInstanceOf(SecondPolyAnyView.class, ctx.newValue());
assertInstanceOf(PolyAnyView.class, ctx.newValue());
assertInstanceOf(FirstPolyAnyView.class, ctx.oldValue());
assertInstanceOf(PolyAnyView.class, ctx.oldValue());
assertEquals("0", ctx.newName(PolyAnyView.class));
assertEquals("0", ctx.newName(SecondPolyAnyView.class));
assertNull(ctx.newName(FirstPolyAnyView.class));
assertInstanceOf(PolyAnyView.class, ctx.newValue(PolyAnyView.class));
assertInstanceOf(SecondPolyAnyView.class, ctx.newValue(SecondPolyAnyView.class));
assertNull(ctx.newValue(FirstPolyAnyView.class));
}));
rootConfig.polyNamed()
.change(c -> c.update("0", c1 -> c1.convert(SecondPolyAnyChange.class).changeStrVal("0").changeIntVal(0)))
.get(1, SECONDS);
assertTrue(invokeListener.get());
}
}