blob: b5ea873e34c4e506044d90acf33df47a922071bb [file] [log] [blame]
// Copyright 2019 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.
#include "services/network/trust_tokens/trust_token_persister.h"
#include <memory>
#include <string>
#include <utility>
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "services/network/trust_tokens/in_memory_trust_token_persister.h"
#include "services/network/trust_tokens/proto/public.pb.h"
#include "services/network/trust_tokens/proto/storage.pb.h"
#include "services/network/trust_tokens/sqlite_trust_token_persister.h"
#include "services/network/trust_tokens/trust_token_database_owner.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using ::testing::IsNull;
using ::testing::Pointee;
namespace network {
namespace {
MATCHER_P(EqualsProto,
message,
"Match a proto Message equal to the matcher's argument.") {
std::string expected_serialized, actual_serialized;
message.SerializeToString(&expected_serialized);
arg.SerializeToString(&actual_serialized);
return expected_serialized == actual_serialized;
}
class InMemoryTrustTokenPersisterFactory {
public:
static std::unique_ptr<TrustTokenPersister> Create() {
return std::make_unique<InMemoryTrustTokenPersister>();
}
};
class NoDatabaseSqliteTrustTokenPersisterFactory {
public:
static std::unique_ptr<TrustTokenPersister> Create() {
std::unique_ptr<TrustTokenDatabaseOwner> owner;
// Fail to open the database, in order to test that the in-memory fallback
// on database error works as intended.
TrustTokenDatabaseOwner::Create(
/*db_opener=*/base::BindOnce([](sql::Database*) { return false; }),
base::ThreadTaskRunnerHandle::Get(),
/*flush_delay_for_writes=*/base::TimeDelta(),
base::BindLambdaForTesting(
[&owner](std::unique_ptr<TrustTokenDatabaseOwner> created) {
owner = std::move(created);
base::RunLoop().Quit();
}));
base::RunLoop().RunUntilIdle();
CHECK(owner);
return std::make_unique<SQLiteTrustTokenPersister>(std::move(owner));
}
};
class EndToEndSqliteTrustTokenPersisterFactory {
public:
static std::unique_ptr<TrustTokenPersister> Create() {
std::unique_ptr<TrustTokenDatabaseOwner> owner;
TrustTokenDatabaseOwner::Create(
/*db_opener=*/base::BindOnce(
[](sql::Database* db) { return db->OpenInMemory(); }),
base::ThreadTaskRunnerHandle::Get(),
/*flush_delay_for_writes=*/base::TimeDelta(),
base::BindLambdaForTesting(
[&owner](std::unique_ptr<TrustTokenDatabaseOwner> created) {
owner = std::move(created);
base::RunLoop().Quit();
}));
base::RunLoop().RunUntilIdle();
CHECK(owner);
return std::make_unique<SQLiteTrustTokenPersister>(std::move(owner));
}
};
} // namespace
template <typename Factory>
class TrustTokenPersisterTest : public ::testing::Test {};
typedef ::testing::Types<InMemoryTrustTokenPersisterFactory,
NoDatabaseSqliteTrustTokenPersisterFactory,
EndToEndSqliteTrustTokenPersisterFactory>
TrustTokenPersisterFactoryTypes;
class PersisterFactoryTypeNames {
public:
template <typename T>
static std::string GetName(int) {
if (std::is_same<T, InMemoryTrustTokenPersisterFactory>())
return "InMemoryPersister";
if (std::is_same<T, NoDatabaseSqliteTrustTokenPersisterFactory>())
return "SQLitePersisterMemoryFallback";
if (std::is_same<T, EndToEndSqliteTrustTokenPersisterFactory>())
return "SQLitePersisterOnDisk";
NOTREACHED();
return "";
}
};
TYPED_TEST_SUITE(TrustTokenPersisterTest,
TrustTokenPersisterFactoryTypes,
PersisterFactoryTypeNames);
TYPED_TEST(TrustTokenPersisterTest, NegativeResults) {
base::test::TaskEnvironment env;
std::unique_ptr<TrustTokenPersister> persister = TypeParam::Create();
env.RunUntilIdle(); // Give implementations with asynchronous initialization
// time to initialize.
auto origin = *SuitableTrustTokenOrigin::Create(GURL("https://a.com/"));
EXPECT_THAT(persister->GetIssuerConfig(origin), IsNull());
EXPECT_THAT(persister->GetToplevelConfig(origin), IsNull());
EXPECT_THAT(persister->GetIssuerToplevelPairConfig(origin, origin), IsNull());
// Some implementations of TrustTokenPersister may release resources
// asynchronously at destruction time; manually free the persister and allow
// this asynchronous release to occur, if any.
persister.reset();
env.RunUntilIdle();
}
TYPED_TEST(TrustTokenPersisterTest, StoresIssuerConfigs) {
base::test::TaskEnvironment env;
std::unique_ptr<TrustTokenPersister> persister = TypeParam::Create();
env.RunUntilIdle(); // Give implementations with asynchronous initialization
// time to initialize.
TrustTokenIssuerConfig config;
TrustToken my_token;
my_token.set_body("token token token");
*config.add_tokens() = my_token;
auto config_to_store = std::make_unique<TrustTokenIssuerConfig>(config);
auto origin = *SuitableTrustTokenOrigin::Create(GURL("https://a.com/"));
persister->SetIssuerConfig(origin, std::move(config_to_store));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
auto result = persister->GetIssuerConfig(origin);
EXPECT_THAT(result, Pointee(EqualsProto(config)));
// Some implementations of TrustTokenPersister may release resources
// asynchronously at destruction time; manually free the persister and allow
// this asynchronous release to occur, if any.
persister.reset();
env.RunUntilIdle();
}
TYPED_TEST(TrustTokenPersisterTest, StoresToplevelConfigs) {
base::test::TaskEnvironment env;
std::unique_ptr<TrustTokenPersister> persister = TypeParam::Create();
env.RunUntilIdle(); // Give implementations with asynchronous initialization
// time to initialize.
TrustTokenToplevelConfig config;
*config.add_associated_issuers() = "an issuer";
auto config_to_store = std::make_unique<TrustTokenToplevelConfig>(config);
auto origin = *SuitableTrustTokenOrigin::Create(GURL("https://a.com/"));
persister->SetToplevelConfig(origin, std::move(config_to_store));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
auto result = persister->GetToplevelConfig(origin);
EXPECT_THAT(result, Pointee(EqualsProto(config)));
// Some implementations of TrustTokenPersister may release resources
// asynchronously at destruction time; manually free the persister and allow
// this asynchronous release to occur, if any.
persister.reset();
env.RunUntilIdle();
}
TYPED_TEST(TrustTokenPersisterTest, StoresIssuerToplevelPairConfigs) {
base::test::TaskEnvironment env;
std::unique_ptr<TrustTokenPersister> persister = TypeParam::Create();
env.RunUntilIdle(); // Give implementations with asynchronous initialization
// time to initialize.
TrustTokenIssuerToplevelPairConfig config;
config.set_last_redemption("five o'clock");
auto config_to_store =
std::make_unique<TrustTokenIssuerToplevelPairConfig>(config);
auto toplevel = *SuitableTrustTokenOrigin::Create(GURL("https://a.com/"));
auto issuer = *SuitableTrustTokenOrigin::Create(GURL("https://issuer.com/"));
persister->SetIssuerToplevelPairConfig(issuer, toplevel,
std::move(config_to_store));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
auto result = persister->GetIssuerToplevelPairConfig(issuer, toplevel);
EXPECT_THAT(result, Pointee(EqualsProto(config)));
// Some implementations of TrustTokenPersister may release resources
// asynchronously at destruction time; manually free the persister and allow
// this asynchronous release to occur, if any.
persister.reset();
env.RunUntilIdle();
}
TYPED_TEST(TrustTokenPersisterTest, DeletesIssuerToplevelKeyedData) {
base::test::TaskEnvironment env;
std::unique_ptr<TrustTokenPersister> persister = TypeParam::Create();
env.RunUntilIdle(); // Give implementations with asynchronous initialization
// time to initialize.
TrustTokenIssuerToplevelPairConfig pair_config;
pair_config.set_last_redemption("five o'clock");
auto toplevel = *SuitableTrustTokenOrigin::Create(GURL("https://a.com/"));
auto issuer = *SuitableTrustTokenOrigin::Create(GURL("https://issuer.com/"));
persister->SetIssuerToplevelPairConfig(
issuer, toplevel,
std::make_unique<TrustTokenIssuerToplevelPairConfig>(pair_config));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
// A matcher matching neither the issuer nor the top-level origin should not
// delete (issuer, top level)-keyed data.
EXPECT_FALSE(persister->DeleteForOrigins(base::BindLambdaForTesting(
[&](const SuitableTrustTokenOrigin& origin) { return false; })));
// A matcher matching the issuer should delete (issuer, top level)-keyed data.
EXPECT_TRUE(persister->DeleteForOrigins(
base::BindLambdaForTesting([&](const SuitableTrustTokenOrigin& origin) {
return origin == issuer;
})));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
EXPECT_FALSE(persister->GetIssuerToplevelPairConfig(issuer, toplevel));
// A matcher matching the top-level origin should delete (issuer, top
// level)-keyed data, too.
persister->SetIssuerToplevelPairConfig(
issuer, toplevel,
std::make_unique<TrustTokenIssuerToplevelPairConfig>(pair_config));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
ASSERT_TRUE(persister->GetIssuerToplevelPairConfig(issuer, toplevel));
EXPECT_TRUE(persister->DeleteForOrigins(
base::BindLambdaForTesting([&](const SuitableTrustTokenOrigin& origin) {
return origin == toplevel;
})));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
EXPECT_FALSE(persister->GetIssuerToplevelPairConfig(issuer, toplevel));
// Some implementations of TrustTokenPersister may release resources
// asynchronously at destruction time; manually free the persister and allow
// this asynchronous release to occur, if any.
persister.reset();
env.RunUntilIdle();
}
TYPED_TEST(TrustTokenPersisterTest, DeletesIssuerKeyedData) {
base::test::TaskEnvironment env;
std::unique_ptr<TrustTokenPersister> persister = TypeParam::Create();
env.RunUntilIdle(); // Give implementations with asynchronous initialization
// time to initialize.
TrustTokenIssuerConfig issuer_config;
issuer_config.add_tokens()->set_signing_key("key");
auto issuer = *SuitableTrustTokenOrigin::Create(GURL("https://issuer.com/"));
persister->SetIssuerConfig(
issuer, std::make_unique<TrustTokenIssuerConfig>(issuer_config));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
ASSERT_TRUE(persister->GetIssuerConfig(issuer));
// Deleting with a matcher not matching |issuer| should no-op.
EXPECT_FALSE(persister->DeleteForOrigins(base::BindLambdaForTesting(
[&](const SuitableTrustTokenOrigin& origin) { return false; })));
// Deleting with a matcher not matching |issuer| should delete data.
EXPECT_TRUE(persister->DeleteForOrigins(
base::BindLambdaForTesting([&](const SuitableTrustTokenOrigin& origin) {
return origin == issuer;
})));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
ASSERT_FALSE(persister->GetIssuerConfig(issuer));
// Some implementations of TrustTokenPersister may release resources
// asynchronously at destruction time; manually free the persister and allow
// this asynchronous release to occur, if any.
persister.reset();
env.RunUntilIdle();
}
TYPED_TEST(TrustTokenPersisterTest, DeletesToplevelKeyedData) {
base::test::TaskEnvironment env;
std::unique_ptr<TrustTokenPersister> persister = TypeParam::Create();
env.RunUntilIdle(); // Give implementations with asynchronous initialization
// time to initialize.
TrustTokenToplevelConfig toplevel_config;
*toplevel_config.add_associated_issuers() = "some issuer";
auto toplevel = *SuitableTrustTokenOrigin::Create(GURL("https://a.com/"));
persister->SetToplevelConfig(
toplevel, std::make_unique<TrustTokenToplevelConfig>(toplevel_config));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
ASSERT_TRUE(persister->GetToplevelConfig(toplevel));
// Deleting with a matcher not matching |toplevel| should no-op.
EXPECT_FALSE(persister->DeleteForOrigins(base::BindLambdaForTesting(
[&](const SuitableTrustTokenOrigin& origin) { return false; })));
// Deleting with a matcher matching |toplevel| should delete the data.
EXPECT_TRUE(persister->DeleteForOrigins(
base::BindLambdaForTesting([&](const SuitableTrustTokenOrigin& origin) {
return origin == toplevel;
})));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
ASSERT_FALSE(persister->GetToplevelConfig(toplevel));
// Some implementations of TrustTokenPersister may release resources
// asynchronously at destruction time; manually free the persister and allow
// this asynchronous release to occur, if any.
persister.reset();
env.RunUntilIdle();
}
TYPED_TEST(TrustTokenPersisterTest, RetrievesAvailableTrustTokens) {
base::test::TaskEnvironment env;
std::unique_ptr<TrustTokenPersister> persister = TypeParam::Create();
env.RunUntilIdle(); // Give implementations with asynchronous initialization
// time to initialize.
auto result = persister->GetStoredTrustTokenCounts();
EXPECT_EQ(result.size(), 0ul);
TrustTokenIssuerConfig config;
TrustToken my_token;
my_token.set_body("token token token");
*config.add_tokens() = my_token;
auto config_to_store = std::make_unique<TrustTokenIssuerConfig>(config);
auto origin = *SuitableTrustTokenOrigin::Create(GURL("https://a.com/"));
persister->SetIssuerConfig(origin, std::move(config_to_store));
env.RunUntilIdle(); // Give implementations with asynchronous write
// operations time to complete the operation.
result = persister->GetStoredTrustTokenCounts();
EXPECT_EQ(result.size(), 1ul);
EXPECT_EQ(result.begin()->first, origin);
EXPECT_EQ(result.begin()->second, 1);
// Some implementations of TrustTokenPersister may release resources
// asynchronously at destruction time; manually free the persister and allow
// this asynchronous release to occur, if any.
persister.reset();
env.RunUntilIdle();
}
} // namespace network