package io.eguan.vvr.configuration; /* * #%L * Project eguan * %% * Copyright (C) 2012 - 2017 Oodrive * %% * Licensed 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. * #L% */ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import io.eguan.configuration.AbstractConfigKey; import io.eguan.configuration.AbstractConfigurationContext; import io.eguan.configuration.ConfigValidationException; import io.eguan.configuration.MetaConfiguration; import io.eguan.configuration.StringConfigKey; import io.eguan.configuration.ValidConfigurationContext; import io.eguan.ibs.Ibs; import io.eguan.ibs.IbsFactory; import io.eguan.vvr.configuration.IbsConfigurationContext; import io.eguan.vvr.configuration.keys.IbsAutoConfRamSize; import io.eguan.vvr.configuration.keys.IbsBufferRotationDelay; import io.eguan.vvr.configuration.keys.IbsBufferRotationThreshold; import io.eguan.vvr.configuration.keys.IbsBufferWriteDelayIncrement; import io.eguan.vvr.configuration.keys.IbsBufferWriteDelayLevelSize; import io.eguan.vvr.configuration.keys.IbsBufferWriteDelayThreshold; import io.eguan.vvr.configuration.keys.IbsCompressionConfigKey; import io.eguan.vvr.configuration.keys.IbsCompressionValue; import io.eguan.vvr.configuration.keys.IbsConfigKey; import io.eguan.vvr.configuration.keys.IbsDisableBackgroundCompactionForIbpgenConfigKey; import io.eguan.vvr.configuration.keys.IbsDumpAtStopBestEffortDelayConfigKey; import io.eguan.vvr.configuration.keys.IbsHotDataConfigKey; import io.eguan.vvr.configuration.keys.IbsIbpGenPathConfigKey; import io.eguan.vvr.configuration.keys.IbsIbpPathConfigKey; import io.eguan.vvr.configuration.keys.IbsLdbBlockRestartIntervalConfigKey; import io.eguan.vvr.configuration.keys.IbsLdbBlockSizeConfigKey; import io.eguan.vvr.configuration.keys.IbsLogLevel; import io.eguan.vvr.configuration.keys.IbsLogLevelConfigKey; import io.eguan.vvr.configuration.keys.IbsOwnerUuidConfigKey; import io.eguan.vvr.configuration.keys.IbsRecordExecutionConfigKey; import io.eguan.vvr.configuration.keys.IbsSyslogConfigKey; import io.eguan.vvr.configuration.keys.IbsUuidConfigKey; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.util.ArrayList; import java.util.Properties; import java.util.UUID; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runners.model.InitializationError; /** * {@link ValidConfigurationContext} implementation with {@link IbsConfigurationContext}-specific tests. * * @author oodrive * @author pwehrle * @author llambert * @author jmcaba * @author ebredzinski * */ public final class TestValidIbsConfigurationContext extends ValidConfigurationContext { private static class ContextTestHelperIbs extends ContextTestHelper<IbsConfigurationContext> { protected File ibsIbpGenDir; protected ArrayList<File> ibsIbpDirList; protected ContextTestHelperIbs() { super(IbsConfigurationContext.getInstance()); } @Override public void setUp() throws InitializationError { final String tmpFilePrefix = TestValidIbsConfigurationContext.class.getSimpleName(); try { ibsIbpGenDir = Files.createTempDirectory(tmpFilePrefix).toFile(); ibsIbpDirList = new ArrayList<File>(); for (int i = 0; i < 4; i++) { ibsIbpDirList.add(Files.createTempDirectory(tmpFilePrefix).toFile()); } } catch (final IOException e) { throw new InitializationError(e); } } @Override public void tearDown() throws InitializationError { try { io.eguan.utils.Files.deleteRecursive(ibsIbpGenDir.toPath()); for (final File currFile : ibsIbpDirList) { io.eguan.utils.Files.deleteRecursive(currFile.toPath()); } } catch (final IOException e) { throw new InitializationError(e); } } @Override public Properties getConfig() { final Properties result = new Properties(); result.setProperty(getPropertyKey(IbsIbpPathConfigKey.getInstance()), ibsIbpDirList.toString().replaceAll("[\\[\\]]", "")); result.setProperty(getPropertyKey(IbsIbpGenPathConfigKey.getInstance()), ibsIbpGenDir.toString()); result.setProperty(getPropertyKey(IbsHotDataConfigKey.getInstance()), "TRUE"); result.setProperty(getPropertyKey(IbsDisableBackgroundCompactionForIbpgenConfigKey.getInstance()), "TRUE"); result.setProperty(getPropertyKey(IbsCompressionConfigKey.getInstance()), IbsCompressionValue.valueOf("front").toString()); result.setProperty(getPropertyKey(IbsUuidConfigKey.getInstance()), UUID.randomUUID().toString()); result.setProperty(getPropertyKey(IbsOwnerUuidConfigKey.getInstance()), UUID.randomUUID().toString()); result.setProperty(getPropertyKey(IbsLogLevelConfigKey.getInstance()), IbsLogLevel.valueOf("info") .toString()); result.setProperty(getPropertyKey(IbsLdbBlockSizeConfigKey.getInstance()), Integer.valueOf(4096).toString()); result.setProperty(getPropertyKey(IbsLdbBlockRestartIntervalConfigKey.getInstance()), Integer .valueOf(32768).toString()); result.setProperty(getPropertyKey(IbsBufferRotationThreshold.getInstance()), Integer.valueOf(1048576) .toString()); result.setProperty(getPropertyKey(IbsBufferRotationDelay.getInstance()), Integer.valueOf(20).toString()); result.setProperty(getPropertyKey(IbsBufferWriteDelayThreshold.getInstance()), Integer.valueOf(20) .toString()); result.setProperty(getPropertyKey(IbsBufferWriteDelayLevelSize.getInstance()), Integer.valueOf(7) .toString()); result.setProperty(getPropertyKey(IbsBufferWriteDelayIncrement.getInstance()), Integer.valueOf(10) .toString()); result.setProperty(getPropertyKey(IbsAutoConfRamSize.getInstance()), Integer.valueOf(4 << 30).toString()); result.setProperty(getPropertyKey(IbsRecordExecutionConfigKey.getInstance()), ""); result.setProperty(getPropertyKey(IbsDumpAtStopBestEffortDelayConfigKey.getInstance()), Integer.valueOf(10) .toString()); result.setProperty(getPropertyKey(IbsSyslogConfigKey.getInstance()), Boolean.FALSE.toString()); return result; } } /** * Generate errors every 10 {@link Ibs} IO operations. * */ private static final class ContextTestHelperIbsError extends ContextTestHelperIbs { private File ibpDirParent; private File ibpDir; @Override public void setUp() throws InitializationError { final String tmpFilePrefix = TestValidIbsConfigurationContext.class.getSimpleName(); try { ibsIbpGenDir = Files.createTempDirectory(tmpFilePrefix).toFile(); ibsIbpDirList = new ArrayList<File>(1); ibpDirParent = Files.createTempDirectory(tmpFilePrefix).toFile(); ibpDir = new File(ibpDirParent, Ibs.UNIT_TEST_IBS_HEADER + "10"); ibpDir.mkdir(); ibsIbpDirList.add(ibpDir); } catch (final IOException e) { throw new InitializationError(e); } } @Override public void tearDown() throws InitializationError { try { io.eguan.utils.Files.deleteRecursive(ibsIbpGenDir.toPath()); } catch (final IOException e) { throw new InitializationError(e); } try { io.eguan.utils.Files.deleteRecursive(ibpDirParent.toPath()); } catch (final IOException e) { throw new InitializationError(e); } // Destroy Ibs try { final Ibs toDel = IbsFactory.openIbs(ibpDir); toDel.destroy(); } catch (final Exception e) { throw new InitializationError(e); } } } private static final ContextTestHelperIbs testHelper = new ContextTestHelperIbs(); private static final ContextTestHelperIbs testErrHelper = new ContextTestHelperIbsError(); private static ArrayList<File> tmpDirectories = new ArrayList<File>(); @BeforeClass public static void setUpClass() throws InitializationError { testHelper.setUp(); } @AfterClass public static void tearDownClass() throws InitializationError { testHelper.tearDown(); final ArrayList<Throwable> exceptionList = new ArrayList<Throwable>(); for (final File currFile : tmpDirectories) { try { Files.deleteIfExists(currFile.toPath()); } catch (final IOException e) { exceptionList.add(e); } } if (!exceptionList.isEmpty()) { throw new InitializationError(exceptionList); } } @Test public final void testMetaConfigurationIbsConfigurationContextAcceptSimilarDirs() throws RuntimeException, IOException, ConfigValidationException { final Properties config = testHelper.getConfig(); MetaConfiguration preConfig = null; try { preConfig = MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } catch (final ConfigValidationException ce) { throw new IllegalStateException(ce); } final ArrayList<File> ibpPaths = IbsIbpPathConfigKey.getInstance().getTypedValue(preConfig); // this directory is valid, but would fail a simple substring test final File validIbpPath = new File(ibpPaths.get(0).getAbsolutePath() + "addIbp"); validIbpPath.mkdirs(); tmpDirectories.add(validIbpPath); final String ibpPropertyKey = testHelper.getPropertyKey(IbsIbpPathConfigKey.getInstance()); config.setProperty(ibpPropertyKey, validIbpPath.getAbsolutePath() + "," + config.getProperty(ibpPropertyKey)); MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } /** * Test failure to create a {@link MetaConfiguration} with {@link IbsConfigurationContext} as context due to a path * whose a child of another at the beginning of the Ibp path list. * * @throws ConfigValidationException * if the prepared configuration is invalid. Expected for this test. */ @Test(expected = ConfigValidationException.class) public final void testMetaConfigurationIbsConfigurationContextFailIbpFirstChildPath() throws RuntimeException, IOException, ConfigValidationException { final Properties config = testHelper.getConfig(); MetaConfiguration preConfig = null; try { preConfig = MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } catch (final ConfigValidationException ce) { throw new IllegalStateException(ce); } final ArrayList<File> ibpPaths = IbsIbpPathConfigKey.getInstance().getTypedValue(preConfig); final File badIbpChildPath = new File(ibpPaths.get(0), "badIbpPath"); badIbpChildPath.mkdirs(); tmpDirectories.add(badIbpChildPath); final String ibpPropertyKey = testHelper.getPropertyKey(IbsIbpPathConfigKey.getInstance()); config.setProperty(ibpPropertyKey, badIbpChildPath.getAbsolutePath() + "," + config.getProperty(ibpPropertyKey)); MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } /** * Test failure to create a {@link MetaConfiguration} with {@link IbsConfigurationContext} as context due to a path * whose a child of another at the end of the Ibp path list. * * @throws ConfigValidationException * if the prepared configuration is invalid. Expected for this test. */ @Test(expected = ConfigValidationException.class) public final void testMetaConfigurationIbsConfigurationContextFailIbpEndChildPath() throws RuntimeException, IOException, ConfigValidationException { final Properties config = testHelper.getConfig(); MetaConfiguration preConfig = null; try { preConfig = MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } catch (final ConfigValidationException ce) { throw new IllegalStateException(ce); } final ArrayList<File> ibpPaths = IbsIbpPathConfigKey.getInstance().getTypedValue(preConfig); final File badIbpChildPath = new File(ibpPaths.get(0), "badIbpPath"); badIbpChildPath.mkdirs(); tmpDirectories.add(badIbpChildPath); final String ibpPropertyKey = testHelper.getPropertyKey(IbsIbpPathConfigKey.getInstance()); config.setProperty(ibpPropertyKey, config.getProperty(ibpPropertyKey) + "," + badIbpChildPath.getAbsolutePath()); MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } /** * Test failure to create a {@link MetaConfiguration} with {@link IbsConfigurationContext} as context due to a path * whose a parent of another at the beginning of the Ibp path list. * * @throws ConfigValidationException * if the prepared configuration is invalid. Expected for this test. */ @Test(expected = ConfigValidationException.class) public final void testMetaConfigurationIbsConfigurationContextFailIbpFirstParentPath() throws RuntimeException, IOException, ConfigValidationException { final Properties config = testHelper.getConfig(); MetaConfiguration preConfig = null; try { preConfig = MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } catch (final ConfigValidationException ce) { throw new IllegalStateException(ce); } final ArrayList<File> ibpPaths = IbsIbpPathConfigKey.getInstance().getTypedValue(preConfig); final File badIbpParentPath = ibpPaths.get(0).getParentFile(); assertNotNull(badIbpParentPath); final String ibpPropertyKey = testHelper.getPropertyKey(IbsIbpPathConfigKey.getInstance()); config.setProperty(ibpPropertyKey, badIbpParentPath.getAbsolutePath() + "," + config.getProperty(ibpPropertyKey)); MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } /** * Test failure to create a {@link MetaConfiguration} with {@link IbsConfigurationContext} as context due to a path * whose a parent of another at the end of the Ibp path list. * * @throws ConfigValidationException * if the prepared configuration is invalid. Expected for this test. */ @Test(expected = ConfigValidationException.class) public final void testMetaConfigurationIbsConfigurationContextFailIbpEndParentPath() throws RuntimeException, IOException, ConfigValidationException { final Properties config = testHelper.getConfig(); MetaConfiguration preConfig = null; try { preConfig = MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } catch (final ConfigValidationException ce) { throw new IllegalStateException(ce); } final ArrayList<File> ibpPaths = IbsIbpPathConfigKey.getInstance().getTypedValue(preConfig); final File badIbpParentPath = ibpPaths.get(0).getParentFile(); assertNotNull(badIbpParentPath); final String ibpPropertyKey = testHelper.getPropertyKey(IbsIbpPathConfigKey.getInstance()); config.setProperty(ibpPropertyKey, config.getProperty(ibpPropertyKey) + "," + badIbpParentPath.getAbsolutePath()); MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } /** * Test failure to create a {@link MetaConfiguration} with {@link IbsConfigurationContext} as context due to an * IbpGen path overlapping Ibp paths. * * @throws ConfigValidationException * if the prepared configuration is invalid. Expected for this test. */ @Test(expected = ConfigValidationException.class) public final void testMetaConfigurationIbsConfigurationContextFailIbpGenPath() throws RuntimeException, IOException, ConfigValidationException { final Properties config = testHelper.getConfig(); MetaConfiguration preConfig = null; try { preConfig = MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } catch (final ConfigValidationException ce) { throw new IllegalStateException(ce); } final ArrayList<File> ibpPaths = IbsIbpPathConfigKey.getInstance().getTypedValue(preConfig); final File badIbpGenPath = new File(ibpPaths.get(0), "badIbpGenPath"); badIbpGenPath.mkdirs(); tmpDirectories.add(badIbpGenPath); System.out.println(ibpPaths + ": " + badIbpGenPath); final String ibpGenPropertyKey = testHelper.getPropertyKey(IbsIbpGenPathConfigKey.getInstance()); config.setProperty(ibpGenPropertyKey, badIbpGenPath.getAbsolutePath()); MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } /** * Test failure to create a {@link MetaConfiguration} with {@link IbsConfigurationContext} as context due to a * <code>null</code> Ibp path list. * * @throws ConfigValidationException * if the prepared configuration is invalid. Expected for this test. */ @Test(expected = ConfigValidationException.class) public final void testMetaConfigurationIbsConfigurationContextFailIbpPathsNull() throws RuntimeException, IOException, ConfigValidationException { final Properties config = testHelper.getConfig(); config.remove(testHelper.getPropertyKey(IbsIbpPathConfigKey.getInstance())); MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } /** * Test failure to create a {@link MetaConfiguration} with {@link IbsConfigurationContext} as context due to a * <code>null</code> IbpGen path. * * @throws ConfigValidationException * if the prepared configuration is invalid. Expected for this test. */ @Test(expected = ConfigValidationException.class) public final void testMetaConfigurationIbsConfigurationContextFailIbpGenPathNull() throws RuntimeException, IOException, ConfigValidationException { final Properties config = testHelper.getConfig(); config.remove(testHelper.getPropertyKey(IbsIbpGenPathConfigKey.getInstance())); MetaConfiguration.newConfiguration(ContextTestHelper.getPropertiesAsInputStream(config), IbsConfigurationContext.getInstance()); } /** * Tests successful execution of {@link IbsConfigurationContext#storeIbsConfig(MetaConfiguration, OutputStream)}. */ @Test public final void testStoreIbsConfig() throws RuntimeException, IOException, ConfigValidationException { final Properties configProps = testHelper.getConfig(); final IbsConfigurationContext targetContext = IbsConfigurationContext.getInstance(); final MetaConfiguration configuration = MetaConfiguration.newConfiguration( ContextTestHelper.getPropertiesAsInputStream(configProps), targetContext); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); targetContext.storeIbsConfig(configuration, outputStream); final Properties resultProps = new Properties(); resultProps.load(new ByteArrayInputStream(outputStream.toByteArray())); for (final AbstractConfigKey currKey : targetContext.getConfigKeys()) { if (!(currKey instanceof IbsConfigKey)) { continue; } final String resultValue = resultProps.getProperty(((IbsConfigKey) currKey).getBackendConfigKey()); assertNotNull("key saved to Ibs config", resultValue); assertEquals("value saved to Ibs config", ContextTestHelper.getStringValue(configuration, currKey), resultValue); } } /** * Tests failure of {@link IbsConfigurationContext#storeIbsConfig(MetaConfiguration, OutputStream)} due to a faulty * configuration. * * @throws IllegalStateException * if the configuration does not manage {@link IbsConfigurationContext}'s keys. Expected for this test. */ @Test(expected = IllegalStateException.class) public final void testStoreIbsConfigFailBadConfiguration() throws IllegalStateException, RuntimeException, IOException, ConfigValidationException { final AbstractConfigurationContext DummyContext = new AbstractConfigurationContext("com.example.test", new StringConfigKey("no.key") { @Override protected String getDefaultValue() { return "default"; } }) { }; final MetaConfiguration configuration = MetaConfiguration.newConfiguration( ContextTestHelper.getPropertiesAsInputStream(testHelper.getConfig()), DummyContext); IbsConfigurationContext.getInstance().storeIbsConfig(configuration, new ByteArrayOutputStream()); } /** * Tests failure of {@link IbsConfigurationContext#storeIbsConfig(MetaConfiguration, OutputStream)} due to a * <code>null</code> configuration. * * @throws NullPointerException * Expected for this test. */ @Test(expected = NullPointerException.class) public final void testStoreIbsConfigFailNullConfiguration() throws NullPointerException, RuntimeException, IOException, ConfigValidationException { IbsConfigurationContext.getInstance().storeIbsConfig(null, new ByteArrayOutputStream()); } /** * Tests failure of {@link IbsConfigurationContext#storeIbsConfig(MetaConfiguration, OutputStream)} due to an * unwritable {@link OutputStream}. * * @throws IOException * if writing to the {@link OutputStream} fails. Expected for this test. */ @Test(expected = IOException.class) public final void testStoreIbsConfigFailBadOutputStream() throws RuntimeException, IOException, ConfigValidationException { final MetaConfiguration configuration = MetaConfiguration.newConfiguration( ContextTestHelper.getPropertiesAsInputStream(testHelper.getConfig()), IbsConfigurationContext.getInstance()); final OutputStream badOutputStream = new OutputStream() { @Override public final void write(final int b) throws IOException { throw new IOException(); } }; IbsConfigurationContext.getInstance().storeIbsConfig(configuration, badOutputStream); } /** * Tests failure of {@link IbsConfigurationContext#storeIbsConfig(MetaConfiguration, OutputStream)} due to a * <code>null</code> {@link OutputStream}. * * @throws NullPointerException * Expected for this test. */ @Test(expected = NullPointerException.class) public final void testStoreIbsConfigFailNullOutputStream() throws NullPointerException, RuntimeException, IOException, ConfigValidationException { final MetaConfiguration configuration = MetaConfiguration.newConfiguration( ContextTestHelper.getPropertiesAsInputStream(testHelper.getConfig()), IbsConfigurationContext.getInstance()); IbsConfigurationContext.getInstance().storeIbsConfig(configuration, null); } @Override public final ContextTestHelper<?> getTestHelper() { return testHelper; } public final ContextTestHelper<?> getTestErrHelper() { return testErrHelper; } }