blob: f98ab3d069212c2ffcb8784ca11626c2642ea6af [file] [log] [blame]
Hugo Benichi5e055182016-06-01 08:50:38 +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
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090019import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
20import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
21import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.fail;
Hugo Benichi5e055182016-06-01 08:50:38 +090023import static org.mockito.Mockito.any;
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090024import static org.mockito.Mockito.mock;
Hugo Benichi5e055182016-06-01 08:50:38 +090025import static org.mockito.Mockito.anyInt;
26import static org.mockito.Mockito.eq;
27import static org.mockito.Mockito.timeout;
28import static org.mockito.Mockito.times;
29import static org.mockito.Mockito.verify;
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090030import static org.mockito.Mockito.when;
Hugo Benichi5e055182016-06-01 08:50:38 +090031
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090032import android.content.Context;
33import android.net.ConnectivityManager;
34import android.net.Network;
35import android.net.NetworkCapabilities;
36import android.support.test.runner.AndroidJUnit4;
37import android.system.OsConstants;
38import android.test.suitebuilder.annotation.SmallTest;
39import android.util.Base64;
40import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.DNSLookupBatch;
41import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
42import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
43import java.io.FileOutputStream;
44import java.io.PrintWriter;
45import java.io.StringWriter;
46import java.util.ArrayList;
47import java.util.Arrays;
48import java.util.Comparator;
49import java.util.List;
50import org.junit.Before;
51import org.junit.Test;
52import org.junit.runner.RunWith;
Hugo Benichi5e055182016-06-01 08:50:38 +090053
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090054@RunWith(AndroidJUnit4.class)
55@SmallTest
56public class NetdEventListenerServiceTest {
Hugo Benichi0d4a3982016-11-25 11:24:22 +090057 private static final String EXAMPLE_IPV4 = "192.0.2.1";
58 private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
59
Michal Karpinski4f261032016-09-26 09:20:25 +010060 NetdEventListenerService mNetdEventListenerService;
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090061 ConnectivityManager mCm;
Hugo Benichi5e055182016-06-01 08:50:38 +090062
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090063 @Before
Hugo Benichi5e055182016-06-01 08:50:38 +090064 public void setUp() {
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090065 NetworkCapabilities ncWifi = new NetworkCapabilities();
66 NetworkCapabilities ncCell = new NetworkCapabilities();
67 ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
68 ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
Hugo Benichi5e055182016-06-01 08:50:38 +090069
Hugo Benichi5eb90532017-03-23 18:38:22 +090070 mCm = mock(ConnectivityManager.class);
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090071 when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
72 when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
Hugo Benichi5e055182016-06-01 08:50:38 +090073
Hugo Benichi5eb90532017-03-23 18:38:22 +090074 mNetdEventListenerService = new NetdEventListenerService(mCm);
75 }
76
77 @Test
78 public void testDnsLogging() throws Exception {
79 asyncDump(100);
80
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090081 dnsEvent(100, EVENT_GETADDRINFO, 0, 3456);
82 dnsEvent(100, EVENT_GETADDRINFO, 0, 267);
83 dnsEvent(100, EVENT_GETHOSTBYNAME, 22, 1230);
84 dnsEvent(100, EVENT_GETADDRINFO, 3, 45);
85 dnsEvent(100, EVENT_GETADDRINFO, 1, 2111);
86 dnsEvent(100, EVENT_GETADDRINFO, 0, 450);
87 dnsEvent(100, EVENT_GETHOSTBYNAME, 200, 638);
88 dnsEvent(100, EVENT_GETHOSTBYNAME, 178, 1300);
89 dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
90 dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
91 dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
92 dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 56);
93 dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
94 dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
Hugo Benichi5e055182016-06-01 08:50:38 +090095
Hugo Benichi2a5cfb92017-03-22 22:21:44 +090096 String got = flushStatistics();
97 String want = String.join("\n",
98 "dropped_events: 0",
99 "events <",
100 " if_name: \"\"",
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900101 " link_layer: 4",
102 " network_id: 100",
103 " time_ms: 0",
104 " transports: 2",
105 " dns_lookup_batch <",
106 " event_types: 1",
107 " event_types: 1",
108 " event_types: 2",
109 " event_types: 1",
110 " event_types: 1",
111 " event_types: 1",
112 " event_types: 2",
113 " event_types: 2",
114 " latencies_ms: 3456",
115 " latencies_ms: 267",
116 " latencies_ms: 1230",
117 " latencies_ms: 45",
118 " latencies_ms: 2111",
119 " latencies_ms: 450",
120 " latencies_ms: 638",
121 " latencies_ms: 1300",
122 " return_codes: 0",
123 " return_codes: 0",
124 " return_codes: 22",
125 " return_codes: 3",
126 " return_codes: 1",
127 " return_codes: 0",
128 " return_codes: 200",
129 " return_codes: 178",
130 " >",
131 ">",
132 "events <",
133 " if_name: \"\"",
134 " link_layer: 2",
135 " network_id: 101",
136 " time_ms: 0",
137 " transports: 1",
138 " dns_lookup_batch <",
139 " event_types: 1",
140 " event_types: 1",
141 " event_types: 1",
142 " event_types: 2",
143 " event_types: 1",
144 " event_types: 1",
145 " latencies_ms: 56",
146 " latencies_ms: 78",
147 " latencies_ms: 14",
148 " latencies_ms: 56",
149 " latencies_ms: 78",
150 " latencies_ms: 14",
151 " return_codes: 0",
152 " return_codes: 0",
153 " return_codes: 0",
154 " return_codes: 0",
155 " return_codes: 0",
156 " return_codes: 0",
157 " >",
158 ">",
159 "version: 2\n");
160 assertEquals(want, got);
Hugo Benichi5e055182016-06-01 08:50:38 +0900161 }
162
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900163 @Test
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900164 public void testConnectLogging() throws Exception {
Hugo Benichi5eb90532017-03-23 18:38:22 +0900165 asyncDump(100);
166
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900167 final int OK = 0;
168 Thread[] logActions = {
169 // ignored
Hugo Benichi5eb90532017-03-23 18:38:22 +0900170 connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV4),
171 connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV6),
172 connectEventAction(100, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV4),
173 connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
174 connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900175 // valid latencies
Hugo Benichi5eb90532017-03-23 18:38:22 +0900176 connectEventAction(100, OK, 110, EXAMPLE_IPV4),
177 connectEventAction(100, OK, 23, EXAMPLE_IPV4),
178 connectEventAction(100, OK, 45, EXAMPLE_IPV4),
179 connectEventAction(101, OK, 56, EXAMPLE_IPV4),
180 connectEventAction(101, OK, 523, EXAMPLE_IPV6),
181 connectEventAction(101, OK, 214, EXAMPLE_IPV6),
182 connectEventAction(101, OK, 67, EXAMPLE_IPV6),
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900183 // errors
Hugo Benichi5eb90532017-03-23 18:38:22 +0900184 connectEventAction(100, OsConstants.EPERM, 0, EXAMPLE_IPV4),
185 connectEventAction(101, OsConstants.EPERM, 0, EXAMPLE_IPV4),
186 connectEventAction(100, OsConstants.EAGAIN, 0, EXAMPLE_IPV4),
187 connectEventAction(100, OsConstants.EACCES, 0, EXAMPLE_IPV4),
188 connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV4),
189 connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV6),
190 connectEventAction(100, OsConstants.EADDRINUSE, 0, EXAMPLE_IPV4),
191 connectEventAction(101, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV4),
192 connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
193 connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
194 connectEventAction(101, OsConstants.ECONNREFUSED, 0, EXAMPLE_IPV4),
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900195 };
196
197 for (Thread t : logActions) {
198 t.start();
199 }
200 for (Thread t : logActions) {
201 t.join();
202 }
203
Hugo Benichi5eb90532017-03-23 18:38:22 +0900204 String got = flushStatistics();
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900205 String want = String.join("\n",
Hugo Benichi5eb90532017-03-23 18:38:22 +0900206 "dropped_events: 0",
207 "events <",
208 " if_name: \"\"",
209 " link_layer: 4",
210 " network_id: 100",
211 " time_ms: 0",
212 " transports: 2",
213 " connect_statistics <",
214 " connect_blocking_count: 3",
215 " connect_count: 6",
216 " errnos_counters <",
217 " key: 1",
218 " value: 1",
219 " >",
220 " errnos_counters <",
221 " key: 11",
222 " value: 1",
223 " >",
224 " errnos_counters <",
225 " key: 13",
226 " value: 1",
227 " >",
228 " errnos_counters <",
229 " key: 98",
230 " value: 1",
231 " >",
232 " errnos_counters <",
233 " key: 110",
234 " value: 2",
235 " >",
236 " ipv6_addr_count: 1",
237 " latencies_ms: 23",
238 " latencies_ms: 45",
239 " latencies_ms: 110",
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900240 " >",
Hugo Benichi5eb90532017-03-23 18:38:22 +0900241 ">",
242 "events <",
243 " if_name: \"\"",
244 " link_layer: 2",
245 " network_id: 101",
246 " time_ms: 0",
247 " transports: 1",
248 " connect_statistics <",
249 " connect_blocking_count: 4",
250 " connect_count: 6",
251 " errnos_counters <",
252 " key: 1",
253 " value: 1",
254 " >",
255 " errnos_counters <",
256 " key: 13",
257 " value: 2",
258 " >",
259 " errnos_counters <",
260 " key: 110",
261 " value: 1",
262 " >",
263 " errnos_counters <",
264 " key: 111",
265 " value: 1",
266 " >",
267 " ipv6_addr_count: 5",
268 " latencies_ms: 56",
269 " latencies_ms: 67",
270 " latencies_ms: 214",
271 " latencies_ms: 523",
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900272 " >",
Hugo Benichi5eb90532017-03-23 18:38:22 +0900273 ">",
274 "version: 2\n");
275 assertEquals(want, got);
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900276 }
277
Hugo Benichi5eb90532017-03-23 18:38:22 +0900278 Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) {
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900279 return new Thread(() -> {
280 try {
Hugo Benichi5eb90532017-03-23 18:38:22 +0900281 mNetdEventListenerService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900282 } catch (Exception e) {
283 fail(e.toString());
284 }
285 });
286 }
287
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900288 void dnsEvent(int netId, int type, int result, int latency) throws Exception {
289 mNetdEventListenerService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
290 }
291
Hugo Benichi5eb90532017-03-23 18:38:22 +0900292 void asyncDump(long durationMs) throws Exception {
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900293 final long stop = System.currentTimeMillis() + durationMs;
294 final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
Hugo Benichi5eb90532017-03-23 18:38:22 +0900295 new Thread(() -> {
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900296 while (System.currentTimeMillis() < stop) {
297 mNetdEventListenerService.dump(pw);
Michal Karpinskidd9bb4f2016-10-12 14:59:26 +0100298 }
Hugo Benichi5eb90532017-03-23 18:38:22 +0900299 }).start();
Hugo Benichi0d4a3982016-11-25 11:24:22 +0900300 }
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900301
302 // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
303 String flushStatistics() throws Exception {
304 IpConnectivityMetrics metricsService =
305 new IpConnectivityMetrics(mock(Context.class), (ctx) -> 2000);
306 metricsService.mNetdListener = mNetdEventListenerService;
307
308 StringWriter buffer = new StringWriter();
309 PrintWriter writer = new PrintWriter(buffer);
310 metricsService.impl.dump(null, writer, new String[]{"flush"});
311 byte[] bytes = Base64.decode(buffer.toString(), Base64.DEFAULT);
Hugo Benichi5eb90532017-03-23 18:38:22 +0900312 IpConnectivityLog log = IpConnectivityLog.parseFrom(bytes);
313 for (IpConnectivityEvent ev : log.events) {
314 if (ev.getConnectStatistics() == null) {
315 continue;
316 }
317 // Sort repeated fields of connect() events arriving in non-deterministic order.
318 Arrays.sort(ev.getConnectStatistics().latenciesMs);
319 Arrays.sort(ev.getConnectStatistics().errnosCounters,
320 Comparator.comparingInt((p) -> p.key));
321 }
322 return log.toString();
Hugo Benichi2a5cfb92017-03-22 22:21:44 +0900323 }
Hugo Benichi5e055182016-06-01 08:50:38 +0900324}