blob: 9ede9b2804a4fa2981a65fd5473dab51339df96e [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_provider/impl/p2p_provider_impl.h"
#include <algorithm>
#include <ostream>
#include <string>
#include <lib/fit/function.h>
// gtest matchers are in gmock.
#include <lib/fidl/cpp/binding.h>
#include <lib/fxl/macros.h>
#include <lib/gtest/test_loop_fixture.h>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "peridot/bin/ledger/p2p_provider/impl/static_user_id_provider.h"
#include "peridot/bin/ledger/p2p_provider/public/user_id_provider.h"
#include "peridot/bin/ledger/testing/netconnector/netconnector_factory.h"
namespace p2p_provider {
namespace {
class RecordingClient : public P2PProvider::Client {
public:
struct DeviceChange {
std::string device;
DeviceChangeType change;
bool operator==(const DeviceChange& b) const {
return device == b.device && change == b.change;
}
};
struct Message {
std::string source;
std::string data;
bool operator==(const Message& b) const {
return source == b.source && data == b.data;
}
};
void OnDeviceChange(fxl::StringView device_name,
DeviceChangeType change_type) override {
device_changes.push_back(DeviceChange{device_name.ToString(), change_type});
}
void OnNewMessage(fxl::StringView device_name,
fxl::StringView message) override {
messages.push_back(Message{device_name.ToString(), message.ToString()});
}
std::vector<DeviceChange> device_changes;
std::vector<Message> messages;
};
std::ostream& operator<<(std::ostream& os,
const RecordingClient::DeviceChange& d) {
return os << "DeviceChange{" << d.device << ", " << bool(d.change) << "}";
}
std::ostream& operator<<(std::ostream& os, const RecordingClient::Message& m) {
return os << "Message{" << m.source << ", " << m.data << "}";
}
class P2PProviderImplTest : public gtest::TestLoopFixture {
public:
P2PProviderImplTest() {}
~P2PProviderImplTest() override {}
std::unique_ptr<P2PProvider> GetProvider(std::string host_name,
std::string user_name = "user") {
fuchsia::netconnector::NetConnectorPtr netconnector;
net_connector_factory_.AddBinding(host_name, netconnector.NewRequest());
return std::make_unique<p2p_provider::P2PProviderImpl>(
std::move(host_name), std::move(netconnector),
std::make_unique<StaticUserIdProvider>(std::move(user_name)));
}
protected:
void SetUp() override { ::testing::Test::SetUp(); }
ledger::NetConnectorFactory net_connector_factory_;
private:
FXL_DISALLOW_COPY_AND_ASSIGN(P2PProviderImplTest);
};
TEST_F(P2PProviderImplTest, ThreeHosts_SameUser) {
std::unique_ptr<P2PProvider> provider1 = GetProvider("host1");
RecordingClient client1;
provider1->Start(&client1);
RunLoopUntilIdle();
EXPECT_TRUE(client1.device_changes.empty());
std::unique_ptr<P2PProvider> provider2 = GetProvider("host2");
RecordingClient client2;
provider2->Start(&client2);
RunLoopUntilIdle();
EXPECT_THAT(client1.device_changes,
testing::UnorderedElementsAre(RecordingClient::DeviceChange{
"host2", DeviceChangeType::NEW}));
EXPECT_THAT(client2.device_changes,
testing::UnorderedElementsAre(RecordingClient::DeviceChange{
"host1", DeviceChangeType::NEW}));
std::unique_ptr<P2PProvider> provider3 = GetProvider("host3");
RecordingClient client3;
provider3->Start(&client3);
RunLoopUntilIdle();
EXPECT_THAT(
client1.device_changes,
testing::ElementsAre(
RecordingClient::DeviceChange{"host2", DeviceChangeType::NEW},
RecordingClient::DeviceChange{"host3", DeviceChangeType::NEW}));
EXPECT_THAT(
client2.device_changes,
testing::ElementsAre(
RecordingClient::DeviceChange{"host1", DeviceChangeType::NEW},
RecordingClient::DeviceChange{"host3", DeviceChangeType::NEW}));
EXPECT_THAT(
client3.device_changes,
testing::UnorderedElementsAre(
RecordingClient::DeviceChange{"host1", DeviceChangeType::NEW},
RecordingClient::DeviceChange{"host2", DeviceChangeType::NEW}));
// Disconnect one host, and verify disconnection notices are sent.
provider2.reset();
RunLoopUntilIdle();
EXPECT_THAT(
client1.device_changes,
testing::ElementsAre(
RecordingClient::DeviceChange{"host2", DeviceChangeType::NEW},
RecordingClient::DeviceChange{"host3", DeviceChangeType::NEW},
RecordingClient::DeviceChange{"host2", DeviceChangeType::DELETED}));
EXPECT_THAT(
client3.device_changes,
testing::UnorderedElementsAre(
RecordingClient::DeviceChange{"host1", DeviceChangeType::NEW},
RecordingClient::DeviceChange{"host2", DeviceChangeType::NEW},
RecordingClient::DeviceChange{"host2", DeviceChangeType::DELETED}));
}
TEST_F(P2PProviderImplTest, FourHosts_TwoUsers) {
std::unique_ptr<P2PProvider> provider1 = GetProvider("host1", "user1");
RecordingClient client1;
provider1->Start(&client1);
std::unique_ptr<P2PProvider> provider2 = GetProvider("host2", "user2");
RecordingClient client2;
provider2->Start(&client2);
std::unique_ptr<P2PProvider> provider3 = GetProvider("host3", "user2");
RecordingClient client3;
provider3->Start(&client3);
std::unique_ptr<P2PProvider> provider4 = GetProvider("host4", "user1");
RecordingClient client4;
provider4->Start(&client4);
RunLoopUntilIdle();
// Verify that only devices with the same user connect together.
EXPECT_THAT(client1.device_changes,
testing::ElementsAre(RecordingClient::DeviceChange{
"host4", DeviceChangeType::NEW}));
EXPECT_THAT(client2.device_changes,
testing::ElementsAre(RecordingClient::DeviceChange{
"host3", DeviceChangeType::NEW}));
EXPECT_THAT(client3.device_changes,
testing::ElementsAre(RecordingClient::DeviceChange{
"host2", DeviceChangeType::NEW}));
EXPECT_THAT(client4.device_changes,
testing::ElementsAre(RecordingClient::DeviceChange{
"host1", DeviceChangeType::NEW}));
provider4.reset();
RunLoopUntilIdle();
EXPECT_THAT(
client1.device_changes,
testing::ElementsAre(
RecordingClient::DeviceChange{"host4", DeviceChangeType::NEW},
RecordingClient::DeviceChange{"host4", DeviceChangeType::DELETED}));
EXPECT_THAT(client2.device_changes,
testing::ElementsAre(RecordingClient::DeviceChange{
"host3", DeviceChangeType::NEW}));
EXPECT_THAT(client3.device_changes,
testing::ElementsAre(RecordingClient::DeviceChange{
"host2", DeviceChangeType::NEW}));
}
TEST_F(P2PProviderImplTest, TwoHosts_Messages) {
std::unique_ptr<P2PProvider> provider1 = GetProvider("host1");
RecordingClient client1;
provider1->Start(&client1);
std::unique_ptr<P2PProvider> provider2 = GetProvider("host2");
RecordingClient client2;
provider2->Start(&client2);
RunLoopUntilIdle();
EXPECT_TRUE(provider1->SendMessage("host2", "datagram"));
RunLoopUntilIdle();
EXPECT_THAT(client1.messages, testing::ElementsAre());
EXPECT_THAT(client2.messages, testing::ElementsAre(RecordingClient::Message{
"host1", "datagram"}));
}
} // namespace
} // namespace p2p_provider