blob: a5e8c1f81ebeae5db2af615d3a7fc5306f6eb6e1 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.
*/
#pragma once
#include <algorithm>
#include <cstdint>
#include <random>
#include <string>
#include <utility>
#include <gtest/gtest.h>
#include "iggy.hpp"
struct TrackedConsumerGroup {
std::string stream_name;
std::string topic_name;
std::string group_name;
};
class E2ETestFixture : public ::testing::Test {
public:
~E2ETestFixture() override { CleanupBestEffort(); }
void TearDown() override { Cleanup(); }
protected:
iggy::IggyBlockingClient GetLoggedOutHighLevelClient() { return iggy::IggyBlockingClient::Builder().Build(); }
iggy::IggyBlockingClient GetLoggedInHighLevelClient(std::string username = "iggy", std::string password = "iggy") {
auto client = GetLoggedOutHighLevelClient();
client.Connect();
client.Login(std::move(username), std::move(password));
return client;
}
std::string GetRandomName(const std::size_t max_length = 255) {
if (max_length == 0) {
return {};
}
static constexpr char alphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static thread_local std::mt19937 generator(std::random_device{}());
const std::size_t min_length = std::min<std::size_t>(8, max_length);
std::uniform_int_distribution<std::size_t> length_distribution(min_length, max_length);
std::uniform_int_distribution<std::size_t> distribution(0, sizeof(alphabet) - 2);
const std::size_t length = length_distribution(generator);
std::string name;
name.reserve(length);
name.push_back('a');
for (std::size_t i = 1; i < length; ++i) {
name.push_back(alphabet[distribution(generator)]);
}
return name;
}
iggy::UserInfoDetails CreateUser(iggy::IggyBlockingClient &client,
const std::string &username,
const std::string &password,
const iggy::UserStatus status,
std::optional<iggy::Permissions> permissions = std::nullopt) {
auto user = client.CreateUser(username, password, status, permissions);
tracked_user_names_.push_back(username);
return user;
}
void ForgetUser(const std::string &username) {
tracked_user_names_.erase(std::remove(tracked_user_names_.begin(), tracked_user_names_.end(), username),
tracked_user_names_.end());
}
void RenameTrackedUser(const std::string &from, const std::string &to) {
const auto tracked_user = std::find(tracked_user_names_.begin(), tracked_user_names_.end(), from);
ASSERT_NE(tracked_user, tracked_user_names_.end());
*tracked_user = to;
}
void TrackStream(const std::string &stream_name) { tracked_stream_names_.push_back(stream_name); }
void TrackStream(const std::uint32_t stream_id) { tracked_stream_ids_.push_back(stream_id); }
void TrackConsumerGroup(const std::string &stream_name,
const std::string &topic_name,
const std::string &group_name) {
tracked_consumer_groups_.push_back({stream_name, topic_name, group_name});
}
void ForgetTrackedStream(const std::string &stream_name) {
tracked_stream_names_.erase(
std::remove(tracked_stream_names_.begin(), tracked_stream_names_.end(), stream_name),
tracked_stream_names_.end());
for (std::size_t i = 0; i < tracked_consumer_groups_.size();) {
const auto &group = tracked_consumer_groups_[i];
if (group.stream_name == stream_name) {
ForgetTrackedConsumerGroup(group.stream_name, group.topic_name, group.group_name);
continue;
}
++i;
}
}
void ForgetTrackedStream(const std::uint32_t stream_id) {
tracked_stream_ids_.erase(std::remove(tracked_stream_ids_.begin(), tracked_stream_ids_.end(), stream_id),
tracked_stream_ids_.end());
}
void ForgetTrackedConsumerGroup(const std::string &stream_name,
const std::string &topic_name,
const std::string &group_name) {
for (std::size_t i = 0; i < tracked_consumer_groups_.size();) {
const auto &tracked_group = tracked_consumer_groups_[i];
if (tracked_group.stream_name == stream_name && tracked_group.topic_name == topic_name &&
tracked_group.group_name == group_name) {
tracked_consumer_groups_.erase(tracked_consumer_groups_.begin() + i);
continue;
}
++i;
}
}
void Cleanup() {
if (HasTrackedResources()) {
RunAsRoot([this](iggy::IggyBlockingClient &client) {
CleanupConsumerGroups(client);
CleanupStreams(client);
CleanupUsers(client);
});
}
}
private:
void CleanupBestEffort() noexcept {
if (HasTrackedResources()) {
RunAsRootBestEffort([this](iggy::IggyBlockingClient &client) {
CleanupConsumerGroupsBestEffort(client);
CleanupStreamsBestEffort(client);
CleanupUsersBestEffort(client);
});
}
}
void CleanupUsers(iggy::IggyBlockingClient &client) {
for (const auto &username : tracked_user_names_) {
EXPECT_NO_THROW(client.DeleteUser(iggy::Identifier::String(username)));
}
tracked_user_names_.clear();
}
void CleanupUsersBestEffort(iggy::IggyBlockingClient &client) noexcept {
try {
for (const auto &username : tracked_user_names_) {
client.DeleteUser(iggy::Identifier::String(username));
}
} catch (...) {
}
tracked_user_names_.clear();
}
void CleanupStreams(iggy::IggyBlockingClient &client) {
for (const auto &stream_name : tracked_stream_names_) {
EXPECT_NO_THROW(client.DeleteStream(iggy::Identifier::String(stream_name)));
}
for (const auto stream_id : tracked_stream_ids_) {
EXPECT_NO_THROW(client.DeleteStream(iggy::Identifier::Numeric(stream_id)));
}
tracked_stream_names_.clear();
tracked_stream_ids_.clear();
}
void CleanupStreamsBestEffort(iggy::IggyBlockingClient &client) noexcept {
try {
for (const auto &stream_name : tracked_stream_names_) {
client.DeleteStream(iggy::Identifier::String(stream_name));
}
for (const auto stream_id : tracked_stream_ids_) {
client.DeleteStream(iggy::Identifier::Numeric(stream_id));
}
} catch (...) {
}
tracked_stream_names_.clear();
tracked_stream_ids_.clear();
}
void CleanupConsumerGroups(iggy::IggyBlockingClient &client) {
for (const auto &group : tracked_consumer_groups_) {
EXPECT_NO_THROW(client.DeleteConsumerGroup(iggy::Identifier::String(group.stream_name),
iggy::Identifier::String(group.topic_name),
iggy::Identifier::String(group.group_name)));
}
tracked_consumer_groups_.clear();
}
void CleanupConsumerGroupsBestEffort(iggy::IggyBlockingClient &client) noexcept {
try {
for (const auto &group : tracked_consumer_groups_) {
client.DeleteConsumerGroup(iggy::Identifier::String(group.stream_name),
iggy::Identifier::String(group.topic_name),
iggy::Identifier::String(group.group_name));
}
} catch (...) {
}
tracked_consumer_groups_.clear();
}
template <typename Cleanup>
void RunAsRoot(Cleanup &&cleanup) {
auto cleanup_client = iggy::IggyBlockingClient::Builder().Build();
ASSERT_NO_THROW(cleanup_client.Connect());
ASSERT_NO_THROW(cleanup_client.Login("iggy", "iggy"));
cleanup(cleanup_client);
}
template <typename Cleanup>
void RunAsRootBestEffort(Cleanup &&cleanup) noexcept {
try {
auto cleanup_client = iggy::IggyBlockingClient::Builder().Build();
cleanup_client.Connect();
cleanup_client.Login("iggy", "iggy");
cleanup(cleanup_client);
} catch (...) {
}
}
bool HasTrackedResources() const {
return !tracked_consumer_groups_.empty() || !tracked_stream_names_.empty() || !tracked_stream_ids_.empty() ||
!tracked_user_names_.empty();
}
std::vector<std::string> tracked_user_names_;
std::vector<std::string> tracked_stream_names_;
std::vector<std::uint32_t> tracked_stream_ids_;
std::vector<TrackedConsumerGroup> tracked_consumer_groups_;
};