Skip to content

Commit

Permalink
feat(binding/python): new behavior testing for python (#3245)
Browse files Browse the repository at this point in the history
* test(bindings/python): New behavior testing.

1. Add pytest
1. Add operator fixture
1. Add `test_sync_write`
1. Update `service_test_s3.yaml`

* refactor(bindings/python): Rename file

1. Rename `test_rw.py` to `test_write.py`

* chore(bindings/python): Add license headers

1. Add license headers to `test_write.py`

* test(bindings/python): Add more cases.

* test(bindings/python): Add redis workflow

* test(bindings/python): Remove redis test.

it seems that this Python binding dose not currently support redis feature.

* test(bindings/python): Load `.env` file before run tests.

* test(bindings/python): Remove `random_file` fixture

* refactor(bindings/python): Use `os.urandom` to create bytes

* test(bindings/python): Update `operator` fixture

1. Find service name by match `OPENDAL_XXX_TEST`

* test(bindings/python): Switch test to xunit-style

1. Switch test to xunit-style.
1. Remove try...except block.
1. Add random part in every file name or dir name.
1. Use `pytest -k TestXXX` select service.
1. Use random size between 1..1024 when generate random file.

---------

Co-authored-by: Xuanwo <[email protected]>
  • Loading branch information
laipz8200 and Xuanwo authored Oct 9, 2023
1 parent 50b07c5 commit 5d4966e
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 1 deletion.
23 changes: 23 additions & 0 deletions .github/workflows/service_test_memory.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,26 @@ jobs:
run: cargo nextest run memory
env:
OPENDAL_MEMORY_TEST: on

python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: "3.11"

- name: Setup Rust toolchain
uses: ./.github/actions/setup

- name: Build with maturin
working-directory: "bindings/python"
run: |
python -m pip install -e .[test]
- name: Test
shell: bash
working-directory: bindings/python
run: pytest -vk TestMemory
env:
OPENDAL_MEMORY_TEST: on
40 changes: 40 additions & 0 deletions .github/workflows/service_test_s3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,43 @@ jobs:
OPENDAL_S3_ACCESS_KEY_ID: minioadmin
OPENDAL_S3_SECRET_ACCESS_KEY: minioadmin
OPENDAL_S3_REGION: us-east-1

python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: "3.11"

- name: Setup MinIO Server
shell: bash
working-directory: fixtures/s3
run: docker-compose -f docker-compose-minio.yml up -d

- name: Setup test bucket
env:
AWS_ACCESS_KEY_ID: "minioadmin"
AWS_SECRET_ACCESS_KEY: "minioadmin"
AWS_EC2_METADATA_DISABLED: "true"
run: aws --endpoint-url http://127.0.0.1:9000/ s3 mb s3://test

- name: Setup Rust toolchain
uses: ./.github/actions/setup

- name: Build with maturin
working-directory: "bindings/python"
run: |
python -m pip install -e .[test]
- name: Test
shell: bash
working-directory: bindings/python
run: pytest -vk TestS3
env:
OPENDAL_S3_TEST: on
OPENDAL_S3_BUCKET: test
OPENDAL_S3_ENDPOINT: "http://127.0.0.1:9000"
OPENDAL_S3_ACCESS_KEY_ID: minioadmin
OPENDAL_S3_SECRET_ACCESS_KEY: minioadmin
OPENDAL_S3_REGION: us-east-1
2 changes: 1 addition & 1 deletion bindings/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ benchmark = [
"boto3-stubs[essential]",
]
docs = ["pdoc"]
test = ["behave"]
test = ["behave", "pytest", "python-dotenv"]

[project.urls]
Documentation = "https://opendal.apache.org/docs/python/opendal.html"
Expand Down
21 changes: 21 additions & 0 deletions bindings/python/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 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 dotenv import load_dotenv


load_dotenv()
125 changes: 125 additions & 0 deletions bindings/python/tests/test_services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# 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
from abc import ABC
from uuid import uuid4
from random import randint

import opendal
import pytest


class AbstractTestSuite(ABC):
service_name = ""

def setup_method(self):
# Read arguments from envs.
prefix = f"opendal_{self.service_name}_"
self.config = {}
for key in os.environ.keys():
if key.lower().startswith(prefix):
self.config[key[len(prefix) :].lower()] = os.environ.get(key)

# Check if current test be enabled.
test_flag = self.config.get("test", "")
if test_flag != "on" and test_flag != "true":
raise ValueError(f"Service {self.service_name} test is not enabled.")

self.operator = opendal.Operator(self.service_name, **self.config)

def test_sync_read(self):
size = randint(1, 1024)
filename = f"random_file_{str(uuid4())}"
content = os.urandom(size)
self.operator.write(filename, content)

read_content = self.operator.read(filename)
assert read_content is not None
assert read_content == content

def test_sync_read_stat(self):
size = randint(1, 1024)
filename = f"random_file_{str(uuid4())}"
content = os.urandom(size)
self.operator.write(filename, content)

metadata = self.operator.stat(filename)
assert metadata is not None
assert metadata.content_length == len(content)
assert metadata.mode.is_file()

def test_sync_read_not_exists(self):
with pytest.raises(FileNotFoundError):
self.operator.read(str(uuid4()))

def test_sync_write(self):
size = randint(1, 1024)
filename = f"test_file_{str(uuid4())}.txt"
content = os.urandom(size)
size = len(content)
self.operator.write(filename, content)
metadata = self.operator.stat(filename)
assert metadata is not None
assert metadata.mode.is_file()
assert metadata.content_length == size

self.operator.delete(filename)

def test_sync_write_with_non_ascii_name(self):
size = randint(1, 1024)
filename = f"❌😱中文_{str(uuid4())}.test"
content = os.urandom(size)
size = len(content)
self.operator.write(filename, content)
metadata = self.operator.stat(filename)
assert metadata is not None
assert metadata.mode.is_file()
assert metadata.content_length == size

self.operator.delete(filename)

def test_sync_create_dir(self):
path = f"test_dir_{str(uuid4())}/"
self.operator.create_dir(path)
metadata = self.operator.stat(path)
assert metadata is not None
assert metadata.mode.is_dir()

self.operator.delete(path)

def test_sync_delete(self):
size = randint(1, 1024)
filename = f"test_file_{str(uuid4())}.txt"
content = os.urandom(size)
size = len(content)
self.operator.write(filename, content)
self.operator.delete(filename)
with pytest.raises(FileNotFoundError):
self.operator.stat(filename)


class TestS3(AbstractTestSuite):
service_name = "s3"


class TestFS(AbstractTestSuite):
service_name = "fs"


class TestMemory(AbstractTestSuite):
service_name = "memory"

0 comments on commit 5d4966e

Please sign in to comment.