TraceAndSpanIdGenerator { public static String generateId() { return longToUnsignedLowerHexString(generate64BitRandomLong()); } private  TraceAndSpanIdGenerator(); static String generateId(); static long generate64BitRandomLong(); static String longToUnsignedLowerHexString(long primitiveLong); static long unsignedLowerHexStringToLong(String hexString); static long unsignedLowerHexStringToLong(String hexString, int index);  }
@Test public void generateId_should_return_16_char_length_string_that_can_be_parsed_into_a_long_when_interpreted_as_a_64_bit_unsigned_hex_long() { Set<Character> charactersFromIds = new HashSet<>(); for (int i = 0; i < 10000; i++) { final String idVal = TraceAndSpanIdGenerator.generateId(); assertThat(idVal).hasSize(16); Throwable parseException = catchThrowable(new ThrowableAssert.ThrowingCallable() { @Override public void call() throws Throwable { new BigInteger(idVal, 16).longValue(); } }); assertThat(parseException).isNull(); for (char c : idVal.toCharArray()) { charactersFromIds.add(c); } } assertThat(charactersFromIds).containsOnly('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); }
@Test public void generateId_should_not_generate_duplicate_ids_over_reasonable_number_of_attempts() throws Exception { Set<String> ids = new HashSet<>(); int numAttempts = 1000000; for (int i = 0; i < numAttempts; i++) { ids.add(TraceAndSpanIdGenerator.generateId()); } assertThat(ids.size()).isEqualTo(numAttempts); }