Moving Pageble<T> to Core and updating KeyVault to use it (#2144)

* updated getDeletedKeys

* pagable for list keys
This commit is contained in:
Victor Vazquez 2021-04-27 02:44:03 +00:00 committed by GitHub
parent 0c24db5a10
commit fe9002e905
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 317 additions and 115 deletions

View File

@ -2,6 +2,10 @@
## 1.0.0-beta.9 (Unreleased)
### New Features
- Added `Azure::PagedResponse<T>`.
### Bug Fixes
- Do not re-use a libcurl connection to same host but different port.

View File

@ -75,6 +75,7 @@ set(
inc/azure/core/modified_conditions.hpp
inc/azure/core/nullable.hpp
inc/azure/core/operation.hpp
inc/azure/core/paged_response.hpp
inc/azure/core/operation_status.hpp
inc/azure/core/platform.hpp
inc/azure/core/response.hpp

View File

@ -0,0 +1,97 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Provides support for responses of paginated collections from the service.
*/
#pragma once
#include <cstdlib>
#include <string>
#include "azure/core/context.hpp"
#include "azure/core/http/raw_response.hpp"
#include "azure/core/nullable.hpp"
namespace Azure { namespace Core {
/**
* @brief Defines the base type and behavior for a paged response.
*
* @remark The template is used for static-inheritance.
*
* @remark T classes must implement the way to get and move to the next page.
*
* @tparam T A class type for static-inheritance.
*/
template <class T> class PagedResponse {
private:
// The field used to check when the end of the response is reached. We default it true as the
// starting point because all responses from a service will always come with a payload that
// represents at least one page. The page might or might not contain elements in the page.
// `m_hasPage` is then turned to `false` once `MoveToNextPage` is called on the last page.
bool m_hasPage = true;
protected:
PagedResponse() = default;
PagedResponse(PagedResponse&&) = default;
PagedResponse& operator=(PagedResponse&&) = default;
public:
/**
* @brief Defines the token used to fetch the current page.
*
*/
std::string CurrentPageToken;
/**
* @brief Defines the token for getting the next page.
*
* @remark If there are no more pages, this field becomes an empty string.
*
* @remark Assumes all services will include NextPageToken in the payload, it is set to either
* null or empty for the last page or to a value used for getting the next page.
*
*/
Azure::Nullable<std::string> NextPageToken;
/**
* @brief The HTTP response returned by the service.
*
*/
std::unique_ptr<Azure::Core::Http::RawResponse> RawResponse;
/**
* @brief Check if a page exists. It returns false after the last page.
*
*/
bool HasPage() const { return m_hasPage; }
/**
* @brief Move to the next page of the response.
*
* @remark Calling this method on the last page will set #HasPage() to false.
*
* @param context An #Azure::Core::Context controlling the request lifetime.
*/
void MoveToNextPage(const Azure::Core::Context& context = Azure::Core::Context())
{
static_assert(
std::is_base_of<PagedResponse, T>::value,
"The template argument \"T\" should derive from PagedResponse<T>.");
if (!NextPageToken.HasValue() || NextPageToken.Value().empty())
{
m_hasPage = false;
return;
}
// Developer must make sure current page is kept unchanged if OnNextPage()
// throws exception.
static_cast<T*>(this)->OnNextPage(context);
}
};
}} // namespace Azure::Core

View File

@ -113,7 +113,7 @@ namespace Azure { namespace Security { namespace KeyVault { namespace _internal
// Saving the value in a local is required before passing it in to Response<T> to avoid
// compiler optimizations re-ordering the `factoryFn` function call and the RawResponse move.
T value = factoryFn(*response);
return Azure::Response<T>(value, std::move(response));
return Azure::Response<T>(std::move(value), std::move(response));
}
/**

View File

@ -13,14 +13,9 @@
#include <string>
namespace Azure { namespace Security { namespace KeyVault { namespace _internal {
struct SinglePage
{
Azure::Nullable<std::string> ContinuationToken;
};
struct GetSinglePageOptions
{
Azure::Nullable<std::string> ContinuationToken;
Azure::Nullable<std::string> NextPageToken;
Azure::Nullable<uint32_t> MaxPageResults;
};
}}}} // namespace Azure::Security::KeyVault::_internal

View File

@ -12,6 +12,9 @@
- Replaced static functions from `KeyOperation` and `KeyCurveName` with static const members.
- Replaced the enum `JsonWebKeyType` for a class with static const members as an extensible enum called `KeyVaultKeyType`.
- Renamed `MaxResults` to `MaxPageResults` for `GetSinglePageOptions`.
- Changed the returned type for list keys, key versions, and deleted keys from `Response<T>` to `PagedResponse<T>` affecting:
- `GetPropertiesOfKeysSinglePage()` and `GetPropertiesOfKeyVersionsSinglePage()` now returns `KeyPropertiesSinglePage`.
- `GetDeletedKeysSinglePage()` now returns `DeletedKeySinglePage`.
### Bug Fixes

View File

@ -73,6 +73,13 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
KeyClientOptions options = KeyClientOptions());
/**
* @brief Construct a new Key Client object from another key client.
*
* @param keyClient An existing key vault key client.
*/
explicit KeyClient(KeyClient const& keyClient) : m_pipeline(keyClient.m_pipeline) {}
/**
* @brief Gets the public part of a stored key.
*
@ -168,15 +175,14 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
*
* @remark Use \p options to control which page to get. If
* #GetPropertiesOfKeysSinglePageOptions.NextLink is not set, the operation will get the first
* page and it will set the `ContinuationToken` from the #KeyPropertiesSinglePage as the next
* page and it will set the `NextPageToken` from the #KeyPropertiesSinglePage as the next
* page of the response if there is a next page.
*
* @param options The #GetPropertiesOfKeysSinglePageOptions object to for setting the operation
* up.
* @param context A #Azure::Core::Context controlling the request lifetime.
* @return Azure::Response<KeyPropertiesSinglePage>
*/
Azure::Response<KeyPropertiesSinglePage> GetPropertiesOfKeysSinglePage(
KeyPropertiesSinglePage GetPropertiesOfKeysSinglePage(
GetPropertiesOfKeysSinglePageOptions const& options
= GetPropertiesOfKeysSinglePageOptions(),
Azure::Core::Context const& context = Azure::Core::Context()) const;
@ -191,16 +197,15 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
*
* @remark Use \p options to control which page to get. If
* #GetPropertiesOfKeyVersionsSinglePageOptions.NextLink is not set, the operation will get the
* first page and it will set the `ContinuationToken` from the #KeyPropertiesSinglePage as the
* first page and it will set the `NextPageToken` from the #KeyPropertiesSinglePage as the
* next page of the response if there is a next page.
*
* @param name The name of the key.
* @param options The #GetPropertiesOfKeyVersionsSinglePageOptions object to for setting the
* operation up.
* @param context A #Azure::Core::Context controlling the request lifetime.
* @return Azure::Response<KeyPropertiesSinglePage>
*/
Azure::Response<KeyPropertiesSinglePage> GetPropertiesOfKeyVersionsSinglePage(
KeyPropertiesSinglePage GetPropertiesOfKeyVersionsSinglePage(
std::string const& name,
GetPropertiesOfKeyVersionsSinglePageOptions const& options
= GetPropertiesOfKeyVersionsSinglePageOptions(),
@ -262,15 +267,15 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
* requires the keys/list permission.
*
* @remark Use \p options to control which page to get. If
* #GetPropertiesOfKeyVersionsSinglePageOptions.NextLink is not set, the operation will get the
* first page and it will set the `ContinuationToken` from the #KeyPropertiesSinglePage as the
* #GetPropertiesOfKeyVersionsSinglePageOptions.NextPageToken is not set, the operation will get
* the first page and it will set the `NextPageToken` from the #KeyPropertiesSinglePage as the
* next page of the response if there is a next page.
*
* @param options The #GetDeletedKeysSinglePageOptions object to for setting the operation up.
* @param context A #Azure::Core::Context controlling the request lifetime.
* @return Azure::Response<DeletedKeySinglePage>
*/
Azure::Response<DeletedKeySinglePage> GetDeletedKeysSinglePage(
DeletedKeySinglePage GetDeletedKeysSinglePage(
GetDeletedKeysSinglePageOptions const& options = GetDeletedKeysSinglePageOptions(),
Azure::Core::Context const& context = Azure::Core::Context()) const;

View File

@ -9,38 +9,139 @@
#pragma once
#include <azure/core/http/http.hpp>
#include <azure/core/paged_response.hpp>
#include <azure/keyvault/common/internal/single_page.hpp>
#include "azure/keyvault/keys/deleted_key.hpp"
#include "azure/keyvault/keys/json_web_key.hpp"
#include "azure/keyvault/keys/key_vault_key.hpp"
#include <azure/keyvault/common/internal/single_page.hpp>
#include <azure/core/http/http.hpp>
#include <memory>
#include <vector>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
class KeyClient;
struct KeyPropertiesSinglePage : public Azure::Security::KeyVault::_internal::SinglePage
{
/**
* @brief Define a single page to list the keys from the Key Vault.
*
*/
class KeyPropertiesSinglePage : public Azure::Core::PagedResponse<KeyPropertiesSinglePage> {
private:
friend class KeyClient;
friend class Azure::Core::PagedResponse<KeyPropertiesSinglePage>;
std::string m_keyName;
std::shared_ptr<KeyClient> m_keyClient;
void OnNextPage(const Azure::Core::Context&);
/**
* @brief Construct a new Key Properties Single Page object.
*
* @remark The constructor is private and only a key client or PagedResponse can init this.
*
* @param keyProperties A previously created #KeyPropertiesSinglePage that is used to init this
* instance.
* @param rawResponse The Http raw response from where the #KeyPropertiesSinglePage was parsed.
* @param keyClient A key client required for getting the next pages.
* @param keyName When \p keyName is set, the response is listing key versions. Otherwise, the
* response is for listing keys from the Key Vault.
*/
KeyPropertiesSinglePage(
KeyPropertiesSinglePage&& keyProperties,
std::unique_ptr<Azure::Core::Http::RawResponse> rawResponse,
std::shared_ptr<KeyClient> keyClient,
std::string const& keyName = std::string())
: m_keyName(keyName), m_keyClient(keyClient), Items(std::move(keyProperties.Items))
{
RawResponse = std::move(rawResponse);
}
public:
/**
* @brief Construct a new key properties object.
*
*/
KeyPropertiesSinglePage() = default;
/**
* @brief Each #KeyProperties represent a Key in the Key Vault.
*
*/
std::vector<KeyProperties> Items;
};
struct DeletedKeySinglePage : public Azure::Security::KeyVault::_internal::SinglePage
{
/**
* @brief Define a single page containing the deleted keys from the Key Vault.
*
*/
class DeletedKeySinglePage : public Azure::Core::PagedResponse<DeletedKeySinglePage> {
private:
friend class KeyClient;
friend class Azure::Core::PagedResponse<DeletedKeySinglePage>;
std::shared_ptr<KeyClient> m_keyClient;
void OnNextPage(const Azure::Core::Context& context);
/**
* @brief Construct a new Key Properties Single Page object.
*
* @remark The constructor is private and only a key client or PagedResponse can init this.
*
* @param deletedKeyProperties A previously created #DeletedKeySinglePage that is used to init
* this new instance.
* @param rawResponse The Http raw response from where the #DeletedKeySinglePage was parsed.
* @param keyClient A key client required for getting the next pages.
* @param keyName When \p keyName is set, the response is listing key versions. Otherwise, the
* response is for listing keys from the Key Vault.
*/
DeletedKeySinglePage(
DeletedKeySinglePage&& deletedKeyProperties,
std::unique_ptr<Azure::Core::Http::RawResponse> rawResponse,
std::shared_ptr<KeyClient> keyClient)
: m_keyClient(keyClient), Items(std::move(deletedKeyProperties.Items))
{
RawResponse = std::move(rawResponse);
}
public:
/**
* @brief Construct a new Deleted Key Single Page object
*
*/
DeletedKeySinglePage() = default;
/**
* @brief Each #DeletedKey represent a deleted key in the Key Vault.
*
*/
std::vector<DeletedKey> Items;
};
/**
* @brief The options for calling an operation #GetPropertiesOfKeysSinglePage.
*
*/
struct GetPropertiesOfKeysSinglePageOptions
: public Azure::Security::KeyVault::_internal::GetSinglePageOptions
{
};
/**
* @brief The options for calling an operation #GetPropertiesOfKeyVersionsSinglePage.
*
*/
struct GetPropertiesOfKeyVersionsSinglePageOptions
: public Azure::Security::KeyVault::_internal::GetSinglePageOptions
{
};
/**
* @brief The options for calling an operation #GetDeletedKeysSinglePage.
*
*/
struct GetDeletedKeysSinglePageOptions
: public Azure::Security::KeyVault::_internal::GetSinglePageOptions
{

View File

@ -35,11 +35,11 @@ static inline RequestWithContinuationToken BuildRequestFromContinuationToken(
{
RequestWithContinuationToken request;
request.Path = defaultPath;
if (options.ContinuationToken)
if (options.NextPageToken)
{
// Using a continuation token requires to send the request to the continuation token url instead
// of the default url which is used only for the first page.
Azure::Core::Url nextPageUrl(options.ContinuationToken.Value());
Azure::Core::Url nextPageUrl(options.NextPageToken.Value());
request.Query
= std::make_unique<std::map<std::string, std::string>>(nextPageUrl.GetQueryParameters());
request.Path.clear();
@ -155,12 +155,12 @@ Azure::Response<KeyVaultKey> KeyClient::CreateOctKey(
{_detail::KeysPath, keyName, "create"});
}
Azure::Response<KeyPropertiesSinglePage> KeyClient::GetPropertiesOfKeysSinglePage(
KeyPropertiesSinglePage KeyClient::GetPropertiesOfKeysSinglePage(
GetPropertiesOfKeysSinglePageOptions const& options,
Azure::Core::Context const& context) const
{
auto const request = BuildRequestFromContinuationToken(options, {_detail::KeysPath});
return m_pipeline->SendRequest<KeyPropertiesSinglePage>(
auto response = m_pipeline->SendRequest<KeyPropertiesSinglePage>(
context,
Azure::Core::Http::HttpMethod::Get,
[](Azure::Core::Http::RawResponse const& rawResponse) {
@ -169,16 +169,21 @@ Azure::Response<KeyPropertiesSinglePage> KeyClient::GetPropertiesOfKeysSinglePag
},
request.Path,
request.Query);
return KeyPropertiesSinglePage(
std::move(response.Value),
std::move(response.RawResponse),
std::make_unique<KeyClient>(*this));
}
Azure::Response<KeyPropertiesSinglePage> KeyClient::GetPropertiesOfKeyVersionsSinglePage(
KeyPropertiesSinglePage KeyClient::GetPropertiesOfKeyVersionsSinglePage(
std::string const& name,
GetPropertiesOfKeyVersionsSinglePageOptions const& options,
Azure::Core::Context const& context) const
{
auto const request
= BuildRequestFromContinuationToken(options, {_detail::KeysPath, name, "versions"});
return m_pipeline->SendRequest<KeyPropertiesSinglePage>(
auto response = m_pipeline->SendRequest<KeyPropertiesSinglePage>(
context,
Azure::Core::Http::HttpMethod::Get,
[](Azure::Core::Http::RawResponse const& rawResponse) {
@ -187,6 +192,12 @@ Azure::Response<KeyPropertiesSinglePage> KeyClient::GetPropertiesOfKeyVersionsSi
},
request.Path,
request.Query);
return KeyPropertiesSinglePage(
std::move(response.Value),
std::move(response.RawResponse),
std::make_unique<KeyClient>(*this),
name);
}
Azure::Security::KeyVault::Keys::DeleteKeyOperation KeyClient::StartDeleteKey(
@ -254,12 +265,12 @@ Azure::Response<DeletedKey> KeyClient::GetDeletedKey(
{_detail::DeletedKeysPath, name});
}
Azure::Response<DeletedKeySinglePage> KeyClient::GetDeletedKeysSinglePage(
DeletedKeySinglePage KeyClient::GetDeletedKeysSinglePage(
GetDeletedKeysSinglePageOptions const& options,
Azure::Core::Context const& context) const
{
auto const request = BuildRequestFromContinuationToken(options, {_detail::DeletedKeysPath});
return m_pipeline->SendRequest<DeletedKeySinglePage>(
auto response = m_pipeline->SendRequest<DeletedKeySinglePage>(
context,
Azure::Core::Http::HttpMethod::Get,
[](Azure::Core::Http::RawResponse const& rawResponse) {
@ -268,6 +279,11 @@ Azure::Response<DeletedKeySinglePage> KeyClient::GetDeletedKeysSinglePage(
},
request.Path,
request.Query);
return DeletedKeySinglePage(
std::move(response.Value),
std::move(response.RawResponse),
std::make_unique<KeyClient>(*this));
}
Azure::Response<PurgedKey> KeyClient::PurgeDeletedKey(

View File

@ -4,6 +4,7 @@
#include "azure/keyvault/keys/list_keys_single_page_result.hpp"
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/details/key_serializers.hpp"
#include "azure/keyvault/keys/key_client.hpp"
#include <azure/keyvault/common/internal/unix_time_helper.hpp>
@ -24,7 +25,7 @@ _detail::KeyPropertiesSinglePageSerializer::KeyPropertiesSinglePageDeserialize(
auto const& body = rawResponse.GetBody();
auto jsonParser = json::parse(body);
JsonOptional::SetIfExists(result.ContinuationToken, jsonParser, "nextLink");
JsonOptional::SetIfExists(result.NextPageToken, jsonParser, "nextLink");
// Key properties
auto keyPropertiesJson = jsonParser["value"];
@ -90,7 +91,8 @@ DeletedKeySinglePage _detail::KeyPropertiesSinglePageSerializer::DeletedKeySingl
auto jsonParser = Azure::Core::Json::_internal::json::parse(body);
DeletedKeySinglePage deletedKeySinglePage;
JsonOptional::SetIfExists(deletedKeySinglePage.ContinuationToken, jsonParser, "nextLink");
JsonOptional::SetIfExists(deletedKeySinglePage.NextPageToken, jsonParser, "nextLink");
auto deletedKeys = jsonParser["value"];
for (auto const& key : deletedKeys)
@ -125,3 +127,39 @@ DeletedKeySinglePage _detail::KeyPropertiesSinglePageSerializer::DeletedKeySingl
return deletedKeySinglePage;
}
void DeletedKeySinglePage::OnNextPage(const Azure::Core::Context& context)
{
// Before calling `OnNextPage` pagedResponse validates there is a next page, so we are sure
// NextPageToken is valid.
GetDeletedKeysSinglePageOptions options;
options.NextPageToken = NextPageToken;
*this = m_keyClient->GetDeletedKeysSinglePage(options, context);
CurrentPageToken = options.NextPageToken.Value();
}
void KeyPropertiesSinglePage::OnNextPage(const Azure::Core::Context& context)
{
// Notes
// - Before calling `OnNextPage` pagedResponse validates there is a next page, so we are sure
// NextPageToken is valid.
// - KeyPropertiesSinglePage is used to list keys from a Key Vault and also to list the key
// versions from a specific key. When KeyPropertiesSinglePage is listing keys, the `m_keyName`
// fields will be empty, but for listing the key versions, the KeyPropertiesSinglePage needs to
// keep the name of the key in `m_keyName` because it is required to get more pages.
//
if (m_keyName.empty())
{
GetPropertiesOfKeysSinglePageOptions options;
options.NextPageToken = NextPageToken;
*this = m_keyClient->GetPropertiesOfKeysSinglePage(options, context);
CurrentPageToken = options.NextPageToken.Value();
}
else
{
GetPropertiesOfKeyVersionsSinglePageOptions options;
options.NextPageToken = NextPageToken;
*this = m_keyClient->GetPropertiesOfKeyVersionsSinglePage(m_keyName, options, context);
CurrentPageToken = options.NextPageToken.Value();
}
}

View File

@ -56,7 +56,8 @@ int main()
keyClient.CreateEcKey(ecKey);
std::cout << "\t-List Keys" << std::endl;
for (auto keysSinglePage = keyClient.GetPropertiesOfKeysSinglePage().Value;;)
for (auto keysSinglePage = keyClient.GetPropertiesOfKeysSinglePage(); keysSinglePage.HasPage();
keysSinglePage.MoveToNextPage())
{
for (auto const& key : keysSinglePage.Items)
{
@ -68,17 +69,6 @@ int main()
std::cout << "Key is returned with name: " << keyWithType.Name()
<< " and type: " << keyWithType.GetKeyType().ToString() << std::endl;
}
if (!keysSinglePage.ContinuationToken.HasValue())
{
// No more pages for the response, break the loop
break;
}
// Get the next page
GetPropertiesOfKeysSinglePageOptions options;
options.ContinuationToken = keysSinglePage.ContinuationToken.Value();
keysSinglePage = keyClient.GetPropertiesOfKeysSinglePage(options).Value;
}
// update key
@ -90,26 +80,14 @@ int main()
// List key versions
std::cout << "\t-List Key versions" << std::endl;
for (auto keyVersionsSinglePage
= keyClient.GetPropertiesOfKeyVersionsSinglePage(rsaKeyName).Value;
;)
for (auto keyVersionsSinglePage = keyClient.GetPropertiesOfKeyVersionsSinglePage(rsaKeyName);
keyVersionsSinglePage.HasPage();
keyVersionsSinglePage.MoveToNextPage())
{
for (auto const& key : keyVersionsSinglePage.Items)
{
std::cout << "Key's version: " << key.Version << " with name: " << key.Name << std::endl;
}
if (!keyVersionsSinglePage.ContinuationToken.HasValue())
{
// No more pages for the response, break the loop
break;
}
// Get the next page
GetPropertiesOfKeyVersionsSinglePageOptions options;
options.ContinuationToken = keyVersionsSinglePage.ContinuationToken.Value();
keyVersionsSinglePage
= keyClient.GetPropertiesOfKeyVersionsSinglePage(rsaKeyName, options).Value;
}
std::cout << "\t-Delete Keys" << std::endl;
@ -123,7 +101,8 @@ int main()
std::cout << "\t-List Deleted Keys" << std::endl;
// Start getting the first page.
for (auto keysDeletedPage = keyClient.GetDeletedKeysSinglePage().Value;;)
for (auto keysDeletedPage = keyClient.GetDeletedKeysSinglePage(); keysDeletedPage.HasPage();
keysDeletedPage.MoveToNextPage())
{
for (auto const& key : keysDeletedPage.Items)
{
@ -131,17 +110,6 @@ int main()
<< ", recovery level: " << key.Properties.RecoveryLevel
<< " and recovery Id: " << key.RecoveryId << std::endl;
}
if (!keysDeletedPage.ContinuationToken.HasValue())
{
// No more pages for the response, break the loop
break;
}
// Get the next page
GetDeletedKeysSinglePageOptions options;
options.ContinuationToken = keysDeletedPage.ContinuationToken.Value();
keysDeletedPage = keyClient.GetDeletedKeysSinglePage(options).Value;
}
// If the keyvault is soft-delete enabled, then for permanent deletion, deleted keys needs to be

View File

@ -70,19 +70,13 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { nam
static inline void CleanUpKeyVault(KeyClient const& keyClient)
{
std::vector<DeletedKey> deletedKeys;
GetDeletedKeysSinglePageOptions options;
while (true)
for (auto keyResponse = keyClient.GetDeletedKeysSinglePage(); keyResponse.HasPage();
keyResponse.MoveToNextPage())
{
auto keyResponse = keyClient.GetDeletedKeysSinglePage(options);
for (auto& key : keyResponse.Value.Items)
for (auto& key : keyResponse.Items)
{
deletedKeys.emplace_back(key);
}
if (!keyResponse.Value.ContinuationToken)
{
break;
}
options.ContinuationToken = keyResponse.Value.ContinuationToken;
}
if (deletedKeys.size() > 0)
{
@ -99,18 +93,13 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { nam
{
std::vector<DeleteKeyOperation> deletedKeys;
GetPropertiesOfKeysSinglePageOptions options;
while (true)
for (auto keyResponse = keyClient.GetPropertiesOfKeysSinglePage(); keyResponse.HasPage();
keyResponse.MoveToNextPage())
{
auto keyResponse = keyClient.GetPropertiesOfKeysSinglePage(options);
for (auto& key : keyResponse.Value.Items)
for (auto& key : keyResponse.Items)
{
deletedKeys.emplace_back(keyClient.StartDeleteKey(key.Name));
}
if (!keyResponse.Value.ContinuationToken)
{
break;
}
options.ContinuationToken = keyResponse.Value.ContinuationToken;
}
if (deletedKeys.size() > 0)
{

View File

@ -53,18 +53,13 @@ TEST_F(KeyVaultClientTest, GetPropertiesOfKeysOnePage)
// Get Key properties
std::vector<KeyProperties> keyPropertiesList;
GetPropertiesOfKeysSinglePageOptions options;
while (true)
for (auto keyResponse = keyClient.GetPropertiesOfKeysSinglePage(options); keyResponse.HasPage();
keyResponse.MoveToNextPage())
{
auto keyResponse = keyClient.GetPropertiesOfKeysSinglePage(options);
for (auto& key : keyResponse.Value.Items)
for (auto& key : keyResponse.Items)
{
keyPropertiesList.emplace_back(key);
}
if (!keyResponse.Value.ContinuationToken)
{
break;
}
options.ContinuationToken = keyResponse.Value.ContinuationToken;
}
EXPECT_EQ(keyNames.size(), keyPropertiesList.size());
@ -95,18 +90,14 @@ TEST_F(KeyVaultClientTest, GetKeysVersionsOnePage)
// Get Key versions
std::vector<KeyProperties> keyPropertiesList;
GetPropertiesOfKeyVersionsSinglePageOptions getKeyOptions;
while (true)
for (auto keyResponse = keyClient.GetPropertiesOfKeyVersionsSinglePage(keyName);
keyResponse.HasPage();
keyResponse.MoveToNextPage())
{
auto keyResponse = keyClient.GetPropertiesOfKeyVersionsSinglePage(keyName, getKeyOptions);
for (auto& key : keyResponse.Value.Items)
for (auto& key : keyResponse.Items)
{
keyPropertiesList.emplace_back(key);
}
if (!keyResponse.Value.ContinuationToken)
{
break;
}
getKeyOptions.ContinuationToken = keyResponse.Value.ContinuationToken;
}
EXPECT_EQ(expectedVersions, keyPropertiesList.size());
@ -150,19 +141,13 @@ TEST_F(KeyVaultClientTest, GetDeletedKeysOnePage)
// Get all deleted Keys
std::vector<DeletedKey> deletedKeys;
GetDeletedKeysSinglePageOptions options;
while (true)
for (auto keyResponse = keyClient.GetDeletedKeysSinglePage(); keyResponse.HasPage();
keyResponse.MoveToNextPage())
{
auto keyResponse = keyClient.GetDeletedKeysSinglePage(options);
for (auto& key : keyResponse.Value.Items)
for (auto& key : keyResponse.Items)
{
deletedKeys.emplace_back(key);
}
if (!keyResponse.Value.ContinuationToken)
{
break;
}
options.ContinuationToken = keyResponse.Value.ContinuationToken;
}
EXPECT_EQ(keyNames.size(), deletedKeys.size());