// Copyright 2019 The Chromium 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 "cast/common/public/service_info.h" #include #include #include "cast/common/public/testing/discovery_utils.h" #include "discovery/dnssd/public/dns_sd_instance.h" #include "gmock/gmock.h" #include "gtest/gtest.h" namespace openscreen { namespace cast { namespace { constexpr NetworkInterfaceIndex kNetworkInterface = 0; } TEST(ServiceInfoTests, ConvertValidFromDnsSd) { std::string instance = "InstanceId"; discovery::DnsSdTxtRecord txt = CreateValidTxt(); discovery::DnsSdInstanceEndpoint record( instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface, kEndpointV4, kEndpointV6); ErrorOr info = DnsSdInstanceEndpointToServiceInfo(record); ASSERT_TRUE(info.is_value()) << info; EXPECT_EQ(info.value().unique_id, kTestUniqueId); EXPECT_TRUE(info.value().v4_address); EXPECT_EQ(info.value().v4_address, kAddressV4); EXPECT_TRUE(info.value().v6_address); EXPECT_EQ(info.value().v6_address, kAddressV6); EXPECT_EQ(info.value().port, kPort); EXPECT_EQ(info.value().unique_id, kTestUniqueId); EXPECT_EQ(info.value().protocol_version, kTestVersion); EXPECT_EQ(info.value().capabilities, kCapabilitiesParsed); EXPECT_EQ(info.value().status, kStatusParsed); EXPECT_EQ(info.value().model_name, kModelName); EXPECT_EQ(info.value().friendly_name, kFriendlyName); record = discovery::DnsSdInstanceEndpoint(instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface, kEndpointV4); info = DnsSdInstanceEndpointToServiceInfo(record); ASSERT_TRUE(info.is_value()); EXPECT_EQ(info.value().unique_id, kTestUniqueId); EXPECT_TRUE(info.value().v4_address); EXPECT_EQ(info.value().v4_address, kAddressV4); EXPECT_FALSE(info.value().v6_address); EXPECT_EQ(info.value().unique_id, kTestUniqueId); EXPECT_EQ(info.value().protocol_version, kTestVersion); EXPECT_EQ(info.value().capabilities, kCapabilitiesParsed); EXPECT_EQ(info.value().status, kStatusParsed); EXPECT_EQ(info.value().model_name, kModelName); EXPECT_EQ(info.value().friendly_name, kFriendlyName); record = discovery::DnsSdInstanceEndpoint(instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface, kEndpointV6); info = DnsSdInstanceEndpointToServiceInfo(record); ASSERT_TRUE(info.is_value()); EXPECT_EQ(info.value().unique_id, kTestUniqueId); EXPECT_FALSE(info.value().v4_address); EXPECT_TRUE(info.value().v6_address); EXPECT_EQ(info.value().v6_address, kAddressV6); EXPECT_EQ(info.value().unique_id, kTestUniqueId); EXPECT_EQ(info.value().protocol_version, kTestVersion); EXPECT_EQ(info.value().capabilities, kCapabilitiesParsed); EXPECT_EQ(info.value().status, kStatusParsed); EXPECT_EQ(info.value().model_name, kModelName); EXPECT_EQ(info.value().friendly_name, kFriendlyName); } TEST(ServiceInfoTests, ConvertInvalidFromDnsSd) { std::string instance = "InstanceId"; discovery::DnsSdTxtRecord txt = CreateValidTxt(); txt.ClearValue(kUniqueIdKey); discovery::DnsSdInstanceEndpoint record( instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface, kEndpointV4, kEndpointV6); EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error()); txt = CreateValidTxt(); txt.ClearValue(kVersionKey); record = discovery::DnsSdInstanceEndpoint( instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface, kEndpointV4, kEndpointV6); EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error()); txt = CreateValidTxt(); txt.ClearValue(kCapabilitiesKey); record = discovery::DnsSdInstanceEndpoint( instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface, kEndpointV4, kEndpointV6); EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error()); txt = CreateValidTxt(); txt.ClearValue(kStatusKey); record = discovery::DnsSdInstanceEndpoint( instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface, kEndpointV4, kEndpointV6); EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error()); txt = CreateValidTxt(); txt.ClearValue(kFriendlyNameKey); record = discovery::DnsSdInstanceEndpoint( instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface, kEndpointV4, kEndpointV6); EXPECT_TRUE(DnsSdInstanceEndpointToServiceInfo(record).is_error()); txt = CreateValidTxt(); txt.ClearValue(kModelNameKey); record = discovery::DnsSdInstanceEndpoint( instance, kCastV2ServiceId, kCastV2DomainId, txt, kNetworkInterface, kEndpointV4, kEndpointV6); // Note: Model name is an optional field. EXPECT_FALSE(DnsSdInstanceEndpointToServiceInfo(record).is_error()); } TEST(ServiceInfoTests, ConvertValidToDnsSd) { ServiceInfo info; info.v4_address = kAddressV4; info.v6_address = kAddressV6; info.port = kPort; info.unique_id = kTestUniqueId; info.protocol_version = kTestVersion; info.capabilities = kCapabilitiesParsed; info.status = kStatusParsed; info.model_name = kModelName; info.friendly_name = kFriendlyName; discovery::DnsSdInstance instance = ServiceInfoToDnsSdInstance(info); CompareTxtString(instance.txt(), kUniqueIdKey, kTestUniqueId); CompareTxtString(instance.txt(), kCapabilitiesKey, kCapabilitiesString); CompareTxtString(instance.txt(), kModelNameKey, kModelName); CompareTxtString(instance.txt(), kFriendlyNameKey, kFriendlyName); CompareTxtInt(instance.txt(), kVersionKey, kTestVersion); CompareTxtInt(instance.txt(), kStatusKey, kStatus); } TEST(ServiceInfoTests, ParseServiceInfoFromRealTXT) { constexpr struct { const char* key; const char* value; } kRealTXTForReceiverCastingYoutube[] = { {"bs", "FA99CBBF17D0"}, // Note: Includes bits set that are not known: {"ca", "208901"}, {"cd", "FED81089FA3FF851CF088AB33AB014C0"}, {"fn", u8"⚡ Yurovision® ULTRA™"}, {"ic", "/setup/icon.png"}, {"id", "4ef522244a5a877f35ddead7d98702e6"}, {"md", "Chromecast Ultra"}, {"nf", "2"}, {"rm", "6342FE65DD269999"}, {"rs", "YouTube"}, {"st", "1"}, {"ve", "05"}, }; discovery::DnsSdTxtRecord txt; for (const auto e : kRealTXTForReceiverCastingYoutube) { ASSERT_TRUE(txt.SetValue(e.key, e.value).ok()); } const discovery::DnsSdInstanceEndpoint record( "InstanceId", kCastV2ServiceId, kCastV2DomainId, std::move(txt), kNetworkInterface, kEndpointV4, kEndpointV6); const ErrorOr result = DnsSdInstanceEndpointToServiceInfo(record); const ServiceInfo& info = result.value(); EXPECT_EQ(info.unique_id, "4ef522244a5a877f35ddead7d98702e6"); EXPECT_EQ(info.protocol_version, 5); EXPECT_TRUE(info.capabilities & (kHasVideoOutput | kHasAudioOutput)); EXPECT_EQ(info.status, kBusy); EXPECT_EQ(info.model_name, "Chromecast Ultra"); EXPECT_EQ(info.friendly_name, u8"⚡ Yurovision® ULTRA™"); } } // namespace cast } // namespace openscreen