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
17package com.android.server.connectivity;
18
19import android.content.Context;
20import android.net.ConnectivityMetricsEvent;
21import android.os.Bundle;
22import android.os.RemoteException;
23import static android.net.ConnectivityMetricsEvent.Reference;
24
25import junit.framework.TestCase;
26import org.junit.Before;
27import org.junit.Test;
28import static org.junit.Assert.assertEquals;
29import static org.junit.Assert.assertArrayEquals;
30
31import org.mockito.Mock;
32import org.mockito.MockitoAnnotations;
33
34import java.io.FileDescriptor;
35import java.io.FileOutputStream;
36import java.util.Arrays;
37import java.util.Comparator;
38import java.util.concurrent.CountDownLatch;
39import java.util.concurrent.TimeUnit;
40
41/*
42 * TODO:
43 *  - allow overriding MetricsLoggerService constants in tests.
44 *  - test intents are correctly sent after the notification threshold.
45 *  - test oldest events are correctly pushed out when internal deque is full.
46 *  - test throttling triggers correctly.
47 */
48public class MetricsLoggerServiceTest extends TestCase {
49
50    static final int COMPONENT_TAG = 1;
51    static final long N_EVENTS = 10L;
52    static final ConnectivityMetricsEvent EVENTS[] = new ConnectivityMetricsEvent[(int)N_EVENTS];
53    static {
54        for (int i = 0; i < N_EVENTS; i++) {
55            EVENTS[i] = new ConnectivityMetricsEvent(i, COMPONENT_TAG, i, new Bundle());
56        }
57    }
58
59    static final ConnectivityMetricsEvent NO_EVENTS[] = new ConnectivityMetricsEvent[0];
60
61    @Mock Context mContext;
62    MetricsLoggerService mService;
63
64    public void setUp() {
65        MockitoAnnotations.initMocks(this);
66        mService = new MetricsLoggerService(mContext);
67        mService.onStart();
68    }
69
70    public void testGetNoEvents() throws Exception {
71        Reference r = new Reference(0);
72        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
73        assertEquals(0, r.getValue());
74    }
75
76    public void testLogAndGetEvents() throws Exception {
77        mService.mBinder.logEvents(EVENTS);
78
79        Reference r = new Reference(0);
80
81        assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
82        assertEquals(N_EVENTS, r.getValue());
83
84        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
85        assertEquals(N_EVENTS, r.getValue());
86    }
87
88    public void testLogOneByOne() throws Exception {
89        for (ConnectivityMetricsEvent ev : EVENTS) {
90            mService.mBinder.logEvent(ev);
91        }
92
93        Reference r = new Reference(0);
94
95        assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
96        assertEquals(N_EVENTS, r.getValue());
97
98        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
99        assertEquals(N_EVENTS, r.getValue());
100    }
101
102    public void testInterleavedLogAndGet() throws Exception {
103        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3));
104
105        Reference r = new Reference(0);
106
107        assertArrayEquals(Arrays.copyOfRange(EVENTS, 0, 3), mService.mBinder.getEvents(r));
108        assertEquals(3, r.getValue());
109
110        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 8));
111        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 8, 10));
112
113        assertArrayEquals(Arrays.copyOfRange(EVENTS, 3, 10), mService.mBinder.getEvents(r));
114        assertEquals(N_EVENTS, r.getValue());
115
116        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
117        assertEquals(N_EVENTS, r.getValue());
118    }
119
120    public void testMultipleGetAll() throws Exception {
121        mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3));
122
123        Reference r1 = new Reference(0);
124        assertArrayEquals(Arrays.copyOf(EVENTS, 3), mService.mBinder.getEvents(r1));
125        assertEquals(3, r1.getValue());
126
127        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 10));
128
129        Reference r2 = new Reference(0);
130        assertArrayEquals(EVENTS, mService.mBinder.getEvents(r2));
131        assertEquals(N_EVENTS, r2.getValue());
132    }
133
134    public void testLogAndDumpConcurrently() throws Exception {
135        for (int i = 0; i < 50; i++) {
136            mContext = null;
137            mService = null;
138            setUp();
139            logAndDumpConcurrently();
140        }
141    }
142
143    public void logAndDumpConcurrently() throws Exception {
144        final CountDownLatch latch = new CountDownLatch((int)N_EVENTS);
145        final FileDescriptor fd = new FileOutputStream("/dev/null").getFD();
146
147        for (ConnectivityMetricsEvent ev : EVENTS) {
148            new Thread() {
149                public void run() {
150                    mService.mBinder.logEvent(ev);
151                    latch.countDown();
152                }
153            }.start();
154        }
155
156        new Thread() {
157            public void run() {
158                while (latch.getCount() > 0) {
159                    mService.mBinder.dump(fd, new String[]{"--all"});
160                }
161            }
162        }.start();
163
164        latch.await(100, TimeUnit.MILLISECONDS);
165
166        Reference r = new Reference(0);
167        ConnectivityMetricsEvent[] got = mService.mBinder.getEvents(r);
168        Arrays.sort(got, new EventComparator());
169        assertArrayEquals(EVENTS, got);
170        assertEquals(N_EVENTS, r.getValue());
171    }
172
173    static class EventComparator implements Comparator<ConnectivityMetricsEvent> {
174        public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
175            return Long.compare(ev1.timestamp, ev2.timestamp);
176        }
177        public boolean equal(Object o) {
178            return o instanceof EventComparator;
179        }
180    };
181}
182