Skip to content

Commit bd1d8b4

Browse files
authored
Support for protocol version (RESP3) (#190)
Support for protocol version (RESP3) * Added `protocol=n` argument to environment classes * Added `Defaults.env_factory` to allow default environment customization (e.g. in RedisTimeSeries) * Extended `terminateRetries` support to `Defaults` and `RedisCluster` * Aviod "UnicodeEncodeError: 'ascii' codec can't encode character" errors by reopening stdout/err with utf8 encoding * CI: solve redis 7.2 build problem on macOS by using `getredis` from Readies
1 parent 15eb6e9 commit bd1d8b4

File tree

7 files changed

+109
-69
lines changed

7 files changed

+109
-69
lines changed

.github/workflows/ci.yml

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
- cron: "0 0 * * *"
1010

1111
jobs:
12-
build-ubuntu:
12+
build:
1313
name: Test on ${{ matrix.platform }} with Python ${{ matrix.python }}
1414
runs-on: ${{ matrix.platform }}
1515
timeout-minutes: 40
@@ -18,6 +18,9 @@ jobs:
1818
platform: ['ubuntu-20.04', 'macos-11']
1919
python: ['3.7', '3.8', '3.9', '3.10', '3.11']
2020
fail-fast: false
21+
defaults:
22+
run:
23+
shell: bash -l -eo pipefail {0}
2124

2225
steps:
2326
- uses: actions/checkout@v3
@@ -40,20 +43,23 @@ jobs:
4043
restore-keys: |
4144
${{ matrix.platform }}-${{ matrix.python }}-pyproject.toml-${{hashFiles('pyproject.toml')}}}
4245
46+
- name: Setup automation
47+
run: |
48+
git clone --recursive https://github.com/RedisLabsModules/readies.git
49+
./readies/bin/getpy3
50+
4351
- name: Install Python dependencies
4452
run: |
45-
pip install poetry
46-
poetry config virtualenvs.create false
47-
poetry export --dev --without-hashes -o requirements-${{matrix.platform}}-${{matrix.python}}.txt
48-
pip install -r requirements-${{matrix.platform}}-${{matrix.python}}.txt
53+
python3 -m pip install poetry
54+
python3 -m poetry config virtualenvs.create false
55+
python3 -m poetry export --dev --without-hashes -o requirements-${{matrix.platform}}-${{matrix.python}}.txt
56+
python3 -m pip install -r requirements-${{matrix.platform}}-${{matrix.python}}.txt
4957
5058
- name: Install Redis Server test dependencies
51-
# if: steps.cache-redis.outputs.cache-hit != 'true'
5259
run: |
53-
git clone https://github.com/redis/redis.git --branch 6.2.7 --depth 1
54-
cd redis
55-
make BUILD_TLS=yes -j
56-
./src/redis-server --version
60+
./readies/bin/getredis --workdir /tmp/redis -v 7 --keep
61+
ln -s /tmp/redis/redis redis
62+
redis-server --version
5763
5864
- name: Generate test certificates
5965
run: |
@@ -64,109 +70,115 @@ jobs:
6470
- name: Unit Test with pytest
6571
timeout-minutes: 30
6672
run: |
67-
TLS_CERT=./redis/tests/tls/redis.crt \
68-
TLS_KEY=./redis/tests/tls/redis.key \
69-
TLS_CACERT=./redis/tests/tls/ca.crt \
70-
REDIS_BINARY=./redis/src/redis-server \
73+
TLS="$PWD/redis/tests/tls"
74+
TLS_CERT=$TLS/redis.crt \
75+
TLS_KEY=$TLS/redis.key \
76+
TLS_CACERT=$TLS/ca.crt \
77+
REDIS_BINARY=`command -v redis-server` \
7178
pytest --ignore=tests/flow --ignore=test_example.py -v
7279
7380
- name: Install RLTest
7481
run: |
75-
pip install .
82+
python3 -m pip install .
7683
7784
- name: Flow Test OSS Single Module
7885
run: |
7986
cd tests/flow
8087
make -C modules
81-
CONTAINS_MODULES=1 RLTest --env oss -v --clear-logs --oss-redis-path ../../redis/src/redis-server --module modules/module1.so
88+
CONTAINS_MODULES=1 RLTest --env oss -v --clear-logs --module modules/module1.so
8289
8390
- name: Flow Test OSS Multiple Modules --use-slaves
8491
run: |
8592
cd tests/flow
8693
make -C modules
87-
CONTAINS_MODULES=1 RLTest --env oss -v --clear-logs --oss-redis-path ../../redis/src/redis-server \
88-
--module modules/module1.so --module-args '' --module modules/module2.so --module-args '' \
94+
CONTAINS_MODULES=1 RLTest --env oss -v --clear-logs \
95+
--module modules/module1.so --module-args '' \
96+
--module modules/module2.so --module-args '' \
8997
--use-slaves
9098
9199
- name: Flow Test OSS Multiple Modules --use-aof
92100
run: |
93101
cd tests/flow
94102
make -C modules
95-
CONTAINS_MODULES=1 RLTest --env oss -v --clear-logs --oss-redis-path ../../redis/src/redis-server \
96-
--module modules/module1.so --module-args '' --module modules/module2.so --module-args '' \
103+
CONTAINS_MODULES=1 RLTest --env oss -v --clear-logs \
104+
--module modules/module1.so --module-args '' \
105+
--module modules/module2.so --module-args '' \
97106
--use-aof
98107
99108
- name: Flow Test OSS Multiple Modules
100109
run: |
101110
cd tests/flow
102111
make -C modules
103-
CONTAINS_MODULES=1 RLTest --env oss -v --clear-logs --oss-redis-path ../../redis/src/redis-server \
104-
--module modules/module1.so --module-args '' --module modules/module2.so --module-args ''
112+
CONTAINS_MODULES=1 RLTest --env oss -v --clear-logs \
113+
--module modules/module1.so --module-args '' \
114+
--module modules/module2.so --module-args ''
105115
106116
- name: Flow Test OSS-CLUSTER Modules
107117
run: |
108118
cd tests/flow
109119
make -C modules
110-
CONTAINS_MODULES=1 RLTest --env oss-cluster -v --clear-logs --oss-redis-path ../../redis/src/redis-server \
111-
--module modules/module1.so --module-args '' --module modules/module2.so --module-args ''
120+
CONTAINS_MODULES=1 RLTest --env oss-cluster -v --clear-logs \
121+
--module modules/module1.so --module-args '' \
122+
--module modules/module2.so --module-args ''
112123
113124
- name: Flow Test OSS TCP
114125
run: |
115126
cd tests/flow
116-
RLTest --env oss -v --clear-logs --oss-redis-path ../../redis/src/redis-server
127+
RLTest --env oss -v --clear-logs
117128
118129
- name: Flow Test OSS UNIX SOCKETS
119130
run: |
120131
cd tests/flow
121-
RLTest --env oss -v --clear-logs --oss-redis-path ../../redis/src/redis-server
132+
RLTest --env oss -v --clear-logs
122133
123134
- name: Flow Test OSS TCP SLAVES
124135
run: |
125136
cd tests/flow
126-
RLTest --env oss -v --unix --clear-logs --oss-redis-path ../../redis/src/redis-server
137+
RLTest --env oss -v --unix --clear-logs
127138
128139
- name: Flow Test OSS-CLUSTER TCP
129140
run: |
130141
cd tests/flow
131-
RLTest --env oss-cluster -v --clear-logs --shards-count 3 --oss-redis-path ../../redis/src/redis-server
142+
RLTest --env oss-cluster -v --clear-logs --shards-count 3
132143
133144
- name: Flow Test OSS TCP with TLS
134145
run: |
146+
TLS="$PWD/redis/tests/tls"
135147
cd tests/flow
136148
RLTest --env oss -v --clear-logs \
137-
--oss-redis-path ../../redis/src/redis-server \
138-
--tls-cert-file ../../redis/tests/tls/redis.crt \
139-
--tls-key-file ../../redis/tests/tls/redis.key \
140-
--tls-ca-cert-file ../../redis/tests/tls/ca.crt \
149+
--tls-cert-file $TLS/redis.crt \
150+
--tls-key-file $TLS/redis.key \
151+
--tls-ca-cert-file $TLS/ca.crt \
141152
--tls
142153
143154
- name: Flow Test OSS-CLUSTER with TLS
144155
run: |
156+
TLS="$PWD/redis/tests/tls"
145157
cd tests/flow
146158
RLTest --env oss-cluster --shards-count 3 -v --clear-logs \
147-
--oss-redis-path ../../redis/src/redis-server \
148-
--tls-cert-file ../../redis/tests/tls/redis.crt \
149-
--tls-key-file ../../redis/tests/tls/redis.key \
150-
--tls-ca-cert-file ../../redis/tests/tls/ca.crt \
159+
--tls-cert-file $TLS/redis.crt \
160+
--tls-key-file $TLS/redis.key \
161+
--tls-ca-cert-file $TLS/ca.crt \
151162
--tls
152163
153164
- name: Flow Test OSS-CLUSTER with SLAVES and TLS
154165
run: |
166+
TLS="$PWD/redis/tests/tls"
155167
cd tests/flow
156168
RLTest --env oss-cluster --shards-count 3 --use-slaves -v --clear-logs \
157-
--oss-redis-path ../../redis/src/redis-server \
158-
--tls-cert-file ../../redis/tests/tls/redis.crt \
159-
--tls-key-file ../../redis/tests/tls/redis.key \
160-
--tls-ca-cert-file ../../redis/tests/tls/ca.crt \
169+
--tls-cert-file $TLS/redis.crt \
170+
--tls-key-file $TLS/redis.key \
171+
--tls-ca-cert-file $TLS/ca.crt \
161172
--tls
162173
163174
- name: Generate coverage report
164175
if: matrix.python == '3.9' && matrix.platform != 'macos-11'
165176
run: |
166-
TLS_CERT=./redis/tests/tls/redis.crt \
167-
TLS_KEY=./redis/tests/tls/redis.key \
168-
TLS_CACERT=./redis/tests/tls/ca.crt \
169-
REDIS_BINARY=./redis/src/redis-server \
177+
TLS="$PWD/redis/tests/tls"
178+
TLS_CERT=$TLS/redis.crt \
179+
TLS_KEY=$TLS/redis.key \
180+
TLS_CACERT=$TLS/ca.crt \
181+
REDIS_BINARY=`command -v redis-server` \
170182
pytest --ignore=tests/flow --ignore=test_example.py --cov-config=.coveragerc --cov-report=xml --cov=RLTest
171183
172184
- name: Upload coverage to Codecov

