Bug 1616003 - QM: Make it possible to verify initialization status from unit tests; r=ttung,dom-workers-and-storage-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D63052

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jan Varga 2020-02-22 07:57:28 +00:00
parent 36fd1ef404
commit 34927b46f0
10 changed files with 285 additions and 2 deletions

View File

@ -304,6 +304,14 @@ mozilla::ipc::IPCResult QuotaRequestChild::Recv__delete__(
HandleResponse(aResponse.get_nsresult());
break;
case RequestResponse::TStorageInitializedResponse:
HandleResponse(aResponse.get_StorageInitializedResponse().initialized());
break;
case RequestResponse::TTemporaryStorageInitializedResponse:
HandleResponse(aResponse.get_TemporaryStorageInitializedResponse().initialized());
break;
case RequestResponse::TInitResponse:
case RequestResponse::TInitTemporaryStorageResponse:
case RequestResponse::TClearOriginResponse:

View File

@ -1487,6 +1487,35 @@ class QuotaRequestBase : public NormalOriginOperationBase,
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
};
class InitializedRequestBase : public QuotaRequestBase {
protected:
bool mInitialized;
public:
bool Init(Quota* aQuota) override;
protected:
InitializedRequestBase();
};
class StorageInitializedOp final : public InitializedRequestBase {
private:
~StorageInitializedOp() = default;
nsresult DoDirectoryWork(QuotaManager* aQuotaManager) override;
void GetResponse(RequestResponse& aResponse) override;
};
class TemporaryStorageInitializedOp final : public InitializedRequestBase {
private:
~TemporaryStorageInitializedOp() = default;
nsresult DoDirectoryWork(QuotaManager* aQuotaManager) override;
void GetResponse(RequestResponse& aResponse) override;
};
class InitOp final : public QuotaRequestBase {
public:
InitOp() : QuotaRequestBase(/* aExclusive */ false) {
@ -6234,7 +6263,7 @@ nsresult QuotaManager::UpgradeLocalStorageArchiveFrom4To5(
void QuotaManager::AssertStorageIsInitialized() const {
AssertIsOnIOThread();
MOZ_ASSERT(mStorageConnection);
MOZ_ASSERT(IsStorageInitialized());
}
#endif // DEBUG
@ -8503,6 +8532,8 @@ bool Quota::VerifyRequestParams(const RequestParams& aParams) const {
MOZ_ASSERT(aParams.type() != RequestParams::T__None);
switch (aParams.type()) {
case RequestParams::TStorageInitializedParams:
case RequestParams::TTemporaryStorageInitializedParams:
case RequestParams::TInitParams:
case RequestParams::TInitTemporaryStorageParams:
break;
@ -8695,6 +8726,14 @@ PQuotaRequestParent* Quota::AllocPQuotaRequestParent(
RefPtr<QuotaRequestBase> actor;
switch (aParams.type()) {
case RequestParams::TStorageInitializedParams:
actor = new StorageInitializedOp();
break;
case RequestParams::TTemporaryStorageInitializedParams:
actor = new TemporaryStorageInitializedOp();
break;
case RequestParams::TInitParams:
actor = new InitOp();
break;
@ -9320,6 +9359,65 @@ void QuotaRequestBase::ActorDestroy(ActorDestroyReason aWhy) {
NoteActorDestroyed();
}
InitializedRequestBase::InitializedRequestBase()
: QuotaRequestBase(/* aExclusive */ false), mInitialized(false) {
AssertIsOnOwningThread();
// Overwrite NormalOriginOperationBase default values.
mNeedsDirectoryLocking = false;
// Overwrite OriginOperationBase default values.
mNeedsQuotaManagerInit = true;
mNeedsStorageInit = false;
}
bool InitializedRequestBase::Init(Quota* aQuota) {
AssertIsOnOwningThread();
MOZ_ASSERT(aQuota);
return true;
}
nsresult StorageInitializedOp::DoDirectoryWork(QuotaManager* aQuotaManager) {
AssertIsOnIOThread();
AUTO_PROFILER_LABEL("StorageInitializedOp::DoDirectoryWork", OTHER);
mInitialized = aQuotaManager->IsStorageInitialized();
return NS_OK;
}
void StorageInitializedOp::GetResponse(RequestResponse& aResponse) {
AssertIsOnOwningThread();
StorageInitializedResponse storageInitializedResponse;
storageInitializedResponse.initialized() = mInitialized;
aResponse = storageInitializedResponse;
}
nsresult TemporaryStorageInitializedOp::DoDirectoryWork(QuotaManager* aQuotaManager) {
AssertIsOnIOThread();
AUTO_PROFILER_LABEL("TemporaryStorageInitializedOp::DoDirectoryWork", OTHER);
mInitialized = aQuotaManager->IsTemporaryStorageInitialized();
return NS_OK;
}
void TemporaryStorageInitializedOp::GetResponse(RequestResponse& aResponse) {
AssertIsOnOwningThread();
TemporaryStorageInitializedResponse temporaryStorageInitializedResponse;
temporaryStorageInitializedResponse.initialized() = mInitialized;
aResponse = temporaryStorageInitializedResponse;
}
nsresult InitOp::DoDirectoryWork(QuotaManager* aQuotaManager) {
AssertIsOnIOThread();

View File

@ -26,6 +26,14 @@ namespace mozilla {
namespace dom {
namespace quota {
struct StorageInitializedParams
{
};
struct TemporaryStorageInitializedParams
{
};
struct InitParams
{
};
@ -113,6 +121,8 @@ struct ListOriginsParams
union RequestParams
{
StorageInitializedParams;
TemporaryStorageInitializedParams;
InitParams;
InitTemporaryStorageParams;
InitStorageAndOriginParams;

View File

@ -8,6 +8,16 @@ namespace mozilla {
namespace dom {
namespace quota {
struct StorageInitializedResponse
{
bool initialized;
};
struct TemporaryStorageInitializedResponse
{
bool initialized;
};
struct InitResponse
{
};
@ -64,6 +74,8 @@ struct ListOriginsResponse
union RequestResponse
{
nsresult;
StorageInitializedResponse;
TemporaryStorageInitializedResponse;
InitResponse;
InitTemporaryStorageResponse;
InitStorageAndOriginResponse;

View File

@ -327,6 +327,11 @@ class QuotaManager final : public BackgroundThreadObject {
template <typename P>
void CollectPendingOriginsForListing(P aPredicate);
bool IsStorageInitialized() const {
AssertIsOnIOThread();
return static_cast<bool>(mStorageConnection);
}
void AssertStorageIsInitialized() const
#ifdef DEBUG
;

View File

@ -385,6 +385,54 @@ NS_IMPL_RELEASE_WITH_DESTROY(QuotaManagerService, Destroy())
NS_IMPL_QUERY_INTERFACE(QuotaManagerService, nsIQuotaManagerService,
nsIObserver)
NS_IMETHODIMP
QuotaManagerService::StorageInitialized(nsIQuotaRequest** _retval) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(nsContentUtils::IsCallerChrome());
if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
return NS_ERROR_UNEXPECTED;
}
RefPtr<Request> request = new Request();
StorageInitializedParams params;
nsAutoPtr<PendingRequestInfo> info(new RequestInfo(request, params));
nsresult rv = InitiateRequest(info);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
request.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
QuotaManagerService::TemporaryStorageInitialized(nsIQuotaRequest** _retval) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(nsContentUtils::IsCallerChrome());
if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
return NS_ERROR_UNEXPECTED;
}
RefPtr<Request> request = new Request();
TemporaryStorageInitializedParams params;
nsAutoPtr<PendingRequestInfo> info(new RequestInfo(request, params));
nsresult rv = InitiateRequest(info);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
request.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
QuotaManagerService::Init(nsIQuotaRequest** _retval) {
MOZ_ASSERT(NS_IsMainThread());

View File

@ -15,6 +15,18 @@ interface nsIQuotaUsageRequest;
[scriptable, builtinclass, uuid(1b3d0a38-8151-4cf9-89fa-4f92c2ef0e7e)]
interface nsIQuotaManagerService : nsISupports
{
/**
* Check if storage is initialized.
*/
[must_use] nsIQuotaRequest
storageInitialized();
/**
* Check if temporary storage is initialized.
*/
[must_use] nsIQuotaRequest
temporaryStorageInitialized();
/**
* Initializes storage directory. This can be used in tests to verify
* upgrade methods.

View File

@ -116,6 +116,20 @@ function resetGlobalLimit() {
SpecialPowers.clearUserPref("dom.quotaManager.temporaryStorage.fixedLimit");
}
function storageInitialized(callback) {
let request = SpecialPowers._getQuotaManager().storageInitialized();
request.callback = callback;
return request;
}
function temporaryStorageInitialized(callback) {
let request = SpecialPowers._getQuotaManager().temporaryStorageInitialized();
request.callback = callback;
return request;
}
function init(callback) {
let request = SpecialPowers._getQuotaManager().init();
request.callback = callback;
@ -680,3 +694,39 @@ function verifyStorage(packageDefinitionRelativePaths, key) {
compareEntries(currentEntries, expectedEntries, key);
}
async function verifyInitializationStatus(
expectStorageIsInitialized,
expectTemporaryStorageIsInitialized
) {
if (!expectStorageIsInitialized && expectTemporaryStorageIsInitialized) {
throw new Error("Invalid expectation");
}
let request = storageInitialized();
await requestFinished(request);
const storageIsInitialized = request.result;
request = temporaryStorageInitialized();
await requestFinished(request);
const temporaryStorageIsInitialized = request.result;
ok(
!(!storageIsInitialized && temporaryStorageIsInitialized),
"Initialization status is consistent"
);
if (expectStorageIsInitialized) {
ok(storageIsInitialized, "Storage is initialized");
} else {
ok(!storageIsInitialized, "Storage is not initialized");
}
if (expectTemporaryStorageIsInitialized) {
ok(temporaryStorageIsInitialized, "Temporary storage is initialized");
} else {
ok(!temporaryStorageIsInitialized, "Temporary storage is not initialized");
}
}

View File

@ -35,6 +35,11 @@ function* testSteps() {
clear(continueToNextStepSync);
yield undefined;
info("Verifying initialization status");
verifyInitializationStatus(false, false).then(continueToNextStepSync);
yield undefined;
info("Getting usage");
getCurrentUsage(grabUsageAndContinueHandler);
@ -42,11 +47,21 @@ function* testSteps() {
ok(usage == 0, "Usage is zero");
info("Verifying initialization status");
verifyInitializationStatus(true, false).then(continueToNextStepSync);
yield undefined;
info("Clearing");
clear(continueToNextStepSync);
yield undefined;
info("Verifying initialization status");
verifyInitializationStatus(false, false).then(continueToNextStepSync);
yield undefined;
info("Installing package");
// The profile contains just one empty IndexedDB database. The file
@ -62,6 +77,11 @@ function* testSteps() {
ok(usage > 0, "Usage is not zero");
info("Verifying initialization status");
verifyInitializationStatus(true, false).then(continueToNextStepSync);
yield undefined;
info("Clearing");
clear(continueToNextStepSync);
@ -74,9 +94,14 @@ function* testSteps() {
let exists = file.exists();
ok(!exists, "Storage file doesn't exist");
info("Verifying initialization status");
verifyInitializationStatus(false, false).then(continueToNextStepSync);
yield undefined;
info("Initializing");
let request = init(continueToNextStepSync);
request = init(continueToNextStepSync);
yield undefined;
ok(request.resultCode == NS_OK, "Initialization succeeded");
@ -84,6 +109,11 @@ function* testSteps() {
exists = file.exists();
ok(exists, "Storage file does exist");
info("Verifying initialization status");
verifyInitializationStatus(true, false).then(continueToNextStepSync);
yield undefined;
info("Initializing origin");
request = initStorageAndChromeOrigin("persistent", continueToNextStepSync);
@ -105,5 +135,11 @@ function* testSteps() {
}
}
info("Verifying initialization status");
verifyInitializationStatus(true, false).then(continueToNextStepSync);
yield undefined;
finishTest();
}

View File

@ -33,4 +33,8 @@ async function testSteps() {
metadataFile.append(metadataFileName);
ok(metadataFile.exists(), "Directory metadata file does exist");
info("Verifying initialization status");
await verifyInitializationStatus(true, true);
}