This is an automated email from the ASF dual-hosted git repository.

gkoszyk pushed a commit to branch io_uring_tpc
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/io_uring_tpc by this push:
     new 4ae1fbcd feat(io_uring): adapt rust, python and csharp bdd tests to 
new interface (#2241)
4ae1fbcd is described below

commit 4ae1fbcdba0076367656e38620c8b0e87fd1c703
Author: Hubert Gruszecki <[email protected]>
AuthorDate: Mon Oct 6 17:07:38 2025 +0200

    feat(io_uring): adapt rust, python and csharp bdd tests to new interface 
(#2241)
---
 bdd/docker-compose.yml                             | 43 ++++++++----------
 bdd/python/Dockerfile                              |  4 +-
 bdd/python/tests/test_basic_messaging.py           | 35 +++++++--------
 bdd/rust/tests/steps/streams.rs                    | 16 +++----
 bdd/rust/tests/steps/topics.rs                     | 16 ++-----
 bdd/scenarios/basic_messaging.feature              | 12 ++---
 core/server/src/tcp/tcp_listener.rs                |  1 -
 .../Iggy_SDK.Tests.BDD/Context/TestContext.cs      | 51 +++++++---------------
 .../BasicMessagingOperationsSteps.cs               | 21 ++++-----
 foreign/python/src/client.rs                       | 23 +++++-----
 scripts/run-bdd-tests.sh                           | 15 +++++++
 11 files changed, 99 insertions(+), 138 deletions(-)

diff --git a/bdd/docker-compose.yml b/bdd/docker-compose.yml
index 95d64d44..40fd2c7a 100644
--- a/bdd/docker-compose.yml
+++ b/bdd/docker-compose.yml
@@ -27,10 +27,22 @@ services:
         PREBUILT_IGGY_CLI: ${IGGY_CLI_PATH:-target/debug/iggy}
         LIBC: glibc
         PROFILE: debug
-    command: ["--fresh"]
+    command: ["--fresh", "--with-default-root-credentials"]
+    cap_add:
+      - SYS_NICE
+    security_opt:
+      - seccomp:unconfined
+    ulimits:
+      memlock:
+        soft: -1
+        hard: -1
+    healthcheck:
+      test: ["CMD", "/usr/local/bin/iggy", "ping"]
+      interval: 1s
+      timeout: 3s
+      retries: 30
+      start_period: 2s
     environment:
-      - IGGY_ROOT_USERNAME=iggy
-      - IGGY_ROOT_PASSWORD=iggy
       - RUST_LOG=info
       - IGGY_SYSTEM_PATH=local_data
       - IGGY_TCP_ADDRESS=0.0.0.0:8090
@@ -105,7 +117,8 @@ services:
       context: ..
       dockerfile: bdd/node/Dockerfile
     depends_on:
-      - iggy-server
+      iggy-server:
+        condition: service_healthy
     environment:
       - IGGY_ROOT_USERNAME=iggy
       - IGGY_ROOT_PASSWORD=iggy
@@ -132,27 +145,5 @@ networks:
   iggy-bdd-network:
     driver: bridge
 
-  node-bdd:
-    build:
-      context: ..
-      dockerfile: bdd/node/Dockerfile
-    depends_on:
-      iggy-server:
-        condition: service_healthy
-    environment:
-      - IGGY_TCP_ADDRESS=iggy-server:8090
-    command: ["npm", "run", "test:bdd"]
-
-  csharp-bdd:
-    build:
-      context: ..
-      dockerfile: bdd/csharp/Dockerfile
-    depends_on:
-      iggy-server:
-        condition: service_healthy
-    environment:
-      - IGGY_TCP_ADDRESS=iggy-server:8090
-    command: ["dotnet", "test"]
-    
 volumes:
   iggy_data:
diff --git a/bdd/python/Dockerfile b/bdd/python/Dockerfile
index 7b7b3770..4ee7961a 100644
--- a/bdd/python/Dockerfile
+++ b/bdd/python/Dockerfile
@@ -41,8 +41,8 @@ WORKDIR /workspace/foreign/python
 RUN pip3 install --no-cache-dir -r /workspace/bdd/python/requirements.txt
 
 # Build and install the Iggy Python SDK
-RUN maturin build --out dist && \
-    pip3 install dist/*.whl
+RUN maturin build --interpreter python3 --out dist && \
+    pip3 install dist/*cp313*.whl
 
 # Set up BDD test directory
 WORKDIR /app
diff --git a/bdd/python/tests/test_basic_messaging.py 
b/bdd/python/tests/test_basic_messaging.py
index 9abd177c..ea5cc8ed 100644
--- a/bdd/python/tests/test_basic_messaging.py
+++ b/bdd/python/tests/test_basic_messaging.py
@@ -65,12 +65,12 @@ def no_streams_in_system(context):
     pass
 
 
-@when(parsers.parse('I create a stream with ID {stream_id:d} and name 
{stream_name}'))
-def create_stream(context, stream_id, stream_name):
-    """Create a stream with specified ID and name"""
+@when(parsers.parse('I create a stream with name {stream_name}'))
+def create_stream(context, stream_name):
+    """Create a stream with specified name"""
     async def _create():
-        await context.client.create_stream(name=stream_name, 
stream_id=stream_id)
-        context.last_stream_id = stream_id
+        stream = await context.client.create_stream(name=stream_name)
+        context.last_stream_id = stream.id
         context.last_stream_name = stream_name
 
     asyncio.run(_create())
@@ -86,29 +86,27 @@ def stream_created_successfully(context):
     asyncio.run(_verify())
 
 
-@then(parsers.parse('the stream should have ID {stream_id:d} and name 
{stream_name}'))
-def verify_stream_properties(context, stream_id, stream_name):
-    """Verify stream has correct ID and name"""
+@then(parsers.parse('the stream should have name {stream_name}'))
+def verify_stream_properties(context, stream_name):
+    """Verify stream has correct name"""
     async def _verify():
         stream = await context.client.get_stream(stream_name)
         assert stream is not None
-        assert stream.id == stream_id
         assert stream.name == stream_name
 
     asyncio.run(_verify())
 
 
-@when(parsers.parse('I create a topic with ID {topic_id:d} and name 
{topic_name} in stream {stream_id:d} with {partitions:d} partitions'))
-def create_topic(context, topic_id, topic_name, stream_id, partitions):
+@when(parsers.parse('I create a topic with name {topic_name} in stream 
{stream_id:d} with {partitions:d} partitions'))
+def create_topic(context, topic_name, stream_id, partitions):
     """Create a topic with specified parameters"""
     async def _create():
-        await context.client.create_topic(
+        topic = await context.client.create_topic(
             stream=stream_id,
             name=topic_name,
-            partitions_count=partitions,
-            topic_id=topic_id
+            partitions_count=partitions
         )
-        context.last_topic_id = topic_id
+        context.last_topic_id = topic.id
         context.last_topic_name = topic_name
         context.last_topic_partitions = partitions
 
@@ -125,13 +123,12 @@ def topic_created_successfully(context):
     asyncio.run(_verify())
 
 
-@then(parsers.parse('the topic should have ID {topic_id:d} and name 
{topic_name}'))
-def verify_topic_properties(context, topic_id, topic_name):
-    """Verify topic has correct ID and name"""
+@then(parsers.parse('the topic should have name {topic_name}'))
+def verify_topic_properties(context, topic_name):
+    """Verify topic has correct name"""
     async def _verify():
         topic = await context.client.get_topic(context.last_stream_id, 
topic_name)
         assert topic is not None
-        assert topic.id == topic_id
         assert topic.name == topic_name
 
     asyncio.run(_verify())
diff --git a/bdd/rust/tests/steps/streams.rs b/bdd/rust/tests/steps/streams.rs
index f64f680e..f24a6791 100644
--- a/bdd/rust/tests/steps/streams.rs
+++ b/bdd/rust/tests/steps/streams.rs
@@ -33,11 +33,11 @@ pub async fn given_no_streams(world: &mut GlobalContext) {
     );
 }
 
-#[when(regex = r"^I create a stream with ID (\d+) and name (.+)$")]
-pub async fn when_create_stream(world: &mut GlobalContext, stream_id: u32, 
stream_name: String) {
+#[when(regex = r"^I create a stream with name (.+)$")]
+pub async fn when_create_stream(world: &mut GlobalContext, stream_name: 
String) {
     let client = world.client.as_ref().expect("Client should be available");
     let stream = client
-        .create_stream(&stream_name, Some(stream_id))
+        .create_stream(&stream_name)
         .await
         .expect("Should be able to create stream");
 
@@ -53,18 +53,12 @@ pub async fn then_stream_created_successfully(world: &mut 
GlobalContext) {
     );
 }
 
-#[then(regex = r"^the stream should have ID (\d+) and name (.+)$")]
-pub async fn then_stream_has_id_and_name(
-    world: &mut GlobalContext,
-    expected_id: u32,
-    expected_name: String,
-) {
-    let stream_id = world.last_stream_id.expect("Stream should exist");
+#[then(regex = r"^the stream should have name (.+)$")]
+pub async fn then_stream_has_name(world: &mut GlobalContext, expected_name: 
String) {
     let stream_name = world
         .last_stream_name
         .as_ref()
         .expect("Stream should exist");
-    assert_eq!(stream_id, expected_id, "Stream should have expected ID");
     assert_eq!(
         stream_name, &expected_name,
         "Stream should have expected name"
diff --git a/bdd/rust/tests/steps/topics.rs b/bdd/rust/tests/steps/topics.rs
index 93557663..63150f32 100644
--- a/bdd/rust/tests/steps/topics.rs
+++ b/bdd/rust/tests/steps/topics.rs
@@ -20,12 +20,9 @@ use crate::common::global_context::GlobalContext;
 use cucumber::{then, when};
 use iggy::prelude::{CompressionAlgorithm, Identifier, IggyExpiry, 
MaxTopicSize, TopicClient};
 
-#[when(
-    regex = r"^I create a topic with ID (\d+) and name (.+) in stream (\d+) 
with (\d+) partitions$"
-)]
+#[when(regex = r"^I create a topic with name (.+) in stream (\d+) with (\d+) 
partitions$")]
 pub async fn when_create_topic(
     world: &mut GlobalContext,
-    topic_id: u32,
     topic_name: String,
     stream_id: u32,
     partitions_count: u32,
@@ -38,7 +35,6 @@ pub async fn when_create_topic(
             partitions_count,
             CompressionAlgorithm::default(),
             None,
-            Some(topic_id),
             IggyExpiry::NeverExpire,
             MaxTopicSize::ServerDefault,
         )
@@ -58,15 +54,9 @@ pub async fn then_topic_created_successfully(world: &mut 
GlobalContext) {
     );
 }
 
-#[then(regex = r"^the topic should have ID (\d+) and name (.+)$")]
-pub async fn then_topic_has_id_and_name(
-    world: &mut GlobalContext,
-    expected_id: u32,
-    expected_name: String,
-) {
-    let topic_id = world.last_topic_id.expect("Topic should exist");
+#[then(regex = r"^the topic should have name (.+)$")]
+pub async fn then_topic_has_name(world: &mut GlobalContext, expected_name: 
String) {
     let topic_name = world.last_topic_name.as_ref().expect("Topic should 
exist");
-    assert_eq!(topic_id, expected_id, "Topic should have expected ID");
     assert_eq!(
         topic_name, &expected_name,
         "Topic should have expected name"
diff --git a/bdd/scenarios/basic_messaging.feature 
b/bdd/scenarios/basic_messaging.feature
index 1709626e..c13109dc 100644
--- a/bdd/scenarios/basic_messaging.feature
+++ b/bdd/scenarios/basic_messaging.feature
@@ -26,19 +26,19 @@ Feature: Basic Messaging Operations
 
   Scenario: Create stream and send messages
     Given I have no streams in the system
-    When I create a stream with ID 1 and name "test-stream"
+    When I create a stream with name "test-stream"
     Then the stream should be created successfully
-    And the stream should have ID 1 and name "test-stream"
+    And the stream should have name "test-stream"
 
-    When I create a topic with ID 1 and name "test-topic" in stream 1 with 3 
partitions
+    When I create a topic with name "test-topic" in stream 0 with 3 partitions
     Then the topic should be created successfully
-    And the topic should have ID 1 and name "test-topic" 
+    And the topic should have name "test-topic"
     And the topic should have 3 partitions
 
-    When I send 10 messages to stream 1, topic 1, partition 1
+    When I send 10 messages to stream 0, topic 0, partition 0
     Then all messages should be sent successfully
 
-    When I poll messages from stream 1, topic 1, partition 1 starting from 
offset 0
+    When I poll messages from stream 0, topic 0, partition 0 starting from 
offset 0
     Then I should receive 10 messages
     And the messages should have sequential offsets from 0 to 9
     And each message should have the expected payload content
diff --git a/core/server/src/tcp/tcp_listener.rs 
b/core/server/src/tcp/tcp_listener.rs
index 5332ec19..335bb8e4 100644
--- a/core/server/src/tcp/tcp_listener.rs
+++ b/core/server/src/tcp/tcp_listener.rs
@@ -89,7 +89,6 @@ pub async fn start(
             format!("Failed to bind {server_name} server to address: {addr}, 
{err}")
         })?;
     let actual_addr = listener.local_addr().map_err(|e| {
-        // TODO(hubcio): macro doesn't work properly with syntax like {e}
         shard_error!(shard.id, "Failed to get local address: {}", e);
         IggyError::CannotBindToSocket(addr.to_string())
     })?;
diff --git a/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs 
b/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs
index 2c345e6c..a30bdcb3 100644
--- a/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs
+++ b/foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs
@@ -1,31 +1,26 @@
-// // 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.
+// 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.
 
-<<<<<<<< HEAD:foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs
 using Apache.Iggy.Contracts;
 using Apache.Iggy.IggyClient;
 using Apache.Iggy.Messages;
-========
-using Apache.Iggy.Enums;
->>>>>>>> 
master:foreign/csharp/Iggy_SDK.Tests.Integration/Helpers/NameIdHelpers.cs
 
 namespace Apache.Iggy.Tests.BDD.Context;
 
-<<<<<<<< HEAD:foreign/csharp/Iggy_SDK.Tests.BDD/Context/TestContext.cs
 public class TestContext
 {
     public IIggyClient IggyClient { get; set; } = null!;
@@ -35,17 +30,3 @@ public class TestContext
     public List<MessageResponse> PolledMessages { get; set; } = new();
     public Message? LastSendMessage { get; set; }
 }
-========
-public static class ProtocolHelpers
-{
-    public static string GetWithProtocol(this string name, Protocol protocol)
-    {
-        return $"{name}_{protocol.ToString().ToLowerInvariant()}";
-    }
-
-    public static uint GetWithProtocol(this uint id, Protocol protocol)
-    {
-        return id + (uint)protocol * 10;
-    }
-}
->>>>>>>> 
master:foreign/csharp/Iggy_SDK.Tests.Integration/Helpers/NameIdHelpers.cs
diff --git 
a/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/BasicMessagingOperationsSteps.cs
 
b/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/BasicMessagingOperationsSteps.cs
index a25a2202..c83b5fa9 100644
--- 
a/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/BasicMessagingOperationsSteps.cs
+++ 
b/foreign/csharp/Iggy_SDK.Tests.BDD/StepDefinitions/BasicMessagingOperationsSteps.cs
@@ -70,10 +70,10 @@ public class BasicMessagingOperationsSteps
         streams.Count.ShouldBe(0);
     }
 
-    [When(@"I create a stream with ID (\d+) and name (.*)")]
-    public async Task WhenICreateAStreamWithIdAndName(uint streamId, string 
streamName)
+    [When(@"I create a stream with name (.*)")]
+    public async Task WhenICreateAStreamWithName(string streamName)
     {
-        _context.CreatedStream = await 
_context.IggyClient.CreateStreamAsync(streamName, streamId);
+        _context.CreatedStream = await 
_context.IggyClient.CreateStreamAsync(streamName);
     }
 
     [Then(@"the stream should be created successfully")]
@@ -84,19 +84,17 @@ public class BasicMessagingOperationsSteps
         _context.CreatedStream.Name.ShouldNotBeNullOrEmpty();
     }
 
-    [Then(@"the stream should have ID (\d+) and name (.*)")]
-    public void ThenTheStreamShouldHaveIdAndName(uint expectedId, string 
expectedName)
+    [Then(@"the stream should have name (.*)")]
+    public void ThenTheStreamShouldHaveName(string expectedName)
     {
-        _context.CreatedStream!.Id.ShouldBe(expectedId);
         _context.CreatedStream!.Name.ShouldBe(expectedName);
     }
 
-    [When(@"I create a topic with ID (\d+) and name (.*) in stream (\d+) with 
(\d+) partitions")]
-    public async Task 
WhenICreateATopicWithIdAndNameInStreamWithPartitions(uint topicId, string 
topicName,
+    [When(@"I create a topic with name (.*) in stream (\d+) with (\d+) 
partitions")]
+    public async Task WhenICreateATopicWithNameInStreamWithPartitions(string 
topicName,
         uint streamId, uint partitions)
     {
         _context.CreatedTopic = await 
_context.IggyClient.CreateTopicAsync(Identifier.Numeric(streamId),
-            topicId: topicId,
             name: topicName,
             partitionsCount: partitions);
     }
@@ -109,10 +107,9 @@ public class BasicMessagingOperationsSteps
         _context.CreatedTopic.Name.ShouldNotBeNullOrEmpty();
     }
 
-    [Then(@"the topic should have ID (\d+) and name (.*)")]
-    public void ThenTheTopicShouldHaveIdAndName(uint expectedId, string 
expectedName)
+    [Then(@"the topic should have name (.*)")]
+    public void ThenTheTopicShouldHaveName(string expectedName)
     {
-        _context.CreatedTopic!.Id.ShouldBe(expectedId);
         _context.CreatedTopic!.Name.ShouldBe(expectedName);
     }
 
diff --git a/foreign/python/src/client.rs b/foreign/python/src/client.rs
index 93af01ce..31f677e6 100644
--- a/foreign/python/src/client.rs
+++ b/foreign/python/src/client.rs
@@ -137,21 +137,20 @@ impl IggyClient {
     /// Creates a new stream with the provided ID and name.
     ///
     /// Returns Ok(()) on successful stream creation or a PyRuntimeError on 
failure.
-    #[pyo3(signature = (name, stream_id = None))]
-    
#[gen_stub(override_return_type(type_repr="collections.abc.Awaitable[None]", 
imports=("collections.abc")))]
+    #[pyo3(signature = (name))]
+    
#[gen_stub(override_return_type(type_repr="collections.abc.Awaitable[StreamDetails]",
 imports=("collections.abc")))]
     fn create_stream<'a>(
         &self,
         py: Python<'a>,
         name: String,
-        stream_id: Option<u32>,
     ) -> PyResult<Bound<'a, PyAny>> {
         let inner = self.inner.clone();
         future_into_py(py, async move {
-            inner
-                .create_stream(&name, stream_id)
+            let stream = inner
+                .create_stream(&name)
                 .await
                 .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, 
_>(format!("{e:?}")))?;
-            Ok(())
+            Ok(StreamDetails::from(stream))
         })
     }
 
@@ -178,12 +177,12 @@ impl IggyClient {
 
     /// Creates a new topic with the given parameters.
     ///
-    /// Returns Ok(()) on successful topic creation or a PyRuntimeError on 
failure.
+    /// Returns TopicDetails on successful topic creation or a PyRuntimeError 
on failure.
     #[pyo3(
-        signature = (stream, name, partitions_count, compression_algorithm = 
None, topic_id = None, replication_factor = None)
+        signature = (stream, name, partitions_count, compression_algorithm = 
None, replication_factor = None)
     )]
     #[allow(clippy::too_many_arguments)]
-    
#[gen_stub(override_return_type(type_repr="collections.abc.Awaitable[None]", 
imports=("collections.abc")))]
+    
#[gen_stub(override_return_type(type_repr="collections.abc.Awaitable[TopicDetails]",
 imports=("collections.abc")))]
     fn create_topic<'a>(
         &self,
         py: Python<'a>,
@@ -191,7 +190,6 @@ impl IggyClient {
         name: String,
         partitions_count: u32,
         compression_algorithm: Option<String>,
-        topic_id: Option<u32>,
         replication_factor: Option<u8>,
     ) -> PyResult<Bound<'a, PyAny>> {
         let compression_algorithm = match compression_algorithm {
@@ -204,20 +202,19 @@ impl IggyClient {
         let inner = self.inner.clone();
 
         future_into_py(py, async move {
-            inner
+            let topic = inner
                 .create_topic(
                     &stream,
                     &name,
                     partitions_count,
                     compression_algorithm,
                     replication_factor,
-                    topic_id,
                     IggyExpiry::NeverExpire,
                     MaxTopicSize::ServerDefault,
                 )
                 .await
                 .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, 
_>(format!("{e:?}")))?;
-            Ok(())
+            Ok(TopicDetails::from(topic))
         })
     }
 
diff --git a/scripts/run-bdd-tests.sh b/scripts/run-bdd-tests.sh
index 45d334c9..58314c91 100755
--- a/scripts/run-bdd-tests.sh
+++ b/scripts/run-bdd-tests.sh
@@ -33,9 +33,24 @@ cleanup(){
 }
 trap cleanup EXIT INT TERM
 
+# Check if Docker supports cap_add
+check_docker_capabilities(){
+  if ! docker info | grep -q "Security Options"; then
+    log "โš ๏ธ  Warning: Docker may not support security options"
+  fi
+
+  # Verify cap_add is supported by checking docker compose config
+  if ! docker compose config >/dev/null 2>&1; then
+    log "โŒ Error: docker-compose.yml validation failed"
+    exit 1
+  fi
+}
+
 log "๐Ÿงช Running BDD tests for SDK: ${SDK}"
 log "๐Ÿ“ Feature file: ${FEATURE}"
 
+check_docker_capabilities
+
 run_suite(){
   local svc="$1" emoji="$2" label="$3"
   log "${emoji}  ${label}โ€ฆ"

Reply via email to