Commit 72d4d605 authored by David Maunder's avatar David Maunder Committed by Commit Bot

Fix flaky CriticalPersistedTabData tests

I believe the problem is we are not synchronizing the
delete and save operations - we try to verify one
is done without waiting for the operation to complete.
I solved this by adding in some callbacks

Bug: 1101760
Change-Id: I851e9488df971728738b47292de96710d00a4bc3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2300811Reviewed-by: default avatarTommy Nyquist <nyquist@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Commit-Queue: David Maunder <davidjm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795660}
parent 369a40b0
...@@ -16,7 +16,6 @@ import org.mockito.MockitoAnnotations; ...@@ -16,7 +16,6 @@ import org.mockito.MockitoAnnotations;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.chrome.browser.tab.MockTab; import org.chromium.chrome.browser.tab.MockTab;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.WebContentsState; import org.chromium.chrome.browser.tab.WebContentsState;
...@@ -52,6 +51,8 @@ public class CriticalPersistedTabDataTest { ...@@ -52,6 +51,8 @@ public class CriticalPersistedTabDataTest {
private CriticalPersistedTabData mCriticalPersistedTabData; private CriticalPersistedTabData mCriticalPersistedTabData;
private MockPersistedTabDataStorage mStorage;
private static Tab mockTab(int id, boolean isEncrypted) { private static Tab mockTab(int id, boolean isEncrypted) {
return new MockTab(id, isEncrypted); return new MockTab(id, isEncrypted);
} }
...@@ -59,18 +60,19 @@ public class CriticalPersistedTabDataTest { ...@@ -59,18 +60,19 @@ public class CriticalPersistedTabDataTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
PersistedTabDataConfiguration.setUseTestConfig(true);
mStorage =
(MockPersistedTabDataStorage) PersistedTabDataConfiguration.getTestConfig().storage;
} }
@SmallTest @SmallTest
@Test @Test
@DisabledTest(message = "https://crbug.com/1101760")
public void testNonEncryptedSaveRestore() throws InterruptedException { public void testNonEncryptedSaveRestore() throws InterruptedException {
testSaveRestoreDelete(false); testSaveRestoreDelete(false);
} }
@SmallTest @SmallTest
@Test @Test
@DisabledTest(message = "https://crbug.com/1101760")
public void testEncryptedSaveRestoreDelete() throws InterruptedException { public void testEncryptedSaveRestoreDelete() throws InterruptedException {
testSaveRestoreDelete(true); testSaveRestoreDelete(true);
} }
...@@ -84,14 +86,14 @@ public class CriticalPersistedTabDataTest { ...@@ -84,14 +86,14 @@ public class CriticalPersistedTabDataTest {
semaphore.release(); semaphore.release();
} }
}; };
final Semaphore saveSemaphore = new Semaphore(0);
ThreadUtils.runOnUiThreadBlocking(() -> { ThreadUtils.runOnUiThreadBlocking(() -> {
PersistedTabDataConfiguration config = CriticalPersistedTabData criticalPersistedTabData = new CriticalPersistedTabData(
PersistedTabDataConfiguration.get(CriticalPersistedTabData.class, isEncrypted); mockTab(TAB_ID, isEncrypted), PARENT_ID, ROOT_ID, TIMESTAMP, WEB_CONTENTS_STATE,
CriticalPersistedTabData criticalPersistedTabData = CONTENT_STATE_VERSION, OPENER_APP_ID, THEME_COLOR, LAUNCH_TYPE_AT_CREATION);
new CriticalPersistedTabData(mockTab(TAB_ID, isEncrypted), PARENT_ID, ROOT_ID, mStorage.setSemaphore(saveSemaphore);
TIMESTAMP, WEB_CONTENTS_STATE, CONTENT_STATE_VERSION, OPENER_APP_ID, criticalPersistedTabData.saveForTesting();
THEME_COLOR, LAUNCH_TYPE_AT_CREATION, config.storage, config.id); acquireSemaphore(saveSemaphore);
criticalPersistedTabData.save();
CriticalPersistedTabData.from(mockTab(TAB_ID, isEncrypted), callback); CriticalPersistedTabData.from(mockTab(TAB_ID, isEncrypted), callback);
}); });
semaphore.acquire(); semaphore.acquire();
...@@ -108,8 +110,11 @@ public class CriticalPersistedTabDataTest { ...@@ -108,8 +110,11 @@ public class CriticalPersistedTabDataTest {
Assert.assertArrayEquals(mCriticalPersistedTabData.getWebContentsState().buffer().array(), Assert.assertArrayEquals(mCriticalPersistedTabData.getWebContentsState().buffer().array(),
WEB_CONTENTS_STATE_BYTES); WEB_CONTENTS_STATE_BYTES);
Semaphore deleteSemaphore = new Semaphore(0);
ThreadUtils.runOnUiThreadBlocking(() -> { ThreadUtils.runOnUiThreadBlocking(() -> {
mStorage.setSemaphore(deleteSemaphore);
mCriticalPersistedTabData.delete(); mCriticalPersistedTabData.delete();
acquireSemaphore(deleteSemaphore);
CriticalPersistedTabData.from(mockTab(TAB_ID, isEncrypted), callback); CriticalPersistedTabData.from(mockTab(TAB_ID, isEncrypted), callback);
}); });
semaphore.acquire(); semaphore.acquire();
...@@ -122,4 +127,13 @@ public class CriticalPersistedTabDataTest { ...@@ -122,4 +127,13 @@ public class CriticalPersistedTabDataTest {
// - restore() multiple times // - restore() multiple times
// - delete() multiple times // - delete() multiple times
} }
private static void acquireSemaphore(Semaphore semaphore) {
try {
semaphore.acquire();
} catch (InterruptedException e) {
// Throw Runtime exception to make catching InterruptedException unnecessary
throw new RuntimeException(e);
}
}
} }
...@@ -28,6 +28,7 @@ android_library("java") { ...@@ -28,6 +28,7 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java", "java/src/org/chromium/chrome/browser/tab/state/EncryptedFilePersistedTabDataStorage.java",
"java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java", "java/src/org/chromium/chrome/browser/tab/state/FilePersistedTabDataStorage.java",
"java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java", "java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabData.java",
"java/src/org/chromium/chrome/browser/tab/state/MockPersistedTabDataStorage.java",
"java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java", "java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java",
"java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java", "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataConfiguration.java",
"java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java", "java/src/org/chromium/chrome/browser/tab/state/PersistedTabDataFactory.java",
......
...@@ -75,9 +75,8 @@ public class CriticalPersistedTabData extends PersistedTabData { ...@@ -75,9 +75,8 @@ public class CriticalPersistedTabData extends PersistedTabData {
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
CriticalPersistedTabData(Tab tab, int parentId, int rootId, long timestampMillis, CriticalPersistedTabData(Tab tab, int parentId, int rootId, long timestampMillis,
WebContentsState webContentsState, int contentStateVersion, String openerAppId, WebContentsState webContentsState, int contentStateVersion, String openerAppId,
int themeColor, int launchTypeAtCreation, int themeColor, int launchTypeAtCreation) {
PersistedTabDataStorage persistedTabDataStorage, String persistedTabDataId) { this(tab);
super(tab, persistedTabDataStorage, persistedTabDataId);
mParentId = parentId; mParentId = parentId;
mRootId = rootId; mRootId = rootId;
mTimestampMillis = timestampMillis; mTimestampMillis = timestampMillis;
...@@ -136,16 +135,13 @@ public class CriticalPersistedTabData extends PersistedTabData { ...@@ -136,16 +135,13 @@ public class CriticalPersistedTabData extends PersistedTabData {
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public static CriticalPersistedTabData build(Tab tab) { public static CriticalPersistedTabData build(Tab tab) {
PersistedTabDataConfiguration config = PersistedTabDataConfiguration.get(
CriticalPersistedTabData.class, tab.isIncognito());
// CriticalPersistedTabData is initialized with default values // CriticalPersistedTabData is initialized with default values
CriticalPersistedTabData criticalPersistedTabData = CriticalPersistedTabData criticalPersistedTabData =
new CriticalPersistedTabData(tab, Tab.INVALID_TAB_ID, tab.getId(), new CriticalPersistedTabData(tab, Tab.INVALID_TAB_ID, tab.getId(),
INVALID_TIMESTAMP, null, -1, "", UNSPECIFIED_THEME_COLOR, INVALID_TIMESTAMP, null, -1, "", UNSPECIFIED_THEME_COLOR,
tab.getLaunchTypeAtInitialTabCreation() == null tab.getLaunchTypeAtInitialTabCreation() == null
? TabLaunchType.FROM_LINK ? TabLaunchType.FROM_LINK
: tab.getLaunchTypeAtInitialTabCreation(), : tab.getLaunchTypeAtInitialTabCreation());
config.storage, config.id);
return criticalPersistedTabData; return criticalPersistedTabData;
} }
...@@ -268,7 +264,7 @@ public class CriticalPersistedTabData extends PersistedTabData { ...@@ -268,7 +264,7 @@ public class CriticalPersistedTabData extends PersistedTabData {
.setParentId(mParentId) .setParentId(mParentId)
.setRootId(mRootId) .setRootId(mRootId)
.setTimestampMillis(mTimestampMillis) .setTimestampMillis(mTimestampMillis)
.setWebContentsStateBytes(ByteString.copyFrom(mWebContentsState.buffer())) .setWebContentsStateBytes(ByteString.copyFrom(mWebContentsState.buffer().array()))
.setContentStateVersion(mContentStateVersion) .setContentStateVersion(mContentStateVersion)
.setOpenerAppId(mOpenerAppId) .setOpenerAppId(mOpenerAppId)
.setThemeColor(mThemeColor) .setThemeColor(mThemeColor)
...@@ -277,6 +273,7 @@ public class CriticalPersistedTabData extends PersistedTabData { ...@@ -277,6 +273,7 @@ public class CriticalPersistedTabData extends PersistedTabData {
.toByteArray(); .toByteArray();
} }
// TODO(crbug.com/1113814) remove save() override
@Override @Override
public void save() { public void save() {
mTab.setIsTabStateDirty(true); mTab.setIsTabStateDirty(true);
...@@ -285,6 +282,17 @@ public class CriticalPersistedTabData extends PersistedTabData { ...@@ -285,6 +282,17 @@ public class CriticalPersistedTabData extends PersistedTabData {
// without saving (i.e. as a regular UserData object). // without saving (i.e. as a regular UserData object).
} }
/**
* Used in tests when we need to save a CriticalPersistedTabData object.
* Ultimately will be deprecated by this.save() - for now this.save()
* is not saving while fields are being migrated to CriticalPersistedTabData
* TODO(crbug.com/1113813) Remove saveForTesting()
*/
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
protected void saveForTesting() {
super.save();
}
@Override @Override
public void destroy() {} public void destroy() {}
......
// 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 org.chromium.base.Callback;
import org.chromium.base.task.PostTask;
import org.chromium.content_public.browser.UiThreadTaskTraits;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Semaphore;
/**
* Mock implementation of {@link PersistedTabDataStorage} for tests
*/
public class MockPersistedTabDataStorage implements PersistedTabDataStorage {
private Semaphore mSemaphore;
private final Map<String, byte[]> mStorage = new HashMap<>();
@Override
public void save(int tabId, String tabDataId, byte[] data) {
mStorage.put(getKey(tabId), data);
if (mSemaphore != null) {
mSemaphore.release();
}
}
@Override
public void restore(int tabId, String tabDataId, Callback<byte[]> callback) {
PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT,
() -> { callback.onResult(mStorage.get(getKey(tabId))); });
if (mSemaphore != null) {
mSemaphore.release();
}
}
@Override
public void delete(int tabId, String tabDataId) {
mStorage.remove(getKey(tabId));
if (mSemaphore != null) {
mSemaphore.release();
}
}
@Override
public String getUmaTag() {
return "MPTDS";
}
private static String getKey(int tabId) {
return String.format(Locale.US, "%d", tabId);
}
public void setSemaphore(Semaphore semaphore) {
mSemaphore = semaphore;
}
}
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.tab.state; package org.chromium.chrome.browser.tab.state;
import androidx.annotation.VisibleForTesting;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -17,13 +19,17 @@ public enum PersistedTabDataConfiguration { ...@@ -17,13 +19,17 @@ public enum PersistedTabDataConfiguration {
CRITICAL_PERSISTED_TAB_DATA("CPTD", new FilePersistedTabDataStorage()), CRITICAL_PERSISTED_TAB_DATA("CPTD", new FilePersistedTabDataStorage()),
ENCRYPTED_CRITICAL_PERSISTED_TAB_DATA("ECPTD", new EncryptedFilePersistedTabDataStorage()), ENCRYPTED_CRITICAL_PERSISTED_TAB_DATA("ECPTD", new EncryptedFilePersistedTabDataStorage()),
MOCK_PERSISTED_TAB_DATA("MPTD", new FilePersistedTabDataStorage()), MOCK_PERSISTED_TAB_DATA("MPTD", new FilePersistedTabDataStorage()),
ENCRYPTED_MOCK_PERSISTED_TAB_DATA("EMPTD", new EncryptedFilePersistedTabDataStorage()); ENCRYPTED_MOCK_PERSISTED_TAB_DATA("EMPTD", new EncryptedFilePersistedTabDataStorage()),
// TODO(crbug.com/1113828) investigate separating test from prod test implementations
TEST_CONFIG("TC", new MockPersistedTabDataStorage());
private static final Map<Class<? extends PersistedTabData>, PersistedTabDataConfiguration> private static final Map<Class<? extends PersistedTabData>, PersistedTabDataConfiguration>
sLookup = new HashMap<>(); sLookup = new HashMap<>();
private static final Map<Class<? extends PersistedTabData>, PersistedTabDataConfiguration> private static final Map<Class<? extends PersistedTabData>, PersistedTabDataConfiguration>
sEncryptedLookup = new HashMap<>(); sEncryptedLookup = new HashMap<>();
private static boolean sUseTestConfig;
static { static {
// TODO(crbug.com/1060187) remove static initializer and initialization lazy // TODO(crbug.com/1060187) remove static initializer and initialization lazy
sLookup.put(CriticalPersistedTabData.class, CRITICAL_PERSISTED_TAB_DATA); sLookup.put(CriticalPersistedTabData.class, CRITICAL_PERSISTED_TAB_DATA);
...@@ -49,9 +55,22 @@ public enum PersistedTabDataConfiguration { ...@@ -49,9 +55,22 @@ public enum PersistedTabDataConfiguration {
*/ */
public static PersistedTabDataConfiguration get( public static PersistedTabDataConfiguration get(
Class<? extends PersistedTabData> clazz, boolean isEncrypted) { Class<? extends PersistedTabData> clazz, boolean isEncrypted) {
if (sUseTestConfig) {
return TEST_CONFIG;
}
if (isEncrypted) { if (isEncrypted) {
return sEncryptedLookup.get(clazz); return sEncryptedLookup.get(clazz);
} }
return sLookup.get(clazz); return sLookup.get(clazz);
} }
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
protected static void setUseTestConfig(boolean useTestConfig) {
sUseTestConfig = useTestConfig;
}
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
protected static PersistedTabDataConfiguration getTestConfig() {
return TEST_CONFIG;
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment