package com.netflix.astyanax.entitystore;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.google.common.collect.ImmutableMap;
import com.netflix.astyanax.AstyanaxContext;
import com.netflix.astyanax.Keyspace;
import com.netflix.astyanax.connectionpool.NodeDiscoveryType;
import com.netflix.astyanax.connectionpool.impl.ConnectionPoolConfigurationImpl;
import com.netflix.astyanax.connectionpool.impl.ConnectionPoolType;
import com.netflix.astyanax.connectionpool.impl.CountingConnectionPoolMonitor;
import com.netflix.astyanax.entitystore.NullableEntity.AllMandatoryNestedEntity;
import com.netflix.astyanax.entitystore.NullableEntity.AllOptionalNestedEntity;
import com.netflix.astyanax.impl.AstyanaxConfigurationImpl;
import com.netflix.astyanax.model.ColumnFamily;
import com.netflix.astyanax.model.ColumnList;
import com.netflix.astyanax.serializers.StringSerializer;
import com.netflix.astyanax.thrift.ThriftFamilyFactory;
import com.netflix.astyanax.util.SingletonEmbeddedCassandra;
public class DefaultEntityManagerNullableTest {
private static Keyspace keyspace;
private static AstyanaxContext<Keyspace> keyspaceContext;
private static String TEST_CLUSTER_NAME = "junit_cass_sandbox";
private static String TEST_KEYSPACE_NAME = "EntityPersisterTestKeyspace";
private static final String SEEDS = "localhost:9160";
public static ColumnFamily<String, String> CF_SAMPLE_ENTITY = ColumnFamily.newColumnFamily(
"SampleEntityColumnFamily",
StringSerializer.get(),
StringSerializer.get());
public static ColumnFamily<String, String> CF_SIMPLE_ENTITY = ColumnFamily.newColumnFamily(
"SimpleEntityColumnFamily",
StringSerializer.get(),
StringSerializer.get());
@BeforeClass
public static void setup() throws Exception {
SingletonEmbeddedCassandra.getInstance();
Thread.sleep(1000 * 3);
createKeyspace();
Thread.sleep(1000 * 3);
}
@AfterClass
public static void teardown() throws Exception {
if (keyspaceContext != null)
keyspaceContext.shutdown();
Thread.sleep(1000 * 10);
}
private static void createKeyspace() throws Exception {
keyspaceContext = new AstyanaxContext.Builder()
.forCluster(TEST_CLUSTER_NAME)
.forKeyspace(TEST_KEYSPACE_NAME)
.withAstyanaxConfiguration(
new AstyanaxConfigurationImpl()
.setDiscoveryType(NodeDiscoveryType.RING_DESCRIBE)
.setConnectionPoolType(ConnectionPoolType.ROUND_ROBIN))
.withConnectionPoolConfiguration(
new ConnectionPoolConfigurationImpl(TEST_CLUSTER_NAME
+ "_" + TEST_KEYSPACE_NAME)
.setSocketTimeout(30000)
.setMaxTimeoutWhenExhausted(2000)
.setMaxConnsPerHost(20)
.setInitConnsPerHost(10)
.setSeeds(SEEDS))
.withConnectionPoolMonitor(new CountingConnectionPoolMonitor())
.buildKeyspace(ThriftFamilyFactory.getInstance());
keyspaceContext.start();
keyspace = keyspaceContext.getEntity();
try {
keyspace.dropKeyspace();
}
catch (Exception e) {
e.printStackTrace();
}
keyspace.createKeyspace(ImmutableMap.<String, Object>builder()
.put("strategy_options", ImmutableMap.<String, Object>builder()
.put("replication_factor", "1")
.build())
.put("strategy_class", "SimpleStrategy")
.build()
);
keyspace.createColumnFamily(CF_SAMPLE_ENTITY, null);
keyspace.createColumnFamily(CF_SIMPLE_ENTITY, null);
}
private NullableEntity createNullableEntity(final String id) {
NullableEntity entity = new NullableEntity();
entity.setId(id);
entity.setNotnullable("notnullable");
entity.setNullable("nullable");
AllOptionalNestedEntity notnullableAllOptionalNestedEntity = new AllOptionalNestedEntity();
notnullableAllOptionalNestedEntity.setNullable("notnullableAllOptionalNestedEntity");
entity.setNotnullableAllOptionalNestedEntity(notnullableAllOptionalNestedEntity);
AllOptionalNestedEntity nullableAllOptionalNestedEntity = new AllOptionalNestedEntity();
nullableAllOptionalNestedEntity.setNullable("nullableAllOptionalNestedEntity");
entity.setNullableAllOptionalNestedEntity(nullableAllOptionalNestedEntity);
AllMandatoryNestedEntity notnullableAllMandatoryNestedEntity = new AllMandatoryNestedEntity();
notnullableAllMandatoryNestedEntity.setNotnullable("notnullableAllMandatoryNestedEntity");
entity.setNotnullableAllMandatoryNestedEntity(notnullableAllMandatoryNestedEntity);
AllMandatoryNestedEntity nullableAllMandatoryNestedEntity = new AllMandatoryNestedEntity();
nullableAllMandatoryNestedEntity.setNotnullable("nullableAllMandatoryNestedEntity");
entity.setNullableAllMandatoryNestedEntity(nullableAllMandatoryNestedEntity);
return entity;
}
@Test
public void nullableColumn() throws Exception {
final String id = "nullableColumn";
EntityManager<NullableEntity, String> entityPersister = new DefaultEntityManager.Builder<NullableEntity, String>()
.withEntityType(NullableEntity.class)
.withKeyspace(keyspace)
.withColumnFamily(CF_SAMPLE_ENTITY)
.build();
NullableEntity origEntity = createNullableEntity(id);
origEntity.setNullable(null);
entityPersister.put(origEntity);
// use low-level astyanax API to confirm the null column
// is not written as empty column
{
ColumnList<String> cl = keyspace.prepareQuery(CF_SAMPLE_ENTITY).getKey(id).execute().getResult();
// test column number
Assert.assertEquals(5, cl.size());
// assert non-existent
Assert.assertNull(cl.getColumnByName("nullable"));
// test column value
Assert.assertEquals(origEntity.getNotnullable(), cl.getColumnByName("notnullable").getStringValue());
}
NullableEntity getEntity = entityPersister.get(id);
assertNull(getEntity.getNullable());
assertEquals(origEntity, getEntity);
entityPersister.delete(id);
// use low-level astyanax API to confirm the delete
{
ColumnList<String> cl = keyspace.prepareQuery(CF_SAMPLE_ENTITY).getKey(id).execute().getResult();
Assert.assertEquals(0, cl.size());
}
}
@Test
public void expectNullColumnException() throws Exception {
final String id = "expectNullColumnException";
try {
EntityManager<NullableEntity, String> entityPersister = new DefaultEntityManager.Builder<NullableEntity, String>()
.withEntityType(NullableEntity.class)
.withKeyspace(keyspace)
.withColumnFamily(CF_SAMPLE_ENTITY)
.build();
NullableEntity origEntity = createNullableEntity(id);
origEntity.setNotnullable(null);
entityPersister.put(origEntity);
} catch(PersistenceException e) {
// catch expected exception and verify the cause
Throwable rootCause = ExceptionUtils.getRootCause(e);
assertEquals(IllegalArgumentException.class, rootCause.getClass());
assertEquals("cannot write non-nullable column with null value: notnullable", rootCause.getMessage());
}
}
@Test
public void nullableNestedColumn() throws Exception {
final String id = "nullableNestedColumn";
EntityManager<NullableEntity, String> entityPersister = new DefaultEntityManager.Builder<NullableEntity, String>()
.withEntityType(NullableEntity.class)
.withKeyspace(keyspace)
.withColumnFamily(CF_SAMPLE_ENTITY)
.build();
NullableEntity origEntity = createNullableEntity(id);
origEntity.setNullableAllOptionalNestedEntity(null);
origEntity.getNotnullableAllOptionalNestedEntity().setNullable(null);
entityPersister.put(origEntity);
// use low-level astyanax API to confirm the null column
// is not written as empty column
{
ColumnList<String> cl = keyspace.prepareQuery(CF_SAMPLE_ENTITY).getKey(id).execute().getResult();
// test column number
Assert.assertEquals(4, cl.size());
// assert non-existent
Assert.assertNull(cl.getColumnByName("nullableAllOptionalNestedEntity.nullable"));
Assert.assertNull(cl.getColumnByName("notnullableAllOptionalNestedEntity.nullable"));
// test column value
Assert.assertEquals(origEntity.getNotnullable(), cl.getColumnByName("notnullable").getStringValue());
Assert.assertEquals(origEntity.getNullable(), cl.getColumnByName("nullable").getStringValue());
Assert.assertEquals(origEntity.getNotnullableAllMandatoryNestedEntity().getNotnullable(), cl.getColumnByName("notnullableAllMandatoryNestedEntity.notnullable").getStringValue());
Assert.assertEquals(origEntity.getNullableAllMandatoryNestedEntity().getNotnullable(), cl.getColumnByName("nullableAllMandatoryNestedEntity.notnullable").getStringValue());
}
NullableEntity getEntity = entityPersister.get(id);
Assert.assertNull(getEntity.getNullableAllOptionalNestedEntity());
// note this is special. it is NOT null
// Assert.assertNotNull(getEntity.getNotnullableAllOptionalNestedEntity());
// Assert.assertNull(getEntity.getNotnullableAllOptionalNestedEntity().getNullable());
// Assert.assertEquals(origEntity, getEntity);
entityPersister.delete(id);
// use low-level astyanax API to confirm the delete
{
ColumnList<String> cl = keyspace.prepareQuery(CF_SAMPLE_ENTITY).getKey(id).execute().getResult();
Assert.assertEquals(0, cl.size());
}
}
@Test
public void expectNullColumnExceptionNotnullableAllOptionalNestedEntity() throws Exception {
final String id = "expectNullColumnExceptionNotnullableAllOptionalNestedEntity";
try {
EntityManager<NullableEntity, String> entityPersister = new DefaultEntityManager.Builder<NullableEntity, String>()
.withEntityType(NullableEntity.class)
.withKeyspace(keyspace)
.withColumnFamily(CF_SAMPLE_ENTITY)
.build();
NullableEntity origEntity = createNullableEntity(id);
origEntity.setNotnullableAllOptionalNestedEntity(null);
entityPersister.put(origEntity);
} catch(PersistenceException e) {
// catch expected exception and verify the cause
Throwable rootCause = ExceptionUtils.getRootCause(e);
assertEquals(IllegalArgumentException.class, rootCause.getClass());
assertEquals("cannot write non-nullable column with null value: notnullableAllOptionalNestedEntity", rootCause.getMessage());
}
}
@Test
public void expectNullColumnExceptionNotnullableAllMandatoryNestedEntity() throws Exception {
final String id = "expectNullColumnExceptionNotnullableAllMandatoryNestedEntity";
try {
EntityManager<NullableEntity, String> entityPersister = new DefaultEntityManager.Builder<NullableEntity, String>()
.withEntityType(NullableEntity.class)
.withKeyspace(keyspace)
.withColumnFamily(CF_SAMPLE_ENTITY)
.build();
NullableEntity origEntity = createNullableEntity(id);
origEntity.setNotnullableAllMandatoryNestedEntity(null);
entityPersister.put(origEntity);
} catch(PersistenceException e) {
// catch expected exception and verify the cause
Throwable rootCause = ExceptionUtils.getRootCause(e);
assertEquals(IllegalArgumentException.class, rootCause.getClass());
assertEquals("cannot write non-nullable column with null value: notnullableAllMandatoryNestedEntity", rootCause.getMessage());
}
}
@Test
public void expectNestedNullColumnExceptionNullableAllMandatoryNestedEntityNullChild() throws Exception {
final String id = "expectNestedNullColumnException";
try {
EntityManager<NullableEntity, String> entityPersister = new DefaultEntityManager.Builder<NullableEntity, String>()
.withEntityType(NullableEntity.class)
.withKeyspace(keyspace)
.withColumnFamily(CF_SAMPLE_ENTITY)
.build();
NullableEntity origEntity = createNullableEntity(id);
origEntity.getNullableAllMandatoryNestedEntity().setNotnullable(null);
entityPersister.put(origEntity);
} catch(PersistenceException e) {
// catch expected exception and verify the cause
Throwable rootCause = ExceptionUtils.getRootCause(e);
assertEquals(IllegalArgumentException.class, rootCause.getClass());
assertEquals("cannot write non-nullable column with null value: notnullable", rootCause.getMessage());
}
}
}