blob: da2c0d9f89799bc2775f6804c3d0a2ebf24aefb6 [file] [log] [blame]
Hugo Benichi00a42d42016-09-13 15:55:09 +09001/*
2 * Copyright (C) 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.connectivity;
18
19import android.content.Context;
20import android.net.ConnectivityMetricsEvent;
21import android.net.IIpConnectivityMetrics;
Hugo Benichie1c173d2016-10-18 10:36:33 +090022import android.net.metrics.ApfProgramEvent;
Hugo Benichi00a42d42016-09-13 15:55:09 +090023import android.net.metrics.ApfStats;
24import android.net.metrics.DefaultNetworkEvent;
25import android.net.metrics.DhcpClientEvent;
26import android.net.metrics.IpConnectivityLog;
27import android.net.metrics.IpManagerEvent;
28import android.net.metrics.IpReachabilityEvent;
29import android.net.metrics.RaEvent;
30import android.net.metrics.ValidationProbeEvent;
31import android.os.Parcelable;
32import android.util.Base64;
33import com.android.server.connectivity.metrics.IpConnectivityLogClass;
34import com.google.protobuf.nano.MessageNano;
35import java.io.PrintWriter;
36import java.io.StringWriter;
37import java.util.Collections;
38import java.util.Comparator;
39import java.util.Iterator;
40import java.util.List;
41import junit.framework.TestCase;
42import org.mockito.ArgumentCaptor;
43import org.mockito.Mock;
44import org.mockito.MockitoAnnotations;
45
46import static org.mockito.Mockito.timeout;
47import static org.mockito.Mockito.times;
48import static org.mockito.Mockito.verify;
49
50public class IpConnectivityMetricsTest extends TestCase {
51 static final IpReachabilityEvent FAKE_EV =
52 new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED);
53
54 @Mock Context mCtx;
55 @Mock IIpConnectivityMetrics mMockService;
56
57 IpConnectivityMetrics mService;
58
59 public void setUp() {
60 MockitoAnnotations.initMocks(this);
Hugo Benichi05686db2016-10-19 11:17:28 +090061 mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
Hugo Benichi00a42d42016-09-13 15:55:09 +090062 }
63
64 public void testLoggingEvents() throws Exception {
65 IpConnectivityLog logger = new IpConnectivityLog(mMockService);
66
67 assertTrue(logger.log(1, FAKE_EV));
68 assertTrue(logger.log(2, FAKE_EV));
69 assertTrue(logger.log(3, FAKE_EV));
70
71 List<ConnectivityMetricsEvent> got = verifyEvents(3);
72 assertEventsEqual(expectedEvent(1), got.get(0));
73 assertEventsEqual(expectedEvent(2), got.get(1));
74 assertEventsEqual(expectedEvent(3), got.get(2));
75 }
76
77 public void testLoggingEventsWithMultipleCallers() throws Exception {
78 IpConnectivityLog logger = new IpConnectivityLog(mMockService);
79
80 final int nCallers = 10;
81 final int nEvents = 10;
82 for (int n = 0; n < nCallers; n++) {
83 final int i = n;
84 new Thread() {
85 public void run() {
86 for (int j = 0; j < nEvents; j++) {
87 assertTrue(logger.log(i * 100 + j, FAKE_EV));
88 }
89 }
90 }.start();
91 }
92
93 List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 100);
94 Collections.sort(got, EVENT_COMPARATOR);
95 Iterator<ConnectivityMetricsEvent> iter = got.iterator();
96 for (int i = 0; i < nCallers; i++) {
97 for (int j = 0; j < nEvents; j++) {
98 int expectedTimestamp = i * 100 + j;
99 assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
100 }
101 }
102 }
103
104 public void testBufferFlushing() {
105 String output1 = getdump("flush");
106 assertEquals("", output1);
107
108 new IpConnectivityLog(mService.impl).log(1, FAKE_EV);
109 String output2 = getdump("flush");
110 assertFalse("".equals(output2));
111
112 String output3 = getdump("flush");
113 assertEquals("", output3);
114 }
115
Hugo Benichie1c173d2016-10-18 10:36:33 +0900116 public void testRateLimiting() {
117 final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
118 final ApfProgramEvent ev = new ApfProgramEvent(0, 0, 0, 0, 0);
119 final long fakeTimestamp = 1;
120
121 int attempt = 100; // More than burst quota, but less than buffer size.
122 for (int i = 0; i < attempt; i++) {
123 logger.log(ev);
124 }
125
126 String output1 = getdump("flush");
127 assertFalse("".equals(output1));
128
129 for (int i = 0; i < attempt; i++) {
130 assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
131 }
132
133 String output2 = getdump("flush");
134 assertEquals("", output2);
135 }
136
Hugo Benichi00a42d42016-09-13 15:55:09 +0900137 public void testEndToEndLogging() {
138 IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
139
140 Parcelable[] events = {
141 new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED),
142 new DhcpClientEvent("wlan0", "SomeState", 192),
143 new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false),
144 new IpManagerEvent("wlan0", IpManagerEvent.PROVISIONING_OK, 5678),
145 new ValidationProbeEvent(120, 40730, ValidationProbeEvent.PROBE_HTTP, 204),
146 new ApfStats(45000, 10, 2, 2, 1, 2, 4, 2048),
147 new RaEvent(2000, 400, 300, -1, 1000, -1)
148 };
149
150 for (int i = 0; i < events.length; i++) {
151 logger.log(100 * (i + 1), events[i]);
152 }
153
154 String want = joinLines(
155 "dropped_events: 0",
156 "events <",
157 " ip_reachability_event <",
158 " event_type: 512",
159 " if_name: \"wlan0\"",
160 " >",
161 " time_ms: 100",
162 ">",
163 "events <",
164 " dhcp_event <",
165 " duration_ms: 192",
166 " error_code: 0",
167 " if_name: \"wlan0\"",
168 " state_transition: \"SomeState\"",
169 " >",
170 " time_ms: 200",
171 ">",
172 "events <",
173 " default_network_event <",
174 " network_id <",
175 " network_id: 102",
176 " >",
177 " previous_network_id <",
178 " network_id: 101",
179 " >",
180 " previous_network_ip_support: 1",
181 " transport_types: 1",
182 " transport_types: 2",
183 " transport_types: 3",
184 " >",
185 " time_ms: 300",
186 ">",
187 "events <",
188 " ip_provisioning_event <",
189 " event_type: 1",
190 " if_name: \"wlan0\"",
191 " latency_ms: 5678",
192 " >",
193 " time_ms: 400",
194 ">",
195 "events <",
196 " time_ms: 500",
197 " validation_probe_event <",
198 " latency_ms: 40730",
199 " network_id <",
200 " network_id: 120",
201 " >",
202 " probe_result: 204",
203 " probe_type: 1",
204 " >",
205 ">",
206 "events <",
207 " apf_statistics <",
208 " dropped_ras: 2",
209 " duration_ms: 45000",
210 " matching_ras: 2",
211 " max_program_size: 2048",
212 " parse_errors: 2",
213 " program_updates: 4",
214 " received_ras: 10",
215 " zero_lifetime_ras: 1",
216 " >",
217 " time_ms: 600",
218 ">",
219 "events <",
220 " ra_event <",
221 " dnssl_lifetime: -1",
222 " prefix_preferred_lifetime: 300",
223 " prefix_valid_lifetime: 400",
224 " rdnss_lifetime: 1000",
225 " route_info_lifetime: -1",
226 " router_lifetime: 2000",
227 " >",
228 " time_ms: 700",
229 ">");
230
231 verifySerialization(want, getdump("flush"));
232 }
233
234 String getdump(String ... command) {
235 StringWriter buffer = new StringWriter();
236 PrintWriter writer = new PrintWriter(buffer);
237 mService.impl.dump(null, writer, command);
238 return buffer.toString();
239 }
240
241 List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
242 ArgumentCaptor<ConnectivityMetricsEvent> captor =
243 ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
244 verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
245 return captor.getAllValues();
246 }
247
248 List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
249 return verifyEvents(n, 10);
250 }
251
252 static void verifySerialization(String want, String output) {
253 try {
254 byte[] got = Base64.decode(output, Base64.DEFAULT);
255 IpConnectivityLogClass.IpConnectivityLog log =
256 new IpConnectivityLogClass.IpConnectivityLog();
257 MessageNano.mergeFrom(log, got);
258 assertEquals(want, log.toString());
259 } catch (Exception e) {
260 fail(e.toString());
261 }
262 }
263
264 static String joinLines(String ... elems) {
265 StringBuilder b = new StringBuilder();
266 for (String s : elems) {
267 b.append(s).append("\n");
268 }
269 return b.toString();
270 }
271
272 static ConnectivityMetricsEvent expectedEvent(int timestamp) {
273 return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
274 }
275
276 /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
277 static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
278 assertEquals(expected.timestamp, got.timestamp);
279 assertEquals(expected.componentTag, got.componentTag);
280 assertEquals(expected.eventTag, got.eventTag);
281 assertEquals(expected.data, got.data);
282 }
283
284 static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
285 new Comparator<ConnectivityMetricsEvent>() {
286 @Override
287 public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
288 return (int) (ev1.timestamp - ev2.timestamp);
289 }
290 };
291}