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