-
Notifications
You must be signed in to change notification settings - Fork 93
Expand file tree
/
Copy pathtest_cluster_pipelining.py
More file actions
208 lines (164 loc) · 5.94 KB
/
Copy pathtest_cluster_pipelining.py
File metadata and controls
208 lines (164 loc) · 5.94 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
"""
Tests ClusterPipeline
"""
import pytest
from redis.cluster import RedisCluster
from redis.commands.helpers import get_protocol_version
from redisvl.index import SearchIndex
from redisvl.schema import IndexSchema
@pytest.mark.requires_cluster
def test_real_cluster_pipeline_get_protocol_version(redis_cluster_url):
"""
Test that get_protocol_version works with ClusterPipeline
"""
# Create REAL Redis Cluster client
cluster_client = RedisCluster.from_url(redis_cluster_url)
# Create REAL pipeline from cluster
pipeline = cluster_client.pipeline()
# This is the actual line that was failing in issue #365
# If our fix works, this should NOT raise AttributeError
protocol = get_protocol_version(pipeline)
# Protocol should be a string ("2" or "3") or None
assert protocol in [None, "2", "3", 2, 3], f"Unexpected protocol: {protocol}"
# Clean up
cluster_client.close()
@pytest.mark.requires_cluster
def test_real_searchindex_with_cluster_batch_operations(
redis_cluster_url, redis_test_name
):
"""
Test SearchIndex.load() with Redis Cluster.
"""
# Create schema like the user had
index_prefix = redis_test_name("doc")
schema_dict = {
"index": {
"name": redis_test_name("test-real-365"),
"prefix": index_prefix,
"storage_type": "hash",
},
"fields": [
{"name": "id", "type": "tag"},
{"name": "text", "type": "text"},
],
}
schema = IndexSchema.from_dict(schema_dict)
# Create SearchIndex with REAL cluster URL
index = SearchIndex(schema, redis_url=redis_cluster_url)
# Create the index
index.create(overwrite=True, drop=True)
try:
# Test data like user had
test_data = [{"id": f"item{i}", "text": f"Document {i}"} for i in range(10)]
# See issue #365
# index.load() with batch_size triggers pipeline operations internally
keys = index.load(
data=test_data,
id_field="id",
batch_size=3, # Forces multiple pipeline operations
)
assert len(keys) == 10
assert all(k.startswith(f"{index_prefix}:") for k in keys)
finally:
# Clean up
index.delete(drop=True)
@pytest.mark.requires_cluster
def test_cluster_pipeline_protocol_version_directly():
"""
Test get_protocol_version with various cluster configurations.
"""
import os
# Skip if no cluster available
cluster_url = os.getenv("REDIS_CLUSTER_URL", "redis://localhost:7000")
try:
# Test with default protocol
cluster = RedisCluster.from_url(cluster_url)
pipeline = cluster.pipeline()
# This should work without AttributeError
protocol = get_protocol_version(pipeline)
print(f"Protocol version from real cluster pipeline: {protocol}")
cluster.close()
# Test with explicit RESP2
cluster2 = RedisCluster.from_url(cluster_url, protocol=2)
pipeline2 = cluster2.pipeline()
protocol2 = get_protocol_version(pipeline2)
assert protocol2 in [2, "2", None]
cluster2.close()
# Test with explicit RESP3
cluster3 = RedisCluster.from_url(cluster_url, protocol=3)
pipeline3 = cluster3.pipeline()
protocol3 = get_protocol_version(pipeline3)
assert protocol3 in [3, "3", None]
cluster3.close()
except Exception as e:
pytest.skip(f"Redis Cluster not available: {e}")
@pytest.mark.requires_cluster
def test_batch_search_with_real_cluster(redis_cluster_url, redis_test_name):
"""
Test batch_search which uses get_protocol_version internally.
"""
from redisvl.query import FilterQuery
schema_dict = {
"index": {
"name": redis_test_name("test-batch-365"),
"prefix": redis_test_name("batch"),
"storage_type": "json",
},
"fields": [
{"name": "id", "type": "tag"},
{"name": "category", "type": "tag"},
],
}
schema = IndexSchema.from_dict(schema_dict)
index = SearchIndex(schema, redis_url=redis_cluster_url)
index.create(overwrite=True, drop=True)
try:
# Load test data
data = [{"id": f"doc{i}", "category": f"cat{i % 3}"} for i in range(15)]
index.load(data=data, id_field="id")
# Create multiple queries
queries = [
FilterQuery(filter_expression=f"@category:{{cat{i}}}") for i in range(3)
]
# batch_search internally uses get_protocol_version on pipelines
results = index.batch_search(
[(q.query, q.params) for q in queries], batch_size=2
)
assert len(results) == 3
finally:
index.delete(drop=True)
@pytest.mark.requires_cluster
@pytest.mark.parametrize("ttl", [None, 30])
def test_cluster_load_with_ttl(redis_cluster_url, ttl, redis_test_name):
"""
Test that TTL is correctly set on keys when using load() with ttl parameter on cluster.
"""
schema_dict = {
"index": {
"name": redis_test_name("test-ttl-cluster"),
"prefix": redis_test_name("ttl"),
"storage_type": "hash",
},
"fields": [
{"name": "id", "type": "tag"},
{"name": "text", "type": "text"},
],
}
schema = IndexSchema.from_dict(schema_dict)
index = SearchIndex(schema, redis_url=redis_cluster_url)
index.create(overwrite=True, drop=True)
try:
# Load test data with TTL parameter
data = [{"id": "1", "text": "foo"}]
keys = index.load(data, id_field="id", ttl=ttl)
# Check TTL on the loaded key
key_ttl = index.client.ttl(keys[0])
if ttl is None:
# No TTL set, should return -1
assert key_ttl == -1
else:
# TTL should be set and close to the expected value
assert key_ttl > 0
assert abs(key_ttl - ttl) <= 5
finally:
index.delete(drop=True)