11package org .hypertrace .entity .data .service .client ;
22
3+ import static org .junit .jupiter .api .Assertions .assertEquals ;
34import static org .mockito .ArgumentMatchers .any ;
45import static org .mockito .ArgumentMatchers .anyString ;
56import static org .mockito .Mockito .mock ;
1011
1112import java .util .HashMap ;
1213import java .util .Map ;
14+ import org .hypertrace .entity .change .event .v1 .EntityChangeEventKey ;
15+ import org .hypertrace .entity .change .event .v1 .EntityChangeEventValue ;
16+ import org .hypertrace .entity .change .event .v1 .EntityCreateEvent ;
17+ import org .hypertrace .entity .change .event .v1 .EntityDeleteEvent ;
18+ import org .hypertrace .entity .change .event .v1 .EntityUpdateEvent ;
1319import org .hypertrace .entity .data .service .v1 .AttributeValue ;
1420import org .hypertrace .entity .data .service .v1 .ByIdRequest ;
1521import org .hypertrace .entity .data .service .v1 .ByTypeAndIdentifyingAttributes ;
@@ -163,32 +169,14 @@ public void testGetById() {
163169 String tenantId = "tenant" ;
164170 String entityId = "entity-12346" ;
165171
166- Map <String , AttributeValue > identifyingAttributesMap = new HashMap <>();
167- identifyingAttributesMap .put (
168- "entity_name" ,
169- AttributeValue .newBuilder ()
170- .setValue (Value .newBuilder ().setString ("GET /products" ).build ())
171- .build ());
172- identifyingAttributesMap .put (
173- "is_active" ,
174- AttributeValue .newBuilder ().setValue (Value .newBuilder ().setBoolean (true ).build ()).build ());
175-
176- Entity entity =
177- Entity .newBuilder ()
178- .setTenantId (tenantId )
179- .setEntityId (entityId )
180- .setEntityType ("API" )
181- .setEntityName ("GET /products" )
182- .putAllIdentifyingAttributes (identifyingAttributesMap )
183- .build ();
184-
185- when (entityDataServiceClient .getById (anyString (), any (ByIdRequest .class ))).thenReturn (entity );
172+ when (entityDataServiceClient .getById (anyString (), any (ByIdRequest .class )))
173+ .thenReturn (getEntity (tenantId , entityId ));
186174
187175 edsCacheClient .getById (tenantId , entityId );
188176 edsCacheClient .getById (tenantId , entityId );
189177
190178 verify (entityDataServiceClient , times (1 ))
191- .getById ("tenant" , ByIdRequest .newBuilder ().setEntityId ("entity-12346" ).build ());
179+ .getById (tenantId , ByIdRequest .newBuilder ().setEntityId (entityId ).build ());
192180 }
193181
194182 @ Test
@@ -207,4 +195,139 @@ public void testGetByIdForNull() {
207195 verify (entityDataServiceClient , times (2 ))
208196 .getById ("tenant" , ByIdRequest .newBuilder ().setEntityId ("entity-12346" ).build ());
209197 }
198+
199+ @ Test
200+ void testUpdateBasedOnCreateChangeEvent () {
201+ String tenantId = "tenant" ;
202+ String entityId = "entityId" ;
203+ EntityChangeEventKey key =
204+ EntityChangeEventKey .newBuilder ()
205+ .setTenantId (tenantId )
206+ .setEntityType ("API" )
207+ .setEntityId (entityId )
208+ .build ();
209+ EntityChangeEventValue value =
210+ EntityChangeEventValue .newBuilder ()
211+ .setCreateEvent (
212+ EntityCreateEvent .newBuilder ()
213+ .setCreatedEntity (getEntity (tenantId , entityId ))
214+ .build ())
215+ .build ();
216+
217+ // expectation: no-op for create event
218+ edsCacheClient .updateBasedOnChangeEvent (key , value );
219+ // mock the eds call for get
220+ when (entityDataServiceClient .getById (anyString (), any (ByIdRequest .class )))
221+ .thenReturn (getEntity (tenantId , entityId ));
222+ // try to fetch from cache
223+ edsCacheClient .getById (tenantId , entityId );
224+ // since create event is ignored the fetch triggers a invocation
225+ verify (entityDataServiceClient , times (1 ))
226+ .getById (tenantId , ByIdRequest .newBuilder ().setEntityId (entityId ).build ());
227+ }
228+
229+ @ Test
230+ void testUpdateBasedOnUpdateChangeEvent () {
231+ String tenantId = "tenant" ;
232+ String entityId = "entityId" ;
233+
234+ String originalEntityName = "GET /products-v1" ;
235+ when (entityDataServiceClient .getById (anyString (), any (ByIdRequest .class )))
236+ .thenReturn (getEntity (tenantId , entityId , originalEntityName ));
237+
238+ // seed cache
239+ edsCacheClient .getById (tenantId , entityId );
240+ Entity returnedEntity = edsCacheClient .getById (tenantId , entityId );
241+ assertEquals (originalEntityName , returnedEntity .getEntityName ());
242+
243+ verify (entityDataServiceClient , times (1 ))
244+ .getById (tenantId , ByIdRequest .newBuilder ().setEntityId (entityId ).build ());
245+
246+ EntityChangeEventKey key =
247+ EntityChangeEventKey .newBuilder ()
248+ .setTenantId (tenantId )
249+ .setEntityType ("API" )
250+ .setEntityId (entityId )
251+ .build ();
252+ String updatedEntityName = "GET /products-v2" ;
253+ EntityChangeEventValue value =
254+ EntityChangeEventValue .newBuilder ()
255+ .setUpdateEvent (
256+ EntityUpdateEvent .newBuilder ()
257+ .setLatestEntity (getEntity (tenantId , entityId , updatedEntityName ))
258+ .build ())
259+ .build ();
260+
261+ // expectation: update entity name to newer one
262+ edsCacheClient .updateBasedOnChangeEvent (key , value );
263+ // try to fetch from cache, should return one with new entityName
264+ returnedEntity = edsCacheClient .getById (tenantId , entityId );
265+ assertEquals (updatedEntityName , returnedEntity .getEntityName ());
266+ // no more invocations same as before (1) done while seeding cache
267+ verify (entityDataServiceClient , times (1 ))
268+ .getById (tenantId , ByIdRequest .newBuilder ().setEntityId (entityId ).build ());
269+ }
270+
271+ @ Test
272+ void testUpdateBasedOnDeleteChangeEvent () {
273+ String tenantId = "tenant" ;
274+ String entityId = "entityId" ;
275+
276+ when (entityDataServiceClient .getById (anyString (), any (ByIdRequest .class )))
277+ .thenReturn (getEntity (tenantId , entityId ));
278+
279+ // seed cache
280+ edsCacheClient .getById (tenantId , entityId );
281+ edsCacheClient .getById (tenantId , entityId );
282+
283+ verify (entityDataServiceClient , times (1 ))
284+ .getById (tenantId , ByIdRequest .newBuilder ().setEntityId (entityId ).build ());
285+
286+ EntityChangeEventKey key =
287+ EntityChangeEventKey .newBuilder ()
288+ .setTenantId (tenantId )
289+ .setEntityType ("API" )
290+ .setEntityId (entityId )
291+ .build ();
292+ String updatedEntityName = "GET /products-v2" ;
293+ EntityChangeEventValue value =
294+ EntityChangeEventValue .newBuilder ()
295+ .setDeleteEvent (
296+ EntityDeleteEvent .newBuilder ()
297+ .setDeletedEntity (getEntity (tenantId , entityId , updatedEntityName ))
298+ .build ())
299+ .build ();
300+
301+ // expectation: invalidate cache
302+ edsCacheClient .updateBasedOnChangeEvent (key , value );
303+ // try to fetch from cache, fetch should result in remote call
304+ edsCacheClient .getById (tenantId , entityId );
305+ // one more invocation same after seeding cache
306+ verify (entityDataServiceClient , times (2 ))
307+ .getById (tenantId , ByIdRequest .newBuilder ().setEntityId (entityId ).build ());
308+ }
309+
310+ private Entity getEntity (String tenantId , String entityId ) {
311+ return getEntity (tenantId , entityId , "GET /products" );
312+ }
313+
314+ private Entity getEntity (String tenantId , String entityId , String entityName ) {
315+ Map <String , AttributeValue > identifyingAttributesMap = new HashMap <>();
316+ identifyingAttributesMap .put (
317+ "entity_name" ,
318+ AttributeValue .newBuilder ()
319+ .setValue (Value .newBuilder ().setString (entityName ).build ())
320+ .build ());
321+ identifyingAttributesMap .put (
322+ "is_active" ,
323+ AttributeValue .newBuilder ().setValue (Value .newBuilder ().setBoolean (true ).build ()).build ());
324+
325+ return Entity .newBuilder ()
326+ .setTenantId (tenantId )
327+ .setEntityId (entityId )
328+ .setEntityType ("API" )
329+ .setEntityName (entityName )
330+ .putAllIdentifyingAttributes (identifyingAttributesMap )
331+ .build ();
332+ }
210333}
0 commit comments