blob: 3815b83e163511621bc7f67eae6ed1d15e6b5fb6 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "peridot/bin/ledger/p2p_sync/impl/user_communicator_impl.h"
#include <algorithm>
#include <string>
#include <lib/fit/function.h>
#include <lib/gtest/test_loop_fixture.h>
// gtest matchers are in gmock and we cannot include the specific header file
// directly as it is private to the library.
#include <lib/fidl/cpp/binding.h>
#include <lib/fxl/macros.h>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "peridot/bin/ledger/coroutine/coroutine_impl.h"
#include "peridot/bin/ledger/p2p_provider/impl/p2p_provider_impl.h"
#include "peridot/bin/ledger/p2p_provider/public/user_id_provider.h"
#include "peridot/bin/ledger/p2p_sync/impl/page_communicator_impl.h"
#include "peridot/bin/ledger/storage/testing/page_storage_empty_impl.h"
#include "peridot/bin/ledger/testing/netconnector/netconnector_factory.h"
namespace p2p_sync {
class PageCommunicatorImplInspectorForTest {
public:
static const std::set<std::string, convert::StringViewComparator>&
GetInterestedDevices(const std::unique_ptr<PageCommunicator>& page) {
return reinterpret_cast<PageCommunicatorImpl*>(page.get())
->interested_devices_;
}
};
namespace {
class FakePageStorage : public storage::PageStorageEmptyImpl {
public:
explicit FakePageStorage(std::string page_id)
: page_id_(std::move(page_id)) {}
~FakePageStorage() override {}
storage::PageId GetId() override { return page_id_; }
void MarkSyncedToPeer(
fit::function<void(storage::Status)> callback) override {
callback(storage::Status::OK);
}
private:
const std::string page_id_;
};
class FakeUserIdProvider : public p2p_provider::UserIdProvider {
public:
explicit FakeUserIdProvider(std::string user_id)
: user_id_(std::move(user_id)) {}
void GetUserId(fit::function<void(Status, std::string)> callback) override {
callback(Status::OK, user_id_);
};
private:
std::string user_id_;
};
class UserCommunicatorImplTest : public gtest::TestLoopFixture {
public:
UserCommunicatorImplTest() {}
~UserCommunicatorImplTest() override {}
std::unique_ptr<UserCommunicator> GetUserCommunicator(
std::string host_name, std::string user_name = "user") {
fuchsia::netconnector::NetConnectorPtr netconnector;
net_connector_factory_.AddBinding(host_name, netconnector.NewRequest());
std::unique_ptr<p2p_provider::P2PProvider> provider =
std::make_unique<p2p_provider::P2PProviderImpl>(
std::move(host_name), std::move(netconnector),
std::make_unique<FakeUserIdProvider>(std::move(user_name)));
return std::make_unique<UserCommunicatorImpl>(std::move(provider),
&coroutine_service_);
}
protected:
void SetUp() override { ::testing::Test::SetUp(); }
ledger::NetConnectorFactory net_connector_factory_;
private:
coroutine::CoroutineServiceImpl coroutine_service_;
FXL_DISALLOW_COPY_AND_ASSIGN(UserCommunicatorImplTest);
};
TEST_F(UserCommunicatorImplTest, OneHost_NoCrash) {
std::unique_ptr<UserCommunicator> user_communicator =
GetUserCommunicator("host1");
user_communicator->Start();
std::unique_ptr<LedgerCommunicator> ledger =
user_communicator->GetLedgerCommunicator("ledger1");
FakePageStorage storage("page1");
std::unique_ptr<PageCommunicator> page =
ledger->GetPageCommunicator(&storage, &storage);
page->Start();
RunLoopUntilIdle();
}
TEST_F(UserCommunicatorImplTest, ThreeHosts_SamePage) {
std::unique_ptr<UserCommunicator> user_communicator1 =
GetUserCommunicator("host1");
user_communicator1->Start();
std::unique_ptr<LedgerCommunicator> ledger1 =
user_communicator1->GetLedgerCommunicator("app");
FakePageStorage storage1("page");
std::unique_ptr<PageCommunicator> page1 =
ledger1->GetPageCommunicator(&storage1, &storage1);
page1->Start();
RunLoopUntilIdle();
std::unique_ptr<UserCommunicator> user_communicator2 =
GetUserCommunicator("host2");
user_communicator2->Start();
std::unique_ptr<LedgerCommunicator> ledger2 =
user_communicator2->GetLedgerCommunicator("app");
FakePageStorage storage2("page");
std::unique_ptr<PageCommunicator> page2 =
ledger2->GetPageCommunicator(&storage2, &storage2);
page2->Start();
RunLoopUntilIdle();
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page1),
testing::UnorderedElementsAre("host2"));
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page2),
testing::UnorderedElementsAre("host1"));
std::unique_ptr<UserCommunicator> user_communicator3 =
GetUserCommunicator("host3");
user_communicator3->Start();
std::unique_ptr<LedgerCommunicator> ledger3 =
user_communicator3->GetLedgerCommunicator("app");
FakePageStorage storage3("page");
std::unique_ptr<PageCommunicator> page3 =
ledger3->GetPageCommunicator(&storage3, &storage3);
page3->Start();
RunLoopUntilIdle();
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page1),
testing::UnorderedElementsAre("host2", "host3"));
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page2),
testing::UnorderedElementsAre("host1", "host3"));
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page3),
testing::UnorderedElementsAre("host1", "host2"));
page2.reset();
RunLoopUntilIdle();
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page1),
testing::UnorderedElementsAre("host3"));
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page3),
testing::UnorderedElementsAre("host1"));
}
TEST_F(UserCommunicatorImplTest, ThreeHosts_TwoPages) {
std::unique_ptr<UserCommunicator> user_communicator1 =
GetUserCommunicator("host1");
user_communicator1->Start();
std::unique_ptr<LedgerCommunicator> ledger1 =
user_communicator1->GetLedgerCommunicator("app");
FakePageStorage storage1_1("page1");
std::unique_ptr<PageCommunicator> page1_1 =
ledger1->GetPageCommunicator(&storage1_1, &storage1_1);
page1_1->Start();
FakePageStorage storage1_2("page2");
std::unique_ptr<PageCommunicator> page1_2 =
ledger1->GetPageCommunicator(&storage1_2, &storage1_2);
page1_2->Start();
RunLoopUntilIdle();
std::unique_ptr<UserCommunicator> user_communicator2 =
GetUserCommunicator("host2");
user_communicator2->Start();
std::unique_ptr<LedgerCommunicator> ledger2 =
user_communicator2->GetLedgerCommunicator("app");
FakePageStorage storage2_1("page1");
std::unique_ptr<PageCommunicator> page2_1 =
ledger2->GetPageCommunicator(&storage2_1, &storage2_1);
page2_1->Start();
RunLoopUntilIdle();
std::unique_ptr<UserCommunicator> user_communicator3 =
GetUserCommunicator("host3");
user_communicator3->Start();
std::unique_ptr<LedgerCommunicator> ledger3 =
user_communicator3->GetLedgerCommunicator("app");
FakePageStorage storage3_2("page2");
std::unique_ptr<PageCommunicator> page3_2 =
ledger3->GetPageCommunicator(&storage3_2, &storage3_2);
page3_2->Start();
RunLoopUntilIdle();
EXPECT_THAT(
PageCommunicatorImplInspectorForTest::GetInterestedDevices(page1_1),
testing::UnorderedElementsAre("host2"));
EXPECT_THAT(
PageCommunicatorImplInspectorForTest::GetInterestedDevices(page1_2),
testing::UnorderedElementsAre("host3"));
EXPECT_THAT(
PageCommunicatorImplInspectorForTest::GetInterestedDevices(page2_1),
testing::UnorderedElementsAre("host1"));
EXPECT_THAT(
PageCommunicatorImplInspectorForTest::GetInterestedDevices(page3_2),
testing::UnorderedElementsAre("host1"));
}
// This test adds some delay (ie. runs the loop until idle) between the time a
// device becomes visible and the time the page we are interested in becomes
// active. This ensure we correctly connect pages that become active after the
// device is connected.
TEST_F(UserCommunicatorImplTest, ThreeHosts_WaitBeforePageIsActive) {
std::unique_ptr<UserCommunicator> user_communicator1 =
GetUserCommunicator("host1");
user_communicator1->Start();
RunLoopUntilIdle();
std::unique_ptr<LedgerCommunicator> ledger1 =
user_communicator1->GetLedgerCommunicator("app");
FakePageStorage storage1("page");
std::unique_ptr<PageCommunicator> page1 =
ledger1->GetPageCommunicator(&storage1, &storage1);
page1->Start();
RunLoopUntilIdle();
std::unique_ptr<UserCommunicator> user_communicator2 =
GetUserCommunicator("host2");
user_communicator2->Start();
RunLoopUntilIdle();
std::unique_ptr<LedgerCommunicator> ledger2 =
user_communicator2->GetLedgerCommunicator("app");
FakePageStorage storage2("page");
std::unique_ptr<PageCommunicator> page2 =
ledger2->GetPageCommunicator(&storage2, &storage2);
page2->Start();
RunLoopUntilIdle();
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page1),
testing::UnorderedElementsAre("host2"));
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page2),
testing::UnorderedElementsAre("host1"));
std::unique_ptr<UserCommunicator> user_communicator3 =
GetUserCommunicator("host3");
user_communicator3->Start();
RunLoopUntilIdle();
std::unique_ptr<LedgerCommunicator> ledger3 =
user_communicator3->GetLedgerCommunicator("app");
FakePageStorage storage3("page");
std::unique_ptr<PageCommunicator> page3 =
ledger3->GetPageCommunicator(&storage3, &storage3);
page3->Start();
RunLoopUntilIdle();
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page1),
testing::UnorderedElementsAre("host2", "host3"));
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page2),
testing::UnorderedElementsAre("host1", "host3"));
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page3),
testing::UnorderedElementsAre("host1", "host2"));
page2.reset();
RunLoopUntilIdle();
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page1),
testing::UnorderedElementsAre("host3"));
EXPECT_THAT(PageCommunicatorImplInspectorForTest::GetInterestedDevices(page3),
testing::UnorderedElementsAre("host1"));
}
} // namespace
} // namespace p2p_sync