1
+ """Tests for Jupyter Server metrics functionality."""
2
+
3
+ import pytest
4
+ import requests
5
+ import time
6
+ from unittest .mock import patch
7
+
8
+ from jupyter_server .prometheus .server import PrometheusMetricsServer , start_metrics_server
9
+ from jupyter_server .serverapp import ServerApp
10
+
11
+
12
+ @pytest .fixture
13
+ def metrics_server_app ():
14
+ """Create a server app with metrics enabled on a specific port."""
15
+ # Override the environment variable for this test
16
+ with patch .dict ('os.environ' , {'JUPYTER_SERVER_METRICS_PORT' : '9090' }):
17
+ app = ServerApp ()
18
+ # Set the metrics_port directly as a trait
19
+ app .metrics_port = 9090
20
+ app .initialize ([])
21
+ return app
22
+
23
+
24
+ @pytest .fixture
25
+ def metrics_server (metrics_server_app ):
26
+ """Start a metrics server for testing."""
27
+ server = start_metrics_server (metrics_server_app , 9090 )
28
+ # Give the server time to start
29
+ time .sleep (0.1 )
30
+ yield server
31
+ # Cleanup
32
+ if hasattr (server , 'stop' ):
33
+ server .stop ()
34
+
35
+
36
+ def test_metrics_server_starts (metrics_server ):
37
+ """Test that the metrics server starts successfully."""
38
+ assert metrics_server is not None
39
+ assert hasattr (metrics_server , 'port' )
40
+ assert metrics_server .port == 9090
41
+
42
+
43
+ def test_metrics_endpoint_accessible (metrics_server ):
44
+ """Test that the metrics endpoint is accessible."""
45
+ response = requests .get (f'http://localhost:{ metrics_server .port } /metrics' )
46
+ assert response .status_code == 200
47
+ assert 'jupyter_server' in response .text
48
+
49
+
50
+ def test_metrics_contains_kernel_metrics (metrics_server ):
51
+ """Test that kernel metrics are present."""
52
+ response = requests .get (f'http://localhost:{ metrics_server .port } /metrics' )
53
+ assert response .status_code == 200
54
+ content = response .text
55
+ assert 'jupyter_kernel_currently_running_total' in content
56
+
57
+
58
+ def test_metrics_contains_server_info (metrics_server ):
59
+ """Test that server info metrics are present."""
60
+ response = requests .get (f'http://localhost:{ metrics_server .port } /metrics' )
61
+ assert response .status_code == 200
62
+ content = response .text
63
+ assert 'jupyter_server_info' in content
64
+
65
+
66
+ def test_metrics_server_with_authentication ():
67
+ """Test metrics server with authentication enabled."""
68
+ app = ServerApp ()
69
+ app .metrics_port = 9091
70
+ app .authenticate_prometheus = True
71
+ app .initialize ([])
72
+ app .identity_provider .token = "test_token"
73
+
74
+ server = start_metrics_server (app , 9091 )
75
+ time .sleep (0.1 )
76
+
77
+ try :
78
+ # Without token should fail
79
+ response = requests .get (f'http://localhost:{ server .port } /metrics' )
80
+ assert response .status_code == 401
81
+
82
+ # With token should succeed
83
+ response = requests .get (f'http://localhost:{ server .port } /metrics?token=test_token' )
84
+ assert response .status_code == 200
85
+ finally :
86
+ if hasattr (server , 'stop' ):
87
+ server .stop ()
88
+
89
+
90
+ def test_metrics_server_port_conflict_handling ():
91
+ """Test that metrics server handles port conflicts gracefully."""
92
+ app = ServerApp ()
93
+ app .metrics_port = 9092
94
+ app .initialize ([])
95
+ server2 = None
96
+ # Start first server
97
+ server1 = start_metrics_server (app , 9092 )
98
+ time .sleep (0.1 )
99
+
100
+ try :
101
+ # Try to start second server on same port
102
+ server2 = start_metrics_server (app , 9092 )
103
+ time .sleep (0.1 )
104
+
105
+ # One of them should have failed to start or used a different port
106
+ if server2 is not None and hasattr (server2 , 'port' ):
107
+ assert server2 .port != 9092 or server1 .port != 9092
108
+ finally :
109
+ if hasattr (server1 , 'stop' ):
110
+ server1 .stop ()
111
+ if server2 is not None and hasattr (server2 , 'stop' ):
112
+ server2 .stop ()
113
+
114
+
115
+ def test_metrics_server_disabled_when_port_zero ():
116
+ """Test that metrics server is not started when port is 0."""
117
+ with patch .dict ('os.environ' , {'JUPYTER_SERVER_METRICS_PORT' : '0' }):
118
+ app = ServerApp ()
119
+ app .metrics_port = 0
120
+ app .initialize ([])
121
+
122
+ # Should not start metrics server
123
+ assert not hasattr (app , 'metrics_server' ) or app .metrics_server is None
124
+
125
+
126
+ def test_metrics_url_logging_with_separate_server ():
127
+ """Test that metrics URL is logged correctly with separate server."""
128
+ app = ServerApp ()
129
+ app .metrics_port = 9093
130
+ app .authenticate_prometheus = True
131
+ app .initialize ([])
132
+ app .identity_provider .token = "test_token"
133
+
134
+ # Start metrics server
135
+ server = start_metrics_server (app , 9093 )
136
+ time .sleep (0.1 )
137
+
138
+ try :
139
+ # The URL should include the separate port
140
+ expected_url = "http://localhost:9093/metrics?token=test_token"
141
+ # This is a basic test - in practice you'd capture the log output
142
+ assert server .port == 9093
143
+ finally :
144
+ if hasattr (server , 'stop' ):
145
+ server .stop ()
146
+
147
+
148
+ def test_metrics_url_logging_with_main_server ():
149
+ """Test that metrics URL is logged correctly when using main server."""
150
+ app = ServerApp ()
151
+ app .metrics_port = 0 # Disable separate server
152
+ app .authenticate_prometheus = True
153
+ app .initialize ([])
154
+ app .identity_provider .token = "test_token"
155
+
156
+ # Should use main server's /metrics endpoint
157
+ # This would be tested by checking the log output in practice
158
+ assert app .metrics_port == 0
0 commit comments