RLTest/__main__.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import print_function
22

33
import argparse
4+
import io
45
import os
56
import cmd
67
import traceback
@@ -587,10 +588,11 @@ def _runTest(self, test, numberOfAssertionFailed=0, prefix='', before=None, afte
587588
test_args = inspect.getargspec(test.target).args
588589
except:
589590
test_args = inspect.getfullargspec(test.target).args
590-
591+
591592
if len(test_args) > 0 and not test.is_method:
592593
try:
593-
env = Env(testName=test.name)
594+
# env = Env(testName=test.name)
595+
env = Defaults.env_factory(testName=test.name)
594596
except Exception as e:
595597
self.handleFailure(testFullName=testFullName, exception=e, prefix=msgPrefix, testname=test.name)
596598
return 0
@@ -674,7 +676,8 @@ def execute(self):
674676
Env.RTestInstance = self
675677
if self.args.env_only:
676678
Defaults.verbose = 2
677-
env = Env(testName='manual test env')
679+
# env = Env(testName='manual test env')
680+
env = Defaults.env_factory(testName='manual test env')
678681
if self.args.interactive_debugger:
679682
while env.isUp():
680683
time.sleep(1)
@@ -786,6 +789,9 @@ def run_jobs(jobs, results, port):
786789

787790

788791
def main():
792+
# Aviod "UnicodeEncodeError: 'ascii' codec can't encode character" errors
793+
sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')
794+
sys.stderr = io.open(sys.stderr.fileno(), 'w', encoding='utf8')
789795
RLTest().execute()
790796

791797

RLTest/env.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class Defaults:
112112
module_args = None
113113

114114
env = 'oss'
115+
env_factory = lambda *args, **kwargs: Env(*args, **kwargs)
115116
binary = 'redis-server'
116117
proxy_binary = None
117118
re_binary = None
@@ -143,6 +144,8 @@ class Defaults:
143144
curr_test_name = None
144145
port=6379
145146
enable_debug_command=False
147+
terminate_retries=None
148+
terminate_retry_secs=None
146149

147150
def getKwargs(self):
148151
kwargs = {
@@ -163,15 +166,17 @@ def getKwargs(self):
163166
'tlsKeyFile': self.tls_key_file,
164167
'tlsCaCertFile': self.tls_ca_cert_file,
165168
'tlsPassphrase': self.tls_passphrase,
166-
'password': self.oss_password
169+
'password': self.oss_password,
170+
'terminateRetries': self.terminate_retries,
171+
'terminateRetrySecs': self.terminate_retry_secs,
167172
}
168173
return kwargs
169174

170175

171176
class Env:
172177
RTestInstance = None
173178
EnvCompareParams = ['module', 'moduleArgs', 'env', 'useSlaves', 'shardsCount', 'useAof',
174-
'useRdbPreamble', 'forceTcp', 'enableDebugCommand']
179+
'useRdbPreamble', 'forceTcp', 'enableDebugCommand', 'protocol']
175180

