// Copyright 2016 The Weave 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 "src/access_revocation_manager_impl.h" #include #include #include #include #include "src/test/mock_clock.h" #include "src/bind_lambda.h" using testing::_; using testing::Return; using testing::StrictMock; namespace weave { class AccessRevocationManagerImplTest : public testing::Test { protected: void SetUp() { std::string to_load = R"([{ "user": "BQID", "app": "BwQF", "expiration": 463315200, "revocation": 463314200 }, { "user": "AQID", "app": "AwQF", "expiration": 473315199, "revocation": 473313199 }])"; EXPECT_CALL(config_store_, LoadSettings("black_list")) .WillOnce(Return(to_load)); EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( [](const std::string& json, const DoneCallback& callback) { std::string to_save = R"([{ "user": "AQID", "app": "AwQF", "expiration": 473315199, "revocation": 473313199 }])"; EXPECT_JSON_EQ(to_save, *test::CreateValue(json)); if (!callback.is_null()) callback.Run(nullptr); }))); EXPECT_CALL(clock_, Now()) .WillRepeatedly(Return(base::Time::FromTimeT(1412121212))); manager_.reset( new AccessRevocationManagerImpl{&config_store_, 10, &clock_}); } StrictMock clock_; StrictMock config_store_{false}; std::unique_ptr manager_; }; TEST_F(AccessRevocationManagerImplTest, Init) { EXPECT_EQ(1u, manager_->GetSize()); EXPECT_EQ(10u, manager_->GetCapacity()); EXPECT_EQ((std::vector{{ {1, 2, 3}, {3, 4, 5}, base::Time::FromTimeT(1419997999), base::Time::FromTimeT(1419999999), }}), manager_->GetEntries()); } TEST_F(AccessRevocationManagerImplTest, Block) { bool callback_called = false; manager_->AddEntryAddedCallback( base::Bind([&callback_called]() { callback_called = true; })); EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( [](const std::string& json, const DoneCallback& callback) { std::string to_save = R"([{ "user": "AQID", "app": "AwQF", "expiration": 473315199, "revocation": 473313199 }, { "app": "CAgI", "user": "BwcH", "expiration": 473305200, "revocation": 473295200 }])"; EXPECT_JSON_EQ(to_save, *test::CreateValue(json)); if (!callback.is_null()) callback.Run(nullptr); }))); manager_->Block({{7, 7, 7}, {8, 8, 8}, base::Time::FromTimeT(1419980000), base::Time::FromTimeT(1419990000)}, {}); EXPECT_TRUE(callback_called); } TEST_F(AccessRevocationManagerImplTest, BlockExpired) { manager_->Block({{}, {}, base::Time::FromTimeT(1300000000), base::Time::FromTimeT(1400000000)}, base::Bind([](ErrorPtr error) { EXPECT_TRUE(error->HasError("aleady_expired")); })); } TEST_F(AccessRevocationManagerImplTest, BlockListOverflow) { EXPECT_CALL(config_store_, LoadSettings("black_list")).WillOnce(Return("")); manager_.reset(new AccessRevocationManagerImpl{&config_store_, 10, &clock_}); EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) .WillRepeatedly(testing::WithArgs<1, 2>(testing::Invoke( [](const std::string& json, const DoneCallback& callback) { if (!callback.is_null()) callback.Run(nullptr); }))); EXPECT_EQ(0u, manager_->GetSize()); // Trigger overflow several times. for (size_t i = 0; i < manager_->GetCapacity() + 3; ++i) { bool callback_called = false; manager_->Block({{99, static_cast(i), static_cast(i)}, {8, 8, 8}, base::Time::FromTimeT(1419970000 + i), base::Time::FromTimeT(1419990000)}, base::Bind([&callback_called](ErrorPtr error) { callback_called = true; EXPECT_FALSE(error); })); EXPECT_TRUE(callback_called); } EXPECT_EQ(manager_->GetCapacity(), manager_->GetSize()); // We didn't block these ids, so we can use this to check if all_blocking // issue is set for correct revocation time. EXPECT_TRUE(manager_->IsBlocked({1}, {2}, base::Time::FromTimeT(1419970003))); EXPECT_FALSE( manager_->IsBlocked({1}, {2}, base::Time::FromTimeT(1419970004))); // Check if all blocking rules still work. for (size_t i = 0; i < manager_->GetCapacity() + 3; ++i) { EXPECT_TRUE(manager_->IsBlocked( {99, static_cast(i), static_cast(i)}, {8, 8, 8}, base::Time::FromTimeT(1419970000 + i))); } } TEST_F(AccessRevocationManagerImplTest, IsBlockedIdsNotMacth) { EXPECT_FALSE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}, {})); } TEST_F(AccessRevocationManagerImplTest, IsBlockedRevocationIsOld) { // Ids match but delegation time is newer than revocation time. EXPECT_FALSE(manager_->IsBlocked({1, 2, 3}, {3, 4, 5}, base::Time::FromTimeT(1429997999))); } class AccessRevocationManagerImplIsBlockedTest : public AccessRevocationManagerImplTest, public testing::WithParamInterface< std::tuple, std::vector>> { public: void SetUp() override { AccessRevocationManagerImplTest::SetUp(); EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) .WillOnce(testing::WithArgs<2>( testing::Invoke([](const DoneCallback& callback) { if (!callback.is_null()) callback.Run(nullptr); }))); manager_->Block({std::get<0>(GetParam()), std::get<1>(GetParam()), {}, base::Time::FromTimeT(1419990000)}, {}); } }; TEST_P(AccessRevocationManagerImplIsBlockedTest, IsBlocked) { EXPECT_TRUE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}, {})); } INSTANTIATE_TEST_CASE_P( Filters, AccessRevocationManagerImplIsBlockedTest, testing::Combine(testing::Values(std::vector{}, std::vector{7, 7, 7}), testing::Values(std::vector{}, std::vector{8, 8, 8}))); } // namespace weave