-
Notifications
You must be signed in to change notification settings - Fork 18
Dx 2353 - Update Redis API compat page for v1.15 #68
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
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
b16eca3
feat: add new hash commands
alitariksahin 3c42076
feat: add new stream commands
alitariksahin a049f9f
feat: add new connection command
alitariksahin 4493afe
feat: add new bitop params
alitariksahin 1af6372
feat: extend xadd param definition
alitariksahin 0b31a9d
fix: tests and lint
alitariksahin 0bac05e
fix: formatting
alitariksahin bfb8989
fix: mypy
alitariksahin ddd01e1
feat: add async tests
alitariksahin a111bf1
fix: tests
alitariksahin 101e957
fix: rename folders to avoid cache conflicts
alitariksahin 1170fa0
fix:tests
alitariksahin cfa20fe
fix: reviews
alitariksahin 8a61dbd
fix: format
alitariksahin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains hidden or 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,215 @@ | ||
| import pytest_asyncio | ||
| from pytest import mark, raises | ||
|
|
||
| from tests.execute_on_http import execute_on_http | ||
| from upstash_redis.asyncio import Redis | ||
|
|
||
|
|
||
| @pytest_asyncio.fixture | ||
| async def setup_test_data(async_redis: Redis): | ||
| """Setup test data for bitop operations""" | ||
| # Setup source strings for original tests (without flushing entire DB) | ||
| await async_redis.set("string_as_bitop_source_1", "1234") | ||
| await async_redis.set("string_as_bitop_source_2", "ABCD") | ||
| yield | ||
| # Cleanup only our test keys | ||
| await async_redis.delete("string_as_bitop_source_1", "string_as_bitop_source_2") | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_not_not_operation(async_redis: Redis, setup_test_data) -> None: | ||
| assert ( | ||
| await async_redis.bitop( | ||
| "AND", | ||
| "bitop_destination_1", | ||
| "string_as_bitop_source_1", | ||
| "string_as_bitop_source_2", | ||
| ) | ||
| == 4 | ||
| ) | ||
|
|
||
| # Verify the result exists | ||
| result = await execute_on_http("GET", "bitop_destination_1") | ||
| assert result is not None | ||
| assert isinstance(result, str) | ||
| assert len(result) == 4 | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_without_source_keys(async_redis: Redis) -> None: | ||
| with raises(Exception) as exception: | ||
| await async_redis.bitop("AND", "bitop_destination_1") | ||
|
|
||
| assert str(exception.value) == "At least one source key must be specified." | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_not_with_more_than_one_source_key( | ||
| async_redis: Redis, setup_test_data | ||
| ) -> None: | ||
| with raises(Exception) as exception: | ||
| await async_redis.bitop( | ||
| "NOT", | ||
| "bitop_destination_4", | ||
| "string_as_bitop_source_1", | ||
| "string_as_bitop_source_2", | ||
| ) | ||
|
|
||
| assert ( | ||
| str(exception.value) | ||
| == 'The "NOT" operation takes only one source key as argument.' | ||
| ) | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_not(async_redis: Redis, setup_test_data) -> None: | ||
| assert ( | ||
| await async_redis.bitop( | ||
| "NOT", "bitop_destination_4", "string_as_bitop_source_1" | ||
| ) | ||
| == 4 | ||
| ) | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_diff(async_redis: Redis) -> None: | ||
| """Test BITOP DIFF operation - sets bits that are in X but not in any Y""" | ||
| # Setup test keys with known bit patterns | ||
| await async_redis.setbit("diff_key1", 0, 1) | ||
| await async_redis.setbit("diff_key1", 1, 1) | ||
| await async_redis.setbit("diff_key1", 2, 1) | ||
|
|
||
| await async_redis.setbit("diff_key2", 1, 1) | ||
| await async_redis.setbit("diff_key2", 2, 1) | ||
| await async_redis.setbit("diff_key2", 3, 1) | ||
|
|
||
| await async_redis.setbit("diff_key3", 2, 1) | ||
| await async_redis.setbit("diff_key3", 3, 1) | ||
| await async_redis.setbit("diff_key3", 4, 1) | ||
|
|
||
| result = await async_redis.bitop( | ||
| "DIFF", "diff_dest", "diff_key1", "diff_key2", "diff_key3" | ||
| ) | ||
| assert result == 1 | ||
|
|
||
| # Only bit 0 is in key1 but not in key2 or key3 | ||
| assert await async_redis.getbit("diff_dest", 0) == 1 | ||
| assert await async_redis.getbit("diff_dest", 1) == 0 | ||
| assert await async_redis.getbit("diff_dest", 2) == 0 | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_diff1(async_redis: Redis) -> None: | ||
| """Test BITOP DIFF1 operation - sets bits that are in Y but not in X""" | ||
| # Setup test keys with known bit patterns | ||
| await async_redis.setbit("diff1_key1", 0, 1) | ||
| await async_redis.setbit("diff1_key1", 1, 1) | ||
| await async_redis.setbit("diff1_key1", 2, 1) | ||
|
|
||
| await async_redis.setbit("diff1_key2", 1, 1) | ||
| await async_redis.setbit("diff1_key2", 2, 1) | ||
| await async_redis.setbit("diff1_key2", 3, 1) | ||
|
|
||
| await async_redis.setbit("diff1_key3", 2, 1) | ||
| await async_redis.setbit("diff1_key3", 3, 1) | ||
| await async_redis.setbit("diff1_key3", 4, 1) | ||
|
|
||
| result = await async_redis.bitop( | ||
| "DIFF1", "diff1_dest", "diff1_key1", "diff1_key2", "diff1_key3" | ||
| ) | ||
| assert result == 1 | ||
|
|
||
| # Bits 3 and 4 are in Y keys but not in key1 | ||
| assert await async_redis.getbit("diff1_dest", 0) == 0 | ||
| assert await async_redis.getbit("diff1_dest", 3) == 1 | ||
| assert await async_redis.getbit("diff1_dest", 4) == 1 | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_andor(async_redis: Redis) -> None: | ||
| """Test BITOP ANDOR operation - bit set if in X and in one or more Y""" | ||
| # Setup test keys with known bit patterns | ||
| await async_redis.setbit("andor_key1", 0, 1) | ||
| await async_redis.setbit("andor_key1", 1, 1) | ||
| await async_redis.setbit("andor_key1", 2, 1) | ||
|
|
||
| await async_redis.setbit("andor_key2", 1, 1) | ||
| await async_redis.setbit("andor_key2", 2, 1) | ||
| await async_redis.setbit("andor_key2", 3, 1) | ||
|
|
||
| await async_redis.setbit("andor_key3", 2, 1) | ||
| await async_redis.setbit("andor_key3", 3, 1) | ||
| await async_redis.setbit("andor_key3", 4, 1) | ||
|
|
||
| result = await async_redis.bitop( | ||
| "ANDOR", "andor_dest", "andor_key1", "andor_key2", "andor_key3" | ||
| ) | ||
| assert result == 1 | ||
|
|
||
| # Bit must be in key1 AND (key2 OR key3) | ||
| assert ( | ||
| await async_redis.getbit("andor_dest", 0) == 0 | ||
| ) # In key1 but not in key2 or key3 | ||
| assert await async_redis.getbit("andor_dest", 1) == 1 # In key1 and key2 | ||
| assert await async_redis.getbit("andor_dest", 2) == 1 # In key1 and both key2, key3 | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_one(async_redis: Redis) -> None: | ||
| """Test BITOP ONE operation - bit set if in exactly one source""" | ||
| # Setup test keys with known bit patterns | ||
| await async_redis.setbit("one_key1", 0, 1) | ||
| await async_redis.setbit("one_key1", 1, 1) | ||
| await async_redis.setbit("one_key1", 2, 1) | ||
|
|
||
| await async_redis.setbit("one_key2", 1, 1) | ||
| await async_redis.setbit("one_key2", 2, 1) | ||
| await async_redis.setbit("one_key2", 3, 1) | ||
|
|
||
| await async_redis.setbit("one_key3", 2, 1) | ||
| await async_redis.setbit("one_key3", 3, 1) | ||
| await async_redis.setbit("one_key3", 4, 1) | ||
|
|
||
| result = await async_redis.bitop( | ||
| "ONE", "one_dest", "one_key1", "one_key2", "one_key3" | ||
| ) | ||
| assert result == 1 | ||
|
|
||
| # Bits must be in exactly one source | ||
| assert await async_redis.getbit("one_dest", 0) == 1 # Only in key1 | ||
| assert await async_redis.getbit("one_dest", 1) == 0 # In key1 and key2 | ||
| assert await async_redis.getbit("one_dest", 2) == 0 # In all three | ||
| assert await async_redis.getbit("one_dest", 4) == 1 # Only in key3 | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_diff_requires_multiple_keys(async_redis: Redis) -> None: | ||
| """Test BITOP DIFF requires at least two source keys""" | ||
| with raises(Exception) as exception: | ||
| await async_redis.bitop("DIFF", "dest", "key1") | ||
|
|
||
| assert "BITOP DIFF must be called with at least two source keys" in str( | ||
| exception.value | ||
| ) | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_diff1_requires_multiple_keys(async_redis: Redis) -> None: | ||
| """Test BITOP DIFF1 requires at least two source keys""" | ||
| with raises(Exception) as exception: | ||
| await async_redis.bitop("DIFF1", "dest", "key1") | ||
|
|
||
| assert "BITOP DIFF1 must be called with at least two source keys" in str( | ||
| exception.value | ||
| ) | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_andor_requires_multiple_keys(async_redis: Redis) -> None: | ||
| """Test BITOP ANDOR requires at least two source keys""" | ||
| with raises(Exception) as exception: | ||
| await async_redis.bitop("ANDOR", "dest", "key1") | ||
|
|
||
| assert "BITOP ANDOR must be called with at least two source keys" in str( | ||
| exception.value | ||
| ) | ||
75 changes: 75 additions & 0 deletions
75
tests/commands/asyncio/connection/test_client_setinfo_async.py
This file contains hidden or 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,75 @@ | ||
| """ | ||
| Tests for CLIENT SETINFO command (async version). | ||
| """ | ||
|
|
||
| from pytest import mark | ||
|
|
||
| from upstash_redis.asyncio import Redis | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_client_setinfo_lib_name(async_redis: Redis) -> None: | ||
| """Test CLIENT SETINFO with LIB-NAME""" | ||
| try: | ||
| result = await async_redis.client_setinfo("LIB-NAME", "redis-py") | ||
| assert result in ["OK", "ok", True] | ||
| except Exception: | ||
| # CLIENT commands might not be supported in REST API | ||
| pass | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_client_setinfo_lib_ver(async_redis: Redis) -> None: | ||
| """Test CLIENT SETINFO with LIB-VER""" | ||
| try: | ||
| result = await async_redis.client_setinfo("LIB-VER", "1.0.0") | ||
| assert result in ["OK", "ok", True] | ||
| except Exception: | ||
| # CLIENT commands might not be supported in REST API | ||
| pass | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_client_setinfo_case_insensitive_lib_name(async_redis: Redis) -> None: | ||
| """Test CLIENT SETINFO with lowercase lib-name""" | ||
| try: | ||
| result = await async_redis.client_setinfo("lib-name", "redis-py") | ||
| assert result in ["OK", "ok", True] | ||
| except Exception: | ||
| # CLIENT commands might not be supported in REST API | ||
| pass | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_client_setinfo_case_insensitive_lib_ver(async_redis: Redis) -> None: | ||
| """Test CLIENT SETINFO with lowercase lib-ver""" | ||
| try: | ||
| result = await async_redis.client_setinfo("lib-ver", "2.0.0") | ||
| assert result in ["OK", "ok", True] | ||
| except Exception: | ||
| # CLIENT commands might not be supported in REST API | ||
| pass | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_client_setinfo_lib_name_with_suffix(async_redis: Redis) -> None: | ||
| """Test CLIENT SETINFO with library name containing custom suffix""" | ||
| try: | ||
| result = await async_redis.client_setinfo( | ||
| "LIB-NAME", "redis-py(upstash_v1.0.0)" | ||
| ) | ||
| assert result in ["OK", "ok", True] | ||
| except Exception: | ||
| # CLIENT commands might not be supported in REST API | ||
| pass | ||
|
|
||
|
|
||
| @mark.asyncio | ||
| async def test_client_setinfo_version_with_dots(async_redis: Redis) -> None: | ||
| """Test CLIENT SETINFO with version containing multiple dots""" | ||
| try: | ||
| result = await async_redis.client_setinfo("LIB-VER", "3.2.1") | ||
| assert result in ["OK", "ok", True] | ||
| except Exception: | ||
| # CLIENT commands might not be supported in REST API | ||
| pass |
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.
Uh oh!
There was an error while loading. Please reload this page.