/* * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.android.libraries.mobiledatadownload.internal.logging; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import android.content.Context; import androidx.test.core.app.ApplicationProvider; import com.google.android.libraries.mobiledatadownload.Logger; import com.google.android.libraries.mobiledatadownload.testing.FakeTimeSource; import com.google.android.libraries.mobiledatadownload.testing.MddTestDependencies; import com.google.android.libraries.mobiledatadownload.testing.TestFlags; import com.google.common.base.Optional; import com.google.mobiledatadownload.LogEnumsProto.MddClientEvent; import com.google.mobiledatadownload.LogEnumsProto.MddDownloadResult; import com.google.mobiledatadownload.LogProto.AndroidClientInfo; import com.google.mobiledatadownload.LogProto.DataDownloadFileGroupStats; import com.google.mobiledatadownload.LogProto.MddDeviceInfo; import com.google.mobiledatadownload.LogProto.MddDownloadResultLog; import com.google.mobiledatadownload.LogProto.MddLogData; import com.google.mobiledatadownload.LogProto.StableSamplingInfo; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; import java.security.SecureRandom; import java.util.Random; @RunWith(RobolectricTestRunner.class) public class MddEventLoggerTest { @Rule public final MockitoRule mocks = MockitoJUnit.rule(); private static final int SOME_MODULE_VERSION = 42; private static final int SAMPLING_ALWAYS = 1; private static final int SAMPLING_NEVER = 0; @Mock private Logger mockLogger; private MddEventLogger mddEventLogger; private final Context context = ApplicationProvider.getApplicationContext(); private final TestFlags flags = new TestFlags(); @Before public void setUp() throws Exception { mddEventLogger = new MddEventLogger( context, mockLogger, SOME_MODULE_VERSION, new LogSampler(flags, new SecureRandom()), flags); mddEventLogger.setLoggingStateStore( MddTestDependencies.LoggingStateStoreImpl.SHARED_PREFERENCES.loggingStateStore( context, Optional.absent(), new FakeTimeSource(), directExecutor(), new Random(0))); } private MddLogData.Builder newLogDataBuilderWithClientInfo() { return MddLogData.newBuilder() .setAndroidClientInfo( AndroidClientInfo.newBuilder() .setModuleVersion(SOME_MODULE_VERSION) .setHostPackageName(context.getPackageName())); } @Test public void testSampleInterval_zero_none() { assertFalse(LogUtil.shouldSampleInterval(0)); } @Test public void testSampleInterval_negative_none() { assertFalse(LogUtil.shouldSampleInterval(-1)); } @Test public void testSampleInterval_always() { assertTrue(LogUtil.shouldSampleInterval(1)); } @Test public void testLogMddEvents_noLog() { overrideDefaultSampleInterval(SAMPLING_NEVER); mddEventLogger.logEventSampled( MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, "fileGroup", /* fileGroupVersionNumber= */ 0, /* buildId= */ 0, /* variantId= */ ""); verifyNoInteractions(mockLogger); } @Test public void testLogMddEvents() { overrideDefaultSampleInterval(SAMPLING_ALWAYS); mddEventLogger.logEventSampled( MddClientEvent.Code.EVENT_CODE_UNSPECIFIED, "fileGroup", /* fileGroupVersionNumber= */ 1, /* buildId= */ 123, /* variantId= */ "testVariant"); MddLogData expectedData = newLogDataBuilderWithClientInfo() .setSamplingInterval(SAMPLING_ALWAYS) .setDataDownloadFileGroupStats( DataDownloadFileGroupStats.newBuilder() .setFileGroupName("fileGroup") .setFileGroupVersionNumber(1) .setBuildId(123) .setVariantId("testVariant")) .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) .setStableSamplingInfo(getStableSamplingInfo()) .build(); verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); } @Test public void testLogExpirationHandlerRemoveUnaccountedFilesSampled() { final int unaccountedFileCount = 5; overrideDefaultSampleInterval(SAMPLING_ALWAYS); mddEventLogger.logMddDataDownloadFileExpirationEvent(0, unaccountedFileCount); MddLogData expectedData = newLogDataBuilderWithClientInfo() .setSamplingInterval(SAMPLING_ALWAYS) .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) .setStableSamplingInfo(getStableSamplingInfo()) .build(); verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); } @Test public void testLogMddNetworkSavingsSampled() { overrideDefaultSampleInterval(SAMPLING_ALWAYS); DataDownloadFileGroupStats icingDataDownloadFileGroupStats = DataDownloadFileGroupStats.newBuilder() .setFileGroupName("fileGroup") .setFileGroupVersionNumber(1) .build(); mddEventLogger.logMddNetworkSavings( icingDataDownloadFileGroupStats, 0, 200L, 100L, "file-id", 1); MddLogData expectedData = newLogDataBuilderWithClientInfo() .setSamplingInterval(SAMPLING_ALWAYS) .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) .setStableSamplingInfo(getStableSamplingInfo()) .build(); verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); } @Test public void testLogMddDownloadResult() { overrideDefaultSampleInterval(SAMPLING_ALWAYS); DataDownloadFileGroupStats icingDataDownloadFileGroupStats = DataDownloadFileGroupStats.newBuilder() .setFileGroupName("fileGroup") .setFileGroupVersionNumber(1) .build(); mddEventLogger.logMddDownloadResult( MddDownloadResult.Code.LOW_DISK_ERROR, icingDataDownloadFileGroupStats); MddLogData expectedData = newLogDataBuilderWithClientInfo() .setSamplingInterval(SAMPLING_ALWAYS) .setMddDownloadResultLog( MddDownloadResultLog.newBuilder() .setResult(MddDownloadResult.Code.LOW_DISK_ERROR) .setDataDownloadFileGroupStats( icingDataDownloadFileGroupStats)) .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) .setStableSamplingInfo(getStableSamplingInfo()) .build(); verify(mockLogger).log(expectedData, MddClientEvent.Code.DATA_DOWNLOAD_RESULT_LOG_VALUE); } @Test public void testLogMddUsageEvent() { overrideDefaultSampleInterval(SAMPLING_ALWAYS); DataDownloadFileGroupStats icingDataDownloadFileGroupStats = DataDownloadFileGroupStats.newBuilder() .setFileGroupName("fileGroup") .setFileGroupVersionNumber(1) .setBuildId(123) .setVariantId("variant-id") .build(); Void usageEventLog = null; mddEventLogger.logMddUsageEvent(icingDataDownloadFileGroupStats, usageEventLog); MddLogData expectedData = newLogDataBuilderWithClientInfo() .setDataDownloadFileGroupStats(icingDataDownloadFileGroupStats) .setSamplingInterval(SAMPLING_ALWAYS) .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) .setStableSamplingInfo(getStableSamplingInfo()) .build(); verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); } @Test public void testlogMddLibApiResultLog() { overrideApiLoggingSampleInterval(SAMPLING_ALWAYS); DataDownloadFileGroupStats icingDataDownloadFileGroupStats = DataDownloadFileGroupStats.newBuilder() .setFileGroupName("fileGroup") .setFileGroupVersionNumber(1) .build(); Void mddLibApiResultLog = null; mddEventLogger.logMddLibApiResultLog(mddLibApiResultLog); MddLogData expectedData = newLogDataBuilderWithClientInfo() .setSamplingInterval(SAMPLING_ALWAYS) .setDeviceInfo(MddDeviceInfo.newBuilder().setDeviceStorageLow(false)) .setStableSamplingInfo(getStableSamplingInfo()) .build(); verify(mockLogger).log(expectedData, MddClientEvent.Code.EVENT_CODE_UNSPECIFIED_VALUE); } private void overrideDefaultSampleInterval(int sampleInterval) { flags.mddDefaultSampleInterval = Optional.of(sampleInterval); } private void overrideApiLoggingSampleInterval(int sampleInterval) { flags.apiLoggingSampleInterval = Optional.of(sampleInterval); } private StableSamplingInfo getStableSamplingInfo() { if (flags.enableRngBasedDeviceStableSampling()) { return StableSamplingInfo.newBuilder() .setStableSamplingUsed(true) .setStableSamplingFirstEnabledTimestampMs(0) .setPartOfAlwaysLoggingGroup(false) .setInvalidSamplingRateUsed(false) .build(); } return StableSamplingInfo.newBuilder().setStableSamplingUsed(false).build(); } }