package brave.internal;
import com.google.common.collect.Sets;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.annotation.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import zipkin.Endpoint;
import static org.assertj.core.api.Assertions.assertThat;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
// Added to declutter console: tells power mock not to mess with implicit classes we aren't testing
@PowerMockIgnore({"org.apache.logging.*", "javax.script.*"})
@PrepareForTest({Platform.class, NetworkInterface.class})
public class PlatformTest {
Endpoint unknownEndpoint = Endpoint.builder().serviceName("unknown").build();
Platform platform = Platform.Jre7.buildIfSupported();
@Test public void relativeTimestamp_incrementsAccordingToNanoTick() {
mockStatic(System.class);
when(System.currentTimeMillis()).thenReturn(0L);
when(System.nanoTime()).thenReturn(0L);
Platform platform = new Platform() {
@Override public long randomLong() {
return 1L;
}
};
when(System.nanoTime()).thenReturn(1000L); // 1 microsecond
assertThat(platform.currentTimeMicroseconds()).isEqualTo(1);
}
@Test public void localEndpoint_lazySet() {
assertThat(platform.localEndpoint).isNull(); // sanity check setup
assertThat(platform.localEndpoint())
.isNotNull();
}
@Test public void localEndpoint_sameInstance() {
assertThat(platform.localEndpoint())
.isSameAs(platform.localEndpoint());
}
@Test public void produceLocalEndpoint_exceptionReadingNics() throws Exception {
mockStatic(NetworkInterface.class);
when(NetworkInterface.getNetworkInterfaces()).thenThrow(SocketException.class);
assertThat(platform.produceLocalEndpoint())
.isEqualTo(unknownEndpoint);
}
/** possible albeit very unlikely */
@Test public void produceLocalEndpoint_noNics() throws Exception {
mockStatic(NetworkInterface.class);
when(NetworkInterface.getNetworkInterfaces())
.thenReturn(null);
assertThat(platform.localEndpoint())
.isEqualTo(unknownEndpoint);
when(NetworkInterface.getNetworkInterfaces())
.thenReturn(new Vector<NetworkInterface>().elements());
assertThat(platform.produceLocalEndpoint())
.isEqualTo(unknownEndpoint);
}
/** also possible albeit unlikely */
@Test public void produceLocalEndpoint_noAddresses() throws Exception {
nicWithAddress(null);
assertThat(platform.produceLocalEndpoint())
.isEqualTo(unknownEndpoint);
}
@Test public void produceLocalEndpoint_siteLocal_ipv4() throws Exception {
nicWithAddress(InetAddress.getByAddress("local", new byte[] {(byte) 192, (byte) 168, 0, 1}));
assertThat(platform.produceLocalEndpoint())
.isEqualTo(unknownEndpoint.toBuilder().ipv4(192 << 24 | 168 << 16 | 1).build());
}
@Test public void produceLocalEndpoint_siteLocal_ipv6() throws Exception {
InetAddress ipv6 = Inet6Address.getByName("fec0:db8::c001");
nicWithAddress(ipv6);
assertThat(platform.produceLocalEndpoint())
.isEqualTo(unknownEndpoint.toBuilder().ipv6(ipv6.getAddress()).build());
}
@Test public void produceLocalEndpoint_notSiteLocal_ipv4() throws Exception {
nicWithAddress(InetAddress.getByAddress("external", new byte[] {1, 2, 3, 4}));
assertThat(platform.produceLocalEndpoint())
.isEqualTo(unknownEndpoint);
}
@Test public void produceLocalEndpoint_notSiteLocal_ipv6() throws Exception {
nicWithAddress(Inet6Address.getByName("2001:db8::c001"));
assertThat(platform.produceLocalEndpoint())
.isEqualTo(unknownEndpoint);
}
/**
* Getting an endpoint is expensive. This tests it is provisioned only once.
*
* test inspired by dagger.internal.DoubleCheckTest
*/
@Test
public void localEndpoint_provisionsOnce() throws Exception {
// create all the tasks up front so that they are executed with no delay
List<Callable<Endpoint>> tasks = new ArrayList<>();
for (int i = 0; i < 10; i++) {
tasks.add(() -> platform.localEndpoint());
}
ExecutorService executor = Executors.newFixedThreadPool(tasks.size());
List<Future<Endpoint>> futures = executor.invokeAll(tasks);
// check there's only a single unique endpoint returned
Set<Object> results = Sets.newIdentityHashSet();
for (Future<Endpoint> future : futures) {
results.add(future.get());
}
assertThat(results).hasSize(1);
executor.shutdownNow();
}
static void nicWithAddress(@Nullable InetAddress address) throws SocketException {
mockStatic(NetworkInterface.class);
Vector<InetAddress> addresses = new Vector<>();
if (address != null) addresses.add(address);
NetworkInterface nic = PowerMockito.mock(NetworkInterface.class);
Vector<NetworkInterface> nics = new Vector<>();
nics.add(nic);
when(NetworkInterface.getNetworkInterfaces()).thenReturn(nics.elements());
when(nic.getInetAddresses()).thenReturn(addresses.elements());
}
}