/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.usergrid.utils; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.apache.usergrid.ExperimentalTest; import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.apache.usergrid.utils.UUIDUtils.getTimestampInMillis; import static org.apache.usergrid.utils.UUIDUtils.newTimeUUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class UUIDUtilsTest { private static final Logger logger = LoggerFactory.getLogger( UUIDUtilsTest.class ); @Test public void testUUIDUtils() { UUID uuid = UUIDUtils.newTimeUUID(); logger.info("" + uuid); logger.info("" + uuid.timestamp()); logger.info("" + UUIDUtils.getTimestampInMillis(uuid)); logger.info("" + UUIDUtils.getTimestampInMillis(UUIDUtils.newTimeUUID())); logger.info("" + System.currentTimeMillis()); logger.info("" + UUIDUtils.getTimestampInMicros(UUIDUtils.newTimeUUID())); logger.info("" + (System.currentTimeMillis() * 1000)); logger.info("" + UUIDUtils.MIN_TIME_UUID); logger.info("" + UUIDUtils.MIN_TIME_UUID.variant()); logger.info("" + UUIDUtils.MIN_TIME_UUID.version()); logger.info("" + UUIDUtils.MIN_TIME_UUID.clockSequence()); logger.info("" + UUIDUtils.MIN_TIME_UUID.timestamp()); logger.info("" + UUIDUtils.MAX_TIME_UUID); logger.info("" + UUIDUtils.MAX_TIME_UUID.variant()); logger.info("" + UUIDUtils.MAX_TIME_UUID.version()); logger.info("" + UUIDUtils.MAX_TIME_UUID.clockSequence()); logger.info("" + UUIDUtils.MAX_TIME_UUID.timestamp()); } @Test public void testAppProvidedTimestamp() { logger.info("UUIDUtilsTest.testAppProvidedTimestamp"); long ts = System.currentTimeMillis(); System.out.println( ts ); Set<UUID> uuids = new HashSet<UUID>(); int count = 1000000; logger.info("Generating " + count + " UUIDs..."); for ( int i = 0; i < count; i++ ) { UUID uuid = newTimeUUID( ts ); assertFalse( "UUID already generated", uuids.contains( uuid ) ); uuids.add( uuid ); assertEquals( "Incorrect UUID timestamp value", ts, getTimestampInMillis( uuid ) ); if ( i % 1000 == 0 ) { logger.info("testAppProvidedTimestamp processed " + i); } } logger.info("UUIDs checked"); } @Test public void testAppProvidedTimestampOrdering() { logger.info("UUIDUtilsTest.testAppProvidedTimestamp"); long ts = System.currentTimeMillis(); System.out.println( ts ); UUID first = newTimeUUID( ts, 0 ); UUID second = newTimeUUID( ts, 1 ); assertFalse( first.equals( second ) ); assertTrue( first.compareTo( second ) < 0 ); } @Test public void timeUUIDOrdering() { int count = 10000; long ts = System.currentTimeMillis(); List<UUID> uuids = new ArrayList<UUID>( count ); logger.info("Generating " + count + " UUIDs..."); for ( int i = 0; i < count; i++ ) { UUID uuid = newTimeUUID( ts, i ); uuids.add( uuid ); assertEquals( "Incorrect UUID timestamp value", ts, getTimestampInMillis( uuid ) ); if ( i % 1000 == 0 ) { logger.info("timeUUIDOrdering processed " + i); } } for ( int i = 0; i < count - 1; i++ ) { assertEquals( -1, uuids.get( i ).compareTo( uuids.get( i + 1 ) ) ); } } @Test @Category(ExperimentalTest.class) @SuppressWarnings("unchecked") public void verifyOrderingTsOnlyAndUnique() { int count = 500; long ts = System.currentTimeMillis(); List<UUID> uuids = new ArrayList<UUID>( count ); HashSet times = new HashSet(); UUID lastSeen; for ( int i = 0; i < count; i++ ) { lastSeen = newTimeUUID( ts ); uuids.add( lastSeen ); times.add( UUIDUtils.getTimestampInMicros( lastSeen ) ); } assertEquals( 500, times.size() ); for ( int i = 0; i < count - 1; i++ ) { assertEquals( -1, uuids.get( i ).compareTo( uuids.get( i + 1 ) ) ); } } /** Populate timestamp set for the methods testing uuid contention */ @SuppressWarnings("unchecked") private static Set<UUID> buildTsMicros( int count ) { HashSet<UUID> created = new HashSet<>( count ); for ( int x = 0; x < count; x++ ) { created.add( UUIDUtils.newTimeUUID() ); } return created; } @Test public void directUuidFrob() { long startTime = System.currentTimeMillis(); int count = 1000 * 1000; Set created = buildTsMicros( count ); logger.info("execution took {}", System.currentTimeMillis() - startTime); assertEquals( count, created.size() ); assertTrue( created.size() > 0 ); } @Test public void concurrentUuidFrob() throws Exception { long startTime = System.currentTimeMillis(); List<Future> jobs = executeFrob(); for ( Future f : jobs ) { logger.info("waiting on job..."); f.get(); } logger.info("execution took {}", System.currentTimeMillis() - startTime); } private List<Future> executeFrob() { ExecutorService exec = Executors.newFixedThreadPool( 5 ); List<Future> jobs = new ArrayList<Future>( 10 ); for ( int x = 0; x < 10; x++ ) { jobs.add( exec.submit( () -> { logger.info("call invoked"); int count = 1000 * 100; Set created = buildTsMicros( count ); assertEquals( count, created.size() ); assertTrue( created.size() > 0 ); logger.info("run complete"); return null; } ) ); } return jobs; } @Test public void timeUUIDOrderingRolls() { long ts = System.currentTimeMillis(); UUID first = newTimeUUID( ts, 0 ); assertEquals( ts, getTimestampInMillis( first ) ); UUID second = newTimeUUID( ts, 10001 ); assertEquals( ts + 1, getTimestampInMillis( second ) ); } @Test public void timeUUIDOrderingGaps() throws InterruptedException { UUID now1 = newTimeUUID(); UUID now2 = newTimeUUID(); Thread.sleep( 1 ); long start = System.currentTimeMillis(); UUID t1 = newTimeUUID( start, 0 ); UUID t2 = newTimeUUID( start, 1 ); // we are moving independantly now between the default form of // newTimeUUID and the user-determined offsets. Keeping them // in sync is not feasible and no longer necessary TimeUnit.MILLISECONDS.sleep( 1 ); UUID now3 = newTimeUUID(); assertEquals( -1, now1.compareTo( t1 ) ); assertEquals( -1, now2.compareTo( t1 ) ); assertEquals( -1, now1.compareTo( t2 ) ); assertEquals( -1, now2.compareTo( t2 ) ); assertEquals( -1, t1.compareTo( now3 ) ); assertEquals( -1, t2.compareTo( now3 ) ); } @Test public void max() { long start = System.currentTimeMillis(); UUID t1 = newTimeUUID( start, 0 ); UUID t2 = newTimeUUID( start, 1 ); assertEquals( t2, UUIDUtils.max( t1, t2 ) ); } @Test public void maxFirstNull() { long start = System.currentTimeMillis(); UUID t1 = newTimeUUID( start, 0 ); assertEquals( t1, UUIDUtils.max( null, t1 ) ); } @Test public void maxSecondNull() { long start = System.currentTimeMillis(); UUID t1 = newTimeUUID( start, 0 ); assertEquals( t1, UUIDUtils.max( t1, null ) ); } @Test public void maxBothNull() { assertNull( UUIDUtils.max( null, null ) ); } @Test public void min() { long start = System.currentTimeMillis(); UUID t1 = newTimeUUID( start, 0 ); UUID t2 = newTimeUUID( start, 1 ); assertEquals( t1, UUIDUtils.min( t1, t2 ) ); } @Test public void minFirstNull() { long start = System.currentTimeMillis(); UUID t1 = newTimeUUID( start, 0 ); assertEquals( t1, UUIDUtils.min( null, t1 ) ); } @Test public void minSecondNull() { long start = System.currentTimeMillis(); UUID t1 = newTimeUUID( start, 0 ); assertEquals( t1, UUIDUtils.min( t1, null ) ); } @Test public void minBothNull() { assertNull( UUIDUtils.min( null, null ) ); } @Test public void testDecrement() { int testSize = 100000; UUID current = UUIDUtils.MAX_TIME_UUID; UUID previous = current; for ( int i = 0; i < testSize; i++ ) { current = UUIDUtils.decrement( current ); assertEquals( -1, current.compareTo( previous ) ); if ( i % 1000 == 0 ) { logger.info("testDecrement processed " + i); } previous = current; } } @Test(expected = IllegalArgumentException.class) public void testDecrementMin() { UUIDUtils.decrement( UUIDUtils.MIN_TIME_UUID ); } @Test(expected = IllegalArgumentException.class) public void nonTimeUUID() { UUIDUtils.decrement( UUID.randomUUID() ); } }