/* * Copyright (C) 2014 Lable ([email protected]) * * 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.lable.oss.uniqueid.bytes; import org.apache.commons.codec.binary.Hex; import org.junit.Test; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.lable.oss.uniqueid.bytes.IDBuilder.parseGeneratorId; public class IDBuilderTest { @Test public void buildZero() { final byte[] result = IDBuilder.build(new Blueprint(0, 0, 0, 0)); final byte[] zero = new byte[8]; // Baseline check, if all ID parts are zero so is the result. assertThat(result, is(zero)); } @Test public void buildMostlyOnes() { final byte[] result = IDBuilder.build(new Blueprint( Blueprint.MAX_TIMESTAMP, Blueprint.MAX_SEQUENCE_COUNTER, Blueprint.MAX_GENERATOR_ID, Blueprint.MAX_CLUSTER_ID, Mode.SPREAD )); // The "0f" for the 7th byte is due to the reserved bits that are always zero for the SPREAD mode. final String expected = "ffffffffffff0fff"; // Baseline check, if all ID parts are all ones so is the result (except for the reserved bytes). assertThat(Hex.encodeHexString(result), is(expected)); } @Test public void buildTimestampOnly() { final long TEST_TS_A = 143062936275L; // This is the above long with its bytes reversed. final String TEST_A_REVERSED = "cb54ecf284000000"; // Timestamp test. final byte[] result_a = IDBuilder.build(new Blueprint(TEST_TS_A, 0, 0, 0)); assertThat(Hex.encodeHexString(result_a).toLowerCase(), is(TEST_A_REVERSED)); final long TEST_TS_B = 0x3FFFFFFFDL; // This is the above long with its bytes reversed. final String TEST_B_REVERSED = "bfffffffc0000000"; // Timestamp test. final byte[] result_b = IDBuilder.build(new Blueprint(TEST_TS_B, 0, 0, 0)); assertThat(Hex.encodeHexString(result_b).toLowerCase(), is(TEST_B_REVERSED)); } @Test public void buildSequenceCounterOnly() { // Sequence counter test. final byte[] result = IDBuilder.build(new Blueprint(0, 0x22, 0, 0)); final byte[] sixthByte = new byte[]{result[5]}; // 0x88 is 0x22 shifted left two bits. final String expected = "22"; assertThat(Hex.encodeHexString(sixthByte), is(expected)); } @Test public void buildGeneratorIdOnly() { // Generator ID test. final byte[] result = IDBuilder.build(new Blueprint(0, 0, 0x27, 0)); final byte[] lastTwoBytes = new byte[]{result[6], result[7]}; // 0x0270 is 0x0027 shifted left four bits. final String expected = "0270"; assertThat(Hex.encodeHexString(lastTwoBytes), is(expected)); } @Test public void buildClusterIdOnly() { // Cluster ID test. final byte[] result = IDBuilder.build(new Blueprint(0, 0, 0, 5)); final byte[] lastTwoBytes = new byte[]{result[6], result[7]}; final String expected = "0005"; assertThat(Hex.encodeHexString(lastTwoBytes), is(expected)); } @Test public void buildModeOnlySpread() { // Cluster ID test. final byte[] result = IDBuilder.build(new Blueprint(0, 0, 0, 0)); final byte[] lastTwoBytes = new byte[]{result[6], result[7]}; final String expected = "0000"; assertThat(Hex.encodeHexString(lastTwoBytes), is(expected)); } @Test public void buildModeOnlySpreadExplicit() { // Cluster ID test. final byte[] result = IDBuilder.build(new Blueprint(0, 0, 0, 0, Mode.SPREAD)); final byte[] lastTwoBytes = new byte[]{result[6], result[7]}; final String expected = "0000"; assertThat(Hex.encodeHexString(lastTwoBytes), is(expected)); } @Test public void buildModeOnlyTimeExplicit() { // Cluster ID test. final byte[] result = IDBuilder.build(new Blueprint(0, 0, 0, 0, Mode.TIME_SEQUENTIAL)); final byte[] lastTwoBytes = new byte[]{result[6], result[7]}; final String expected = "1000"; assertThat(Hex.encodeHexString(lastTwoBytes), is(expected)); } @Test public void parseBytes() { // Create an ID, then un-mangle it, and run the resulting blueprint through the mangler again. final long TEST_TS = 143062936275L; final byte[] resultOne = IDBuilder.build(new Blueprint(TEST_TS, 10, 1, 5)); assertThat(IDBuilder.parseGeneratorId(resultOne), is(1)); assertThat(IDBuilder.parseClusterId(resultOne), is(5)); assertThat(IDBuilder.parseSequenceId(resultOne), is(10)); assertThat(IDBuilder.parseTimestamp(resultOne), is(TEST_TS)); assertThat(IDBuilder.parseMode(resultOne), is(Mode.SPREAD)); Blueprint blueprint = IDBuilder.parse(resultOne); final byte[] result_two = IDBuilder.build(blueprint); assertThat(resultOne, is(result_two)); } @Test public void parseBytesTimeSequential() { // Create an ID, then un-mangle it, and run the resulting blueprint through the mangler again. final long TEST_TS = 143062936275L; final byte[] resultOne = IDBuilder.build(new Blueprint(TEST_TS, 10, 2, 5, Mode.TIME_SEQUENTIAL)); assertThat(IDBuilder.parseGeneratorId(resultOne), is(2)); assertThat(IDBuilder.parseClusterId(resultOne), is(5)); assertThat(IDBuilder.parseSequenceId(resultOne), is(10)); assertThat(IDBuilder.parseTimestamp(resultOne), is(TEST_TS)); assertThat(IDBuilder.parseMode(resultOne), is(Mode.TIME_SEQUENTIAL)); Blueprint blueprint = IDBuilder.parse(resultOne); final byte[] result_two = IDBuilder.build(blueprint); assertThat(resultOne, is(result_two)); } @Test public void blueprintSpread() { // Round-trip test. First generate the byte[] with mangleBytes, then back to the blueprint with Blueprint.parse. final long TEST_TS = 143062936275L; final byte[] resultOne = IDBuilder.build(new Blueprint(TEST_TS, 10, 1, 5)); final Blueprint blueprintOne = IDBuilder.parse(resultOne); final byte[] resultOneAgain = IDBuilder.build(blueprintOne); assertThat(resultOne, is(resultOneAgain)); final byte[] resultZeros = IDBuilder.build(new Blueprint(0, 0, 0, 0)); final Blueprint blueprintZeros = IDBuilder.parse(resultZeros); final byte[] resultZerosAgain = IDBuilder.build(blueprintZeros); assertThat(resultZeros, is(resultZerosAgain)); final byte[] resultMostlyOnes = IDBuilder.build(new Blueprint( Blueprint.MAX_TIMESTAMP, Blueprint.MAX_SEQUENCE_COUNTER, Blueprint.MAX_GENERATOR_ID, Blueprint.MAX_CLUSTER_ID )); final Blueprint blueprintMostlyOnes = IDBuilder.parse(resultMostlyOnes); final byte[] resultMostlyOnesAgain = IDBuilder.build(blueprintMostlyOnes); assertThat(resultMostlyOnes, is(resultMostlyOnesAgain)); } @Test public void blueprintTimeSequential() { // Round-trip test. First generate the byte[] with mangleBytes, then back to the blueprint with Blueprint.parse. final long TEST_TS = 143062936275L; final byte[] resultOne = IDBuilder.build(new Blueprint(TEST_TS, 10, 1, 5, Mode.TIME_SEQUENTIAL)); final Blueprint blueprintOne = IDBuilder.parse(resultOne); final byte[] resultOneAgain = IDBuilder.build(blueprintOne); assertThat(resultOne, is(resultOneAgain)); final byte[] resultZeros = IDBuilder.build(new Blueprint(0, 0, 0, 0, Mode.TIME_SEQUENTIAL)); final Blueprint blueprintZeros = IDBuilder.parse(resultZeros); final byte[] resultZerosAgain = IDBuilder.build(blueprintZeros); assertThat(resultZeros, is(resultZerosAgain)); final byte[] resultMostlyOnes = IDBuilder.build(new Blueprint( Blueprint.MAX_TIMESTAMP, Blueprint.MAX_SEQUENCE_COUNTER, Blueprint.MAX_GENERATOR_ID, Blueprint.MAX_CLUSTER_ID, Mode.TIME_SEQUENTIAL )); final Blueprint blueprintMostlyOnes = IDBuilder.parse(resultMostlyOnes); final byte[] resultMostlyOnesAgain = IDBuilder.build(blueprintMostlyOnes); assertThat(resultMostlyOnes, is(resultMostlyOnesAgain)); } @Test public void parseGeneratorIdTest() { byte[] id = new byte[8]; id[6] = 0x0f; id[7] = (byte) (0x0f << 4); byte[] clone = id.clone(); assertThat(parseGeneratorId(id), is(255)); assertThat(id, is(clone)); } @Test(expected = IllegalArgumentException.class) public void parseIllegalArgument() { IDBuilder.parse(new byte[0]); } @Test(expected = IllegalArgumentException.class) public void parseIllegalArgumentNull() { IDBuilder.parse(null); } }