package org.rhq.plugins.storage;
import static org.testng.Assert.assertEquals;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.rhq.cassandra.util.ConfigEditor;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.util.file.FileUtil;
import org.rhq.core.util.stream.StreamUtil;
/**
* @author John Sanda
*/
public class StorageNodeConfigDelegateTest {
private File basedir;
private File cassandraYamlFile;
private StorageNodeConfigDelegate configDelegate;
@BeforeMethod
public void initDirs(Method test) throws Exception {
File dir = new File(getClass().getResource(".").toURI());
basedir = new File(dir, getClass().getSimpleName() + "/" + test.getName());
FileUtil.purge(basedir, true);
configDelegate = new StorageNodeConfigDelegate(basedir, null);
cassandraYamlFile = new File(confDir(), "cassandra.yaml");
InputStream inputStream = getClass().getResourceAsStream("/cassandra.yaml");
FileOutputStream outputStream = new FileOutputStream(cassandraYamlFile);
StreamUtil.copy(inputStream, outputStream);
}
@Test
public void loadValidConfig() throws Exception {
createDefaultConfig();
Configuration config = configDelegate.loadResourceConfiguration();
assertEquals(config.getSimpleValue("minHeapSize"), "512M", "Failed to load property [minHeapSize]");
assertEquals(config.getSimpleValue("maxHeapSize"), "512M", "Failed to load property [maxHepSize]");
assertEquals(config.getSimpleValue("heapNewSize"), "128M", "Failed to load property [heapNewSize]");
assertEquals(config.getSimpleValue("threadStackSize"), "180", "Failed to load property [threadStackSize]");
assertEquals(config.getSimple("heapDumpOnOOMError").getBooleanValue(), (Boolean) true,
"Failed to load property [heapDumpOnOOMError]");
assertEquals(new File(config.getSimpleValue("heapDumpDir")), binDir(), "Failed to load property [heapDumpDir]");
}
@Test
public void updateValidConfig() throws Exception {
createDefaultConfig();
Configuration config = Configuration.builder()
.addSimple("minHeapSize", "1024M")
.addSimple("maxHeapSize", "1024M")
.addSimple("heapNewSize", "256M")
.addSimple("threadStackSize", "240")
.addSimple("heapDumpOnOOMError", true)
.addSimple("heapDumpDir", confDir())
.addSimple("cqlPort", 9595)
.addSimple("gossipPort", 9696)
.build();
// config.put(new PropertySimple("minHeapSize", "1024M"));
// config.put(new PropertySimple("maxHeapSize", "1024M"));
// config.put(new PropertySimple("heapNewSize", "256M"));
// config.put(new PropertySimple("threadStackSize", "240"));
// config.put(new PropertySimple("heapDumpOnOOMError", true));
// config.put(new PropertySimple("heapDumpDir", confDir()));
// config.put(new PropertySimple("cqlPort", 9595));
// config.put(new PropertySimple("gossipPort", 9696));
ConfigurationUpdateReport report = new ConfigurationUpdateReport(config);
configDelegate.updateResourceConfiguration(report);
Properties properties = loadCassandraJvmProps();
assertEquals(properties.getProperty("heap_min"), "-Xms1024M", "Failed to update property [minHeapSize]");
assertEquals(properties.getProperty("heap_max"), "-Xmx1024M", "Failed to update property [maxHeapSize]");
assertEquals(properties.getProperty("heap_new"), "-Xmn256M", "Failed to update property [heapNewSize]");
assertEquals(properties.getProperty("thread_stack_size"), "-Xss240k",
"Failed to update property [threadStackSize]");
assertEquals(properties.getProperty("heap_dump_on_OOMError"), "-XX:+HeapDumpOnOutOfMemoryError",
"Failed to update property [heap_dump_on_OOMError]");
assertEquals(properties.getProperty("heap_dump_dir"), confDir().getAbsolutePath(),
"Failed to update property [heap_dump_dir]");
ConfigEditor yamlEditor = new ConfigEditor(cassandraYamlFile);
yamlEditor.load();
assertEquals(yamlEditor.getNativeTransportPort(), (Integer) 9595, "Failed to update native_transport_port");
assertEquals(yamlEditor.getStoragePort(), (Integer) 9696, "Failed to update storage_port");
}
@Test
public void minHeapSizeShouldBeTheSameAsMaxHeapSize() throws Exception {
createDefaultConfig();
Configuration config = new Configuration();
config.put(new PropertySimple("minHeapSize", "512M"));
config.put(new PropertySimple("maxHeapSize", "768M"));
ConfigurationUpdateReport report = new ConfigurationUpdateReport(config);
configDelegate.updateResourceConfiguration(report);
Properties properties = loadCassandraJvmProps();
assertEquals(properties.getProperty("heap_max"), "-Xmx768M", "Failed to update property [maxHeapSize]");
assertEquals(properties.getProperty("heap_min"), "-Xms768M", "Failed to update property [maxHeapSize]. It " +
"should be the same as [maxHeapSize].");
}
@Test
public void disableHeapDumps() throws Exception {
createDefaultConfig();
ConfigurationUpdateReport report = new ConfigurationUpdateReport(Configuration.builder()
.addSimple("heapDumpOnOOMError", false).build());
configDelegate.updateResourceConfiguration(report);
Properties properties = loadCassandraJvmProps();
assertEquals(properties.getProperty("heap_dump_on_OOMError"), "", "Failed to disable property " +
"[heapDumpOnOOMError]");
}
@Test
public void updateShouldFailWhenMaxHeapSizeIsInvalid() throws Exception {
createDefaultConfig();
ConfigurationUpdateReport report = new ConfigurationUpdateReport(Configuration.builder()
.addSimple("maxHeapSize", "256GB").build());
configDelegate.updateResourceConfiguration(report);
assertEquals(report.getStatus(), ConfigurationUpdateStatus.FAILURE, "The configuration update should fail " +
"when [maxHeapSize] has an invalid value.");
}
@Test
public void updateShouldFailWhenHeapNewSizeIsInvalid() throws Exception {
createDefaultConfig();
ConfigurationUpdateReport report = new ConfigurationUpdateReport(Configuration.builder()
.addSimple("heapNewSize", "25^G").build());
configDelegate.updateResourceConfiguration(report);
assertEquals(report.getStatus(), ConfigurationUpdateStatus.FAILURE, "The configuration update should fail " +
"when [heapNewSize] has an invalid value.");
}
@Test
public void updateShouldFailWhenThreadStackSizeIsInvalid() throws Exception {
createDefaultConfig();
ConfigurationUpdateReport report = new ConfigurationUpdateReport(Configuration.builder()
.addSimple("threadStackSize", "128M").build());
configDelegate.updateResourceConfiguration(report);
assertEquals(report.getStatus(), ConfigurationUpdateStatus.FAILURE, "The configuration update should fail " +
"when [threadStackSize] has an invalid value.");
}
private void createDefaultConfig() throws IOException {
Properties properties = new Properties();
properties.setProperty("heap_min", "-Xms512M");
properties.setProperty("heap_max", "-Xmx512M");
properties.setProperty("heap_new", "-Xmn128M");
properties.setProperty("thread_stack_size", "-Xss180k");
properties.setProperty("heap_dump_on_OOMError", "-XX:+HeapDumpOnOutOfMemoryError");
properties.setProperty("heap_dump_dir", binDir().getAbsolutePath());
properties.store(new FileOutputStream(new File(confDir(), "cassandra-jvm.properties")), "");
}
private Properties loadCassandraJvmProps() throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream(new File(confDir(), "cassandra-jvm.properties")));
return properties;
}
private File confDir() {
return mkdirIfNecessary(basedir, "conf");
}
private File binDir() {
return mkdirIfNecessary(basedir, "bin");
}
private File mkdirIfNecessary(File parent, String path) {
File dir = new File(parent, path);
if (!dir.exists()) {
dir.mkdirs();
}
return dir;
}
}