1 /* 2 * Copyright 2022 Google LLC 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 package com.google.android.libraries.mobiledatadownload.internal.logging; 17 18 import static com.google.common.util.concurrent.MoreExecutors.directExecutor; 19 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 import static org.mockito.Mockito.verify; 23 import static org.mockito.Mockito.verifyNoInteractions; 24 25 import android.content.Context; 26 27 import androidx.test.core.app.ApplicationProvider; 28 29 import com.google.android.libraries.mobiledatadownload.Logger; 30 import com.google.android.libraries.mobiledatadownload.testing.FakeTimeSource; 31 import com.google.android.libraries.mobiledatadownload.testing.MddTestDependencies; 32 import com.google.android.libraries.mobiledatadownload.testing.TestFlags; 33 import com.google.common.base.Optional; 34 import com.google.mobiledatadownload.LogEnumsProto.MddClientEvent; 35 import com.google.mobiledatadownload.LogEnumsProto.MddDownloadResult; 36 import com.google.mobiledatadownload.LogProto.AndroidClientInfo; 37 import com.google.mobiledatadownload.LogProto.DataDownloadFileGroupStats; 38 import com.google.mobiledatadownload.LogProto.MddDeviceInfo; 39 import com.google.mobiledatadownload.LogProto.MddDownloadResultLog; 40 import com.google.mobiledatadownload.LogProto.MddLogData; 41 import com.google.mobiledatadownload.LogProto.StableSamplingInfo; 42 43 import org.junit.Before; 44 import org.junit.Rule; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 import org.mockito.Mock; 48 import org.mockito.junit.MockitoJUnit; 49 import org.mockito.junit.MockitoRule; 50 import org.robolectric.RobolectricTestRunner; 51 52 import java.security.SecureRandom; 53 import java.util.Random; 54 55 @RunWith(RobolectricTestRunner.class) 56 public class MddEventLoggerTest { 57 58 @Rule 59 public final MockitoRule mocks = MockitoJUnit.rule(); 60 61 private static final int SOME_MODULE_VERSION = 42; 62 private static final int SAMPLING_ALWAYS = 1; 63 private static final int SAMPLING_NEVER = 0; 64 65 @Mock 66 private Logger mockLogger; 67 private MddEventLogger mddEventLogger; 68 69 private final Context context = ApplicationProvider.getApplicationContext(); 70 private final TestFlags flags = new TestFlags(); 71 72 @Before setUp()73 public void setUp() throws Exception { 74 mddEventLogger = 75 new MddEventLogger( 76 context, 77 mockLogger, 78 SOME_MODULE_VERSION, 79 new LogSampler(flags, new SecureRandom()), 80 flags); 81 mddEventLogger.setLoggingStateStore( 82 MddTestDependencies.LoggingStateStoreImpl.SHARED_PREFERENCES.loggingStateStore( 83 context, Optional.absent(), new FakeTimeSource(), directExecutor(), 84 new Random(0))); 85 } 86 newLogDataBuilderWithClientInfo()87 private MddLogData.Builder newLogDataBuilderWithClientInfo() { 88 return MddLogData.newBuilder() 89 .setAndroidClientInfo( 90 AndroidClientInfo.newBuilder() 91 .setModuleVersion(SOME_MODULE_VERSION) 92 .setHostPackageName(context.getPackageName())); 93 } 94 95 @Test testSampleInterval_zero_none()96 public void testSampleInterval_zero_none() { 97 assertFalse(LogUtil.shouldSampleInterval(0)); 98 } 99 100 @Test testSampleInterval_negative_none()101 public void testSampleInterval_negative_none() { 102 assertFalse(LogUtil.shouldSampleInterval(-1)); 103 } 104 105 @Test testSampleInterval_always()106 public void testSampleInterval_always() { 107 assertTrue(LogUtil.shouldSampleInterval(1)); 108 } 109 110 @Test testLogMddEvents_noLog()111 public void testLogMddEvents_noLog() { 112 overrideDefaultSampleInterval(SAMPLING_NEVER); 113 114 mddEventLogger.logEventSampled( 115 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 116 "fileGroup", 117 /* fileGroupVersionNumber= */ 0, 118 /* buildId= */ 0, 119 /* variantId= */ ""); 120 verifyNoInteractions(mockLogger); 121 } 122 123 @Test testLogMddEvents()124 public void testLogMddEvents() { 125 overrideDefaultSampleInterval(SAMPLING_ALWAYS); 126 mddEventLogger.logEventSampled( 127 MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, 128 "fileGroup", 129 /* fileGroupVersionNumber= */ 1, 130 /* buildId= */ 123, 131 /* variantId= */ "testVariant"); 132 133 MddLogData expectedData = 134 newLogDataBuilderWithClientInfo() 135 .setSamplingInterval(SAMPLING_ALWAYS) 136 .setDataDownloadFileGroupStats( 137 DataDownloadFileGroupStats.newBuilder() 138 .setFileGroupName("fileGroup") 139 .setFileGroupVersionNumber(1) 140 .setBuildId(123) 141 .setVariantId("testVariant")) 142 .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) 143 .setStableSamplingInfo(getStableSamplingInfo()) 144 .build(); 145 146 verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); 147 } 148 149 @Test testLogExpirationHandlerRemoveUnaccountedFilesSampled()150 public void testLogExpirationHandlerRemoveUnaccountedFilesSampled() { 151 final int unaccountedFileCount = 5; 152 overrideDefaultSampleInterval(SAMPLING_ALWAYS); 153 mddEventLogger.logMddDataDownloadFileExpirationEvent(0, unaccountedFileCount); 154 155 MddLogData expectedData = 156 newLogDataBuilderWithClientInfo() 157 .setSamplingInterval(SAMPLING_ALWAYS) 158 .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) 159 .setStableSamplingInfo(getStableSamplingInfo()) 160 .build(); 161 162 verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); 163 } 164 165 @Test testLogMddNetworkSavingsSampled()166 public void testLogMddNetworkSavingsSampled() { 167 overrideDefaultSampleInterval(SAMPLING_ALWAYS); 168 DataDownloadFileGroupStats icingDataDownloadFileGroupStats = 169 DataDownloadFileGroupStats.newBuilder() 170 .setFileGroupName("fileGroup") 171 .setFileGroupVersionNumber(1) 172 .build(); 173 mddEventLogger.logMddNetworkSavings( 174 icingDataDownloadFileGroupStats, 0, 200L, 100L, "file-id", 1); 175 MddLogData expectedData = 176 newLogDataBuilderWithClientInfo() 177 .setSamplingInterval(SAMPLING_ALWAYS) 178 .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) 179 .setStableSamplingInfo(getStableSamplingInfo()) 180 .build(); 181 182 verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); 183 } 184 185 @Test testLogMddDownloadResult()186 public void testLogMddDownloadResult() { 187 overrideDefaultSampleInterval(SAMPLING_ALWAYS); 188 DataDownloadFileGroupStats icingDataDownloadFileGroupStats = 189 DataDownloadFileGroupStats.newBuilder() 190 .setFileGroupName("fileGroup") 191 .setFileGroupVersionNumber(1) 192 .build(); 193 mddEventLogger.logMddDownloadResult( 194 MddDownloadResult.Code.LOW_DISK_ERROR, icingDataDownloadFileGroupStats); 195 196 MddLogData expectedData = 197 newLogDataBuilderWithClientInfo() 198 .setSamplingInterval(SAMPLING_ALWAYS) 199 .setMddDownloadResultLog( 200 MddDownloadResultLog.newBuilder() 201 .setResult(MddDownloadResult.Code.LOW_DISK_ERROR) 202 .setDataDownloadFileGroupStats( 203 icingDataDownloadFileGroupStats)) 204 .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) 205 .setStableSamplingInfo(getStableSamplingInfo()) 206 .build(); 207 208 verify(mockLogger).log(expectedData, MddClientEvent.Code.DATA_DOWNLOAD_RESULT_LOG_VALUE); 209 } 210 211 @Test testLogMddUsageEvent()212 public void testLogMddUsageEvent() { 213 overrideDefaultSampleInterval(SAMPLING_ALWAYS); 214 215 DataDownloadFileGroupStats icingDataDownloadFileGroupStats = 216 DataDownloadFileGroupStats.newBuilder() 217 .setFileGroupName("fileGroup") 218 .setFileGroupVersionNumber(1) 219 .setBuildId(123) 220 .setVariantId("variant-id") 221 .build(); 222 223 Void usageEventLog = null; 224 225 mddEventLogger.logMddUsageEvent(icingDataDownloadFileGroupStats, usageEventLog); 226 227 MddLogData expectedData = 228 newLogDataBuilderWithClientInfo() 229 .setDataDownloadFileGroupStats(icingDataDownloadFileGroupStats) 230 .setSamplingInterval(SAMPLING_ALWAYS) 231 .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) 232 .setStableSamplingInfo(getStableSamplingInfo()) 233 .build(); 234 235 verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); 236 } 237 238 @Test testlogMddLibApiResultLog()239 public void testlogMddLibApiResultLog() { 240 overrideApiLoggingSampleInterval(SAMPLING_ALWAYS); 241 242 DataDownloadFileGroupStats icingDataDownloadFileGroupStats = 243 DataDownloadFileGroupStats.newBuilder() 244 .setFileGroupName("fileGroup") 245 .setFileGroupVersionNumber(1) 246 .build(); 247 248 Void mddLibApiResultLog = null; 249 mddEventLogger.logMddLibApiResultLog(mddLibApiResultLog); 250 251 MddLogData expectedData = 252 newLogDataBuilderWithClientInfo() 253 .setSamplingInterval(SAMPLING_ALWAYS) 254 .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) 255 .setStableSamplingInfo(getStableSamplingInfo()) 256 .build(); 257 258 verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); 259 } 260 overrideDefaultSampleInterval(int sampleInterval)261 private void overrideDefaultSampleInterval(int sampleInterval) { 262 flags.mddDefaultSampleInterval = Optional.of(sampleInterval); 263 } 264 overrideApiLoggingSampleInterval(int sampleInterval)265 private void overrideApiLoggingSampleInterval(int sampleInterval) { 266 flags.apiLoggingSampleInterval = Optional.of(sampleInterval); 267 } 268 getStableSamplingInfo()269 private StableSamplingInfo getStableSamplingInfo() { 270 if (flags.enableRngBasedDeviceStableSampling()) { 271 return StableSamplingInfo.newBuilder() 272 .setStableSamplingUsed(true) 273 .setStableSamplingFirstEnabledTimestampMs(0) 274 .setPartOfAlwaysLoggingGroup(false) 275 .setInvalidSamplingRateUsed(false) 276 .build(); 277 } 278 279 return StableSamplingInfo.newBuilder().setStableSamplingUsed(false).build(); 280 } 281 } 282