| package net.onrc.onos.core.datastore.hazelcast; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.nio.charset.StandardCharsets; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| import net.onrc.onos.core.datastore.IKVTable.IKVEntry; |
| import net.onrc.onos.core.datastore.ObjectDoesntExistException; |
| import net.onrc.onos.core.datastore.ObjectExistsException; |
| import net.onrc.onos.core.datastore.WrongVersionException; |
| import net.onrc.onos.core.datastore.hazelcast.HZTable.VersionedValue; |
| import net.onrc.onos.core.datastore.utils.ByteArrayComparator; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.TestName; |
| |
| public class HZTableTest { |
| @Rule |
| public TestName name = new TestName(); |
| |
| static { |
| // configuration to quickly fall back to instance mode for faster test run |
| System.setProperty("net.onrc.onos.core.datastore.hazelcast.client.attemptLimit", "0"); |
| } |
| |
| static final String TEST_TABLE_NAME = "TableForUnitTest"; |
| HZTable table; |
| |
| @Before |
| public void setUp() throws Exception { |
| table = (HZTable) HZClient.getClient().getTable(TEST_TABLE_NAME); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| HZClient.getClient().dropTable(table); |
| } |
| |
| public void assertEntryInTable(final byte[] key, final byte[] value, final long version) { |
| VersionedValue valueblob = table.getBackendMap().get(key); |
| assertNotNull(valueblob); |
| assertArrayEquals(value, valueblob.getValue()); |
| assertEquals(version, valueblob.getVersion()); |
| } |
| |
| public void assertKeyNotInTable(final byte[] key) { |
| VersionedValue valueblob = table.getBackendMap().get(key); |
| assertNull(valueblob); |
| } |
| |
| @Test |
| public void testGetInitialVersion() { |
| final long version1 = HZTable.getInitialVersion(); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version1); |
| |
| final long version2 = HZTable.getInitialVersion(); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version2); |
| assertNotEquals(version1, version2); |
| } |
| |
| @Test |
| public void testGetNextVersion() { |
| final long nextVersion = HZTable.getNextVersion(1); |
| assertNotEquals(nextVersion, HZClient.VERSION_NONEXISTENT); |
| assertNotEquals(nextVersion, 1); |
| |
| final long nextVersion1 = HZTable.getNextVersion(Long.MAX_VALUE); |
| assertNotEquals(nextVersion1, HZClient.VERSION_NONEXISTENT); |
| assertNotEquals(nextVersion1, Long.MAX_VALUE); |
| |
| final long nextVersion11 = HZTable.getNextVersion(HZClient.VERSION_NONEXISTENT - 1); |
| assertNotEquals(nextVersion11, HZClient.VERSION_NONEXISTENT); |
| assertNotEquals(nextVersion11, HZClient.VERSION_NONEXISTENT - 1); |
| } |
| |
| @Ignore // nothing to test for now |
| @Test |
| public void testHZTable() { |
| fail("Not yet implemented"); |
| } |
| |
| @Test |
| public void testGetTableName() { |
| assertEquals(TEST_TABLE_NAME, table.getTableName()); |
| } |
| |
| @Test |
| public void testVERSION_NONEXISTENT() { |
| assertEquals(HZClient.VERSION_NONEXISTENT, table.getVersionNonexistant()); |
| } |
| |
| @Test |
| public void testGetTableId() { |
| // for Hazelcast implementation IKVTableID is table itself |
| assertEquals(table, table.getTableId()); |
| } |
| |
| @Test |
| public void testCreate() throws ObjectExistsException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| final long version = table.create(key, value); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| |
| assertEntryInTable(key, value, version); |
| } |
| |
| @Test(expected = ObjectExistsException.class) |
| public void testCreateConflict() throws ObjectExistsException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| final long version = table.create(key, value); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| |
| assertEntryInTable(key, value, version); |
| |
| table.create(key, value); |
| fail("Should have thrown exception"); |
| } |
| |
| @Test |
| public void testForceCreate() { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| final long version = table.forceCreate(key, value); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| assertEntryInTable(key, value, version); |
| |
| |
| final long version1 = table.forceCreate(key, value); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version1); |
| assertNotEquals(version, version1); |
| assertEntryInTable(key, value, version1); |
| } |
| |
| @Test |
| public void testRead() throws ObjectDoesntExistException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| // put data to read |
| final long version = table.forceCreate(key, value); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| assertEntryInTable(key, value, version); |
| |
| // test body |
| final IKVEntry readValue = table.read(key); |
| assertArrayEquals(key, readValue.getKey()); |
| assertArrayEquals(value, readValue.getValue()); |
| assertEquals(version, readValue.getVersion()); |
| } |
| |
| |
| @Test(expected = ObjectDoesntExistException.class) |
| public void testReadNotExist() throws ObjectDoesntExistException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| |
| table.read(key); |
| fail("Should have thrown exception"); |
| } |
| |
| @Test |
| public void testUpdateByteArrayByteArrayLongSuccess() throws ObjectDoesntExistException, WrongVersionException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] oldValue = "OldValue".getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| // put data to update |
| final long oldVersion = table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| assertEntryInTable(key, oldValue, oldVersion); |
| |
| final long version = table.update(key, value, oldVersion); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| assertEntryInTable(key, value, version); |
| } |
| |
| @Test(expected = ObjectDoesntExistException.class) |
| public void testUpdateByteArrayByteArrayLongFailNoOldValue() throws ObjectDoesntExistException, WrongVersionException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| final long oldVersion = 0xDEAD; |
| |
| final long version = table.update(key, value, oldVersion); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| assertEntryInTable(key, value, version); |
| } |
| |
| @Test(expected = WrongVersionException.class) |
| public void testUpdateByteArrayByteArrayLongFailWrongVersion() throws ObjectDoesntExistException, WrongVersionException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] oldValue = "OldValue".getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| // put data to update |
| final long oldVersion = table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| assertEntryInTable(key, oldValue, oldVersion); |
| // some one updates (from different thread/process in reality) |
| table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| |
| |
| table.update(key, value, oldVersion); |
| fail("Should have thrown exception"); |
| } |
| |
| @Test |
| public void testUpdateByteArrayByteArraySuccess() throws ObjectDoesntExistException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] oldValue = "OldValue".getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| // put data to update |
| final long oldVersion = table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| assertEntryInTable(key, oldValue, oldVersion); |
| |
| final long version = table.update(key, value); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| assertEntryInTable(key, value, version); |
| } |
| |
| @Test(expected = ObjectDoesntExistException.class) |
| public void testUpdateByteArrayByteArrayFailNoOldValue() throws ObjectDoesntExistException, WrongVersionException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| final long version = table.update(key, value); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| assertEntryInTable(key, value, version); |
| fail("Should have thrown exception"); |
| } |
| |
| @Test |
| public void testUpdateByteArrayByteArraySuccessIgnoreVersion() throws ObjectDoesntExistException, WrongVersionException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] oldValue = "OldValue".getBytes(StandardCharsets.UTF_8); |
| final byte[] value = "SomeValue".getBytes(StandardCharsets.UTF_8); |
| |
| // put data to update |
| final long oldVersion = table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| assertEntryInTable(key, oldValue, oldVersion); |
| // someone updates (from different thread/process in reality) |
| table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| |
| |
| final long version = table.update(key, value); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| assertEntryInTable(key, value, version); |
| } |
| |
| @Test |
| public void testDelete() throws ObjectDoesntExistException, WrongVersionException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] oldValue = "OldValue".getBytes(StandardCharsets.UTF_8); |
| |
| // put data to delete |
| final long oldVersion = table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| assertEntryInTable(key, oldValue, oldVersion); |
| |
| long version = table.delete(key, oldVersion); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| assertEquals(oldVersion, version); |
| assertKeyNotInTable(key); |
| } |
| |
| @Test(expected = ObjectDoesntExistException.class) |
| public void testDeleteFailNoEntry() throws ObjectDoesntExistException, WrongVersionException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| |
| final long oldVersion = 0xDEAD; |
| |
| try { |
| table.delete(key, oldVersion); |
| } catch (ObjectDoesntExistException | WrongVersionException e) { |
| assertKeyNotInTable(key); |
| throw e; |
| } |
| fail("Should have thrown exception"); |
| } |
| |
| @Test(expected = WrongVersionException.class) |
| public void testDeleteFailWrongVersion() throws ObjectDoesntExistException, WrongVersionException { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] oldValue = "OldValue".getBytes(StandardCharsets.UTF_8); |
| |
| // put data to delete |
| final long oldVersion = table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| assertEntryInTable(key, oldValue, oldVersion); |
| // someone updates (from different thread/process in reality) |
| final long latestVersion = table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, latestVersion); |
| |
| try { |
| table.delete(key, oldVersion); |
| } catch (ObjectDoesntExistException | WrongVersionException e) { |
| assertEntryInTable(key, oldValue, latestVersion); |
| throw e; |
| } |
| fail("Should have thrown exception"); |
| } |
| |
| |
| @Test |
| public void testForceDelete() { |
| final byte[] key = name.getMethodName().getBytes(StandardCharsets.UTF_8); |
| final byte[] oldValue = "OldValue".getBytes(StandardCharsets.UTF_8); |
| |
| // put data to delete |
| final long oldVersion = table.forceCreate(key, oldValue); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| assertEntryInTable(key, oldValue, oldVersion); |
| |
| long version = table.forceDelete(key); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, oldVersion); |
| assertEquals(oldVersion, version); |
| assertKeyNotInTable(key); |
| } |
| |
| @Test |
| public void testGetAllEntries() { |
| final int DATASETSIZE = 100; |
| final Map<byte[], VersionedValue> testdata = new TreeMap<>(ByteArrayComparator.BYTEARRAY_COMPARATOR); |
| for (int i = 0; i < DATASETSIZE; ++i) { |
| final byte[] key = (name.getMethodName() + i).getBytes(StandardCharsets.UTF_8); |
| final byte[] value = ("Value" + i).getBytes(StandardCharsets.UTF_8); |
| |
| // put data to delete |
| final long version = table.forceCreate(key, value); |
| assertNotEquals(HZClient.VERSION_NONEXISTENT, version); |
| assertEntryInTable(key, value, version); |
| |
| testdata.put(key, new VersionedValue(value, version)); |
| } |
| |
| Iterable<IKVEntry> datastore = table.getAllEntries(); |
| for (IKVEntry entry : datastore) { |
| VersionedValue expectedValue = testdata.get(entry.getKey()); |
| assertNotNull(expectedValue); |
| assertArrayEquals(expectedValue.getValue(), entry.getValue()); |
| assertEquals(expectedValue.getVersion(), entry.getVersion()); |
| |
| testdata.remove(entry.getKey()); |
| } |
| |
| assertTrue(testdata.isEmpty()); |
| } |
| |
| @Test |
| public void testToString() { |
| assertEquals("[HZTable " + TEST_TABLE_NAME + "]", table.toString()); |
| } |
| |
| } |