Commit 58430a06 authored by Richard Knoll's avatar Richard Knoll Committed by Commit Bot

[Nearby] Implement SendPayloads

This starts sending the actual payloads via NearbyConnectionsManager. It
is now only missing the connection to the PayloadTracker.

Bug: 1085067
Change-Id: I9c9ee61264799c62df13417c908bdaba82d1de3b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2366746
Commit-Queue: Richard Knoll <knollr@chromium.org>
Reviewed-by: default avatarAlex Chau <alexchau@chromium.org>
Cr-Commit-Position: refs/heads/master@{#800350}
parent 54dddfc2
......@@ -69,7 +69,8 @@ void FakeNearbyConnectionsManager::Send(const std::string& endpoint_id,
PayloadPtr payload,
PayloadStatusListener* listener) {
DCHECK(!is_shutdown());
// TODO(alexchau): Implement.
if (send_payload_callback_)
send_payload_callback_.Run(std::move(payload));
}
void FakeNearbyConnectionsManager::RegisterPayloadStatusListener(
......
......@@ -11,6 +11,7 @@
#include <utility>
#include <vector>
#include "base/callback.h"
#include "chrome/browser/nearby_sharing/nearby_connections_manager.h"
#include "chrome/services/sharing/public/mojom/nearby_connections.mojom.h"
......@@ -80,6 +81,10 @@ class FakeNearbyConnectionsManager
connection_ = connection;
}
DataUsage connected_data_usage() const { return connected_data_usage_; }
void set_send_payload_callback(
base::RepeatingCallback<void(PayloadPtr payload)> callback) {
send_payload_callback_ = std::move(callback);
}
private:
IncomingConnectionListener* advertising_listener_ = nullptr;
......@@ -91,6 +96,7 @@ class FakeNearbyConnectionsManager
std::map<std::string, std::vector<uint8_t>> endpoint_auth_tokens_;
NearbyConnection* connection_ = nullptr;
DataUsage connected_data_usage_ = DataUsage::kUnknown;
base::RepeatingCallback<void(PayloadPtr payload)> send_payload_callback_;
};
#endif // CHROME_BROWSER_NEARBY_SHARING_FAKE_NEARBY_CONNECTIONS_MANAGER_H_
......@@ -1319,12 +1319,32 @@ NearbySharingService::StatusCodes NearbySharingServiceImpl::ReceivePayloads(
NearbySharingService::StatusCodes NearbySharingServiceImpl::SendPayloads(
const ShareTarget& share_target) {
// TODO(crbug.com/1085067) - Implement.
NS_LOG(VERBOSE) << __func__ << ": Preparing to send payloads to "
<< share_target.device_name;
ShareTargetInfo* info = GetShareTargetInfo(share_target);
if (!info || !info->connection()) {
NS_LOG(WARNING) << "Failed to send payload due to missing connection.";
return StatusCodes::kOutOfOrderApiCall;
}
OnOutgoingTransferUpdate(
share_target,
TransferMetadataBuilder()
.set_token(info->token())
.set_status(TransferMetadata::Status::kAwaitingRemoteAcceptance)
.build());
if (!info->endpoint_id()) {
OnOutgoingTransferUpdate(share_target,
TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kFailed)
.build());
info->connection()->Close();
NS_LOG(WARNING) << "Failed to send payload due to missing endpoint id.";
return StatusCodes::kOutOfOrderApiCall;
}
ReceiveConnectionResponse(share_target);
return StatusCodes::kOk;
}
......@@ -2014,6 +2034,140 @@ void NearbySharingServiceImpl::OnReceivedIntroduction(
std::move(four_digit_token)));
}
void NearbySharingServiceImpl::ReceiveConnectionResponse(
ShareTarget share_target) {
NS_LOG(VERBOSE) << __func__ << ": Receiving response frame from "
<< share_target.device_name;
ShareTargetInfo* info = GetShareTargetInfo(share_target);
DCHECK(info && info->connection());
info->frames_reader()->ReadFrame(
sharing::mojom::V1Frame::Tag::CONNECTION_RESPONSE,
base::BindOnce(&NearbySharingServiceImpl::OnReceiveConnectionResponse,
weak_ptr_factory_.GetWeakPtr(), std::move(share_target)),
kReadResponseFrameTimeout);
}
void NearbySharingServiceImpl::OnReceiveConnectionResponse(
ShareTarget share_target,
base::Optional<sharing::mojom::V1FramePtr> frame) {
OutgoingShareTargetInfo* info = GetOutgoingShareTargetInfo(share_target);
if (!info || !info->connection()) {
NS_LOG(WARNING) << __func__
<< ": Ignore received connection response, due to no "
"connection established.";
return;
}
NearbyConnection* connection = info->connection();
if (!frame) {
NS_LOG(WARNING)
<< __func__
<< ": Failed to read a response from the remote device. Disconnecting.";
OnOutgoingTransferUpdate(share_target,
TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kFailed)
.build());
connection->Close();
return;
}
mutual_acceptance_timeout_alarm_.Cancel();
NS_LOG(VERBOSE) << __func__
<< ": Successfully read the connection response frame.";
sharing::mojom::ConnectionResponseFramePtr response =
std::move((*frame)->get_connection_response());
switch (response->status) {
case sharing::mojom::ConnectionResponseFrame::Status::kAccept: {
info->frames_reader()->ReadFrame(base::BindOnce(
&NearbySharingServiceImpl::OnFrameRead,
weak_ptr_factory_.GetWeakPtr(), std::move(share_target)));
OnOutgoingTransferUpdate(
share_target, TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kInProgress)
.build());
// TODO(himanshujaju) - Implement payload tracker.
// PayloadTracker tracker = new PayloadTracker(shareTarget, callback);
NearbyConnectionsManager::PayloadStatusListener* tracker = nullptr;
for (auto& payload : info->ExtractTextPayloads()) {
nearby_connections_manager_->Send(*info->endpoint_id(),
std::move(payload), tracker);
}
for (auto& payload : info->ExtractFilePayloads()) {
nearby_connections_manager_->Send(*info->endpoint_id(),
std::move(payload), tracker);
}
NS_LOG(VERBOSE)
<< __func__
<< ": The connection was accepted. Payloads are now being sent.";
break;
}
case sharing::mojom::ConnectionResponseFrame::Status::kReject:
OnOutgoingTransferUpdate(
share_target, TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kRejected)
.build());
connection->Close();
NS_LOG(VERBOSE)
<< __func__
<< ": The connection was rejected. The connection has been closed.";
break;
case sharing::mojom::ConnectionResponseFrame::Status::kNotEnoughSpace:
OnOutgoingTransferUpdate(
share_target,
TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kNotEnoughSpace)
.build());
connection->Close();
NS_LOG(VERBOSE)
<< __func__
<< ": The connection was rejected because the remote device "
"does not have enough space for our attachments. The "
"connection has been closed.";
break;
case sharing::mojom::ConnectionResponseFrame::Status::
kUnsupportedAttachmentType:
OnOutgoingTransferUpdate(
share_target,
TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kUnsupportedAttachmentType)
.build());
connection->Close();
NS_LOG(VERBOSE)
<< __func__
<< ": The connection was rejected because the remote device "
"does not support the attachments we were sending. The "
"connection has been closed.";
break;
case sharing::mojom::ConnectionResponseFrame::Status::kTimedOut:
OnOutgoingTransferUpdate(
share_target, TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kTimedOut)
.build());
connection->Close();
NS_LOG(VERBOSE)
<< __func__
<< ": The connection was rejected because the remote device "
"timed out. The connection has been closed.";
break;
default:
OnOutgoingTransferUpdate(
share_target, TransferMetadataBuilder()
.set_status(TransferMetadata::Status::kFailed)
.build());
connection->Close();
NS_LOG(VERBOSE)
<< __func__
<< ": The connection failed. The connection has been closed.";
break;
}
}
void NearbySharingServiceImpl::OnStorageCheckCompleted(
ShareTarget share_target,
base::Optional<std::string> four_digit_token,
......
......@@ -215,6 +215,10 @@ class NearbySharingServiceImpl
void OnReceivedIntroduction(ShareTarget share_target,
base::Optional<std::string> four_digit_token,
base::Optional<sharing::mojom::V1FramePtr> frame);
void ReceiveConnectionResponse(ShareTarget share_target);
void OnReceiveConnectionResponse(
ShareTarget share_target,
base::Optional<sharing::mojom::V1FramePtr> frame);
void OnStorageCheckCompleted(ShareTarget share_target,
base::Optional<std::string> four_digit_token,
bool is_out_of_storage);
......
......@@ -237,6 +237,17 @@ sharing::mojom::FramePtr GetEmptyIntroductionFrame() {
return mojo_frame;
}
sharing::mojom::FramePtr GetConnectionResponseFrame(
sharing::mojom::ConnectionResponseFrame::Status status) {
sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New();
mojo_v1frame->set_connection_response(
sharing::mojom::ConnectionResponseFrame::New(status));
sharing::mojom::FramePtr mojo_frame = sharing::mojom::Frame::New();
mojo_frame->set_v1(std::move(mojo_v1frame));
return mojo_frame;
}
int64_t GetFreeSpaceInDownloadPath(Profile* profile) {
base::ScopedAllowBlockingForTesting allow_blocking;
base::FilePath file_path =
......@@ -495,6 +506,19 @@ class NearbySharingServiceImplTest : public testing::Test {
connection_.AppendReadableData(bytes);
}
void SendConnectionResponse(
sharing::mojom::ConnectionResponseFrame::Status status) {
std::string intro = "connection_result_frame";
std::vector<uint8_t> bytes(intro.begin(), intro.end());
EXPECT_CALL(mock_decoder_, DecodeFrame(testing::Eq(bytes), testing::_))
.WillOnce(testing::Invoke(
[=](const std::vector<uint8_t>& data,
MockNearbySharingDecoder::DecodeFrameCallback callback) {
std::move(callback).Run(GetConnectionResponseFrame(status));
}));
connection_.AppendReadableData(bytes);
}
ShareTarget SetUpIncomingConnection(
NiceMock<MockTransferUpdateCallback>& callback) {
fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
......@@ -607,6 +631,12 @@ class NearbySharingServiceImplTest : public testing::Test {
EXPECT_EQ(status, frame.v1().connection_response().status());
}
void ExpectIntroductionFrame() {
sharing::nearby::Frame frame = GetWrittenFrame();
ASSERT_TRUE(frame.has_v1());
ASSERT_TRUE(frame.v1().has_introduction());
}
void ExpectTransferUpdates(
MockTransferUpdateCallback& transfer_callback,
const ShareTarget& target,
......@@ -711,6 +741,25 @@ class NearbySharingServiceImplInvalidSendTest
: public NearbySharingServiceImplTest,
public testing::WithParamInterface<InvalidSendSurfaceTestData> {};
using ResponseFrameStatus = sharing::mojom::ConnectionResponseFrame::Status;
struct SendFailureTestData {
ResponseFrameStatus response_status;
TransferMetadata::Status expected_status;
} kSendFailureTestData[] = {
{ResponseFrameStatus::kReject, TransferMetadata::Status::kRejected},
{ResponseFrameStatus::kNotEnoughSpace,
TransferMetadata::Status::kNotEnoughSpace},
{ResponseFrameStatus::kUnsupportedAttachmentType,
TransferMetadata::Status::kUnsupportedAttachmentType},
{ResponseFrameStatus::kTimedOut, TransferMetadata::Status::kTimedOut},
{ResponseFrameStatus::kUnknown, TransferMetadata::Status::kFailed},
};
class NearbySharingServiceImplSendFailureTest
: public NearbySharingServiceImplTest,
public testing::WithParamInterface<SendFailureTestData> {};
} // namespace
TEST_F(NearbySharingServiceImplTest, AddsNearbyProcessObserver) {
......@@ -2359,22 +2408,96 @@ TEST_F(NearbySharingServiceImplTest, SendText_UnableToVerifyKey) {
service_->UnregisterSendSurface(&transfer_callback, &discovery_callback);
}
TEST_P(NearbySharingServiceImplSendFailureTest, SendText_RemoteFailure) {
MockTransferUpdateCallback transfer_callback;
MockShareTargetDiscoveredCallback discovery_callback;
ShareTarget target =
SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
base::RunLoop introduction_run_loop;
ExpectTransferUpdates(transfer_callback, target,
{TransferMetadata::Status::kConnecting,
TransferMetadata::Status::kAwaitingLocalConfirmation,
TransferMetadata::Status::kAwaitingRemoteAcceptance},
introduction_run_loop.QuitClosure());
EXPECT_EQ(NearbySharingServiceImpl::StatusCodes::kOk,
service_->SendText(target, kTextPayload));
introduction_run_loop.Run();
// Verify data sent to the remote device so far.
ExpectPairedKeyEncryptionFrame();
ExpectPairedKeyResultFrame();
ExpectIntroductionFrame();
// We're now waiting for the remote device to respond with the accept result.
base::RunLoop reject_run_loop;
ExpectTransferUpdates(
transfer_callback, target,
{GetParam().expected_status,
// TODO(crbug.com/1085067): Filter updates after the first final one.
TransferMetadata::Status::kAwaitingRemoteAcceptanceFailed},
reject_run_loop.QuitClosure());
// Cancel the transfer by rejecting it.
SendConnectionResponse(GetParam().response_status);
reject_run_loop.Run();
EXPECT_TRUE(connection_.IsClosed());
service_->UnregisterSendSurface(&transfer_callback, &discovery_callback);
}
INSTANTIATE_TEST_SUITE_P(NearbySharingServiceImplSendFailureTest,
NearbySharingServiceImplSendFailureTest,
testing::ValuesIn(kSendFailureTestData));
TEST_F(NearbySharingServiceImplTest, SendText_Success) {
MockTransferUpdateCallback transfer_callback;
MockShareTargetDiscoveredCallback discovery_callback;
ShareTarget target =
SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
base::RunLoop run_loop;
base::RunLoop introduction_run_loop;
ExpectTransferUpdates(transfer_callback, target,
{TransferMetadata::Status::kConnecting,
TransferMetadata::Status::kAwaitingLocalConfirmation,
TransferMetadata::Status::kAwaitingRemoteAcceptance},
run_loop.QuitClosure());
introduction_run_loop.QuitClosure());
EXPECT_EQ(NearbySharingServiceImpl::StatusCodes::kOk,
service_->SendText(target, kTextPayload));
run_loop.Run();
introduction_run_loop.Run();
// Verify data sent to the remote device so far.
ExpectPairedKeyEncryptionFrame();
ExpectPairedKeyResultFrame();
ExpectIntroductionFrame();
// Expect the text payload to be sent in the end.
base::RunLoop payload_run_loop;
fake_nearby_connections_manager_->set_send_payload_callback(
base::BindLambdaForTesting(
[&](NearbyConnectionsManager::PayloadPtr payload) {
ASSERT_TRUE(payload->content->is_bytes());
std::vector<uint8_t> bytes = payload->content->get_bytes()->bytes;
std::string sent = std::string(bytes.begin(), bytes.end());
EXPECT_EQ(kTextPayload, sent);
payload_run_loop.Quit();
}));
// We're now waiting for the remote device to respond with the accept result.
base::RunLoop accept_run_loop;
ExpectTransferUpdates(transfer_callback, target,
{TransferMetadata::Status::kInProgress},
accept_run_loop.QuitClosure());
// Kick off send process by accepting the transfer from the remote device.
SendConnectionResponse(
sharing::mojom::ConnectionResponseFrame::Status::kAccept);
accept_run_loop.Run();
payload_run_loop.Run();
service_->UnregisterSendSurface(&transfer_callback, &discovery_callback);
}
......
......@@ -13,3 +13,13 @@ OutgoingShareTargetInfo& OutgoingShareTargetInfo::operator=(
OutgoingShareTargetInfo&&) = default;
OutgoingShareTargetInfo::~OutgoingShareTargetInfo() = default;
std::vector<OutgoingShareTargetInfo::PayloadPtr>
OutgoingShareTargetInfo::ExtractTextPayloads() {
return std::move(text_payloads_);
}
std::vector<OutgoingShareTargetInfo::PayloadPtr>
OutgoingShareTargetInfo::ExtractFilePayloads() {
return std::move(file_payloads_);
}
......@@ -46,6 +46,9 @@ class OutgoingShareTargetInfo : public ShareTargetInfo {
file_payloads_ = std::move(payloads);
}
std::vector<PayloadPtr> ExtractTextPayloads();
std::vector<PayloadPtr> ExtractFilePayloads();
private:
base::Optional<std::string> obfuscated_gaia_id_;
std::vector<PayloadPtr> text_payloads_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment