package io.eguan.ibs;
/*
* #%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 io.eguan.ibs.IbsTestDefinitions.CONF_HOTDATA;
import static io.eguan.ibs.IbsTestDefinitions.CONF_HOTDATA_OFF;
import static io.eguan.ibs.IbsTestDefinitions.CONF_IBP;
import static io.eguan.ibs.IbsTestDefinitions.CONF_IBPGEN;
import static io.eguan.ibs.IbsTestDefinitions.CONF_OWNER;
import static io.eguan.ibs.IbsTestDefinitions.CONF_OWNER_ALT;
import static io.eguan.ibs.IbsTestDefinitions.CONF_UUID;
import static io.eguan.ibs.IbsTestDefinitions.CONF_UUID_ALT;
import static io.eguan.ibs.IbsTestDefinitions.TEMP_PREFIX;
import static io.eguan.ibs.IbsTestDefinitions.TEMP_SUFFIX;
import io.eguan.utils.ByteArrays;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import junit.framework.AssertionFailedError;
import org.junit.Assert;
import org.junit.Test;
/**
* Test IBS initialization (success and failures).
*
* @author oodrive
* @author llambert
* @author jmcaba
*
*/
public final class TestIbsInit {
private static final int TST_KEY_LEN = 32;
private static final int TST_VALUE_LEN = 4096;
private static final int IDX_CONFIG_FILE = 0;
private static final int IDX_IBPGEN_DIR = 1;
private static final int IDX_IBP1_DIR = 2;
private static final int IDX_IBP2_DIR = 3;
// IBS internals
private static final String IBP_CONFIG_FILE = "ibpid.conf";
private static final String IBPGEN_CONFIG_FILE = "ibs.conf";
private static final String IBP_CONFIG_OWNER_KEY = "owner";
private static final String IBP_CONFIG_UUID_KEY = "uuid";
enum HotDataDef {
DEFAULT, ON, OFF;
}
@Test(expected = IbsException.class)
public void testCreateConfigNotExist() throws IOException {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
Assert.assertTrue(tempConfig.delete());
try {
IbsFactory.createIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
@Test(expected = IbsException.class)
public void testCreateConfigEmpty() throws IOException {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
try {
try {
IbsFactory.createIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
tempConfig.delete();
}
}
@Test(expected = IbsException.class)
public void testCreateConfigDirsEquals() throws IOException {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
try {
final Path tempDir = Files.createTempDirectory(TEMP_PREFIX);
try {
// Write config: same directory twice
try (PrintStream config = new PrintStream(tempConfig)) {
final String dir = tempDir.toAbsolutePath().toString();
config.println(CONF_IBPGEN + dir);
config.println(CONF_IBP + dir);
config.println(CONF_UUID);
config.println(CONF_OWNER);
}
try {
IbsFactory.createIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
Files.delete(tempDir);
}
}
finally {
tempConfig.delete();
}
}
@Test(expected = IbsException.class)
public void testCreateConfigDirIbpgenNotExists() throws IOException {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
try {
final Path tempDir1 = Files.createTempDirectory(TEMP_PREFIX);
Assert.assertTrue(Files.deleteIfExists(tempDir1));
final Path tempDir2 = Files.createTempDirectory(TEMP_PREFIX);
try {
// Write config: directory
try (PrintStream config = new PrintStream(tempConfig)) {
config.println(CONF_IBPGEN + tempDir1.toAbsolutePath());
config.println(CONF_IBP + tempDir2.toAbsolutePath());
config.println(CONF_UUID);
config.println(CONF_OWNER);
}
try {
IbsFactory.createIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
Files.delete(tempDir2);
}
}
finally {
tempConfig.delete();
}
}
@Test(expected = IbsException.class)
public void testCreateConfigDirIbpNotExists() throws IOException {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
try {
final Path tempDir1 = Files.createTempDirectory(TEMP_PREFIX);
final Path tempDir2 = Files.createTempDirectory(TEMP_PREFIX);
Assert.assertTrue(Files.deleteIfExists(tempDir2));
try {
// Write config: directory
try (PrintStream config = new PrintStream(tempConfig)) {
config.println(CONF_IBPGEN + tempDir1.toAbsolutePath());
config.println(CONF_IBP + tempDir2.toAbsolutePath());
config.println(CONF_UUID);
config.println(CONF_OWNER);
}
try {
IbsFactory.createIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
Files.delete(tempDir1);
}
}
finally {
tempConfig.delete();
}
}
@Test
public void testCreateConfigHotDataDefault() throws IOException {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
try {
final Path tempDir1 = Files.createTempDirectory(TEMP_PREFIX);
try {
final Path tempDir2 = Files.createTempDirectory(TEMP_PREFIX);
try {
// Write config: directory
try (PrintStream config = new PrintStream(tempConfig)) {
config.println(CONF_IBPGEN + tempDir1.toAbsolutePath());
config.println(CONF_IBP + tempDir2.toAbsolutePath());
config.println(CONF_UUID);
config.println(CONF_OWNER);
}
final Ibs ibs = IbsFactory.createIbs(tempConfig);
try {
// Hot data enabled by default
Assert.assertTrue(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
finally {
io.eguan.utils.Files.deleteRecursive(tempDir2);
}
}
finally {
io.eguan.utils.Files.deleteRecursive(tempDir1);
}
}
finally {
tempConfig.delete();
}
}
@Test
public void testCreateConfigHotDataOn() throws IOException {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
try {
final Path tempDir1 = Files.createTempDirectory(TEMP_PREFIX);
try {
final Path tempDir2 = Files.createTempDirectory(TEMP_PREFIX);
try {
// Write config: directory
try (PrintStream config = new PrintStream(tempConfig)) {
config.println(CONF_IBPGEN + tempDir1.toAbsolutePath());
config.println(CONF_IBP + tempDir2.toAbsolutePath());
config.println(CONF_HOTDATA);
config.println(CONF_UUID);
config.println(CONF_OWNER);
}
final Ibs ibs = IbsFactory.createIbs(tempConfig);
try {
Assert.assertTrue(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
finally {
io.eguan.utils.Files.deleteRecursive(tempDir2);
}
}
finally {
io.eguan.utils.Files.deleteRecursive(tempDir1);
}
}
finally {
tempConfig.delete();
}
}
@Test
public void testCreateConfigHotDataOff() throws IOException {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
try {
final Path tempDir1 = Files.createTempDirectory(TEMP_PREFIX);
try {
final Path tempDir2 = Files.createTempDirectory(TEMP_PREFIX);
try {
// Write config: directory
try (PrintStream config = new PrintStream(tempConfig)) {
config.println(CONF_IBPGEN + tempDir1.toAbsolutePath());
config.println(CONF_IBP + tempDir2.toAbsolutePath());
config.println(CONF_HOTDATA_OFF);
config.println(CONF_UUID);
config.println(CONF_OWNER);
}
final Ibs ibs = IbsFactory.createIbs(tempConfig);
try {
Assert.assertFalse(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
finally {
io.eguan.utils.Files.deleteRecursive(tempDir2);
}
}
finally {
io.eguan.utils.Files.deleteRecursive(tempDir1);
}
}
finally {
tempConfig.delete();
}
}
@Test(expected = IbsException.class)
public void testCreateConfigHotDataClosed() throws IOException {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
try {
final Path tempDir1 = Files.createTempDirectory(TEMP_PREFIX);
try {
final Path tempDir2 = Files.createTempDirectory(TEMP_PREFIX);
try {
// Write config: directory
try (PrintStream config = new PrintStream(tempConfig)) {
config.println(CONF_IBPGEN + tempDir1.toAbsolutePath());
config.println(CONF_IBP + tempDir2.toAbsolutePath());
config.println(CONF_HOTDATA_OFF);
config.println(CONF_UUID);
config.println(CONF_OWNER);
}
final Ibs ibs = IbsFactory.createIbs(tempConfig);
ibs.close();
try {
ibs.isHotDataEnabled();
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.INVALID_IBS_ID, e.getErrorCode());
throw e;
}
}
finally {
io.eguan.utils.Files.deleteRecursive(tempDir2);
}
}
finally {
io.eguan.utils.Files.deleteRecursive(tempDir1);
}
}
finally {
tempConfig.delete();
}
}
@Test(expected = IbsException.class)
public void testOpenConfigNotExist() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
Assert.assertTrue(tempConfig.delete());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigEmpty() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
Assert.assertTrue(tempConfig.delete());
Assert.assertTrue(tempConfig.createNewFile());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirsEquals() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final File tempGenDir = files.get(IDX_IBPGEN_DIR);
// Write config: same directory twice
try (PrintStream config = new PrintStream(tempConfig)) {
final String dir = tempGenDir.getAbsolutePath();
config.println(CONF_IBPGEN + dir);
config.println(CONF_IBP + dir);
config.println(CONF_UUID);
config.println(CONF_OWNER);
}
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpgenNotExists() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final File tempGenDir = files.get(IDX_IBPGEN_DIR);
io.eguan.utils.Files.deleteRecursive(tempGenDir.toPath());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpgenEmpty() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final File tempGenDir = files.get(IDX_IBPGEN_DIR);
io.eguan.utils.Files.deleteRecursive(tempGenDir.toPath());
Assert.assertTrue(tempGenDir.mkdir());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.INIT_FROM_EMPTY_DIR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test
public void testOpenConfigDirIbpgenMoved() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final File tempGenDir = files.get(IDX_IBPGEN_DIR);
// Rename gendir and re-write config file
final Path tempGenDirNewPath = Files.createTempDirectory(TEMP_PREFIX);
Files.delete(tempGenDirNewPath);
Files.move(tempGenDir.toPath(), tempGenDirNewPath);
files.set(IDX_IBPGEN_DIR, tempGenDirNewPath.toFile());
writeIbsConfig(HotDataDef.DEFAULT, files);
final Ibs ibs = IbsFactory.openIbs(tempConfig);
ibs.close();
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpgenChangedUuid() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Change UUID in IBPGEN config file
final File ibpConf = new File(files.get(IDX_IBPGEN_DIR), IBPGEN_CONFIG_FILE);
changeIbpConfigKey(ibpConf, IBP_CONFIG_UUID_KEY, UUID.randomUUID().toString());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpgenChangedOwner() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Change owner in IBPGEN config file
final File ibpConf = new File(files.get(IDX_IBPGEN_DIR), IBPGEN_CONFIG_FILE);
changeIbpConfigKey(ibpConf, IBP_CONFIG_OWNER_KEY, UUID.randomUUID().toString());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpNotExists1() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final File tempPDir1 = files.get(IDX_IBP1_DIR);
io.eguan.utils.Files.deleteRecursive(tempPDir1.toPath());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpEmpty1() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final File tempPDir1 = files.get(IDX_IBP1_DIR);
io.eguan.utils.Files.deleteRecursive(tempPDir1.toPath());
Assert.assertTrue(tempPDir1.mkdir());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.INIT_FROM_EMPTY_DIR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpNotExists2() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final File tempPDir2 = files.get(IDX_IBP2_DIR);
io.eguan.utils.Files.deleteRecursive(tempPDir2.toPath());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpEmpty2() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final File tempPDir2 = files.get(IDX_IBP2_DIR);
io.eguan.utils.Files.deleteRecursive(tempPDir2.toPath());
Assert.assertTrue(tempPDir2.mkdir());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.INIT_FROM_EMPTY_DIR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpChangedRemove1() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
File toDel = null;
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
toDel = files.remove(IDX_IBP1_DIR);
writeIbsConfig(HotDataDef.DEFAULT, files);
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
if (toDel != null) {
io.eguan.utils.Files.deleteRecursive(toDel.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpChangedRemove2() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
File toDel = null;
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
toDel = files.remove(IDX_IBP2_DIR);
writeIbsConfig(HotDataDef.DEFAULT, files);
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
if (toDel != null) {
io.eguan.utils.Files.deleteRecursive(toDel.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpChangedUuid() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Change owner in IBP config file
final File ibpConf = new File(files.get(IDX_IBP2_DIR), IBP_CONFIG_FILE);
changeIbpConfigKey(ibpConf, IBP_CONFIG_UUID_KEY, UUID.randomUUID().toString());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpChangedOwner() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Change owner in IBP config file
final File ibpConf = new File(files.get(IDX_IBP2_DIR), IBP_CONFIG_FILE);
changeIbpConfigKey(ibpConf, IBP_CONFIG_OWNER_KEY, UUID.randomUUID().toString());
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test
public void testOpenConfigDirIbpChangedSwitchIbp() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Write some values
final Map<byte[], byte[]> values = writeValues(tempConfig);
// Switch ibp
final File file = files.remove(IDX_IBP1_DIR);
files.add(file);
writeIbsConfig(HotDataDef.DEFAULT, files);
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
ibs.start();
try {
for (final Iterator<Entry<byte[], byte[]>> entries = values.entrySet().iterator(); entries
.hasNext();) {
final Entry<byte[], byte[]> entry = entries.next();
final ByteBuffer valueBuf = ibs.get(entry.getKey(), TST_VALUE_LEN, false);
ByteArrays.assertEqualsByteArrays(entry.getValue(), valueBuf.array());
}
}
finally {
ibs.stop();
}
}
finally {
ibs.close();
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test
public void testOpenConfigDirIbpChangedMoveIbp1() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Write some values
final Map<byte[], byte[]> values = writeValues(tempConfig);
// Rename ibp1 and re-write config file
final File tempPDir1 = files.get(IDX_IBP1_DIR);
final Path tempPDir1NewPath = Files.createTempDirectory(TEMP_PREFIX);
Files.delete(tempPDir1NewPath);
Files.move(tempPDir1.toPath(), tempPDir1NewPath);
files.set(IDX_IBP1_DIR, tempPDir1NewPath.toFile());
writeIbsConfig(HotDataDef.DEFAULT, files);
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
ibs.start();
try {
for (final Iterator<Entry<byte[], byte[]>> entries = values.entrySet().iterator(); entries
.hasNext();) {
final Entry<byte[], byte[]> entry = entries.next();
final ByteBuffer valueBuf = ibs.get(entry.getKey(), TST_VALUE_LEN, false);
ByteArrays.assertEqualsByteArrays(entry.getValue(), valueBuf.array());
}
}
finally {
ibs.stop();
}
}
finally {
ibs.close();
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test
public void testOpenConfigDirIbpChangedMoveIbp2() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Write some values
final Map<byte[], byte[]> values = writeValues(tempConfig);
// Rename ibp2 and re-write config file
final File tempPDir2 = files.get(IDX_IBP2_DIR);
final Path tempPDir2NewPath = Files.createTempDirectory(TEMP_PREFIX);
Files.delete(tempPDir2NewPath);
Files.move(tempPDir2.toPath(), tempPDir2NewPath);
files.set(IDX_IBP2_DIR, tempPDir2NewPath.toFile());
writeIbsConfig(HotDataDef.DEFAULT, files);
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
ibs.start();
try {
for (final Iterator<Entry<byte[], byte[]>> entries = values.entrySet().iterator(); entries
.hasNext();) {
final Entry<byte[], byte[]> entry = entries.next();
final ByteBuffer valueBuf = ibs.get(entry.getKey(), TST_VALUE_LEN, false);
ByteArrays.assertEqualsByteArrays(entry.getValue(), valueBuf.array());
}
}
finally {
ibs.stop();
}
}
finally {
ibs.close();
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpChangedIbp1Twice() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Add ibp2 again and re-write config file
final File tempPDir1 = files.get(IDX_IBP1_DIR);
files.add(tempPDir1);
writeIbsConfig(HotDataDef.DEFAULT, files);
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpChangedIbp2Twice() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Add ibp2 again and re-write config file
final File tempPDir2 = files.get(IDX_IBP2_DIR);
files.add(tempPDir2);
writeIbsConfig(HotDataDef.DEFAULT, files);
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirIbpChangedSwitchIbpgen() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
// Switch ibpgen and ibp1
final File file = files.remove(IDX_IBPGEN_DIR);
files.add(file);
writeIbsConfig(HotDataDef.DEFAULT, files);
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirUuidChanged() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
File toDel = null;
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
toDel = files.remove(IDX_IBP1_DIR);
writeIbsConfig(HotDataDef.DEFAULT, files, true, false);
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
if (toDel != null) {
io.eguan.utils.Files.deleteRecursive(toDel.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigDirOwnerChanged() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
File toDel = null;
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
toDel = files.remove(IDX_IBP1_DIR);
writeIbsConfig(HotDataDef.DEFAULT, files, false, true);
try {
IbsFactory.openIbs(tempConfig);
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.CONFIG_ERROR, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
if (toDel != null) {
io.eguan.utils.Files.deleteRecursive(toDel.toPath());
}
}
}
@Test
public void testOpenConfigHotDataDefault() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.DEFAULT);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
// Hot data enabled by default
Assert.assertTrue(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test
public void testOpenConfigHotDataOn() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.ON);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
Assert.assertTrue(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test
public void testOpenConfigHotDataOnOff() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.ON);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
{
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
Assert.assertTrue(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
// Switch to OFF
writeIbsConfig(HotDataDef.OFF, files);
{
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
Assert.assertFalse(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test
public void testOpenConfigHotDataOff() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.OFF);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
Assert.assertFalse(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test
public void testOpenConfigHotDataOffOn() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.OFF);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
{
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
Assert.assertFalse(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
// Switch to ON
writeIbsConfig(HotDataDef.ON, files);
{
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
Assert.assertTrue(ibs.isHotDataEnabled());
}
finally {
ibs.close();
}
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
@Test(expected = IbsException.class)
public void testOpenConfigHotDataClosed() throws IOException {
final ArrayList<File> files = createIbs(HotDataDef.ON);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
final Ibs ibs = IbsFactory.openIbs(tempConfig);
ibs.close();
try {
ibs.isHotDataEnabled();
throw new AssertionFailedError("Should not be reached");
}
catch (final IbsException e) {
Assert.assertEquals(IbsErrorCode.INVALID_IBS_ID, e.getErrorCode());
throw e;
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
}
/**
* Base Ibs operations for multi-thread stress test.
*
*
*/
static class IbsOpenClose implements Callable<Boolean> {
final AtomicBoolean goOn = new AtomicBoolean(true);
@Override
public Boolean call() throws Exception {
final ArrayList<File> files = createIbs(HotDataDef.ON);
try {
final File tempConfig = files.get(IDX_CONFIG_FILE);
while (goOn.get()) {
final Ibs ibs = IbsFactory.openIbs(tempConfig);
try {
ibs.start();
ibs.stop();
}
finally {
ibs.close();
}
}
}
finally {
for (final File file : files) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
}
return Boolean.TRUE;
}
}
@Test
public void testOpenIbsMultiThread() throws InterruptedException, ExecutionException {
final int threadCount = Runtime.getRuntime().availableProcessors();
final ExecutorService exec = Executors.newFixedThreadPool(threadCount);
final List<IbsOpenClose> tasks = new ArrayList<>(threadCount);
for (int i = 0; i < threadCount; i++) {
tasks.add(new IbsOpenClose());
}
// Start tasks
final List<Future<Boolean>> threads = new ArrayList<>(threadCount);
for (final IbsOpenClose task : tasks) {
threads.add(exec.submit(task));
}
Thread.sleep(15 * 1000);
// Shutdown tasks
for (final IbsOpenClose task : tasks) {
task.goOn.set(false);
}
// Check tasks run
for (final Future<Boolean> thread : threads) {
Assert.assertTrue(thread.get().booleanValue());
}
}
/**
* Create a IBS for init tests.
*
* @return the first file is the config file.
* @throws IOException
*/
private static final ArrayList<File> createIbs(final HotDataDef hotDataDef) throws IOException {
final ArrayList<File> result = new ArrayList<>();
boolean done = false;
try {
final File tempConfig = File.createTempFile(TEMP_PREFIX, TEMP_SUFFIX);
result.add(tempConfig);
final Path tempDirGen = Files.createTempDirectory(TEMP_PREFIX);
result.add(tempDirGen.toFile());
final Path tempDirP1 = Files.createTempDirectory(TEMP_PREFIX);
result.add(tempDirP1.toFile());
final Path tempDirP2 = Files.createTempDirectory(TEMP_PREFIX);
result.add(tempDirP2.toFile());
// Write config
writeIbsConfig(hotDataDef, result);
final Ibs ibs = IbsFactory.createIbs(tempConfig);
ibs.close();
done = true;
}
finally {
if (!done) {
for (final File file : result) {
io.eguan.utils.Files.deleteRecursive(file.toPath());
}
result.clear();
}
}
return result;
}
private static final void writeIbsConfig(final HotDataDef hotDataDef, final ArrayList<File> configFiles)
throws IOException {
writeIbsConfig(hotDataDef, configFiles, false, false);
}
private static final void writeIbsConfig(final HotDataDef hotDataDef, final ArrayList<File> configFiles,
final boolean altUuid, final boolean altOwner) throws IOException {
// Write config
try (PrintStream config = new PrintStream(configFiles.get(IDX_CONFIG_FILE))) {
config.println(CONF_IBPGEN + configFiles.get(IDX_IBPGEN_DIR).getAbsolutePath());
config.print(CONF_IBP);
for (int i = 2; i < configFiles.size(); i++) {
final File ibpDir = configFiles.get(i);
config.print(ibpDir.getAbsolutePath());
if (i != (configFiles.size() - 1)) {
config.print(',');
}
}
config.println();
if (altUuid)
config.println(CONF_UUID_ALT);
else
config.println(CONF_UUID);
if (altOwner)
config.println(CONF_OWNER_ALT);
else
config.println(CONF_OWNER);
// HotData config
if (hotDataDef == HotDataDef.DEFAULT) {
// nop
}
else if (hotDataDef == HotDataDef.ON) {
config.println(CONF_HOTDATA);
}
else if (hotDataDef == HotDataDef.OFF) {
config.println(CONF_HOTDATA_OFF);
}
else {
throw new AssertionFailedError("Should not be reached");
}
}
}
/**
* Change the value of a key in a IBP config file.
*
* @param ibpConfigFile
* @param key
* @param newValue
* @throws IOException
*/
private static final void changeIbpConfigKey(final File ibpConfigFile, final String key, final String newValue)
throws IOException {
// Load config
final Properties config = new Properties();
try (FileInputStream fis = new FileInputStream(ibpConfigFile)) {
config.load(fis);
}
// Check that the value is defined
Assert.assertNotNull(config.get(key));
config.setProperty(key, newValue);
// Write config
try (PrintStream ps = new PrintStream(ibpConfigFile)) {
final Iterator<Entry<Object, Object>> ite = config.entrySet().iterator();
while (ite.hasNext()) {
final Map.Entry<Object, Object> entry = ite.next();
ps.print(entry.getKey());
ps.print('=');
ps.println(entry.getValue());
}
}
}
/**
* Write random key/value pairs in the IBS.
*
* @param configFile
* IBS config file
* @return the key/value pairs put in the IBS
* @throws NullPointerException
* @throws IbsIOException
* @throws IbsException
*/
private static final Map<byte[], byte[]> writeValues(final File configFile) throws IbsException, IbsIOException,
NullPointerException {
// Compute random values
final Random random = new SecureRandom();
final Map<byte[], byte[]> values = new HashMap<>();
for (int i = 0; i < 32; i++) {
final byte[] key = new byte[TST_KEY_LEN];
random.nextBytes(key);
final byte[] value = new byte[TST_VALUE_LEN];
random.nextBytes(value);
values.put(key, value);
}
// Write values to IBS
final Ibs ibs = IbsFactory.openIbs(configFile);
try {
ibs.start();
try {
for (final Iterator<Entry<byte[], byte[]>> entries = values.entrySet().iterator(); entries.hasNext();) {
final Entry<byte[], byte[]> entry = entries.next();
final ByteBuffer value = ByteBuffer.wrap(entry.getValue());
ibs.put(entry.getKey(), value);
}
}
finally {
ibs.stop();
}
}
finally {
ibs.close();
}
return values;
}
}