/*
* Copyright 2010 Outerthought bvba
*
* 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.
*/
package org.lilyproject.repository.impl.test;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.junit.Test;
import org.lilyproject.repository.api.IdGenerator;
import org.lilyproject.repository.api.RecordId;
import org.lilyproject.repository.impl.id.IdGeneratorImpl;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class IdGeneratorImplTest {
@Test
public void testRandomUUID() {
UUID newUUid = UUID.randomUUID();
String uuidString = newUUid.toString();
UUID uuidFromString = UUID.fromString(uuidString);
assertEquals(uuidFromString.toString(), uuidString);
}
@Test
public void testIdGeneratorDefault() {
IdGenerator idGenerator = new IdGeneratorImpl();
RecordId recordId = idGenerator.newRecordId();
assertEquals(recordId, idGenerator.fromBytes(recordId.toBytes()));
assertEquals(recordId, idGenerator.fromString(recordId.toString()));
}
@Test
public void testUUID() {
IdGenerator idGenerator = new IdGeneratorImpl();
// Test string representation
String uuidRecordIDString = "UUID.d27cdb6e-ae6d-11cf-96b8-444553540000";
assertEquals(uuidRecordIDString, idGenerator.fromString(uuidRecordIDString).toString());
// Check it's not recognized as a variant
assertTrue(idGenerator.fromString(uuidRecordIDString).isMaster());
// Test bytes representation
byte[] uuidRecordIdBytes = new byte[] {1, -46, 124, -37, 110, -82, 109, 17, -49, -106, -72, 68, 69, 83, 84, 0, 0};
assertArrayEquals(uuidRecordIdBytes, idGenerator.fromBytes(uuidRecordIdBytes).toBytes());
assertEquals(uuidRecordIDString, idGenerator.fromBytes(uuidRecordIdBytes).toString());
}
@Test
public void testUSER() {
IdGenerator idGenerator = new IdGeneratorImpl();
RecordId newRecordId = idGenerator.newRecordId("aUserId");
String userRecordIDString = "USER.aUserId";
// Check it's not recognized as a variant
assertTrue(newRecordId.isMaster());
// Test string representation
assertEquals(newRecordId, idGenerator.fromString(userRecordIDString));
assertEquals(userRecordIDString, idGenerator.fromString(userRecordIDString).toString());
// Test bytes representation cycle
byte[] userRecordIdBytes = newRecordId.toBytes();
assertArrayEquals(userRecordIdBytes, idGenerator.fromBytes(userRecordIdBytes).toBytes());
assertEquals(userRecordIDString, idGenerator.fromBytes(userRecordIdBytes).toString());
// Test the bytes representation is really what we expect it to be
byte[] idBytes = new byte[] {0, 65, 66, 67};
String idString = "USER.ABC";
assertArrayEquals(idBytes, idGenerator.fromString(idString).toBytes());
byte[] withDotsBytes = new byte[] { 0, 65, 66, ':', 67, 68, '.', 69, 70 };
String withDots = "USER.AB:CD\\.EF";
assertArrayEquals(withDotsBytes, idGenerator.fromString(withDots).toBytes());
}
@Test
public void testUUIDWithVariantSingleProperty() {
IdGenerator idGenerator = new IdGeneratorImpl();
RecordId masterRecordId = idGenerator.newRecordId();
Map<String, String> variantProperties = new HashMap<String, String>();
variantProperties.put("dim1", "dimvalue1");
RecordId variantRecordId = idGenerator.newRecordId(masterRecordId, variantProperties);
// Test it is recognized as variant
assertFalse(variantRecordId.isMaster());
// Test string representation is what it is supposed to be
String variantRecordIdString = masterRecordId.toString() + ".dim1=dimvalue1";
assertEquals(variantRecordIdString, variantRecordId.toString());
assertEquals(variantRecordId, idGenerator.fromString(variantRecordIdString));
// Test round-trip string & bytes conversion
assertEquals(variantRecordId, idGenerator.fromString(variantRecordId.toString()));
assertEquals(variantRecordId, idGenerator.fromBytes(variantRecordId.toBytes()));
// Test bytes representation is really what we expect it to be
byte[] masterIdBytes = new byte[] {
/* uuid type marker */1,
/* uuid bytes */-46, 124, -37, 110, -82, 109, 17, -49, -106, -72, 68, 69, 83, 84, 0, 0 };
byte[] variantIdBytes = new byte[] {
/* uuid type marker */1,
/* uuid bytes */-46, 124, -37, 110, -82, 109, 17, -49, -106, -72, 68, 69, 83, 84, 0, 0
/* length of key (vint) */, 1
/* the key (letter X) */, 88
/* length of value (vint) */, 3
/* the value (ABC) */, 65, 66, 67 };
RecordId variantId = idGenerator.newRecordId(idGenerator.fromBytes(masterIdBytes),
Collections.singletonMap("X", "ABC"));
assertArrayEquals(variantIdBytes, variantId.toBytes());
}
@Test
public void testUUUIDWithMultipleProperties() {
IdGenerator idGenerator = new IdGeneratorImpl();
RecordId masterRecordId = idGenerator.newRecordId();
Map<String, String> variantProperties = new HashMap<String, String>();
variantProperties.put("dim1", "dimvalue1");
variantProperties.put("dim2", "dimvalue2");
RecordId variantRecordId = idGenerator.newRecordId(masterRecordId, variantProperties);
// Test string representation is what it is supposed to be
String variantRecordIdString = masterRecordId.toString() + ".dim1=dimvalue1,dim2=dimvalue2";
assertEquals(variantRecordIdString, variantRecordId.toString());
assertEquals(variantRecordId, idGenerator.fromString(variantRecordIdString));
// Test round-trip string & bytes conversion
assertEquals(variantRecordId, idGenerator.fromString(variantRecordIdString));
assertEquals(variantRecordId, idGenerator.fromBytes(variantRecordId.toBytes()));
}
@Test
public void testUserIdWithVariantProperties() {
IdGenerator idGenerator = new IdGeneratorImpl();
RecordId masterId = idGenerator.newRecordId("marvellous");
Map<String, String> variantProperties = new HashMap<String, String>();
variantProperties.put("a", "x");
variantProperties.put("aa", "xx");
RecordId variantId = idGenerator.newRecordId(masterId, variantProperties);
// Test it is recognized as variant
assertFalse(variantId.isMaster());
// Test round-trip string & bytes conversion
assertEquals(variantId, idGenerator.fromBytes(variantId.toBytes()));
assertEquals(variantId, idGenerator.fromString(variantId.toString()));
// Test string representation is what it is supposed to be
String expectedString = "USER.marvellous.a=x,aa=xx";
assertEquals(expectedString, variantId.toString());
// Test bytes representation is what it is supposed to be
// Note that the keys should always be in sorted order
byte[] variantIdBytes = new byte[] {
/* user type marker */0,
/* 'marvellous' as bytes */109, 97, 114, 118, 101, 108, 108, 111, 117, 115,
/* separator byte between id and the props */0,
/* -- first property -- */
/* length of key */1,
/* the key (a) */97,
/* length of value */1,
/* the value (x) */120,
/* -- second property -- */
/* length of key */2,
/* the key (aa) */97, 97,
/* length of value */2,
/* the value (xx) */120, 120
};
assertArrayEquals(variantIdBytes, variantId.toBytes());
}
@Test
public void testNullCharacterNotAllowedInUserId() {
IdGenerator idGenerator = new IdGeneratorImpl();
try {
idGenerator.fromString("USER.hello\u0000world");
fail("Expected an exception when using zero byte in string.");
} catch (IllegalArgumentException e) {
// expected
}
try {
idGenerator.newRecordId("hello\u0000world");
fail("Expected an exception when using zero byte in string.");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void testReservedCharacterEscapingInUserId() {
IdGenerator idGenerator = new IdGeneratorImpl();
char[] chars = new char[] {'.', ',', '=' };
for (char c : chars) {
RecordId recordId = idGenerator.newRecordId("hello" + c + "world");
String idString = recordId.toString();
assertEquals("USER.hello\\" + c + "world", idString);
}
}
@Test
public void testReservedCharacterUnEscapingInUserId() {
IdGenerator idGenerator = new IdGeneratorImpl();
String idString = "USER.special\\.characters\\,are\\=fun\\\\.key=hoeba\\=hoep";
RecordId recordId = idGenerator.fromString(idString);
String encodedString = recordId.toString();
assertEquals(idString, encodedString);
}
@Test
public void testReservedCharsInUserIdFromString() {
char[] chars = new char[] {'.', ',', '=' };
for (char c : chars) {
testNotAllowedChar(c);
testEscapedNotAllowedChar(c);
}
}
private void testNotAllowedChar(char c) {
IdGenerator idGenerator = new IdGeneratorImpl();
try {
idGenerator.fromString("USER.hello" + c + "world");
fail("Expected an exception when using character " + c);
} catch (IllegalArgumentException e) {
// expected
}
}
private void testEscapedNotAllowedChar(char c) {
IdGenerator idGenerator = new IdGeneratorImpl();
String idString = "USER.hello\\" + c + "world";
try {
RecordId recordId = idGenerator.fromString(idString);
assertEquals(idString, recordId.toString());
} catch (IllegalArgumentException e) {
// expected
}
}
}