diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java index d819b9642e..d11565abb9 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java @@ -45,7 +45,9 @@ import android.net.metrics.NetworkEvent; import android.net.metrics.RaEvent; import android.net.metrics.ValidationProbeEvent; import android.test.suitebuilder.annotation.SmallTest; +import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; import java.util.Arrays; +import java.util.List; import junit.framework.TestCase; // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto. @@ -57,7 +59,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { aType(IpReachabilityEvent.class), anInt(IpReachabilityEvent.NUD_FAILED)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -70,13 +72,13 @@ public class IpConnectivityEventBuilderTest extends TestCase { " if_name: \"\"", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); ev.netId = 123; ev.transports = 3; // transports have priority for inferrence of link layer ev.ifname = "wlan0"; - want = joinLines( + want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -89,12 +91,12 @@ public class IpConnectivityEventBuilderTest extends TestCase { " if_name: \"\"", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); ev.transports = 1; ev.ifname = null; - want = joinLines( + want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -107,12 +109,12 @@ public class IpConnectivityEventBuilderTest extends TestCase { " if_name: \"\"", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); ev.transports = 0; ev.ifname = "not_inferred"; - want = joinLines( + want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"not_inferred\"", @@ -125,11 +127,11 @@ public class IpConnectivityEventBuilderTest extends TestCase { " if_name: \"\"", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); ev.ifname = "bt-pan"; - want = joinLines( + want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -142,11 +144,11 @@ public class IpConnectivityEventBuilderTest extends TestCase { " if_name: \"\"", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); ev.ifname = "rmnet_ipa0"; - want = joinLines( + want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -159,11 +161,11 @@ public class IpConnectivityEventBuilderTest extends TestCase { " if_name: \"\"", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); ev.ifname = "wlan0"; - want = joinLines( + want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -176,7 +178,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " if_name: \"\"", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -190,7 +192,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { aBool(true), aBool(false)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -211,7 +213,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " transport_types: 3", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -223,7 +225,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { aString("SomeState"), anInt(192)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -237,7 +239,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " state_transition: \"SomeState\"", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -248,7 +250,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { aType(DhcpErrorEvent.class), anInt(DhcpErrorEvent.L4_NOT_UDP)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -262,59 +264,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " error_code: 50397184", " >", ">", - "version: 2"); - - verifySerialization(want, ev); - } - - @SmallTest - public void testDnsEventSerialization() { - ConnectivityMetricsEvent ev = describeIpEvent( - aType(DnsEvent.class), - anInt(101), - aByteArray(b(1), b(1), b(2), b(1), b(1), b(1), b(2), b(2)), - aByteArray(b(0), b(0), b(22), b(3), b(1), b(0), b(200), b(178)), - anIntArray(3456, 267, 1230, 45, 2111, 450, 638, 1300)); - - String want = joinLines( - "dropped_events: 0", - "events <", - " if_name: \"\"", - " link_layer: 0", - " network_id: 0", - " time_ms: 1", - " transports: 0", - " dns_lookup_batch <", - " event_types: 1", - " event_types: 1", - " event_types: 2", - " event_types: 1", - " event_types: 1", - " event_types: 1", - " event_types: 2", - " event_types: 2", - " latencies_ms: 3456", - " latencies_ms: 267", - " latencies_ms: 1230", - " latencies_ms: 45", - " latencies_ms: 2111", - " latencies_ms: 450", - " latencies_ms: 638", - " latencies_ms: 1300", - " network_id <", - " network_id: 101", - " >", - " return_codes: 0", - " return_codes: 0", - " return_codes: 22", - " return_codes: 3", - " return_codes: 1", - " return_codes: 0", - " return_codes: 200", - " return_codes: 178", - " >", - ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -326,7 +276,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { anInt(IpManagerEvent.PROVISIONING_OK), aLong(5678)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -340,7 +290,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " latency_ms: 5678", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -351,7 +301,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { aType(IpReachabilityEvent.class), anInt(IpReachabilityEvent.NUD_FAILED)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -364,7 +314,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " if_name: \"\"", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -377,7 +327,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { anInt(5), aLong(20410)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -393,7 +343,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " >", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -406,7 +356,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { anInt(ValidationProbeEvent.PROBE_HTTP), anInt(204)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -420,7 +370,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " probe_type: 1", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -436,7 +386,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { anInt(2048), anInt(3)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -454,7 +404,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " program_length: 2048", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -474,7 +424,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { anInt(3), anInt(2048)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -495,7 +445,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { " zero_lifetime_ras: 1", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } @@ -511,7 +461,7 @@ public class IpConnectivityEventBuilderTest extends TestCase { aLong(1000), aLong(-1)); - String want = joinLines( + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -528,28 +478,20 @@ public class IpConnectivityEventBuilderTest extends TestCase { " router_lifetime: 2000", " >", ">", - "version: 2"); + "version: 2\n"); verifySerialization(want, ev); } static void verifySerialization(String want, ConnectivityMetricsEvent... input) { try { - byte[] got = IpConnectivityEventBuilder.serialize(0, - IpConnectivityEventBuilder.toProto(Arrays.asList(input))); + List proto = + IpConnectivityEventBuilder.toProto(Arrays.asList(input)); + byte[] got = IpConnectivityEventBuilder.serialize(0, proto); IpConnectivityLog log = IpConnectivityLog.parseFrom(got); assertEquals(want, log.toString()); } catch (Exception e) { fail(e.toString()); } } - - static String joinLines(String ... elems) { - StringBuilder b = new StringBuilder(); - for (String s : elems) { - b.append(s); - b.append("\n"); - } - return b.toString(); - } } diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index 68786d0b42..e01469b182 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java @@ -16,12 +16,22 @@ package com.android.server.connectivity; +import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO; +import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.content.Context; +import android.net.ConnectivityManager; import android.net.ConnectivityMetricsEvent; import android.net.IIpConnectivityMetrics; +import android.net.Network; +import android.net.NetworkCapabilities; import android.net.metrics.ApfProgramEvent; import android.net.metrics.ApfStats; import android.net.metrics.DefaultNetworkEvent; @@ -31,7 +41,9 @@ import android.net.metrics.IpManagerEvent; import android.net.metrics.IpReachabilityEvent; import android.net.metrics.RaEvent; import android.net.metrics.ValidationProbeEvent; +import android.system.OsConstants; import android.os.Parcelable; +import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; import android.util.Base64; import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass; @@ -41,26 +53,38 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; -import junit.framework.TestCase; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; -public class IpConnectivityMetricsTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IpConnectivityMetricsTest { static final IpReachabilityEvent FAKE_EV = new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED); + private static final String EXAMPLE_IPV4 = "192.0.2.1"; + private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1"; + @Mock Context mCtx; @Mock IIpConnectivityMetrics mMockService; + @Mock ConnectivityManager mCm; IpConnectivityMetrics mService; + NetdEventListenerService mNetdListener; + @Before public void setUp() { MockitoAnnotations.initMocks(this); mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000); + mNetdListener = new NetdEventListenerService(mCm); + mService.mNetdListener = mNetdListener; } - @SmallTest + @Test public void testLoggingEvents() throws Exception { IpConnectivityLog logger = new IpConnectivityLog(mMockService); @@ -74,7 +98,7 @@ public class IpConnectivityMetricsTest extends TestCase { assertEventsEqual(expectedEvent(3), got.get(2)); } - @SmallTest + @Test public void testLoggingEventsWithMultipleCallers() throws Exception { IpConnectivityLog logger = new IpConnectivityLog(mMockService); @@ -91,7 +115,7 @@ public class IpConnectivityMetricsTest extends TestCase { }.start(); } - List got = verifyEvents(nCallers * nEvents, 100); + List got = verifyEvents(nCallers * nEvents, 200); Collections.sort(got, EVENT_COMPARATOR); Iterator iter = got.iterator(); for (int i = 0; i < nCallers; i++) { @@ -102,7 +126,7 @@ public class IpConnectivityMetricsTest extends TestCase { } } - @SmallTest + @Test public void testBufferFlushing() { String output1 = getdump("flush"); assertEquals("", output1); @@ -115,7 +139,7 @@ public class IpConnectivityMetricsTest extends TestCase { assertEquals("", output3); } - @SmallTest + @Test public void testRateLimiting() { final IpConnectivityLog logger = new IpConnectivityLog(mService.impl); final ApfProgramEvent ev = new ApfProgramEvent(); @@ -137,11 +161,19 @@ public class IpConnectivityMetricsTest extends TestCase { assertEquals("", output2); } - @SmallTest - public void testEndToEndLogging() { + @Test + public void testEndToEndLogging() throws Exception { // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto. IpConnectivityLog logger = new IpConnectivityLog(mService.impl); + NetworkCapabilities ncWifi = new NetworkCapabilities(); + NetworkCapabilities ncCell = new NetworkCapabilities(); + ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); + + when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi); + when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell); + ApfStats apfStats = new ApfStats(); apfStats.durationMs = 45000; apfStats.receivedRas = 10; @@ -177,7 +209,22 @@ public class IpConnectivityMetricsTest extends TestCase { logger.log(ev); } - String want = joinLines( + // netId, errno, latency, destination + connectEvent(100, OsConstants.EALREADY, 0, EXAMPLE_IPV4); + connectEvent(100, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6); + connectEvent(100, 0, 110, EXAMPLE_IPV4); + connectEvent(101, 0, 23, EXAMPLE_IPV4); + connectEvent(101, 0, 45, EXAMPLE_IPV6); + connectEvent(100, OsConstants.EAGAIN, 0, EXAMPLE_IPV4); + + // netId, type, return code, latency + dnsEvent(100, EVENT_GETADDRINFO, 0, 3456); + dnsEvent(100, EVENT_GETADDRINFO, 3, 45); + dnsEvent(100, EVENT_GETHOSTBYNAME, 0, 638); + dnsEvent(101, EVENT_GETADDRINFO, 0, 56); + dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 34); + + String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", @@ -279,7 +326,71 @@ public class IpConnectivityMetricsTest extends TestCase { " router_lifetime: 2000", " >", ">", - "version: 2"); + "events <", + " if_name: \"\"", + " link_layer: 4", + " network_id: 100", + " time_ms: 0", + " transports: 2", + " connect_statistics <", + " connect_blocking_count: 1", + " connect_count: 3", + " errnos_counters <", + " key: 11", + " value: 1", + " >", + " ipv6_addr_count: 1", + " latencies_ms: 110", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 2", + " network_id: 101", + " time_ms: 0", + " transports: 1", + " connect_statistics <", + " connect_blocking_count: 2", + " connect_count: 2", + " ipv6_addr_count: 1", + " latencies_ms: 23", + " latencies_ms: 45", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 4", + " network_id: 100", + " time_ms: 0", + " transports: 2", + " dns_lookup_batch <", + " event_types: 1", + " event_types: 1", + " event_types: 2", + " latencies_ms: 3456", + " latencies_ms: 45", + " latencies_ms: 638", + " return_codes: 0", + " return_codes: 3", + " return_codes: 0", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 2", + " network_id: 101", + " time_ms: 0", + " transports: 1", + " dns_lookup_batch <", + " event_types: 1", + " event_types: 2", + " latencies_ms: 56", + " latencies_ms: 34", + " return_codes: 0", + " return_codes: 0", + " >", + ">", + "version: 2\n"); verifySerialization(want, getdump("flush")); } @@ -291,6 +402,14 @@ public class IpConnectivityMetricsTest extends TestCase { return buffer.toString(); } + void connectEvent(int netid, int error, int latencyMs, String ipAddr) throws Exception { + mNetdListener.onConnectEvent(netid, error, latencyMs, ipAddr, 80, 1); + } + + void dnsEvent(int netId, int type, int result, int latency) throws Exception { + mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0); + } + List verifyEvents(int n, int timeoutMs) throws Exception { ArgumentCaptor captor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class); diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java index 0ab440641d..f98ab3d069 100644 --- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java +++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java @@ -16,190 +16,182 @@ package com.android.server.connectivity; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.net.metrics.ConnectStats; -import android.net.metrics.DnsEvent; -import android.net.metrics.INetdEventListener; -import android.net.metrics.IpConnectivityLog; -import android.os.Parcelable; -import android.os.RemoteException; -import android.system.OsConstants; -import android.test.suitebuilder.annotation.SmallTest; -import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; -import java.io.FileOutputStream; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.OptionalInt; -import java.util.stream.IntStream; -import junit.framework.TestCase; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertTrue; +import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO; +import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -public class NetdEventListenerServiceTest extends TestCase { - - // TODO: read from NetdEventListenerService after this constant is read from system property - static final int BATCH_SIZE = 100; - static final int EVENT_TYPE = INetdEventListener.EVENT_GETADDRINFO; - // TODO: read from INetdEventListener - static final int RETURN_CODE = 1; - - static final byte[] EVENT_TYPES = new byte[BATCH_SIZE]; - static final byte[] RETURN_CODES = new byte[BATCH_SIZE]; - static final int[] LATENCIES = new int[BATCH_SIZE]; - static { - for (int i = 0; i < BATCH_SIZE; i++) { - EVENT_TYPES[i] = EVENT_TYPE; - RETURN_CODES[i] = RETURN_CODE; - LATENCIES[i] = i; - } - } +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.support.test.runner.AndroidJUnit4; +import android.system.OsConstants; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Base64; +import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.DNSLookupBatch; +import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; +import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NetdEventListenerServiceTest { private static final String EXAMPLE_IPV4 = "192.0.2.1"; private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1"; NetdEventListenerService mNetdEventListenerService; + ConnectivityManager mCm; - @Mock ConnectivityManager mCm; - @Mock IpConnectivityLog mLog; - ArgumentCaptor mCallbackCaptor; - ArgumentCaptor mDnsEvCaptor; - + @Before public void setUp() { - MockitoAnnotations.initMocks(this); - mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class); - mDnsEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); - mNetdEventListenerService = new NetdEventListenerService(mCm, mLog); + NetworkCapabilities ncWifi = new NetworkCapabilities(); + NetworkCapabilities ncCell = new NetworkCapabilities(); + ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); - verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture()); + mCm = mock(ConnectivityManager.class); + when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi); + when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell); + + mNetdEventListenerService = new NetdEventListenerService(mCm); } - @SmallTest - public void testOneDnsBatch() throws Exception { - log(105, LATENCIES); - log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event + @Test + public void testDnsLogging() throws Exception { + asyncDump(100); - verifyLoggedDnsEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES)); + dnsEvent(100, EVENT_GETADDRINFO, 0, 3456); + dnsEvent(100, EVENT_GETADDRINFO, 0, 267); + dnsEvent(100, EVENT_GETHOSTBYNAME, 22, 1230); + dnsEvent(100, EVENT_GETADDRINFO, 3, 45); + dnsEvent(100, EVENT_GETADDRINFO, 1, 2111); + dnsEvent(100, EVENT_GETADDRINFO, 0, 450); + dnsEvent(100, EVENT_GETHOSTBYNAME, 200, 638); + dnsEvent(100, EVENT_GETHOSTBYNAME, 178, 1300); + dnsEvent(101, EVENT_GETADDRINFO, 0, 56); + dnsEvent(101, EVENT_GETADDRINFO, 0, 78); + dnsEvent(101, EVENT_GETADDRINFO, 0, 14); + dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 56); + dnsEvent(101, EVENT_GETADDRINFO, 0, 78); + dnsEvent(101, EVENT_GETADDRINFO, 0, 14); - log(106, Arrays.copyOfRange(LATENCIES, BATCH_SIZE - 1, BATCH_SIZE)); - - mDnsEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor - verifyLoggedDnsEvents( - new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES), - new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES)); + String got = flushStatistics(); + String want = String.join("\n", + "dropped_events: 0", + "events <", + " if_name: \"\"", + " link_layer: 4", + " network_id: 100", + " time_ms: 0", + " transports: 2", + " dns_lookup_batch <", + " event_types: 1", + " event_types: 1", + " event_types: 2", + " event_types: 1", + " event_types: 1", + " event_types: 1", + " event_types: 2", + " event_types: 2", + " latencies_ms: 3456", + " latencies_ms: 267", + " latencies_ms: 1230", + " latencies_ms: 45", + " latencies_ms: 2111", + " latencies_ms: 450", + " latencies_ms: 638", + " latencies_ms: 1300", + " return_codes: 0", + " return_codes: 0", + " return_codes: 22", + " return_codes: 3", + " return_codes: 1", + " return_codes: 0", + " return_codes: 200", + " return_codes: 178", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 2", + " network_id: 101", + " time_ms: 0", + " transports: 1", + " dns_lookup_batch <", + " event_types: 1", + " event_types: 1", + " event_types: 1", + " event_types: 2", + " event_types: 1", + " event_types: 1", + " latencies_ms: 56", + " latencies_ms: 78", + " latencies_ms: 14", + " latencies_ms: 56", + " latencies_ms: 78", + " latencies_ms: 14", + " return_codes: 0", + " return_codes: 0", + " return_codes: 0", + " return_codes: 0", + " return_codes: 0", + " return_codes: 0", + " >", + ">", + "version: 2\n"); + assertEquals(want, got); } - @SmallTest - public void testSeveralDmsBatches() throws Exception { - log(105, LATENCIES); - log(106, LATENCIES); - log(105, LATENCIES); - log(107, LATENCIES); - - verifyLoggedDnsEvents( - new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES), - new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES), - new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES), - new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES)); - } - - @SmallTest - public void testDnsBatchAndNetworkLost() throws Exception { - byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20); - byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20); - int[] latencies = Arrays.copyOf(LATENCIES, 20); - - log(105, LATENCIES); - log(105, latencies); - mCallbackCaptor.getValue().onLost(new Network(105)); - log(105, LATENCIES); - - verifyLoggedDnsEvents( - new DnsEvent(105, eventTypes, returnCodes, latencies), - new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES), - new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES)); - } - - @SmallTest - public void testConcurrentDnsBatchesAndDumps() throws Exception { - final long stop = System.currentTimeMillis() + 100; - final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null")); - new Thread() { - public void run() { - while (System.currentTimeMillis() < stop) { - mNetdEventListenerService.dump(pw); - } - } - }.start(); - - logDnsAsync(105, LATENCIES); - logDnsAsync(106, LATENCIES); - logDnsAsync(107, LATENCIES); - - verifyLoggedDnsEvents(500, - new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES), - new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES), - new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES)); - } - - @SmallTest - public void testConcurrentDnsBatchesAndNetworkLoss() throws Exception { - logDnsAsync(105, LATENCIES); - Thread.sleep(10L); - // call onLost() asynchronously to logDnsAsync's onDnsEvent() calls. - mCallbackCaptor.getValue().onLost(new Network(105)); - - // do not verify batch with unpredictable length - verify(mLog, timeout(500).times(1)).log(any(Parcelable.class)); - } - - @SmallTest + @Test public void testConnectLogging() throws Exception { + asyncDump(100); + final int OK = 0; Thread[] logActions = { // ignored - connectEventAction(OsConstants.EALREADY, 0, EXAMPLE_IPV4), - connectEventAction(OsConstants.EALREADY, 0, EXAMPLE_IPV6), - connectEventAction(OsConstants.EINPROGRESS, 0, EXAMPLE_IPV4), - connectEventAction(OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6), - connectEventAction(OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6), + connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV4), + connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV6), + connectEventAction(100, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV4), + connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6), + connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6), // valid latencies - connectEventAction(OK, 110, EXAMPLE_IPV4), - connectEventAction(OK, 23, EXAMPLE_IPV4), - connectEventAction(OK, 45, EXAMPLE_IPV4), - connectEventAction(OK, 56, EXAMPLE_IPV4), - connectEventAction(OK, 523, EXAMPLE_IPV6), - connectEventAction(OK, 214, EXAMPLE_IPV6), - connectEventAction(OK, 67, EXAMPLE_IPV6), + connectEventAction(100, OK, 110, EXAMPLE_IPV4), + connectEventAction(100, OK, 23, EXAMPLE_IPV4), + connectEventAction(100, OK, 45, EXAMPLE_IPV4), + connectEventAction(101, OK, 56, EXAMPLE_IPV4), + connectEventAction(101, OK, 523, EXAMPLE_IPV6), + connectEventAction(101, OK, 214, EXAMPLE_IPV6), + connectEventAction(101, OK, 67, EXAMPLE_IPV6), // errors - connectEventAction(OsConstants.EPERM, 0, EXAMPLE_IPV4), - connectEventAction(OsConstants.EPERM, 0, EXAMPLE_IPV4), - connectEventAction(OsConstants.EAGAIN, 0, EXAMPLE_IPV4), - connectEventAction(OsConstants.EACCES, 0, EXAMPLE_IPV4), - connectEventAction(OsConstants.EACCES, 0, EXAMPLE_IPV4), - connectEventAction(OsConstants.EACCES, 0, EXAMPLE_IPV6), - connectEventAction(OsConstants.EADDRINUSE, 0, EXAMPLE_IPV4), - connectEventAction(OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV4), - connectEventAction(OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6), - connectEventAction(OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6), - connectEventAction(OsConstants.ECONNREFUSED, 0, EXAMPLE_IPV4), + connectEventAction(100, OsConstants.EPERM, 0, EXAMPLE_IPV4), + connectEventAction(101, OsConstants.EPERM, 0, EXAMPLE_IPV4), + connectEventAction(100, OsConstants.EAGAIN, 0, EXAMPLE_IPV4), + connectEventAction(100, OsConstants.EACCES, 0, EXAMPLE_IPV4), + connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV4), + connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV6), + connectEventAction(100, OsConstants.EADDRINUSE, 0, EXAMPLE_IPV4), + connectEventAction(101, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV4), + connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6), + connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6), + connectEventAction(101, OsConstants.ECONNREFUSED, 0, EXAMPLE_IPV4), }; for (Thread t : logActions) { @@ -209,113 +201,124 @@ public class NetdEventListenerServiceTest extends TestCase { t.join(); } - List events = new ArrayList<>(); - mNetdEventListenerService.flushStatistics(events); - - IpConnectivityEvent got = events.get(0); + String got = flushStatistics(); String want = String.join("\n", - "if_name: \"\"", - "link_layer: 0", - "network_id: 0", - "time_ms: 0", - "transports: 0", - "connect_statistics <", - " connect_blocking_count: 7", - " connect_count: 12", - " errnos_counters <", - " key: 1", - " value: 2", + "dropped_events: 0", + "events <", + " if_name: \"\"", + " link_layer: 4", + " network_id: 100", + " time_ms: 0", + " transports: 2", + " connect_statistics <", + " connect_blocking_count: 3", + " connect_count: 6", + " errnos_counters <", + " key: 1", + " value: 1", + " >", + " errnos_counters <", + " key: 11", + " value: 1", + " >", + " errnos_counters <", + " key: 13", + " value: 1", + " >", + " errnos_counters <", + " key: 98", + " value: 1", + " >", + " errnos_counters <", + " key: 110", + " value: 2", + " >", + " ipv6_addr_count: 1", + " latencies_ms: 23", + " latencies_ms: 45", + " latencies_ms: 110", " >", - " errnos_counters <", - " key: 11", - " value: 1", + ">", + "events <", + " if_name: \"\"", + " link_layer: 2", + " network_id: 101", + " time_ms: 0", + " transports: 1", + " connect_statistics <", + " connect_blocking_count: 4", + " connect_count: 6", + " errnos_counters <", + " key: 1", + " value: 1", + " >", + " errnos_counters <", + " key: 13", + " value: 2", + " >", + " errnos_counters <", + " key: 110", + " value: 1", + " >", + " errnos_counters <", + " key: 111", + " value: 1", + " >", + " ipv6_addr_count: 5", + " latencies_ms: 56", + " latencies_ms: 67", + " latencies_ms: 214", + " latencies_ms: 523", " >", - " errnos_counters <", - " key: 13", - " value: 3", - " >", - " errnos_counters <", - " key: 98", - " value: 1", - " >", - " errnos_counters <", - " key: 110", - " value: 3", - " >", - " errnos_counters <", - " key: 111", - " value: 1", - " >", - " ipv6_addr_count: 6", - " latencies_ms: 23", - " latencies_ms: 45", - " latencies_ms: 56", - " latencies_ms: 67", - " latencies_ms: 110", - " latencies_ms: 214", - " latencies_ms: 523", - ">\n"); - verifyConnectEvent(want, got); + ">", + "version: 2\n"); + assertEquals(want, got); } - Thread connectEventAction(int error, int latencyMs, String ipAddr) { + Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) { return new Thread(() -> { try { - mNetdEventListenerService.onConnectEvent(100, error, latencyMs, ipAddr, 80, 1); + mNetdEventListenerService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1); } catch (Exception e) { fail(e.toString()); } }); } - void log(int netId, int[] latencies) { - try { - for (int l : latencies) { - mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null, - 0, 0); + void dnsEvent(int netId, int type, int result, int latency) throws Exception { + mNetdEventListenerService.onDnsEvent(netId, type, result, latency, "", null, 0, 0); + } + + void asyncDump(long durationMs) throws Exception { + final long stop = System.currentTimeMillis() + durationMs; + final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null")); + new Thread(() -> { + while (System.currentTimeMillis() < stop) { + mNetdEventListenerService.dump(pw); } - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } + }).start(); } - void logDnsAsync(int netId, int[] latencies) { - new Thread(() -> log(netId, latencies)).start(); - } + // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto. + String flushStatistics() throws Exception { + IpConnectivityMetrics metricsService = + new IpConnectivityMetrics(mock(Context.class), (ctx) -> 2000); + metricsService.mNetdListener = mNetdEventListenerService; - void verifyLoggedDnsEvents(DnsEvent... expected) { - verifyLoggedDnsEvents(0, expected); - } - - void verifyLoggedDnsEvents(int wait, DnsEvent... expectedEvents) { - verify(mLog, timeout(wait).times(expectedEvents.length)).log(mDnsEvCaptor.capture()); - for (DnsEvent got : mDnsEvCaptor.getAllValues()) { - OptionalInt index = IntStream.range(0, expectedEvents.length) - .filter(i -> dnsEventsEqual(expectedEvents[i], got)) - .findFirst(); - // Don't match same expected event more than once. - index.ifPresent(i -> expectedEvents[i] = null); - assertTrue(index.isPresent()); - } - } - - /** equality function for DnsEvent to avoid overriding equals() and hashCode(). */ - static boolean dnsEventsEqual(DnsEvent expected, DnsEvent got) { - return (expected == got) || ((expected != null) && (got != null) - && (expected.netId == got.netId) - && Arrays.equals(expected.eventTypes, got.eventTypes) - && Arrays.equals(expected.returnCodes, got.returnCodes) - && Arrays.equals(expected.latenciesMs, got.latenciesMs)); - } - - static void verifyConnectEvent(String expected, IpConnectivityEvent got) { - try { - Arrays.sort(got.getConnectStatistics().latenciesMs); - Arrays.sort(got.getConnectStatistics().errnosCounters, + StringWriter buffer = new StringWriter(); + PrintWriter writer = new PrintWriter(buffer); + metricsService.impl.dump(null, writer, new String[]{"flush"}); + byte[] bytes = Base64.decode(buffer.toString(), Base64.DEFAULT); + IpConnectivityLog log = IpConnectivityLog.parseFrom(bytes); + for (IpConnectivityEvent ev : log.events) { + if (ev.getConnectStatistics() == null) { + continue; + } + // Sort repeated fields of connect() events arriving in non-deterministic order. + Arrays.sort(ev.getConnectStatistics().latenciesMs); + Arrays.sort(ev.getConnectStatistics().errnosCounters, Comparator.comparingInt((p) -> p.key)); - assertEquals(expected, got.toString()); - } catch (Exception e) { - fail(e.toString()); } + return log.toString(); } }