Skip to content

Commit

Permalink
tests: add retry conformance test framework and test always idempoten…
Browse files Browse the repository at this point in the history
…t operations (#450)

* initial tests for retry strategy conformance tests implementation

* revise helper methods to interact with Retry Test API

* add helper to delete retry test

* handle exceptions in helper methods

* remove try except

* change payload key to instructions to align emulator change

* rename and revise to loop through each case and method

* wip populate resources to conf tests

* add logic to populate fixture resources

* add helper method to populate fixture hmacy key

* revise endpoints and 2 clients

* add assertions to testdata scenarios

* add logic for preconditions wip

* add mapping scenarios and formatting for readability

* add library methods to method invocation mapping and json

* lint

* refactor using **kwargs

* remove unused module and fix lint

* handle misused arguments following style guide

* handle unused arguments

* wip: add library methods to mapping and json

* add client_options to resource populating client

* log warnings and revise try except blocks

* update schema for S1 and S2

* fix lint and mark error

* move retry conformance tests to separate folder

* update noxfile

* relocate conformance tests

* add S1 S2 tests and delete json file

* lint and clean comments

* add S2 object library methods

* address comments

* change test parametrization to separate test cases and address comments

* add assertion message and display library method name

* add multiple lib methods and revise assertion message

* add S2 entry library methods after emulator fix

* address comments

* revise test case structure using python globals

* revise library methods naming to start with class name

* unify library method signatures

* cleanup code

* use pytest fixtures to populate resources

* address comments and update docstrings

* address comments. change to use anonymous credentials

* update descriptions
  • Loading branch information
cojenco committed Aug 19, 2021
1 parent 18241b2 commit bd72f5d
Show file tree
Hide file tree
Showing 5 changed files with 1,051 additions and 0 deletions.
34 changes: 34 additions & 0 deletions noxfile.py
Expand Up @@ -30,6 +30,9 @@
DEFAULT_PYTHON_VERSION = "3.8"
SYSTEM_TEST_PYTHON_VERSIONS = ["2.7", "3.8"]
UNIT_TEST_PYTHON_VERSIONS = ["2.7", "3.6", "3.7", "3.8", "3.9"]
CONFORMANCE_TEST_PYTHON_VERSIONS = ["3.8"]

_DEFAULT_STORAGE_HOST = "https://storage.googleapis.com"

CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute()

Expand Down Expand Up @@ -148,6 +151,37 @@ def system(session):
session.run("py.test", "--quiet", system_test_folder_path, *session.posargs)


@nox.session(python=CONFORMANCE_TEST_PYTHON_VERSIONS)
def conftest_retry(session):
"""Run the retry conformance test suite."""
conformance_test_path = os.path.join("tests", "conformance.py")
conformance_test_folder_path = os.path.join("tests", "conformance")

# Environment check: Only run tests if the STORAGE_EMULATOR_HOST is set.
if (
os.environ.get("STORAGE_EMULATOR_HOST", _DEFAULT_STORAGE_HOST)
== _DEFAULT_STORAGE_HOST
):
session.skip("Set STORAGE_EMULATOR_HOST to run, skipping")

conformance_test_exists = os.path.exists(conformance_test_path)
conformance_test_folder_exists = os.path.exists(conformance_test_folder_path)
# Environment check: only run tests if found.
if not conformance_test_exists and not conformance_test_folder_exists:
session.skip("Conformance tests were not found")

session.install("pytest",)
session.install("-e", ".")

# Run py.test against the conformance tests.
if conformance_test_exists:
session.run("py.test", "--quiet", conformance_test_path, *session.posargs)
if conformance_test_folder_exists:
session.run(
"py.test", "--quiet", conformance_test_folder_path, *session.posargs
)


@nox.session(python=DEFAULT_PYTHON_VERSION)
def cover(session):
"""Run the final coverage report.
Expand Down
24 changes: 24 additions & 0 deletions tests/conformance/__init__.py
@@ -0,0 +1,24 @@
# Copyright 2021 Google LLC
#
# Licensed 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 io
import json
import os


def _read_local_json(json_file):
here = os.path.dirname(__file__)
json_path = os.path.abspath(os.path.join(here, json_file))
with io.open(json_path, "r", encoding="utf-8-sig") as fileobj:
return json.load(fileobj)
262 changes: 262 additions & 0 deletions tests/conformance/retry_strategy_test_data.json
@@ -0,0 +1,262 @@
{
"retryStrategyTests": [
{
"id": 1,
"description": "always idempotent",
"cases": [
{
"instructions": [
"return-503",
"return-503"
]
}
],
"methods": [
{
"name": "storage.bucket_acl.get",
"resources": [
"BUCKET"
]
},
{
"name": "storage.bucket_acl.list",
"resources": [
"BUCKET"
]
},
{
"name": "storage.buckets.delete",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.buckets.get",
"resources": [
"BUCKET"
]
},
{
"name": "storage.buckets.getIamPolicy",
"resources": [
"BUCKET"
]
},
{
"name": "storage.buckets.insert",
"resources": []
},
{
"name": "storage.buckets.list",
"resources": [
"BUCKET"
]
},
{
"name": "storage.buckets.lockRententionPolicy",
"resources": [
"BUCKET"
]
},
{
"name": "storage.buckets.testIamPermission",
"resources": [
"BUCKET"
]
},
{
"name": "storage.default_object_acl.get",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.default_object_acl.list",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.hmacKey.delete",
"resources": []
},
{
"name": "storage.hmacKey.get",
"resources": []
},
{
"name": "storage.hmacKey.list",
"resources": []
},
{
"name": "storage.notifications.delete",
"resources": [
"BUCKET",
"NOTIFICATION"
]
},
{
"name": "storage.notifications.get",
"resources": [
"BUCKET",
"NOTIFICATION"
]
},
{
"name": "storage.notifications.list",
"resources": [
"BUCKET",
"NOTIFICATION"
]
},
{
"name": "storage.object_acl.get",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.object_acl.list",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.objects.get",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.objects.list",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.serviceaccount.get",
"resources": []
}
],
"preconditionProvided": false,
"expectSuccess": true
},
{
"id": 2,
"description": "conditionally idempotent retries when precondition is present",
"cases": [
{
"instructions": [
"return-503",
"return-503"
]
}
],
"methods": [
{
"name": "storage.buckets.patch",
"resources": [
"BUCKET"
]
},
{
"name": "storage.buckets.setIamPolicy",
"resources": [
"BUCKET"
]
},
{
"name": "storage.buckets.update",
"resources": [
"BUCKET"
]
},
{
"name": "storage.hmacKey.update",
"resources": []
},
{
"name": "storage.objects.compose",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.objects.copy",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.objects.delete",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.objects.insert",
"resources": [
"BUCKET"
]
},
{
"name": "storage.objects.patch",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.objects.rewrite",
"resources": [
"BUCKET",
"OBJECT"
]
},
{
"name": "storage.objects.update",
"resources": [
"BUCKET",
"OBJECT"
]
}
],
"preconditionProvided": true,
"expectSuccess": true
},
{
"id": 3,
"description": "conditionally idempotent no retries when precondition is absent",
"cases": [
{
"instructions": []
}
],
"methods": [],
"preconditionProvided": false,
"expectSuccess": false
},
{
"id": 4,
"description": "non idempotent",
"cases": [
{
"instructions": []
}
],
"methods": [],
"preconditionProvided": false,
"expectSuccess": false
}
]
}

0 comments on commit bd72f5d

Please sign in to comment.