package org.dcache.boot; import org.junit.Before; import org.junit.Test; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.LineNumberReader; import java.io.PrintStream; import java.io.StringReader; import java.util.Properties; import org.dcache.util.ConfigurationProperties; import static org.dcache.boot.Properties.PROPERTY_CELL_NAME_SUFFIX; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; /** * Tests for the Python Oracle */ public class PythonOracleLayoutPrinterTests { private ConfigurationProperties _globalDefaults; private ConfigurationProperties _dCacheConf; private ConfigurationProperties _layoutDefaults; private Layout _layout; private PythonOracleLayoutPrinter _printer; private ScriptEngine _engine; @Before public void setUp() { _globalDefaults = new ConfigurationProperties(new Properties()); _globalDefaults.setProperty(org.dcache.boot.Properties.PROPERTY_DOMAIN_SERVICE_URI, "classpath:/org/dcache/boot/empty.batch"); _dCacheConf = new ConfigurationProperties(_globalDefaults); _layout = new Layout(_dCacheConf); _layoutDefaults = _layout.properties(); _printer = new PythonOracleLayoutPrinter(_layout); _engine = new ScriptEngineManager().getEngineByName("python"); } @Test public void shouldFindGlobalValueIfDefined() { givenDefaults().with("property.name", "default value"); whenOracleIsLoadedAndExec(); assertThat(globalScopedProperty("property.name"), is("default value")); } @Test public void shouldFindAwkwardGlobalValueIfDefined() { givenDefaults().with("property.name", "the\\value\nis\t'here'"); whenOracleIsLoadedAndExec(); assertThat(globalScopedProperty("property.name"), is("the\\value\nis\t'here'")); } @Test public void shouldNotFindGlobalValueIfNotDefined() { givenDefaults().with("property.name", "default value"); whenOracleIsLoadedAndExec(); assertThat(globalScopedProperty("a.different.property.name"), is(nullValue())); } @Test public void shouldFindValueIfDefinedInDcacheConf() { givenDcacheConf().with("property.name", "dCache.conf value"); whenOracleIsLoadedAndExec(); assertThat(globalScopedProperty("property.name"), is("dCache.conf value")); } @Test public void shouldReturnValueIfDcacheConfOverridesDefault() { givenDefaults().with("property.name", "default value"); givenDcacheConf().with("property.name", "dCache.conf value"); whenOracleIsLoadedAndExec(); assertThat(globalScopedProperty("property.name"), is("dCache.conf value")); } @Test public void shouldNotFindValueDefinedInDomain() { givenDomain("domain 1").with("property.name", "domain 1 value"); whenOracleIsLoadedAndExec(); assertThat(globalScopedProperty("property.name"), is(nullValue())); } @Test public void shouldFindValueDefinedInDomain() { givenDomain("domain 1").with("property.name", "domain 1 value"); whenOracleIsLoadedAndExec(); assertThat(domainScopedProperty("domain 1", "property.name"), is("domain 1 value")); } @Test public void shouldFindDomainValueIfGlobalDefined() { givenDefaults().with("property.name", " defaultvalue"); givenDcacheConf().with("property.name", "dCache.conf value"); givenDomain("domain 1").with("property.name", "domain 1 value"); whenOracleIsLoadedAndExec(); assertThat(domainScopedProperty("domain 1", "property.name"), is("domain 1 value")); assertThat(globalScopedProperty("property.name"), is("dCache.conf value")); } @Test public void shouldFindServiceValueIfDefined() throws IOException { givenDefaults().with("property.name", "default value"); givenDcacheConf().with("property.name", "dCache.conf value"); givenDomain("domain 1"). with("property.name", "domain 1 value"). withService("pool", "pool1"). with("property.name", "pool1-value"); whenOracleIsLoadedAndExec(); assertThat(serviceScopedProperty("domain 1", "pool1", "property.name"), is("pool1-value")); assertThat(domainScopedProperty("domain 1", "property.name"), is("domain 1 value")); assertThat(globalScopedProperty("property.name"), is("dCache.conf value")); } @Test public void shouldFindSpecificServiceValueIfDefined() throws IOException { givenDefaults().with("property.name", "default value"); givenDcacheConf().with("property.name", "dCache.conf value"); givenDomain("domain 1"). with("property.name", "domain 1 value"). withService("pool", "pool1"). with("property.name", "pool1 value"). withService("pool", "pool2"). with("property.name", "pool2 value"); whenOracleIsLoadedAndExec(); assertThat(serviceScopedProperty("domain 1", "pool1", "property.name"), is("pool1 value")); assertThat(serviceScopedProperty("domain 1", "pool2", "property.name"), is("pool2 value")); } private void whenOracleIsLoadedAndExec() { ByteArrayOutputStream stored = new ByteArrayOutputStream(); PrintStream s = new PrintStream(stored); _printer.print(s); // We assign the variable 'declaration' with the Oracle definition. // This is to simulate running the bootloader to generate the python // oracle. _engine.put("declaration", stored.toString()); try { _engine.eval("exec declaration"); } catch (ScriptException e) { throw new RuntimeException(e); } } private String globalScopedProperty(String key) { String args = "'" + key + "'"; return lookupArgs(args); } private String domainScopedProperty(String domain, String key) { String args = "'" + key +"', '" + domain + "'"; return lookupArgs(args); } private String serviceScopedProperty(String domain, String service, String key) { String args = "'" + key +"', '" + domain + "', '" + service + "'"; return lookupArgs(args); } private String lookupArgs(String args) { try { _engine.eval("result = properties.get(" + args + ")"); } catch (ScriptException e) { throw new RuntimeException(e); } Object result = _engine.get("result"); return result == null ? null : result.toString(); } private PropertyBuilder givenDefaults() { return new PropertyBuilder(_globalDefaults); } private PropertyBuilder givenDcacheConf() { return new PropertyBuilder(_dCacheConf); } private PropertyBuilder givenLayoutDefaults() { return new PropertyBuilder(_layoutDefaults); } /** * Class with fluent interface that allows initialising a * ConfigurationProperties. */ private class PropertyBuilder { private final ConfigurationProperties _inner; public PropertyBuilder(ConfigurationProperties properties) { _inner = properties; } public PropertyBuilder with(String key, String value) { _inner.put(key, value); return this; } } private DomainBuilder givenDomain(String name) { return new DomainBuilder(name); } /** * Class with fluent interface that allows building of a domain * with domain-scoped default values and services with service-scoped * property values. */ private class DomainBuilder { private final Domain _domain; private ConfigurationProperties _properties; public DomainBuilder(String name) { _layout.createDomain(name); _domain = _layout.getDomain(name); _properties = _domain.properties(); } public DomainBuilder with(String key, String value) { _properties.put(key, value); return this; } public DomainBuilder withService(String type, String cellName) throws IOException { _properties = _domain.createService("source", new LineNumberReader(new StringReader("")), type); _properties.put(type + "." + PROPERTY_CELL_NAME_SUFFIX, cellName); return this; } } }