blob: aabdc3bd472a23e4321f1d93cb79020ee9ccfdf1 [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.
*/
// Unique step-class prefix so the generated CukeObject<n> symbols do not clash with the other
// step file when linked together (see background_steps.cpp for details).
#define CUKE_OBJECT_PREFIX IggyBddMessaging
#include <gtest/gtest.h>
#include <cucumber-cpp/autodetect.hpp>
#include <cstddef>
#include <cstdint>
#include <string>
#include "world.hpp"
GIVEN("^I have no streams in the system$") {
cucumber::ScenarioScope<bdd::GlobalContext> context;
ASSERT_TRUE(context->client.has_value());
const auto streams = context->client->GetStreams();
EXPECT_EQ(streams.size(), static_cast<std::size_t>(0));
}
WHEN("^I create a stream with name \"([^\"]{1,255})\"$") {
REGEX_PARAM(std::string, name);
cucumber::ScenarioScope<bdd::GlobalContext> context;
context->client->CreateStream(name);
}
THEN("^the stream should be created successfully$") {
cucumber::ScenarioScope<bdd::GlobalContext> context;
const auto streams = context->client->GetStreams();
EXPECT_EQ(streams.size(), static_cast<std::size_t>(1));
}
THEN("^the stream should have name \"([^\"]{1,255})\"$") {
REGEX_PARAM(std::string, name);
cucumber::ScenarioScope<bdd::GlobalContext> context;
const auto stream = context->client->GetStream(iggy::Identifier::Numeric(0));
EXPECT_EQ(stream.Name(), name);
}
WHEN("^I create a topic with name \"([^\"]{1,255})\" in stream ([0-9]+) with ([0-9]+) partitions$") {
REGEX_PARAM(std::string, topic_name);
REGEX_PARAM(int, stream_id);
REGEX_PARAM(int, partitions_count);
cucumber::ScenarioScope<bdd::GlobalContext> context;
iggy::TopicCreateOptions options;
options.SetPartitionsCount(static_cast<std::uint32_t>(partitions_count))
.SetCompressionAlgorithm(iggy::CompressionAlgorithm::None())
.SetMessageExpiry(iggy::Expiry::NeverExpire());
context->client->CreateTopic(iggy::Identifier::Numeric(static_cast<std::uint32_t>(stream_id)), topic_name, options);
}
THEN("^the topic should be created successfully$") {
cucumber::ScenarioScope<bdd::GlobalContext> context;
const auto stream = context->client->GetStream(iggy::Identifier::Numeric(0));
EXPECT_FALSE(stream.Topics().empty());
}
THEN("^the topic should have name \"([^\"]{1,255})\"$") {
REGEX_PARAM(std::string, name);
cucumber::ScenarioScope<bdd::GlobalContext> context;
const auto stream = context->client->GetStream(iggy::Identifier::Numeric(0));
ASSERT_FALSE(stream.Topics().empty());
EXPECT_EQ(stream.Topics()[0].Name(), name);
}
THEN("^the topic should have ([0-9]+) partitions$") {
REGEX_PARAM(int, partitions_count);
cucumber::ScenarioScope<bdd::GlobalContext> context;
const auto stream = context->client->GetStream(iggy::Identifier::Numeric(0));
ASSERT_FALSE(stream.Topics().empty());
EXPECT_EQ(stream.Topics()[0].PartitionsCount(), static_cast<std::uint32_t>(partitions_count));
}
WHEN("^I send ([0-9]+) messages to stream ([0-9]+), topic ([0-9]+), partition ([0-9]+)$") {
REGEX_PARAM(int, message_count);
REGEX_PARAM(int, stream_id);
REGEX_PARAM(int, topic_id);
REGEX_PARAM(int, partition_id);
cucumber::ScenarioScope<bdd::GlobalContext> context;
std::vector<iggy::IggyMessageToSend> messages;
for (int index = 0; index < message_count; ++index) {
// Assign an explicit, 1-based id so the last-sent/last-polled comparison is meaningful.
messages.push_back(
iggy::IggyMessageToSend::Create(bdd::expected_payload(static_cast<std::uint32_t>(index)), {},
static_cast<absl::uint128>(static_cast<std::uint64_t>(index) + 1)));
}
context->client->SendMessages(iggy::Identifier::Numeric(static_cast<std::uint32_t>(stream_id)),
iggy::Identifier::Numeric(static_cast<std::uint32_t>(topic_id)),
iggy::Partitioning::PartitionId(static_cast<std::uint32_t>(partition_id)), messages);
context->last_sent_payload = bdd::expected_payload(static_cast<std::uint32_t>(message_count - 1));
context->last_sent_id_lo = static_cast<std::uint64_t>(message_count);
}
THEN("^all messages should be sent successfully$") {
// SendMessages() in the WHEN step throws on failure, so reaching this step means the batch
// was accepted; there is no client-side count to assert (the Rust suite is a no-op here too).
}
WHEN("^I poll messages from stream ([0-9]+), topic ([0-9]+), partition ([0-9]+) starting from offset ([0-9]+)$") {
REGEX_PARAM(int, stream_id);
REGEX_PARAM(int, topic_id);
REGEX_PARAM(int, partition_id);
REGEX_PARAM(int, offset);
cucumber::ScenarioScope<bdd::GlobalContext> context;
const auto polled = context->client->PollMessages(
iggy::Identifier::Numeric(static_cast<std::uint32_t>(stream_id)),
iggy::Identifier::Numeric(static_cast<std::uint32_t>(topic_id)), static_cast<std::uint32_t>(partition_id),
iggy::Consumer::Single(iggy::Identifier::Numeric(1)),
iggy::PollingStrategy::Offset(static_cast<std::uint64_t>(offset)), 100, false);
context->polled.count = polled.Count();
context->polled.offsets.clear();
context->polled.id_los.clear();
context->polled.payloads.clear();
for (const auto &message : polled.Messages()) {
context->polled.offsets.push_back(message.Offset());
context->polled.id_los.push_back(absl::Uint128Low64(message.Id()));
const auto &payload = message.Payload();
context->polled.payloads.emplace_back(payload.begin(), payload.end());
}
}
THEN("^I should receive ([0-9]+) messages$") {
REGEX_PARAM(int, expected_count);
cucumber::ScenarioScope<bdd::GlobalContext> context;
EXPECT_EQ(context->polled.count, static_cast<std::uint32_t>(expected_count));
EXPECT_EQ(context->polled.payloads.size(), static_cast<std::size_t>(expected_count));
}
THEN("^the messages should have sequential offsets from ([0-9]+) to ([0-9]+)$") {
REGEX_PARAM(int, from);
REGEX_PARAM(int, to);
cucumber::ScenarioScope<bdd::GlobalContext> context;
ASSERT_EQ(context->polled.offsets.size(), static_cast<std::size_t>(to - from + 1));
for (int offset = from; offset <= to; ++offset) {
EXPECT_EQ(context->polled.offsets[static_cast<std::size_t>(offset - from)], static_cast<std::uint64_t>(offset));
}
}
THEN("^each message should have the expected payload content$") {
cucumber::ScenarioScope<bdd::GlobalContext> context;
for (std::size_t index = 0; index < context->polled.payloads.size(); ++index) {
EXPECT_EQ(context->polled.payloads[index], bdd::expected_payload(static_cast<std::uint32_t>(index)));
}
}
THEN("^the last polled message should match the last sent message$") {
cucumber::ScenarioScope<bdd::GlobalContext> context;
ASSERT_FALSE(context->polled.payloads.empty());
EXPECT_EQ(context->polled.payloads.back(), context->last_sent_payload);
EXPECT_EQ(context->polled.id_los.back(), context->last_sent_id_lo);
}