| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/components/kcer/token_key_finder.h" |
| #include "base/test/task_environment.h" |
| #include "base/test/test_future.h" |
| #include "base/timer/timer.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace kcer::internal { |
| namespace { |
| |
| class KcerTokenKeyFinderTest : public ::testing::Test { |
| protected: |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| }; |
| |
| // Test that TokenKeyFinder can collect one "key found" result which is returned |
| // synchronously. |
| TEST_F(KcerTokenKeyFinderTest, OneKeyFoundResultSync) { |
| base::test::TestFuture<base::expected<absl::optional<Token>, Error>> |
| result_waiter; |
| |
| auto finder = TokenKeyFinder::Create( |
| /*results_to_receive=*/1, result_waiter.GetCallback()); |
| |
| auto finder_callback = finder->GetCallback(Token::kDevice); |
| |
| finder.reset(); // It should be ok to delete the original ref-pointer now. |
| |
| EXPECT_FALSE(result_waiter.IsReady()); |
| |
| std::move(finder_callback).Run(/*key_exists=*/true); |
| |
| EXPECT_TRUE(result_waiter.IsReady()); |
| ASSERT_TRUE(result_waiter.Get().has_value()); |
| EXPECT_EQ(result_waiter.Get().value(), Token::kDevice); |
| } |
| |
| // Test that TokenKeyFinder can collect one "key found" result which is returned |
| // asynchronously. |
| TEST_F(KcerTokenKeyFinderTest, OneKeyFoundResultAsync) { |
| base::test::TestFuture<base::expected<absl::optional<Token>, Error>> |
| result_waiter; |
| |
| auto finder = TokenKeyFinder::Create( |
| /*results_to_receive=*/1, result_waiter.GetCallback()); |
| |
| base::OneShotTimer fake_token; // Runs a callback after a delay. |
| fake_token.Start(FROM_HERE, base::Seconds(10), |
| base::BindOnce(finder->GetCallback(Token::kDevice), |
| /*key_exists=*/true)); |
| |
| finder.reset(); // It should be ok to delete the original ref-pointer now. |
| |
| EXPECT_FALSE(result_waiter.IsReady()); |
| |
| task_environment_.FastForwardBy(base::Seconds(5)); |
| EXPECT_FALSE(result_waiter.IsReady()); |
| task_environment_.FastForwardBy(base::Seconds(6)); |
| |
| EXPECT_TRUE(result_waiter.IsReady()); |
| ASSERT_TRUE(result_waiter.Get().has_value()); |
| EXPECT_EQ(result_waiter.Get().value(), Token::kDevice); |
| } |
| |
| // Test that TokenKeyFinder can collect one "key not found" result. |
| TEST_F(KcerTokenKeyFinderTest, OneKeyNotFoundResult) { |
| base::test::TestFuture<base::expected<absl::optional<Token>, Error>> |
| result_waiter; |
| |
| auto finder = TokenKeyFinder::Create( |
| /*results_to_receive=*/1, result_waiter.GetCallback()); |
| |
| base::OneShotTimer fake_token; // Runs a callback after a delay. |
| fake_token.Start(FROM_HERE, base::Seconds(10), |
| base::BindOnce(finder->GetCallback(Token::kDevice), |
| /*key_exists=*/false)); |
| |
| finder.reset(); // It should be ok to delete the original ref-pointer now. |
| |
| EXPECT_FALSE(result_waiter.IsReady()); |
| |
| task_environment_.FastForwardBy(base::Seconds(11)); |
| |
| EXPECT_TRUE(result_waiter.IsReady()); |
| ASSERT_TRUE(result_waiter.Get().has_value()); |
| EXPECT_FALSE(result_waiter.Get().value().has_value()); |
| } |
| |
| // Test that TokenKeyFinder can collect one failure result. |
| TEST_F(KcerTokenKeyFinderTest, OneFailureResult) { |
| base::test::TestFuture<base::expected<absl::optional<Token>, Error>> |
| result_waiter; |
| |
| auto finder = TokenKeyFinder::Create( |
| /*results_to_receive=*/1, result_waiter.GetCallback()); |
| |
| base::OneShotTimer fake_token; // Runs a callback after a delay. |
| fake_token.Start(FROM_HERE, base::Seconds(10), |
| base::BindOnce(finder->GetCallback(Token::kUser), |
| /*key_exists=*/base::unexpected( |
| Error::kTokenInitializationFailed))); |
| |
| finder.reset(); // It should be ok to delete the original ref-pointer now. |
| |
| EXPECT_FALSE(result_waiter.IsReady()); |
| |
| task_environment_.FastForwardBy(base::Seconds(11)); |
| |
| EXPECT_TRUE(result_waiter.IsReady()); |
| ASSERT_FALSE(result_waiter.Get().has_value()); |
| EXPECT_EQ(result_waiter.Get().error(), Error::kTokenInitializationFailed); |
| } |
| |
| // Test that TokenKeyFinder indicates when a key is found when it's found on |
| // both tokens (not supposed to happen, but still a theoretically possible edge |
| // case). |
| TEST_F(KcerTokenKeyFinderTest, TwoKeysFound) { |
| base::test::TestFuture<base::expected<absl::optional<Token>, Error>> |
| result_waiter; |
| |
| auto finder = TokenKeyFinder::Create( |
| /*results_to_receive=*/2, result_waiter.GetCallback()); |
| |
| base::OneShotTimer fake_token_1; // Runs a callback after a delay. |
| fake_token_1.Start(FROM_HERE, base::Seconds(3), |
| base::BindOnce(finder->GetCallback(Token::kUser), |
| /*key_exists=*/true)); |
| |
| base::OneShotTimer fake_token_2; // Runs a callback after a delay. |
| fake_token_2.Start(FROM_HERE, base::Seconds(5), |
| base::BindOnce(finder->GetCallback(Token::kDevice), |
| /*key_exists=*/true)); |
| |
| finder.reset(); // It should be ok to delete the original ref-pointer now. |
| |
| EXPECT_FALSE(result_waiter.IsReady()); |
| |
| task_environment_.FastForwardBy(base::Seconds(6)); |
| |
| EXPECT_TRUE(result_waiter.IsReady()); |
| ASSERT_TRUE(result_waiter.Get().has_value()); |
| EXPECT_TRUE(result_waiter.Get().value().has_value()); |
| } |
| |
| // Test that TokenKeyFinder indicates that the key was not found when it was not |
| // found on both tokens. |
| TEST_F(KcerTokenKeyFinderTest, TwoTokensKeyNotFound) { |
| base::test::TestFuture<base::expected<absl::optional<Token>, Error>> |
| result_waiter; |
| |
| auto finder = TokenKeyFinder::Create( |
| /*results_to_receive=*/2, result_waiter.GetCallback()); |
| |
| base::OneShotTimer fake_token_1; // Runs a callback after a delay. |
| fake_token_1.Start(FROM_HERE, base::Seconds(3), |
| base::BindOnce(finder->GetCallback(Token::kUser), |
| /*key_exists=*/false)); |
| |
| base::OneShotTimer fake_token_2; // Runs a callback after a delay. |
| fake_token_2.Start(FROM_HERE, base::Seconds(5), |
| base::BindOnce(finder->GetCallback(Token::kDevice), |
| /*key_exists=*/false)); |
| |
| finder.reset(); // It should be ok to delete the original ref-pointer now. |
| |
| EXPECT_FALSE(result_waiter.IsReady()); |
| |
| task_environment_.FastForwardBy(base::Seconds(6)); |
| |
| EXPECT_TRUE(result_waiter.IsReady()); |
| ASSERT_TRUE(result_waiter.Get().has_value()); |
| EXPECT_FALSE(result_waiter.Get().value().has_value()); |
| } |
| |
| // Test that TokenKeyFinder indicates that the key was found when it was found |
| // on one of the tokens. |
| TEST_F(KcerTokenKeyFinderTest, TwoTokensOneKeyFound) { |
| base::test::TestFuture<base::expected<absl::optional<Token>, Error>> |
| result_waiter; |
| |
| auto finder = TokenKeyFinder::Create( |
| /*results_to_receive=*/2, result_waiter.GetCallback()); |
| |
| base::OneShotTimer fake_token_1; // Runs a callback after a delay. |
| fake_token_1.Start(FROM_HERE, base::Seconds(10), |
| base::BindOnce(finder->GetCallback(Token::kUser), |
| /*key_exists=*/false)); |
| |
| base::OneShotTimer fake_token_2; // Runs a callback after a delay. |
| fake_token_2.Start(FROM_HERE, base::Seconds(20), |
| base::BindOnce(finder->GetCallback(Token::kDevice), |
| /*key_exists=*/true)); |
| |
| finder.reset(); // It should be ok to delete the original ref-pointer now. |
| |
| EXPECT_FALSE(result_waiter.IsReady()); |
| |
| task_environment_.FastForwardBy(base::Seconds(15)); |
| EXPECT_FALSE(result_waiter.IsReady()); |
| task_environment_.FastForwardBy(base::Seconds(7)); |
| |
| EXPECT_TRUE(result_waiter.IsReady()); |
| ASSERT_TRUE(result_waiter.Get().has_value()); |
| EXPECT_EQ(result_waiter.Get().value(), Token::kDevice); |
| } |
| |
| // Test that TokenKeyFinder returns an error when the key is not found on one |
| // token and another one returned an error. |
| TEST_F(KcerTokenKeyFinderTest, OneErrorOneNotFound) { |
| base::test::TestFuture<base::expected<absl::optional<Token>, Error>> |
| result_waiter; |
| |
| auto finder = TokenKeyFinder::Create( |
| /*results_to_receive=*/2, result_waiter.GetCallback()); |
| |
| base::OneShotTimer fake_token_1; // Runs a callback after a delay. |
| fake_token_1.Start(FROM_HERE, base::Seconds(3), |
| base::BindOnce(finder->GetCallback(Token::kUser), |
| /*key_exists=*/base::unexpected( |
| Error::kTokenInitializationFailed))); |
| |
| base::OneShotTimer fake_token_2; // Runs a callback after a delay. |
| fake_token_2.Start(FROM_HERE, base::Seconds(4), |
| base::BindOnce(finder->GetCallback(Token::kDevice), |
| /*key_exists=*/false)); |
| |
| finder.reset(); // It should be ok to delete the original ref-pointer now. |
| |
| EXPECT_FALSE(result_waiter.IsReady()); |
| |
| task_environment_.FastForwardBy(base::Seconds(7)); |
| |
| EXPECT_TRUE(result_waiter.IsReady()); |
| ASSERT_FALSE(result_waiter.Get().has_value()); |
| EXPECT_EQ(result_waiter.Get().error(), Error::kTokenInitializationFailed); |
| } |
| |
| } // namespace |
| } // namespace kcer::internal |