package org.dcache.util; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; import org.junit.Before; import org.junit.Test; import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import static org.junit.Assert.*; public class ConfigurationPropertiesTests { private static final String NORMAL_PROPERTY_NAME = "normalProperty"; private static final String NORMAL_PROPERTY_VALUE = "some normal value"; private static final String SIMPLE_PROPERTY_NAME = "simple-key"; private static final String SIMPLE_PROPERTY_VALUE = "simple-value"; private static final String OBSOLETE_PROPERTY_NAME = "obsoleteProperty"; private static final String OBSOLETE_PROPERTY_KEY = "(obsolete)" + OBSOLETE_PROPERTY_NAME; private static final String OBSOLETE_PROPERTY_W_ERROR_NAME = "obsoletePropertyWithError"; private static final String OBSOLETE_PROPERTY_W_ERROR_VALUE = "an error message"; private static final String OBSOLETE_PROPERTY_W_ERROR_KEY = "(obsolete)" + OBSOLETE_PROPERTY_W_ERROR_NAME; private static final String FORBIDDEN_PROPERTY_NAME = "forbiddenProperty"; private static final String FORBIDDEN_PROPERTY_KEY = "(forbidden)" + FORBIDDEN_PROPERTY_NAME; private static final String FORBIDDEN_PROPERTY_W_ERROR_NAME = "forbiddenPropertyWithError"; private static final String FORBIDDEN_PROPERTY_W_ERROR_VALUE = "an error message"; private static final String FORBIDDEN_PROPERTY_W_ERROR_KEY = "(forbidden)" + FORBIDDEN_PROPERTY_W_ERROR_NAME; private static final String DEPRECATED_PROPERTY_NAME = "deprecatedProperty"; private static final String DEPRECATED_PROPERTY_VALUE = "some deprecated value"; private static final String DEPRECATED_PROPERTY_KEY = "(deprecated)" + DEPRECATED_PROPERTY_NAME; private static final String IMMUTABLE_PROPERTY_NAME = "immutableProperty"; private static final String IMMUTABLE_PROPERTY_VALUE = "some immutable value"; private static final String IMMUTABLE_PROPERTY_KEY = "(immutable)" + IMMUTABLE_PROPERTY_NAME; private static final String DEPRECATED_PROPERTY_W_FORWARD_SYNONYM_NAME = "deprecatedProperty.forward"; private static final String DEPRECATED_PROPERTY_W_FORWARD_SYNONYM_VALUE = "${" + SIMPLE_PROPERTY_NAME + "}"; private static final String DEPRECATED_PROPERTY_W_FORWARD_SYNONYM_KEY = "(deprecated)" + DEPRECATED_PROPERTY_W_FORWARD_SYNONYM_NAME; private static final String DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME = "deprecatedProperty.backward"; private static final String DEPRECATED_PROPERTY_W_BACK_SYNONYM_VALUE = "some value"; private static final String DEPRECATED_PROPERTY_W_BACK_SYNONYM_KEY = "(deprecated)" + DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME; private static final String ONE_OF_PROPERTY_NAME = "one-ofProperty"; private static final String ONE_OF_PROPERTY_VALUE = "value-A"; private static final String ONE_OF_PROPERTY_KEY = "(one-of?value-A|value-B)" + ONE_OF_PROPERTY_NAME; private static final String SIMPLE_SYNONYM_OF_DEPRECATED_NAME = "synonym.of.deprecated"; private static final String SIMPLE_SYNONYM_OF_DEPRECATED_VALUE = "${" + DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME + "}"; private static final String SIMPLE_SYNONYM_OF_DEPRECATED_KEY = SIMPLE_SYNONYM_OF_DEPRECATED_NAME; private static final String PROPERTY_WITH_SUFFIX_NAME = SIMPLE_PROPERTY_NAME + "-foo"; private static final String PROPERTY_WITH_SUFFIX_VALUE = "value-foo"; private static final String PROPERTY_WITH_PREFIX_NAME = "foo-" + SIMPLE_PROPERTY_NAME; private static final String PROPERTY_WITH_PREFIX_VALUE = "foo-value"; private static final String EXPANDING_PROPERTY_NAME = "expanding-key"; private static final String SCOPED_PROPERTY_NAME = "scoped/property"; private ConfigurationProperties _properties; private ConfigurationProperties _initiallyEmptyProperties; private ConfigurationProperties _standardProperties; private List<ILoggingEvent> _log; @Before public void setUp() { resetProperties(); resetLogCapture(); } private void resetProperties() { _properties = new ConfigurationProperties(); _properties.put( NORMAL_PROPERTY_NAME, NORMAL_PROPERTY_VALUE); _properties.put( ONE_OF_PROPERTY_KEY, ONE_OF_PROPERTY_VALUE); _properties.put( IMMUTABLE_PROPERTY_KEY, IMMUTABLE_PROPERTY_VALUE); _properties.put( OBSOLETE_PROPERTY_KEY, ""); _properties.put( OBSOLETE_PROPERTY_W_ERROR_KEY, OBSOLETE_PROPERTY_W_ERROR_VALUE); _properties.put( FORBIDDEN_PROPERTY_KEY, ""); _properties.put( FORBIDDEN_PROPERTY_W_ERROR_KEY, FORBIDDEN_PROPERTY_W_ERROR_VALUE); _properties.put( DEPRECATED_PROPERTY_KEY, DEPRECATED_PROPERTY_VALUE); _properties.put( DEPRECATED_PROPERTY_W_FORWARD_SYNONYM_KEY, DEPRECATED_PROPERTY_W_FORWARD_SYNONYM_VALUE); _properties.put(DEPRECATED_PROPERTY_W_BACK_SYNONYM_KEY, DEPRECATED_PROPERTY_W_BACK_SYNONYM_VALUE); _properties.put(SIMPLE_SYNONYM_OF_DEPRECATED_KEY, SIMPLE_SYNONYM_OF_DEPRECATED_VALUE); _initiallyEmptyProperties = new ConfigurationProperties(); _standardProperties = new ConfigurationProperties(); _standardProperties.setProperty( SIMPLE_PROPERTY_NAME, SIMPLE_PROPERTY_VALUE); _standardProperties.setProperty( PROPERTY_WITH_SUFFIX_NAME, PROPERTY_WITH_SUFFIX_VALUE); _standardProperties.setProperty( PROPERTY_WITH_PREFIX_NAME, PROPERTY_WITH_PREFIX_VALUE); } private void resetLogCapture() { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); loggerContext.reset(); ListAppender<ILoggingEvent> appender = new ListAppender<>(); appender.setContext(loggerContext); appender.setName("appender"); appender.start(); _log = appender.list; Logger logger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME); logger.addAppender(appender); logger.setLevel(Level.WARN); } @Test public void testNormalPropertyGet() { assertEquals( "testing normal property", NORMAL_PROPERTY_VALUE, _properties.get( NORMAL_PROPERTY_NAME)); } @Test public void testImmutablePropertyGet() { assertEquals( "testing immutable property", IMMUTABLE_PROPERTY_VALUE, _properties.get(IMMUTABLE_PROPERTY_NAME)); } @Test public void testDeprecatedPropertyGet() { assertEquals( "testing deprecated property", DEPRECATED_PROPERTY_VALUE, _properties.get( DEPRECATED_PROPERTY_NAME)); } @Test public void testObsoletePropertyGet() { assertFalse( "testing obsolete property missing", _properties.containsKey( OBSOLETE_PROPERTY_NAME)); } @Test public void testObsoleteWithErrorPropertyContainsKey() { assertFalse( "testing obsolete property missing", _properties.containsKey( OBSOLETE_PROPERTY_W_ERROR_NAME)); } @Test public void testForbiddenWithErrorPropertyContainsKey() { assertFalse( "testing obsolete property missing", _properties.containsKey( FORBIDDEN_PROPERTY_W_ERROR_NAME)); } @Test public void testForbiddenPropertyContainsKey() { assertFalse( "testing forbidden property missing", _properties.containsKey( FORBIDDEN_PROPERTY_NAME)); } @Test public void testNormalPropertyPut() { _properties.put( NORMAL_PROPERTY_NAME, "some value"); assertEquals(0, _log.size()); } @Test public void testImmutablePropertyPut() { try { _properties.put(IMMUTABLE_PROPERTY_NAME, "some new value"); fail( "no exception thrown"); } catch (IllegalArgumentException e) { assertEquals( "Property " + IMMUTABLE_PROPERTY_NAME + ": " + "may not be adjusted as it is marked 'immutable'", e.getMessage()); } } @Test public void testDeprecatedPropertyPut() { _properties.put( DEPRECATED_PROPERTY_NAME, "some value"); assertEquals(1, _log.size()); assertEquals(Level.WARN, _log.get(0).getLevel()); assertEquals("Property " + DEPRECATED_PROPERTY_NAME + ": please review configuration; support for " + DEPRECATED_PROPERTY_NAME + " will be removed in the future", _log.get(0).getFormattedMessage()); } @Test public void testDeprecatedBackSynonymDefaultPropertyPut() { ConfigurationProperties properties = new ConfigurationProperties(_properties); properties.put( DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME, "some value"); assertEquals(1, _log.size()); assertEquals(Level.WARN, _log.get(0).getLevel()); assertEquals("Property " + DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME + ": use \"" + SIMPLE_SYNONYM_OF_DEPRECATED_NAME + "\" instead; support for " + DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME + " will be removed in the future", _log.get(0).getFormattedMessage()); } @Test public void testDeprecatedBackSynonymPropertyPut() { _properties.put( DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME, "some value"); assertEquals(1, _log.size()); assertEquals(Level.WARN, _log.get(0).getLevel()); assertEquals("Property " + DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME + ": use \"" + SIMPLE_SYNONYM_OF_DEPRECATED_NAME + "\" instead; support for " + DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME + " will be removed in the future", _log.get(0).getFormattedMessage()); } @Test public void testObsoletePropertyPut() { _properties.put( OBSOLETE_PROPERTY_NAME, "some value"); assertEquals(1, _log.size()); assertEquals(Level.WARN, _log.get(0).getLevel()); assertEquals("Property " + OBSOLETE_PROPERTY_NAME + ": " + "please remove this assignment; it has no effect", _log.get(0).getFormattedMessage()); } @Test public void testObsoleteWithErrorPropertyPut() { _properties.put( OBSOLETE_PROPERTY_W_ERROR_NAME, "some value"); assertEquals(1, _log.size()); assertEquals(Level.WARN, _log.get(0).getLevel()); assertEquals("Property " + OBSOLETE_PROPERTY_W_ERROR_NAME + ": " + "please remove this assignment; " + OBSOLETE_PROPERTY_W_ERROR_VALUE, _log.get(0).getFormattedMessage()); } @Test public void testForbiddenPropertyPut() { try { _properties.put( FORBIDDEN_PROPERTY_NAME, "some value"); fail( "no exception thrown"); } catch (IllegalArgumentException e) { assertEquals( "Property " + FORBIDDEN_PROPERTY_NAME + ": " + "may not be adjusted; this property no longer affects dCache", e.getMessage()); } } @Test public void testForbiddenWithErrorPropertyPut() { try { _properties.put( FORBIDDEN_PROPERTY_W_ERROR_NAME, "some value"); fail( "no exception thrown"); } catch (IllegalArgumentException e) { assertEquals( "Property " + FORBIDDEN_PROPERTY_W_ERROR_NAME + ": " + "may not be adjusted; " + FORBIDDEN_PROPERTY_W_ERROR_VALUE, e.getMessage()); } } @Test(expected = IllegalArgumentException.class) public void testScopedPropertyPut() { _properties.put(SCOPED_PROPERTY_NAME, "some value"); } @Test public void testStringPropertyNames() { String[] expected = new String[] { NORMAL_PROPERTY_NAME, IMMUTABLE_PROPERTY_NAME, DEPRECATED_PROPERTY_NAME, DEPRECATED_PROPERTY_W_FORWARD_SYNONYM_NAME, DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME, ONE_OF_PROPERTY_NAME, SIMPLE_SYNONYM_OF_DEPRECATED_NAME}; assertEquals(new HashSet<>(Arrays.asList(expected)), _properties.stringPropertyNames()); } @Test public void testPropertyNames() { String[] expected = new String[] { NORMAL_PROPERTY_NAME, IMMUTABLE_PROPERTY_NAME, DEPRECATED_PROPERTY_NAME, DEPRECATED_PROPERTY_W_FORWARD_SYNONYM_NAME, DEPRECATED_PROPERTY_W_BACK_SYNONYM_NAME, ONE_OF_PROPERTY_NAME, SIMPLE_SYNONYM_OF_DEPRECATED_NAME}; Collection<String> results = new HashSet<>(); Enumeration<?> e = _properties.propertyNames(); while( e.hasMoreElements()) { results.add( String.valueOf(e.nextElement())); } assertEquals(new HashSet<>(Arrays.asList(expected)), results); } @Test public void testGetPropertySimple() { assertEquals( SIMPLE_PROPERTY_VALUE, _standardProperties.getProperty( SIMPLE_PROPERTY_NAME)); } @Test public void testGetReplacementSimple() { assertEquals( SIMPLE_PROPERTY_VALUE, _standardProperties.getValue( SIMPLE_PROPERTY_NAME)); } @Test public void testPropertyUpdatable() { String newValue = "new value"; _standardProperties.setProperty( SIMPLE_PROPERTY_NAME, newValue); assertEquals( newValue, _standardProperties.getProperty( SIMPLE_PROPERTY_NAME)); } @Test public void testGetPropertyExpanding() { String expandingValue = propertyReference( SIMPLE_PROPERTY_NAME); _standardProperties.setProperty( EXPANDING_PROPERTY_NAME, expandingValue); assertEquals( expandingValue, _standardProperties.getProperty( EXPANDING_PROPERTY_NAME)); } @Test public void testGetReplacementExpanding() { String expandingValue = propertyReference( SIMPLE_PROPERTY_NAME); _standardProperties.setProperty( EXPANDING_PROPERTY_NAME, expandingValue); assertEquals( SIMPLE_PROPERTY_VALUE, _standardProperties.getValue( EXPANDING_PROPERTY_NAME)); } @Test public void testGetReplacementExpandingWithPreamble() { String prefix = "FOO"; String expandingValue = prefix + propertyReference( SIMPLE_PROPERTY_NAME); _standardProperties.setProperty( EXPANDING_PROPERTY_NAME, expandingValue); assertEquals( prefix + SIMPLE_PROPERTY_VALUE, _standardProperties.getValue( EXPANDING_PROPERTY_NAME)); } @Test public void testGetReplacementExpandingWithPostamble() { String postfix = "FOO"; String expandingValue = propertyReference( SIMPLE_PROPERTY_NAME) + postfix; _standardProperties.setProperty( EXPANDING_PROPERTY_NAME, expandingValue); assertEquals( SIMPLE_PROPERTY_VALUE + postfix, _standardProperties.getValue( EXPANDING_PROPERTY_NAME)); } @Test public void testGetReplacementExpandingWithSpace() { String valueWithSpace = "This is a test"; _standardProperties.setProperty( SIMPLE_PROPERTY_NAME, valueWithSpace); String expandingValue = propertyReference( SIMPLE_PROPERTY_NAME); _standardProperties.setProperty( EXPANDING_PROPERTY_NAME, expandingValue); assertEquals( valueWithSpace, _standardProperties.getValue( EXPANDING_PROPERTY_NAME)); } @Test public void testTwoDeepExpansion() { String expanding1Value = propertyReference( SIMPLE_PROPERTY_NAME); _standardProperties.setProperty( EXPANDING_PROPERTY_NAME, expanding1Value); String expanding2Name = EXPANDING_PROPERTY_NAME + "-2"; String expanding2Value = propertyReference( EXPANDING_PROPERTY_NAME); _standardProperties.setProperty( expanding2Name, expanding2Value); assertEquals( SIMPLE_PROPERTY_VALUE, _standardProperties.getValue( expanding2Name)); } @Test public void testTwoByTwoDeepExpansion() { String expanding1Value = propertyReference( SIMPLE_PROPERTY_NAME); _standardProperties.setProperty( EXPANDING_PROPERTY_NAME, expanding1Value); String expanding2Name = EXPANDING_PROPERTY_NAME + "-2"; String expanding2Value = propertyReference( EXPANDING_PROPERTY_NAME) + propertyReference( EXPANDING_PROPERTY_NAME); _standardProperties.setProperty( expanding2Name, expanding2Value); assertEquals( SIMPLE_PROPERTY_VALUE + SIMPLE_PROPERTY_VALUE, _standardProperties.getValue( expanding2Name)); } @Test public void testRecursiveExpansion() { String expanding2Name = EXPANDING_PROPERTY_NAME + "-2"; String expanding1Value = propertyReference( expanding2Name); _standardProperties.setProperty( EXPANDING_PROPERTY_NAME, expanding1Value); String expanding2Value = propertyReference( EXPANDING_PROPERTY_NAME); _standardProperties.setProperty( expanding2Name, expanding2Value); assertEquals( expanding2Value, _standardProperties.getValue( expanding2Name)); } /* * Tests against load( Reader) */ @Test public void testLoadEmptyContentsIsEmpty() throws IOException { Reader in = new StringReader(""); _initiallyEmptyProperties.load( in); assertEquals( "check size is zero after loading empty data", 0, _initiallyEmptyProperties.size()); } @Test public void testLoadSingleProperty() throws IOException { String assignment = SIMPLE_PROPERTY_NAME + "=" + SIMPLE_PROPERTY_VALUE + "\n"; Reader in = new StringReader(assignment); _initiallyEmptyProperties.load( in); assertEquals( "check size is zero after loading empty data", 1, _initiallyEmptyProperties.size()); assertEquals( SIMPLE_PROPERTY_VALUE, _initiallyEmptyProperties.getProperty( SIMPLE_PROPERTY_NAME)); } @Test public void testLoadSinglePropertyWithSpace() throws IOException { String propertyValue = "This is a test"; Reader in = new StringReader(SIMPLE_PROPERTY_NAME + "=" + propertyValue); _initiallyEmptyProperties.load( in); assertEquals( "check size is zero after loading empty data", 1, _initiallyEmptyProperties.size()); assertEquals( propertyValue, _initiallyEmptyProperties.getProperty( SIMPLE_PROPERTY_NAME)); } @Test(expected=IllegalArgumentException.class) public void testLoadSinglePropertyTwiceFails() throws IOException { String propertyAssignment = SIMPLE_PROPERTY_NAME + "=" + "This is a test\n"; Reader in = new StringReader(propertyAssignment + propertyAssignment); _initiallyEmptyProperties.load( in); } /* * Test against load( InputStream) */ @Test public void testLoadInputStreamWithNoProperties() throws IOException { InputStream in = new ByteArrayInputStream( "".getBytes()); _initiallyEmptyProperties.load( in); assertEquals( "checking number of entries", 0, _initiallyEmptyProperties.size()); } @Test public void testLoadInputStreamWithSingleProperty() throws IOException { String assignment = SIMPLE_PROPERTY_NAME + "=" + SIMPLE_PROPERTY_VALUE + "\n"; InputStream in = new ByteArrayInputStream( assignment.getBytes()); _initiallyEmptyProperties.load( in); assertEquals( "check size is zero after loading empty data", 1, _initiallyEmptyProperties.size()); assertEquals( SIMPLE_PROPERTY_VALUE, _initiallyEmptyProperties.getProperty( SIMPLE_PROPERTY_NAME)); } @Test public void testLoadInputStreamWithSinglePropertyWithSpace() throws IOException { String propertyValue = "This is a test"; String assignment = SIMPLE_PROPERTY_NAME + "=" + propertyValue + "\n"; InputStream in = new ByteArrayInputStream( assignment.getBytes()); _initiallyEmptyProperties.load( in); assertEquals( "check size is zero after loading empty data", 1, _initiallyEmptyProperties.size()); assertEquals( propertyValue, _initiallyEmptyProperties.getProperty( SIMPLE_PROPERTY_NAME)); } @Test(expected=IllegalArgumentException.class) public void testLoadInputStreamWithSinglePropertyTwiceFails() throws IOException { String propertyAssignment = SIMPLE_PROPERTY_NAME + "=" + "This is a test\n"; String twoAssignments = propertyAssignment + propertyAssignment; InputStream in = new ByteArrayInputStream( twoAssignments.getBytes()); _initiallyEmptyProperties.load( in); } @Test public void testOneOfWithValidValueSucceeds() { _properties.put(ONE_OF_PROPERTY_NAME, "value-B"); } @Test(expected=IllegalArgumentException.class) public void testOneOfWithInvalidValueFails() { _properties.put(ONE_OF_PROPERTY_NAME, "value-C"); } /* * Support methods */ private String propertyReference( String name) { return "${" + name + "}"; } }