Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.server.connectivity; |
| 18 | |
Glen Kuhne | 0719940 | 2016-10-25 15:47:25 -0700 | [diff] [blame] | 19 | import static org.mockito.Mockito.timeout; |
| 20 | import static org.mockito.Mockito.verify; |
| 21 | |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 22 | import android.content.Context; |
| 23 | import android.net.ConnectivityMetricsEvent; |
| 24 | import android.net.IIpConnectivityMetrics; |
Hugo Benichi | e1c173d | 2016-10-18 10:36:33 +0900 | [diff] [blame] | 25 | import android.net.metrics.ApfProgramEvent; |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 26 | import android.net.metrics.ApfStats; |
| 27 | import android.net.metrics.DefaultNetworkEvent; |
| 28 | import android.net.metrics.DhcpClientEvent; |
| 29 | import android.net.metrics.IpConnectivityLog; |
| 30 | import android.net.metrics.IpManagerEvent; |
| 31 | import android.net.metrics.IpReachabilityEvent; |
| 32 | import android.net.metrics.RaEvent; |
| 33 | import android.net.metrics.ValidationProbeEvent; |
| 34 | import android.os.Parcelable; |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 35 | import android.test.suitebuilder.annotation.SmallTest; |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 36 | import android.util.Base64; |
Tamas Berghammer | 383db5eb | 2016-06-22 15:21:38 +0100 | [diff] [blame] | 37 | import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass; |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 38 | import java.io.PrintWriter; |
| 39 | import java.io.StringWriter; |
| 40 | import java.util.Collections; |
| 41 | import java.util.Comparator; |
| 42 | import java.util.Iterator; |
| 43 | import java.util.List; |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 44 | import junit.framework.TestCase; |
| 45 | import org.mockito.ArgumentCaptor; |
| 46 | import org.mockito.Mock; |
| 47 | import org.mockito.MockitoAnnotations; |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 48 | |
| 49 | public class IpConnectivityMetricsTest extends TestCase { |
| 50 | static final IpReachabilityEvent FAKE_EV = |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 51 | new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED); |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 52 | |
| 53 | @Mock Context mCtx; |
| 54 | @Mock IIpConnectivityMetrics mMockService; |
| 55 | |
| 56 | IpConnectivityMetrics mService; |
| 57 | |
| 58 | public void setUp() { |
| 59 | MockitoAnnotations.initMocks(this); |
Hugo Benichi | 05686db | 2016-10-19 11:17:28 +0900 | [diff] [blame] | 60 | mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000); |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 61 | } |
| 62 | |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 63 | @SmallTest |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 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 | |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 77 | @SmallTest |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 78 | 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 Benichi | 946b7e4 | 2017-03-15 16:35:26 +0900 | [diff] [blame] | 88 | assertTrue(logger.log(1 + i * 100 + j, FAKE_EV)); |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 89 | } |
| 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 Benichi | 946b7e4 | 2017-03-15 16:35:26 +0900 | [diff] [blame] | 99 | int expectedTimestamp = 1 + i * 100 + j; |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 100 | assertEventsEqual(expectedEvent(expectedTimestamp), iter.next()); |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 105 | @SmallTest |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 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 Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 118 | @SmallTest |
Hugo Benichi | e1c173d | 2016-10-18 10:36:33 +0900 | [diff] [blame] | 119 | public void testRateLimiting() { |
| 120 | final IpConnectivityLog logger = new IpConnectivityLog(mService.impl); |
Hugo Benichi | 22d9b2d | 2017-02-22 13:02:27 +0900 | [diff] [blame] | 121 | final ApfProgramEvent ev = new ApfProgramEvent(); |
Hugo Benichi | e1c173d | 2016-10-18 10:36:33 +0900 | [diff] [blame] | 122 | 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 Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 140 | @SmallTest |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 141 | public void testEndToEndLogging() { |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 142 | // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto. |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 143 | IpConnectivityLog logger = new IpConnectivityLog(mService.impl); |
| 144 | |
Hugo Benichi | 22d9b2d | 2017-02-22 13:02:27 +0900 | [diff] [blame] | 145 | ApfStats apfStats = new ApfStats(); |
| 146 | apfStats.durationMs = 45000; |
| 147 | apfStats.receivedRas = 10; |
| 148 | apfStats.matchingRas = 2; |
| 149 | apfStats.droppedRas = 2; |
| 150 | apfStats.parseErrors = 2; |
| 151 | apfStats.zeroLifetimeRas = 1; |
| 152 | apfStats.programUpdates = 4; |
| 153 | apfStats.programUpdatesAll = 7; |
| 154 | apfStats.programUpdatesAllowingMulticast = 3; |
| 155 | apfStats.maxProgramSize = 2048; |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 156 | Parcelable[] events = { |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 157 | new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED), |
| 158 | new DhcpClientEvent("SomeState", 192), |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 159 | new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false), |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 160 | new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678), |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 161 | new ValidationProbeEvent(120, 40730, ValidationProbeEvent.PROBE_HTTP, 204), |
Hugo Benichi | 22d9b2d | 2017-02-22 13:02:27 +0900 | [diff] [blame] | 162 | apfStats, |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 163 | new RaEvent(2000, 400, 300, -1, 1000, -1) |
| 164 | }; |
| 165 | |
| 166 | for (int i = 0; i < events.length; i++) { |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 167 | ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent(); |
| 168 | ev.timestamp = 100 * (i + 1); |
| 169 | ev.ifname = "wlan0"; |
| 170 | ev.data = events[i]; |
| 171 | logger.log(ev); |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | String want = joinLines( |
| 175 | "dropped_events: 0", |
| 176 | "events <", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 177 | " if_name: \"\"", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 178 | " link_layer: 4", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 179 | " network_id: 0", |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 180 | " time_ms: 100", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 181 | " transports: 0", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 182 | " ip_reachability_event <", |
| 183 | " event_type: 512", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 184 | " if_name: \"\"", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 185 | " >", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 186 | ">", |
| 187 | "events <", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 188 | " if_name: \"\"", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 189 | " link_layer: 4", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 190 | " network_id: 0", |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 191 | " time_ms: 200", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 192 | " transports: 0", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 193 | " dhcp_event <", |
| 194 | " duration_ms: 192", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 195 | " if_name: \"\"", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 196 | " state_transition: \"SomeState\"", |
| 197 | " >", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 198 | ">", |
| 199 | "events <", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 200 | " if_name: \"\"", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 201 | " link_layer: 4", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 202 | " network_id: 0", |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 203 | " time_ms: 300", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 204 | " transports: 0", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 205 | " default_network_event <", |
| 206 | " network_id <", |
| 207 | " network_id: 102", |
| 208 | " >", |
| 209 | " previous_network_id <", |
| 210 | " network_id: 101", |
| 211 | " >", |
| 212 | " previous_network_ip_support: 1", |
| 213 | " transport_types: 1", |
| 214 | " transport_types: 2", |
| 215 | " transport_types: 3", |
| 216 | " >", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 217 | ">", |
| 218 | "events <", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 219 | " if_name: \"\"", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 220 | " link_layer: 4", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 221 | " network_id: 0", |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 222 | " time_ms: 400", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 223 | " transports: 0", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 224 | " ip_provisioning_event <", |
| 225 | " event_type: 1", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 226 | " if_name: \"\"", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 227 | " latency_ms: 5678", |
| 228 | " >", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 229 | ">", |
| 230 | "events <", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 231 | " if_name: \"\"", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 232 | " link_layer: 4", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 233 | " network_id: 0", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 234 | " time_ms: 500", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 235 | " transports: 0", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 236 | " validation_probe_event <", |
| 237 | " latency_ms: 40730", |
| 238 | " network_id <", |
| 239 | " network_id: 120", |
| 240 | " >", |
| 241 | " probe_result: 204", |
| 242 | " probe_type: 1", |
| 243 | " >", |
| 244 | ">", |
| 245 | "events <", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 246 | " if_name: \"\"", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 247 | " link_layer: 4", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 248 | " network_id: 0", |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 249 | " time_ms: 600", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 250 | " transports: 0", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 251 | " apf_statistics <", |
| 252 | " dropped_ras: 2", |
| 253 | " duration_ms: 45000", |
| 254 | " matching_ras: 2", |
| 255 | " max_program_size: 2048", |
| 256 | " parse_errors: 2", |
| 257 | " program_updates: 4", |
Hugo Benichi | 22d9b2d | 2017-02-22 13:02:27 +0900 | [diff] [blame] | 258 | " program_updates_all: 7", |
| 259 | " program_updates_allowing_multicast: 3", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 260 | " received_ras: 10", |
| 261 | " zero_lifetime_ras: 1", |
| 262 | " >", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 263 | ">", |
| 264 | "events <", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 265 | " if_name: \"\"", |
Hugo Benichi | 948a859 | 2017-03-16 16:33:47 +0900 | [diff] [blame^] | 266 | " link_layer: 4", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 267 | " network_id: 0", |
Hugo Benichi | 80df43e | 2016-11-24 11:28:06 +0900 | [diff] [blame] | 268 | " time_ms: 700", |
Hugo Benichi | f684050 | 2017-03-08 11:59:36 +0900 | [diff] [blame] | 269 | " transports: 0", |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 270 | " ra_event <", |
| 271 | " dnssl_lifetime: -1", |
| 272 | " prefix_preferred_lifetime: 300", |
| 273 | " prefix_valid_lifetime: 400", |
| 274 | " rdnss_lifetime: 1000", |
| 275 | " route_info_lifetime: -1", |
| 276 | " router_lifetime: 2000", |
| 277 | " >", |
Hugo Benichi | d680d4c | 2016-10-13 13:16:16 +0900 | [diff] [blame] | 278 | ">", |
| 279 | "version: 2"); |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 280 | |
| 281 | verifySerialization(want, getdump("flush")); |
| 282 | } |
| 283 | |
| 284 | String getdump(String ... command) { |
| 285 | StringWriter buffer = new StringWriter(); |
| 286 | PrintWriter writer = new PrintWriter(buffer); |
| 287 | mService.impl.dump(null, writer, command); |
| 288 | return buffer.toString(); |
| 289 | } |
| 290 | |
| 291 | List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception { |
| 292 | ArgumentCaptor<ConnectivityMetricsEvent> captor = |
| 293 | ArgumentCaptor.forClass(ConnectivityMetricsEvent.class); |
| 294 | verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture()); |
| 295 | return captor.getAllValues(); |
| 296 | } |
| 297 | |
| 298 | List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception { |
| 299 | return verifyEvents(n, 10); |
| 300 | } |
| 301 | |
| 302 | static void verifySerialization(String want, String output) { |
| 303 | try { |
| 304 | byte[] got = Base64.decode(output, Base64.DEFAULT); |
| 305 | IpConnectivityLogClass.IpConnectivityLog log = |
Glen Kuhne | 0719940 | 2016-10-25 15:47:25 -0700 | [diff] [blame] | 306 | IpConnectivityLogClass.IpConnectivityLog.parseFrom(got); |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 307 | assertEquals(want, log.toString()); |
| 308 | } catch (Exception e) { |
| 309 | fail(e.toString()); |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | static String joinLines(String ... elems) { |
| 314 | StringBuilder b = new StringBuilder(); |
| 315 | for (String s : elems) { |
| 316 | b.append(s).append("\n"); |
| 317 | } |
| 318 | return b.toString(); |
| 319 | } |
| 320 | |
| 321 | static ConnectivityMetricsEvent expectedEvent(int timestamp) { |
Hugo Benichi | ec27c4d | 2017-03-15 15:07:42 +0900 | [diff] [blame] | 322 | ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent(); |
| 323 | ev.timestamp = timestamp; |
| 324 | ev.data = FAKE_EV; |
| 325 | return ev; |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 326 | } |
| 327 | |
| 328 | /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */ |
| 329 | static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) { |
| 330 | assertEquals(expected.timestamp, got.timestamp); |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 331 | assertEquals(expected.data, got.data); |
| 332 | } |
| 333 | |
| 334 | static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR = |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 335 | Comparator.comparingLong((ev) -> ev.timestamp); |
Hugo Benichi | 00a42d4 | 2016-09-13 15:55:09 +0900 | [diff] [blame] | 336 | } |