summaryrefslogtreecommitdiff
path: root/pymemcache/test/test_serde.py
blob: cb9227153f0244839be93a7fa4f5d5986b7c291e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
from unittest import TestCase

from pymemcache.serde import (
    CompressedSerde,
    pickle_serde,
    PickleSerde,
    FLAG_BYTES,
    FLAG_COMPRESSED,
    FLAG_PICKLE,
    FLAG_INTEGER,
    FLAG_TEXT,
)
import pytest
import pickle
import sys
import zlib


class CustomInt(int):
    """
    Custom integer type for testing.

    Entirely useless, but used to show that built in types get serialized and
    deserialized back as the same type of object.
    """

    pass


def check(serde, value, expected_flags):
    serialized, flags = serde.serialize(b"key", value)
    assert flags == expected_flags

    # pymemcache stores values as byte strings, so we immediately the value
    # if needed so deserialized works as it would with a real server
    if not isinstance(serialized, bytes):
        serialized = str(serialized).encode("ascii")

    deserialized = serde.deserialize(b"key", serialized, flags)
    assert deserialized == value


@pytest.mark.unit()
class TestSerde:
    serde = pickle_serde

    def test_bytes(self):
        check(self.serde, b"value", FLAG_BYTES)
        check(self.serde, b"\xc2\xa3 $ \xe2\x82\xac", FLAG_BYTES)  # £ $ €

    def test_unicode(self):
        check(self.serde, "value", FLAG_TEXT)
        check(self.serde, "£ $ €", FLAG_TEXT)

    def test_int(self):
        check(self.serde, 1, FLAG_INTEGER)

    def test_pickleable(self):
        check(self.serde, {"a": "dict"}, FLAG_PICKLE)

    def test_subtype(self):
        # Subclass of a native type will be restored as the same type
        check(self.serde, CustomInt(123123), FLAG_PICKLE)


@pytest.mark.unit()
class TestSerdePickleVersion0(TestCase):
    serde = PickleSerde(pickle_version=0)


@pytest.mark.unit()
class TestSerdePickleVersion1(TestCase):
    serde = PickleSerde(pickle_version=1)


@pytest.mark.unit()
class TestSerdePickleVersion2(TestCase):
    serde = PickleSerde(pickle_version=2)


@pytest.mark.unit()
class TestSerdePickleVersionHighest(TestCase):
    serde = PickleSerde(pickle_version=pickle.HIGHEST_PROTOCOL)


@pytest.mark.parametrize("serde", [pickle_serde, CompressedSerde()])
@pytest.mark.unit()
def test_compressed_simple(serde):
    # test_bytes
    check(serde, b"value", FLAG_BYTES)
    check(serde, b"\xc2\xa3 $ \xe2\x82\xac", FLAG_BYTES)  # £ $ €

    # test_unicode
    check(serde, "value", FLAG_TEXT)
    check(serde, "£ $ €", FLAG_TEXT)

    # test_int
    check(serde, 1, FLAG_INTEGER)

    # test_pickleable
    check(serde, {"a": "dict"}, FLAG_PICKLE)

    # test_subtype
    # Subclass of a native type will be restored as the same type
    check(serde, CustomInt(12312), FLAG_PICKLE)


@pytest.mark.parametrize(
    "serde",
    [
        CompressedSerde(min_compress_len=49),
        # Custom compression.  This could be something like lz4
        CompressedSerde(
            compress=lambda value: zlib.compress(value, 9),
            decompress=lambda value: zlib.decompress(value),
            min_compress_len=49,
        ),
    ],
)
@pytest.mark.unit()
def test_compressed_complex(serde):
    # test_bytes
    check(serde, b"value" * 10, FLAG_BYTES | FLAG_COMPRESSED)
    check(serde, b"\xc2\xa3 $ \xe2\x82\xac" * 10, FLAG_BYTES | FLAG_COMPRESSED)  # £ $ €

    # test_unicode
    check(serde, "value" * 10, FLAG_TEXT | FLAG_COMPRESSED)
    check(serde, "£ $ €" * 10, FLAG_TEXT | FLAG_COMPRESSED)

    # test_int, doesn't make sense to compress
    check(serde, sys.maxsize, FLAG_INTEGER)

    # test_pickleable
    check(
        serde,
        {
            "foo": "bar",
            "baz": "qux",
            "uno": "dos",
            "tres": "tres",
        },
        FLAG_PICKLE | FLAG_COMPRESSED,
    )

    # test_subtype
    # Subclass of a native type will be restored as the same type
    check(serde, CustomInt(sys.maxsize), FLAG_PICKLE | FLAG_COMPRESSED)