Skip to content

Commit 968ee7b

Browse files
authored
PYTHON-2868 Test Serverless behind a load balancer (mongodb#742)
1 parent c7d8080 commit 968ee7b

15 files changed

+152
-53
lines changed

.evergreen/config.yml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,11 @@ functions:
417417
fi
418418
if [ -n "${test_serverless}" ]; then
419419
export TEST_SERVERLESS=1
420-
export MONGODB_URI="${MONGODB_URI}"
420+
export MONGODB_URI="${SINGLE_ATLASPROXY_SERVERLESS_URI}"
421421
export SERVERLESS_ATLAS_USER="${SERVERLESS_ATLAS_USER}"
422422
export SERVERLESS_ATLAS_PASSWORD="${SERVERLESS_ATLAS_PASSWORD}"
423+
export SINGLE_MONGOS_LB_URI="${SINGLE_ATLASPROXY_SERVERLESS_URI}"
424+
export MULTI_MONGOS_LB_URI="${MULTI_ATLASPROXY_SERVERLESS_URI}"
423425
fi
424426
425427
PYTHON_BINARY=${PYTHON_BINARY} \
@@ -873,9 +875,10 @@ task_groups:
873875
script: |
874876
${PREPARE_SHELL}
875877
set +o xtrace
876-
SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} \
877-
SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \
878-
SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \
878+
LOADBALANCED=ON \
879+
SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} \
880+
SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \
881+
SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \
879882
bash ${DRIVERS_TOOLS}/.evergreen/serverless/create-instance.sh
880883
- command: expansions.update
881884
params:
@@ -887,9 +890,9 @@ task_groups:
887890
${PREPARE_SHELL}
888891
set +o xtrace
889892
SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} \
890-
SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \
891-
SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \
892-
SERVERLESS_INSTANCE_NAME=${SERVERLESS_INSTANCE_NAME} \
893+
SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \
894+
SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \
895+
SERVERLESS_INSTANCE_NAME=${SERVERLESS_INSTANCE_NAME} \
893896
bash ${DRIVERS_TOOLS}/.evergreen/serverless/delete-instance.sh
894897
tasks:
895898
- ".serverless"

test/__init__.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,14 @@
107107
db_user = res['username'] or db_user
108108
db_pwd = res['password'] or db_pwd
109109
elif TEST_SERVERLESS:
110-
res = parse_uri(os.environ["MONGODB_URI"])
111-
host, port = res['nodelist'].pop(0)
112-
additional_serverless_mongoses = res['nodelist']
110+
TEST_LOADBALANCER = True
111+
res = parse_uri(SINGLE_MONGOS_LB_URI)
112+
host, port = res['nodelist'][0]
113113
db_user = res['username'] or db_user
114114
db_pwd = res['password'] or db_pwd
115115
TLS_OPTIONS = {'tls': True}
116+
# Spec says serverless tests must be run with compression.
117+
COMPRESSORS = COMPRESSORS or 'zlib'
116118

117119

118120
def is_server_resolvable():
@@ -236,7 +238,7 @@ def __init__(self):
236238
self.version = Version(-1) # Needs to be comparable with Version
237239
self.auth_enabled = False
238240
self.test_commands_enabled = False
239-
self.server_parameters = None
241+
self.server_parameters = {}
240242
self.is_mongos = False
241243
self.mongoses = []
242244
self.is_rs = False
@@ -251,7 +253,7 @@ def __init__(self):
251253
self.is_data_lake = False
252254
self.load_balancer = TEST_LOADBALANCER
253255
self.serverless = TEST_SERVERLESS
254-
if self.load_balancer:
256+
if self.load_balancer or self.serverless:
255257
self.default_client_options["loadBalanced"] = True
256258
if COMPRESSORS:
257259
self.default_client_options["compressors"] = COMPRESSORS
@@ -402,7 +404,11 @@ def _init_client(self):
402404
self.w = len(hello.get("hosts", [])) or 1
403405
self.version = Version.from_client(self.client)
404406

405-
if TEST_SERVERLESS:
407+
if self.serverless:
408+
self.server_parameters = {
409+
'requireApiVersion': False,
410+
'enableTestCommands': True,
411+
}
406412
self.test_commands_enabled = True
407413
self.has_ipv6 = False
408414
else:
@@ -422,14 +428,11 @@ def _init_client(self):
422428

