1/*
2 * Copyright (C) 2017 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.internal.os;
18
19import static org.mockito.Mockito.verify;
20import static org.mockito.Mockito.verifyNoMoreInteractions;
21import static org.mockito.Mockito.verifyZeroInteractions;
22import static org.mockito.Mockito.when;
23
24import android.support.test.filters.SmallTest;
25import android.support.test.runner.AndroidJUnit4;
26
27import org.junit.Before;
28import org.junit.Test;
29import org.junit.runner.RunWith;
30import org.mockito.Mock;
31import org.mockito.Mockito;
32import org.mockito.MockitoAnnotations;
33
34import java.io.BufferedReader;
35
36/**
37 * Test class for {@link KernelUidCpuFreqTimeReader}.
38 *
39 * To run the tests, use
40 *
41 * runtest -c com.android.internal.os.KernelUidCpuFreqTimeReaderTest frameworks-core
42 *
43 * or the following steps:
44 *
45 * Build: m FrameworksCoreTests
46 * Install: adb install -r \
47 *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
48 * Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \
49 *     com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
50 */
51@SmallTest
52@RunWith(AndroidJUnit4.class)
53public class KernelUidCpuFreqTimeReaderTest {
54    @Mock private BufferedReader mBufferedReader;
55    @Mock private KernelUidCpuFreqTimeReader.Callback mCallback;
56
57    private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader;
58
59    @Before
60    public void setUp() {
61        MockitoAnnotations.initMocks(this);
62        mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader();
63    }
64
65    @Test
66    public void testReadDelta() throws Exception {
67        final long[] freqs = {1, 12, 123, 1234, 12345, 123456};
68        final int[] uids = {1, 22, 333, 4444, 5555};
69        final long[][] times = new long[uids.length][freqs.length];
70        for (int i = 0; i < uids.length; ++i) {
71            for (int j = 0; j < freqs.length; ++j) {
72                times[i][j] = uids[i] * freqs[j] * 10;
73            }
74        }
75        when(mBufferedReader.readLine())
76                .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times));
77        mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
78        verify(mCallback).onCpuFreqs(freqs);
79        for (int i = 0; i < uids.length; ++i) {
80            verify(mCallback).onUidCpuFreqTime(uids[i], times[i]);
81        }
82        verifyNoMoreInteractions(mCallback);
83
84        // Verify that a second call will only return deltas.
85        Mockito.reset(mCallback, mBufferedReader);
86        final long[][] newTimes1 = new long[uids.length][freqs.length];
87        for (int i = 0; i < uids.length; ++i) {
88            for (int j = 0; j < freqs.length; ++j) {
89                newTimes1[i][j] = (times[i][j] + uids[i] + freqs[j]) * 10;
90            }
91        }
92        when(mBufferedReader.readLine())
93                .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1));
94        mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
95        verify(mCallback).onCpuFreqs(freqs);
96        for (int i = 0; i < uids.length; ++i) {
97            verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes1[i], times[i]));
98        }
99        verifyNoMoreInteractions(mCallback);
100
101        // Verify that calling with a null callback doesn't result in any crashes
102        Mockito.reset(mCallback, mBufferedReader);
103        final long[][] newTimes2 = new long[uids.length][freqs.length];
104        for (int i = 0; i < uids.length; ++i) {
105            for (int j = 0; j < freqs.length; ++j) {
106                newTimes2[i][j] = (newTimes1[i][j] + uids[i] * freqs[j]) * 10;
107            }
108        }
109        when(mBufferedReader.readLine())
110                .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2));
111        mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, null);
112        verifyZeroInteractions(mCallback);
113
114        // Verify that the readDelta call will only return deltas when
115        // the previous call had null callback.
116        Mockito.reset(mCallback, mBufferedReader);
117        final long[][] newTimes3 = new long[uids.length][freqs.length];
118        for (int i = 0; i < uids.length; ++i) {
119            for (int j = 0; j < freqs.length; ++j) {
120                newTimes3[i][j] = (newTimes2[i][j] * (uids[i] + freqs[j])) * 10;
121            }
122        }
123        when(mBufferedReader.readLine())
124                .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes3));
125        mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
126        verify(mCallback).onCpuFreqs(freqs);
127        for (int i = 0; i < uids.length; ++i) {
128            verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes3[i], newTimes2[i]));
129        }
130        verifyNoMoreInteractions(mCallback);
131    }
132
133    private long[] subtract(long[] a1, long[] a2) {
134        long[] val = new long[a1.length];
135        for (int i = 0; i < val.length; ++i) {
136            val[i] = a1[i] - a2[i];
137        }
138        return val;
139    }
140
141    private String getFreqsLine(long[] freqs) {
142        final StringBuilder sb = new StringBuilder();
143        sb.append("uid:");
144        for (int i = 0; i < freqs.length; ++i) {
145            sb.append(" " + freqs[i]);
146        }
147        return sb.toString();
148    }
149
150    private String[] getUidTimesLines(int[] uids, long[][] times) {
151        final String[] lines = new String[uids.length + 1];
152        final StringBuilder sb = new StringBuilder();
153        for (int i = 0; i < uids.length; ++i) {
154            sb.setLength(0);
155            sb.append(uids[i] + ":");
156            for (int j = 0; j < times[i].length; ++j) {
157                sb.append(" " + times[i][j] / 10);
158            }
159            lines[i] = sb.toString();
160        }
161        lines[uids.length] = null;
162        return lines;
163    }
164}
165