/*
* Copyright (c) 2013-2017 Cinchapi Inc.
*
* 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 com.cinchapi.concourse.util;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Assert;
import org.junit.Test;
import com.cinchapi.concourse.thrift.AccessToken;
import com.cinchapi.concourse.time.Time;
import com.google.common.collect.Maps;
import com.google.common.hash.Hashing;
/**
* Unit tests for {@link ConcurrentMaps}. util class
*
* @author Jeff Nelson
*/
public class ConcurrentMapsTest {
@Test
public void testWaitAndRemove() {
final ConcurrentMap<AccessToken, String> map = Maps.newConcurrentMap();
String username = Random.getString();
long salt = Random.getLong();
long timestamp = Time.now();
final AccessToken token0 = createAccessToken(username, salt, timestamp);
final AtomicReference<String> actual = new AtomicReference<String>(null);
final AtomicBoolean done = new AtomicBoolean(false);
Thread waiter = new Thread(new Runnable() {
@Override
public void run() {
actual.set(ConcurrentMaps.waitAndRemove(map, token0));
done.set(true);
}
});
waiter.start();
AccessToken token = createAccessToken(username, salt, timestamp);
Assert.assertNotSame(token0, token);
String expected = Random.getString();
ConcurrentMaps.putAndSignal(map, token, expected);
while (!done.get()) {
continue;
}
Assert.assertEquals(expected, actual.get());
}
@Test
public void testWaitAndRemoveAfterDelay() throws InterruptedException {
int sleep = ConcurrentMaps.SPIN_THRESHOLD_IN_MILLIS;
ConcurrentMaps.SPIN_THRESHOLD_IN_MILLIS = 100;
try {
final ConcurrentMap<AccessToken, String> map = Maps
.newConcurrentMap();
String username = Random.getString();
long salt = Random.getLong();
long timestamp = Time.now();
final AccessToken token0 = createAccessToken(username, salt,
timestamp);
final AtomicReference<String> actual = new AtomicReference<String>(
null);
final AtomicBoolean done = new AtomicBoolean(false);
Thread waiter = new Thread(new Runnable() {
@Override
public void run() {
actual.set(ConcurrentMaps.waitAndRemove(map, token0));
done.set(true);
}
});
waiter.start();
AccessToken token = createAccessToken(username, salt, timestamp);
Assert.assertNotSame(token0, token);
String expected = Random.getString();
Thread.sleep(101);
ConcurrentMaps.putAndSignal(map, token, expected);
while (!done.get()) {
continue;
}
Assert.assertEquals(expected, actual.get());
}
finally {
ConcurrentMaps.SPIN_THRESHOLD_IN_MILLIS = sleep;
}
}
/**
* Create an {@link AccessToken} based on all the input components.
*
* @param username
* @param salt
* @param timestamp
* @return a new {@link AccessToken}.
*/
private static AccessToken createAccessToken(String username, long salt,
long timestamp) {
StringBuilder sb = new StringBuilder();
sb.append(username);
sb.append(salt);
sb.append(timestamp);
AccessToken token = new AccessToken(ByteBuffer.wrap(Hashing.sha256()
.hashUnencodedChars(sb.toString()).asBytes()));
return token;
}
}