1 /*
2  * Copyright (C) 2023 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.telephony.statslib;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.spy;
25 import static org.mockito.Mockito.timeout;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.content.Context;
31 import android.util.StatsLog;
32 
33 import androidx.test.core.app.ApplicationProvider;
34 
35 import org.junit.After;
36 import org.junit.Before;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 import org.junit.runners.JUnit4;
40 import org.mockito.Mock;
41 import org.mockito.MockitoAnnotations;
42 import org.mockito.MockitoSession;
43 import org.mockito.quality.Strictness;
44 
45 import java.util.Random;
46 import java.util.concurrent.Callable;
47 import java.util.concurrent.ExecutionException;
48 import java.util.concurrent.Executors;
49 import java.util.concurrent.ScheduledExecutorService;
50 import java.util.concurrent.ScheduledFuture;
51 import java.util.concurrent.TimeUnit;
52 
53 @RunWith(JUnit4.class)
54 public class StatsLibTest {
55 
56     private static final String RET_SUCCESS = "success";
57     private static final String RET_FAILED = "failed";
58 
59     @Mock Context mMockContext;
60     @Mock StatsLibPulledAtomCallback mMockPulledAtomCallback;
61     @Mock StatsLibStorage mMockStorage;
62     @Mock PulledCallback mMockPulledCallback;
63     private StatsLib mStatsLib;
64     private MockitoSession mMockitoSession;
65 
66     @Before
setUp()67     public void setUp() {
68         MockitoAnnotations.initMocks(this);
69         mMockContext = spy(ApplicationProvider.getApplicationContext());
70         mMockitoSession =
71                 mockitoSession()
72                         .strictness(Strictness.LENIENT)
73                         .mockStatic(StatsLog.class)
74                         .startMocking();
75         when(mMockPulledAtomCallback.getStatsLibStorage()).thenReturn(mMockStorage);
76         mStatsLib = new StatsLib(mMockPulledAtomCallback);
77     }
78 
79     @After
tearDown()80     public void tearDown() {
81         mStatsLib = null;
82         if (mMockitoSession != null) {
83             mMockitoSession.finishMocking();
84             mMockitoSession = null;
85         }
86     }
87 
88     @Test
testWritePushedAtomHandler()89     public void testWritePushedAtomHandler() {
90         AtomsPushedTestInfo first = new AtomsPushedTestInfo(1);
91         AtomsPushedTestInfo second = new AtomsPushedTestInfo(2);
92         AtomsPushedTestInfo third = new AtomsPushedTestInfo(3);
93 
94         ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
95         Callable<String> callableTask =
96                 () -> {
97                     mStatsLib.write(null);
98                     mStatsLib.write(first);
99                     mStatsLib.write(second);
100                     mStatsLib.write(third);
101                     return RET_SUCCESS;
102                 };
103         int delay = 100;
104         ScheduledFuture<String> future =
105                 executor.schedule(callableTask, delay, TimeUnit.MILLISECONDS);
106         String result;
107         try {
108             result = future.get();
109         } catch (ExecutionException | InterruptedException e) {
110             result = RET_FAILED;
111         }
112 
113         assertEquals(result, RET_SUCCESS);
114         verify(mMockStorage, timeout(300).times(3)).appendPushedAtoms(any(AtomsPushed.class));
115     }
116 
117     @Test
testRegisterPulledAtomCallback()118     public void testRegisterPulledAtomCallback() {
119         AtomsPulledTestInfo first = new AtomsPulledTestInfo();
120         mStatsLib.registerPulledAtomCallback(first.getStatsId(), mMockPulledCallback);
121         verify(mMockPulledAtomCallback).registerAtom(first.getStatsId(), mMockPulledCallback);
122     }
123 
124     @Test
testNullStorage()125     public void testNullStorage() {
126         when(mMockPulledAtomCallback.getStatsLibStorage()).thenReturn(null);
127 
128         mStatsLib.onWritePushedAtom(new AtomsPushedTestInfo());
129         mStatsLib.append(new AtomsPulledTestInfo());
130         verify(mMockStorage, never()).appendPushedAtoms(any());
131         verify(mMockStorage, never()).appendPulledAtoms(any());
132     }
133 
134     @Test
testAppendPulledAtom()135     public void testAppendPulledAtom() {
136         final int type1 = 1;
137         final int type2 = 2;
138         Random random = new Random();
139         int count1 = random.nextInt(100);
140         int count2 = random.nextInt(1000);
141         int count3 = random.nextInt(10000);
142         int count4 = random.nextInt(100000);
143 
144         mStatsLib.append(null);
145         mStatsLib.append(new AtomsPulledTestInfo(type1, count1));
146         mStatsLib.append(new AtomsPulledTestInfo(type1, count2));
147         mStatsLib.append(new AtomsPulledTestInfo(type2, count3));
148         mStatsLib.append(new AtomsPulledTestInfo(type2, count4));
149 
150         verify(mMockStorage, times(4)).appendPulledAtoms(any());
151     }
152 }
153