176181
def compareEnvs(self, env):
177182
if env is None:
@@ -186,7 +191,7 @@ def __init__(self, testName=None, testDescription=None, module=None,
186191
useAof=None, useRdbPreamble=None, forceTcp=False, useTLS=False, tlsCertFile=None, tlsKeyFile=None,
187192
tlsCaCertFile=None, tlsPassphrase=None, logDir=None, redisBinaryPath=None, dmcBinaryPath=None,
188193
redisEnterpriseBinaryPath=None, noDefaultModuleArgs=False, clusterNodeTimeout = None,
189-
freshEnv=False, enableDebugCommand=None):
194+
freshEnv=False, enableDebugCommand=None, protocol=2, terminateRetries=None, terminateRetrySecs=None):
190195

191196
self.testName = testName if testName else Defaults.curr_test_name
192197
if self.testName is None:
@@ -224,10 +229,14 @@ def __init__(self, testName=None, testDescription=None, module=None,
224229
self.clusterNodeTimeout = clusterNodeTimeout if clusterNodeTimeout else Defaults.cluster_node_timeout
225230
self.port = Defaults.port
226231
self.enableDebugCommand = enableDebugCommand if enableDebugCommand else Defaults.enable_debug_command
232+
self.terminateRetries = terminateRetries
233+
self.terminateRetrySecs = terminateRetrySecs
234+
235+
self.protocol = protocol
227236

228237
self.assertionFailedSummary = []
229238

230-
if (not freshEnv) and Env.RTestInstance and Env.RTestInstance.currEnv and self.compareEnvs(Env.RTestInstance.currEnv):
239+
if not freshEnv and Env.RTestInstance and Env.RTestInstance.currEnv and self.compareEnvs(Env.RTestInstance.currEnv):
231240
self.envRunner = Env.RTestInstance.currEnv.envRunner
232241
else:
233242
if Env.RTestInstance and Env.RTestInstance.currEnv:
@@ -324,7 +333,10 @@ def getEnvKwargs(self):
324333
'clusterNodeTimeout': self.clusterNodeTimeout,
325334
'tlsPassphrase': self.tlsPassphrase,
326335
'port': self.port,
327-
'enableDebugCommand': self.enableDebugCommand
336+
'enableDebugCommand': self.enableDebugCommand,
337+
'protocol': self.protocol,
338+
'terminateRetries': self.terminateRetries,
339+
'terminateRetrySecs': self.terminateRetrySecs,
328340
}
329341
return kwargs
330342