423429
self.is_mongos = (self.hello.get('msg') == 'isdbgrid')
424430
if self.is_mongos:
425-
if self.serverless:
426-
self.mongoses.append(self.client.address)
427-
self.mongoses.extend(additional_serverless_mongoses)
428-
else:
431+
address = self.client.address
432+
self.mongoses.append(address)
433+
if not self.serverless:
429434
# Check for another mongos on the next port.
430-
address = self.client.address
431435
next_address = address[0], address[1] + 1
432-
self.mongoses.append(address)
433436
mongos_client = self._connect(
434437
*next_address, **self.default_client_options)
435438
if mongos_client:

test/load_balancer/cursors.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,11 @@
902902
},
903903
{
904904
"description": "listCollections pins the cursor to a connection",
905+
"runOnRequirements": [
906+
{
907+
"serverless": "forbid"
908+
}
909+
],
905910
"operations": [
906911
{
907912
"name": "listCollections",
@@ -1151,6 +1156,11 @@
11511156
},
11521157
{
11531158
"description": "change streams pin to a connection",
1159+
"runOnRequirements": [
1160+
{
1161+
"serverless": "forbid"
1162+
}
1163+
],
11541164
"operations": [
11551165
{
11561166
"name": "createChangeStream",

test/load_balancer/sdam-error-handling.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@
127127
"tests": [
128128
{
129129
"description": "only connections for a specific serviceId are closed when pools are cleared",
130+
"runOnRequirements": [
131+
{
132+
"serverless": "forbid"
133+
}
134+
],
130135
"operations": [
131136
{
132137
"name": "createFindCursor",
@@ -255,7 +260,7 @@
255260
]
256261
},
257262
{
258-
"description": "errors during the initial connection hello are ignore",
263+
"description": "errors during the initial connection hello are ignored",
259264
"runOnRequirements": [
260265
{
261266
"minServerVersion": "4.9"
@@ -274,7 +279,9 @@
274279
},
275280
"data": {
276281
"failCommands": [
277-
"isMaster"
282+
"ismaster",
283+
"isMaster",
284+
"hello"
278285
],
279286
"closeConnection": true,
280287
"appName": "lbSDAMErrorTestClient"

test/load_balancer/transactions.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,11 @@
607607
},
608608
{
609609
"description": "pinned connection is released after a transient non-network CRUD error",
610+
"runOnRequirements": [
611+
{
612+
"serverless": "forbid"
613+
}
614+
],
610615
"operations": [
611616
{
612617
"name": "failPoint",
@@ -715,6 +720,11 @@
715720
},
716721
{
717722
"description": "pinned connection is released after a transient network CRUD error",
723+
"runOnRequirements": [
724+
{
725+
"serverless": "forbid"
726+
}
727+
],
718728
"operations": [
719729
{
720730
"name": "failPoint",
@@ -831,6 +841,11 @@
831841
},
832842
{
833843
"description": "pinned connection is released after a transient non-network commit error",
844+
"runOnRequirements": [
845+
{
846+
"serverless": "forbid"
847+
}
848+
],
834849
"operations": [
835850
{
836851
"name": "failPoint",

test/load_balancer/wait-queue-timeouts.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"useMultipleMongoses": true,
1616
"uriOptions": {
1717
"maxPoolSize": 1,
18-
"waitQueueTimeoutMS": 5
18+
"waitQueueTimeoutMS": 50
1919
},
2020
"observeEvents": [
2121
"connectionCheckedOutEvent",

test/test_client.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ def test_auth_from_uri(self):
889889
"pymongo_test", "user", "pass", roles=['userAdmin', 'readWrite'])
890890

891891
with self.assertRaises(OperationFailure):
892-
connected(rs_or_single_client(
892+
connected(rs_or_single_client_noauth(
893893
"mongodb://a:b@%s:%d" % (host, port)))
894894

895895
# No error.
@@ -899,7 +899,7 @@ def test_auth_from_uri(self):
899899
# Wrong database.
900900
uri = "mongodb://admin:pass@%s:%d/pymongo_test" % (host, port)
901901
with self.assertRaises(OperationFailure):
902-
connected(rs_or_single_client(uri))
902+
connected(rs_or_single_client_noauth(uri))
903903

904904
# No error.
905905
connected(rs_or_single_client_noauth(
@@ -923,7 +923,7 @@ def test_username_and_password(self):
923923
client_context.create_user("admin", "ad min", "pa/ss")
924924
self.addCleanup(client_context.drop_user, "admin", "ad min")
925925

926-
c = rs_or_single_client(username="ad min", password="pa/ss")
926+
c = rs_or_single_client_noauth(username="ad min", password="pa/ss")
927927

928928
# Username and password aren't in strings that will likely be logged.
929929
self.assertNotIn("ad min", repr(c))
@@ -935,7 +935,8 @@ def test_username_and_password(self):
935935
c.server_info()
936936

937937
with self.assertRaises(OperationFailure):
938-
rs_or_single_client(username="ad min", password="foo").server_info()
938+
rs_or_single_client_noauth(
939+
username="ad min", password="foo").server_info()
939940

940941
@client_context.require_auth
941942
def test_lazy_auth_raises_operation_failure(self):
@@ -957,11 +958,7 @@ def test_unix_socket(self):
957958
if not os.access(mongodb_socket, os.R_OK):
958959
raise SkipTest("Socket file is not accessible")
959960

960-
if client_context.auth_enabled:
961-
uri = "mongodb://%s:%s@%s" % (db_user, db_pwd, encoded_socket)
962-
else:
963-
uri = "mongodb://%s" % encoded_socket
964-
961+
uri = "mongodb://%s" % encoded_socket
965962
# Confirm we can do operations via the socket.
966963
client = rs_or_single_client(uri)
967964
client.pymongo_test.test.insert_one({"dummy": "object"})

test/test_cmap.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
OvertCommandListener,
5656
rs_or_single_client,
5757
single_client,
58+
single_client_noauth,
5859
TestCreator,
5960
wait_until)
6061
from test.utils_spec_runner import SpecRunnerThread
@@ -334,7 +335,7 @@ def test_3_uri_connection_pool_options(self):
334335
opts = '&'.join(['%s=%s' % (k, v)
335336
for k, v in self.POOL_OPTIONS.items()])
336337
uri = 'mongodb://%s/?%s' % (client_context.pair, opts)
337-
client = rs_or_single_client(uri, **self.credentials)
338+
client = rs_or_single_client(uri)
338339
self.addCleanup(client.close)
339340
pool_opts = get_pool(client).opts
340341
self.assertEqual(pool_opts.non_default_options, self.POOL_OPTIONS)
@@ -395,8 +396,9 @@ def mock_connect(*args, **kwargs):
395396

396397
def test_5_check_out_fails_auth_error(self):
397398
listener = CMAPListener()
398-
client = single_client(username="notauser", password="fail",
399-
event_listeners=[listener])
399+
client = single_client_noauth(
400+
username="notauser", password="fail",
401+
event_listeners=[listener])
400402
self.addCleanup(client.close)
401403

402404
# Attempt to create a new connection.

test/test_load_balancer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
class TestLB(IntegrationTest):
4040
RUN_ON_LOAD_BALANCER = True
41+
RUN_ON_SERVERLESS = True
4142

4243
def test_connections_are_only_returned_once(self):
4344
pool = get_pool(self.client)
@@ -97,7 +98,6 @@ def _test_no_gc_deadlock(self, create_resource):
9798
"failCommands": [
9899
"find", "aggregate"
99100
],
100-
"errorCode": 91,
101101
"closeConnection": True,
102102
}
103103
}

test/test_unified_format.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
class_name_prefix='UnifiedTestFormat',
3434
expected_failures=[
3535
'Client side error in command starting transaction', # PYTHON-1894
36-
]))
36+
],
37+
RUN_ON_SERVERLESS=False))
3738

3839

3940
globals().update(generate_test_classes(
@@ -43,7 +44,8 @@
4344
bypass_test_generation_errors=True,
4445
expected_failures=[
4546
'.*', # All tests expected to fail
46-
]))
47+
],
48+
RUN_ON_SERVERLESS=False))
4749

4850

4951
class TestMatchEvaluatorUtil(unittest.TestCase):

0 commit comments

Comments
 (0)