blob: fd81c90a050c79424ae6c02894bad2cce3845435 [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
Glen Kuhne07199402016-10-25 15:47:25 -070019import static org.mockito.Mockito.timeout;
20import static org.mockito.Mockito.verify;
21
Hugo Benichi00a42d42016-09-13 15:55:09 +090022import android.content.Context;
23import android.net.ConnectivityMetricsEvent;
24import android.net.IIpConnectivityMetrics;
Hugo Benichie1c173d2016-10-18 10:36:33 +090025import android.net.metrics.ApfProgramEvent;
Hugo Benichi00a42d42016-09-13 15:55:09 +090026import android.net.metrics.ApfStats;
27import android.net.metrics.DefaultNetworkEvent;
28import android.net.metrics.DhcpClientEvent;
29import android.net.metrics.IpConnectivityLog;
30import android.net.metrics.IpManagerEvent;
31import android.net.metrics.IpReachabilityEvent;
32import android.net.metrics.RaEvent;
33import android.net.metrics.ValidationProbeEvent;
34import android.os.Parcelable;
Hugo Benichi80df43e2016-11-24 11:28:06 +090035import android.test.suitebuilder.annotation.SmallTest;
Hugo Benichi00a42d42016-09-13 15:55:09 +090036import android.util.Base64;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010037import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
Hugo Benichi00a42d42016-09-13 15:55:09 +090038import java.io.PrintWriter;
39import java.io.StringWriter;
40import java.util.Collections;
41import java.util.Comparator;
42import java.util.Iterator;
43import java.util.List;
Hugo Benichi80df43e2016-11-24 11:28:06 +090044import junit.framework.TestCase;
45import org.mockito.ArgumentCaptor;
46import org.mockito.Mock;
47import org.mockito.MockitoAnnotations;
Hugo Benichi00a42d42016-09-13 15:55:09 +090048
49public class IpConnectivityMetricsTest extends TestCase {
50 static final IpReachabilityEvent FAKE_EV =
Hugo Benichi948a8592017-03-16 16:33:47 +090051 new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
Hugo Benichi00a42d42016-09-13 15:55:09 +090052
53 @Mock Context mCtx;
54 @Mock IIpConnectivityMetrics mMockService;
55
56 IpConnectivityMetrics mService;
57
58 public void setUp() {
59 MockitoAnnotations.initMocks(this);
Hugo Benichi05686db2016-10-19 11:17:28 +090060 mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
Hugo Benichi00a42d42016-09-13 15:55:09 +090061 }
62
Hugo Benichi80df43e2016-11-24 11:28:06 +090063 @SmallTest
Hugo Benichi00a42d42016-09-13 15:55:09 +090064 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
Hugo Benichi80df43e2016-11-24 11:28:06 +090077 @SmallTest
Hugo Benichi00a42d42016-09-13 15:55:09 +090078 public void testLoggingEventsWithMultipleCallers() throws Exception {
79 IpConnectivityLog logger = new IpConnectivityLog(mMockService);
80
81 final int nCallers = 10;
82 final int nEvents = 10;
83 for (int n = 0; n < nCallers; n++) {
84 final int i = n;
85 new Thread() {
86 public void run() {
87 for (int j = 0; j < nEvents; j++) {
Hugo Benichi946b7e42017-03-15 16:35:26 +090088 assertTrue(logger.log(1 + i * 100 + j, FAKE_EV));
Hugo Benichi00a42d42016-09-13 15:55:09 +090089 }
90 }
91 }.start();
92 }
93
94 List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 100);
95 Collections.sort(got, EVENT_COMPARATOR);
96 Iterator<ConnectivityMetricsEvent> iter = got.iterator();
97 for (int i = 0; i < nCallers; i++) {
98 for (int j = 0; j < nEvents; j++) {
Hugo Benichi946b7e42017-03-15 16:35:26 +090099 int expectedTimestamp = 1 + i * 100 + j;
Hugo Benichi00a42d42016-09-13 15:55:09 +0900100 assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
101 }
102 }
103 }
104
Hugo Benichi80df43e2016-11-24 11:28:06 +0900105 @SmallTest
Hugo Benichi00a42d42016-09-13 15:55:09 +0900106 public void testBufferFlushing() {
107 String output1 = getdump("flush");
108 assertEquals("", output1);
109
110 new IpConnectivityLog(mService.impl).log(1, FAKE_EV);
111 String output2 = getdump("flush");
112 assertFalse("".equals(output2));
113
114 String output3 = getdump("flush");
115 assertEquals("", output3);
116 }
117
Hugo Benichi80df43e2016-11-24 11:28:06 +0900118 @SmallTest
Hugo Benichie1c173d2016-10-18 10:36:33 +0900119 public void testRateLimiting() {
120 final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
Hugo Benichi22d9b2d2017-02-22 13:02:27 +0900121 final ApfProgramEvent ev = new ApfProgramEvent();
Hugo Benichie1c173d2016-10-18 10:36:33 +0900122 final long fakeTimestamp = 1;
123
124 int attempt = 100; // More than burst quota, but less than buffer size.
125 for (int i = 0; i < attempt; i++) {
126 logger.log(ev);
127 }
128
129 String output1 = getdump("flush");
130 assertFalse("".equals(output1));
131
132 for (int i = 0; i < attempt; i++) {
133 assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
134 }
135
136 String output2 = getdump("flush");
137 assertEquals("", output2);
138 }
139
Hugo Benichi80df43e2016-11-24 11:28:06 +0900140 @SmallTest
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900141 // TODO: add NetdEventListenerService coverage too
Hugo Benichi00a42d42016-09-13 15:55:09 +0900142 public void testEndToEndLogging() {
Hugo Benichif6840502017-03-08 11:59:36 +0900143 // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
Hugo Benichi00a42d42016-09-13 15:55:09 +0900144 IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
145
Hugo Benichi22d9b2d2017-02-22 13:02:27 +0900146 ApfStats apfStats = new ApfStats();
147 apfStats.durationMs = 45000;
148 apfStats.receivedRas = 10;
149 apfStats.matchingRas = 2;
150 apfStats.droppedRas = 2;
151 apfStats.parseErrors = 2;
152 apfStats.zeroLifetimeRas = 1;
153 apfStats.programUpdates = 4;
154 apfStats.programUpdatesAll = 7;
155 apfStats.programUpdatesAllowingMulticast = 3;
156 apfStats.maxProgramSize = 2048;
Hugo Benichif927f0c2017-03-17 15:42:40 +0900157
158 ValidationProbeEvent validationEv = new ValidationProbeEvent();
159 validationEv.durationMs = 40730;
160 validationEv.probeType = ValidationProbeEvent.PROBE_HTTP;
161 validationEv.returnCode = 204;
162
Hugo Benichi00a42d42016-09-13 15:55:09 +0900163 Parcelable[] events = {
Hugo Benichi948a8592017-03-16 16:33:47 +0900164 new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED),
165 new DhcpClientEvent("SomeState", 192),
Hugo Benichi00a42d42016-09-13 15:55:09 +0900166 new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false),
Hugo Benichi948a8592017-03-16 16:33:47 +0900167 new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678),
Hugo Benichif927f0c2017-03-17 15:42:40 +0900168 validationEv,
Hugo Benichi22d9b2d2017-02-22 13:02:27 +0900169 apfStats,
Hugo Benichi00a42d42016-09-13 15:55:09 +0900170 new RaEvent(2000, 400, 300, -1, 1000, -1)
171 };
172
173 for (int i = 0; i < events.length; i++) {
Hugo Benichi948a8592017-03-16 16:33:47 +0900174 ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
175 ev.timestamp = 100 * (i + 1);
176 ev.ifname = "wlan0";
177 ev.data = events[i];
178 logger.log(ev);
Hugo Benichi00a42d42016-09-13 15:55:09 +0900179 }
180
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900181 String want = String.join("\n",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900182 "dropped_events: 0",
183 "events <",
Hugo Benichif6840502017-03-08 11:59:36 +0900184 " if_name: \"\"",
Hugo Benichi948a8592017-03-16 16:33:47 +0900185 " link_layer: 4",
Hugo Benichif6840502017-03-08 11:59:36 +0900186 " network_id: 0",
Hugo Benichi80df43e2016-11-24 11:28:06 +0900187 " time_ms: 100",
Hugo Benichif6840502017-03-08 11:59:36 +0900188 " transports: 0",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900189 " ip_reachability_event <",
190 " event_type: 512",
Hugo Benichi948a8592017-03-16 16:33:47 +0900191 " if_name: \"\"",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900192 " >",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900193 ">",
194 "events <",
Hugo Benichif6840502017-03-08 11:59:36 +0900195 " if_name: \"\"",
Hugo Benichi948a8592017-03-16 16:33:47 +0900196 " link_layer: 4",
Hugo Benichif6840502017-03-08 11:59:36 +0900197 " network_id: 0",
Hugo Benichi80df43e2016-11-24 11:28:06 +0900198 " time_ms: 200",
Hugo Benichif6840502017-03-08 11:59:36 +0900199 " transports: 0",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900200 " dhcp_event <",
201 " duration_ms: 192",
Hugo Benichi948a8592017-03-16 16:33:47 +0900202 " if_name: \"\"",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900203 " state_transition: \"SomeState\"",
204 " >",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900205 ">",
206 "events <",
Hugo Benichif6840502017-03-08 11:59:36 +0900207 " if_name: \"\"",
Hugo Benichi948a8592017-03-16 16:33:47 +0900208 " link_layer: 4",
Hugo Benichif6840502017-03-08 11:59:36 +0900209 " network_id: 0",
Hugo Benichi80df43e2016-11-24 11:28:06 +0900210 " time_ms: 300",
Hugo Benichif6840502017-03-08 11:59:36 +0900211 " transports: 0",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900212 " default_network_event <",
213 " network_id <",
214 " network_id: 102",
215 " >",
216 " previous_network_id <",
217 " network_id: 101",
218 " >",
219 " previous_network_ip_support: 1",
220 " transport_types: 1",
221 " transport_types: 2",
222 " transport_types: 3",
223 " >",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900224 ">",
225 "events <",
Hugo Benichif6840502017-03-08 11:59:36 +0900226 " if_name: \"\"",
Hugo Benichi948a8592017-03-16 16:33:47 +0900227 " link_layer: 4",
Hugo Benichif6840502017-03-08 11:59:36 +0900228 " network_id: 0",
Hugo Benichi80df43e2016-11-24 11:28:06 +0900229 " time_ms: 400",
Hugo Benichif6840502017-03-08 11:59:36 +0900230 " transports: 0",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900231 " ip_provisioning_event <",
232 " event_type: 1",
Hugo Benichi948a8592017-03-16 16:33:47 +0900233 " if_name: \"\"",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900234 " latency_ms: 5678",
235 " >",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900236 ">",
237 "events <",
Hugo Benichif6840502017-03-08 11:59:36 +0900238 " if_name: \"\"",
Hugo Benichi948a8592017-03-16 16:33:47 +0900239 " link_layer: 4",
Hugo Benichif6840502017-03-08 11:59:36 +0900240 " network_id: 0",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900241 " time_ms: 500",
Hugo Benichif6840502017-03-08 11:59:36 +0900242 " transports: 0",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900243 " validation_probe_event <",
244 " latency_ms: 40730",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900245 " probe_result: 204",
246 " probe_type: 1",
247 " >",
248 ">",
249 "events <",
Hugo Benichif6840502017-03-08 11:59:36 +0900250 " if_name: \"\"",
Hugo Benichi948a8592017-03-16 16:33:47 +0900251 " link_layer: 4",
Hugo Benichif6840502017-03-08 11:59:36 +0900252 " network_id: 0",
Hugo Benichi80df43e2016-11-24 11:28:06 +0900253 " time_ms: 600",
Hugo Benichif6840502017-03-08 11:59:36 +0900254 " transports: 0",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900255 " apf_statistics <",
256 " dropped_ras: 2",
257 " duration_ms: 45000",
258 " matching_ras: 2",
259 " max_program_size: 2048",
260 " parse_errors: 2",
261 " program_updates: 4",
Hugo Benichi22d9b2d2017-02-22 13:02:27 +0900262 " program_updates_all: 7",
263 " program_updates_allowing_multicast: 3",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900264 " received_ras: 10",
265 " zero_lifetime_ras: 1",
266 " >",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900267 ">",
268 "events <",
Hugo Benichif6840502017-03-08 11:59:36 +0900269 " if_name: \"\"",
Hugo Benichi948a8592017-03-16 16:33:47 +0900270 " link_layer: 4",
Hugo Benichif6840502017-03-08 11:59:36 +0900271 " network_id: 0",
Hugo Benichi80df43e2016-11-24 11:28:06 +0900272 " time_ms: 700",
Hugo Benichif6840502017-03-08 11:59:36 +0900273 " transports: 0",
Hugo Benichi00a42d42016-09-13 15:55:09 +0900274 " ra_event <",
275 " dnssl_lifetime: -1",
276 " prefix_preferred_lifetime: 300",
277 " prefix_valid_lifetime: 400",
278 " rdnss_lifetime: 1000",
279 " route_info_lifetime: -1",
280 " router_lifetime: 2000",
281 " >",
Hugo Benichid680d4c2016-10-13 13:16:16 +0900282 ">",
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900283 "version: 2\n");
Hugo Benichi00a42d42016-09-13 15:55:09 +0900284
285 verifySerialization(want, getdump("flush"));
286 }
287
288 String getdump(String ... command) {
289 StringWriter buffer = new StringWriter();
290 PrintWriter writer = new PrintWriter(buffer);
291 mService.impl.dump(null, writer, command);
292 return buffer.toString();
293 }
294
295 List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
296 ArgumentCaptor<ConnectivityMetricsEvent> captor =
297 ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
298 verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
299 return captor.getAllValues();
300 }
301
302 List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
303 return verifyEvents(n, 10);
304 }
305
306 static void verifySerialization(String want, String output) {
307 try {
308 byte[] got = Base64.decode(output, Base64.DEFAULT);
309 IpConnectivityLogClass.IpConnectivityLog log =
Glen Kuhne07199402016-10-25 15:47:25 -0700310 IpConnectivityLogClass.IpConnectivityLog.parseFrom(got);
Hugo Benichi00a42d42016-09-13 15:55:09 +0900311 assertEquals(want, log.toString());
312 } catch (Exception e) {
313 fail(e.toString());
314 }
315 }
316
317 static String joinLines(String ... elems) {
318 StringBuilder b = new StringBuilder();
319 for (String s : elems) {
320 b.append(s).append("\n");
321 }
322 return b.toString();
323 }
324
325 static ConnectivityMetricsEvent expectedEvent(int timestamp) {
Hugo Benichiec27c4d2017-03-15 15:07:42 +0900326 ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
327 ev.timestamp = timestamp;
328 ev.data = FAKE_EV;
329 return ev;
Hugo Benichi00a42d42016-09-13 15:55:09 +0900330 }
331
332 /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
333 static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
334 assertEquals(expected.timestamp, got.timestamp);
Hugo Benichi00a42d42016-09-13 15:55:09 +0900335 assertEquals(expected.data, got.data);
336 }
337
338 static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900339 Comparator.comparingLong((ev) -> ev.timestamp);
Hugo Benichi00a42d42016-09-13 15:55:09 +0900340}