442 lines
12 KiB
Python
442 lines
12 KiB
Python
# Copyright 2012 Pinterest.com
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import json
|
|
from collections import defaultdict
|
|
|
|
import pytest
|
|
from pymemcache.client.base import Client
|
|
from pymemcache.exceptions import (
|
|
MemcacheClientError,
|
|
MemcacheIllegalInputError,
|
|
MemcacheServerError,
|
|
)
|
|
from pymemcache.serde import PickleSerde, compressed_serde, pickle_serde
|
|
|
|
|
|
def get_set_helper(client, key, value, key2, value2):
|
|
result = client.get(key)
|
|
assert result is None
|
|
|
|
client.set(key, value, noreply=False)
|
|
result = client.get(key)
|
|
assert result == value
|
|
|
|
client.set(key2, value2, noreply=True)
|
|
result = client.get(key2)
|
|
assert result == value2
|
|
|
|
result = client.get_many([key, key2])
|
|
assert result == {key: value, key2: value2}
|
|
|
|
result = client.get_many([])
|
|
assert result == {}
|
|
|
|
|
|
@pytest.mark.integration()
|
|
@pytest.mark.parametrize(
|
|
"serde",
|
|
[
|
|
pickle_serde,
|
|
compressed_serde,
|
|
],
|
|
)
|
|
def test_get_set(client_class, host, port, serde, socket_module, key_prefix):
|
|
client = client_class(
|
|
(host, port), serde=serde, socket_module=socket_module, key_prefix=key_prefix
|
|
)
|
|
client.flush_all()
|
|
|
|
key = b"key"
|
|
value = b"value"
|
|
key2 = b"key2"
|
|
value2 = b"value2"
|
|
get_set_helper(client, key, value, key2, value2)
|
|
|
|
|
|
@pytest.mark.integration()
|
|
@pytest.mark.parametrize(
|
|
"serde",
|
|
[
|
|
pickle_serde,
|
|
compressed_serde,
|
|
],
|
|
)
|
|
def test_get_set_unicode_key(
|
|
client_class, host, port, serde, socket_module, key_prefix
|
|
):
|
|
client = client_class(
|
|
(host, port),
|
|
serde=serde,
|
|
socket_module=socket_module,
|
|
allow_unicode_keys=True,
|
|
key_prefix=key_prefix,
|
|
)
|
|
client.flush_all()
|
|
|
|
key = "こんにちは"
|
|
value = b"hello"
|
|
key2 = "my☃"
|
|
value2 = b"value2"
|
|
get_set_helper(client, key, value, key2, value2)
|
|
|
|
|
|
@pytest.mark.integration()
|
|
@pytest.mark.parametrize(
|
|
"serde",
|
|
[
|
|
pickle_serde,
|
|
compressed_serde,
|
|
],
|
|
)
|
|
def test_add_replace(client_class, host, port, serde, socket_module, key_prefix):
|
|
client = client_class(
|
|
(host, port), serde=serde, socket_module=socket_module, key_prefix=key_prefix
|
|
)
|
|
client.flush_all()
|
|
|
|
result = client.add(b"key", b"value", noreply=False)
|
|
assert result is True
|
|
result = client.get(b"key")
|
|
assert result == b"value"
|
|
|
|
result = client.add(b"key", b"value2", noreply=False)
|
|
assert result is False
|
|
result = client.get(b"key")
|
|
assert result == b"value"
|
|
|
|
result = client.replace(b"key1", b"value1", noreply=False)
|
|
assert result is False
|
|
result = client.get(b"key1")
|
|
assert result is None
|
|
|
|
result = client.replace(b"key", b"value2", noreply=False)
|
|
assert result is True
|
|
result = client.get(b"key")
|
|
assert result == b"value2"
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_append_prepend(client_class, host, port, socket_module, key_prefix):
|
|
client = client_class(
|
|
(host, port), socket_module=socket_module, key_prefix=key_prefix
|
|
)
|
|
client.flush_all()
|
|
|
|
result = client.append(b"key", b"value", noreply=False)
|
|
assert result is False
|
|
result = client.get(b"key")
|
|
assert result is None
|
|
|
|
result = client.set(b"key", b"value", noreply=False)
|
|
assert result is True
|
|
result = client.append(b"key", b"after", noreply=False)
|
|
assert result is True
|
|
result = client.get(b"key")
|
|
assert result == b"valueafter"
|
|
|
|
result = client.prepend(b"key1", b"value", noreply=False)
|
|
assert result is False
|
|
result = client.get(b"key1")
|
|
assert result is None
|
|
|
|
result = client.prepend(b"key", b"before", noreply=False)
|
|
assert result is True
|
|
result = client.get(b"key")
|
|
assert result == b"beforevalueafter"
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_cas(client_class, host, port, socket_module, key_prefix):
|
|
client = client_class(
|
|
(host, port), socket_module=socket_module, key_prefix=key_prefix
|
|
)
|
|
client.flush_all()
|
|
result = client.cas(b"key", b"value", b"1", noreply=False)
|
|
assert result is None
|
|
|
|
result = client.set(b"key", b"value", noreply=False)
|
|
assert result is True
|
|
|
|
# binary, string, and raw int all match -- should all be encoded as b'1'
|
|
result = client.cas(b"key", b"value", b"1", noreply=False)
|
|
assert result is False
|
|
result = client.cas(b"key", b"value", "1", noreply=False)
|
|
assert result is False
|
|
result = client.cas(b"key", b"value", 1, noreply=False)
|
|
assert result is False
|
|
|
|
result, cas = client.gets(b"key")
|
|
assert result == b"value"
|
|
|
|
result = client.cas(b"key", b"value1", cas, noreply=False)
|
|
assert result is True
|
|
|
|
result = client.cas(b"key", b"value2", cas, noreply=False)
|
|
assert result is False
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_gets(client_class, host, port, socket_module, key_prefix):
|
|
client = client_class(
|
|
(host, port), socket_module=socket_module, key_prefix=key_prefix
|
|
)
|
|
client.flush_all()
|
|
|
|
result = client.gets(b"key")
|
|
assert result == (None, None)
|
|
|
|
result = client.set(b"key", b"value", noreply=False)
|
|
assert result is True
|
|
result = client.gets(b"key")
|
|
assert result[0] == b"value"
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_delete(client_class, host, port, socket_module, key_prefix):
|
|
client = client_class(
|
|
(host, port), socket_module=socket_module, key_prefix=key_prefix
|
|
)
|
|
client.flush_all()
|
|
|
|
result = client.delete(b"key", noreply=False)
|
|
assert result is False
|
|
|
|
result = client.get(b"key")
|
|
assert result is None
|
|
result = client.set(b"key", b"value", noreply=False)
|
|
assert result is True
|
|
result = client.delete(b"key", noreply=False)
|
|
assert result is True
|
|
result = client.get(b"key")
|
|
assert result is None
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_incr_decr(client_class, host, port, socket_module, key_prefix):
|
|
client = Client((host, port), socket_module=socket_module, key_prefix=key_prefix)
|
|
client.flush_all()
|
|
|
|
result = client.incr(b"key", 1, noreply=False)
|
|
assert result is None
|
|
|
|
result = client.set(b"key", b"0", noreply=False)
|
|
assert result is True
|
|
result = client.incr(b"key", 1, noreply=False)
|
|
assert result == 1
|
|
|
|
def _bad_int():
|
|
client.incr(b"key", b"foobar")
|
|
|
|
with pytest.raises(MemcacheClientError):
|
|
_bad_int()
|
|
|
|
result = client.decr(b"key1", 1, noreply=False)
|
|
assert result is None
|
|
|
|
result = client.decr(b"key", 1, noreply=False)
|
|
assert result == 0
|
|
result = client.get(b"key")
|
|
assert result == b"0"
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_touch(client_class, host, port, socket_module, key_prefix):
|
|
client = client_class(
|
|
(host, port), socket_module=socket_module, key_prefix=key_prefix
|
|
)
|
|
client.flush_all()
|
|
|
|
result = client.touch(b"key", noreply=False)
|
|
assert result is False
|
|
|
|
result = client.set(b"key", b"0", 1, noreply=False)
|
|
assert result is True
|
|
|
|
result = client.touch(b"key", noreply=False)
|
|
assert result is True
|
|
|
|
result = client.touch(b"key", 1, noreply=False)
|
|
assert result is True
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_misc(client_class, host, port, socket_module, key_prefix):
|
|
client = Client((host, port), socket_module=socket_module, key_prefix=key_prefix)
|
|
client.flush_all()
|
|
|
|
# Ensure no exceptions are thrown
|
|
client.stats("cachedump", "1", "1")
|
|
|
|
success = client.cache_memlimit(50)
|
|
assert success
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_serialization_deserialization(host, port, socket_module):
|
|
class JsonSerde:
|
|
def serialize(self, key, value):
|
|
return json.dumps(value).encode("ascii"), 1
|
|
|
|
def deserialize(self, key, value, flags):
|
|
if flags == 1:
|
|
return json.loads(value.decode("ascii"))
|
|
return value
|
|
|
|
client = Client((host, port), serde=JsonSerde(), socket_module=socket_module)
|
|
client.flush_all()
|
|
|
|
value = {"a": "b", "c": ["d"]}
|
|
client.set(b"key", value)
|
|
result = client.get(b"key")
|
|
assert result == value
|
|
|
|
|
|
def serde_serialization_helper(client_class, host, port, socket_module, serde):
|
|
def check(value):
|
|
client.set(b"key", value, noreply=False)
|
|
result = client.get(b"key")
|
|
assert result == value
|
|
assert type(result) is type(value)
|
|
|
|
client = client_class((host, port), serde=serde, socket_module=socket_module)
|
|
client.flush_all()
|
|
|
|
check(b"byte string")
|
|
check("unicode string")
|
|
check("olé")
|
|
check("olé")
|
|
check(1)
|
|
check(123123123123123123123)
|
|
check({"a": "pickle"})
|
|
check(["one pickle", "two pickle"])
|
|
testdict = defaultdict(int)
|
|
testdict["one pickle"]
|
|
testdict[b"two pickle"]
|
|
check(testdict)
|
|
|
|
|
|
@pytest.mark.integration()
|
|
@pytest.mark.parametrize(
|
|
"serde",
|
|
[
|
|
pickle_serde,
|
|
compressed_serde,
|
|
],
|
|
)
|
|
def test_serde_serialization(client_class, host, port, socket_module, serde):
|
|
serde_serialization_helper(client_class, host, port, socket_module, serde)
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_serde_serialization0(client_class, host, port, socket_module):
|
|
serde_serialization_helper(
|
|
client_class, host, port, socket_module, PickleSerde(pickle_version=0)
|
|
)
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_serde_serialization2(client_class, host, port, socket_module):
|
|
serde_serialization_helper(
|
|
client_class, host, port, socket_module, PickleSerde(pickle_version=2)
|
|
)
|
|
|
|
|
|
@pytest.mark.integration()
|
|
def test_errors(client_class, host, port, socket_module):
|
|
client = client_class((host, port), socket_module=socket_module)
|
|
client.flush_all()
|
|
|
|
def _key_with_ws():
|
|
client.set(b"key with spaces", b"value", noreply=False)
|
|
|
|
with pytest.raises(MemcacheIllegalInputError):
|
|
_key_with_ws()
|
|
|
|
def _key_with_illegal_carriage_return():
|
|
client.set(b"\r\nflush_all", b"value", noreply=False)
|
|
|
|
with pytest.raises(MemcacheIllegalInputError):
|
|
_key_with_illegal_carriage_return()
|
|
|
|
def _key_too_long():
|
|
client.set(b"x" * 1024, b"value", noreply=False)
|
|
|
|
with pytest.raises(MemcacheClientError):
|
|
_key_too_long()
|
|
|
|
def _unicode_key_in_set():
|
|
client.set("\u0FFF", b"value", noreply=False)
|
|
|
|
with pytest.raises(MemcacheClientError):
|
|
_unicode_key_in_set()
|
|
|
|
def _unicode_key_in_get():
|
|
client.get("\u0FFF")
|
|
|
|
with pytest.raises(MemcacheClientError):
|
|
_unicode_key_in_get()
|
|
|
|
def _unicode_value_in_set():
|
|
client.set(b"key", "\u0FFF", noreply=False)
|
|
|
|
with pytest.raises(MemcacheClientError):
|
|
_unicode_value_in_set()
|
|
|
|
|
|
@pytest.mark.skip("https://github.com/pinterest/pymemcache/issues/39")
|
|
@pytest.mark.integration()
|
|
def test_tls(client_class, tls_host, tls_port, socket_module, tls_context):
|
|
client = client_class(
|
|
(tls_host, tls_port), socket_module=socket_module, tls_context=tls_context
|
|
)
|
|
client.flush_all()
|
|
|
|
key = b"key"
|
|
value = b"value"
|
|
key2 = b"key2"
|
|
value2 = b"value2"
|
|
get_set_helper(client, key, value, key2, value2)
|
|
|
|
|
|
@pytest.mark.integration()
|
|
@pytest.mark.parametrize(
|
|
"serde,should_fail",
|
|
[
|
|
(pickle_serde, True),
|
|
(compressed_serde, False),
|
|
],
|
|
)
|
|
def test_get_set_large(
|
|
client_class,
|
|
host,
|
|
port,
|
|
serde,
|
|
socket_module,
|
|
should_fail,
|
|
):
|
|
client = client_class((host, port), serde=serde, socket_module=socket_module)
|
|
client.flush_all()
|
|
|
|
key = b"key"
|
|
value = b"value" * 1024 * 1024
|
|
key2 = b"key2"
|
|
value2 = b"value2" * 1024 * 1024
|
|
|
|
if should_fail:
|
|
with pytest.raises(MemcacheServerError):
|
|
get_set_helper(client, key, value, key2, value2)
|
|
else:
|
|
get_set_helper(client, key, value, key2, value2)
|