New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Package up base db and atomic db test suites into re-usable classes #1813
Merged
pipermerriam
merged 1 commit into
ethereum:master
from
pipermerriam:piper/re-usable-atomic-and-base-db-test-suites
Aug 13, 2019
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import pytest | ||
|
||
from eth_utils import ValidationError | ||
|
||
from eth.abc import AtomicDatabaseAPI | ||
|
||
|
||
class AtomicDatabaseBatchAPITestSuite: | ||
def test_atomic_batch_set_and_get(self, atomic_db: AtomicDatabaseAPI) -> None: | ||
with atomic_db.atomic_batch() as batch: | ||
batch.set(b'1', b'2') | ||
assert batch.get(b'1') == b'2' | ||
|
||
assert atomic_db.get(b'1') == b'2' | ||
|
||
def test_atomic_db_cannot_recursively_batch(self, atomic_db: AtomicDatabaseAPI) -> None: | ||
with atomic_db.atomic_batch() as batch: | ||
assert not hasattr(batch, 'atomic_batch') | ||
|
||
def test_atomic_db_with_set_and_delete_batch(self, atomic_db: AtomicDatabaseAPI) -> None: | ||
atomic_db[b'key-1'] = b'origin' | ||
|
||
with atomic_db.atomic_batch() as batch: | ||
batch.delete(b'key-1') | ||
|
||
assert b'key-1' not in batch | ||
with pytest.raises(KeyError): | ||
assert batch[b'key-1'] | ||
|
||
with pytest.raises(KeyError): | ||
atomic_db[b'key-1'] | ||
|
||
def test_atomic_db_unbatched_sets_are_immediate(self, atomic_db: AtomicDatabaseAPI) -> None: | ||
atomic_db[b'1'] = b'A' | ||
|
||
with atomic_db.atomic_batch() as batch: | ||
# Unbatched changes are immediate, and show up in batch reads | ||
atomic_db[b'1'] = b'B' | ||
assert batch[b'1'] == b'B' | ||
|
||
batch[b'1'] = b'C1' | ||
|
||
# It doesn't matter what changes happen underlying, all reads now | ||
# show the write applied to the batch db handle | ||
atomic_db[b'1'] = b'C2' | ||
assert batch[b'1'] == b'C1' | ||
|
||
# the batch write should overwrite any intermediate changes | ||
assert atomic_db[b'1'] == b'C1' | ||
|
||
def test_atomic_db_unbatched_deletes_are_immediate(self, atomic_db: AtomicDatabaseAPI) -> None: | ||
atomic_db[b'1'] = b'A' | ||
|
||
with atomic_db.atomic_batch() as batch: | ||
assert b'1' in batch | ||
|
||
# Unbatched changes are immediate, and show up in batch reads | ||
del atomic_db[b'1'] | ||
|
||
assert b'1' not in batch | ||
|
||
batch[b'1'] = b'C1' | ||
|
||
# It doesn't matter what changes happen underlying, all reads now | ||
# show the write applied to the batch db handle | ||
atomic_db[b'1'] = b'C2' | ||
assert batch[b'1'] == b'C1' | ||
|
||
# the batch write should overwrite any intermediate changes | ||
assert atomic_db[b'1'] == b'C1' | ||
|
||
def test_atomic_db_cannot_use_batch_after_context(self, atomic_db: AtomicDatabaseAPI) -> None: | ||
atomic_db[b'1'] = b'A' | ||
|
||
with atomic_db.atomic_batch() as batch: | ||
batch[b'1'] = b'B' | ||
|
||
# set | ||
with pytest.raises(ValidationError): | ||
batch[b'1'] = b'C' | ||
|
||
with pytest.raises(ValidationError): | ||
batch.set(b'1', b'C') | ||
|
||
# get | ||
with pytest.raises(ValidationError): | ||
batch[b'1'] | ||
|
||
with pytest.raises(ValidationError): | ||
batch.get(b'1') | ||
|
||
# exists | ||
with pytest.raises(ValidationError): | ||
b'1' in batch | ||
|
||
with pytest.raises(ValidationError): | ||
batch.exists(b'1') | ||
|
||
# delete | ||
with pytest.raises(ValidationError): | ||
del batch[b'1'] | ||
|
||
with pytest.raises(ValidationError): | ||
batch.delete(b'1') | ||
|
||
# none of the invalid changes above should change the original db | ||
assert atomic_db[b'1'] == b'B' | ||
|
||
def test_atomic_db_with_reverted_delete_batch(self, atomic_db: AtomicDatabaseAPI) -> None: | ||
class CustomException(Exception): | ||
pass | ||
|
||
atomic_db[b'key-1'] = b'origin' | ||
|
||
with pytest.raises(CustomException): | ||
with atomic_db.atomic_batch() as batch: | ||
batch.delete(b'key-1') | ||
|
||
assert b'key-1' not in batch | ||
with pytest.raises(KeyError): | ||
assert batch[b'key-1'] | ||
|
||
raise CustomException('pretend something went wrong') | ||
|
||
assert atomic_db[b'key-1'] == b'origin' | ||
|
||
def test_atomic_db_temporary_state_dropped_across_batches(self, | ||
atomic_db: AtomicDatabaseAPI) -> None: | ||
class CustomException(Exception): | ||
pass | ||
|
||
atomic_db[b'key-1'] = b'origin' | ||
|
||
with pytest.raises(CustomException): | ||
with atomic_db.atomic_batch() as batch: | ||
batch.delete(b'key-1') | ||
batch.set(b'key-2', b'val-2') | ||
raise CustomException('pretend something went wrong') | ||
|
||
with atomic_db.atomic_batch() as batch: | ||
assert batch[b'key-1'] == b'origin' | ||
assert b'key-2' not in batch | ||
|
||
def test_atomic_db_with_exception_batch(self, atomic_db: AtomicDatabaseAPI) -> None: | ||
atomic_db.set(b'key-1', b'value-1') | ||
|
||
try: | ||
with atomic_db.atomic_batch() as batch: | ||
batch.set(b'key-1', b'new-value-1') | ||
batch.set(b'key-2', b'value-2') | ||
raise Exception | ||
except Exception: | ||
pass | ||
|
||
assert atomic_db.get(b'key-1') == b'value-1' | ||
|
||
with pytest.raises(KeyError): | ||
atomic_db[b'key-2'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import pytest | ||
|
||
from eth.abc import DatabaseAPI | ||
|
||
|
||
class DatabaseAPITestSuite: | ||
def test_database_api_get(self, db: DatabaseAPI) -> None: | ||
db[b'key-1'] = b'value-1' | ||
assert db.get(b'key-1') == b'value-1' | ||
|
||
def test_database_api_item_getter(self, db: DatabaseAPI) -> None: | ||
db[b'key-1'] = b'value-1' | ||
assert db[b'key-1'] == b'value-1' | ||
|
||
def test_database_api_get_missing_key(self, db: DatabaseAPI) -> None: | ||
assert b'key-1' not in db | ||
assert db.get(b'key-1') is None | ||
|
||
def test_database_api_item_getter_missing_key(self, db: DatabaseAPI) -> None: | ||
assert b'key-1' not in db | ||
with pytest.raises(KeyError): | ||
db[b'key-1'] | ||
|
||
def test_database_api_set(self, db: DatabaseAPI) -> None: | ||
db[b'key-1'] = b'value-1' | ||
assert db[b'key-1'] == b'value-1' | ||
db[b'key-1'] = b'value-2' | ||
assert db[b'key-1'] == b'value-2' | ||
|
||
def test_database_api_item_setter(self, db: DatabaseAPI) -> None: | ||
db.set(b'key-1', b'value-1') | ||
assert db[b'key-1'] == b'value-1' | ||
db.set(b'key-1', b'value-2') | ||
assert db[b'key-1'] == b'value-2' | ||
|
||
def test_database_api_exists(self, db: DatabaseAPI) -> None: | ||
assert db.exists(b'key-1') is False | ||
|
||
db[b'key-1'] = b'value-1' | ||
|
||
assert db.exists(b'key-1') is True | ||
|
||
def test_database_api_contains_checking(self, db: DatabaseAPI) -> None: | ||
assert b'key-1' not in db | ||
|
||
db[b'key-1'] = b'value-1' | ||
|
||
assert b'key-1' in db | ||
|
||
def test_database_api_delete(self, db: DatabaseAPI) -> None: | ||
db[b'key-1'] = b'value-1' | ||
|
||
assert b'key-1' in db | ||
|
||
db.delete(b'key-1') | ||
|
||
assert not db.exists(b'key-1') | ||
assert b'key-1' not in db | ||
|
||
def test_database_api_item_delete(self, db: DatabaseAPI) -> None: | ||
db[b'key-1'] = b'value-1' | ||
|
||
assert b'key-1' in db | ||
|
||
del db[b'key-1'] | ||
|
||
assert b'key-1' not in db | ||
|
||
def test_database_api_delete_missing_key(self, db: DatabaseAPI) -> None: | ||
assert b'key-1' not in db | ||
db.delete(b'key-1') | ||
|
||
def test_database_api_item_delete_missing_key(self, db: DatabaseAPI) -> None: | ||
assert b'key-1' not in db | ||
with pytest.raises(KeyError): | ||
del db[b'key-1'] | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Package up test suites for the ``DatabaseAPI`` and ``AtomicDatabaseAPI`` to be class-based to make them reusable by other libaries. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import pytest | ||
|
||
from eth.db.atomic import AtomicDB | ||
from eth.db.backends.level import LevelDB | ||
|
||
from eth.tools.db.base import DatabaseAPITestSuite | ||
from eth.tools.db.atomic import AtomicDatabaseBatchAPITestSuite | ||
|
||
|
||
@pytest.fixture(params=['atomic', 'level']) | ||
def atomic_db(request, tmpdir): | ||
if request.param == 'atomic': | ||
return AtomicDB() | ||
elif request.param == 'level': | ||
return LevelDB(db_path=tmpdir.mkdir("level_db_path")) | ||
else: | ||
raise ValueError("Unexpected database type: {}".format(request.param)) | ||
|
||
|
||
@pytest.fixture | ||
def db(atomic_db): | ||
return atomic_db | ||
|
||
|
||
class TestAtomicDatabaseBatchAPI(AtomicDatabaseBatchAPITestSuite): | ||
pass | ||
|
||
|
||
class TestAtomicDatabaseAPI(DatabaseAPITestSuite): | ||
pass |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised that
.delete()
doesn't throw an exception but__delitem__
does! It seems like those two should have the same behavior.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realized that
MutableMapping
doesn't have aset
,delete
orexists
API....