You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2023/03/17 06:12:27 UTC

[incubator-opendal] branch bdd-tests-for-bindings created (now 57416051)

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

xuanwo pushed a change to branch bdd-tests-for-bindings
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git


      at 57416051 feat(tests): Introducing BDD tests for all bindings

This branch includes the following new commits:

     new 57416051 feat(tests): Introducing BDD tests for all bindings

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[incubator-opendal] 01/01: feat(tests): Introducing BDD tests for all bindings

Posted by xu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch bdd-tests-for-bindings
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git

commit 574160511371b108199d1d2aa6d944fc75e58135
Author: Xuanwo <gi...@xuanwo.io>
AuthorDate: Fri Mar 17 14:12:08 2023 +0800

    feat(tests): Introducing BDD tests for all bindings
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
---
 .github/workflows/bindings_python.yml   |   4 +-
 bindings/python/README.md               |   2 +-
 bindings/python/pyproject.toml          |   2 +-
 bindings/python/tests/binding.feature   |   1 +
 bindings/python/tests/steps/binding.py  |  79 ++++++++++++++++++++++
 bindings/python/tests/test_core.py      | 114 --------------------------------
 bindings/tests/README.md                |   3 +
 bindings/tests/features/binding.feature |  34 ++++++++++
 licenserc.toml                          |   1 +
 9 files changed, 122 insertions(+), 118 deletions(-)

diff --git a/.github/workflows/bindings_python.yml b/.github/workflows/bindings_python.yml
index 610cea3a..c75197fb 100644
--- a/.github/workflows/bindings_python.yml
+++ b/.github/workflows/bindings_python.yml
@@ -51,10 +51,10 @@ jobs:
         working-directory: "bindings/python"
         run: |
           python -m pip install -e .[test]
-      - name: Run pytest
+      - name: Run behave
         working-directory: "bindings/python"
         run: |
-          python -m pytest
+          python -m behave tests
 
   linux:
     runs-on: ubuntu-latest
diff --git a/bindings/python/README.md b/bindings/python/README.md
index 473668e4..03a4bcb1 100644
--- a/bindings/python/README.md
+++ b/bindings/python/README.md
@@ -62,5 +62,5 @@ Running some tests:
 
 ```shell
 maturin develop -E test
-pytest
+behave tests
 ```
diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml
index 356b6f63..597b7311 100644
--- a/bindings/python/pyproject.toml
+++ b/bindings/python/pyproject.toml
@@ -32,7 +32,7 @@ readme = "README.md"
 requires-python = ">=3.7"
 
 [project.optional-dependencies]
-test = ["pytest", "pytest-asyncio"]
+test = ["pytest", "pytest-asyncio", "behave"]
 
 [project.urls]
 Documentation = "https://docs.rs/opendal/"
