blob: 5b5819df0ddbd44a8208b9d78d6cc0e9872e6eac [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.juneau.config;
import static org.junit.Assert.*;
import org.apache.juneau.config.event.*;
import org.apache.juneau.config.store.*;
import org.apache.juneau.internal.*;
import org.junit.*;
/**
* Validates aspects of config imports.
*/
public class ConfigImportsTest {
//-----------------------------------------------------------------------------------------------------------------
// Value inheritance
//-----------------------------------------------------------------------------------------------------------------
@Test
public void oneSimpleImport() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1");
ms.write("B", "", "<A>");
Config c = Config
.create("B")
.store(ms)
.build();
assertEquals("1", c.getString("x"));
c.set("x", "2");
c.commit();
assertEquals("x=1", ms.read("A"));
assertEquals("x = 2\n", ms.read("B"));
}
@Test
public void twoSimpleImports() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A1", "", "x=1");
ms.write("A2", "", "y=2");
ms.write("B", "", "<A1>\n<A2>");
Config c = Config.create("B").store(ms).build();
assertEquals("1", c.getString("x"));
assertEquals("2", c.getString("y"));
c.set("x", "3");
c.set("y", "4");
c.commit();
assertEquals("x=1", ms.read("A1"));
assertEquals("y=2", ms.read("A2"));
assertEquals("x = 3\ny = 4\n", ms.read("B"));
}
@Test
public void nestedImports() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A1", "", "x=1");
ms.write("A2", "", "<A1>\ny=2");
ms.write("B", "", "<A2>");
Config c = Config.create("B").store(ms).build();
assertEquals("1", c.getString("x"));
assertEquals("2", c.getString("y"));
c.set("x", "3");
c.set("y", "4");
c.commit();
assertEquals("x=1", ms.read("A1"));
assertEquals("<A1>\ny=2", ms.read("A2"));
assertEquals("x = 3\ny = 4\n", ms.read("B"));
}
@Test
public void nestedImportsLoop() throws Exception {
// This shouldn't blow up.
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A1", "", "<A2>\nx=1");
ms.write("A2", "", "<A1>\ny=2");
ms.write("B", "", "<A2>");
try {
Config.create("B").store(ms).build();
fail("Exception expected.");
} catch (Exception e) {
// OK
}
}
@Test
public void importNotFound() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("B", "", "<A>\nx=1");
Config c = Config.create("B").store(ms).build();
assertEquals("1", c.getString("x"));
}
@Test
public void noOverwriteOnImports() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1");
ms.write("B", "", "<A>");
Config c = Config.create("B").store(ms).build();
assertEquals("1", c.getString("x"));
c.set("x", "2");
assertEquals("2", c.getString("x"));
assertEquals("1", Config.create("A").store(ms).build().getString("x"));
}
@Test
public void overlappingSections() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1\n[A]\na1=1");
ms.write("B", "", "<A>\n[A]\na2=2");
Config c = Config.create("B").store(ms).build();
assertEquals("1", c.getString("A/a1"));
assertEquals("2", c.getString("A/a2"));
}
@Test
public void overlappingSectionsImportAtEnd() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1\n[A]\na1=1");
ms.write("B", "", "[A]\na2=2\n<A>");
Config c = Config.create("B").store(ms).build();
assertEquals("1", c.getString("A/a1"));
assertEquals("2", c.getString("A/a2"));
}
@Test
public void overlappingSectionsAndValues() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1\n[A]\na1=1");
ms.write("B", "", "<A>\n[A]\na1=2");
Config c = Config.create("B").store(ms).build();
assertEquals("2", c.getString("A/a1"));
}
//-----------------------------------------------------------------------------------------------------------------
// Listeners
//-----------------------------------------------------------------------------------------------------------------
public static class TestListener implements ConfigEventListener {
private boolean triggered;
private ConfigEvents events;
@Override
public void onConfigChange(ConfigEvents events) {
this.triggered = true;
this.events = events;
}
public TestListener reset() {
triggered = false;
events = null;
return this;
}
public boolean isTriggered() {
return triggered;
}
public ConfigEvents getEvents() {
return events;
}
public String getNewValue(String section, String key) {
if (events.size() == 0)
return null;
for (ConfigEvent ce : events)
if (StringUtils.isEquals(section, ce.getSection()) && StringUtils.isEquals(key, ce.getKey()))
return ce.getValue();
return null;
}
}
@Test
public void testUpdateOnParent() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1\n[A]\na1=1");
ms.write("B", "", "<A>\n[B]\nb1=2");
Config ca = Config.create("A").store(ms).build();
Config cb = Config.create("B").store(ms).build();
assertEquals(2, ca.getConfigMap().getListeners().size());
assertEquals(1, cb.getConfigMap().getListeners().size());
TestListener l = new TestListener();
cb.addListener(l);
assertEquals(0, ca.getListeners().size());
assertEquals(1, cb.getListeners().size());
ms.write("A", "x=1\n[A]\na1=1", "x=1\n[A]\na1=2");
assertTrue(l.isTriggered());
assertEquals(1, l.getEvents().size());
assertEquals("2", l.getNewValue("A", "a1"));
assertEquals("2", cb.get("A/a1"));
assertEquals("2", cb.get("B/b1"));
l.reset();
cb.removeListener(l);
assertEquals(0, ca.getListeners().size());
assertEquals(0, cb.getListeners().size());
ms.write("A", "x=1\n[A]\na1=2", "x=1\n[A]\na1=3");
assertFalse(l.isTriggered());
assertEquals("3", cb.get("A/a1"));
assertEquals("2", cb.get("B/b1"));
}
@Test
public void testUpdateOnGrandParent() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1\n[A]\na1=1");
ms.write("B", "", "<A>\n[B]\nb1=2");
ms.write("C", "", "<B>\n[C]\nc1=3");
Config ca = Config.create("A").store(ms).build();
Config cb = Config.create("B").store(ms).build();
Config cc = Config.create("C").store(ms).build();
assertEquals(3, ca.getConfigMap().getListeners().size());
assertEquals(2, cb.getConfigMap().getListeners().size());
assertEquals(1, cc.getConfigMap().getListeners().size());
TestListener l = new TestListener();
cc.addListener(l);
assertEquals(0, ca.getListeners().size());
assertEquals(0, cb.getListeners().size());
assertEquals(1, cc.getListeners().size());
ms.write("A", "x=1\n[A]\na1=1", "x=1\n[A]\na1=2");
assertTrue(l.isTriggered());
assertEquals(1, l.getEvents().size());
assertEquals("2", l.getNewValue("A", "a1"));
assertEquals("2", cc.get("A/a1"));
assertEquals("2", cc.get("B/b1"));
assertEquals("3", cc.get("C/c1"));
l.reset();
cc.removeListener(l);
assertEquals(0, ca.getListeners().size());
assertEquals(0, cb.getListeners().size());
assertEquals(0, cc.getListeners().size());
ms.write("A", "x=1\n[A]\na1=2", "x=1\n[A]\na1=3");
assertFalse(l.isTriggered());
assertEquals("3", cc.get("A/a1"));
assertEquals("2", cc.get("B/b1"));
assertEquals("3", cc.get("C/c1"));
}
@Test
public void testUpdateOnParentSameSection() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1\n[A]\na1=1");
ms.write("B", "", "<A>\n[A]\nb1=2");
Config ca = Config.create("A").store(ms).build();
Config cb = Config.create("B").store(ms).build();
assertEquals(2, ca.getConfigMap().getListeners().size());
assertEquals(1, cb.getConfigMap().getListeners().size());
TestListener l = new TestListener();
cb.addListener(l);
ms.write("A", "x=1\n[A]\na1=1", "x=1\n[A]\na1=2");
assertTrue(l.isTriggered());
assertEquals(1, l.getEvents().size());
assertEquals("2", l.getNewValue("A", "a1"));
assertEquals("2", cb.get("A/a1"));
assertEquals("2", cb.get("A/b1"));
l.reset();
cb.removeListener(l);
assertEquals(0, ca.getListeners().size());
assertEquals(0, cb.getListeners().size());
ms.write("A", "x=1\n[A]\na1=2", "x=1\n[A]\na1=3");
assertFalse(l.isTriggered());
assertEquals("3", cb.get("A/a1"));
assertEquals("2", cb.get("A/b1"));
}
@Test
public void testUpdateOnParentSameSectionSameKey() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1\n[A]\na1=1");
ms.write("B", "", "<A>\n[A]\na1=2");
Config ca = Config.create("A").store(ms).build();
Config cb = Config.create("B").store(ms).build();
assertEquals(2, ca.getConfigMap().getListeners().size());
assertEquals(1, cb.getConfigMap().getListeners().size());
TestListener l = new TestListener();
cb.addListener(l);
ms.write("A", "x=1\n[A]\na1=1", "x=1\n[A]\na1=3");
assertFalse(l.isTriggered());
assertEquals("2", cb.get("A/a1"));
}
@Test
public void testUpdateOnGrandParentSameSection() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1\n[A]\na1=1");
ms.write("B", "", "<A>\n[A]\na1=2");
ms.write("C", "", "<B>\n[A]\na1=3");
Config ca = Config.create("A").store(ms).build();
Config cb = Config.create("B").store(ms).build();
Config cc = Config.create("C").store(ms).build();
assertEquals(3, ca.getConfigMap().getListeners().size());
assertEquals(2, cb.getConfigMap().getListeners().size());
assertEquals(1, cc.getConfigMap().getListeners().size());
TestListener l = new TestListener();
cc.addListener(l);
ms.write("A", "x=1\n[A]\na1=1", "x=1\n[A]\na1=4");
assertFalse(l.isTriggered());
assertEquals("3", cc.get("A/a1"));
}
//-----------------------------------------------------------------------------------------------------------------
// Listeners and dynamically modifying imports
//-----------------------------------------------------------------------------------------------------------------
@Test
public void testUpdateOnParentDynamic() throws Exception {
ConfigMemoryStore ms = ConfigMemoryStore.create().build();
ms.write("A", "", "x=1\ny=1\n[A]\na1=1");
ms.write("B", "", "x=2\n[B]\nb1=2");
Config ca = Config.create("A").store(ms).build();
Config cb = Config.create("B").store(ms).build();
assertEquals(1, ca.getConfigMap().getListeners().size());
assertEquals(1, cb.getConfigMap().getListeners().size());
TestListener l = new TestListener();
cb.addListener(l);
assertEquals(0, ca.getListeners().size());
assertEquals(1, cb.getListeners().size());
ms.write("B", "x=2\n[B]\nb1=2", "x=2\n<A>\n[B]\nb1=2");
assertTrue(l.isTriggered());
assertEquals(2, l.getEvents().size()); // Should contain [SET(y = 1), SET(A/a1 = 1)]
assertEquals("1", l.getNewValue("A", "a1"));
assertEquals("1", cb.get("A/a1"));
assertEquals("2", cb.get("B/b1"));
assertEquals(2, ca.getConfigMap().getListeners().size());
assertEquals(1, cb.getConfigMap().getListeners().size());
l.reset();
ms.write("B", "x=2\n<A>\n[B]\nb1=2", "x=2\n[B]\nb1=2");
assertTrue(l.isTriggered());
assertEquals(2, l.getEvents().size()); // Should contain [REMOVE_ENTRY(y), REMOVE_ENTRY(A/a1)]
assertEquals(null, l.getNewValue("A", "a1"));
assertNull(cb.get("A/a1"));
assertEquals("2", cb.get("B/b1"));
l.reset();
cb.removeListener(l);
assertEquals(0, ca.getListeners().size());
assertEquals(0, cb.getListeners().size());
ms.write("B", "x=2\n[B]\nb1=2", "x=2\n<A>\n[B]\nb1=2");
assertFalse(l.isTriggered());
assertEquals("1", cb.get("A/a1"));
assertEquals("2", cb.get("B/b1"));
}
}