11# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22# SPDX-License-Identifier: Apache-2.0
3- import sys
3+ import os
44from typing import Dict
55from unittest import TestCase
66from unittest .mock import MagicMock , patch
77
8+ import gevent .monkey
89import pkg_resources
910
10- from amazon .opentelemetry .distro .patches ._instrumentation_patch import apply_instrumentation_patches
11+ from amazon .opentelemetry .distro .patches ._instrumentation_patch import (
12+ AWS_GEVENT_PATCH_MODULES ,
13+ apply_instrumentation_patches ,
14+ )
1115from opentelemetry .instrumentation .botocore .extensions import _KNOWN_EXTENSIONS
1216from opentelemetry .semconv .trace import SpanAttributes
1317
@@ -55,17 +59,37 @@ def test_instrumentation_patch(self):
5559 def _run_patch_behaviour_tests (self ):
5660 # Test setup
5761 self .method_patches [GET_DISTRIBUTION_PATCH ].return_value = "CorrectDistributionObject"
62+ # Test setup to not patch gevent
63+ os .environ [AWS_GEVENT_PATCH_MODULES ] = "none"
5864
5965 # Validate unpatched upstream behaviour - important to detect upstream changes that may break instrumentation
6066 self ._test_unpatched_botocore_instrumentation ()
61- self ._test_unpatched_gevent_ssl_instrumentation ()
67+ self ._test_unpatched_gevent_instrumentation ()
6268
6369 # Apply patches
6470 apply_instrumentation_patches ()
6571
6672 # Validate patched upstream behaviour - important to detect downstream changes that may break instrumentation
6773 self ._test_patched_botocore_instrumentation ()
68- self ._test_patched_gevent_ssl_instrumentation ()
74+ self ._test_unpatched_gevent_instrumentation ()
75+
76+ # Test setup to check whether only these two modules get patched by gevent monkey
77+ os .environ [AWS_GEVENT_PATCH_MODULES ] = "os, ssl"
78+
79+ # Apply patches
80+ apply_instrumentation_patches ()
81+
82+ # Validate that os and ssl gevent monkey patch modules were patched
83+ self ._test_patched_gevent_os_ssl_instrumentation ()
84+
85+ # Set the value to 'all' so that all the remaining gevent monkey patch modules are patched
86+ os .environ [AWS_GEVENT_PATCH_MODULES ] = "all"
87+
88+ # Apply patches again.
89+ apply_instrumentation_patches ()
90+
91+ # Validate that remaining gevent monkey patch modules were patched
92+ self ._test_patched_gevent_instrumentation ()
6993
7094 # Test teardown
7195 self ._reset_mocks ()
@@ -96,9 +120,19 @@ def _test_unpatched_botocore_instrumentation(self):
96120 self .assertFalse ("aws.sqs.queue_url" in attributes )
97121 self .assertFalse ("aws.sqs.queue_name" in attributes )
98122
99- def _test_unpatched_gevent_ssl_instrumentation (self ):
100- # Ssl
101- self .assertFalse ("gevent.ssl" in sys .modules , "Upstream has added the gevent ssl patch" )
123+ def _test_unpatched_gevent_instrumentation (self ):
124+ self .assertFalse (gevent .monkey .is_module_patched ("os" ), "gevent os module has been patched" )
125+ self .assertFalse (gevent .monkey .is_module_patched ("thread" ), "gevent thread module has been patched" )
126+ self .assertFalse (gevent .monkey .is_module_patched ("time" ), "gevent time module has been patched" )
127+ self .assertFalse (gevent .monkey .is_module_patched ("sys" ), "gevent sys module has been patched" )
128+ self .assertFalse (gevent .monkey .is_module_patched ("socket" ), "gevent socket module has been patched" )
129+ self .assertFalse (gevent .monkey .is_module_patched ("select" ), "gevent select module has been patched" )
130+ self .assertFalse (gevent .monkey .is_module_patched ("ssl" ), "gevent ssl module has been patched" )
131+ self .assertFalse (gevent .monkey .is_module_patched ("subprocess" ), "gevent subprocess module has been patched" )
132+ self .assertFalse (gevent .monkey .is_module_patched ("builtins" ), "gevent builtins module has been patched" )
133+ self .assertFalse (gevent .monkey .is_module_patched ("signal" ), "gevent signal module has been patched" )
134+ self .assertFalse (gevent .monkey .is_module_patched ("queue" ), "gevent queue module has been patched" )
135+ self .assertFalse (gevent .monkey .is_module_patched ("contextvars" ), "gevent contextvars module has been patched" )
102136
103137 def _test_patched_botocore_instrumentation (self ):
104138 # Kinesis
@@ -122,9 +156,37 @@ def _test_patched_botocore_instrumentation(self):
122156 self .assertTrue ("aws.sqs.queue_name" in sqs_attributes )
123157 self .assertEqual (sqs_attributes ["aws.sqs.queue_name" ], _QUEUE_NAME )
124158
125- def _test_patched_gevent_ssl_instrumentation (self ):
126- # Ssl
127- self .assertTrue ("gevent.ssl" in sys .modules )
159+ def _test_patched_gevent_os_ssl_instrumentation (self ):
160+ # Only ssl and os module should have been patched since the environment variable was set to 'os, ssl'
161+ self .assertTrue (gevent .monkey .is_module_patched ("ssl" ), "gevent ssl module has not been patched" )
162+ self .assertTrue (gevent .monkey .is_module_patched ("os" ), "gevent os module has not been patched" )
163+ # Rest should still be unpatched
164+ self .assertFalse (gevent .monkey .is_module_patched ("thread" ), "gevent thread module has been patched" )
165+ self .assertFalse (gevent .monkey .is_module_patched ("time" ), "gevent time module has been patched" )
166+ self .assertFalse (gevent .monkey .is_module_patched ("sys" ), "gevent sys module has been patched" )
167+ self .assertFalse (gevent .monkey .is_module_patched ("socket" ), "gevent socket module has been patched" )
168+ self .assertFalse (gevent .monkey .is_module_patched ("select" ), "gevent select module has been patched" )
169+ self .assertFalse (gevent .monkey .is_module_patched ("subprocess" ), "gevent subprocess module has been patched" )
170+ self .assertFalse (gevent .monkey .is_module_patched ("builtins" ), "gevent builtins module has been patched" )
171+ self .assertFalse (gevent .monkey .is_module_patched ("signal" ), "gevent signal module has been patched" )
172+ self .assertFalse (gevent .monkey .is_module_patched ("queue" ), "gevent queue module has been patched" )
173+ self .assertFalse (gevent .monkey .is_module_patched ("contextvars" ), "gevent contextvars module has been patched" )
174+
175+ def _test_patched_gevent_instrumentation (self ):
176+ self .assertTrue (gevent .monkey .is_module_patched ("os" ), "gevent os module has not been patched" )
177+ self .assertTrue (gevent .monkey .is_module_patched ("time" ), "gevent time module has not been patched" )
178+ self .assertTrue (gevent .monkey .is_module_patched ("socket" ), "gevent socket module has not been patched" )
179+ self .assertTrue (gevent .monkey .is_module_patched ("select" ), "gevent select module has not been patched" )
180+ self .assertTrue (gevent .monkey .is_module_patched ("ssl" ), "gevent ssl module has not been patched" )
181+ self .assertTrue (gevent .monkey .is_module_patched ("subprocess" ), "gevent subprocess module has not been patched" )
182+ self .assertTrue (gevent .monkey .is_module_patched ("signal" ), "gevent signal module has not been patched" )
183+ self .assertTrue (gevent .monkey .is_module_patched ("queue" ), "gevent queue module has not been patched" )
184+
185+ # Current version of gevent.monkey.patch_all() does not do anything to these modules despite being called
186+ self .assertFalse (gevent .monkey .is_module_patched ("thread" ), "gevent thread module has been patched" )
187+ self .assertFalse (gevent .monkey .is_module_patched ("sys" ), "gevent sys module has been patched" )
188+ self .assertFalse (gevent .monkey .is_module_patched ("builtins" ), "gevent builtins module not been patched" )
189+ self .assertFalse (gevent .monkey .is_module_patched ("contextvars" ), "gevent contextvars module has been patched" )
128190
129191 def _test_botocore_installed_flag (self ):
130192 with patch (
0 commit comments