summaryrefslogtreecommitdiff
path: root/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java')
-rw-r--r--tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java645
1 files changed, 645 insertions, 0 deletions
diff --git a/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
new file mode 100644
index 0000000000..8b072c49de
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2016, The Android Open Source Project
+ *
+ * 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.android.server.connectivity;
+
+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.assertFalse;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityMetricsEvent;
+import android.net.IIpConnectivityMetrics;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.RouteInfo;
+import android.net.metrics.ApfProgramEvent;
+import android.net.metrics.ApfStats;
+import android.net.metrics.DhcpClientEvent;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.IpManagerEvent;
+import android.net.metrics.IpReachabilityEvent;
+import android.net.metrics.RaEvent;
+import android.net.metrics.ValidationProbeEvent;
+import android.os.Parcelable;
+import android.system.OsConstants;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.BitUtils;
+import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+@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";
+
+ private static final byte[] MAC_ADDR =
+ {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
+
+ @Mock Context mCtx;
+ @Mock IIpConnectivityMetrics mMockService;
+ @Mock ConnectivityManager mCm;
+
+ IpConnectivityMetrics mService;
+ NetdEventListenerService mNetdListener;
+ private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build();
+ private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
+ mNetdListener = new NetdEventListenerService(mCm);
+ mService.mNetdListener = mNetdListener;
+ }
+
+ @Test
+ public void testBufferFlushing() {
+ String output1 = getdump("flush");
+ assertEquals("", output1);
+
+ new IpConnectivityLog(mService.impl).log(1, FAKE_EV);
+ String output2 = getdump("flush");
+ assertFalse("".equals(output2));
+
+ String output3 = getdump("flush");
+ assertEquals("", output3);
+ }
+
+ @Test
+ public void testRateLimiting() {
+ final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
+ final ApfProgramEvent ev = new ApfProgramEvent.Builder().build();
+ final long fakeTimestamp = 1;
+
+ int attempt = 100; // More than burst quota, but less than buffer size.
+ for (int i = 0; i < attempt; i++) {
+ logger.log(ev);
+ }
+
+ String output1 = getdump("flush");
+ assertFalse("".equals(output1));
+
+ for (int i = 0; i < attempt; i++) {
+ assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
+ }
+
+ String output2 = getdump("flush");
+ assertEquals("", output2);
+ }
+
+ private void logDefaultNetworkEvent(long timeMs, NetworkAgentInfo nai,
+ NetworkAgentInfo oldNai) {
+ final Network network = (nai != null) ? nai.network() : null;
+ final int score = (nai != null) ? nai.getCurrentScore() : 0;
+ final boolean validated = (nai != null) ? nai.lastValidated : false;
+ final LinkProperties lp = (nai != null) ? nai.linkProperties : null;
+ final NetworkCapabilities nc = (nai != null) ? nai.networkCapabilities : null;
+
+ final Network prevNetwork = (oldNai != null) ? oldNai.network() : null;
+ final int prevScore = (oldNai != null) ? oldNai.getCurrentScore() : 0;
+ final LinkProperties prevLp = (oldNai != null) ? oldNai.linkProperties : null;
+ final NetworkCapabilities prevNc = (oldNai != null) ? oldNai.networkCapabilities : null;
+
+ mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, network, score, validated,
+ lp, nc, prevNetwork, prevScore, prevLp, prevNc);
+ }
+ @Test
+ public void testDefaultNetworkEvents() throws Exception {
+ final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
+ final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
+
+ NetworkAgentInfo[][] defaultNetworks = {
+ // nothing -> cell
+ {null, makeNai(100, 10, false, true, cell)},
+ // cell -> wifi
+ {makeNai(100, 50, true, true, cell), makeNai(101, 20, true, false, wifi)},
+ // wifi -> nothing
+ {makeNai(101, 60, true, false, wifi), null},
+ // nothing -> cell
+ {null, makeNai(102, 10, true, true, cell)},
+ // cell -> wifi
+ {makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)},
+ };
+
+ long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
+ long durationMs = 1001;
+ for (NetworkAgentInfo[] pair : defaultNetworks) {
+ timeMs += durationMs;
+ durationMs += durationMs;
+ logDefaultNetworkEvent(timeMs, pair[1], pair[0]);
+ }
+
+ String want = String.join("\n",
+ "dropped_events: 0",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 5",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " default_network_event <",
+ " default_network_duration_ms: 1001",
+ " final_score: 0",
+ " initial_score: 0",
+ " ip_support: 0",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 0",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 0",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 2",
+ " network_id: 100",
+ " time_ms: 0",
+ " transports: 1",
+ " default_network_event <",
+ " default_network_duration_ms: 2002",
+ " final_score: 50",
+ " initial_score: 10",
+ " ip_support: 3",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 0",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 2002",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 101",
+ " time_ms: 0",
+ " transports: 2",
+ " default_network_event <",
+ " default_network_duration_ms: 4004",
+ " final_score: 60",
+ " initial_score: 20",
+ " ip_support: 1",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 2",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 4004",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 5",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " default_network_event <",
+ " default_network_duration_ms: 8008",
+ " final_score: 0",
+ " initial_score: 0",
+ " ip_support: 0",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 4",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 0",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 2",
+ " network_id: 102",
+ " time_ms: 0",
+ " transports: 1",
+ " default_network_event <",
+ " default_network_duration_ms: 16016",
+ " final_score: 50",
+ " initial_score: 10",
+ " ip_support: 3",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 4",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 16016",
+ " >",
+ ">",
+ "version: 2\n");
+
+ verifySerialization(want, getdump("flush"));
+ }
+
+ @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);
+
+ ApfStats apfStats = new ApfStats.Builder()
+ .setDurationMs(45000)
+ .setReceivedRas(10)
+ .setMatchingRas(2)
+ .setDroppedRas(2)
+ .setParseErrors(2)
+ .setZeroLifetimeRas(1)
+ .setProgramUpdates(4)
+ .setProgramUpdatesAll(7)
+ .setProgramUpdatesAllowingMulticast(3)
+ .setMaxProgramSize(2048)
+ .build();
+
+ final ValidationProbeEvent validationEv = new ValidationProbeEvent.Builder()
+ .setDurationMs(40730)
+ .setProbeType(ValidationProbeEvent.PROBE_HTTP, true)
+ .setReturnCode(204)
+ .build();
+
+ final DhcpClientEvent event = new DhcpClientEvent.Builder()
+ .setMsg("SomeState")
+ .setDurationMs(192)
+ .build();
+ Parcelable[] events = {
+ new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED), event,
+ new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678),
+ validationEv,
+ apfStats,
+ new RaEvent(2000, 400, 300, -1, 1000, -1)
+ };
+
+ for (int i = 0; i < events.length; i++) {
+ ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
+ ev.timestamp = 100 * (i + 1);
+ ev.ifname = "wlan0";
+ ev.data = events[i];
+ logger.log(ev);
+ }
+
+ // 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);
+
+ // iface, uid
+ final byte[] mac = {0x48, 0x7c, 0x2b, 0x6a, 0x3e, 0x4b};
+ final String srcIp = "192.168.2.1";
+ final String dstIp = "192.168.2.23";
+ final int sport = 2356;
+ final int dport = 13489;
+ final long now = 1001L;
+ final int v4 = 0x800;
+ final int tcp = 6;
+ final int udp = 17;
+ wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", 10008, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", -1, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
+
+ long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
+ final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
+ final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
+ NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell);
+ NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi);
+ logDefaultNetworkEvent(timeMs + 200L, cellNai, null);
+ logDefaultNetworkEvent(timeMs + 300L, wifiNai, cellNai);
+
+ String want = String.join("\n",
+ "dropped_events: 0",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 100",
+ " transports: 0",
+ " ip_reachability_event <",
+ " event_type: 512",
+ " if_name: \"\"",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 200",
+ " transports: 0",
+ " dhcp_event <",
+ " duration_ms: 192",
+ " if_name: \"\"",
+ " state_transition: \"SomeState\"",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 300",
+ " transports: 0",
+ " ip_provisioning_event <",
+ " event_type: 1",
+ " if_name: \"\"",
+ " latency_ms: 5678",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 400",
+ " transports: 0",
+ " validation_probe_event <",
+ " latency_ms: 40730",
+ " probe_result: 204",
+ " probe_type: 257",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 500",
+ " transports: 0",
+ " apf_statistics <",
+ " dropped_ras: 2",
+ " duration_ms: 45000",
+ " matching_ras: 2",
+ " max_program_size: 2048",
+ " parse_errors: 2",
+ " program_updates: 4",
+ " program_updates_all: 7",
+ " program_updates_allowing_multicast: 3",
+ " received_ras: 10",
+ " total_packet_dropped: 0",
+ " total_packet_processed: 0",
+ " zero_lifetime_ras: 1",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 600",
+ " transports: 0",
+ " ra_event <",
+ " dnssl_lifetime: -1",
+ " prefix_preferred_lifetime: 300",
+ " prefix_valid_lifetime: 400",
+ " rdnss_lifetime: 1000",
+ " route_info_lifetime: -1",
+ " router_lifetime: 2000",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 5",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " default_network_event <",
+ " default_network_duration_ms: 200",
+ " final_score: 0",
+ " initial_score: 0",
+ " ip_support: 0",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 0",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 0",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 2",
+ " network_id: 100",
+ " time_ms: 0",
+ " transports: 1",
+ " default_network_event <",
+ " default_network_duration_ms: 100",
+ " final_score: 50",
+ " initial_score: 50",
+ " ip_support: 2",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 0",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 100",
+ " >",
+ ">",
+ "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",
+ " getaddrinfo_error_count: 0",
+ " getaddrinfo_query_count: 0",
+ " gethostbyname_error_count: 0",
+ " gethostbyname_query_count: 0",
+ " 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",
+ " getaddrinfo_error_count: 0",
+ " getaddrinfo_query_count: 0",
+ " gethostbyname_error_count: 0",
+ " gethostbyname_query_count: 0",
+ " latencies_ms: 56",
+ " latencies_ms: 34",
+ " return_codes: 0",
+ " return_codes: 0",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " wakeup_stats <",
+ " application_wakeups: 3",
+ " duration_sec: 0",
+ " ethertype_counts <",
+ " key: 2048",
+ " value: 6",
+ " >",
+ " ip_next_header_counts <",
+ " key: 6",
+ " value: 3",
+ " >",
+ " ip_next_header_counts <",
+ " key: 17",
+ " value: 3",
+ " >",
+ " l2_broadcast_count: 0",
+ " l2_multicast_count: 0",
+ " l2_unicast_count: 6",
+ " no_uid_wakeups: 1",
+ " non_application_wakeups: 0",
+ " root_wakeups: 0",
+ " system_wakeups: 2",
+ " total_wakeups: 6",
+ " >",
+ ">",
+ "version: 2\n");
+
+ verifySerialization(want, getdump("flush"));
+ }
+
+ String getdump(String ... command) {
+ StringWriter buffer = new StringWriter();
+ PrintWriter writer = new PrintWriter(buffer);
+ mService.impl.dump(null, writer, command);
+ return buffer.toString();
+ }
+
+ private void setCapabilities(int netId) {
+ final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+ verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
+ networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
+ netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
+ }
+
+ void connectEvent(int netId, int error, int latencyMs, String ipAddr) throws Exception {
+ setCapabilities(netId);
+ mNetdListener.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
+ }
+
+ void dnsEvent(int netId, int type, int result, int latency) throws Exception {
+ setCapabilities(netId);
+ mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
+ }
+
+ void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
+ String dstIp, int sport, int dport, long now) throws Exception {
+ String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
+ mNetdListener.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
+ }
+
+ NetworkAgentInfo makeNai(int netId, int score, boolean ipv4, boolean ipv6, long transports) {
+ NetworkAgentInfo nai = mock(NetworkAgentInfo.class);
+ when(nai.network()).thenReturn(new Network(netId));
+ when(nai.getCurrentScore()).thenReturn(score);
+ nai.linkProperties = new LinkProperties();
+ nai.networkCapabilities = new NetworkCapabilities();
+ nai.lastValidated = true;
+ for (int t : BitUtils.unpackBits(transports)) {
+ nai.networkCapabilities.addTransportType(t);
+ }
+ if (ipv4) {
+ nai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.12/24"));
+ nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
+ }
+ if (ipv6) {
+ nai.linkProperties.addLinkAddress(new LinkAddress("2001:db8:dead:beef:f00::a0/64"));
+ nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("::/0")));
+ }
+ return nai;
+ }
+
+
+
+ static void verifySerialization(String want, String output) {
+ try {
+ byte[] got = Base64.decode(output, Base64.DEFAULT);
+ IpConnectivityLogClass.IpConnectivityLog log =
+ IpConnectivityLogClass.IpConnectivityLog.parseFrom(got);
+ assertEquals(want, log.toString());
+ } catch (Exception e) {
+ fail(e.toString());
+ }
+ }
+}