From e4232651808e821712af0ca763f34a8fe8ec9459 Mon Sep 17 00:00:00 2001 From: Victor Vazquez Date: Wed, 10 Feb 2021 18:16:54 -0800 Subject: [PATCH] Make keyvault to expose telemetry options (#1661) fixes: #1566 --- .../keyvault/keys/key_client_options.hpp | 1 + .../src/key_client.cpp | 3 +- .../test/CMakeLists.txt | 5 +- .../test/mocked_transport_adapter_test.hpp | 93 +++++++++++++++++++ .../test/telemetry_header_test.cpp | 50 ++++++++++ 5 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 sdk/keyvault/azure-security-keyvault-keys/test/mocked_transport_adapter_test.hpp create mode 100644 sdk/keyvault/azure-security-keyvault-keys/test/telemetry_header_test.cpp diff --git a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_options.hpp b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_options.hpp index 4bf18fa54..130dfff07 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_options.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_options.hpp @@ -27,6 +27,7 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { ServiceVersion Version; Azure::Core::Http::RetryOptions RetryOptions; Azure::Core::Http::TransportPolicyOptions TransportPolicyOptions; + Azure::Core::Http::TelemetryPolicyOptions TelemetryPolicyOptions; KeyClientOptions(ServiceVersion version = ServiceVersion::V7_2) : Version(version) {} diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/key_client.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/key_client.cpp index 316f5c89d..c6b2b7b6f 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/key_client.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/key_client.cpp @@ -23,7 +23,8 @@ KeyClient::KeyClient( // Base Pipeline std::vector> policies; - policies.emplace_back(std::make_unique("KeyVault", apiVersion)); + policies.emplace_back( + std::make_unique("KeyVault", apiVersion, options.TelemetryPolicyOptions)); policies.emplace_back(std::make_unique()); policies.emplace_back(std::make_unique(options.RetryOptions)); diff --git a/sdk/keyvault/azure-security-keyvault-keys/test/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-keys/test/CMakeLists.txt index 75a62ce87..d8bed34c9 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/test/CMakeLists.txt +++ b/sdk/keyvault/azure-security-keyvault-keys/test/CMakeLists.txt @@ -12,8 +12,10 @@ include(GoogleTest) ################## Unit Tests ########################## add_executable ( azure-security-keyvault-keys-test - key_client_test.cpp + key_client_test.cpp main.cpp + mocked_transport_adapter_test.hpp + telemetry_header_test.cpp ) if (MSVC) @@ -33,6 +35,7 @@ add_executable ( azure-security-keyvault-keys-test-live key_client_test_live.cpp main.cpp + key_client_base_test.hpp ) if (MSVC) diff --git a/sdk/keyvault/azure-security-keyvault-keys/test/mocked_transport_adapter_test.hpp b/sdk/keyvault/azure-security-keyvault-keys/test/mocked_transport_adapter_test.hpp new file mode 100644 index 000000000..1bdd3ee13 --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-keys/test/mocked_transport_adapter_test.hpp @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/** + * @file + * @brief The base class to construct and init a Key Vault client. + * + */ + +#include + +#include +#include + +#include + +namespace Azure { namespace Security { namespace KeyVault { namespace Keys { namespace Test { + + namespace Details { + // Return a simple key as response so keyvault can parse it to create the T response + // Fake key from https://docs.microsoft.com/en-us/rest/api/keyvault/GetKey/GetKey#examples + constexpr static const char FakeKey[] + = "{ \"key\": { \"kid\": " + "\"https://myvault.vault.azure.net/keys/CreateSoftKeyTest/" + "78deebed173b48e48f55abf87ed4cf71\", \"kty\": \"RSA\", \"key_ops\": [ " + "\"encrypt\", \"decrypt\", \"sign\", \"verify\", \"wrapKey\", " + "\"unwrapKey\" ]}, \"attributes\": { \"enabled\": true, " + "\"created\": 1493942451, \"updated\": 1493942451, \"recoveryLevel\": " + "\"Recoverable+Purgeable\" }, \"tags\": { \"purpose\" " + ": " + "\"unit test\", \"test name \" : \"CreateGetDeleteKeyTest\"}}"; + } // namespace Details + + // A transport adapter which only echo a request headers back as a response. + class MockedTransportAdapter : public Azure::Core::Http::HttpTransport { + std::unique_ptr Send( + Azure::Core::Context const& context, + Azure::Core::Http::Request& request) override + { + (void)context; + auto response = std::make_unique( + 1, 1, Azure::Core::Http::HttpStatusCode::Ok, "Ok"); + + // Copy headers + for (auto header : request.GetHeaders()) + { + response->AddHeader(header.first, header.second); + } + std::string bodyCount(Details::FakeKey); + response->SetBodyStream(std::make_unique( + reinterpret_cast(Details::FakeKey), bodyCount.size())); + return response; + } // namespace Azure + }; // namespace Test + + // A derived class with no credential and authentication + class KeyClientWithNoAuthenticationPolicy : public Azure::Security::KeyVault::Keys::KeyClient { + public: + explicit KeyClientWithNoAuthenticationPolicy( + std::string const& vaultUrl, + KeyClientOptions options = KeyClientOptions()) + : KeyClient(vaultUrl, nullptr, options) + { + auto apiVersion = options.GetVersionString(); + + // Base Pipeline + std::vector> policies; + policies.emplace_back(std::make_unique( + "KeyVault", apiVersion, options.TelemetryPolicyOptions)); + policies.emplace_back(std::make_unique()); + policies.emplace_back(std::make_unique(options.RetryOptions)); + policies.emplace_back(std::make_unique()); + policies.emplace_back( + std::make_unique(options.TransportPolicyOptions)); + Azure::Core::Http::Url url(vaultUrl); + + m_pipeline = std::make_unique( + url, apiVersion, std::move(policies)); + } + }; + + class MockedTransportAdapterTest : public ::testing::Test { + protected: + std::unique_ptr m_client; + Azure::Security::KeyVault::Keys::KeyClientOptions m_clientOptions; + + // Create + virtual void SetUp() override + { + m_clientOptions.TransportPolicyOptions.Transport = std::make_shared(); + } + }; +}}}}} // namespace Azure::Security::KeyVault::Keys::Test diff --git a/sdk/keyvault/azure-security-keyvault-keys/test/telemetry_header_test.cpp b/sdk/keyvault/azure-security-keyvault-keys/test/telemetry_header_test.cpp new file mode 100644 index 000000000..8b3435db0 --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-keys/test/telemetry_header_test.cpp @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#if defined(_MSC_VER) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "gtest/gtest.h" + +#include "mocked_transport_adapter_test.hpp" + +#include +#include + +#include + +using namespace Azure::Security::KeyVault::Keys::Test; + +TEST_F(MockedTransportAdapterTest, keyvaultTelemetryId) +{ + std::string applicationId("ourApplicationId"); + m_clientOptions.TelemetryPolicyOptions.ApplicationId = applicationId; + m_client = std::make_unique< + Azure::Security::KeyVault::Keys::Test::KeyClientWithNoAuthenticationPolicy>( + "url", m_clientOptions); + + // The fake response from the mocked transport adapter is good for parsing a Key back + auto response = m_client->GetKey("name"); + + // The response is an echo of the sent headers. Let's find the telemetry id + auto foundHeader = false; + for (auto& header : response.GetRawResponse().GetHeaders()) + { + if (Azure::Core::Internal::Strings::LocaleInvariantCaseInsensitiveEqual( + header.first, "User-Agent")) + { + foundHeader = true; + EXPECT_PRED2( + [](std::string const& received, std::string const& sent) { + auto telemetryInfoWithNoOSAndDate = received.substr(0, sent.size()); + return Azure::Core::Internal::Strings::LocaleInvariantCaseInsensitiveEqual( + telemetryInfoWithNoOSAndDate, sent); + }, + header.second, + applicationId); + break; + } + } + EXPECT_TRUE(foundHeader); +}