1 /*
2  * Copyright (C) 2019 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 android.net.metrics;
18 
19 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertTrue;
24 import static org.mockito.Mockito.timeout;
25 import static org.mockito.Mockito.verify;
26 
27 import android.net.ConnectivityMetricsEvent;
28 import android.net.IIpConnectivityMetrics;
29 import android.net.Network;
30 
31 import androidx.test.filters.SmallTest;
32 import androidx.test.runner.AndroidJUnit4;
33 
34 import com.android.internal.util.BitUtils;
35 
36 import org.junit.Before;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 import org.mockito.ArgumentCaptor;
40 import org.mockito.Mock;
41 import org.mockito.MockitoAnnotations;
42 
43 import java.util.Collections;
44 import java.util.Comparator;
45 import java.util.Iterator;
46 import java.util.List;
47 
48 @RunWith(AndroidJUnit4.class)
49 @SmallTest
50 public class IpConnectivityLogTest {
51     private static final int FAKE_NET_ID = 100;
52     private static final int[] FAKE_TRANSPORT_TYPES = BitUtils.unpackBits(TRANSPORT_WIFI);
53     private static final long FAKE_TIME_STAMP = System.currentTimeMillis();
54     private static final String FAKE_INTERFACE_NAME = "test";
55     private static final IpReachabilityEvent FAKE_EV =
56             new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
57 
58     @Mock IIpConnectivityMetrics mMockService;
59 
60     @Before
setUp()61     public void setUp() {
62         MockitoAnnotations.initMocks(this);
63     }
64 
65     @Test
testLoggingEvents()66     public void testLoggingEvents() throws Exception {
67         IpConnectivityLog logger = new IpConnectivityLog(mMockService);
68 
69         assertTrue(logger.log(FAKE_EV));
70         assertTrue(logger.log(FAKE_TIME_STAMP, FAKE_EV));
71         assertTrue(logger.log(FAKE_NET_ID, FAKE_TRANSPORT_TYPES, FAKE_EV));
72         assertTrue(logger.log(new Network(FAKE_NET_ID), FAKE_TRANSPORT_TYPES, FAKE_EV));
73         assertTrue(logger.log(FAKE_INTERFACE_NAME, FAKE_EV));
74         assertTrue(logger.log(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID, TRANSPORT_WIFI,
75                 FAKE_INTERFACE_NAME)));
76 
77         List<ConnectivityMetricsEvent> got = verifyEvents(6);
78         assertEventsEqual(makeExpectedEvent(got.get(0).timestamp, 0, 0, null), got.get(0));
79         assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, 0, 0, null), got.get(1));
80         assertEventsEqual(makeExpectedEvent(got.get(2).timestamp, FAKE_NET_ID,
81                 TRANSPORT_WIFI, null), got.get(2));
82         assertEventsEqual(makeExpectedEvent(got.get(3).timestamp, FAKE_NET_ID,
83                 TRANSPORT_WIFI, null), got.get(3));
84         assertEventsEqual(makeExpectedEvent(got.get(4).timestamp, 0, 0, FAKE_INTERFACE_NAME),
85                 got.get(4));
86         assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID,
87                 TRANSPORT_WIFI, FAKE_INTERFACE_NAME), got.get(5));
88     }
89 
90     @Test
testLoggingEventsWithMultipleCallers()91     public void testLoggingEventsWithMultipleCallers() throws Exception {
92         IpConnectivityLog logger = new IpConnectivityLog(mMockService);
93 
94         final int nCallers = 10;
95         final int nEvents = 10;
96         for (int n = 0; n < nCallers; n++) {
97             final int i = n;
98             new Thread() {
99                 public void run() {
100                     for (int j = 0; j < nEvents; j++) {
101                         assertTrue(logger.log(makeExpectedEvent(
102                                 FAKE_TIME_STAMP + i * 100 + j,
103                                 FAKE_NET_ID + i * 100 + j,
104                                 ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR,
105                                 FAKE_INTERFACE_NAME)));
106                     }
107                 }
108             }.start();
109         }
110 
111         List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 200);
112         Collections.sort(got, EVENT_COMPARATOR);
113         Iterator<ConnectivityMetricsEvent> iter = got.iterator();
114         for (int i = 0; i < nCallers; i++) {
115             for (int j = 0; j < nEvents; j++) {
116                 final long expectedTimestamp = FAKE_TIME_STAMP + i * 100 + j;
117                 final int expectedNetId = FAKE_NET_ID + i * 100 + j;
118                 final long expectedTransports =
119                         ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR;
120                 assertEventsEqual(makeExpectedEvent(expectedTimestamp, expectedNetId,
121                         expectedTransports, FAKE_INTERFACE_NAME), iter.next());
122             }
123         }
124     }
125 
verifyEvents(int n, int timeoutMs)126     private List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
127         ArgumentCaptor<ConnectivityMetricsEvent> captor =
128                 ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
129         verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
130         return captor.getAllValues();
131     }
132 
verifyEvents(int n)133     private List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
134         return verifyEvents(n, 10);
135     }
136 
137 
makeExpectedEvent(long timestamp, int netId, long transports, String ifname)138     private ConnectivityMetricsEvent makeExpectedEvent(long timestamp, int netId, long transports,
139             String ifname) {
140         ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
141         ev.timestamp = timestamp;
142         ev.data = FAKE_EV;
143         ev.netId = netId;
144         ev.transports = transports;
145         ev.ifname = ifname;
146         return ev;
147     }
148 
149     /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got)150     private void assertEventsEqual(ConnectivityMetricsEvent expected,
151             ConnectivityMetricsEvent got) {
152         assertEquals(expected.data, got.data);
153         assertEquals(expected.timestamp, got.timestamp);
154         assertEquals(expected.netId, got.netId);
155         assertEquals(expected.transports, got.transports);
156         assertEquals(expected.ifname, got.ifname);
157     }
158 
159     static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
160             Comparator.comparingLong((ev) -> ev.timestamp);
161 }
162