Files
nearby/connections/implementation/offline_frames_test.cc
T
Johnson Lu ee9266b175 Implement Dynamic Role Switch
Implement dynamic role switch in bwu manager. When NC receive BWU request, it will check if it should switch role based on the device's capability.

PiperOrigin-RevId: 755703443
2025-05-06 23:38:16 -07:00

692 lines
22 KiB
C++

// Copyright 2020 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 "connections/implementation/offline_frames.h"
#include <array>
#include <memory>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "connections/connection_options.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/byte_array.h"
namespace nearby {
namespace connections {
namespace parser {
namespace {
using ::location::nearby::connections::OfflineFrame;
using ::location::nearby::connections::OsInfo;
using ::location::nearby::connections::PayloadTransferFrame;
using ::location::nearby::connections::V1Frame;
using Medium = ::location::nearby::proto::connections::Medium;
using ::location::nearby::connections::MediumRole;
using ::protobuf_matchers::EqualsProto;
constexpr absl::string_view kEndpointId{"ABC"};
constexpr absl::string_view kEndpointName{"XYZ"};
constexpr int kNonce = 1234;
constexpr bool kSupports5ghz = true;
constexpr absl::string_view kBssid{"FF:FF:FF:FF:FF:FF"};
constexpr int kApFrequency = 2412;
constexpr absl::string_view kIp4Bytes = {"8xqT"};
constexpr std::array<Medium, 11> kMediums = {
Medium::MDNS, Medium::BLUETOOTH, Medium::WIFI_HOTSPOT,
Medium::BLE, Medium::WIFI_LAN, Medium::WIFI_AWARE,
Medium::NFC, Medium::WIFI_DIRECT, Medium::WEB_RTC,
Medium::USB, Medium::AWDL,
};
constexpr int kKeepAliveIntervalMillis = 1000;
constexpr int kKeepAliveTimeoutMillis = 5000;
TEST(OfflineFramesTest, CanParseMessageFromBytes) {
OfflineFrame tx_message;
{
tx_message.set_version(OfflineFrame::V1);
auto* v1_frame = tx_message.mutable_v1();
auto* sub_frame = v1_frame->mutable_connection_request();
v1_frame->set_type(V1Frame::CONNECTION_REQUEST);
// OSS matchers don't like implicitly comparing string_views to strings.
sub_frame->set_endpoint_id(std::string(kEndpointId));
sub_frame->set_endpoint_name(std::string(kEndpointName));
sub_frame->set_endpoint_info(std::string(kEndpointName));
sub_frame->set_nonce(kNonce);
sub_frame->set_keep_alive_interval_millis(kKeepAliveIntervalMillis);
sub_frame->set_keep_alive_timeout_millis(kKeepAliveTimeoutMillis);
auto* medium_metadata = sub_frame->mutable_medium_metadata();
medium_metadata->set_supports_5_ghz(kSupports5ghz);
medium_metadata->set_bssid(kBssid);
for (auto& medium : kMediums) {
sub_frame->add_mediums(MediumToConnectionRequestMedium(medium));
}
}
auto serialized_bytes = ByteArray(tx_message.SerializeAsString());
auto ret_value = FromBytes(serialized_bytes);
ASSERT_TRUE(ret_value.ok());
const auto& rx_message = ret_value.result();
EXPECT_THAT(rx_message, EqualsProto(tx_message));
EXPECT_EQ(GetFrameType(rx_message), V1Frame::CONNECTION_REQUEST);
EXPECT_EQ(
ConnectionRequestMediumsToMediums(rx_message.v1().connection_request()),
std::vector(kMediums.begin(), kMediums.end()));
}
TEST(OfflineFramesTest, CanGenerateLegacyConnectionRequest) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: CONNECTION_REQUEST
connection_request: <
endpoint_id: "ABC"
endpoint_name: "XYZ"
endpoint_info: "XYZ"
nonce: 1234
medium_metadata: <
supports_5_ghz: true
bssid: "FF:FF:FF:FF:FF:FF"
ip_address: "8xqT"
ap_frequency: 2412
>
mediums: MDNS
mediums: BLUETOOTH
mediums: WIFI_HOTSPOT
mediums: BLE
mediums: WIFI_LAN
mediums: WIFI_AWARE
mediums: NFC
mediums: WIFI_DIRECT
mediums: WEB_RTC
mediums: USB
mediums: AWDL
keep_alive_interval_millis: 1000
keep_alive_timeout_millis: 5000
>
>)pb";
ConnectionInfo connection_info{std::string(kEndpointId),
ByteArray{std::string(kEndpointName)},
kNonce,
kSupports5ghz,
std::string(kBssid),
kApFrequency,
std::string(kIp4Bytes),
std::vector<Medium, std::allocator<Medium>>(
kMediums.begin(), kMediums.end()),
kKeepAliveIntervalMillis,
kKeepAliveTimeoutMillis};
ByteArray bytes = ForConnectionRequestConnections({}, connection_info);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateConnectionsConnectionRequest) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
config_package_nearby::nearby_connections_feature::
kEnableDynamicRoleSwitch,
true);
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: CONNECTION_REQUEST
connection_request: <
endpoint_id: "ABC"
endpoint_name: "XYZ"
endpoint_info: "XYZ"
nonce: 1234
medium_metadata: <
supports_5_ghz: true
bssid: "FF:FF:FF:FF:FF:FF"
ip_address: "8xqT"
ap_frequency: 2412
medium_role: < support_wifi_hotspot_client: true >
>
mediums: MDNS
mediums: BLUETOOTH
mediums: WIFI_HOTSPOT
mediums: BLE
mediums: WIFI_LAN
mediums: WIFI_AWARE
mediums: NFC
mediums: WIFI_DIRECT
mediums: WEB_RTC
mediums: USB
mediums: AWDL
keep_alive_interval_millis: 1000
keep_alive_timeout_millis: 5000
connections_device {
endpoint_id: "ABC"
endpoint_type: CONNECTIONS_ENDPOINT
endpoint_info: "XYZ"
}
>
>)pb";
location::nearby::connections::ConnectionsDevice connections_device;
connections_device.set_endpoint_id("ABC");
connections_device.set_endpoint_type(
location::nearby::connections::CONNECTIONS_ENDPOINT);
connections_device.set_endpoint_info("XYZ");
MediumRole medium_role;
medium_role.set_support_wifi_hotspot_client(true);
ConnectionInfo connection_info{std::string(kEndpointId),
ByteArray{std::string(kEndpointName)},
kNonce,
kSupports5ghz,
std::string(kBssid),
kApFrequency,
std::string(kIp4Bytes),
std::vector<Medium, std::allocator<Medium>>(
kMediums.begin(), kMediums.end()),
kKeepAliveIntervalMillis,
kKeepAliveTimeoutMillis,
medium_role};
ByteArray bytes =
ForConnectionRequestConnections(connections_device, connection_info);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGeneratePresenceConnectionRequest) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: CONNECTION_REQUEST
connection_request: <
endpoint_id: "ABC"
endpoint_name: "XYZ"
endpoint_info: "XYZ"
nonce: 1234
medium_metadata: <
supports_5_ghz: true
bssid: "FF:FF:FF:FF:FF:FF"
ip_address: "8xqT"
ap_frequency: 2412
>
mediums: MDNS
mediums: BLUETOOTH
mediums: WIFI_HOTSPOT
mediums: BLE
mediums: WIFI_LAN
mediums: WIFI_AWARE
mediums: NFC
mediums: WIFI_DIRECT
mediums: WEB_RTC
mediums: USB
mediums: AWDL
keep_alive_interval_millis: 1000
keep_alive_timeout_millis: 5000
presence_device {
endpoint_id: "ABC"
endpoint_type: PRESENCE_ENDPOINT
device_name: "TEST DEVICE"
}
>
>)pb";
ConnectionInfo connection_info{std::string(kEndpointId),
ByteArray{std::string(kEndpointName)},
kNonce,
kSupports5ghz,
std::string(kBssid),
kApFrequency,
std::string(kIp4Bytes),
std::vector<Medium, std::allocator<Medium>>(
kMediums.begin(), kMediums.end()),
kKeepAliveIntervalMillis,
kKeepAliveTimeoutMillis};
location::nearby::connections::PresenceDevice presence_device;
presence_device.set_endpoint_id("ABC");
presence_device.set_endpoint_type(
location::nearby::connections::PRESENCE_ENDPOINT);
presence_device.set_device_name("TEST DEVICE");
ByteArray bytes =
ForConnectionRequestPresence(presence_device, connection_info);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateConnectionResponse) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: CONNECTION_RESPONSE
connection_response: <
status: 1
response: REJECT
os_info { type: LINUX }
multiplex_socket_bitmask: 0x01
safe_to_disconnect_version: 5
>
>)pb";
OsInfo os_info;
os_info.set_type(OsInfo::LINUX);
NearbyFlags::GetInstance().OverrideInt64FlagValue(
config_package_nearby::nearby_connections_feature::
kSafeToDisconnectVersion,
5);
ByteArray bytes =
ForConnectionResponse(1, os_info, /*multiplex_socket_bitmask=*/0x01);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateControlPayloadTransfer) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::ControlMessage control;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::BYTES);
header.set_total_size(1024);
control.set_event(PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED);
control.set_offset(150);
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: PAYLOAD_TRANSFER
payload_transfer: <
packet_type: CONTROL,
payload_header: < type: BYTES id: 12345 total_size: 1024 >
control_message: < event: PAYLOAD_CANCELED offset: 150 >
>
>)pb";
ByteArray bytes = ForControlPayloadTransfer(header, control);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateDataPayloadTransfer) {
PayloadTransferFrame::PayloadHeader header;
PayloadTransferFrame::PayloadChunk chunk;
header.set_id(12345);
header.set_type(PayloadTransferFrame::PayloadHeader::BYTES);
header.set_total_size(1024);
chunk.set_body("payload data");
chunk.set_offset(150);
chunk.set_flags(1);
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: PAYLOAD_TRANSFER
payload_transfer: <
packet_type: DATA,
payload_header: < type: BYTES id: 12345 total_size: 1024 >
payload_chunk: < flags: 1 offset: 150 body: "payload data" >
>
>)pb";
ByteArray bytes = ForDataPayloadTransfer(header, chunk);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGeneratePayloadAckPayloadTransfer) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: PAYLOAD_TRANSFER
payload_transfer: <
packet_type: PAYLOAD_ACK,
payload_header: < id: 12345 total_size: -1 >
>
>)pb";
ByteArray bytes = ForPayloadAckPayloadTransfer(12345);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuWifiHotspotPathAvailable) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: <
event_type: UPGRADE_PATH_AVAILABLE
upgrade_path_info: <
medium: WIFI_HOTSPOT
wifi_hotspot_credentials: <
ssid: "ssid"
password: "password"
port: 1234
gateway: "0.0.0.0"
frequency: 2412
>
supports_disabling_encryption: false
supports_client_introduction_ack: true
>
>
>)pb";
ByteArray bytes = ForBwuWifiHotspotPathAvailable(
"ssid", "password", 1234, /*frequency=*/2412, "0.0.0.0", false);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuWifiLanPathAvailable) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: <
event_type: UPGRADE_PATH_AVAILABLE
upgrade_path_info: <
medium: WIFI_LAN
wifi_lan_socket: < ip_address: "\x01\x02\x03\x04" wifi_port: 1234 >
supports_client_introduction_ack: true
>
>
>)pb";
ByteArray bytes = ForBwuWifiLanPathAvailable("\x01\x02\x03\x04", 1234);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuAwdlPathAvailable) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: <
event_type: UPGRADE_PATH_AVAILABLE
upgrade_path_info: <
medium: AWDL
supports_client_introduction_ack: true
awdl_credentials: <
service_name: "service_name"
service_type: "nearby_upgrade"
>
>
>
>)pb";
ByteArray bytes = ForBwuAwdlPathAvailable("service_name", "nearby_upgrade");
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuWifiAwarePathAvailable) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: <
event_type: UPGRADE_PATH_AVAILABLE
upgrade_path_info: <
medium: WIFI_AWARE
wifi_aware_credentials: <
service_id: "service_id"
service_info: "service_info"
password: "password"
>
supports_disabling_encryption: false
supports_client_introduction_ack: true
>
>
>)pb";
ByteArray bytes = ForBwuWifiAwarePathAvailable("service_id", "service_info",
"password", false);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuWifiDirectPathAvailable) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: <
event_type: UPGRADE_PATH_AVAILABLE
upgrade_path_info: <
medium: WIFI_DIRECT
wifi_direct_credentials: <
ssid: "DIRECT-A0-0123456789AB"
password: "password"
port: 1000
frequency: 2412
gateway: "192.168.1.1"
>
supports_disabling_encryption: false
supports_client_introduction_ack: true
>
>
>)pb";
ByteArray bytes = ForBwuWifiDirectPathAvailable(
"DIRECT-A0-0123456789AB", "password", 1000, 2412, false, "192.168.1.1");
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuBluetoothPathAvailable) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: <
event_type: UPGRADE_PATH_AVAILABLE
upgrade_path_info: <
medium: BLUETOOTH
bluetooth_credentials: <
service_name: "service"
mac_address: "\x11\x22\x33\x44\x55\x66"
>
supports_client_introduction_ack: true
>
>
>)pb";
ByteArray bytes =
ForBwuBluetoothPathAvailable("service", "\x11\x22\x33\x44\x55\x66");
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuLastWrite) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: < event_type: LAST_WRITE_TO_PRIOR_CHANNEL >
>)pb";
ByteArray bytes = ForBwuLastWrite();
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuSafeToClose) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: < event_type: SAFE_TO_CLOSE_PRIOR_CHANNEL >
>)pb";
ByteArray bytes = ForBwuSafeToClose();
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuIntroduction) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: <
event_type: CLIENT_INTRODUCTION
client_introduction: <
endpoint_id: "ABC"
supports_disabling_encryption: false
>
>
>)pb";
ByteArray bytes = ForBwuIntroduction(
std::string(kEndpointId), false /* supports_disabling_encryption */);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateKeepAlive) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: KEEP_ALIVE
keep_alive: <>
>)pb";
ByteArray bytes = ForKeepAlive();
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateDisconnection) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: DISCONNECTION
disconnection: <
request_safe_to_disconnect: true
ack_safe_to_disconnect: true
>
>)pb";
ByteArray bytes = ForDisconnection(/* request_safe_to_disconnect */ true,
/* ack_safe_to_disconnect */ true);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateAutoReconnectIntroduction) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: AUTO_RECONNECT
auto_reconnect: < event_type: CLIENT_INTRODUCTION endpoint_id: "ABC" >
>)pb";
ByteArray bytes = ForAutoReconnectIntroduction(std::string(kEndpointId));
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateAutoReconnectIntroductionAck) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: AUTO_RECONNECT
auto_reconnect: < event_type: CLIENT_INTRODUCTION_ACK >
>)pb";
ByteArray bytes = ForAutoReconnectIntroductionAck();
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBwuPathRequest) {
constexpr absl::string_view kExpected =
R"pb(
version: V1
v1: <
type: BANDWIDTH_UPGRADE_NEGOTIATION
bandwidth_upgrade_negotiation: <
event_type: UPGRADE_PATH_REQUEST
upgrade_path_info: <
upgrade_path_request: <
mediums: WIFI_HOTSPOT
medium_meta_data: <
medium_role: < support_wifi_hotspot_client: true >
>
>
>
>
>)pb";
std::vector<Medium> mediums;
mediums.push_back(Medium::WIFI_HOTSPOT);
MediumRole medium_role;
medium_role.set_support_wifi_hotspot_client(true);
ByteArray bytes = ForBwuPathRequest(mediums, medium_role);
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
EXPECT_THAT(message, EqualsProto(kExpected));
}
} // namespace
} // namespace parser
} // namespace connections
} // namespace nearby