@@ -150,7 +150,119 @@ public void testFindAllNoTenantId() {
150150 }
151151
152152 @ Test
153- public void testFindAttributes () {
153+ public void testFindAttributesWithInternalFlag () {
154+ RequestContext requestContext = mock (RequestContext .class );
155+ when (requestContext .getTenantId ()).thenReturn (Optional .of ("test-tenant-id" ));
156+ Context ctx = Context .current ().withValue (RequestContext .CURRENT , requestContext );
157+
158+ Context previous = ctx .attach ();
159+ try {
160+ Collection collection =
161+ mockCollectionReturningDocuments (
162+ createMockDocument (
163+ "__root" ,
164+ "name" ,
165+ AttributeScope .EVENT ,
166+ AttributeType .ATTRIBUTE ,
167+ AttributeKind .TYPE_STRING ),
168+ createMockDocument (
169+ "__root" ,
170+ "duration" ,
171+ AttributeScope .EVENT ,
172+ AttributeType .METRIC ,
173+ AttributeKind .TYPE_INT64 ));
174+ StreamObserver <AttributeMetadata > responseObserver = mock (StreamObserver .class );
175+ AttributeServiceImpl attributeService = new AttributeServiceImpl (collection );
176+
177+ List <String > fqnList = List .of ("EVENT.name" , "EVENT.id" );
178+ List <String > keyList = List .of ("name" , "startTime" , "duration" );
179+
180+ AttributeMetadataFilter attributeMetadataFilter =
181+ AttributeMetadataFilter .newBuilder ()
182+ .addAllFqn (fqnList )
183+ .addAllKey (keyList )
184+ .addAllScope (
185+ List .of (AttributeScope .TRACE , AttributeScope .EVENT , AttributeScope .BACKEND ))
186+ .addScopeString ("OTHER" )
187+ .setInternal (true )
188+ .build ();
189+
190+ List <String > allScopes =
191+ List .of (
192+ "OTHER" ,
193+ AttributeScope .TRACE .name (),
194+ AttributeScope .EVENT .name (),
195+ AttributeScope .BACKEND .name ());
196+
197+ attributeService .findAttributes (attributeMetadataFilter , responseObserver );
198+
199+ ArgumentCaptor <Query > queryCaptor = ArgumentCaptor .forClass (Query .class );
200+ verify (collection , times (1 )).search (queryCaptor .capture ());
201+
202+ Filter filter = queryCaptor .getValue ().getFilter ();
203+ // The structure of the filters is an and(^) filter chain that looks like this:
204+ // ((((tenant_id ^ fqn) ^ (scope_string | scope)) ^ key) ^ internal)
205+ Assertions .assertEquals (Filter .Op .AND , filter .getOp ());
206+ Assertions .assertEquals (Filter .Op .EQ , filter .getChildFilters ()[1 ].getOp ());
207+ Assertions .assertEquals ("internal" , filter .getChildFilters ()[1 ].getFieldName ());
208+ Assertions .assertEquals (true , filter .getChildFilters ()[1 ].getValue ());
209+
210+ Filter innerFilter = filter .getChildFilters ()[0 ];
211+ Assertions .assertEquals ("key" , innerFilter .getChildFilters ()[1 ].getFieldName ());
212+ Assertions .assertEquals (keyList , innerFilter .getChildFilters ()[1 ].getValue ());
213+
214+ Assertions .assertEquals (Filter .Op .AND , innerFilter .getChildFilters ()[0 ].getOp ());
215+ Filter scopeFilter = innerFilter .getChildFilters ()[0 ].getChildFilters ()[1 ];
216+ Assertions .assertEquals (Filter .Op .OR , scopeFilter .getOp ());
217+
218+ Assertions .assertEquals (Filter .Op .IN , scopeFilter .getChildFilters ()[0 ].getOp ());
219+ Assertions .assertEquals ("scope_string" , scopeFilter .getChildFilters ()[0 ].getFieldName ());
220+ Assertions .assertEquals (allScopes , scopeFilter .getChildFilters ()[0 ].getValue ());
221+
222+ Assertions .assertEquals (Filter .Op .IN , scopeFilter .getChildFilters ()[1 ].getOp ());
223+ Assertions .assertEquals ("scope" , scopeFilter .getChildFilters ()[1 ].getFieldName ());
224+ Assertions .assertEquals (allScopes , scopeFilter .getChildFilters ()[1 ].getValue ());
225+
226+ Assertions .assertEquals (
227+ Filter .Op .AND , innerFilter .getChildFilters ()[0 ].getChildFilters ()[0 ].getOp ());
228+ Assertions .assertEquals (
229+ Filter .Op .IN ,
230+ innerFilter .getChildFilters ()[0 ].getChildFilters ()[0 ].getChildFilters ()[1 ].getOp ());
231+ Assertions .assertEquals (
232+ "fqn" ,
233+ innerFilter .getChildFilters ()[0 ].getChildFilters ()[0 ].getChildFilters ()[1 ]
234+ .getFieldName ());
235+ Assertions .assertEquals (
236+ fqnList ,
237+ innerFilter .getChildFilters ()[0 ].getChildFilters ()[0 ].getChildFilters ()[1 ].getValue ());
238+
239+ Assertions .assertEquals (
240+ Filter .Op .IN ,
241+ innerFilter .getChildFilters ()[0 ].getChildFilters ()[0 ].getChildFilters ()[0 ].getOp ());
242+ Assertions .assertEquals (
243+ List .of ("__root" , "test-tenant-id" ),
244+ innerFilter .getChildFilters ()[0 ].getChildFilters ()[0 ].getChildFilters ()[0 ].getValue ());
245+
246+ ArgumentCaptor <AttributeMetadata > attributeMetadataArgumentCaptor =
247+ ArgumentCaptor .forClass (AttributeMetadata .class );
248+ verify (responseObserver , times (2 )).onNext (attributeMetadataArgumentCaptor .capture ());
249+
250+ List <AttributeMetadata > attributeMetadataList =
251+ attributeMetadataArgumentCaptor .getAllValues ();
252+ Assertions .assertEquals (2 , attributeMetadataList .size ());
253+
254+ Assertions .assertEquals (MOCK_EVENT_NAME_ATTRIBUTE , attributeMetadataList .get (0 ));
255+ Assertions .assertEquals (MOCK_EVENT_DURATION_ATTRIBUTE , attributeMetadataList .get (1 ));
256+
257+ verify (responseObserver , times (1 )).onCompleted ();
258+ verify (responseObserver , never ()).onError (any (Throwable .class ));
259+ } finally {
260+ ctx .detach (previous );
261+ }
262+ }
263+
264+ @ Test
265+ public void testFindAttributesWithNoInternalFlag () {
154266 RequestContext requestContext = mock (RequestContext .class );
155267 when (requestContext .getTenantId ()).thenReturn (Optional .of ("test-tenant-id" ));
156268 Context ctx = Context .current ().withValue (RequestContext .CURRENT , requestContext );
@@ -213,7 +325,6 @@ public void testFindAttributes() {
213325 Assertions .assertEquals (Filter .Op .IN , scopeFilter .getChildFilters ()[0 ].getOp ());
214326 Assertions .assertEquals ("scope_string" , scopeFilter .getChildFilters ()[0 ].getFieldName ());
215327 Assertions .assertEquals (allScopes , scopeFilter .getChildFilters ()[0 ].getValue ());
216-
217328 Assertions .assertEquals (Filter .Op .IN , scopeFilter .getChildFilters ()[1 ].getOp ());
218329 Assertions .assertEquals ("scope" , scopeFilter .getChildFilters ()[1 ].getFieldName ());
219330 Assertions .assertEquals (allScopes , scopeFilter .getChildFilters ()[1 ].getValue ());
@@ -223,13 +334,6 @@ public void testFindAttributes() {
223334 Assertions .assertEquals (
224335 Filter .Op .IN ,
225336 filter .getChildFilters ()[0 ].getChildFilters ()[0 ].getChildFilters ()[1 ].getOp ());
226- Assertions .assertEquals (
227- "fqn" ,
228- filter .getChildFilters ()[0 ].getChildFilters ()[0 ].getChildFilters ()[1 ].getFieldName ());
229- Assertions .assertEquals (
230- fqnList ,
231- filter .getChildFilters ()[0 ].getChildFilters ()[0 ].getChildFilters ()[1 ].getValue ());
232-
233337 Assertions .assertEquals (
234338 Filter .Op .IN ,
235339 filter .getChildFilters ()[0 ].getChildFilters ()[0 ].getChildFilters ()[0 ].getOp ());
@@ -240,14 +344,11 @@ public void testFindAttributes() {
240344 ArgumentCaptor <AttributeMetadata > attributeMetadataArgumentCaptor =
241345 ArgumentCaptor .forClass (AttributeMetadata .class );
242346 verify (responseObserver , times (2 )).onNext (attributeMetadataArgumentCaptor .capture ());
243-
244347 List <AttributeMetadata > attributeMetadataList =
245348 attributeMetadataArgumentCaptor .getAllValues ();
246349 Assertions .assertEquals (2 , attributeMetadataList .size ());
247-
248350 Assertions .assertEquals (MOCK_EVENT_NAME_ATTRIBUTE , attributeMetadataList .get (0 ));
249351 Assertions .assertEquals (MOCK_EVENT_DURATION_ATTRIBUTE , attributeMetadataList .get (1 ));
250-
251352 verify (responseObserver , times (1 )).onCompleted ();
252353 verify (responseObserver , never ()).onError (any (Throwable .class ));
253354 } finally {
0 commit comments