|
3 | 3 | # pylint: disable=import-outside-toplevel |
4 | 4 |
|
5 | 5 | import os |
6 | | -import struct |
7 | 6 | import tempfile |
8 | 7 | import threading |
9 | 8 | import time |
@@ -84,70 +83,51 @@ def _make_hash(seed): |
84 | 83 | """Return a 32-byte hash derived from *seed*.""" |
85 | 84 | return (b'\x00' * 31 + bytes([seed & 0xFF]))[-32:] |
86 | 85 |
|
87 | | - def _flush_and_check(self, obj_hash): |
| 86 | + def _flush_and_check(self, obj_hash, expected_payload=None): |
88 | 87 | """ |
89 | | - Flush the inventory to the database, clear the _objects lookup |
90 | | - cache so that __contains__ is forced to hit sqlite, then verify |
91 | | - the hash is found via the normal inventory API. |
| 88 | + Flush the inventory to the database, clear both in-memory |
| 89 | + caches so that __contains__ and __getitem__ are forced to |
| 90 | + hit sqlite, then verify the hash is found and (optionally) |
| 91 | + that the payload content survived the round-trip. |
92 | 92 | """ |
93 | 93 | self.inventory.flush() |
94 | 94 | self.inventory._objects.clear() |
95 | 95 | self.assertIn(obj_hash, self.inventory) |
| 96 | + if expected_payload is not None: |
| 97 | + value = self.inventory[obj_hash] |
| 98 | + self.assertEqual( |
| 99 | + bytes(value.payload), expected_payload, |
| 100 | + "Payload content corrupted after flush") |
96 | 101 |
|
97 | 102 | # -- test cases ------------------------------------------------------- |
98 | 103 |
|
99 | | - def test_flush_with_bytes_payload(self): |
100 | | - """Baseline: payload and tag are plain bytes.""" |
| 104 | + def test_flush_payload_roundtrip(self): |
| 105 | + """Payload content must survive the flush round-trip.""" |
101 | 106 | h = self._make_hash(1) |
| 107 | + payload = b'\x80\x01' + os.urandom(64) |
102 | 108 | self.inventory[h] = ( |
103 | | - 2, 1, b'\x80\x01' + os.urandom(64), |
| 109 | + 2, 1, payload, |
104 | 110 | int(time.time()) + 3600, b'\xff' * 32) |
105 | | - self._flush_and_check(h) |
106 | | - |
107 | | - def test_flush_with_memoryview_payload(self): |
108 | | - """ |
109 | | - Reproduce the production crash: payload and tag as memoryview |
110 | | - cause 'Error binding parameter 3 - probably unsupported type.' |
111 | | - """ |
112 | | - h = self._make_hash(2) |
113 | | - self.inventory[h] = ( |
114 | | - 2, 1, memoryview(b'\x80\x02' + os.urandom(64)), |
115 | | - int(time.time()) + 3600, memoryview(b'\xee' * 32)) |
116 | | - self._flush_and_check(h) |
117 | | - |
118 | | - def test_flush_with_bytearray_payload(self): |
119 | | - """bytearray is another bytes-like type that could trip sqlite3.""" |
120 | | - h = self._make_hash(3) |
121 | | - self.inventory[h] = ( |
122 | | - 2, 1, bytearray(b'\x80\x03' + os.urandom(64)), |
123 | | - int(time.time()) + 3600, bytearray(b'\xdd' * 32)) |
124 | | - self._flush_and_check(h) |
| 111 | + self._flush_and_check(h, payload) |
125 | 112 |
|
126 | 113 | def test_flush_with_empty_tag(self): |
127 | 114 | """Empty tag (b'') must not break the INSERT.""" |
128 | | - h = self._make_hash(4) |
| 115 | + h = self._make_hash(2) |
| 116 | + payload = b'\x80\x02' + os.urandom(64) |
129 | 117 | self.inventory[h] = ( |
130 | | - 2, 1, b'\x80\x04' + os.urandom(64), |
| 118 | + 2, 1, payload, |
131 | 119 | int(time.time()) + 3600, b'') |
132 | | - self._flush_and_check(h) |
| 120 | + self._flush_and_check(h, payload) |
133 | 121 |
|
134 | | - # pylint: disable=redefined-variable-type |
135 | | - def test_flush_multiple_mixed_types(self): |
136 | | - """Flush a batch of items with mixed blob types.""" |
| 122 | + def test_flush_multiple_items(self): |
| 123 | + """Flush a batch and verify every row arrives.""" |
137 | 124 | count = 20 |
138 | 125 | hashes = [self._make_hash(0x10 + i) for i in range(count)] |
139 | 126 | expires = int(time.time()) + 3600 |
140 | 127 |
|
141 | 128 | for i, h in enumerate(hashes): |
142 | | - payload = struct.pack('>I', i) + os.urandom(60) |
143 | | - tag = struct.pack('>I', i) + b'\x00' * 28 |
144 | | - if i % 3 == 0: |
145 | | - payload = memoryview(payload) |
146 | | - tag = memoryview(tag) |
147 | | - elif i % 3 == 1: |
148 | | - payload = bytearray(payload) |
149 | | - tag = bytearray(tag) |
150 | | - self.inventory[h] = (2, 1, payload, expires, tag) |
| 129 | + self.inventory[h] = ( |
| 130 | + 2, 1, os.urandom(64), expires, b'\x00' * 32) |
151 | 131 |
|
152 | 132 | self.inventory.flush() |
153 | 133 | self.inventory._objects.clear() |
|
0 commit comments