Files
nearby/sharing/outgoing_targets_manager_test.cc
2026-05-26 18:13:09 -07:00

819 lines
32 KiB
C++

// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sharing/outgoing_targets_manager.h"
#include <optional>
#include <string>
#include <vector>
#include "location/nearby/sharing/lib/analytics/analytics_recorder_impl.h"
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "internal/test/fake_clock.h"
#include "internal/test/fake_device_info.h"
#include "internal/test/fake_task_runner.h"
#include "sharing/attachment_container.h"
#include "sharing/certificates/nearby_share_decrypted_public_certificate.h"
#include "sharing/certificates/test_util.h"
#include "sharing/fake_nearby_connections_manager.h"
#include "sharing/nearby_connection_impl.h"
#include "sharing/nearby_connections_types.h"
#include "sharing/outgoing_share_session.h"
#include "sharing/share_target.h"
#include "sharing/text_attachment.h"
#include "sharing/transfer_metadata.h"
namespace nearby::sharing {
namespace {
using ::absl::Seconds;
using ::testing::ElementsAre;
using ::testing::InSequence;
using ::testing::SizeIs;
class OutgoingTargetsManagerTest : public ::testing::Test {
protected:
OutgoingTargetsManagerTest()
: service_thread_(&clock_, /*count=*/1),
analytics_recorder_(/*vendor_id=*/0,
/*event_logger=*/nullptr),
outgoing_targets_manager_(
&clock_, &service_thread_, &connections_manager_,
&analytics_recorder_,
share_target_discovered_callback_.AsStdFunction(),
share_target_updated_callback_.AsStdFunction(),
share_target_lost_callback_.AsStdFunction(),
transfer_update_callback_.AsStdFunction()) {}
FakeClock clock_;
FakeTaskRunner service_thread_;
FakeNearbyConnectionsManager connections_manager_;
analytics::AnalyticsRecorderImpl analytics_recorder_;
testing::MockFunction<void(const ShareTarget&)>
share_target_discovered_callback_;
testing::MockFunction<void(const ShareTarget&)>
share_target_updated_callback_;
testing::MockFunction<void(const ShareTarget&)> share_target_lost_callback_;
testing::MockFunction<void(OutgoingShareSession&, const TransferMetadata&)>
transfer_update_callback_;
FakeDeviceInfo device_info_;
OutgoingTargetsManager outgoing_targets_manager_;
};
TEST_F(OutgoingTargetsManagerTest, onShareTargetDiscoveredNewTarget) {
constexpr int kShareTargetId = 1234;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call).Times(0);
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
OutgoingShareSession* session =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
EXPECT_NE(session, nullptr);
EXPECT_EQ(session->share_target(), target);
EXPECT_EQ(session->endpoint_id(), kEndpointId);
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, target);
});
EXPECT_TRUE(has_targets);
}
TEST_F(OutgoingTargetsManagerTest, onShareTargetLost) {
constexpr int kShareTargetId = 1234;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
ShareTarget disabled_target = target;
disabled_target.receive_disabled = true;
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, disabled_target);
});
EXPECT_CALL(share_target_lost_callback_, Call).Times(1);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
EXPECT_NE(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
outgoing_targets_manager_.OnShareTargetLost(std::string(kEndpointId),
Seconds(10));
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, disabled_target);
});
EXPECT_TRUE(has_targets);
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
// Retention timer expired.
clock_.FastForward(Seconds(10));
service_thread_.Sync();
has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) { has_targets = true; });
EXPECT_FALSE(has_targets);
}
TEST_F(OutgoingTargetsManagerTest, onShareTargetLostConnectedNotClosed) {
constexpr int kShareTargetId = 1234;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call).Times(0);
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
OutgoingShareSession* session =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
NearbyConnectionImpl connection(device_info_);
session->OnConnectResult(&connection, Status::kSuccess);
ASSERT_TRUE(session->IsConnected());
outgoing_targets_manager_.OnShareTargetLost(std::string(kEndpointId),
Seconds(10));
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, target);
});
EXPECT_TRUE(has_targets);
session = outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
EXPECT_TRUE(session->IsConnected());
// Retention timer expired.
clock_.FastForward(Seconds(10));
service_thread_.Sync();
has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, target);
});
EXPECT_TRUE(has_targets);
session = outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
EXPECT_TRUE(session->IsConnected());
}
TEST_F(OutgoingTargetsManagerTest, onShareTargetLostConnectingNotClosed) {
constexpr int kShareTargetId = 1234;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call).Times(0);
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
OutgoingShareSession* session =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
// InitiateSendAttachments is called when session starts connecting.
session->InitiateSendAttachments(
AttachmentContainer::Builder()
.AddTextAttachment(TextAttachment(
nearby::sharing::service::proto::TextMetadata::ADDRESS,
"A bit of text body 2", "Some text title 2", "text/plain"))
.Build());
outgoing_targets_manager_.OnShareTargetLost(std::string(kEndpointId),
Seconds(10));
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, target);
});
EXPECT_TRUE(has_targets);
session = outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
// Retention timer expired.
clock_.FastForward(Seconds(10));
service_thread_.Sync();
has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, target);
});
EXPECT_TRUE(has_targets);
session = outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
}
TEST_F(OutgoingTargetsManagerTest, onShareTargeDedupByEndpointIdNoLoss) {
constexpr int kShareTargetId = 1234;
constexpr int kShareTargetId2 = kShareTargetId + 100;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
target.device_name = "device_name";
ShareTarget target2 = target;
target2.id = kShareTargetId2;
target2.device_name = "device_name_2";
ShareTarget merged_target = target;
merged_target.device_name = "device_name_2";
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, merged_target);
});
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
EXPECT_NE(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
outgoing_targets_manager_.OnShareTargetDiscovered(
target2, kEndpointId, /*certificate=*/std::nullopt);
// Make sure share session is not created for new target id.
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId2),
nullptr);
// Make sure share session is created for original target id.
OutgoingShareSession* session2 =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
EXPECT_NE(session2, nullptr);
EXPECT_EQ(session2->share_target(), merged_target);
EXPECT_EQ(session2->endpoint_id(), kEndpointId);
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, merged_target);
});
EXPECT_TRUE(has_targets);
}
TEST_F(OutgoingTargetsManagerTest,
onShareTargeDedupByEndpointIdNoLossConnected) {
constexpr int kShareTargetId = 1234;
constexpr int kShareTargetId2 = kShareTargetId + 100;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
target.device_name = "device_name";
ShareTarget target2 = target;
target2.id = kShareTargetId2;
target2.device_name = "device_name_2";
ShareTarget merged_target = target;
merged_target.device_name = "device_name_2";
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, merged_target);
});
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
OutgoingShareSession* session =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
NearbyConnectionImpl connection(device_info_);
session->OnConnectResult(&connection, Status::kSuccess);
ASSERT_TRUE(session->IsConnected());
outgoing_targets_manager_.OnShareTargetDiscovered(
target2, kEndpointId, /*certificate=*/std::nullopt);
// Make sure share session is not created for new target id.
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId2),
nullptr);
// Make sure share session is created for original target id.
OutgoingShareSession* session2 =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
EXPECT_NE(session2, nullptr);
EXPECT_EQ(session2->share_target(), merged_target);
// Make sure endpoint id is not updated since session is already connected.
EXPECT_EQ(session2->endpoint_id(), kEndpointId);
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, merged_target);
});
EXPECT_TRUE(has_targets);
}
TEST_F(OutgoingTargetsManagerTest, onShareTargeDedupByDeviceIdNoLossConnected) {
constexpr int kShareTargetId = 1234;
constexpr int kShareTargetId2 = kShareTargetId + 100;
constexpr absl::string_view kEndpointId1 = "endpoint_id";
constexpr absl::string_view kEndpointId2 = "endpoint_id_2";
ShareTarget target;
target.id = kShareTargetId;
target.device_id = "device_id";
target.device_name = "device_name";
ShareTarget target2 = target;
target2.id = kShareTargetId2;
target2.device_name = "device_name_2";
ShareTarget merged_target = target;
merged_target.device_name = "device_name_2";
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, merged_target);
});
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId1, /*certificate=*/std::nullopt);
OutgoingShareSession* session =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
NearbyConnectionImpl connection(device_info_);
session->OnConnectResult(&connection, Status::kSuccess);
ASSERT_TRUE(session->IsConnected());
// Discover a new target with the same device id, but different endpoint id.
outgoing_targets_manager_.OnShareTargetDiscovered(
target2, kEndpointId2, /*certificate=*/std::nullopt);
// Make sure share session is not created for new target id.
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId2),
nullptr);
// Make sure share session is created for original target id.
OutgoingShareSession* session2 =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
EXPECT_NE(session2, nullptr);
EXPECT_EQ(session2->share_target(), merged_target);
// Make sure endpoint id is not updated since session is already connected.
EXPECT_EQ(session2->endpoint_id(), kEndpointId1);
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, merged_target);
});
EXPECT_TRUE(has_targets);
}
TEST_F(OutgoingTargetsManagerTest, onShareTargeDedupByDeviceIdNoLoss) {
constexpr int kShareTargetId = 1234;
constexpr int kShareTargetId2 = kShareTargetId + 100;
constexpr absl::string_view kEndpointId1 = "endpoint_id";
constexpr absl::string_view kEndpointId2 = "endpoint_id_2";
ShareTarget target;
target.id = kShareTargetId;
target.device_id = "device_id";
target.device_name = "device_name";
ShareTarget target2 = target;
target2.id = kShareTargetId2;
target2.device_name = "device_name_2";
ShareTarget merged_target = target;
merged_target.device_name = "device_name_2";
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, merged_target);
});
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId1, /*certificate=*/std::nullopt);
EXPECT_NE(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
// Discover a new target with the same device id, but different endpoint id.
outgoing_targets_manager_.OnShareTargetDiscovered(
target2, kEndpointId2, /*certificate=*/std::nullopt);
// Make sure share session is not created for new target id.
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId2),
nullptr);
// Make sure share session is created for original target id.
OutgoingShareSession* session2 =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
EXPECT_NE(session2, nullptr);
EXPECT_EQ(session2->share_target(), merged_target);
EXPECT_EQ(session2->endpoint_id(), kEndpointId2);
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, merged_target);
});
EXPECT_TRUE(has_targets);
}
TEST_F(OutgoingTargetsManagerTest, onShareTargeDedupByEndpointId) {
constexpr int kShareTargetId = 1234;
constexpr int kShareTargetId2 = kShareTargetId + 100;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
target.device_name = "device_name";
ShareTarget disabled_target = target;
disabled_target.receive_disabled = true;
ShareTarget target2 = target;
target2.id = kShareTargetId2;
target2.device_name = "device_name_2";
ShareTarget merged_target = target;
merged_target.device_name = "device_name_2";
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, disabled_target);
})
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, merged_target);
});
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
EXPECT_NE(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
outgoing_targets_manager_.OnShareTargetLost(std::string(kEndpointId),
Seconds(10));
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
outgoing_targets_manager_.OnShareTargetDiscovered(
target2, kEndpointId, /*certificate=*/std::nullopt);
// Make sure share session is not created for new target id.
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId2),
nullptr);
// Make sure share session is created for original target id.
OutgoingShareSession* session2 =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
EXPECT_NE(session2, nullptr);
EXPECT_EQ(session2->share_target(), merged_target);
EXPECT_EQ(session2->endpoint_id(), kEndpointId);
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, merged_target);
});
EXPECT_TRUE(has_targets);
// Retention timer expired.
clock_.FastForward(Seconds(10));
service_thread_.Sync();
// Make sure share session is not removed after retention timer expired.
session2 = outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
EXPECT_NE(session2, nullptr);
EXPECT_EQ(session2->share_target(), merged_target);
EXPECT_EQ(session2->endpoint_id(), kEndpointId);
has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, merged_target);
});
EXPECT_TRUE(has_targets);
}
TEST_F(OutgoingTargetsManagerTest, onShareTargeDedupByDeviceId) {
constexpr int kShareTargetId = 1234;
constexpr int kShareTargetId2 = kShareTargetId + 100;
constexpr absl::string_view kEndpointId1 = "endpoint_id";
constexpr absl::string_view kEndpointId2 = "endpoint_id_2";
ShareTarget target;
target.id = kShareTargetId;
target.device_id = "device_id";
target.device_name = "device_name";
ShareTarget disabled_target = target;
disabled_target.receive_disabled = true;
ShareTarget target2 = target;
target2.id = kShareTargetId2;
target2.device_name = "device_name_2";
ShareTarget merged_target = target;
merged_target.device_name = "device_name_2";
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, disabled_target);
})
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, merged_target);
});
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId1, /*certificate=*/std::nullopt);
EXPECT_NE(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
outgoing_targets_manager_.OnShareTargetLost(std::string(kEndpointId1),
Seconds(10));
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
// Discover a new target with the same device id, but different endpoint id.
outgoing_targets_manager_.OnShareTargetDiscovered(
target2, kEndpointId2, /*certificate=*/std::nullopt);
// Make sure share session is not created for new target id.
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId2),
nullptr);
// Make sure share session is created for original target id.
OutgoingShareSession* session2 =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
EXPECT_NE(session2, nullptr);
EXPECT_EQ(session2->share_target(), merged_target);
EXPECT_EQ(session2->endpoint_id(), kEndpointId2);
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, merged_target);
});
EXPECT_TRUE(has_targets);
// Retention timer expired.
clock_.FastForward(Seconds(10));
service_thread_.Sync();
// Make sure share session is not removed after retention timer expired.
session2 = outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
EXPECT_NE(session2, nullptr);
EXPECT_EQ(session2->share_target(), merged_target);
EXPECT_EQ(session2->endpoint_id(), kEndpointId2);
has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, merged_target);
});
EXPECT_TRUE(has_targets);
}
TEST_F(OutgoingTargetsManagerTest, onShareTargeNoDedupOnEmptyDeviceId) {
constexpr int kShareTargetId = 1234;
constexpr int kShareTargetId2 = kShareTargetId + 100;
constexpr absl::string_view kEndpointId1 = "endpoint_id";
constexpr absl::string_view kEndpointId2 = "endpoint_id_2";
ShareTarget target;
target.id = kShareTargetId;
target.device_id = "device_id";
target.device_name = "device_name";
ShareTarget disabled_target = target;
disabled_target.receive_disabled = true;
ShareTarget target2 = target;
target2.id = kShareTargetId2;
target2.device_name = "device_name_2";
target2.device_id = "";
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, target);
});
EXPECT_CALL(share_target_updated_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, disabled_target);
});
EXPECT_CALL(share_target_discovered_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, target2);
});
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId1, /*certificate=*/std::nullopt);
EXPECT_NE(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
outgoing_targets_manager_.OnShareTargetLost(std::string(kEndpointId1),
Seconds(10));
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
// Discover a new target with the same device id, but different endpoint id.
outgoing_targets_manager_.OnShareTargetDiscovered(
target2, kEndpointId2, /*certificate=*/std::nullopt);
// Make sure share session is not created for new target id.
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
// Make sure share session is created for original target id.
OutgoingShareSession* session2 =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId2);
EXPECT_NE(session2, nullptr);
EXPECT_EQ(session2->share_target(), target2);
EXPECT_EQ(session2->endpoint_id(), kEndpointId2);
std::vector<ShareTarget> share_targets;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
share_targets.push_back(share_target);
});
EXPECT_THAT(share_targets, SizeIs(2));
EXPECT_THAT(share_targets, ElementsAre(disabled_target, target2));
}
TEST_F(OutgoingTargetsManagerTest, CleanupClosesConnectedSessions) {
constexpr int kShareTargetId = 1234;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
ShareTarget disabled_target = target;
disabled_target.receive_disabled = true;
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call).Times(0);
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call)
.WillOnce([&](OutgoingShareSession& session,
const TransferMetadata& metadata) {
EXPECT_EQ(session.endpoint_id(), kEndpointId);
EXPECT_EQ(session.share_target(), target);
EXPECT_EQ(metadata.status(), TransferMetadata::Status::kFailed);
});
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
OutgoingShareSession* session =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
NearbyConnectionImpl connection(device_info_);
session->OnConnectResult(&connection, Status::kSuccess);
ASSERT_TRUE(session->IsConnected());
outgoing_targets_manager_.Cleanup();
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
});
EXPECT_FALSE(has_targets);
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
}
TEST_F(OutgoingTargetsManagerTest, AllTargetsLostClosesConnectedSessions) {
constexpr int kShareTargetId = 1234;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
ShareTarget disabled_target = target;
disabled_target.receive_disabled = true;
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call)
.WillOnce([&](const ShareTarget& share_target) {
EXPECT_EQ(share_target, disabled_target);
});
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
EXPECT_NE(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
outgoing_targets_manager_.AllTargetsLost(Seconds(10));
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, disabled_target);
});
EXPECT_TRUE(has_targets);
EXPECT_EQ(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
}
TEST_F(OutgoingTargetsManagerTest, AllTargetsLostConnectedSessionsNotClosed) {
constexpr int kShareTargetId = 1234;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
{
InSequence s;
EXPECT_CALL(share_target_discovered_callback_, Call).Times(1);
EXPECT_CALL(share_target_updated_callback_, Call).Times(0);
EXPECT_CALL(share_target_lost_callback_, Call).Times(0);
EXPECT_CALL(transfer_update_callback_, Call).Times(0);
}
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
OutgoingShareSession* session =
outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId);
ASSERT_NE(session, nullptr);
NearbyConnectionImpl connection(device_info_);
session->OnConnectResult(&connection, Status::kSuccess);
ASSERT_TRUE(session->IsConnected());
outgoing_targets_manager_.AllTargetsLost(Seconds(10));
bool has_targets = false;
outgoing_targets_manager_.ForEachShareTarget(
[&](const ShareTarget& share_target) {
has_targets = true;
EXPECT_EQ(share_target, target);
});
EXPECT_TRUE(has_targets);
EXPECT_NE(outgoing_targets_manager_.GetOutgoingShareSession(kShareTargetId),
nullptr);
}
TEST_F(OutgoingTargetsManagerTest, GetBindingIds_NonExistentTarget) {
EXPECT_TRUE(outgoing_targets_manager_.GetBindingIds(1234).empty());
}
TEST_F(OutgoingTargetsManagerTest, GetBindingIds_NoCertificate) {
constexpr int kShareTargetId = 1234;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
outgoing_targets_manager_.OnShareTargetDiscovered(
target, kEndpointId, /*certificate=*/std::nullopt);
EXPECT_TRUE(outgoing_targets_manager_.GetBindingIds(kShareTargetId).empty());
}
TEST_F(OutgoingTargetsManagerTest, GetBindingIds_WithCertificate) {
constexpr int kShareTargetId = 1234;
constexpr absl::string_view kEndpointId = "endpoint_id";
ShareTarget target;
target.id = kShareTargetId;
NearbyShareDecryptedPublicCertificate cert =
GetNearbyShareTestDecryptedPublicCertificate();
outgoing_targets_manager_.OnShareTargetDiscovered(target, kEndpointId, cert);
std::vector<std::string> binding_ids =
outgoing_targets_manager_.GetBindingIds(kShareTargetId);
EXPECT_THAT(binding_ids, ElementsAre(cert.binding_id()));
}
} // namespace
} // namespace nearby::sharing