blob: 2b35cf41f6ad56db80680234db15a9c73ec0d89f [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tab.state;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import androidx.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.chromium.base.UserDataHost;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.UiThreadTest;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcher;
import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcherJni;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridge;
import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridgeJni;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.MockTab;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabImpl;
import org.chromium.chrome.browser.tab.state.PriceDropMetricsLogger.MetricsResult;
import org.chromium.chrome.test.ChromeBrowserTestRule;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.components.optimization_guide.OptimizationGuideDecision;
import org.chromium.components.optimization_guide.proto.HintsProto;
import org.chromium.content_public.browser.NavigationHandle;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.url.GURL;
import java.nio.ByteBuffer;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Test relating to {@link ShoppingPersistedTabData}
*/
@RunWith(BaseJUnit4ClassRunner.class)
@EnableFeatures({ChromeFeatureList.COMMERCE_PRICE_TRACKING + "<Study"})
@CommandLineFlags.
Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "force-fieldtrials=Study/Group"})
public class ShoppingPersistedTabDataTest {
@Rule
public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
@Rule
public JniMocker mMocker = new JniMocker();
@Rule
public TestRule mProcessor = new Features.InstrumentationProcessor();
@Mock
protected EndpointFetcher.Natives mEndpointFetcherJniMock;
@Mock
protected OptimizationGuideBridge.Natives mOptimizationGuideBridgeJniMock;
@Mock
protected Profile mProfileMock;
@Mock
protected NavigationHandle mNavigationHandle;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mMocker.mock(EndpointFetcherJni.TEST_HOOKS, mEndpointFetcherJniMock);
mMocker.mock(OptimizationGuideBridgeJni.TEST_HOOKS, mOptimizationGuideBridgeJniMock);
// Ensure native pointer is initialized
doReturn(1L).when(mOptimizationGuideBridgeJniMock).init();
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.SHOPPING_PAGE_PREDICTOR.getNumber(),
OptimizationGuideDecision.TRUE, null);
PersistedTabDataConfiguration.setUseTestConfig(true);
Profile.setLastUsedProfileForTesting(mProfileMock);
doReturn(true).when(mNavigationHandle).isInPrimaryMainFrame();
}
@UiThreadTest
@SmallTest
@Test
public void testShoppingProto() {
Tab tab = new MockTab(ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab);
ObservableSupplierImpl<Boolean> supplier = new ObservableSupplierImpl<>();
supplier.set(true);
shoppingPersistedTabData.registerIsTabSaveEnabledSupplier(supplier);
shoppingPersistedTabData.setPriceMicros(
ShoppingPersistedTabDataTestUtils.PRICE_MICROS, null);
ByteBuffer serialized = shoppingPersistedTabData.getSerializeSupplier().get();
ShoppingPersistedTabData deserialized = new ShoppingPersistedTabData(tab);
deserialized.deserialize(serialized);
Assert.assertEquals(
ShoppingPersistedTabDataTestUtils.PRICE_MICROS, deserialized.getPriceMicros());
Assert.assertEquals(
ShoppingPersistedTabData.NO_PRICE_KNOWN, deserialized.getPreviousPriceMicros());
MetricsResult metricsResult =
deserialized.getPriceDropMetricsLoggerForTesting().getMetricsResultForTesting();
Assert.assertFalse(metricsResult.isProductDetailPage);
Assert.assertTrue(metricsResult.containsPrice);
Assert.assertFalse(metricsResult.containsPriceDrop);
}
@UiThreadTest
@SmallTest
@Test
public void testMetricDerivations() {
Tab tab = new MockTab(ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab);
ObservableSupplierImpl<Boolean> supplier = new ObservableSupplierImpl<>();
supplier.set(true);
shoppingPersistedTabData.registerIsTabSaveEnabledSupplier(supplier);
for (boolean isProductDetailPage : new boolean[] {false, true}) {
for (boolean containsPrice : new boolean[] {false, true}) {
for (boolean containsPriceDrop : new boolean[] {false, true}) {
shoppingPersistedTabData.setMainOfferId(
isProductDetailPage ? "non-empty-offer-id" : null);
shoppingPersistedTabData.setPriceMicros(containsPrice || containsPriceDrop
? 42_000_000L
: ShoppingPersistedTabData.NO_PRICE_KNOWN);
shoppingPersistedTabData.setPreviousPriceMicros(containsPriceDrop
? 30_000_000L
: ShoppingPersistedTabData.NO_PRICE_KNOWN);
ByteBuffer serialized = shoppingPersistedTabData.getSerializeSupplier().get();
ShoppingPersistedTabData deserialized = new ShoppingPersistedTabData(tab);
deserialized.deserialize(serialized);
MetricsResult metricsResult = deserialized.getPriceDropMetricsLoggerForTesting()
.getMetricsResultForTesting();
Assert.assertEquals(isProductDetailPage, metricsResult.isProductDetailPage);
Assert.assertEquals(
containsPrice || containsPriceDrop, metricsResult.containsPrice);
Assert.assertEquals(containsPriceDrop, metricsResult.containsPriceDrop);
}
}
}
}
@SmallTest
@Test
public void testShoppingBloomFilterNotShoppingWebsite() {
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse
.BUYABLE_PRODUCT_INITIAL);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.SHOPPING_PAGE_PREDICTOR.getNumber(),
OptimizationGuideDecision.FALSE, null);
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
Semaphore semaphore = new Semaphore(0);
TestThreadUtils.runOnUiThreadBlocking(() -> {
ShoppingPersistedTabData.from(
tab, (shoppingPersistedTabData) -> { semaphore.release(); });
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
ShoppingPersistedTabDataTestUtils.verifyPriceTrackingOptimizationTypeCalled(
mOptimizationGuideBridgeJniMock, 0);
}
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_with_optimization_guide/true"})
public void testShoppingBloomFilterShoppingWebsite() {
for (@OptimizationGuideDecision int decision :
new int[] {OptimizationGuideDecision.TRUE, OptimizationGuideDecision.UNKNOWN}) {
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse
.BUYABLE_PRODUCT_INITIAL);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.SHOPPING_PAGE_PREDICTOR.getNumber(), decision,
null);
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
Semaphore semaphore = new Semaphore(0);
TestThreadUtils.runOnUiThreadBlocking(() -> {
ShoppingPersistedTabData.from(
tab, (shoppingPersistedTabData) -> { semaphore.release(); });
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
ShoppingPersistedTabDataTestUtils.verifyPriceTrackingOptimizationTypeCalled(
mOptimizationGuideBridgeJniMock, 1);
}
}
@SmallTest
@Test
public void testStaleTab() {
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
Semaphore semaphore = new Semaphore(0);
TestThreadUtils.runOnUiThreadBlocking(() -> {
CriticalPersistedTabData.from(tab).setTimestampMillis(
System.currentTimeMillis() - TimeUnit.DAYS.toMillis(100));
ShoppingPersistedTabData.from(
tab, (shoppingPersistedTabData) -> { semaphore.release(); });
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
ShoppingPersistedTabDataTestUtils.verifyPriceTrackingOptimizationTypeCalled(
mOptimizationGuideBridgeJniMock, 0);
}
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_stale_tab_threshold_seconds/86400/"
+ "price_tracking_with_optimization_guide/true"})
public void
test2DayTabWithStaleOverride1day() {
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
Semaphore semaphore = new Semaphore(0);
TestThreadUtils.runOnUiThreadBlocking(() -> {
CriticalPersistedTabData.from(tab).setTimestampMillis(
System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2));
ShoppingPersistedTabData.from(
tab, (shoppingPersistedTabData) -> { semaphore.release(); });
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
ShoppingPersistedTabDataTestUtils.verifyPriceTrackingOptimizationTypeCalled(
mOptimizationGuideBridgeJniMock, 0);
}
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_stale_tab_threshold_seconds/86400/"
+ "price_tracking_with_optimization_guide/true"})
public void
testHalfDayTabWithStaleOverride1day() {
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse
.BUYABLE_PRODUCT_INITIAL);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.SHOPPING_PAGE_PREDICTOR.getNumber(),
OptimizationGuideDecision.TRUE, null);
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
Semaphore semaphore = new Semaphore(0);
TestThreadUtils.runOnUiThreadBlocking(() -> {
CriticalPersistedTabData.from(tab).setTimestampMillis(
System.currentTimeMillis() - TimeUnit.HOURS.toMillis(12));
ShoppingPersistedTabData.from(
tab, (shoppingPersistedTabData) -> { semaphore.release(); });
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
ShoppingPersistedTabDataTestUtils.verifyPriceTrackingOptimizationTypeCalled(
mOptimizationGuideBridgeJniMock, 1);
}
@UiThreadTest
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_with_optimization_guide/true"})
public void testNoRefetch() {
final Semaphore initialSemaphore = new Semaphore(0);
final Semaphore updateSemaphore = new Semaphore(0);
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse
.BUYABLE_PRODUCT_INITIAL);
TestThreadUtils.runOnUiThreadBlocking(() -> {
ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> {
Assert.assertEquals(ShoppingPersistedTabDataTestUtils.PRICE_MICROS,
shoppingPersistedTabData.getPriceMicros());
Assert.assertEquals(ShoppingPersistedTabData.NO_PRICE_KNOWN,
shoppingPersistedTabData.getPreviousPriceMicros());
Assert.assertEquals(ShoppingPersistedTabDataTestUtils.UNITED_STATES_CURRENCY_CODE,
shoppingPersistedTabData.getCurrencyCode());
// By setting time to live to be a negative number, an update
// will be forced in the subsequent call
initialSemaphore.release();
});
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(initialSemaphore);
ShoppingPersistedTabDataTestUtils.verifyPriceTrackingOptimizationTypeCalled(
mOptimizationGuideBridgeJniMock, 1);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse
.BUYABLE_PRODUCT_PRICE_UPDATED);
TestThreadUtils.runOnUiThreadBlocking(() -> {
ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> {
Assert.assertEquals(ShoppingPersistedTabDataTestUtils.PRICE_MICROS,
shoppingPersistedTabData.getPriceMicros());
Assert.assertEquals(ShoppingPersistedTabData.NO_PRICE_KNOWN,
shoppingPersistedTabData.getPreviousPriceMicros());
// By setting time to live to be a negative number, an update
// will be forced in the subsequent call
updateSemaphore.release();
});
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(updateSemaphore);
// EndpointFetcher should not have been called a second time - because we haven't passed the
// time to live
ShoppingPersistedTabDataTestUtils.verifyPriceTrackingOptimizationTypeCalled(
mOptimizationGuideBridgeJniMock, 1);
}
@UiThreadTest
@SmallTest
@Test
public void testPriceDrop() {
ShoppingPersistedTabData shoppingPersistedTabData =
ShoppingPersistedTabDataTestUtils.createShoppingPersistedTabDataWithDefaults();
// Prices unknown is not a price drop
Assert.assertNull(shoppingPersistedTabData.getPriceDrop());
// Same price is not a price drop
shoppingPersistedTabData.setPriceMicros(
ShoppingPersistedTabDataTestUtils.HIGH_PRICE_MICROS, null);
shoppingPersistedTabData.setPreviousPriceMicros(
ShoppingPersistedTabDataTestUtils.HIGH_PRICE_MICROS);
Assert.assertNull(shoppingPersistedTabData.getPriceDrop());
// Lower -> Higher price is not a price drop
shoppingPersistedTabData.setPriceMicros(
ShoppingPersistedTabDataTestUtils.HIGH_PRICE_MICROS, null);
shoppingPersistedTabData.setPreviousPriceMicros(
ShoppingPersistedTabDataTestUtils.LOW_PRICE_MICROS);
Assert.assertNull(shoppingPersistedTabData.getPriceDrop());
// Actual price drop (Higher -> Lower)
shoppingPersistedTabData.setPriceMicros(
ShoppingPersistedTabDataTestUtils.LOW_PRICE_MICROS, null);
shoppingPersistedTabData.setPreviousPriceMicros(
ShoppingPersistedTabDataTestUtils.HIGH_PRICE_MICROS);
ShoppingPersistedTabData.PriceDrop priceDrop = shoppingPersistedTabData.getPriceDrop();
Assert.assertEquals(ShoppingPersistedTabDataTestUtils.LOW_PRICE_FORMATTED, priceDrop.price);
Assert.assertEquals(
ShoppingPersistedTabDataTestUtils.HIGH_PRICE_FORMATTED, priceDrop.previousPrice);
}
@UiThreadTest
@SmallTest
@Test
public void testPriceDropFilterSamePrice() {
ShoppingPersistedTabData shoppingPersistedTabData =
ShoppingPersistedTabDataTestUtils.createShoppingPersistedTabDataWithDefaults();
// $10 -> $10 is not a price drop (same price)
shoppingPersistedTabData.setPreviousPriceMicrosForTesting(10_000_000L);
shoppingPersistedTabData.setPriceMicrosForTesting(10_000_000L);
Assert.assertNull(shoppingPersistedTabData.getPriceDrop());
}
@UiThreadTest
@SmallTest
@Test
public void testPriceDropFilterNoFormattedPriceDifference() {
ShoppingPersistedTabData shoppingPersistedTabData =
ShoppingPersistedTabDataTestUtils.createShoppingPersistedTabDataWithDefaults();
// $10.40 -> $10 (which would be displayed $10 -> $10 is not a price drop)
shoppingPersistedTabData.setPreviousPriceMicrosForTesting(10_400_000L);
shoppingPersistedTabData.setPriceMicrosForTesting(10_000_000L);
Assert.assertNull(shoppingPersistedTabData.getPriceDrop());
}
@UiThreadTest
@SmallTest
@Test
public void testPriceDropFilterPriceIncrease() {
ShoppingPersistedTabData shoppingPersistedTabData =
ShoppingPersistedTabDataTestUtils.createShoppingPersistedTabDataWithDefaults();
// $9.33 -> $9.66 price increase is not a price drop
shoppingPersistedTabData.setPreviousPriceMicrosForTesting(9_330_000L);
shoppingPersistedTabData.setPriceMicrosForTesting(9_660_000L);
Assert.assertNull(shoppingPersistedTabData.getPriceDrop());
}
@UiThreadTest
@SmallTest
@Test
public void testPriceDropGBP() {
ShoppingPersistedTabData shoppingPersistedTabData =
ShoppingPersistedTabDataTestUtils.createShoppingPersistedTabDataWithCurrencyCode(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO,
ShoppingPersistedTabDataTestUtils.GREAT_BRITAIN_CURRENCY_CODE);
shoppingPersistedTabData.setPreviousPriceMicrosForTesting(15_000_000L);
shoppingPersistedTabData.setPriceMicrosForTesting(9_560_000L);
Assert.assertNotNull(shoppingPersistedTabData.getPriceDrop());
Assert.assertEquals("£15", shoppingPersistedTabData.getPriceDrop().previousPrice);
Assert.assertEquals("£9.56", shoppingPersistedTabData.getPriceDrop().price);
}
@UiThreadTest
@SmallTest
@Test
public void testPriceDropJPY() {
ShoppingPersistedTabData shoppingPersistedTabData =
ShoppingPersistedTabDataTestUtils.createShoppingPersistedTabDataWithCurrencyCode(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO,
ShoppingPersistedTabDataTestUtils.JAPAN_CURRENCY_CODE);
shoppingPersistedTabData.setPreviousPriceMicrosForTesting(3_140_000_000_000L);
shoppingPersistedTabData.setPriceMicrosForTesting(287_000_000_000L);
Assert.assertNotNull(shoppingPersistedTabData.getPriceDrop());
Assert.assertEquals("Â¥3,140,000", shoppingPersistedTabData.getPriceDrop().previousPrice);
Assert.assertEquals("Â¥287,000", shoppingPersistedTabData.getPriceDrop().price);
}
@UiThreadTest
@SmallTest
@Test
public void testStalePriceDropUSD() {
ShoppingPersistedTabData shoppingPersistedTabData =
ShoppingPersistedTabDataTestUtils.createShoppingPersistedTabDataWithCurrencyCode(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO,
ShoppingPersistedTabDataTestUtils.UNITED_STATES_CURRENCY_CODE);
// $10 -> $5 (50% and $5 price drop is big enough)
shoppingPersistedTabData.setPreviousPriceMicrosForTesting(10000000L);
shoppingPersistedTabData.setPriceMicrosForTesting(5000000L);
Assert.assertNotNull(shoppingPersistedTabData.getPriceDrop());
Assert.assertEquals("$5.00", shoppingPersistedTabData.getPriceDrop().price);
Assert.assertEquals("$10", shoppingPersistedTabData.getPriceDrop().previousPrice);
// Price drops greater than a week old are removed
shoppingPersistedTabData.setLastPriceChangeTimeMsForTesting(
System.currentTimeMillis() - TimeUnit.DAYS.toMillis(8));
Assert.assertNull(shoppingPersistedTabData.getPriceDrop());
}
@UiThreadTest
@SmallTest
@Test
public void testNewUrlResetSPTD() {
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab);
shoppingPersistedTabData.setPriceMicros(42_000_000L);
shoppingPersistedTabData.setPreviousPriceMicros(60_000_000L);
shoppingPersistedTabData.setCurrencyCode("USD");
Assert.assertNotNull(shoppingPersistedTabData.getPriceDrop());
shoppingPersistedTabData.getUrlUpdatedObserverForTesting().onUrlUpdated(tab);
Assert.assertNull(shoppingPersistedTabData.getPriceDrop());
}
@UiThreadTest
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_with_optimization_guide/true"})
public void testSPTDSavingEnabledUponSuccessfulResponse() {
final Semaphore semaphore = new Semaphore(0);
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse
.BUYABLE_PRODUCT_INITIAL);
TestThreadUtils.runOnUiThreadBlocking(() -> {
ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> {
Assert.assertTrue(shoppingPersistedTabData.mIsTabSaveEnabledSupplier.get());
semaphore.release();
});
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
}
@UiThreadTest
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_with_optimization_guide/true"})
public void testSPTDSavingEnabledUponSuccessfulProductUpdateResponse() {
final Semaphore semaphore = new Semaphore(0);
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse
.BUYABLE_PRODUCT_AND_PRODUCT_UPDATE);
TestThreadUtils.runOnUiThreadBlocking(() -> {
ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> {
Assert.assertTrue(shoppingPersistedTabData.mIsTabSaveEnabledSupplier.get());
semaphore.release();
});
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
}
@UiThreadTest
@SmallTest
@Test
public void testSPTDNullUponUnsuccessfulResponse() {
final Semaphore semaphore = new Semaphore(0);
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse.BUYABLE_PRODUCT_EMPTY);
TestThreadUtils.runOnUiThreadBlocking(() -> {
ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> {
Assert.assertNull(shoppingPersistedTabData);
semaphore.release();
});
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
}
@UiThreadTest
@SmallTest
@Test
public void testSPTDNullOptimizationGuideFalse() {
final Semaphore semaphore = new Semaphore(0);
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse.NONE);
TestThreadUtils.runOnUiThreadBlocking(() -> {
ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> {
Assert.assertNull(shoppingPersistedTabData);
semaphore.release();
});
});
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
}
@UiThreadTest
@SmallTest
@Test
public void testSerializationBug() {
Tab tab = ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab);
shoppingPersistedTabData.setPriceMicros(42_000_000L, null);
ByteBuffer serialized = shoppingPersistedTabData.getSerializeSupplier().get();
PersistedTabDataConfiguration config = PersistedTabDataConfiguration.get(
ShoppingPersistedTabData.class, tab.isIncognito());
ShoppingPersistedTabData deserialized =
new ShoppingPersistedTabData(tab, serialized, config.getStorage(), config.getId());
Assert.assertEquals(42_000_000L, deserialized.getPriceMicros());
}
@UiThreadTest
@SmallTest
@Test
public void testSerializeWithOfferId() {
Tab tab = new MockTab(ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab);
ObservableSupplierImpl<Boolean> supplier = new ObservableSupplierImpl<>();
supplier.set(true);
shoppingPersistedTabData.registerIsTabSaveEnabledSupplier(supplier);
shoppingPersistedTabData.setMainOfferId(ShoppingPersistedTabDataTestUtils.FAKE_OFFER_ID);
ByteBuffer serialized = shoppingPersistedTabData.getSerializeSupplier().get();
ShoppingPersistedTabData deserialized = new ShoppingPersistedTabData(tab);
deserialized.deserialize(serialized);
Assert.assertEquals(
ShoppingPersistedTabDataTestUtils.FAKE_OFFER_ID, deserialized.getMainOfferId());
}
@UiThreadTest
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_with_optimization_guide/true"})
public void testOptimizationGuideNavigationIntegration() {
Tab tab = new MockTab(ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab);
doReturn(true).when(mNavigationHandle).isInPrimaryMainFrame();
GURL gurl = new GURL("https://www.google.com");
doReturn(gurl).when(mNavigationHandle).getUrl();
shoppingPersistedTabData.getUrlUpdatedObserverForTesting().onDidFinishNavigation(
tab, mNavigationHandle);
ShoppingPersistedTabDataTestUtils.verifyOptimizationGuideCalledWithNavigationHandle(
mOptimizationGuideBridgeJniMock, gurl);
}
@UiThreadTest
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_with_optimization_guide/true"})
public void testOptGuidePrefetching() {
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponseAsync(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse
.BUYABLE_PRODUCT_AND_PRODUCT_UPDATE);
MockTab tab = (MockTab) ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
tab.setIsInitialized(true);
GURL gurl = new GURL("https://www.google.com");
tab.setGurlOverrideForTesting(gurl);
ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab);
doReturn(gurl).when(mNavigationHandle).getUrl();
Semaphore semaphore = new Semaphore(0);
shoppingPersistedTabData.prefetchOnNewNavigation(
tab, mNavigationHandle, semaphore::release);
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
Assert.assertEquals(287_000_000L, shoppingPersistedTabData.getPriceMicros());
Assert.assertEquals(
123_456_789_012_345L, shoppingPersistedTabData.getPreviousPriceMicros());
}
@UiThreadTest
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_with_optimization_guide/true"})
public void testOptGuidePrefetchingNoResponse() {
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponseAsync(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse.NONE);
MockTab tab = (MockTab) ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
tab.setIsInitialized(true);
GURL gurl = new GURL("https://www.google.com");
tab.setGurlOverrideForTesting(gurl);
ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab);
doReturn(gurl).when(mNavigationHandle).getUrl();
Semaphore semaphore = new Semaphore(0);
shoppingPersistedTabData.prefetchOnNewNavigation(
tab, mNavigationHandle, semaphore::release);
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
Assert.assertEquals(
ShoppingPersistedTabData.NO_PRICE_KNOWN, shoppingPersistedTabData.getPriceMicros());
Assert.assertEquals(ShoppingPersistedTabData.NO_PRICE_KNOWN,
shoppingPersistedTabData.getPreviousPriceMicros());
}
@UiThreadTest
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_with_optimization_guide/true"})
public void testOptGuidePrefetchingUnparseable() {
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponseAsync(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse.UNPARSEABLE);
MockTab tab = (MockTab) ShoppingPersistedTabDataTestUtils.createTabOnUiThread(
ShoppingPersistedTabDataTestUtils.TAB_ID,
ShoppingPersistedTabDataTestUtils.IS_INCOGNITO);
tab.setIsInitialized(true);
GURL gurl = new GURL("https://www.google.com");
tab.setGurlOverrideForTesting(gurl);
ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab);
doReturn(gurl).when(mNavigationHandle).getUrl();
Semaphore semaphore = new Semaphore(0);
shoppingPersistedTabData.prefetchOnNewNavigation(
tab, mNavigationHandle, semaphore::release);
ShoppingPersistedTabDataTestUtils.acquireSemaphore(semaphore);
Assert.assertEquals(
ShoppingPersistedTabData.NO_PRICE_KNOWN, shoppingPersistedTabData.getPriceMicros());
Assert.assertEquals(ShoppingPersistedTabData.NO_PRICE_KNOWN,
shoppingPersistedTabData.getPreviousPriceMicros());
}
@UiThreadTest
@SmallTest
@Test
public void testIncognitoTabDisabled() throws TimeoutException {
TabImpl tab = mock(TabImpl.class);
doReturn(true).when(tab).isIncognito();
CallbackHelper callbackHelper = new CallbackHelper();
ShoppingPersistedTabData.from(tab, (res) -> {
Assert.assertNull(res);
callbackHelper.notifyCalled();
});
callbackHelper.waitForCallback(0);
}
@UiThreadTest
@SmallTest
@Test
public void testCustomTabsDisabled() throws TimeoutException {
TabImpl tab = mock(TabImpl.class);
doReturn(true).when(tab).isCustomTab();
CallbackHelper callbackHelper = new CallbackHelper();
ShoppingPersistedTabData.from(tab, (res) -> {
Assert.assertNull(res);
callbackHelper.notifyCalled();
});
callbackHelper.waitForCallback(0);
}
@UiThreadTest
@SmallTest
@Test
public void testUninitializedTabDisabled() throws TimeoutException {
TabImpl tab = mock(TabImpl.class);
doReturn(false).when(tab).isInitialized();
CallbackHelper callbackHelper = new CallbackHelper();
ShoppingPersistedTabData.from(tab, (res) -> {
Assert.assertNull(res);
callbackHelper.notifyCalled();
});
callbackHelper.waitForCallback(0);
}
@SmallTest
@Test
@CommandLineFlags.
Add({"force-fieldtrial-params=Study.Group:price_tracking_with_optimization_guide/true"})
public void testTabDestroyedSupplier() {
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.PRICE_TRACKING.getNumber(),
ShoppingPersistedTabDataTestUtils.MockPriceTrackingResponse
.BUYABLE_PRODUCT_INITIAL);
ShoppingPersistedTabDataTestUtils.mockOptimizationGuideResponse(
mOptimizationGuideBridgeJniMock,
HintsProto.OptimizationType.SHOPPING_PAGE_PREDICTOR.getNumber(),
OptimizationGuideDecision.TRUE, null);
TabImpl tab = mock(TabImpl.class);
doReturn(ShoppingPersistedTabDataTestUtils.TAB_ID).when(tab).getId();
doReturn(ShoppingPersistedTabDataTestUtils.IS_INCOGNITO).when(tab).isIncognito();
CriticalPersistedTabData criticalPersistedTabData = new CriticalPersistedTabData(tab);
criticalPersistedTabData.setTimestampMillis(
System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1));
for (boolean isInitialized : new boolean[] {false, true}) {
doReturn(isInitialized).when(tab).isInitialized();
Semaphore semaphore = new Semaphore(0);
TestThreadUtils.runOnUiThreadBlocking(() -> {
UserDataHost userDataHost = new UserDataHost();
userDataHost.setUserData(CriticalPersistedTabData.class, criticalPersistedTabData);
doReturn(userDataHost).when(tab).getUserDataHost();
ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> {
if (isInitialized) {
Assert.assertNotNull(shoppingPersistedTabData);
} else {
Assert.assertNull(shoppingPersistedTabData);
}
semaphore.release();
});
});
}
}
}