RLTest/redis_cluster.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ def __init__(self, **kwargs):
2020
self.useTLS = kwargs['useTLS']
2121
self.decodeResponses = kwargs.get('decodeResponses', False)
2222
self.tlsPassphrase = kwargs.get('tlsPassphrase', None)
23+
self.protocol = kwargs.get('protocol', 2)
24+
self.terminateRetries = kwargs.get('terminateRetries', None)
25+
self.terminateRetrySecs = kwargs.get('terminateRetrySecs', None)
2326
startPort = kwargs.pop('port', 10000)
2427
totalRedises = self.shardsCount * (2 if useSlaves else 1)
2528
randomizePorts = kwargs.pop('randomizePorts', False)
@@ -42,7 +45,6 @@ def printEnvData(self, prefix=''):
4245
shard.printEnvData(prefix + '\t')
4346

4447
def waitCluster(self, timeout_sec=40):
45-
4648
st = time.time()
4749
ok = 0
4850

@@ -129,12 +131,16 @@ def getClusterConnection(self):
129131
ssl_password=self.tlsPassphrase,
130132
password=self.password,
131133
startup_nodes=statupNode,
132-
decode_responses=self.decodeResponses
134+
decode_responses=self.decodeResponses,
135+
protocol=self.protocol,
136+
terminateRetries=self.terminateRetries, terminateRetrySecs=self.terminateRetrySecs
133137
)
134138
else:
135139
return redis.RedisCluster(
136140
startup_nodes=statupNode,
137-
decode_responses=self.decodeResponses, password=self.password)
141+
decode_responses=self.decodeResponses, password=self.password,
142+
protocol=self.protocol,
143+
terminateRetries=self.terminateRetries, terminateRetrySecs=self.terminateRetrySecs)
138144

139145
def getSlaveConnection(self):
140146
raise Exception('unsupported')

0 commit comments

Comments
 (0)