diff --git a/.pubnub.yml b/.pubnub.yml index fea0b11c..e87d22fd 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,5 +1,5 @@ name: python -version: 10.1.0 +version: 10.2.0 schema: 1 scm: github.com/pubnub/python sdks: @@ -18,7 +18,7 @@ sdks: distributions: - distribution-type: library distribution-repository: package - package-name: pubnub-10.1.0 + package-name: pubnub-10.2.0 location: https://pypi.org/project/pubnub/ supported-platforms: supported-operating-systems: @@ -91,8 +91,8 @@ sdks: - distribution-type: library distribution-repository: git release - package-name: pubnub-10.1.0 - location: https://github.com/pubnub/python/releases/download/10.1.0/pubnub-10.1.0.tar.gz + package-name: pubnub-10.2.0 + location: https://github.com/pubnub/python/releases/download/10.2.0/pubnub-10.2.0.tar.gz supported-platforms: supported-operating-systems: Linux: @@ -163,6 +163,11 @@ sdks: license-url: https://github.com/encode/httpx/blob/master/LICENSE.md is-required: Required changelog: + - date: 2025-02-07 + version: 10.2.0 + changes: + - type: feature + text: "Write protection with `If-Match` eTag header for setting channel and uuid metadata." - date: 2025-01-30 version: 10.1.0 changes: diff --git a/CHANGELOG.md b/CHANGELOG.md index 46dc73dd..22fe062a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 10.2.0 +February 07 2025 + +#### Added +- Write protection with `If-Match` eTag header for setting channel and uuid metadata. + ## 10.1.0 January 30 2025 diff --git a/examples/native_sync/using_etag.py b/examples/native_sync/using_etag.py new file mode 100644 index 00000000..205e7dc0 --- /dev/null +++ b/examples/native_sync/using_etag.py @@ -0,0 +1,60 @@ +import os + +from copy import deepcopy +from pubnub.pubnub import PubNub +from pubnub.pnconfiguration import PNConfiguration +from pubnub.exceptions import PubNubException + +config = PNConfiguration() +config.publish_key = os.getenv('PUBLISH_KEY', default='demo') +config.subscribe_key = os.getenv('SUBSCRIBE_KEY', default='demo') +config.user_id = "example" + +config_2 = deepcopy(config) +config_2.user_id = "example_2" + +pubnub = PubNub(config) +pubnub_2 = PubNub(config_2) + +sample_user = { + "uuid": "SampleUser", + "name": "John Doe", + "email": "jd@example.com", + "custom": {"age": 42, "address": "123 Main St."}, +} + +# One client creates a metada for the user "SampleUser" and successfully writes it to the server. +set_result = pubnub.set_uuid_metadata( + **sample_user, + include_custom=True, + include_status=True, + include_type=True +).sync() + +# We store the eTag for the user for further updates. +original_e_tag = set_result.result.data.get('eTag') + +# Another client sets the user meta with the same UUID but different data. +overwrite_result = pubnub_2.set_uuid_metadata(uuid="SampleUser", name="Jane Doe").sync() +new_e_tag = overwrite_result.result.data.get('eTag') + +# We can verify that there is a new eTag for the user. +print(f"{original_e_tag == new_e_tag=}") + +# We modify the user and try to update it. +updated_user = {**sample_user, "custom": {"age": 43, "address": "321 Other St."}} + +try: + update_result = pubnub.set_uuid_metadata( + **updated_user, + include_custom=True, + include_status=True, + include_type=True + ).if_matches_etag(original_e_tag).sync() +except PubNubException as e: + # We get an exception and after reading the error message we can see that the reason is that the eTag is outdated. + print(f"Update failed: {e.get_error_message().get('message')}\nHTTP Status Code: {e.get_status_code()}") + + +except Exception as e: + print(f"Unexpected error: {e}") diff --git a/pubnub/endpoints/endpoint.py b/pubnub/endpoints/endpoint.py index 856e1dfb..62813672 100644 --- a/pubnub/endpoints/endpoint.py +++ b/pubnub/endpoints/endpoint.py @@ -25,6 +25,7 @@ class Endpoint(object): __metaclass__ = ABCMeta _path = None + _custom_headers: dict = None def __init__(self, pubnub): self.pubnub = pubnub @@ -100,6 +101,9 @@ def request_headers(self): if self.http_method() in [HttpMethod.POST, HttpMethod.PATCH]: headers["Content-type"] = "application/json" + if self._custom_headers: + headers.update(self._custom_headers) + return headers def build_file_upload_request(self): diff --git a/pubnub/endpoints/objects_v2/objects_endpoint.py b/pubnub/endpoints/objects_v2/objects_endpoint.py index 9ed2de3b..65ca1922 100644 --- a/pubnub/endpoints/objects_v2/objects_endpoint.py +++ b/pubnub/endpoints/objects_v2/objects_endpoint.py @@ -17,6 +17,10 @@ class ObjectsEndpoint(Endpoint): _includes: PNIncludes = None + __if_matches_etag: str = None + + _custom_headers: dict = {} + def __init__(self, pubnub): Endpoint.__init__(self, pubnub) @@ -36,6 +40,11 @@ def validate_params(self): def validate_specific_params(self): pass + def if_matches_etag(self, etag: str): + self.__if_matches_etag = etag + self._custom_headers.update({"If-Match": etag}) + return self + def encoded_params(self): params = {} if isinstance(self, ListEndpoint): diff --git a/pubnub/exceptions.py b/pubnub/exceptions.py index 4f611302..7342c3ff 100644 --- a/pubnub/exceptions.py +++ b/pubnub/exceptions.py @@ -1,3 +1,6 @@ +from json import loads, JSONDecodeError + + class PubNubException(Exception): def __init__(self, errormsg="", status_code=0, pn_error=None, status=None): self._errormsg = errormsg @@ -19,6 +22,16 @@ def _status(self): raise DeprecationWarning return self.status + def get_status_code(self): + return self._status_code + + def get_error_message(self): + try: + error = loads(self._errormsg) + return error.get('error') + except JSONDecodeError: + return self._errormsg + class PubNubAsyncioException(Exception): def __init__(self, result, status): diff --git a/pubnub/pubnub_core.py b/pubnub/pubnub_core.py index f0afaede..412cdda3 100644 --- a/pubnub/pubnub_core.py +++ b/pubnub/pubnub_core.py @@ -96,7 +96,7 @@ class PubNubCore: """A base class for PubNub Python API implementations""" - SDK_VERSION = "10.1.0" + SDK_VERSION = "10.2.0" SDK_NAME = "PubNub-Python" TIMESTAMP_DIVIDER = 1000 @@ -288,9 +288,9 @@ def set_uuid_metadata(self, uuid: str = None, include_custom: bool = None, custo include_type=include_type, status=status, type=type, name=name, email=email, external_id=external_id, profile_url=profile_url) - def get_uuid_metadata(self, uuud: str = None, include_custom: bool = None, include_status: bool = True, + def get_uuid_metadata(self, uuid: str = None, include_custom: bool = None, include_status: bool = True, include_type: bool = True) -> GetUuid: - return GetUuid(self, uuid=uuud, include_custom=include_custom, include_status=include_status, + return GetUuid(self, uuid=uuid, include_custom=include_custom, include_status=include_status, include_type=include_type) def remove_uuid_metadata(self, uuid: str = None) -> RemoveUuid: diff --git a/setup.py b/setup.py index ad61b695..41c4505b 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='pubnub', - version='10.1.0', + version='10.2.0', description='PubNub Real-time push service in the cloud', author='PubNub', author_email='support@pubnub.com', diff --git a/tests/integrational/asyncio/objects_v2/__init__.py b/tests/integrational/asyncio/objects_v2/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/integrational/asyncio/objects_v2/test_channel.py b/tests/integrational/asyncio/objects_v2/test_channel.py new file mode 100644 index 00000000..8174f334 --- /dev/null +++ b/tests/integrational/asyncio/objects_v2/test_channel.py @@ -0,0 +1,215 @@ +import pytest +from pubnub.endpoints.endpoint import Endpoint +from pubnub.endpoints.objects_v2.channel.get_all_channels import GetAllChannels +from pubnub.endpoints.objects_v2.channel.get_channel import GetChannel +from pubnub.endpoints.objects_v2.channel.remove_channel import RemoveChannel +from pubnub.endpoints.objects_v2.channel.set_channel import SetChannel +from pubnub.exceptions import PubNubException +from pubnub.models.consumer.common import PNStatus +from pubnub.models.consumer.objects_v2.channel import PNSetChannelMetadataResult, PNGetChannelMetadataResult, \ + PNRemoveChannelMetadataResult, PNGetAllChannelMetadataResult +from pubnub.models.consumer.objects_v2.sort import PNSortKey, PNSortKeyValue +from pubnub.pubnub_asyncio import PubNubAsyncio +from pubnub.models.envelopes import AsyncioEnvelope +from tests.helper import pnconf_env_copy +from tests.integrational.vcr_helper import pn_vcr + + +def _pubnub(): + config = pnconf_env_copy() + return PubNubAsyncio(config) + + +class TestObjectsV2Channel: + _some_channel_id = "somechannelid" + _some_name = "Some name" + _some_description = "Some description" + _some_custom = { + "key1": "val1", + "key2": "val2" + } + + def test_set_channel_endpoint_available(self): + pn = _pubnub() + set_channel = pn.set_channel_metadata() + assert set_channel is not None + assert isinstance(set_channel, SetChannel) + assert isinstance(set_channel, Endpoint) + + def test_set_channel_is_endpoint(self): + pn = _pubnub() + set_channel = pn.set_channel_metadata() + assert isinstance(set_channel, SetChannel) + assert isinstance(set_channel, Endpoint) + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/channel/set_channel.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_set_channel_happy_path(self): + pn = _pubnub() + + set_channel_result = await pn.set_channel_metadata() \ + .include_custom(True) \ + .channel(TestObjectsV2Channel._some_channel_id) \ + .set_name(TestObjectsV2Channel._some_name) \ + .description(TestObjectsV2Channel._some_description) \ + .custom(TestObjectsV2Channel._some_custom) \ + .future() + + assert isinstance(set_channel_result, AsyncioEnvelope) + assert isinstance(set_channel_result.result, PNSetChannelMetadataResult) + assert isinstance(set_channel_result.status, PNStatus) + assert not set_channel_result.status.is_error() + data = set_channel_result.result.data + assert data['id'] == TestObjectsV2Channel._some_channel_id + assert data['name'] == TestObjectsV2Channel._some_name + assert data['description'] == TestObjectsV2Channel._some_description + assert data['custom'] == TestObjectsV2Channel._some_custom + + def test_get_channel_endpoint_available(self): + pn = _pubnub() + get_channel = pn.get_channel_metadata() + assert get_channel is not None + assert isinstance(get_channel, GetChannel) + assert isinstance(get_channel, Endpoint) + + def test_get_channel_is_endpoint(self): + pn = _pubnub() + get_channel = pn.get_channel_metadata() + assert isinstance(get_channel, GetChannel) + assert isinstance(get_channel, Endpoint) + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/channel/get_channel.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_get_channel_happy_path(self): + pn = _pubnub() + + get_channel_result = await pn.get_channel_metadata() \ + .include_custom(True) \ + .channel(TestObjectsV2Channel._some_channel_id) \ + .future() + + assert isinstance(get_channel_result, AsyncioEnvelope) + assert isinstance(get_channel_result.result, PNGetChannelMetadataResult) + assert isinstance(get_channel_result.status, PNStatus) + assert not get_channel_result.status.is_error() + data = get_channel_result.result.data + assert data['id'] == TestObjectsV2Channel._some_channel_id + assert data['name'] == TestObjectsV2Channel._some_name + assert data['description'] == TestObjectsV2Channel._some_description + assert data['custom'] == TestObjectsV2Channel._some_custom + + def test_remove_channel_endpoint_available(self): + pn = _pubnub() + remove_channel = pn.remove_channel_metadata() + assert remove_channel is not None + assert isinstance(remove_channel, RemoveChannel) + assert isinstance(remove_channel, Endpoint) + + def test_remove_channel_is_endpoint(self): + pn = _pubnub() + remove_channel = pn.remove_channel_metadata() + assert isinstance(remove_channel, RemoveChannel) + assert isinstance(remove_channel, Endpoint) + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/channel/remove_channel.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_remove_channel_happy_path(self): + pn = _pubnub() + + remove_uid_result = await pn.remove_channel_metadata() \ + .channel(TestObjectsV2Channel._some_channel_id) \ + .future() + + assert isinstance(remove_uid_result, AsyncioEnvelope) + assert isinstance(remove_uid_result.result, PNRemoveChannelMetadataResult) + assert isinstance(remove_uid_result.status, PNStatus) + assert not remove_uid_result.status.is_error() + + def test_get_all_channel_endpoint_available(self): + pn = _pubnub() + get_all_channel = pn.get_all_channel_metadata() + assert get_all_channel is not None + assert isinstance(get_all_channel, GetAllChannels) + assert isinstance(get_all_channel, Endpoint) + + def test_get_all_channel_is_endpoint(self): + pn = _pubnub() + get_all_channel = pn.get_all_channel_metadata() + assert isinstance(get_all_channel, GetAllChannels) + assert isinstance(get_all_channel, Endpoint) + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/channel/get_all_channel.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_get_all_channel_happy_path(self): + pn = _pubnub() + + await pn.set_channel_metadata() \ + .include_custom(True) \ + .channel(TestObjectsV2Channel._some_channel_id) \ + .set_name(TestObjectsV2Channel._some_name) \ + .description(TestObjectsV2Channel._some_description) \ + .custom(TestObjectsV2Channel._some_custom) \ + .future() + + get_all_channel_result = await pn.get_all_channel_metadata() \ + .include_custom(True) \ + .limit(10) \ + .include_total_count(True) \ + .sort(PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)) \ + .page(None) \ + .future() + + assert isinstance(get_all_channel_result, AsyncioEnvelope) + assert isinstance(get_all_channel_result.result, PNGetAllChannelMetadataResult) + assert isinstance(get_all_channel_result.status, PNStatus) + assert not get_all_channel_result.status.is_error() + data = get_all_channel_result.result.data + assert isinstance(data, list) + assert get_all_channel_result.result.total_count != 0 + assert get_all_channel_result.result.next is not None + assert get_all_channel_result.result.prev is None + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/channel/if_matches_etag.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_if_matches_etag(self): + pubnub = _pubnub() + + set_channel = await pubnub.set_channel_metadata(channel=self._some_channel_id, name=self._some_name).future() + original_etag = set_channel.result.data.get('eTag') + get_channel = await pubnub.get_channel_metadata(channel=self._some_channel_id).future() + assert original_etag == get_channel.result.data.get('eTag') + + # Update without eTag should be possible + set_channel = await pubnub.set_channel_metadata(channel=self._some_channel_id, name=f"{self._some_name}-2") \ + .future() + + # Response should contain new eTag + new_etag = set_channel.result.data.get('eTag') + assert original_etag != new_etag + assert set_channel.result.data.get('name') == f"{self._some_name}-2" + + get_channel = await pubnub.get_channel_metadata(channel=self._some_channel_id).future() + assert original_etag != get_channel.result.data.get('eTag') + assert get_channel.result.data.get('name') == f"{self._some_name}-2" + + # Update with correct eTag should be possible + set_channel = await pubnub.set_channel_metadata(channel=self._some_channel_id, name=f"{self._some_name}-3") \ + .if_matches_etag(new_etag) \ + .future() + assert set_channel.result.data.get('name') == f"{self._some_name}-3" + + try: + # Update with original - now outdated - eTag should fail + set_channel = await pubnub.set_channel_metadata( + channel=self._some_channel_id, + name=f"{self._some_name}-3" + ).if_matches_etag(original_etag).future() + + except PubNubException as e: + assert e.get_status_code() == 412 + assert e.get_error_message().get('message') == 'Channel to update has been modified after it was read.' diff --git a/tests/integrational/asyncio/objects_v2/test_uuid.py b/tests/integrational/asyncio/objects_v2/test_uuid.py new file mode 100644 index 00000000..7fc697e1 --- /dev/null +++ b/tests/integrational/asyncio/objects_v2/test_uuid.py @@ -0,0 +1,217 @@ +import pytest + +from pubnub.endpoints.endpoint import Endpoint +from pubnub.endpoints.objects_v2.uuid.get_all_uuid import GetAllUuid +from pubnub.endpoints.objects_v2.uuid.get_uuid import GetUuid +from pubnub.endpoints.objects_v2.uuid.remove_uuid import RemoveUuid +from pubnub.endpoints.objects_v2.uuid.set_uuid import SetUuid +from pubnub.exceptions import PubNubException +from pubnub.models.consumer.common import PNStatus +from pubnub.models.consumer.objects_v2.sort import PNSortKey, PNSortKeyValue +from pubnub.models.consumer.objects_v2.uuid import PNSetUUIDMetadataResult, PNGetUUIDMetadataResult, \ + PNRemoveUUIDMetadataResult, PNGetAllUUIDMetadataResult +from pubnub.pubnub_asyncio import PubNubAsyncio +from pubnub.models.envelopes import AsyncioEnvelope +from tests.helper import pnconf_env_copy +from tests.integrational.vcr_helper import pn_vcr + + +class TestObjectsV2UUID: + _some_uuid = "someuuid" + _some_name = "Some name" + _some_email = "test@example.com" + _some_profile_url = "http://example.com" + _some_external_id = "1234" + _some_custom = { + "key1": "val1", + "key2": "val2" + } + + def test_set_uuid_endpoint_available(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + set_uuid = pn.set_uuid_metadata() + assert set_uuid is not None + assert isinstance(set_uuid, SetUuid) + assert isinstance(set_uuid, Endpoint) + + def test_set_uuid_is_endpoint(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + set_uuid = pn.set_uuid_metadata() + assert isinstance(set_uuid, SetUuid) + assert isinstance(set_uuid, Endpoint) + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/uuid/set_uuid.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_set_uuid_happy_path(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + + set_uuid_result = await pn.set_uuid_metadata() \ + .include_custom(True) \ + .uuid(TestObjectsV2UUID._some_uuid) \ + .set_name(TestObjectsV2UUID._some_name) \ + .email(TestObjectsV2UUID._some_email) \ + .profile_url(TestObjectsV2UUID._some_profile_url) \ + .external_id(TestObjectsV2UUID._some_external_id) \ + .custom(TestObjectsV2UUID._some_custom) \ + .future() + + assert isinstance(set_uuid_result, AsyncioEnvelope) + assert isinstance(set_uuid_result.result, PNSetUUIDMetadataResult) + assert isinstance(set_uuid_result.status, PNStatus) + data = set_uuid_result.result.data + assert data['id'] == TestObjectsV2UUID._some_uuid + assert data['name'] == TestObjectsV2UUID._some_name + assert data['externalId'] == TestObjectsV2UUID._some_external_id + assert data['profileUrl'] == TestObjectsV2UUID._some_profile_url + assert data['email'] == TestObjectsV2UUID._some_email + assert data['custom'] == TestObjectsV2UUID._some_custom + + def test_get_uuid_endpoint_available(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + get_uuid = pn.get_uuid_metadata() + assert get_uuid is not None + assert isinstance(get_uuid, GetUuid) + assert isinstance(get_uuid, Endpoint) + + def test_get_uuid_is_endpoint(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + get_uuid = pn.get_uuid_metadata() + assert isinstance(get_uuid, GetUuid) + assert isinstance(get_uuid, Endpoint) + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/uuid/get_uuid.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_get_uuid_happy_path(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + + get_uuid_result = await pn.get_uuid_metadata() \ + .include_custom(True) \ + .uuid(TestObjectsV2UUID._some_uuid) \ + .future() + + assert isinstance(get_uuid_result, AsyncioEnvelope) + assert isinstance(get_uuid_result.result, PNGetUUIDMetadataResult) + assert isinstance(get_uuid_result.status, PNStatus) + data = get_uuid_result.result.data + assert data['id'] == TestObjectsV2UUID._some_uuid + assert data['name'] == TestObjectsV2UUID._some_name + assert data['externalId'] == TestObjectsV2UUID._some_external_id + assert data['profileUrl'] == TestObjectsV2UUID._some_profile_url + assert data['email'] == TestObjectsV2UUID._some_email + assert data['custom'] == TestObjectsV2UUID._some_custom + + def test_remove_uuid_endpoint_available(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + remove_uuid = pn.remove_uuid_metadata() + assert remove_uuid is not None + assert isinstance(remove_uuid, RemoveUuid) + assert isinstance(remove_uuid, Endpoint) + + def test_remove_uuid_is_endpoint(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + remove_uuid = pn.remove_uuid_metadata() + assert isinstance(remove_uuid, RemoveUuid) + assert isinstance(remove_uuid, Endpoint) + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/uuid/remove_uuid.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_remove_uuid_happy_path(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + + remove_uid_result = await pn.remove_uuid_metadata() \ + .uuid(TestObjectsV2UUID._some_uuid) \ + .future() + + assert isinstance(remove_uid_result, AsyncioEnvelope) + assert isinstance(remove_uid_result.result, PNRemoveUUIDMetadataResult) + assert isinstance(remove_uid_result.status, PNStatus) + + def test_get_all_uuid_endpoint_available(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + get_all_uuid = pn.get_all_uuid_metadata() + assert get_all_uuid is not None + assert isinstance(get_all_uuid, GetAllUuid) + assert isinstance(get_all_uuid, Endpoint) + + def test_get_all_uuid_is_endpoint(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + get_all_uuid = pn.get_all_uuid_metadata() + assert isinstance(get_all_uuid, GetAllUuid) + assert isinstance(get_all_uuid, Endpoint) + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/uuid/get_all_uuid.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_get_all_uuid_happy_path(self): + config = pnconf_env_copy() + pn = PubNubAsyncio(config) + + get_all_uuid_result = await pn.get_all_uuid_metadata() \ + .include_custom(True) \ + .limit(10) \ + .include_total_count(True) \ + .sort(PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)) \ + .page(None) \ + .future() + + assert isinstance(get_all_uuid_result, AsyncioEnvelope) + assert isinstance(get_all_uuid_result.result, PNGetAllUUIDMetadataResult) + assert isinstance(get_all_uuid_result.status, PNStatus) + data = get_all_uuid_result.result.data + assert isinstance(data, list) + assert get_all_uuid_result.result.total_count != 0 + assert get_all_uuid_result.result.next is not None + assert get_all_uuid_result.result.prev is None + + @pn_vcr.use_cassette('tests/integrational/fixtures/asyncio/objects_v2/uuid/if_matches_etag.json', + filter_query_parameters=['uuid', 'pnsdk', 'l_obj'], serializer='pn_json') + @pytest.mark.asyncio + async def test_if_matches_etag(self): + config = pnconf_env_copy() + pubnub = PubNubAsyncio(config) + + set_uuid = await pubnub.set_uuid_metadata(uuid=self._some_uuid, name=self._some_name).future() + original_etag = set_uuid.result.data.get('eTag') + get_uuid = await pubnub.get_uuid_metadata(uuid=self._some_uuid).future() + assert original_etag == get_uuid.result.data.get('eTag') + + # Update without eTag should be possible + set_uuid = await pubnub.set_uuid_metadata(uuid=self._some_uuid, name=f"{self._some_name}-2").future() + + # Response should contain new eTag + new_etag = set_uuid.result.data.get('eTag') + assert original_etag != new_etag + assert set_uuid.result.data.get('name') == f"{self._some_name}-2" + + get_uuid = await pubnub.get_uuid_metadata(uuid=self._some_uuid).future() + assert original_etag != get_uuid.result.data.get('eTag') + assert get_uuid.result.data.get('name') == f"{self._some_name}-2" + + # Update with correct eTag should be possible + set_uuid = await pubnub.set_uuid_metadata(uuid=self._some_uuid, name=f"{self._some_name}-3") \ + .if_matches_etag(new_etag) \ + .future() + assert set_uuid.result.data.get('name') == f"{self._some_name}-3" + + try: + # Update with original - now outdated - eTag should fail + set_uuid = await pubnub.set_uuid_metadata(uuid=self._some_uuid, name=f"{self._some_name}-3") \ + .if_matches_etag(original_etag) \ + .future() + except PubNubException as e: + assert e.get_status_code() == 412 + assert e.get_error_message().get('message') == 'User to update has been modified after it was read.' diff --git a/tests/integrational/fixtures/asyncio/objects_v2/channel/get_all_channel.json b/tests/integrational/fixtures/asyncio/objects_v2/channel/get_all_channel.json new file mode 100644 index 00000000..8c095104 --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/channel/get_all_channel.json @@ -0,0 +1,119 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=custom%2Cstatus%2Ctype", + "body": { + "pickle": "gASVhgAAAAAAAACMgnsibmFtZSI6ICJTb21lIG5hbWUiLCAiZGVzY3JpcHRpb24iOiAiU29tZSBkZXNjcmlwdGlvbiIsICJzdGF0dXMiOiBudWxsLCAidHlwZSI6IG51bGwsICJjdXN0b20iOiB7ImtleTEiOiAidmFsMSIsICJrZXkyIjogInZhbDIifX2ULg==" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "130" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:27:41 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "243" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVAwEAAAAAAAB9lIwGc3RyaW5nlIzzeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lIiwiZGVzY3JpcHRpb24iOiJTb21lIGRlc2NyaXB0aW9uIiwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJjdXN0b20iOnsia2V5MSI6InZhbDEiLCJrZXkyIjoidmFsMiJ9LCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQyMToyNzo0MC45ODA4ODRaIiwiZVRhZyI6IjYzMjY1ZTUxNjZhMjEwODEwZTkzOGE4N2ZlYjRhZjE5In19lHMu" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels?count=True&include=custom%2Cstatus%2Ctype&limit=10&sort=id%3Aasc%2Cupdated%3Adesc", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:27:41 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVfAkAAAAAAAB9lIwGc3RyaW5nlFhpCQAAeyJzdGF0dXMiOjIwMCwiZGF0YSI6W3siaWQiOiIwMGE4ZDJlMC1jNjQwLTQ1YjEtZTZkZS1mNjFlNmJkOWEzOTMiLCJuYW1lIjoiMDBhOGQyZTAtYzY0MC00NWIxLWU2ZGUtZjYxZTZiZDlhMzkzIiwiZGVzY3JpcHRpb24iOm51bGwsInR5cGUiOiJncm91cCIsInN0YXR1cyI6bnVsbCwiY3VzdG9tIjpudWxsLCJ1cGRhdGVkIjoiMjAyNC0xMi0xM1QxMTowMzowMy40NTc5OTZaIiwiZVRhZyI6ImJmMjllYjJiZWYxYmFhNDdmZDk1NGVkNzAxMGNiNTFiIn0seyJpZCI6IjAyMzY5M2FjLTVjY2QtNGVkYi1mZDY3LTMzMzRjOGE1ZTdlNiIsIm5hbWUiOiIwMjM2OTNhYy01Y2NkLTRlZGItZmQ2Ny0zMzM0YzhhNWU3ZTYiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6Imdyb3VwIiwic3RhdHVzIjpudWxsLCJjdXN0b20iOm51bGwsInVwZGF0ZWQiOiIyMDI1LTAxLTMwVDA5OjU1OjQzLjE1NDQwNloiLCJlVGFnIjoiOWMxYjE1NTVhZTFjOGMzMzg0M2RmZWE4ZGEyNzljMTkifSx7ImlkIjoiMDNkMjdjMTUtY2RhOS00ZGM3LWUyNzYtYjRkOGZhNmY4NDhlIiwibmFtZSI6IjAzZDI3YzE1LWNkYTktNGRjNy1lMjc2LWI0ZDhmYTZmODQ4ZSIsImRlc2NyaXB0aW9uIjpudWxsLCJ0eXBlIjoiZ3JvdXAiLCJzdGF0dXMiOm51bGwsImN1c3RvbSI6bnVsbCwidXBkYXRlZCI6IjIwMjQtMTItMTZUMDk6MDg6NTQuMjMxNTE1WiIsImVUYWciOiJmZWI0NGU4NDBmYmVlN2RhMWJiYzg3ZWY1MWYyMjNiYSJ9LHsiaWQiOiIwNGUzMDgzZS0wMTlhLTRkYWUtYmU3Zi1kODk2MjkxYWI0ZDkiLCJuYW1lIjoiMDRlMzA4M2UtMDE5YS00ZGFlLWJlN2YtZDg5NjI5MWFiNGQ5IiwiZGVzY3JpcHRpb24iOm51bGwsInR5cGUiOiJncm91cCIsInN0YXR1cyI6bnVsbCwiY3VzdG9tIjpudWxsLCJ1cGRhdGVkIjoiMjAyNC0xMi0xOVQxMjowNjozNy4zMTMyNzVaIiwiZVRhZyI6ImRkZjg5MjliNDU1YjgwMGFmYmY2OTUzMWZjNTZhYWQ4In0seyJpZCI6IjA1YjJkNDAyLWY5MDQtNDk5ZC1iOWYzLTgxNjZmYmNkNjZkNCIsIm5hbWUiOiIwNWIyZDQwMi1mOTA0LTQ5OWQtYjlmMy04MTY2ZmJjZDY2ZDQiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6Imdyb3VwIiwic3RhdHVzIjpudWxsLCJjdXN0b20iOm51bGwsInVwZGF0ZWQiOiIyMDI0LTEyLTE5VDExOjMwOjQzLjIxMjI0WiIsImVUYWciOiIwMDVmODc1ODhhYmY4ZTY3YWVjYTMwMzQwMzEwZGU3ZCJ9LHsiaWQiOiIwNmQ4ZjNiNi0zMmJhLTQ3OWMtODMwMC04ZDdkYWIwZWEyMWIiLCJuYW1lIjoiMDZkOGYzYjYtMzJiYS00NzljLTgzMDAtOGQ3ZGFiMGVhMjFiIiwiZGVzY3JpcHRpb24iOm51bGwsInR5cGUiOiJncm91cCIsInN0YXR1cyI6bnVsbCwiY3VzdG9tIjpudWxsLCJ1cGRhdGVkIjoiMjAyNC0xMi0xOFQxODo0MjoxNi45NjczNjlaIiwiZVRhZyI6IjU5MTFhNjNiZTYyY2FmNjlmZDZhYWVjMGYzZTU0MjEyIn0seyJpZCI6IjA3NWZhMDAzLTRlNjctNGU3ZC04NGI2LThlMDEzYmM3ODIxOCIsIm5hbWUiOiIwNzVmYTAwMy00ZTY3LTRlN2QtODRiNi04ZTAxM2JjNzgyMTgiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6Imdyb3VwIiwic3RhdHVzIjpudWxsLCJjdXN0b20iOm51bGwsInVwZGF0ZWQiOiIyMDI0LTEyLTEyVDEzOjE0OjU1LjE1ODk1N1oiLCJlVGFnIjoiMWVkMzhiMWRkYjY4ZjdiY2YzNjU5N2Q0YjZjYzgxNjAifSx7ImlkIjoiMDg2ZGQ4NGMtZDY0NS00MDNjLWFmYWEtMTY4OTI3OGYxNzBjIiwibmFtZSI6IjA4NmRkODRjLWQ2NDUtNDAzYy1hZmFhLTE2ODkyNzhmMTcwYyIsImRlc2NyaXB0aW9uIjpudWxsLCJ0eXBlIjoiZ3JvdXAiLCJzdGF0dXMiOm51bGwsImN1c3RvbSI6bnVsbCwidXBkYXRlZCI6IjIwMjQtMTItMTZUMTY6NDc6MzEuNDU1NTk0WiIsImVUYWciOiI4MjkyNGFkNjBlMjI2OTE0ODFmNjI4NzJiYzc4MjQzMiJ9LHsiaWQiOiIwQ0lFeXJubWNoYW5uZWxfOEQzU2JJODciLCJuYW1lIjoiMENJRXlybm1UZXN0IENoYW5uZWwiLCJkZXNjcmlwdGlvbiI6IlRoaXMgaXMgYSB0ZXN0IGNoYW5uZWwiLCJ0eXBlIjoidW5rbm93biIsInN0YXR1cyI6bnVsbCwiY3VzdG9tIjpudWxsLCJ1cGRhdGVkIjoiMjAyNC0xMi0xMlQxMzoyNjo1MC43Mzg4MzZaIiwiZVRhZyI6IjE0N2IwZTIyNDZjMjg3ZGE1YWI2MWExZjUzYTg3YTNkIn0seyJpZCI6IjBkMjhkYTgwLTUxYzktNDBmOC1hNjAzLWJjYzFiMzM5OGRjMyIsIm5hbWUiOiIwZDI4ZGE4MC01MWM5LTQwZjgtYTYwMy1iY2MxYjMzOThkYzMiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6InB1YmxpYyIsInN0YXR1cyI6bnVsbCwiY3VzdG9tIjpudWxsLCJ1cGRhdGVkIjoiMjAyNC0xMi0yMFQxNDozNTozMS41NDgxOTdaIiwiZVRhZyI6ImM2ZjVjZDAwOWQwYTgxZDdjNDBlMDIzYmNjYTVmNTU4In1dLCJ0b3RhbENvdW50IjoyMzAzNiwibmV4dCI6Ik1UQSJ9lHMu" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/asyncio/objects_v2/channel/get_channel.json b/tests/integrational/fixtures/asyncio/objects_v2/channel/get_channel.json new file mode 100644 index 00000000..aabc3b6a --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/channel/get_channel.json @@ -0,0 +1,58 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=custom%2Cstatus%2Ctype", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:27:40 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "243" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVAwEAAAAAAAB9lIwGc3RyaW5nlIzzeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lIiwiZGVzY3JpcHRpb24iOiJTb21lIGRlc2NyaXB0aW9uIiwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJjdXN0b20iOnsia2V5MSI6InZhbDEiLCJrZXkyIjoidmFsMiJ9LCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQyMToyNzozOS43ODc0NzdaIiwiZVRhZyI6IjU4ZTg2M2VhMjUwOTg5MjBhNmM1ZDVjMzgxNzZlODYyIn19lHMu" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/asyncio/objects_v2/channel/if_matches_etag.json b/tests/integrational/fixtures/asyncio/objects_v2/channel/if_matches_etag.json new file mode 100644 index 00000000..f7c89950 --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/channel/if_matches_etag.json @@ -0,0 +1,361 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype", + "body": { + "pickle": "gASVXAAAAAAAAACMWHsibmFtZSI6ICJTb21lIG5hbWUiLCAiZGVzY3JpcHRpb24iOiBudWxsLCAic3RhdHVzIjogbnVsbCwgInR5cGUiOiBudWxsLCAiY3VzdG9tIjogbnVsbH2ULg==" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "88" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:10:14 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "189" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVzQAAAAAAAAB9lIwGc3RyaW5nlIy9eyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lIiwiZGVzY3JpcHRpb24iOm51bGwsInR5cGUiOm51bGwsInN0YXR1cyI6bnVsbCwidXBkYXRlZCI6IjIwMjUtMDItMDZUMjE6MTA6MTQuMjQxMzdaIiwiZVRhZyI6ImEwYmI0YjQ1MTJlMzFlMzhlOWQ5NmVhYTc4MmQ4MjIwIn19lHMu" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype&l_obj=0.3599560260772705", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:10:14 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "189" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVzQAAAAAAAAB9lIwGc3RyaW5nlIy9eyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lIiwiZGVzY3JpcHRpb24iOm51bGwsInR5cGUiOm51bGwsInN0YXR1cyI6bnVsbCwidXBkYXRlZCI6IjIwMjUtMDItMDZUMjE6MTA6MTQuMjQxMzdaIiwiZVRhZyI6ImEwYmI0YjQ1MTJlMzFlMzhlOWQ5NmVhYTc4MmQ4MjIwIn19lHMu" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype&l_obj=0.28776609897613525", + "body": { + "pickle": "gASVXgAAAAAAAACMWnsibmFtZSI6ICJTb21lIG5hbWUtMiIsICJkZXNjcmlwdGlvbiI6IG51bGwsICJzdGF0dXMiOiBudWxsLCAidHlwZSI6IG51bGwsICJjdXN0b20iOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "90" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:10:14 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "192" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV0AAAAAAAAAB9lIwGc3RyaW5nlIzAeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lLTIiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQyMToxMDoxNC42ODEwMDZaIiwiZVRhZyI6ImU1YTAwM2IwZmM0ZTNkYzg5OTA5YjgxODlmMTEzZmU5In19lHMu" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype&l_obj=0.2635527451833089", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:10:14 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "192" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV0AAAAAAAAAB9lIwGc3RyaW5nlIzAeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lLTIiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQyMToxMDoxNC42ODEwMDZaIiwiZVRhZyI6ImU1YTAwM2IwZmM0ZTNkYzg5OTA5YjgxODlmMTEzZmU5In19lHMu" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype&l_obj=0.2515745759010315", + "body": { + "pickle": "gASVXgAAAAAAAACMWnsibmFtZSI6ICJTb21lIG5hbWUtMyIsICJkZXNjcmlwdGlvbiI6IG51bGwsICJzdGF0dXMiOiBudWxsLCAidHlwZSI6IG51bGwsICJjdXN0b20iOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "if-match": [ + "e5a003b0fc4e3dc89909b8189f113fe9" + ], + "content-length": [ + "90" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:10:15 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "192" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV0AAAAAAAAAB9lIwGc3RyaW5nlIzAeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lLTMiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQyMToxMDoxNS4xMTUwNzRaIiwiZVRhZyI6Ijk0MjdiN2I2ODVhYjQzZWVlNWY0Y2M1ZmQ5NzJkNjk3In19lHMu" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype&l_obj=0.2458338737487793", + "body": { + "pickle": "gASVXgAAAAAAAACMWnsibmFtZSI6ICJTb21lIG5hbWUtMyIsICJkZXNjcmlwdGlvbiI6IG51bGwsICJzdGF0dXMiOiBudWxsLCAidHlwZSI6IG51bGwsICJjdXN0b20iOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "if-match": [ + "a0bb4b4512e31e38e9d96eaa782d8220" + ], + "content-length": [ + "90" + ] + } + }, + "response": { + "status": { + "code": 412, + "message": "Precondition Failed" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:10:15 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "110" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVfgAAAAAAAAB9lIwGc3RyaW5nlIxueyJzdGF0dXMiOjQxMiwiZXJyb3IiOnsibWVzc2FnZSI6IkNoYW5uZWwgdG8gdXBkYXRlIGhhcyBiZWVuIG1vZGlmaWVkIGFmdGVyIGl0IHdhcyByZWFkLiIsInNvdXJjZSI6Im9iamVjdHMifX2Ucy4=" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/asyncio/objects_v2/channel/remove_channel.json b/tests/integrational/fixtures/asyncio/objects_v2/channel/remove_channel.json new file mode 100644 index 00000000..36278abb --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/channel/remove_channel.json @@ -0,0 +1,58 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "DELETE", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:27:40 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "26" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVKgAAAAAAAAB9lIwGc3RyaW5nlIwaeyJzdGF0dXMiOjIwMCwiZGF0YSI6bnVsbH2Ucy4=" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/asyncio/objects_v2/channel/set_channel.json b/tests/integrational/fixtures/asyncio/objects_v2/channel/set_channel.json new file mode 100644 index 00000000..0fea9492 --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/channel/set_channel.json @@ -0,0 +1,66 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=custom%2Cstatus%2Ctype", + "body": { + "pickle": "gASVhgAAAAAAAACMgnsibmFtZSI6ICJTb21lIG5hbWUiLCAiZGVzY3JpcHRpb24iOiAiU29tZSBkZXNjcmlwdGlvbiIsICJzdGF0dXMiOiBudWxsLCAidHlwZSI6IG51bGwsICJjdXN0b20iOiB7ImtleTEiOiAidmFsMSIsICJrZXkyIjogInZhbDIifX2ULg==" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "130" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:27:39 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "243" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVAwEAAAAAAAB9lIwGc3RyaW5nlIzzeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lIiwiZGVzY3JpcHRpb24iOiJTb21lIGRlc2NyaXB0aW9uIiwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJjdXN0b20iOnsia2V5MSI6InZhbDEiLCJrZXkyIjoidmFsMiJ9LCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQyMToyNzozOS43ODc0NzdaIiwiZVRhZyI6IjU4ZTg2M2VhMjUwOTg5MjBhNmM1ZDVjMzgxNzZlODYyIn19lHMu" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/asyncio/objects_v2/uuid/get_all_uuid.json b/tests/integrational/fixtures/asyncio/objects_v2/uuid/get_all_uuid.json new file mode 100644 index 00000000..2889d0f9 --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/uuid/get_all_uuid.json @@ -0,0 +1,58 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids?count=True&include=custom%2Cstatus%2Ctype&limit=10&sort=id%3Aasc%2Cupdated%3Adesc", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:36 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVsAkAAAAAAAB9lIwGc3RyaW5nlFidCQAAeyJzdGF0dXMiOjIwMCwiZGF0YSI6W3siaWQiOiIwYWVSSHpZY3VzZXJfOHYwMkxuckwiLCJuYW1lIjoiMGFlUkh6WWNUZXN0IFVzZXIiLCJleHRlcm5hbElkIjpudWxsLCJwcm9maWxlVXJsIjpudWxsLCJlbWFpbCI6bnVsbCwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJjdXN0b20iOm51bGwsInVwZGF0ZWQiOiIyMDI0LTEyLTEyVDEzOjI3OjQxLjAyMTcxMloiLCJlVGFnIjoiMTRlN2Y0NzdkZWQyYjZlMzI5ZDE4ODBiODJhZDhmYjQifSx7ImlkIjoiMEgxVmtZSGd1c2VyX2dIQnd4WlVnIiwibmFtZSI6IjBIMVZrWUhnVGVzdCBVc2VyIiwiZXh0ZXJuYWxJZCI6bnVsbCwicHJvZmlsZVVybCI6bnVsbCwiZW1haWwiOm51bGwsInR5cGUiOm51bGwsInN0YXR1cyI6bnVsbCwiY3VzdG9tIjpudWxsLCJ1cGRhdGVkIjoiMjAyNC0xMi0xMlQxMzoyMzoxNS43OTA1NDdaIiwiZVRhZyI6IjQyOTg0ZTI1NDRkNjI5ZTIyOTM2YmJhMmI4MjBmMDAyIn0seyJpZCI6IjBZNXk1TE9zdXNlcl9JR1l0ampJMyIsIm5hbWUiOiIwWTV5NUxPc1Rlc3QgVXNlciIsImV4dGVybmFsSWQiOm51bGwsInByb2ZpbGVVcmwiOm51bGwsImVtYWlsIjpudWxsLCJ0eXBlIjpudWxsLCJzdGF0dXMiOm51bGwsImN1c3RvbSI6bnVsbCwidXBkYXRlZCI6IjIwMjQtMTItMTJUMTM6MjM6MTEuODYwOTY4WiIsImVUYWciOiI5ZDA5MzMyZjJmNTU1MGE1NTVkMmUwMDIwOWYzZDljNiJ9LHsiaWQiOiIxZVBMSFpDViIsIm5hbWUiOiJyYW5kb20tMSIsImV4dGVybmFsSWQiOm51bGwsInByb2ZpbGVVcmwiOm51bGwsImVtYWlsIjpudWxsLCJ0eXBlIjpudWxsLCJzdGF0dXMiOm51bGwsImN1c3RvbSI6bnVsbCwidXBkYXRlZCI6IjIwMjUtMDEtMjFUMDk6MDI6MjIuODkwNzUxWiIsImVUYWciOiJkZjUyNDczMWRmNDViOWY4ZjBlMDA0ZGVjODY2OGZkZCJ9LHsiaWQiOiIxaDBSV0FycXVzZXJfNE85dnZHOVciLCJuYW1lIjoiMWgwUldBcnFUZXN0IFVzZXIiLCJleHRlcm5hbElkIjpudWxsLCJwcm9maWxlVXJsIjpudWxsLCJlbWFpbCI6bnVsbCwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJjdXN0b20iOm51bGwsInVwZGF0ZWQiOiIyMDI0LTEyLTEyVDEzOjI2OjMxLjkyNTgyNloiLCJlVGFnIjoiZWM4NmM0ZmFkYTk0MDdkMWZiZjI1MzY2MmE2Y2ZkYzUifSx7ImlkIjoiMmFpdWlHIiwibmFtZSI6Ik1hcmlhbiBTYWxhemFyIiwiZXh0ZXJuYWxJZCI6IjU0NDU4ODgyMjMiLCJwcm9maWxlVXJsIjoiaHR0cHM6Ly9waWNzdW0ucGhvdG9zLzEwMC8yMDAiLCJlbWFpbCI6Im1hcmlhbi5zYWxhemFyQHB1Ym51Yi5jb20iLCJ0eXBlIjoiYWRtaW4iLCJzdGF0dXMiOiJkZWxldGVkIiwiY3VzdG9tIjp7ImFnZSI6MzYsImNpdHkiOiJMb25kb24ifSwidXBkYXRlZCI6IjIwMjUtMDEtMDNUMTY6MjQ6MjAuNTQ5OTA0WiIsImVUYWciOiI2ZDUwZGNjZGJiYzExOWFhZjIzYWY1NGE1YmNjZjM2YSJ9LHsiaWQiOiIyYVFDNEwiLCJuYW1lIjoiTWFyaWFuIFNhbGF6YXIiLCJleHRlcm5hbElkIjoiNTQ0NTg4ODIyMyIsInByb2ZpbGVVcmwiOiJodHRwczovL3BpY3N1bS5waG90b3MvMTAwLzIwMCIsImVtYWlsIjoibWFyaWFuLnNhbGF6YXJAcHVibnViLmNvbSIsInR5cGUiOiJhZG1pbiIsInN0YXR1cyI6ImRlbGV0ZWQiLCJjdXN0b20iOnsiYWdlIjozNiwiY2l0eSI6IkxvbmRvbiJ9LCJ1cGRhdGVkIjoiMjAyNS0wMS0yOFQwODo1OTo0Ni4yMDU0MzdaIiwiZVRhZyI6IjFmZDFlODBiMTRkZjc2NGJjMDEyYTYzMDFjMTZjM2JjIn0seyJpZCI6IjJFRUdZQ1BpdXNlcl9Qb29qUHNmMSIsIm5hbWUiOiIyRUVHWUNQaVRlc3QgVXNlciIsImV4dGVybmFsSWQiOm51bGwsInByb2ZpbGVVcmwiOm51bGwsImVtYWlsIjpudWxsLCJ0eXBlIjpudWxsLCJzdGF0dXMiOm51bGwsImN1c3RvbSI6bnVsbCwidXBkYXRlZCI6IjIwMjQtMTItMTJUMTM6MjY6MjAuMjg0NDA1WiIsImVUYWciOiIyNjBlZTNlZTc3NjU5ZGFkYmJjZjgyNzc2MGYyOTJmYiJ9LHsiaWQiOiIzamJKQTdaNnVzZXJfVFl6NmRSWHYiLCJuYW1lIjoiM2piSkE3WjZUZXN0IFVzZXIiLCJleHRlcm5hbElkIjpudWxsLCJwcm9maWxlVXJsIjpudWxsLCJlbWFpbCI6bnVsbCwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJjdXN0b20iOm51bGwsInVwZGF0ZWQiOiIyMDI0LTEyLTEyVDEzOjI0OjM1LjgzODI3OVoiLCJlVGFnIjoiMGM0M2JhM2UyODk2Mjg2YzA2ZGY5YjI5NjdkNTQwMjYifSx7ImlkIjoiM0pHbXZtR1J1c2VyX2gyOUozRmRXIiwibmFtZSI6IjNKR212bUdSVGVzdCBVc2VyIiwiZXh0ZXJuYWxJZCI6bnVsbCwicHJvZmlsZVVybCI6bnVsbCwiZW1haWwiOm51bGwsInR5cGUiOm51bGwsInN0YXR1cyI6bnVsbCwiY3VzdG9tIjpudWxsLCJ1cGRhdGVkIjoiMjAyNC0xMi0xMlQxMzoyNzo0NS40NzE1MloiLCJlVGFnIjoiOGMwMWUzMDI5OGUyOWY0MzlmMjlmNDBlYjE5NjZlY2MifV0sInRvdGFsQ291bnQiOjIzMjAsIm5leHQiOiJNVEEifZRzLg==" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/asyncio/objects_v2/uuid/get_uuid.json b/tests/integrational/fixtures/asyncio/objects_v2/uuid/get_uuid.json new file mode 100644 index 00000000..13380a1e --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/uuid/get_uuid.json @@ -0,0 +1,58 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=custom%2Cstatus%2Ctype", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:35 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "290" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVNQEAAAAAAAB9lIwGc3RyaW5nlFgiAQAAeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZSIsImV4dGVybmFsSWQiOiIxMjM0IiwicHJvZmlsZVVybCI6Imh0dHA6Ly9leGFtcGxlLmNvbSIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsInR5cGUiOiJRQSIsInN0YXR1cyI6Im9ubGluZSIsImN1c3RvbSI6eyJrZXkxIjoidmFsMSIsImtleTIiOiJ2YWwyIn0sInVwZGF0ZWQiOiIyMDI1LTAyLTA2VDIxOjE2OjM0LjUyNzg2M1oiLCJlVGFnIjoiZjJkN2EzODY0NDAyZDI1NWQyYWUyMjU1NTY0OTg0MWEifX2Ucy4=" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/asyncio/objects_v2/uuid/if_matches_etag.json b/tests/integrational/fixtures/asyncio/objects_v2/uuid/if_matches_etag.json new file mode 100644 index 00000000..461229c3 --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/uuid/if_matches_etag.json @@ -0,0 +1,361 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype", + "body": { + "pickle": "gASVUAAAAAAAAACMTHsibmFtZSI6ICJTb21lIG5hbWUiLCAiZW1haWwiOiBudWxsLCAiZXh0ZXJuYWxJZCI6IG51bGwsICJwcm9maWxlVXJsIjogbnVsbH2ULg==" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "76" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:36 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "215" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV5wAAAAAAAAB9lIwGc3RyaW5nlIzXeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZSIsImV4dGVybmFsSWQiOm51bGwsInByb2ZpbGVVcmwiOm51bGwsImVtYWlsIjpudWxsLCJ0eXBlIjpudWxsLCJzdGF0dXMiOm51bGwsInVwZGF0ZWQiOiIyMDI1LTAyLTA2VDIxOjE2OjM2LjM5NDEyOVoiLCJlVGFnIjoiMDExYmQxMDRjZWM0MjhiOTA0YjRmNDJmZDk2OGYxZTgifX2Ucy4=" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype&l_obj=0.36420512199401855", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:36 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "215" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV5wAAAAAAAAB9lIwGc3RyaW5nlIzXeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZSIsImV4dGVybmFsSWQiOm51bGwsInByb2ZpbGVVcmwiOm51bGwsImVtYWlsIjpudWxsLCJ0eXBlIjpudWxsLCJzdGF0dXMiOm51bGwsInVwZGF0ZWQiOiIyMDI1LTAyLTA2VDIxOjE2OjM2LjM5NDEyOVoiLCJlVGFnIjoiMDExYmQxMDRjZWM0MjhiOTA0YjRmNDJmZDk2OGYxZTgifX2Ucy4=" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype&l_obj=0.28897154331207275", + "body": { + "pickle": "gASVUgAAAAAAAACMTnsibmFtZSI6ICJTb21lIG5hbWUtMiIsICJlbWFpbCI6IG51bGwsICJleHRlcm5hbElkIjogbnVsbCwgInByb2ZpbGVVcmwiOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "78" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:36 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "217" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV6QAAAAAAAAB9lIwGc3RyaW5nlIzZeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZS0yIiwiZXh0ZXJuYWxJZCI6bnVsbCwicHJvZmlsZVVybCI6bnVsbCwiZW1haWwiOm51bGwsInR5cGUiOm51bGwsInN0YXR1cyI6bnVsbCwidXBkYXRlZCI6IjIwMjUtMDItMDZUMjE6MTY6MzYuODQyNDQ5WiIsImVUYWciOiJkNWJlNmI0OTlhZTU2ZjJjNjE4YTcwZGI1ZGNmYzk5OCJ9fZRzLg==" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype&l_obj=0.26676233609517414", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:37 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "217" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV6QAAAAAAAAB9lIwGc3RyaW5nlIzZeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZS0yIiwiZXh0ZXJuYWxJZCI6bnVsbCwicHJvZmlsZVVybCI6bnVsbCwiZW1haWwiOm51bGwsInR5cGUiOm51bGwsInN0YXR1cyI6bnVsbCwidXBkYXRlZCI6IjIwMjUtMDItMDZUMjE6MTY6MzYuODQyNDQ5WiIsImVUYWciOiJkNWJlNmI0OTlhZTU2ZjJjNjE4YTcwZGI1ZGNmYzk5OCJ9fZRzLg==" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype&l_obj=0.2539291977882385", + "body": { + "pickle": "gASVUgAAAAAAAACMTnsibmFtZSI6ICJTb21lIG5hbWUtMyIsICJlbWFpbCI6IG51bGwsICJleHRlcm5hbElkIjogbnVsbCwgInByb2ZpbGVVcmwiOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "if-match": [ + "d5be6b499ae56f2c618a70db5dcfc998" + ], + "content-length": [ + "78" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:37 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "216" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV6AAAAAAAAAB9lIwGc3RyaW5nlIzYeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZS0zIiwiZXh0ZXJuYWxJZCI6bnVsbCwicHJvZmlsZVVybCI6bnVsbCwiZW1haWwiOm51bGwsInR5cGUiOm51bGwsInN0YXR1cyI6bnVsbCwidXBkYXRlZCI6IjIwMjUtMDItMDZUMjE6MTY6MzcuMjgwNDRaIiwiZVRhZyI6ImMyZTVkZTljNjU0YTQ2MmU0YjI4N2ZkYjg2MmM4YzhkIn19lHMu" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype&l_obj=0.24891014099121095", + "body": { + "pickle": "gASVUgAAAAAAAACMTnsibmFtZSI6ICJTb21lIG5hbWUtMyIsICJlbWFpbCI6IG51bGwsICJleHRlcm5hbElkIjogbnVsbCwgInByb2ZpbGVVcmwiOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "if-match": [ + "011bd104cec428b904b4f42fd968f1e8" + ], + "content-length": [ + "78" + ] + } + }, + "response": { + "status": { + "code": 412, + "message": "Precondition Failed" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:37 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "107" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVewAAAAAAAAB9lIwGc3RyaW5nlIxreyJzdGF0dXMiOjQxMiwiZXJyb3IiOnsibWVzc2FnZSI6IlVzZXIgdG8gdXBkYXRlIGhhcyBiZWVuIG1vZGlmaWVkIGFmdGVyIGl0IHdhcyByZWFkLiIsInNvdXJjZSI6Im9iamVjdHMifX2Ucy4=" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/asyncio/objects_v2/uuid/remove_uuid.json b/tests/integrational/fixtures/asyncio/objects_v2/uuid/remove_uuid.json new file mode 100644 index 00000000..90fd056f --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/uuid/remove_uuid.json @@ -0,0 +1,58 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "DELETE", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:35 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "26" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVKgAAAAAAAAB9lIwGc3RyaW5nlIwaeyJzdGF0dXMiOjIwMCwiZGF0YSI6bnVsbH2Ucy4=" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/asyncio/objects_v2/uuid/set_uuid.json b/tests/integrational/fixtures/asyncio/objects_v2/uuid/set_uuid.json new file mode 100644 index 00000000..3340eace --- /dev/null +++ b/tests/integrational/fixtures/asyncio/objects_v2/uuid/set_uuid.json @@ -0,0 +1,66 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=custom%2Cstatus%2Ctype", + "body": { + "pickle": "gASVnAAAAAAAAACMmHsibmFtZSI6ICJTb21lIG5hbWUiLCAiZW1haWwiOiAidGVzdEBleGFtcGxlLmNvbSIsICJleHRlcm5hbElkIjogIjEyMzQiLCAicHJvZmlsZVVybCI6ICJodHRwOi8vZXhhbXBsZS5jb20iLCAiY3VzdG9tIjogeyJrZXkxIjogInZhbDEiLCAia2V5MiI6ICJ2YWwyIn19lC4=" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python-Asyncio/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "152" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 21:16:34 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "290" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVNQEAAAAAAAB9lIwGc3RyaW5nlFgiAQAAeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZSIsImV4dGVybmFsSWQiOiIxMjM0IiwicHJvZmlsZVVybCI6Imh0dHA6Ly9leGFtcGxlLmNvbSIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsInR5cGUiOiJRQSIsInN0YXR1cyI6Im9ubGluZSIsImN1c3RvbSI6eyJrZXkxIjoidmFsMSIsImtleTIiOiJ2YWwyIn0sInVwZGF0ZWQiOiIyMDI1LTAyLTA2VDIxOjE2OjM0LjUyNzg2M1oiLCJlVGFnIjoiZjJkN2EzODY0NDAyZDI1NWQyYWUyMjU1NTY0OTg0MWEifX2Ucy4=" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/native_sync/objects_v2/channel/if_matches_etag.json b/tests/integrational/fixtures/native_sync/objects_v2/channel/if_matches_etag.json new file mode 100644 index 00000000..c7014034 --- /dev/null +++ b/tests/integrational/fixtures/native_sync/objects_v2/channel/if_matches_etag.json @@ -0,0 +1,361 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype", + "body": { + "pickle": "gASVXAAAAAAAAACMWHsibmFtZSI6ICJTb21lIG5hbWUiLCAiZGVzY3JpcHRpb24iOiBudWxsLCAic3RhdHVzIjogbnVsbCwgInR5cGUiOiBudWxsLCAiY3VzdG9tIjogbnVsbH2ULg==" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "88" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 15:11:06 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "190" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVzgAAAAAAAAB9lIwGc3RyaW5nlIy+eyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lIiwiZGVzY3JpcHRpb24iOm51bGwsInR5cGUiOm51bGwsInN0YXR1cyI6bnVsbCwidXBkYXRlZCI6IjIwMjUtMDItMDZUMTU6MTE6MDYuNjEwNDM5WiIsImVUYWciOiI1NDVhM2M2NDA4YjE0OTdjM2IzMDc0NmFmZTU1MDVkMyJ9fZRzLg==" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 15:11:06 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "190" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVzgAAAAAAAAB9lIwGc3RyaW5nlIy+eyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lIiwiZGVzY3JpcHRpb24iOm51bGwsInR5cGUiOm51bGwsInN0YXR1cyI6bnVsbCwidXBkYXRlZCI6IjIwMjUtMDItMDZUMTU6MTE6MDYuNjEwNDM5WiIsImVUYWciOiI1NDVhM2M2NDA4YjE0OTdjM2IzMDc0NmFmZTU1MDVkMyJ9fZRzLg==" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype", + "body": { + "pickle": "gASVXgAAAAAAAACMWnsibmFtZSI6ICJTb21lIG5hbWUtMiIsICJkZXNjcmlwdGlvbiI6IG51bGwsICJzdGF0dXMiOiBudWxsLCAidHlwZSI6IG51bGwsICJjdXN0b20iOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "90" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 15:11:07 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "192" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV0AAAAAAAAAB9lIwGc3RyaW5nlIzAeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lLTIiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQxNToxMTowNy4xNDYxOTJaIiwiZVRhZyI6IjhhZjBlMGU2MDI0NDViYjYwMGE4MTY0YjU3NTg5YjM1In19lHMu" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 15:11:07 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "192" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV0AAAAAAAAAB9lIwGc3RyaW5nlIzAeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lLTIiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQxNToxMTowNy4xNDYxOTJaIiwiZVRhZyI6IjhhZjBlMGU2MDI0NDViYjYwMGE4MTY0YjU3NTg5YjM1In19lHMu" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype", + "body": { + "pickle": "gASVXgAAAAAAAACMWnsibmFtZSI6ICJTb21lIG5hbWUtMyIsICJkZXNjcmlwdGlvbiI6IG51bGwsICJzdGF0dXMiOiBudWxsLCAidHlwZSI6IG51bGwsICJjdXN0b20iOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ], + "content-type": [ + "application/json" + ], + "if-match": [ + "8af0e0e602445bb600a8164b57589b35" + ], + "content-length": [ + "90" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 15:11:07 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "192" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV0AAAAAAAAAB9lIwGc3RyaW5nlIzAeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWVjaGFubmVsaWQiLCJuYW1lIjoiU29tZSBuYW1lLTMiLCJkZXNjcmlwdGlvbiI6bnVsbCwidHlwZSI6bnVsbCwic3RhdHVzIjpudWxsLCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQxNToxMTowNy41ODIwMjhaIiwiZVRhZyI6IjM4YjA2ZTVjMjM3ZTQyMmNmODQ1YTE3YmQ5ZWJmYzk2In19lHMu" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/channels/somechannelid?include=status%2Ctype", + "body": { + "pickle": "gASVXgAAAAAAAACMWnsibmFtZSI6ICJTb21lIG5hbWUtMyIsICJkZXNjcmlwdGlvbiI6IG51bGwsICJzdGF0dXMiOiBudWxsLCAidHlwZSI6IG51bGwsICJjdXN0b20iOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ], + "content-type": [ + "application/json" + ], + "if-match": [ + "545a3c6408b1497c3b30746afe5505d3" + ], + "content-length": [ + "90" + ] + } + }, + "response": { + "status": { + "code": 412, + "message": "Precondition Failed" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 15:11:07 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "110" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVfgAAAAAAAAB9lIwGc3RyaW5nlIxueyJzdGF0dXMiOjQxMiwiZXJyb3IiOnsibWVzc2FnZSI6IkNoYW5uZWwgdG8gdXBkYXRlIGhhcyBiZWVuIG1vZGlmaWVkIGFmdGVyIGl0IHdhcyByZWFkLiIsInNvdXJjZSI6Im9iamVjdHMifX2Ucy4=" + } + } + } + ] +} diff --git a/tests/integrational/fixtures/native_sync/objects_v2/uuid/if_matches_etag.json b/tests/integrational/fixtures/native_sync/objects_v2/uuid/if_matches_etag.json new file mode 100644 index 00000000..bc337046 --- /dev/null +++ b/tests/integrational/fixtures/native_sync/objects_v2/uuid/if_matches_etag.json @@ -0,0 +1,361 @@ +{ + "version": 1, + "interactions": [ + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype", + "body": { + "pickle": "gASVUAAAAAAAAACMTHsibmFtZSI6ICJTb21lIG5hbWUiLCAiZW1haWwiOiBudWxsLCAiZXh0ZXJuYWxJZCI6IG51bGwsICJwcm9maWxlVXJsIjogbnVsbH2ULg==" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "76" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 14:53:43 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "219" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV6wAAAAAAAAB9lIwGc3RyaW5nlIzbeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZSIsImV4dGVybmFsSWQiOm51bGwsInByb2ZpbGVVcmwiOm51bGwsImVtYWlsIjpudWxsLCJ0eXBlIjoiUUEiLCJzdGF0dXMiOiJvbmxpbmUiLCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQxNDo1Mzo0My41NTY3ODlaIiwiZVRhZyI6IjYxYmUyZWUwZmUxZTM0ODE2NTcyYzkwNzllMWZmZWVjIn19lHMu" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 14:53:43 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "219" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV6wAAAAAAAAB9lIwGc3RyaW5nlIzbeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZSIsImV4dGVybmFsSWQiOm51bGwsInByb2ZpbGVVcmwiOm51bGwsImVtYWlsIjpudWxsLCJ0eXBlIjoiUUEiLCJzdGF0dXMiOiJvbmxpbmUiLCJ1cGRhdGVkIjoiMjAyNS0wMi0wNlQxNDo1Mzo0My41NTY3ODlaIiwiZVRhZyI6IjYxYmUyZWUwZmUxZTM0ODE2NTcyYzkwNzllMWZmZWVjIn19lHMu" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype", + "body": { + "pickle": "gASVUgAAAAAAAACMTnsibmFtZSI6ICJTb21lIG5hbWUtMiIsICJlbWFpbCI6IG51bGwsICJleHRlcm5hbElkIjogbnVsbCwgInByb2ZpbGVVcmwiOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "78" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 14:53:44 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "221" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV7QAAAAAAAAB9lIwGc3RyaW5nlIzdeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZS0yIiwiZXh0ZXJuYWxJZCI6bnVsbCwicHJvZmlsZVVybCI6bnVsbCwiZW1haWwiOm51bGwsInR5cGUiOiJRQSIsInN0YXR1cyI6Im9ubGluZSIsInVwZGF0ZWQiOiIyMDI1LTAyLTA2VDE0OjUzOjQzLjk5ODcwM1oiLCJlVGFnIjoiMTAxYmJlOWEzNzJmZDkwYzdjYjYyNDk3ODE3ZTY0MzgifX2Ucy4=" + } + } + }, + { + "request": { + "method": "GET", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype", + "body": "", + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 14:53:44 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "221" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV7QAAAAAAAAB9lIwGc3RyaW5nlIzdeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZS0yIiwiZXh0ZXJuYWxJZCI6bnVsbCwicHJvZmlsZVVybCI6bnVsbCwiZW1haWwiOm51bGwsInR5cGUiOiJRQSIsInN0YXR1cyI6Im9ubGluZSIsInVwZGF0ZWQiOiIyMDI1LTAyLTA2VDE0OjUzOjQzLjk5ODcwM1oiLCJlVGFnIjoiMTAxYmJlOWEzNzJmZDkwYzdjYjYyNDk3ODE3ZTY0MzgifX2Ucy4=" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype", + "body": { + "pickle": "gASVUgAAAAAAAACMTnsibmFtZSI6ICJTb21lIG5hbWUtMyIsICJlbWFpbCI6IG51bGwsICJleHRlcm5hbElkIjogbnVsbCwgInByb2ZpbGVVcmwiOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ], + "content-type": [ + "application/json" + ], + "if-match": [ + "101bbe9a372fd90c7cb62497817e6438" + ], + "content-length": [ + "78" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 14:53:44 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "221" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASV7QAAAAAAAAB9lIwGc3RyaW5nlIzdeyJzdGF0dXMiOjIwMCwiZGF0YSI6eyJpZCI6InNvbWV1dWlkIiwibmFtZSI6IlNvbWUgbmFtZS0zIiwiZXh0ZXJuYWxJZCI6bnVsbCwicHJvZmlsZVVybCI6bnVsbCwiZW1haWwiOm51bGwsInR5cGUiOiJRQSIsInN0YXR1cyI6Im9ubGluZSIsInVwZGF0ZWQiOiIyMDI1LTAyLTA2VDE0OjUzOjQ0LjQ0MDE2NFoiLCJlVGFnIjoiYmQ5NDIwZjYwYTZmZDllNzljYzZhMTA5YWM1OTg1YjMifX2Ucy4=" + } + } + }, + { + "request": { + "method": "PATCH", + "uri": "https://ps.pndsn.com/v2/objects/{PN_KEY_SUBSCRIBE}/uuids/someuuid?include=status%2Ctype", + "body": { + "pickle": "gASVUgAAAAAAAACMTnsibmFtZSI6ICJTb21lIG5hbWUtMyIsICJlbWFpbCI6IG51bGwsICJleHRlcm5hbElkIjogbnVsbCwgInByb2ZpbGVVcmwiOiBudWxsfZQu" + }, + "headers": { + "host": [ + "ps.pndsn.com" + ], + "accept": [ + "*/*" + ], + "accept-encoding": [ + "gzip, deflate" + ], + "connection": [ + "keep-alive" + ], + "user-agent": [ + "PubNub-Python/10.1.0" + ], + "content-type": [ + "application/json" + ], + "if-match": [ + "61be2ee0fe1e34816572c9079e1ffeec" + ], + "content-length": [ + "78" + ] + } + }, + "response": { + "status": { + "code": 412, + "message": "Precondition Failed" + }, + "headers": { + "Date": [ + "Thu, 06 Feb 2025 14:53:44 GMT" + ], + "Content-Type": [ + "application/json" + ], + "Content-Length": [ + "107" + ], + "Connection": [ + "keep-alive" + ], + "Access-Control-Allow-Credentials": [ + "true" + ], + "Access-Control-Expose-Headers": [ + "*" + ] + }, + "body": { + "pickle": "gASVewAAAAAAAAB9lIwGc3RyaW5nlIxreyJzdGF0dXMiOjQxMiwiZXJyb3IiOnsibWVzc2FnZSI6IlVzZXIgdG8gdXBkYXRlIGhhcyBiZWVuIG1vZGlmaWVkIGFmdGVyIGl0IHdhcyByZWFkLiIsInNvdXJjZSI6Im9iamVjdHMifX2Ucy4=" + } + } + } + ] +} diff --git a/tests/integrational/native_sync/objects_v2/test_channel.py b/tests/integrational/native_sync/objects_v2/test_channel.py index b92f624b..82907115 100644 --- a/tests/integrational/native_sync/objects_v2/test_channel.py +++ b/tests/integrational/native_sync/objects_v2/test_channel.py @@ -3,6 +3,7 @@ from pubnub.endpoints.objects_v2.channel.get_channel import GetChannel from pubnub.endpoints.objects_v2.channel.remove_channel import RemoveChannel from pubnub.endpoints.objects_v2.channel.set_channel import SetChannel +from pubnub.exceptions import PubNubException from pubnub.models.consumer.common import PNStatus from pubnub.models.consumer.objects_v2.channel import PNSetChannelMetadataResult, PNGetChannelMetadataResult, \ PNRemoveChannelMetadataResult, PNGetAllChannelMetadataResult @@ -166,3 +167,41 @@ def test_get_all_channel_happy_path(self): assert get_all_channel_result.result.total_count != 0 assert get_all_channel_result.result.next is not None assert get_all_channel_result.result.prev is None + + @pn_vcr.use_cassette('tests/integrational/fixtures/native_sync/objects_v2/channel/if_matches_etag.json', + filter_query_parameters=['uuid', 'pnsdk'], serializer='pn_json') + def test_if_matches_etag(self): + config = pnconf_env_copy() + pubnub = PubNub(config) + + set_channel = pubnub.set_channel_metadata(channel=self._some_channel_id, name=self._some_name).sync() + original_etag = set_channel.result.data.get('eTag') + get_channel = pubnub.get_channel_metadata(channel=self._some_channel_id).sync() + assert original_etag == get_channel.result.data.get('eTag') + + # Update without eTag should be possible + set_channel = pubnub.set_channel_metadata(channel=self._some_channel_id, name=f"{self._some_name}-2").sync() + + # Response should contain new eTag + new_etag = set_channel.result.data.get('eTag') + assert original_etag != new_etag + assert set_channel.result.data.get('name') == f"{self._some_name}-2" + + get_channel = pubnub.get_channel_metadata(channel=self._some_channel_id).sync() + assert original_etag != get_channel.result.data.get('eTag') + assert get_channel.result.data.get('name') == f"{self._some_name}-2" + + # Update with correct eTag should be possible + set_channel = pubnub.set_channel_metadata(channel=self._some_channel_id, name=f"{self._some_name}-3") \ + .if_matches_etag(new_etag) \ + .sync() + assert set_channel.result.data.get('name') == f"{self._some_name}-3" + + try: + # Update with original - now outdated - eTag should fail + set_channel = pubnub.set_channel_metadata(channel=self._some_channel_id, name=f"{self._some_name}-3") \ + .if_matches_etag(original_etag) \ + .sync() + except PubNubException as e: + assert e.get_status_code() == 412 + assert e.get_error_message().get('message') == 'Channel to update has been modified after it was read.' diff --git a/tests/integrational/native_sync/objects_v2/test_uuid.py b/tests/integrational/native_sync/objects_v2/test_uuid.py index 1f78f32d..5ac8f882 100644 --- a/tests/integrational/native_sync/objects_v2/test_uuid.py +++ b/tests/integrational/native_sync/objects_v2/test_uuid.py @@ -3,6 +3,7 @@ from pubnub.endpoints.objects_v2.uuid.get_uuid import GetUuid from pubnub.endpoints.objects_v2.uuid.remove_uuid import RemoveUuid from pubnub.endpoints.objects_v2.uuid.set_uuid import SetUuid +from pubnub.exceptions import PubNubException from pubnub.models.consumer.common import PNStatus from pubnub.models.consumer.objects_v2.sort import PNSortKey, PNSortKeyValue from pubnub.models.consumer.objects_v2.uuid import PNSetUUIDMetadataResult, PNGetUUIDMetadataResult, \ @@ -169,3 +170,41 @@ def test_get_all_uuid_happy_path(self): assert get_all_uuid_result.result.total_count != 0 assert get_all_uuid_result.result.next is not None assert get_all_uuid_result.result.prev is None + + @pn_vcr.use_cassette('tests/integrational/fixtures/native_sync/objects_v2/uuid/if_matches_etag.json', + filter_query_parameters=['uuid', 'pnsdk'], serializer='pn_json') + def test_if_matches_etag(self): + config = pnconf_env_copy() + pubnub = PubNub(config) + + set_uuid = pubnub.set_uuid_metadata(uuid=self._some_uuid, name=self._some_name).sync() + original_etag = set_uuid.result.data.get('eTag') + get_uuid = pubnub.get_uuid_metadata(uuid=self._some_uuid).sync() + assert original_etag == get_uuid.result.data.get('eTag') + + # Update without eTag should be possible + set_uuid = pubnub.set_uuid_metadata(uuid=self._some_uuid, name=f"{self._some_name}-2").sync() + + # Response should contain new eTag + new_etag = set_uuid.result.data.get('eTag') + assert original_etag != new_etag + assert set_uuid.result.data.get('name') == f"{self._some_name}-2" + + get_uuid = pubnub.get_uuid_metadata(uuid=self._some_uuid).sync() + assert original_etag != get_uuid.result.data.get('eTag') + assert get_uuid.result.data.get('name') == f"{self._some_name}-2" + + # Update with correct eTag should be possible + set_uuid = pubnub.set_uuid_metadata(uuid=self._some_uuid, name=f"{self._some_name}-3") \ + .if_matches_etag(new_etag) \ + .sync() + assert set_uuid.result.data.get('name') == f"{self._some_name}-3" + + try: + # Update with original - now outdated - eTag should fail + set_uuid = pubnub.set_uuid_metadata(uuid=self._some_uuid, name=f"{self._some_name}-3") \ + .if_matches_etag(original_etag) \ + .sync() + except PubNubException as e: + assert e.get_status_code() == 412 + assert e.get_error_message().get('message') == 'User to update has been modified after it was read.'