| // 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 <utility> |
| #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/implementation/proto/offline_wire_formats.pb.h" |
| #include "internal/platform/byte_array.h" |
| |
| namespace location { |
| namespace nearby { |
| namespace connections { |
| namespace parser { |
| namespace { |
| |
| using Medium = proto::connections::Medium; |
| 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 std::array<Medium, 9> kMediums = { |
| Medium::MDNS, Medium::BLUETOOTH, Medium::WIFI_HOTSPOT, |
| Medium::BLE, Medium::WIFI_LAN, Medium::WIFI_AWARE, |
| Medium::NFC, Medium::WIFI_DIRECT, Medium::WEB_RTC, |
| }; |
| 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, CanGenerateConnectionRequest) { |
| constexpr char 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" > |
| mediums: MDNS |
| mediums: BLUETOOTH |
| mediums: WIFI_HOTSPOT |
| mediums: BLE |
| mediums: WIFI_LAN |
| mediums: WIFI_AWARE |
| mediums: NFC |
| mediums: WIFI_DIRECT |
| mediums: WEB_RTC |
| keep_alive_interval_millis: 1000 |
| keep_alive_timeout_millis: 5000 |
| > |
| >)pb"; |
| ByteArray bytes = ForConnectionRequest( |
| std::string(kEndpointId), ByteArray{std::string(kEndpointName)}, kNonce, |
| kSupports5ghz, std::string(kBssid), |
| std::vector(kMediums.begin(), kMediums.end()), kKeepAliveIntervalMillis, |
| kKeepAliveTimeoutMillis); |
| auto response = FromBytes(bytes); |
| ASSERT_TRUE(response.ok()); |
| OfflineFrame message = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateConnectionResponse) { |
| constexpr char kExpected[] = |
| R"pb( |
| version: V1 |
| v1: < |
| type: CONNECTION_RESPONSE |
| connection_response: < status: 1 response: REJECT > |
| >)pb"; |
| ByteArray bytes = ForConnectionResponse(1); |
| auto response = FromBytes(bytes); |
| ASSERT_TRUE(response.ok()); |
| OfflineFrame message = FromBytes(bytes).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 char 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 = FromBytes(bytes).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 char 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 = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateBwuWifiHotspotPathAvailable) { |
| constexpr char 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" |
| > |
| supports_disabling_encryption: false |
| supports_client_introduction_ack: true |
| > |
| > |
| >)pb"; |
| ByteArray bytes = ForBwuWifiHotspotPathAvailable("ssid", "password", 1234, |
| "0.0.0.0", false); |
| auto response = FromBytes(bytes); |
| ASSERT_TRUE(response.ok()); |
| OfflineFrame message = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateBwuWifiLanPathAvailable) { |
| constexpr char 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 = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateBwuWifiAwarePathAvailable) { |
| constexpr char 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 = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateBwuWifiDirectPathAvailable) { |
| constexpr char 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: 1000 |
| > |
| supports_disabling_encryption: false |
| supports_client_introduction_ack: true |
| > |
| > |
| >)pb"; |
| ByteArray bytes = ForBwuWifiDirectPathAvailable( |
| "DIRECT-A0-0123456789AB", "password", 1000, 1000, false); |
| auto response = FromBytes(bytes); |
| ASSERT_TRUE(response.ok()); |
| OfflineFrame message = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateBwuBluetoothPathAvailable) { |
| constexpr char 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 = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateBwuLastWrite) { |
| constexpr char 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 = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateBwuSafeToClose) { |
| constexpr char 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 = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateBwuIntroduction) { |
| constexpr char kExpected[] = |
| R"pb( |
| version: V1 |
| v1: < |
| type: BANDWIDTH_UPGRADE_NEGOTIATION |
| bandwidth_upgrade_negotiation: < |
| event_type: CLIENT_INTRODUCTION |
| client_introduction: < endpoint_id: "ABC" > |
| > |
| >)pb"; |
| ByteArray bytes = ForBwuIntroduction(std::string(kEndpointId)); |
| auto response = FromBytes(bytes); |
| ASSERT_TRUE(response.ok()); |
| OfflineFrame message = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| TEST(OfflineFramesTest, CanGenerateKeepAlive) { |
| constexpr char 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 = FromBytes(bytes).result(); |
| EXPECT_THAT(message, EqualsProto(kExpected)); |
| } |
| |
| } // namespace |
| } // namespace parser |
| } // namespace connections |
| } // namespace nearby |
| } // namespace location |