1 /* 2 * Copyright (C) 2021 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.car.telemetry.systemmonitor; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.any; 22 import static org.mockito.Mockito.atLeastOnce; 23 import static org.mockito.Mockito.doAnswer; 24 import static org.mockito.Mockito.times; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.app.ActivityManager; 29 import android.app.ActivityManager.MemoryInfo; 30 import android.os.Handler; 31 32 import org.junit.Before; 33 import org.junit.Rule; 34 import org.junit.Test; 35 import org.junit.rules.TemporaryFolder; 36 import org.junit.runner.RunWith; 37 import org.mockito.ArgumentCaptor; 38 import org.mockito.Captor; 39 import org.mockito.Mock; 40 import org.mockito.junit.MockitoJUnitRunner; 41 42 import java.io.File; 43 import java.io.FileWriter; 44 import java.io.IOException; 45 46 @RunWith(MockitoJUnitRunner.class) 47 public class SystemMonitorTest { 48 49 @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); 50 51 private static final String TEST_LOADAVG = "0.2 3.4 2.2 123/1452 21348"; 52 private static final String TEST_LOADAVG_BAD_FORMAT = "1.2 3.4"; 53 private static final String TEST_LOADAVG_NOT_FLOAT = "1.2 abc 2.1 12/231 2"; 54 55 @Mock private Handler mMockHandler; // it promptly executes the runnable in the same thread 56 @Mock private ActivityManager mMockActivityManager; 57 @Mock private SystemMonitor.SystemMonitorCallback mMockCallback; 58 59 @Captor ArgumentCaptor<Runnable> mRunnableCaptor; 60 @Captor ArgumentCaptor<SystemMonitorEvent> mEventCaptor; 61 62 @Before setup()63 public void setup() { 64 when(mMockHandler.post(any(Runnable.class))).thenAnswer(i -> { 65 Runnable runnable = i.getArgument(0); 66 runnable.run(); 67 return true; 68 }); 69 } 70 71 @Test testSetEventCpuUsageLevel_setsCorrectUsageLevelForHighUsage()72 public void testSetEventCpuUsageLevel_setsCorrectUsageLevelForHighUsage() { 73 SystemMonitor systemMonitor = SystemMonitor.create(mMockActivityManager, mMockHandler); 74 SystemMonitorEvent event = new SystemMonitorEvent(); 75 76 systemMonitor.setEventCpuUsageLevel(event, /* cpuLoadPerCore= */ 1.5); 77 78 assertThat(event.getCpuUsageLevel()) 79 .isEqualTo(SystemMonitorEvent.USAGE_LEVEL_HI); 80 } 81 82 @Test testSetEventCpuUsageLevel_setsCorrectUsageLevelForMedUsage()83 public void testSetEventCpuUsageLevel_setsCorrectUsageLevelForMedUsage() { 84 SystemMonitor systemMonitor = SystemMonitor.create(mMockActivityManager, mMockHandler); 85 SystemMonitorEvent event = new SystemMonitorEvent(); 86 87 systemMonitor.setEventCpuUsageLevel(event, /* cpuLoadPerCore= */ 0.6); 88 89 assertThat(event.getCpuUsageLevel()) 90 .isEqualTo(SystemMonitorEvent.USAGE_LEVEL_MED); 91 } 92 93 @Test testSetEventCpuUsageLevel_setsCorrectUsageLevelForLowUsage()94 public void testSetEventCpuUsageLevel_setsCorrectUsageLevelForLowUsage() { 95 SystemMonitor systemMonitor = SystemMonitor.create(mMockActivityManager, mMockHandler); 96 SystemMonitorEvent event = new SystemMonitorEvent(); 97 98 systemMonitor.setEventCpuUsageLevel(event, /* cpuLoadPerCore= */ 0.5); 99 100 assertThat(event.getCpuUsageLevel()) 101 .isEqualTo(SystemMonitorEvent.USAGE_LEVEL_LOW); 102 } 103 104 @Test testSetEventMemUsageLevel_setsCorrectUsageLevelForHighUsage()105 public void testSetEventMemUsageLevel_setsCorrectUsageLevelForHighUsage() { 106 SystemMonitor systemMonitor = SystemMonitor.create(mMockActivityManager, mMockHandler); 107 SystemMonitorEvent event = new SystemMonitorEvent(); 108 109 systemMonitor.setEventMemUsageLevel(event, /* memLoadRatio= */ 0.98); 110 111 assertThat(event.getMemoryUsageLevel()) 112 .isEqualTo(SystemMonitorEvent.USAGE_LEVEL_HI); 113 } 114 115 @Test testSetEventMemUsageLevel_setsCorrectUsageLevelForMedUsage()116 public void testSetEventMemUsageLevel_setsCorrectUsageLevelForMedUsage() { 117 SystemMonitor systemMonitor = SystemMonitor.create(mMockActivityManager, mMockHandler); 118 SystemMonitorEvent event = new SystemMonitorEvent(); 119 120 systemMonitor.setEventMemUsageLevel(event, /* memLoadRatio= */ 0.85); 121 122 assertThat(event.getMemoryUsageLevel()) 123 .isEqualTo(SystemMonitorEvent.USAGE_LEVEL_MED); 124 } 125 126 @Test testSetEventMemUsageLevel_setsCorrectUsageLevelForLowUsage()127 public void testSetEventMemUsageLevel_setsCorrectUsageLevelForLowUsage() { 128 SystemMonitor systemMonitor = SystemMonitor.create(mMockActivityManager, mMockHandler); 129 SystemMonitorEvent event = new SystemMonitorEvent(); 130 131 systemMonitor.setEventMemUsageLevel(event, /* memLoadRatio= */ 0.80); 132 133 assertThat(event.getMemoryUsageLevel()) 134 .isEqualTo(SystemMonitorEvent.USAGE_LEVEL_LOW); 135 } 136 137 @Test testSetCallback_whenMemUsageLow_shouldInvokeCallback()138 public void testSetCallback_whenMemUsageLow_shouldInvokeCallback() throws IOException { 139 doAnswer(i -> { 140 MemoryInfo mi = i.getArgument(0); // memory usage is at 50% 141 mi.availMem = 5_000_000L; 142 mi.totalMem = 10_000_000; 143 return null; 144 }).when(mMockActivityManager).getMemoryInfo(any(MemoryInfo.class)); 145 SystemMonitor systemMonitor = new SystemMonitor( 146 mMockActivityManager, mMockHandler, writeTempFile(TEST_LOADAVG)); 147 148 systemMonitor.setSystemMonitorCallback(mMockCallback); 149 150 verify(mMockCallback, atLeastOnce()).onSystemMonitorEvent(mEventCaptor.capture()); 151 SystemMonitorEvent event = mEventCaptor.getValue(); 152 // from TEST_LOADAVG, cpu load = 0.2 / numProcessors, CPU usage should be low 153 assertThat(event.getCpuUsageLevel()).isEqualTo(SystemMonitorEvent.USAGE_LEVEL_LOW); 154 // 1 - 5_000_000 / 10_000_000 = 0.5, memory usage should be low 155 assertThat(event.getMemoryUsageLevel()).isEqualTo(SystemMonitorEvent.USAGE_LEVEL_LOW); 156 } 157 158 @Test testSetCallback_whenMemUsageHigh_shouldInvokeCallback()159 public void testSetCallback_whenMemUsageHigh_shouldInvokeCallback() throws IOException { 160 doAnswer(i -> { 161 MemoryInfo mi = i.getArgument(0); // memory usage is at 95% 162 mi.availMem = 500_000L; 163 mi.totalMem = 10_000_000L; 164 return null; 165 }).when(mMockActivityManager).getMemoryInfo(any(MemoryInfo.class)); 166 SystemMonitor systemMonitor = new SystemMonitor( 167 mMockActivityManager, mMockHandler, writeTempFile(TEST_LOADAVG)); 168 169 systemMonitor.setSystemMonitorCallback(mMockCallback); 170 171 verify(mMockCallback, atLeastOnce()).onSystemMonitorEvent(mEventCaptor.capture()); 172 SystemMonitorEvent event = mEventCaptor.getValue(); 173 // 1 - 500_000 / 10_000_000 = 0.95, memory usage should be high 174 assertThat(event.getMemoryUsageLevel()).isEqualTo(SystemMonitorEvent.USAGE_LEVEL_HI); 175 } 176 177 @Test testWhenLoadavgIsBadFormat_getCpuLoadReturnsNull()178 public void testWhenLoadavgIsBadFormat_getCpuLoadReturnsNull() throws IOException { 179 SystemMonitor systemMonitor = new SystemMonitor( 180 mMockActivityManager, mMockHandler, writeTempFile(TEST_LOADAVG_BAD_FORMAT)); 181 182 assertThat(systemMonitor.getCpuLoad()).isNull(); 183 } 184 185 @Test testWhenLoadavgIsNotFloatParsable_getCpuLoadReturnsNull()186 public void testWhenLoadavgIsNotFloatParsable_getCpuLoadReturnsNull() throws IOException { 187 SystemMonitor systemMonitor = new SystemMonitor( 188 mMockActivityManager, mMockHandler, writeTempFile(TEST_LOADAVG_NOT_FLOAT)); 189 190 assertThat(systemMonitor.getCpuLoad()).isNull(); 191 } 192 193 @Test testWhenUnsetCallback_sameCallbackFromSetCallbackIsRemoved()194 public void testWhenUnsetCallback_sameCallbackFromSetCallbackIsRemoved() throws IOException { 195 SystemMonitor systemMonitor = new SystemMonitor( 196 mMockActivityManager, mMockHandler, writeTempFile(TEST_LOADAVG)); 197 198 systemMonitor.setSystemMonitorCallback(mMockCallback); 199 systemMonitor.unsetSystemMonitorCallback(); 200 201 verify(mMockHandler, times(1)).post(mRunnableCaptor.capture()); 202 Runnable setRunnable = mRunnableCaptor.getValue(); 203 verify(mMockHandler, times(1)).removeCallbacks(mRunnableCaptor.capture()); 204 Runnable unsetRunnable = mRunnableCaptor.getValue(); 205 assertThat(setRunnable).isEqualTo(unsetRunnable); 206 } 207 208 /** 209 * Creates and writes to the temp file, returns its path. 210 */ writeTempFile(String content)211 private String writeTempFile(String content) throws IOException { 212 File tempFile = temporaryFolder.newFile(); 213 try (FileWriter fw = new FileWriter(tempFile)) { 214 fw.write(content); 215 } 216 return tempFile.getAbsolutePath(); 217 } 218 } 219