1+ # BSD 3-Clause License
2+ #
3+ # Copyright (c) 2024, Elasticsearch BV
4+ # All rights reserved.
5+ #
6+ # Redistribution and use in source and binary forms, with or without
7+ # modification, are permitted provided that the following conditions are met:
8+ #
9+ # * Redistributions of source code must retain the above copyright notice, this
10+ # list of conditions and the following disclaimer.
11+ #
12+ # * Redistributions in binary form must reproduce the above copyright notice,
13+ # this list of conditions and the following disclaimer in the documentation
14+ # and/or other materials provided with the distribution.
15+ #
16+ # * Neither the name of the copyright holder nor the names of its
17+ # contributors may be used to endorse or promote products derived from
18+ # this software without specific prior written permission.
19+ #
20+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
31+ import pytest # isort:skip
32+
33+ grpc = pytest .importorskip ("grpc" ) # isort:skip
34+
35+ from elasticapm .conf import constants
36+ from elasticapm .conf .constants import TRANSACTION
37+ from elasticapm .traces import capture_span
38+
39+ pytestmark = pytest .mark .grpc
40+
41+
42+ def test_grpc_client_instrumentation (instrument , elasticapm_client ):
43+ """Test that gRPC client instrumentation creates transactions and adds interceptors"""
44+ # Create a test channel
45+ channel = grpc .insecure_channel ("localhost:50051" )
46+
47+ # Verify that the channel was created with our interceptor
48+ assert hasattr (channel , "_interceptor" )
49+ assert channel ._interceptor .__class__ .__name__ == "_ClientInterceptor"
50+
51+ # Verify transaction was created
52+ transaction = elasticapm_client .events [TRANSACTION ][0 ]
53+ assert transaction ["type" ] == "script"
54+ assert transaction ["name" ] == "grpc_client_instrumentation"
55+
56+
57+ def test_grpc_secure_channel_instrumentation (instrument , elasticapm_client ):
58+ """Test that secure channel instrumentation works correctly"""
59+ # Create a secure channel
60+ channel = grpc .secure_channel ("localhost:50051" , grpc .local_channel_credentials ())
61+
62+ # Verify that the channel was created with our interceptor
63+ assert hasattr (channel , "_interceptor" )
64+ assert channel ._interceptor .__class__ .__name__ == "_ClientInterceptor"
65+
66+ # Verify transaction was created
67+ transaction = elasticapm_client .events [TRANSACTION ][0 ]
68+ assert transaction ["type" ] == "script"
69+ assert transaction ["name" ] == "grpc_client_instrumentation"
70+
71+
72+ def test_grpc_server_instrumentation (instrument , elasticapm_client ):
73+ """Test that gRPC server instrumentation adds interceptors"""
74+ # Create a test server
75+ server = grpc .server (None )
76+
77+ # Verify that the server was created with our interceptor
78+ assert len (server ._interceptors ) > 0
79+ assert server ._interceptors [0 ].__class__ .__name__ == "_ServerInterceptor"
80+
81+ # Verify transaction was created
82+ transaction = elasticapm_client .events [TRANSACTION ][0 ]
83+ assert transaction ["type" ] == "script"
84+ assert transaction ["name" ] == "grpc_server_instrumentation"
85+
86+
87+ def test_grpc_async_server_instrumentation (instrument , elasticapm_client ):
88+ """Test that async server instrumentation adds interceptors"""
89+ # Create a test async server
90+ server = grpc .aio .server ()
91+
92+ # Verify that the server was created with our interceptor
93+ assert len (server ._interceptors ) > 0
94+ assert server ._interceptors [0 ].__class__ .__name__ == "_AsyncServerInterceptor"
95+
96+ # Verify transaction was created
97+ transaction = elasticapm_client .events [TRANSACTION ][0 ]
98+ assert transaction ["type" ] == "script"
99+ assert transaction ["name" ] == "grpc_async_server_instrumentation"
100+
101+
102+ def test_grpc_client_target_parsing (instrument , elasticapm_client ):
103+ """Test that target parsing works correctly for different formats"""
104+ # Test with host:port format
105+ channel = grpc .insecure_channel ("localhost:50051" )
106+ assert channel ._interceptor .host == "localhost"
107+ assert channel ._interceptor .port == 50051
108+
109+ # Test with just host format
110+ channel = grpc .insecure_channel ("localhost" )
111+ assert channel ._interceptor .host == "localhost"
112+ assert channel ._interceptor .port is None
113+
114+ # Test with invalid port format
115+ channel = grpc .insecure_channel ("localhost:invalid" )
116+ assert channel ._interceptor .host == "localhost"
117+ assert channel ._interceptor .port is None
0 commit comments