blob: 3fc89b9ff12d38029f3052aa4cf15524c1617b3a [file] [log] [blame]
/*
* 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 android.content.Context;
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
import android.net.metrics.ApfStats;
import android.net.metrics.DefaultNetworkEvent;
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.util.Base64;
import com.android.server.connectivity.metrics.IpConnectivityLogClass;
import com.google.protobuf.nano.MessageNano;
import java.io.PrintWriter;
import java.io.StringWriter;
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 static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class IpConnectivityMetricsTest extends TestCase {
static final IpReachabilityEvent FAKE_EV =
new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED);
@Mock Context mCtx;
@Mock IIpConnectivityMetrics mMockService;
IpConnectivityMetrics mService;
public void setUp() {
MockitoAnnotations.initMocks(this);
mService = new IpConnectivityMetrics(mCtx);
}
public void testLoggingEvents() throws Exception {
IpConnectivityLog logger = new IpConnectivityLog(mMockService);
assertTrue(logger.log(1, FAKE_EV));
assertTrue(logger.log(2, FAKE_EV));
assertTrue(logger.log(3, FAKE_EV));
List<ConnectivityMetricsEvent> got = verifyEvents(3);
assertEventsEqual(expectedEvent(1), got.get(0));
assertEventsEqual(expectedEvent(2), got.get(1));
assertEventsEqual(expectedEvent(3), got.get(2));
}
public void testLoggingEventsWithMultipleCallers() throws Exception {
IpConnectivityLog logger = new IpConnectivityLog(mMockService);
final int nCallers = 10;
final int nEvents = 10;
for (int n = 0; n < nCallers; n++) {
final int i = n;
new Thread() {
public void run() {
for (int j = 0; j < nEvents; j++) {
assertTrue(logger.log(i * 100 + j, FAKE_EV));
}
}
}.start();
}
List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 100);
Collections.sort(got, EVENT_COMPARATOR);
Iterator<ConnectivityMetricsEvent> iter = got.iterator();
for (int i = 0; i < nCallers; i++) {
for (int j = 0; j < nEvents; j++) {
int expectedTimestamp = i * 100 + j;
assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
}
}
}
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);
}
public void testEndToEndLogging() {
IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
Parcelable[] events = {
new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED),
new DhcpClientEvent("wlan0", "SomeState", 192),
new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false),
new IpManagerEvent("wlan0", IpManagerEvent.PROVISIONING_OK, 5678),
new ValidationProbeEvent(120, 40730, ValidationProbeEvent.PROBE_HTTP, 204),
new ApfStats(45000, 10, 2, 2, 1, 2, 4, 2048),
new RaEvent(2000, 400, 300, -1, 1000, -1)
};
for (int i = 0; i < events.length; i++) {
logger.log(100 * (i + 1), events[i]);
}
String want = joinLines(
"dropped_events: 0",
"events <",
" ip_reachability_event <",
" event_type: 512",
" if_name: \"wlan0\"",
" >",
" time_ms: 100",
">",
"events <",
" dhcp_event <",
" duration_ms: 192",
" error_code: 0",
" if_name: \"wlan0\"",
" state_transition: \"SomeState\"",
" >",
" time_ms: 200",
">",
"events <",
" default_network_event <",
" network_id <",
" network_id: 102",
" >",
" previous_network_id <",
" network_id: 101",
" >",
" previous_network_ip_support: 1",
" transport_types: 1",
" transport_types: 2",
" transport_types: 3",
" >",
" time_ms: 300",
">",
"events <",
" ip_provisioning_event <",
" event_type: 1",
" if_name: \"wlan0\"",
" latency_ms: 5678",
" >",
" time_ms: 400",
">",
"events <",
" time_ms: 500",
" validation_probe_event <",
" latency_ms: 40730",
" network_id <",
" network_id: 120",
" >",
" probe_result: 204",
" probe_type: 1",
" >",
">",
"events <",
" apf_statistics <",
" dropped_ras: 2",
" duration_ms: 45000",
" matching_ras: 2",
" max_program_size: 2048",
" parse_errors: 2",
" program_updates: 4",
" received_ras: 10",
" zero_lifetime_ras: 1",
" >",
" time_ms: 600",
">",
"events <",
" ra_event <",
" dnssl_lifetime: -1",
" prefix_preferred_lifetime: 300",
" prefix_valid_lifetime: 400",
" rdnss_lifetime: 1000",
" route_info_lifetime: -1",
" router_lifetime: 2000",
" >",
" time_ms: 700",
">");
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();
}
List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
ArgumentCaptor<ConnectivityMetricsEvent> captor =
ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
return captor.getAllValues();
}
List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
return verifyEvents(n, 10);
}
static void verifySerialization(String want, String output) {
try {
byte[] got = Base64.decode(output, Base64.DEFAULT);
IpConnectivityLogClass.IpConnectivityLog log =
new IpConnectivityLogClass.IpConnectivityLog();
MessageNano.mergeFrom(log, 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).append("\n");
}
return b.toString();
}
static ConnectivityMetricsEvent expectedEvent(int timestamp) {
return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
}
/** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
assertEquals(expected.timestamp, got.timestamp);
assertEquals(expected.componentTag, got.componentTag);
assertEquals(expected.eventTag, got.eventTag);
assertEquals(expected.data, got.data);
}
static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
new Comparator<ConnectivityMetricsEvent>() {
@Override
public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
return (int) (ev1.timestamp - ev2.timestamp);
}
};
}