Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions tests/api_resources/kv/namespaces/test_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,40 @@ def test_path_params_update(self, client: Cloudflare) -> None:
value="Some Value",
)

@parametrize
@pytest.mark.respx(base_url=base_url)
def test_update_uses_multipart_form_data(self, client: Cloudflare, respx_mock: MockRouter) -> None:
"""Test that values.update sends data as multipart/form-data, not JSON.

This is a regression test for https://github.com/cloudflare/cloudflare-python/issues/2519
"""
respx_mock.put(
"/accounts/023e105f4ecef8ad9ca31a8372d0c353/storage/kv/namespaces/0f2ac74b498b48028cb68387c421e279/values/My-Key"
).mock(return_value=httpx.Response(200, json={"success": True, "result": {}}))

client.kv.namespaces.values.update(
key_name="My-Key",
account_id="023e105f4ecef8ad9ca31a8372d0c353",
namespace_id="0f2ac74b498b48028cb68387c421e279",
metadata='{"someMetadataKey": "someMetadataValue"}',
value="Some Value",
)

# Verify the request was made
assert respx_mock.calls.call_count == 1
request: httpx.Request = cast(Any, respx_mock.calls[0]).request

# Verify Content-Type is multipart/form-data (with boundary)
content_type = request.headers.get("content-type", "")
assert content_type.startswith("multipart/form-data"), (
f"Expected Content-Type to start with 'multipart/form-data', got '{content_type}'"
)

# Verify the body contains separate form fields for value and metadata
body = request.content.decode("utf-8")
assert "Some Value" in body, "Value should be in the multipart body"
assert "someMetadataKey" in body, "Metadata should be in the multipart body"

@parametrize
def test_method_delete(self, client: Cloudflare) -> None:
value = client.kv.namespaces.values.delete(
Expand Down Expand Up @@ -341,6 +375,40 @@ async def test_path_params_update(self, async_client: AsyncCloudflare) -> None:
value="Some Value",
)

@parametrize
@pytest.mark.respx(base_url=base_url)
async def test_update_uses_multipart_form_data(self, async_client: AsyncCloudflare, respx_mock: MockRouter) -> None:
"""Test that values.update sends data as multipart/form-data, not JSON.

This is a regression test for https://github.com/cloudflare/cloudflare-python/issues/2519
"""
respx_mock.put(
"/accounts/023e105f4ecef8ad9ca31a8372d0c353/storage/kv/namespaces/0f2ac74b498b48028cb68387c421e279/values/My-Key"
).mock(return_value=httpx.Response(200, json={"success": True, "result": {}}))

await async_client.kv.namespaces.values.update(
key_name="My-Key",
account_id="023e105f4ecef8ad9ca31a8372d0c353",
namespace_id="0f2ac74b498b48028cb68387c421e279",
metadata='{"someMetadataKey": "someMetadataValue"}',
value="Some Value",
)

# Verify the request was made
assert respx_mock.calls.call_count == 1
request: httpx.Request = cast(Any, respx_mock.calls[0]).request

# Verify Content-Type is multipart/form-data (with boundary)
content_type = request.headers.get("content-type", "")
assert content_type.startswith("multipart/form-data"), (
f"Expected Content-Type to start with 'multipart/form-data', got '{content_type}'"
)

# Verify the body contains separate form fields for value and metadata
body = request.content.decode("utf-8")
assert "Some Value" in body, "Value should be in the multipart body"
assert "someMetadataKey" in body, "Metadata should be in the multipart body"

@parametrize
async def test_method_delete(self, async_client: AsyncCloudflare) -> None:
value = await async_client.kv.namespaces.values.delete(
Expand Down
Loading