Camflake { public long next() { long elapsed = getElapsedTime(); int sequence = getSequence(elapsed); log.debug("sequence id: {}", sequence); if (sequence > SEQUENCE_MAX) { sleep(TimeUnit.MILLISECONDS.toMillis(2L)); elapsed = getElapsedTime(); sequence = getSequence(elapsed); if (sequence > SEQUENCE_MAX) { throw new CamflakeException("Failed to issue sequence id."); } } long id = (elapsed << 22) | (sequence << 16) | machineId; log.debug("unique id: {}", id); return id; } Camflake(MachineId machineId, Instant baseTime);  Camflake(MachineId machineId);  Camflake(); long next();  }
@Test public void testNext() { Camflake camflake = new Camflake(); long id1 = camflake.next(); long id2 = camflake.next(); long id3 = camflake.next(); assertTrue(id2 > id1); assertTrue(id3 > id2); }
@Test public void testNextReturnsExpectedValue() { final Instant baseTime = ZonedDateTime .of(2017, 6, 1, 0, 0, 0, 0, ZoneId.of("UTC")) .toInstant(); final Instant execTime = ZonedDateTime .of(2017, 6, 1, 0, 0, 1, 0, ZoneId.of("UTC")) .toInstant(); new Expectations(Instant.class) { { Instant.now(); returns( baseTime, execTime ); } }; Camflake camflake = new Camflake(new TestMachineId()); long id = camflake.next(); assertThat(id, is(4194304001L)); }
@Test(expected = CamflakeException.class) public void testNextFailsWhenExceededTimeLimit() { final Instant exceededTime = Instant.ofEpochMilli(1L << 41); new Expectations(Instant.class) { { Instant.now(); returns( Instant.EPOCH, exceededTime ); } }; Camflake camflake = new Camflake(new DefaultMachineId(), Instant.EPOCH); camflake.next(); }
@Test public void testNextWithRetryOnce() { final Instant execTime = Instant.ofEpochMilli(1L); final Instant execTime2 = Instant.ofEpochMilli(3L); new Expectations(Instant.class) { { Instant.now(); returns( execTime, execTime, execTime2 ); } }; Camflake camflake = new Camflake(new TestMachineId(), Instant.EPOCH); Deencapsulation.setField(camflake, "counter", new AtomicInteger(SEQUENCE_MAX)); long id = camflake.next(); assertThat(id, is(12582913L)); }
@Test(expected = CamflakeException.class) public void testNextWithRetryFailsWhenSequenceIsExceeded() { new MockUp<Camflake>() { @Mock private int getSequence(long elapsed) { return SEQUENCE_MAX; } }; Camflake camflake = new Camflake(); camflake.next(); }