23
23
##############
24
24
25
25
ALL_VERSIONS = ["4.0" , "4.4" , "5.0" , "6.0" , "7.0" , "8.0" , "rapid" , "latest" ]
26
+ VERSIONS_6_0_PLUS = ["6.0" , "7.0" , "8.0" , "rapid" , "latest" ]
26
27
CPYTHONS = ["3.9" , "3.10" , "3.11" , "3.12" , "3.13" ]
27
28
PYPYS = ["pypy3.9" , "pypy3.10" ]
28
29
ALL_PYTHONS = CPYTHONS + PYPYS
30
+ MIN_MAX_PYTHON = [CPYTHONS [0 ], CPYTHONS [- 1 ]]
29
31
BATCHTIME_WEEK = 10080
32
+ AUTH_SSLS = [("auth" , "ssl" ), ("noauth" , "ssl" ), ("noauth" , "nossl" )]
33
+ TOPOLOGIES = ["standalone" , "replica_set" , "sharded_cluster" ]
34
+ C_EXTS = ["with_ext" , "without_ext" ]
35
+ SYNCS = ["sync" , "async" ]
36
+ DISPLAY_LOOKUP = dict (
37
+ ssl = dict (ssl = "SSL" , nossl = "NoSSL" ),
38
+ auth = dict (auth = "Auth" , noauth = "NoAuth" ),
39
+ test_suites = dict (default = "Sync" , default_async = "Async" ),
40
+ coverage = dict (coverage = "cov" ),
41
+ no_ext = {"1" : "No C" },
42
+ )
30
43
HOSTS = dict ()
31
44
32
45
@@ -39,7 +52,9 @@ class Host:
39
52
40
53
HOSTS ["rhel8" ] = Host ("rhel8" , "rhel87-small" , "RHEL8" )
41
54
HOSTS ["win64" ] = Host ("win64" , "windows-64-vsMulti-small" , "Win64" )
55
+ HOSTS ["win32" ] = Host ("win32" , "windows-64-vsMulti-small" , "Win32" )
42
56
HOSTS ["macos" ] = Host ("macos" , "macos-14" , "macOS" )
57
+ HOSTS ["macos-arm64" ] = Host ("macos-arm64" , "macos-14-arm64" , "macOS Arm64" )
43
58
44
59
45
60
##############
@@ -80,10 +95,8 @@ def create_variant(
80
95
81
96
def get_python_binary (python : str , host : str ) -> str :
82
97
"""Get the appropriate python binary given a python version and host."""
83
- if host == "win64" :
84
- is_32 = python .startswith ("32-bit" )
85
- if is_32 :
86
- _ , python = python .split ()
98
+ if host in ["win64" , "win32" ]:
99
+ if host == "win32" :
87
100
base = "C:/python/32"
88
101
else :
89
102
base = "C:/python"
@@ -93,19 +106,31 @@ def get_python_binary(python: str, host: str) -> str:
93
106
if host == "rhel8" :
94
107
return f"/opt/python/{ python } /bin/python3"
95
108
96
- if host == "macos" :
109
+ if host in [ "macos" , "macos-arm64" ] :
97
110
return f"/Library/Frameworks/Python.Framework/Versions/{ python } /bin/python3"
98
111
99
112
raise ValueError (f"no match found for python { python } on { host } " )
100
113
101
114
102
- def get_display_name (base : str , host : str , version : str , python : str ) -> str :
115
+ def get_display_name (base : str , host : str , ** kwargs ) -> str :
103
116
"""Get the display name of a variant."""
104
- if version not in ["rapid" , "latest" ]:
105
- version = f"v{ version } "
106
- if not python .startswith ("pypy" ):
107
- python = f"py{ python } "
108
- return f"{ base } { HOSTS [host ].display_name } { version } { python } "
117
+ display_name = f"{ base } { HOSTS [host ].display_name } "
118
+ version = kwargs .pop ("VERSION" , None )
119
+ if version :
120
+ if version not in ["rapid" , "latest" ]:
121
+ version = f"v{ version } "
122
+ display_name = f"{ display_name } { version } "
123
+ for key , value in kwargs .items ():
124
+ name = value
125
+ if key .lower () == "python" :
126
+ if not value .startswith ("pypy" ):
127
+ name = f"py{ value } "
128
+ elif key .lower () in DISPLAY_LOOKUP :
129
+ name = DISPLAY_LOOKUP [key .lower ()][value ]
130
+ else :
131
+ continue
132
+ display_name = f"{ display_name } { name } "
133
+ return display_name
109
134
110
135
111
136
def zip_cycle (* iterables , empty_default = None ):
@@ -115,6 +140,21 @@ def zip_cycle(*iterables, empty_default=None):
115
140
yield tuple (next (i , empty_default ) for i in cycles )
116
141
117
142
143
+ def handle_c_ext (c_ext , expansions ):
144
+ """Handle c extension option."""
145
+ if c_ext == C_EXTS [0 ]:
146
+ expansions ["NO_EXT" ] = "1"
147
+
148
+
149
+ def generate_yaml (tasks = None , variants = None ):
150
+ """Generate the yaml for a given set of tasks and variants."""
151
+ project = EvgProject (tasks = tasks , buildvariants = variants )
152
+ out = ShrubService .generate_yaml (project )
153
+ # Dedent by two spaces to match what we use in config.yml
154
+ lines = [line [2 :] for line in out .splitlines ()]
155
+ print ("\n " .join (lines )) # noqa: T201
156
+
157
+
118
158
##############
119
159
# Variants
120
160
##############
@@ -159,9 +199,253 @@ def create_ocsp_variants() -> list[BuildVariant]:
159
199
return variants
160
200
161
201
202
+ def create_server_variants () -> list [BuildVariant ]:
203
+ variants = []
204
+
205
+ # Run the full matrix on linux with min and max CPython, and latest pypy.
206
+ host = "rhel8"
207
+ for python , (auth , ssl ) in product ([* MIN_MAX_PYTHON , PYPYS [- 1 ]], AUTH_SSLS ):
208
+ display_name = f"Test { host } "
209
+ expansions = dict (AUTH = auth , SSL = ssl , COVERAGE = "coverage" )
210
+ display_name = get_display_name ("Test" , host , python = python , ** expansions )
211
+ variant = create_variant (
212
+ [f".{ t } " for t in TOPOLOGIES ],
213
+ display_name ,
214
+ python = python ,
215
+ host = host ,
216
+ tags = ["coverage_tag" ],
217
+ expansions = expansions ,
218
+ )
219
+ variants .append (variant )
220
+
221
+ # Test the rest of the pythons on linux.
222
+ for python , (auth , ssl ), topology in zip_cycle (
223
+ CPYTHONS [1 :- 1 ] + PYPYS [:- 1 ], AUTH_SSLS , TOPOLOGIES
224
+ ):
225
+ display_name = f"Test { host } "
226
+ expansions = dict (AUTH = auth , SSL = ssl )
227
+ display_name = get_display_name ("Test" , host , python = python , ** expansions )
228
+ variant = create_variant (
229
+ [f".{ topology } " ],
230
+ display_name ,
231
+ python = python ,
232
+ host = host ,
233
+ expansions = expansions ,
234
+ )
235
+ variants .append (variant )
236
+
237
+ # Test a subset on each of the other platforms.
238
+ for host in ("macos" , "macos-arm64" , "win64" , "win32" ):
239
+ for (python , (auth , ssl ), topology ), sync in product (
240
+ zip_cycle (MIN_MAX_PYTHON , AUTH_SSLS , TOPOLOGIES ), SYNCS
241
+ ):
242
+ test_suite = "default" if sync == "sync" else "default_async"
243
+ tasks = [f".{ topology } " ]
244
+ # MacOS arm64 only works on server versions 6.0+
245
+ if host == "macos-arm64" :
246
+ tasks = [f".{ topology } .{ version } " for version in VERSIONS_6_0_PLUS ]
247
+ expansions = dict (AUTH = auth , SSL = ssl , TEST_SUITES = test_suite , SKIP_CSOT_TESTS = "true" )
248
+ display_name = get_display_name ("Test" , host , python = python , ** expansions )
249
+ variant = create_variant (
250
+ tasks ,
251
+ display_name ,
252
+ python = python ,
253
+ host = host ,
254
+ expansions = expansions ,
255
+ )
256
+ variants .append (variant )
257
+
258
+ return variants
259
+
260
+
261
+ def create_encryption_variants () -> list [BuildVariant ]:
262
+ variants = []
263
+ tags = ["encryption_tag" ]
264
+ batchtime = BATCHTIME_WEEK
265
+
266
+ def get_encryption_expansions (encryption , ssl = "ssl" ):
267
+ expansions = dict (AUTH = "auth" , SSL = ssl , test_encryption = "true" )
268
+ if "crypt_shared" in encryption :
269
+ expansions ["test_crypt_shared" ] = "true"
270
+ if "PyOpenSSL" in encryption :
271
+ expansions ["test_encryption_pyopenssl" ] = "true"
272
+ return expansions
273
+
274
+ host = "rhel8"
275
+
276
+ # Test against all server versions and topolgies for the three main python versions.
277
+ encryptions = ["Encryption" , "Encryption crypt_shared" , "Encryption PyOpenSSL" ]
278
+ for encryption , python in product (encryptions , [* MIN_MAX_PYTHON , PYPYS [- 1 ]]):
279
+ expansions = get_encryption_expansions (encryption )
280
+ display_name = get_display_name (encryption , host , python = python , ** expansions )
281
+ variant = create_variant (
282
+ [f".{ t } " for t in TOPOLOGIES ],
283
+ display_name ,
284
+ python = python ,
285
+ host = host ,
286
+ expansions = expansions ,
287
+ batchtime = batchtime ,
288
+ tags = tags ,
289
+ )
290
+ variants .append (variant )
291
+
292
+ # Test the rest of the pythons on linux for all server versions.
293
+ for encryption , python , ssl in zip_cycle (
294
+ encryptions , CPYTHONS [1 :- 1 ] + PYPYS [:- 1 ], ["ssl" , "nossl" ]
295
+ ):
296
+ expansions = get_encryption_expansions (encryption , ssl )
297
+ display_name = get_display_name (encryption , host , python = python , ** expansions )
298
+ variant = create_variant (
299
+ [".replica_set" ],
300
+ display_name ,
301
+ python = python ,
302
+ host = host ,
303
+ expansions = expansions ,
304
+ )
305
+ variants .append (variant )
306
+
307
+ # Test on macos and linux on one server version and topology for min and max python.
308
+ encryptions = ["Encryption" , "Encryption crypt_shared" ]
309
+ task_names = [".latest .replica_set" ]
310
+ for host , encryption , python in product (["macos" , "win64" ], encryptions , MIN_MAX_PYTHON ):
311
+ ssl = "ssl" if python == CPYTHONS [0 ] else "nossl"
312
+ expansions = get_encryption_expansions (encryption , ssl )
313
+ display_name = get_display_name (encryption , host , python = python , ** expansions )
314
+ variant = create_variant (
315
+ task_names ,
316
+ display_name ,
317
+ python = python ,
318
+ host = host ,
319
+ expansions = expansions ,
320
+ batchtime = batchtime ,
321
+ tags = tags ,
322
+ )
323
+ variants .append (variant )
324
+ return variants
325
+
326
+
327
+ def create_load_balancer_variants ():
328
+ # Load balancer tests - run all supported versions for all combinations of auth and ssl and system python.
329
+ host = "rhel8"
330
+ task_names = ["load-balancer-test" ]
331
+ batchtime = BATCHTIME_WEEK
332
+ expansions_base = dict (test_loadbalancer = "true" )
333
+ versions = ["6.0" , "7.0" , "8.0" , "latest" , "rapid" ]
334
+ variants = []
335
+ pythons = CPYTHONS + PYPYS
336
+ for ind , (version , (auth , ssl )) in enumerate (product (versions , AUTH_SSLS )):
337
+ expansions = dict (VERSION = version , AUTH = auth , SSL = ssl )
338
+ expansions .update (expansions_base )
339
+ python = pythons [ind % len (pythons )]
340
+ display_name = get_display_name ("Load Balancer" , host , python = python , ** expansions )
341
+ variant = create_variant (
342
+ task_names ,
343
+ display_name ,
344
+ python = python ,
345
+ host = host ,
346
+ expansions = expansions ,
347
+ batchtime = batchtime ,
348
+ )
349
+ variants .append (variant )
350
+ return variants
351
+
352
+
353
+ def create_compression_variants ():
354
+ # Compression tests - standalone versions of each server, across python versions, with and without c extensions.
355
+ # PyPy interpreters are always tested without extensions.
356
+ host = "rhel8"
357
+ task_names = dict (snappy = [".standalone" ], zlib = [".standalone" ], zstd = [".standalone !.4.0" ])
358
+ variants = []
359
+ for ind , (compressor , c_ext ) in enumerate (product (["snappy" , "zlib" , "zstd" ], C_EXTS )):
360
+ expansions = dict (COMPRESSORS = compressor )
361
+ handle_c_ext (c_ext , expansions )
362
+ base_name = f"{ compressor } compression"
363
+ python = CPYTHONS [ind % len (CPYTHONS )]
364
+ display_name = get_display_name (base_name , host , python = python , ** expansions )
365
+ variant = create_variant (
366
+ task_names [compressor ],
367
+ display_name ,
368
+ python = python ,
369
+ host = host ,
370
+ expansions = expansions ,
371
+ )
372
+ variants .append (variant )
373
+
374
+ other_pythons = PYPYS + CPYTHONS [ind :]
375
+ for compressor , python in zip_cycle (["snappy" , "zlib" , "zstd" ], other_pythons ):
376
+ expansions = dict (COMPRESSORS = compressor )
377
+ handle_c_ext (c_ext , expansions )
378
+ base_name = f"{ compressor } compression"
379
+ display_name = get_display_name (base_name , host , python = python , ** expansions )
380
+ variant = create_variant (
381
+ task_names [compressor ],
382
+ display_name ,
383
+ python = python ,
384
+ host = host ,
385
+ expansions = expansions ,
386
+ )
387
+ variants .append (variant )
388
+
389
+ return variants
390
+
391
+
392
+ def create_enterprise_auth_variants ():
393
+ expansions = dict (AUTH = "auth" )
394
+ variants = []
395
+
396
+ # All python versions across platforms.
397
+ for python in ALL_PYTHONS :
398
+ if python == CPYTHONS [0 ]:
399
+ host = "macos"
400
+ elif python == CPYTHONS [- 1 ]:
401
+ host = "win64"
402
+ else :
403
+ host = "rhel8"
404
+ display_name = get_display_name ("Enterprise Auth" , host , python = python , ** expansions )
405
+ variant = create_variant (
406
+ ["test-enterprise-auth" ], display_name , host = host , python = python , expansions = expansions
407
+ )
408
+ variants .append (variant )
409
+
410
+ return variants
411
+
412
+
413
+ def create_pyopenssl_variants ():
414
+ base_name = "PyOpenSSL"
415
+ batchtime = BATCHTIME_WEEK
416
+ base_expansions = dict (test_pyopenssl = "true" , SSL = "ssl" )
417
+ variants = []
418
+
419
+ for python in ALL_PYTHONS :
420
+ # Only test "noauth" with min python.
421
+ auth = "noauth" if python == CPYTHONS [0 ] else "auth"
422
+ if python == CPYTHONS [0 ]:
423
+ host = "macos"
424
+ elif python == CPYTHONS [- 1 ]:
425
+ host = "win64"
426
+ else :
427
+ host = "rhel8"
428
+ expansions = dict (AUTH = auth )
429
+ expansions .update (base_expansions )
430
+
431
+ display_name = get_display_name (base_name , host , python = python )
432
+ variant = create_variant (
433
+ [".replica_set" , ".7.0" ],
434
+ display_name ,
435
+ python = python ,
436
+ host = host ,
437
+ expansions = expansions ,
438
+ batchtime = batchtime ,
439
+ )
440
+ variants .append (variant )
441
+
442
+ return variants
443
+
444
+
162
445
##################
163
446
# Generate Config
164
447
##################
165
448
166
- project = EvgProject (tasks = None , buildvariants = create_ocsp_variants ())
167
- print (ShrubService .generate_yaml (project )) # noqa: T201
449
+ variants = create_pyopenssl_variants ()
450
+ # print(len(variants))
451
+ generate_yaml (variants = variants )
0 commit comments