diff --git a/bindings/python/tests/binding.feature b/bindings/python/tests/binding.feature
new file mode 120000
index 00000000..fcb71d38
--- /dev/null
+++ b/bindings/python/tests/binding.feature
@@ -0,0 +1 @@
+../../tests/features/binding.feature
\ No newline at end of file
diff --git a/bindings/python/tests/steps/binding.py b/bindings/python/tests/steps/binding.py
new file mode 100644
index 00000000..7b33204f
--- /dev/null
+++ b/bindings/python/tests/steps/binding.py
@@ -0,0 +1,79 @@
+# 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.
+
+from behave import given, when, then
+from behave.api.async_step import async_run_until_complete
+import asyncio
+import opendal
+
+@given('A new OpenDAL Blocking Operator')
+def step_impl(context):
+    context.op = opendal.Operator("memory")
+
+@when('Blocking write path "{filename}" with content "{content}"')
+def step_impl(context, filename, content):
+    context.op.write(filename, content.encode())
+
+@then('The blocking file "{filename}" should exist')
+def step_impl(context, filename):
+    context.op.stat(filename)
+
+@then('The blocking file "{filename}" entry mode must be file')
+def step_impl(context, filename):
+    assert context.op.stat(filename).mode.is_file()
+
+@then('The blocking file "{filename}" content length must be "{size:d}"')
+def step_impl(context, filename, size):
+    assert context.op.stat(filename).content_length == size
+
+@then('The blocking file "{filename}" must have content "{content}"')
+def step_impl(context, filename, content):
+    bs = context.op.read(filename)
+    assert bs == content.encode()
+
+@given('A new OpenDAL Async Operator')
+@async_run_until_complete
+async def step_impl(context):
+    context.op = opendal.AsyncOperator("memory")
+
+@when('Async write path "{filename}" with content "{content}"')
+@async_run_until_complete
+async def step_impl(context, filename, content):
+    await context.op.write(filename, content.encode())
+
+@then('The async file "{filename}" should exist')
+@async_run_until_complete
+async def step_impl(context, filename):
+    await context.op.stat(filename)
+
+@then('The async file "{filename}" entry mode must be file')
+@async_run_until_complete
+async def step_impl(context, filename):
+    meta = await context.op.stat(filename)
+    assert meta.mode.is_file()
+
+@then('The async file "{filename}" content length must be "{size:d}"')
+@async_run_until_complete
+async def step_impl(context, filename, size):
+    meta = await context.op.stat(filename)
+    assert meta.content_length == size
+
+@then('The async file "{filename}" must have content "{content}"')
+@async_run_until_complete
+async def step_impl(context, filename, content):
+    bs = await context.op.read(filename)
+    assert bs == content.encode()
diff --git a/bindings/python/tests/test_core.py b/bindings/python/tests/test_core.py
deleted file mode 100644
index 6322e26a..00000000
--- a/bindings/python/tests/test_core.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# 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.
-
-import os
-import opendal
-import pytest
-from opendal import layers
-
-
-def test_blocking():
-    op = opendal.Operator("memory", layers=[layers.RetryLayer()])
-    op.write("test", b"Hello, World!")
-    bs = op.read("test")
-    assert bs == b"Hello, World!", bs
-    meta = op.stat("test")
-    assert meta.content_length == 13, meta.content_length
-    assert meta.mode.is_file()
-    assert [str(entry) for entry in op.list("/")] == ["test"]
-    assert [str(entry) for entry in op.scan("/")] == ["test"]
-
-    reader = op.open_reader("test")
-    bs = reader.read(5)
-    assert bs == b"Hello", bs
-    bs = reader.read()
-    assert bs == b", World!", bs
-    reader.seek(0, os.SEEK_SET)
-    bs = reader.read()
-    assert bs == b"Hello, World!", bs
-    with op.open_reader("test") as f:
-        bs = f.read()
-        assert bs == b"Hello, World!", bs
-
-    op.delete("test")
-
-    op.create_dir("test/")
-
-
-@pytest.mark.asyncio
-async def test_async():
-    op = opendal.AsyncOperator(
-        "memory", layers=[layers.RetryLayer(), layers.ConcurrentLimitLayer(10)]
-    )
-    await op.write("test", b"Hello, World!")
-    bs = await op.read("test")
-    assert bs == b"Hello, World!", bs
-    meta = await op.stat("test")
-    assert meta.content_length == 13, meta.content_length
-    assert meta.mode.is_file()
-    assert [str(entry) async for entry in await op.list("/")] == ["test"]
-    assert [str(entry) async for entry in await op.scan("/")] == ["test"]
-
-    reader = op.open_reader("test")
-    bs = await reader.read(5)
-    assert bs == b"Hello", bs
-    bs = await reader.read()
-    assert bs == b", World!", bs
-    await reader.seek(0, os.SEEK_SET)
-    bs = await reader.read()
-    assert bs == b"Hello, World!", bs
-    async with op.open_reader("test") as f:
-        bs = await f.read()
-        assert bs == b"Hello, World!", bs
-
-    await op.delete("test")
-
-    await op.create_dir("test/")
-
-
-def test_blocking_fs(tmp_path):
-    op = opendal.Operator("fs", root=str(tmp_path))
-    op.write("test.txt", b"Hello, World!")
-    bs = op.read("test.txt")
-    assert bs == b"Hello, World!", bs
-    meta = op.stat("test.txt")
-    assert meta.content_length == 13, meta.content_length
-    assert [str(entry) for entry in op.list("/")] == ["test.txt"]
-    assert [str(entry) for entry in op.scan("/")] == ["test.txt", "/"]
-
-    op.create_dir("test/")
-
-
-@pytest.mark.asyncio
-async def test_async_fs(tmp_path):
-    op = opendal.AsyncOperator("fs", root=str(tmp_path))
-    await op.write("test.txt", b"Hello, World!")
-    bs = await op.read("test.txt")
-    assert bs == b"Hello, World!", bs
-    meta = await op.stat("test.txt")
-    assert meta.content_length == 13, meta.content_length
-
-    await op.create_dir("test/")
-
-
-def test_error():
-    op = opendal.Operator("memory")
-    with pytest.raises(FileNotFoundError):
-        op.read("test")
-
-    with pytest.raises(NotImplementedError):
-        opendal.Operator("foobar")
diff --git a/bindings/tests/README.md b/bindings/tests/README.md
new file mode 100644
index 00000000..5c49d3f6
--- /dev/null
+++ b/bindings/tests/README.md
@@ -0,0 +1,3 @@
+# OpenDAL Binding Tests
+
+OpenDAL will use [Cucumber](https://github.com/cucumber) for [BDD](Behaviour-Driven Development) tests. This module will provide [Gherkin](https://cucumber.io/docs/gherkin/) files and all bindings should implement againest them.
diff --git a/bindings/tests/features/binding.feature b/bindings/tests/features/binding.feature
new file mode 100644
index 00000000..22c08ab1
--- /dev/null
+++ b/bindings/tests/features/binding.feature
@@ -0,0 +1,34 @@
+# 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.
+
+Feature: OpenDAL Binding
+
+    Scenario: OpenDAL Blocking Operations
+        Given A new OpenDAL Blocking Operator
+        When Blocking write path "test" with content "Hello, World!"
+        Then The blocking file "test" should exist
+        Then The blocking file "test" entry mode must be file
+        Then The blocking file "test" content length must be "13"
+        Then The blocking file "test" must have content "Hello, World!"
+
+    Scenario: OpenDAL Async Operations
+        Given A new OpenDAL Async Operator
+        When Async write path "test" with content "Hello, World!"
+        Then The async file "test" should exist
+        Then The async file "test" entry mode must be file
+        Then The async file "test" content length must be "13"
+        Then The async file "test" must have content "Hello, World!"
diff --git a/licenserc.toml b/licenserc.toml
index 645fbf31..d4a7f6c3 100644
--- a/licenserc.toml
+++ b/licenserc.toml
@@ -36,6 +36,7 @@ excludes = [
   "bindings/python/opendal.pyi",
   "**/__pycache__",
   "**/.pytest_cache",
+  "**/venv/**",
   "website/build/**",
   "website/static/.nojekyll",
   "website/.docusaurus",