@@ -155,7 +155,8 @@ void testOM2EnabledWithFeatureFlags() {
155155 .build ())
156156 .build ();
157157 ExpositionFormats formats = ExpositionFormats .init (props );
158- ExpositionFormatWriter writer = formats .findWriter ("application/openmetrics-text" );
158+ ExpositionFormatWriter writer =
159+ formats .findWriter ("application/openmetrics-text; version=2.0.0" );
159160 assertThat (writer ).isInstanceOf (OpenMetrics2TextFormatWriter .class );
160161 }
161162
@@ -173,6 +174,94 @@ void testProtobufWriterTakesPrecedence() {
173174 assertThat (writer ).isInstanceOf (PrometheusProtobufWriter .class );
174175 }
175176
177+ @ Test
178+ void testOM2ContentNegotiationWithVersion2 () {
179+ PrometheusProperties props =
180+ PrometheusProperties .builder ()
181+ .openMetrics2Properties (
182+ OpenMetrics2Properties .builder ().enabled (true ).contentNegotiation (true ).build ())
183+ .build ();
184+ ExpositionFormats formats = ExpositionFormats .init (props );
185+ ExpositionFormatWriter writer =
186+ formats .findWriter ("application/openmetrics-text; version=2.0.0" );
187+ assertThat (writer ).isInstanceOf (OpenMetrics2TextFormatWriter .class );
188+ }
189+
190+ @ Test
191+ void testOM2ContentNegotiationWithVersion1 () {
192+ PrometheusProperties props =
193+ PrometheusProperties .builder ()
194+ .openMetrics2Properties (
195+ OpenMetrics2Properties .builder ().enabled (true ).contentNegotiation (true ).build ())
196+ .build ();
197+ ExpositionFormats formats = ExpositionFormats .init (props );
198+ ExpositionFormatWriter writer =
199+ formats .findWriter ("application/openmetrics-text; version=1.0.0" );
200+ assertThat (writer ).isInstanceOf (OpenMetricsTextFormatWriter .class );
201+ }
202+
203+ @ Test
204+ void testOM2ContentNegotiationWithNoVersion () {
205+ // When contentNegotiation=true and Accept header has no version, use OM1 writer
206+ PrometheusProperties props =
207+ PrometheusProperties .builder ()
208+ .openMetrics2Properties (
209+ OpenMetrics2Properties .builder ().enabled (true ).contentNegotiation (true ).build ())
210+ .build ();
211+ ExpositionFormats formats = ExpositionFormats .init (props );
212+ ExpositionFormatWriter writer = formats .findWriter ("application/openmetrics-text" );
213+ assertThat (writer ).isInstanceOf (OpenMetricsTextFormatWriter .class );
214+ }
215+
216+ @ Test
217+ void testOM2ContentNegotiationDisabled () {
218+ PrometheusProperties props =
219+ PrometheusProperties .builder ()
220+ .openMetrics2Properties (
221+ OpenMetrics2Properties .builder ().enabled (true ).contentNegotiation (false ).build ())
222+ .build ();
223+ ExpositionFormats formats = ExpositionFormats .init (props );
224+ ExpositionFormatWriter writer1 = formats .findWriter ("application/openmetrics-text" );
225+ ExpositionFormatWriter writer2 =
226+ formats .findWriter ("application/openmetrics-text; version=1.0.0" );
227+ ExpositionFormatWriter writer3 =
228+ formats .findWriter ("application/openmetrics-text; version=2.0.0" );
229+ assertThat (writer1 ).isInstanceOf (OpenMetrics2TextFormatWriter .class );
230+ assertThat (writer2 ).isInstanceOf (OpenMetrics2TextFormatWriter .class );
231+ assertThat (writer3 ).isInstanceOf (OpenMetrics2TextFormatWriter .class );
232+ }
233+
234+ @ Test
235+ void testOM2ContentNegotiationMultiTypeAcceptHeaderWithoutOMVersion () {
236+ // When the Accept header has multiple media types and only text/plain has a version,
237+ // the openmetrics type should be treated as having no version (use OM1).
238+ PrometheusProperties props =
239+ PrometheusProperties .builder ()
240+ .openMetrics2Properties (
241+ OpenMetrics2Properties .builder ().enabled (true ).contentNegotiation (true ).build ())
242+ .build ();
243+ ExpositionFormats formats = ExpositionFormats .init (props );
244+ ExpositionFormatWriter writer =
245+ formats .findWriter ("application/openmetrics-text, text/plain; version=0.0.4" );
246+ assertThat (writer ).isInstanceOf (OpenMetricsTextFormatWriter .class );
247+ }
248+
249+ @ Test
250+ void testOM2ContentNegotiationMultiTypeAcceptHeaderWithOMVersion () {
251+ // When the Accept header has multiple media types and openmetrics has version=2.0.0,
252+ // the OM2 writer should be selected.
253+ PrometheusProperties props =
254+ PrometheusProperties .builder ()
255+ .openMetrics2Properties (
256+ OpenMetrics2Properties .builder ().enabled (true ).contentNegotiation (true ).build ())
257+ .build ();
258+ ExpositionFormats formats = ExpositionFormats .init (props );
259+ ExpositionFormatWriter writer =
260+ formats .findWriter (
261+ "application/openmetrics-text; version=2.0.0, text/plain; version=0.0.4" );
262+ assertThat (writer ).isInstanceOf (OpenMetrics2TextFormatWriter .class );
263+ }
264+
176265 @ Test
177266 void testCounterComplete () throws IOException {
178267 String openMetricsText =
@@ -1977,14 +2066,14 @@ void testClassicGaugeHistogramCountAndSum() throws IOException {
19772066 void testClassicHistogramWithDots () throws IOException {
19782067 String openMetricsText =
19792068 """
1980- # TYPE U__my_2e_request_2e_duration_2e_seconds histogram
1981- # UNIT U__my_2e_request_2e_duration_2e_seconds seconds
1982- # HELP U__my_2e_request_2e_duration_2e_seconds Request duration in seconds
1983- U__my_2e_request_2e_duration_2e_seconds_bucket{U__http_2e_path="/hello",le="+Inf"} 130 # {U__some_2e_exemplar_2e_key="some value"} 3.0 1690298864.383
1984- U__my_2e_request_2e_duration_2e_seconds_count{U__http_2e_path="/hello"} 130
1985- U__my_2e_request_2e_duration_2e_seconds_sum{U__http_2e_path="/hello"} 0.01
1986- # EOF
1987- """ ;
2069+ # TYPE U__my_2e_request_2e_duration_2e_seconds histogram
2070+ # UNIT U__my_2e_request_2e_duration_2e_seconds seconds
2071+ # HELP U__my_2e_request_2e_duration_2e_seconds Request duration in seconds
2072+ U__my_2e_request_2e_duration_2e_seconds_bucket{U__http_2e_path="/hello",le="+Inf"} 130 # {U__some_2e_exemplar_2e_key="some value"} 3.0 1690298864.383
2073+ U__my_2e_request_2e_duration_2e_seconds_count{U__http_2e_path="/hello"} 130
2074+ U__my_2e_request_2e_duration_2e_seconds_sum{U__http_2e_path="/hello"} 0.01
2075+ # EOF
2076+ """ ;
19882077 String openMetricsTextWithExemplarsOnAllTimeSeries =
19892078 "# TYPE my_request_duration_seconds histogram\n "
19902079 + "# UNIT my_request_duration_seconds seconds\n "
@@ -2398,14 +2487,14 @@ void testNativeHistogramMinimal() throws IOException {
23982487 void testNativeHistogramWithDots () throws IOException {
23992488 String openMetricsText =
24002489 """
2401- # TYPE U__my_2e_request_2e_duration_2e_seconds histogram
2402- # UNIT U__my_2e_request_2e_duration_2e_seconds seconds
2403- # HELP U__my_2e_request_2e_duration_2e_seconds Request duration in seconds
2404- U__my_2e_request_2e_duration_2e_seconds_bucket{U__http_2e_path="/hello",le="+Inf"} 4 # {U__some_2e_exemplar_2e_key="some value"} 3.0 1690298864.383
2405- U__my_2e_request_2e_duration_2e_seconds_count{U__http_2e_path="/hello"} 4
2406- U__my_2e_request_2e_duration_2e_seconds_sum{U__http_2e_path="/hello"} 3.2
2407- # EOF
2408- """ ;
2490+ # TYPE U__my_2e_request_2e_duration_2e_seconds histogram
2491+ # UNIT U__my_2e_request_2e_duration_2e_seconds seconds
2492+ # HELP U__my_2e_request_2e_duration_2e_seconds Request duration in seconds
2493+ U__my_2e_request_2e_duration_2e_seconds_bucket{U__http_2e_path="/hello",le="+Inf"} 4 # {U__some_2e_exemplar_2e_key="some value"} 3.0 1690298864.383
2494+ U__my_2e_request_2e_duration_2e_seconds_count{U__http_2e_path="/hello"} 4
2495+ U__my_2e_request_2e_duration_2e_seconds_sum{U__http_2e_path="/hello"} 3.2
2496+ # EOF
2497+ """ ;
24092498 String openMetricsTextWithExemplarsOnAllTimeSeries =
24102499 "# TYPE my_request_duration_seconds histogram\n "
24112500 + "# UNIT my_request_duration_seconds seconds\n "
@@ -2876,12 +2965,19 @@ void testLabelValueEscape() throws IOException {
28762965
28772966 @ ParameterizedTest
28782967 @ CsvSource ({
2879- "'application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited', 'application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited; escaping=underscores'" ,
2968+ "'application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited',"
2969+ + " 'application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily;"
2970+ + " encoding=delimited; escaping=underscores'" ,
28802971 "'text/plain;version=0.0.4', 'text/plain; version=0.0.4; charset=utf-8; escaping=underscores'" ,
2881- "'application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited; escaping=allow-utf-8', 'application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited; escaping=allow-utf-8'" ,
2882- "'application/openmetrics-text', 'application/openmetrics-text; version=1.0.0; charset=utf-8; escaping=underscores'" ,
2883- "'application/openmetrics-text;version=0.0.1; escaping=underscores', 'application/openmetrics-text; version=1.0.0; charset=utf-8; escaping=underscores'" ,
2884- "'text/plain;version=0.0.4; escaping=allow-utf-8', 'text/plain; version=0.0.4; charset=utf-8; escaping=allow-utf-8'"
2972+ "'application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;"
2973+ + " escaping=allow-utf-8', 'application/vnd.google.protobuf;"
2974+ + " proto=io.prometheus.client.MetricFamily; encoding=delimited; escaping=allow-utf-8'" ,
2975+ "'application/openmetrics-text', 'application/openmetrics-text; version=1.0.0; charset=utf-8;"
2976+ + " escaping=underscores'" ,
2977+ "'application/openmetrics-text;version=0.0.1; escaping=underscores',"
2978+ + " 'application/openmetrics-text; version=1.0.0; charset=utf-8; escaping=underscores'" ,
2979+ "'text/plain;version=0.0.4; escaping=allow-utf-8', 'text/plain; version=0.0.4; charset=utf-8;"
2980+ + " escaping=allow-utf-8'"
28852981 })
28862982 public void testFindWriter (String acceptHeaderValue , String expectedFmt ) {
28872983 ExpositionFormats expositionFormats = ExpositionFormats .init ();
@@ -2910,9 +3006,9 @@ void testWrite() throws IOException {
29103006
29113007 String expected =
29123008 """
2913- # TYPE foo_metric untyped
2914- foo_metric 1.234
2915- """ ;
3009+ # TYPE foo_metric untyped
3010+ foo_metric 1.234
3011+ """ ;
29163012
29173013 assertThat (new String (out , UTF_8 )).hasToString (expected );
29183014 }
0 commit comments