package com.jivesoftware.os.amzabot.deployable;
import com.jivesoftware.os.amza.api.PartitionClient;
import com.jivesoftware.os.amza.api.PartitionClientProvider;
import com.jivesoftware.os.amza.api.RingPartitionProperties;
import com.jivesoftware.os.amza.api.partition.Consistency;
import com.jivesoftware.os.amza.api.partition.Durability;
import com.jivesoftware.os.amza.api.partition.PartitionName;
import com.jivesoftware.os.amza.api.partition.PartitionProperties;
import com.jivesoftware.os.amza.api.ring.RingMember;
import com.jivesoftware.os.amza.api.wal.KeyUtil;
import com.jivesoftware.os.amza.client.test.InMemoryPartitionClient;
import com.jivesoftware.os.amzabot.deployable.bot.AmzaBotRandomOpConfig;
import com.jivesoftware.os.amzabot.deployable.bot.AmzaBotRandomOpService;
import com.jivesoftware.os.jive.utils.ordered.id.ConstantWriterIdProvider;
import com.jivesoftware.os.jive.utils.ordered.id.OrderIdProvider;
import com.jivesoftware.os.jive.utils.ordered.id.OrderIdProviderImpl;
import com.jivesoftware.os.mlogger.core.AtomicCounter;
import com.jivesoftware.os.mlogger.core.ValueType;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import org.merlin.config.BindInterfaceToConfiguration;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class AmzaBotRandomOpTest {
private AmzaBotRandomOpService service;
private AmzaKeyClearingHouse amzaKeyClearingHouse;
private AmzaBotRandomOpConfig config;
@BeforeMethod
public void setUp() throws Exception {
OrderIdProvider orderIdProvider = new OrderIdProviderImpl(
new ConstantWriterIdProvider(1));
Map<PartitionName, PartitionClient> indexes = new ConcurrentHashMap<>();
PartitionClientProvider partitionClientProvider = new PartitionClientProvider() {
@Override
public PartitionClient getPartition(PartitionName partitionName) throws Exception {
return indexes.computeIfAbsent(partitionName,
partitionName1 -> new InMemoryPartitionClient(new RingMember("member1"),
new ConcurrentSkipListMap<>(),
new ConcurrentSkipListMap<>(KeyUtil.lexicographicalComparator()),
orderIdProvider));
}
@Override
public PartitionClient getPartition(PartitionName partitionName, int desiredRingSize, PartitionProperties partitionProperties) throws Exception {
return getPartition(partitionName);
}
@Override
public RingPartitionProperties getProperties(PartitionName partitionName) throws Exception {
return null;
}
};
AmzaBotConfig amzaBotConfig = BindInterfaceToConfiguration.bindDefault(AmzaBotConfig.class);
config = BindInterfaceToConfiguration.bindDefault(AmzaBotRandomOpConfig.class);
config.setEnabled(false);
config.setHesitationFactorMs(100);
config.setWriteThreshold(100L);
config.setValueSizeThreshold(20);
config.setDurability("fsync_async");
config.setConsistency("leader_quorum");
config.setRingSize(1);
config.setRetryWaitMs(100);
config.setSnapshotFrequency(10);
config.setClientOrdering(false);
config.setBatchFactor(100);
config.setTombstoneTimestampAgeInMillis(60 * 60 * 1_000);
config.setTombstoneTimestampIntervalMillis(30 * 60 * 1_000);
amzaKeyClearingHouse = new AmzaKeyClearingHouse();
service = new AmzaBotRandomOpService(
config,
new AmzaBotService(amzaBotConfig,
partitionClientProvider,
() -> -1L,
Durability.valueOf(config.getDurability()),
Consistency.valueOf(config.getConsistency()),
"amzabot-randomop-test",
config.getRingSize(),
config.getTombstoneTimestampAgeInMillis(),
config.getTombstoneTimestampIntervalMillis()),
amzaKeyClearingHouse);
service.start();
}
@AfterMethod
public void tearDown() throws Exception {
service.stop();
}
@Test
public void testWaitOnProcessor() throws InterruptedException {
Thread.sleep(1_000);
System.out.println("Outstanding key count: " +
amzaKeyClearingHouse.getKeyMap().size());
Assert.assertEquals(amzaKeyClearingHouse.getQuarantinedKeyMap().size(), 0);
service.clearKeyMap();
service.clearQuarantinedKeyMap();
// success
}
@Test
public void testCRUDRandomOp() throws Exception {
boolean create, read, update, delete, batchWrite, batchDelete;
create = read = update = delete = batchWrite = batchDelete = false;
AtomicCounter seq = new AtomicCounter(ValueType.COUNT);
while (!create || !read || !update || !delete || !batchWrite || !batchDelete) {
int op = service.randomOp("test:" + String.valueOf(seq.getValue()));
if (op == 0) {
read = true;
} else if (op == 1) {
delete = true;
} else if (op == 2) {
batchWrite = true;
} else if (op == 3) {
batchDelete = true;
} else if (op == 4) {
update = true;
} else {
create = true;
}
seq.inc();
}
Assert.assertEquals(amzaKeyClearingHouse.getQuarantinedKeyMap().size(), 0);
service.clearKeyMap();
service.clearQuarantinedKeyMap();
// success
}
@Test
public void testMultipleRandomOps() throws Exception {
AtomicCounter seq = new AtomicCounter(ValueType.COUNT);
for (int i = 0; i < 10; i++) {
service.randomOp("test:" + String.valueOf(seq.getValue()));
if (config.getHesitationFactorMs() > 0) {
Thread.sleep(new Random().nextInt(config.getHesitationFactorMs()));
}
seq.inc();
}
System.out.println("Outstanding key count: " +
amzaKeyClearingHouse.getKeyMap().size());
Assert.assertEquals(amzaKeyClearingHouse.getQuarantinedKeyMap().size(), 0);
service.clearKeyMap();
service.clearQuarantinedKeyMap();
// success
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void validateInvalidRandomRange() throws Exception {
Assert.assertEquals(new Random().nextInt(0), 0);
}
@Test
public void validateRandomRange() throws Exception {
Assert.assertEquals(new Random().nextInt(1), 0);
}
}