blob: 78d16d93287ec300add1437b7e6ad28577a1e599 [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;
35import android.util.Base64;
Glen Kuhne07199402016-10-25 15:47:25 -070036
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010037import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
Glen Kuhne07199402016-10-25 15:47:25 -070038
39import junit.framework.TestCase;
40
41import org.mockito.ArgumentCaptor;
42import org.mockito.Mock;
43import org.mockito.MockitoAnnotations;
44
Hugo Benichi00a42d42016-09-13 15:55:09 +090045import java.io.PrintWriter;
46import java.io.StringWriter;
47import java.util.Collections;
48import java.util.Comparator;
49import java.util.Iterator;
50import java.util.List;
Hugo Benichi00a42d42016-09-13 15:55:09 +090051
52public class IpConnectivityMetricsTest extends TestCase {
53 static final IpReachabilityEvent FAKE_EV =
54 new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED);
55
56 @Mock Context mCtx;
57 @Mock IIpConnectivityMetrics mMockService;
58
59 IpConnectivityMetrics mService;
60
61 public void setUp() {
62 MockitoAnnotations.initMocks(this);
Hugo Benichi05686db2016-10-19 11:17:28 +090063 mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
Hugo Benichi00a42d42016-09-13 15:55:09 +090064 }
65
66 public void testLoggingEvents() throws Exception {
67 IpConnectivityLog logger = new IpConnectivityLog(mMockService);
68
69 assertTrue(logger.log(1, FAKE_EV));
70 assertTrue(logger.log(2, FAKE_EV));
71 assertTrue(logger.log(3, FAKE_EV));
72
73 List<ConnectivityMetricsEvent> got = verifyEvents(3);
74 assertEventsEqual(expectedEvent(1), got.get(0));
75 assertEventsEqual(expectedEvent(2), got.get(1));
76 assertEventsEqual(expectedEvent(3), got.get(2));
77 }
78
79 public void testLoggingEventsWithMultipleCallers() throws Exception {
80 IpConnectivityLog logger = new IpConnectivityLog(mMockService);
81
82 final int nCallers = 10;
83 final int nEvents = 10;
84 for (int n = 0; n < nCallers; n++) {
85 final int i = n;
86 new Thread() {
87 public void run() {
88 for (int j = 0; j < nEvents; j++) {
89 assertTrue(logger.log(i * 100 + j, FAKE_EV));
90 }
91 }
92 }.start();
93 }
94
95 List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 100);
96 Collections.sort(got, EVENT_COMPARATOR);
97 Iterator<ConnectivityMetricsEvent> iter = got.iterator();
98 for (int i = 0; i < nCallers; i++) {
99 for (int j = 0; j < nEvents; j++) {
100 int expectedTimestamp = i * 100 + j;
101 assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
102 }
103 }
104 }
105
106 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 Benichie1c173d2016-10-18 10:36:33 +0900118 public void testRateLimiting() {
119 final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
120 final ApfProgramEvent ev = new ApfProgramEvent(0, 0, 0, 0, 0);
121 final long fakeTimestamp = 1;
122
123 int attempt = 100; // More than burst quota, but less than buffer size.
124 for (int i = 0; i < attempt; i++) {
125 logger.log(ev);
126 }
127
128 String output1 = getdump("flush");
129 assertFalse("".equals(output1));
130
131 for (int i = 0; i < attempt; i++) {
132 assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
133 }
134
135 String output2 = getdump("flush");
136 assertEquals("", output2);
137 }
138
Hugo Benichi00a42d42016-09-13 15:55:09 +0900139 public void testEndToEndLogging() {
140 IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
141
142 Parcelable[] events = {
143 new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED),
144 new DhcpClientEvent("wlan0", "SomeState", 192),
145 new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false),
146 new IpManagerEvent("wlan0", IpManagerEvent.PROVISIONING_OK, 5678),
147 new ValidationProbeEvent(120, 40730, ValidationProbeEvent.PROBE_HTTP, 204),
148 new ApfStats(45000, 10, 2, 2, 1, 2, 4, 2048),
149 new RaEvent(2000, 400, 300, -1, 1000, -1)
150 };
151
152 for (int i = 0; i < events.length; i++) {
153 logger.log(100 * (i + 1), events[i]);
154 }
155
156 String want = joinLines(
157 "dropped_events: 0",
158 "events <",
159 " ip_reachability_event <",
160 " event_type: 512",
161 " if_name: \"wlan0\"",
162 " >",
163 " time_ms: 100",
164 ">",
165 "events <",
166 " dhcp_event <",
167 " duration_ms: 192",
168 " error_code: 0",
169 " if_name: \"wlan0\"",
170 " state_transition: \"SomeState\"",
171 " >",
172 " time_ms: 200",
173 ">",
174 "events <",
175 " default_network_event <",
176 " network_id <",
177 " network_id: 102",
178 " >",
179 " previous_network_id <",
180 " network_id: 101",
181 " >",
182 " previous_network_ip_support: 1",
183 " transport_types: 1",
184 " transport_types: 2",
185 " transport_types: 3",
186 " >",
187 " time_ms: 300",
188 ">",
189 "events <",
190 " ip_provisioning_event <",
191 " event_type: 1",
192 " if_name: \"wlan0\"",
193 " latency_ms: 5678",
194 " >",
195 " time_ms: 400",
196 ">",
197 "events <",
198 " time_ms: 500",
199 " validation_probe_event <",
200 " latency_ms: 40730",
201 " network_id <",
202 " network_id: 120",
203 " >",
204 " probe_result: 204",
205 " probe_type: 1",
206 " >",
207 ">",
208 "events <",
209 " apf_statistics <",
210 " dropped_ras: 2",
211 " duration_ms: 45000",
212 " matching_ras: 2",
213 " max_program_size: 2048",
214 " parse_errors: 2",
215 " program_updates: 4",
216 " received_ras: 10",
217 " zero_lifetime_ras: 1",
218 " >",
219 " time_ms: 600",
220 ">",
221 "events <",
222 " ra_event <",
223 " dnssl_lifetime: -1",
224 " prefix_preferred_lifetime: 300",
225 " prefix_valid_lifetime: 400",
226 " rdnss_lifetime: 1000",
227 " route_info_lifetime: -1",
228 " router_lifetime: 2000",
229 " >",
230 " time_ms: 700",
Hugo Benichid680d4c2016-10-13 13:16:16 +0900231 ">",
232 "version: 2");
Hugo Benichi00a42d42016-09-13 15:55:09 +0900233
234 verifySerialization(want, getdump("flush"));
235 }
236
237 String getdump(String ... command) {
238 StringWriter buffer = new StringWriter();
239 PrintWriter writer = new PrintWriter(buffer);
240 mService.impl.dump(null, writer, command);
241 return buffer.toString();
242 }
243
244 List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
245 ArgumentCaptor<ConnectivityMetricsEvent> captor =
246 ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
247 verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
248 return captor.getAllValues();
249 }
250
251 List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
252 return verifyEvents(n, 10);
253 }
254
255 static void verifySerialization(String want, String output) {
256 try {
257 byte[] got = Base64.decode(output, Base64.DEFAULT);
258 IpConnectivityLogClass.IpConnectivityLog log =
Glen Kuhne07199402016-10-25 15:47:25 -0700259 IpConnectivityLogClass.IpConnectivityLog.parseFrom(got);
Hugo Benichi00a42d42016-09-13 15:55:09 +0900260 assertEquals(want, log.toString());
261 } catch (Exception e) {
262 fail(e.toString());
263 }
264 }
265
266 static String joinLines(String ... elems) {
267 StringBuilder b = new StringBuilder();
268 for (String s : elems) {
269 b.append(s).append("\n");
270 }
271 return b.toString();
272 }
273
274 static ConnectivityMetricsEvent expectedEvent(int timestamp) {
275 return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
276 }
277
278 /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
279 static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
280 assertEquals(expected.timestamp, got.timestamp);
281 assertEquals(expected.componentTag, got.componentTag);
282 assertEquals(expected.eventTag, got.eventTag);
283 assertEquals(expected.data, got.data);
284 }
285
286 static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
287 new Comparator<ConnectivityMetricsEvent>() {
288 @Override
289 public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
290 return (int) (ev1.timestamp - ev2.timestamp);
291 }
292 };
293}