3636import io .opentelemetry .proto .trace .v1 .ResourceSpans ;
3737import io .opentelemetry .proto .trace .v1 .ScopeSpans ;
3838import io .opentelemetry .proto .trace .v1 .Span ;
39+ import io .opentelemetry .proto .common .v1 .AnyValue ;
40+ import io .opentelemetry .proto .common .v1 .KeyValue ;
41+ import io .opentelemetry .proto .resource .v1 .Resource ;
42+ import org .opensearch .dataprepper .model .record .Record ;
3943import org .apache .commons .io .IOUtils ;
4044import org .junit .jupiter .api .AfterEach ;
4145import org .junit .jupiter .api .BeforeEach ;
6569import org .opensearch .dataprepper .plugins .HttpBasicArmeriaHttpAuthenticationProvider ;
6670import org .opensearch .dataprepper .plugins .certificate .CertificateProvider ;
6771import org .opensearch .dataprepper .plugins .certificate .model .Certificate ;
72+ import org .opensearch .dataprepper .plugins .otel .codec .OTelOutputFormat ;
6873import org .opensearch .dataprepper .plugins .codec .CompressionOption ;
6974import org .opensearch .dataprepper .plugins .server .HealthGrpcService ;
7075import org .opensearch .dataprepper .plugins .server .RetryInfoConfig ;
7782import java .nio .file .Path ;
7883import java .time .Duration ;
7984import java .util .Base64 ;
85+ import java .util .Collection ;
8086import java .util .Collections ;
8187import java .util .HashMap ;
8288import java .util .List ;
103109import static org .mockito .ArgumentMatchers .anyInt ;
104110import static org .mockito .ArgumentMatchers .eq ;
105111import static org .mockito .ArgumentMatchers .isA ;
112+ import static org .mockito .Mockito .doAnswer ;
106113import static org .mockito .Mockito .lenient ;
107114import static org .mockito .Mockito .mock ;
108115import static org .mockito .Mockito .never ;
@@ -119,6 +126,9 @@ class OTelTraceSourceTest {
119126 private static final String USERNAME = "test_user" ;
120127 private static final String PASSWORD = "test_password" ;
121128 private static final String TEST_PATH = "${pipelineName}/v1/traces" ;
129+ private static final String RESOURCE_ATTR_SERVICE_KEY = "service.name" ;
130+ private static final String TRACE_SERVICE_NAME = "TestTraceServiceName" ;
131+ private static final int TEST_RESOURCE_DROPPED_ATTRIBUTES_COUNT = 11 ;
122132 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ().registerModule (new JavaTimeModule ());
123133 private static final String TEST_PIPELINE_NAME = "test_pipeline" ;
124134 private static final RetryInfoConfig TEST_RETRY_INFO = new RetryInfoConfig (Duration .ofMillis (50 ), Duration .ofMillis (2000 ));
@@ -169,6 +179,7 @@ class OTelTraceSourceTest {
169179 private PluginMetrics pluginMetrics ;
170180 private PipelineDescription pipelineDescription ;
171181 private OTelTraceSource SOURCE ;
182+ private List <Record <org .opensearch .dataprepper .model .trace .Span >> recordsReceived ;
172183
173184 @ BeforeEach
174185 void beforeEach () {
@@ -222,7 +233,54 @@ private void configureObjectUnderTest() {
222233 }
223234
224235 @ Test
225- void testHttpFullJsonWithCustomPathAndAuthHeader_with_successful_response () throws InvalidProtocolBufferException {
236+ void testHttpFullJsonWithCustomPathAndAuthHeader_with_successful_response () throws Exception {
237+ doAnswer ((a )-> {
238+ recordsReceived = ((Collection <Record <org .opensearch .dataprepper .model .trace .Span >>)a .getArgument (0 )).stream ().collect (Collectors .toList ());
239+ return null ;
240+ }).when (buffer ).writeAll (any (), any (Integer .class ));
241+ when (httpBasicAuthenticationConfig .getUsername ()).thenReturn (USERNAME );
242+ when (httpBasicAuthenticationConfig .getPassword ()).thenReturn (PASSWORD );
243+ final GrpcAuthenticationProvider grpcAuthenticationProvider = new GrpcBasicAuthenticationProvider (httpBasicAuthenticationConfig );
244+
245+ when (pluginFactory .loadPlugin (eq (GrpcAuthenticationProvider .class ), any (PluginSetting .class )))
246+ .thenReturn (grpcAuthenticationProvider );
247+ when (oTelTraceSourceConfig .getAuthentication ()).thenReturn (new PluginModel ("http_basic" ,
248+ Map .of (
249+ "username" , USERNAME ,
250+ "password" , PASSWORD
251+ )));
252+ when (oTelTraceSourceConfig .enableUnframedRequests ()).thenReturn (true );
253+ when (oTelTraceSourceConfig .getPath ()).thenReturn (TEST_PATH );
254+ when (oTelTraceSourceConfig .getOutputFormat ()).thenReturn (OTelOutputFormat .OPENSEARCH );
255+
256+ configureObjectUnderTest ();
257+ SOURCE .start (buffer );
258+
259+ final String encodeToString = Base64 .getEncoder ()
260+ .encodeToString (String .format ("%s:%s" , USERNAME , PASSWORD ).getBytes (StandardCharsets .UTF_8 ));
261+
262+ final String transformedPath = "/" + TEST_PIPELINE_NAME + "/v1/traces" ;
263+
264+ WebClient .of ().prepare ()
265+ .post ("http://127.0.0.1:21890" + transformedPath )
266+ .content (MediaType .JSON_UTF_8 , JsonFormat .printer ().print (createExportTraceRequest ()).getBytes ())
267+ .header ("Authorization" , "Basic " + encodeToString )
268+ .execute ()
269+ .aggregate ()
270+ .whenComplete ((response , throwable ) -> assertSecureResponseWithStatusCode (response , HttpStatus .OK , throwable ))
271+ .join ();
272+
273+ assertThat (recordsReceived .size (), equalTo (1 ));
274+ org .opensearch .dataprepper .model .trace .Span span = recordsReceived .get (0 ).getData ();
275+ assertThat (span .get ("attributes/resource.attributes.service@name" , String .class ), equalTo (TRACE_SERVICE_NAME ));
276+ }
277+
278+ @ Test
279+ void testHttpFullJsonWithCustomPathAndAuthHeader_using_otel_format_with_successful_response () throws Exception {
280+ doAnswer ((a )-> {
281+ recordsReceived = ((Collection <Record <org .opensearch .dataprepper .model .trace .Span >>)a .getArgument (0 )).stream ().collect (Collectors .toList ());
282+ return null ;
283+ }).when (buffer ).writeAll (any (), any (Integer .class ));
226284 when (httpBasicAuthenticationConfig .getUsername ()).thenReturn (USERNAME );
227285 when (httpBasicAuthenticationConfig .getPassword ()).thenReturn (PASSWORD );
228286 final GrpcAuthenticationProvider grpcAuthenticationProvider = new GrpcBasicAuthenticationProvider (httpBasicAuthenticationConfig );
@@ -236,6 +294,7 @@ void testHttpFullJsonWithCustomPathAndAuthHeader_with_successful_response() thro
236294 )));
237295 when (oTelTraceSourceConfig .enableUnframedRequests ()).thenReturn (true );
238296 when (oTelTraceSourceConfig .getPath ()).thenReturn (TEST_PATH );
297+ when (oTelTraceSourceConfig .getOutputFormat ()).thenReturn (OTelOutputFormat .OTEL );
239298
240299 configureObjectUnderTest ();
241300 SOURCE .start (buffer );
@@ -253,6 +312,10 @@ void testHttpFullJsonWithCustomPathAndAuthHeader_with_successful_response() thro
253312 .aggregate ()
254313 .whenComplete ((response , throwable ) -> assertSecureResponseWithStatusCode (response , HttpStatus .OK , throwable ))
255314 .join ();
315+
316+ assertThat (recordsReceived .size (), equalTo (1 ));
317+ org .opensearch .dataprepper .model .trace .Span span = recordsReceived .get (0 ).getData ();
318+ assertThat (span .get ("resource/attributes/service.name" , String .class ), equalTo (TRACE_SERVICE_NAME ));
256319 }
257320
258321 @ Test
@@ -792,8 +855,17 @@ private ExportTraceServiceRequest createExportTraceRequest() {
792855 .setEndTimeUnixNano (101 )
793856 .setTraceState ("SUCCESS" ).build ();
794857
858+ final Resource resource = Resource .newBuilder ()
859+ .setDroppedAttributesCount (TEST_RESOURCE_DROPPED_ATTRIBUTES_COUNT )
860+ .addAttributes (KeyValue .newBuilder ()
861+ .setKey (RESOURCE_ATTR_SERVICE_KEY )
862+ .setValue (AnyValue .newBuilder ().setStringValue (TRACE_SERVICE_NAME ).build ())
863+ )
864+ .build ();
865+
795866 return ExportTraceServiceRequest .newBuilder ()
796867 .addResourceSpans (ResourceSpans .newBuilder ()
868+ .setResource (resource )
797869 .addScopeSpans (ScopeSpans .newBuilder ().addSpans (testSpan )).build ())
798870 .build ();
799871 }
0 commit comments