Skip to content

Commit

Permalink
added GetChangedEntitiesCommandHandler. Added more tests to NewRevisi…
Browse files Browse the repository at this point in the history
…onsEventServiceTest. Created GetChangedEntitiesCommandHandlerIT integration test.
  • Loading branch information
soimugeo committed Nov 12, 2024
1 parent be2a2a0 commit 08bc11c
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto;

import java.util.List;

public record ChangedEntities(List<String> createdEntities,
List<String> updatedEntities,
List<String> deletedEntities) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.handlers;

import edu.stanford.protege.webprotege.ipc.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.services.NewRevisionsEventService;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.Nonnull;


@Component
public class GetChangedEntitiesCommandHandler implements CommandHandler<GetChangedEntitiesRequest, GetChangedEntitiesResponse> {

private final NewRevisionsEventService service;

public GetChangedEntitiesCommandHandler(NewRevisionsEventService service) {
this.service = service;
}


@Nonnull
@Override
public String getChannelName() {
return GetChangedEntitiesRequest.CHANNEL;
}

@Override
public Class<GetChangedEntitiesRequest> getRequestClass() {
return GetChangedEntitiesRequest.class;
}

@Override
public Mono<GetChangedEntitiesResponse> handleRequest(GetChangedEntitiesRequest request, ExecutionContext executionContext) {
var entityChanges = service.getChangedEntitiesAfterTimestamp(request.projectId(), request.timestamp());
return Mono.just(GetChangedEntitiesResponse.create(entityChanges));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.handlers;

import com.fasterxml.jackson.annotation.*;
import edu.stanford.protege.webprotege.common.*;

import java.sql.Timestamp;

@JsonTypeName(GetChangedEntitiesRequest.CHANNEL)
public record GetChangedEntitiesRequest(
@JsonProperty("projectId") ProjectId projectId,
@JsonProperty("timestamp") Timestamp timestamp
) implements Request<GetChangedEntitiesResponse> {

public static final String CHANNEL = "webprotege.history.GetChangedEntities";

@Override
public String getChannel() {
return CHANNEL;
}

public static GetChangedEntitiesRequest create(ProjectId projectId,
Timestamp timestamp) {
return new GetChangedEntitiesRequest(projectId, timestamp);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.handlers;

import com.fasterxml.jackson.annotation.*;
import edu.stanford.protege.webprotege.common.Response;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto.ChangedEntities;

import static edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.handlers.GetChangedEntitiesRequest.CHANNEL;

@JsonTypeName(CHANNEL)
public record GetChangedEntitiesResponse(
@JsonProperty("changedEntities") ChangedEntities changedEntities) implements Response {
public static GetChangedEntitiesResponse create(ChangedEntities changedEntities) {
return new GetChangedEntitiesResponse(changedEntities);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.repositories;

import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.events.RevisionsEvent;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.*;

public interface RevisionsEventRepository extends MongoRepository<RevisionsEvent,String> {
import java.util.List;

public interface RevisionsEventRepository extends MongoRepository<RevisionsEvent, String> {
@Query("{ 'projectId.id': ?0, 'timestamp': { $gt: ?1 } }")
List<RevisionsEvent> findByProjectIdAndTimestampAfter(String projectId, long timestamp);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import edu.stanford.protege.webprotege.change.ProjectChange;
import edu.stanford.protege.webprotege.common.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.events.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto.ChangedEntities;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.events.NewRevisionsEvent;
import org.semanticweb.owlapi.model.OWLEntity;

import java.sql.Timestamp;
import java.util.Optional;

public interface NewRevisionsEventService {

void registerEvent(NewRevisionsEvent newLinRevEvent);

Page<ProjectChange> fetchPaginatedProjectChanges(ProjectId projectId, Optional<OWLEntity> subject, int pageNumber, int pageSize);

ChangedEntities getChangedEntitiesAfterTimestamp(ProjectId projectId, Timestamp timestamp);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import edu.stanford.protege.webprotege.change.ProjectChange;
import edu.stanford.protege.webprotege.common.Page;
import edu.stanford.protege.webprotege.common.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.events.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.mappers.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.repositories.RevisionsEventRepository;
Expand All @@ -12,7 +13,9 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

import static edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.events.RevisionsEvent.*;

Expand Down Expand Up @@ -74,4 +77,32 @@ public Page<ProjectChange> fetchPaginatedProjectChanges(ProjectId projectId, Opt
//PageRequest from spring-data is starting from 0
return Page.create(pageNumber, revisionsEventPage.getTotalPages(), changes, revisionsEventPage.getTotalElements());
}

@Override
public ChangedEntities getChangedEntitiesAfterTimestamp(ProjectId projectId, Timestamp timestamp) {
List<RevisionsEvent> revisionsEvents = repository.findByProjectIdAndTimestampAfter(projectId.id(), timestamp.getTime());

List<String> createdEntities = revisionsEvents.stream()
.filter(event -> event.changeType() == ChangeType.CREATE_ENTITY)
.map(RevisionsEvent::whoficEntityIri)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());

List<String> updatedEntities = revisionsEvents.stream()
.filter(event -> event.changeType() == ChangeType.UPDATE_ENTITY)
.map(RevisionsEvent::whoficEntityIri)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());

List<String> deletedEntities = revisionsEvents.stream()
.filter(event -> event.changeType() == ChangeType.DELETE_ENTITY)
.map(RevisionsEvent::whoficEntityIri)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());

return new ChangedEntities(createdEntities, updatedEntities, deletedEntities);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.handlers;

import edu.stanford.protege.webprotege.common.ProjectId;
import edu.stanford.protege.webprotegeeventshistory.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.dto.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.events.RevisionsEvent;
import org.bson.Document;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import reactor.core.publisher.Mono;

import java.sql.Timestamp;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@ExtendWith({SpringExtension.class, RabbitTestExtension.class, MongoTestExtension.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
@Import({WebprotegeEventsHistoryApplication.class})
public class GetChangedEntitiesCommandHandlerIT {

@Autowired
private GetChangedEntitiesCommandHandler commandHandler;

@Autowired
private MongoTemplate mongoTemplate;

@BeforeEach
public void setUp() {
mongoTemplate.dropCollection(RevisionsEvent.class);
}

@Test
public void GIVEN_eventsAfterTimestamp_WHEN_handleRequestCalled_THEN_returnChangedEntities() {
ProjectId projectId = ProjectId.generate();
Timestamp timestamp = new Timestamp(System.currentTimeMillis() - 10000);

insertMockRevisionsEvent(projectId, "entity1", timestamp.getTime() - 5000, ChangeType.CREATE_ENTITY);
insertMockRevisionsEvent(projectId, "entity2", timestamp.getTime() + 5000, ChangeType.UPDATE_ENTITY);
insertMockRevisionsEvent(projectId, "entity3", timestamp.getTime() + 6000, ChangeType.DELETE_ENTITY);

GetChangedEntitiesRequest request = GetChangedEntitiesRequest.create(projectId, timestamp);

Mono<GetChangedEntitiesResponse> responseMono = commandHandler.handleRequest(request, null);
GetChangedEntitiesResponse response = responseMono.block();

assertNotNull(response);
ChangedEntities changedEntities = response.changedEntities();
assertEquals(0, changedEntities.createdEntities().size());
assertEquals(1, changedEntities.updatedEntities().size());
assertEquals(1, changedEntities.deletedEntities().size());

assertEquals("entity2", changedEntities.updatedEntities().get(0));
assertEquals("entity3", changedEntities.deletedEntities().get(0));
}

private void insertMockRevisionsEvent(ProjectId projectId, String entityIri, long timestamp, ChangeType changeType) {
RevisionsEvent revisionsEvent = RevisionsEvent.create(
projectId,
entityIri,
changeType,
timestamp,
new Document()
);
mongoTemplate.save(revisionsEvent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.mappers.*;
import edu.stanford.protege.webprotegeeventshistory.uiHistoryConcern.repositories.RevisionsEventRepository;
import org.bson.Document;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import org.semanticweb.owlapi.model.*;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.*;

import java.sql.Timestamp;
import java.util.*;

import static org.junit.jupiter.api.Assertions.*;
Expand All @@ -37,9 +38,19 @@ public class NewRevisionsEventServiceTest {
@InjectMocks
private NewRevisionsEventServiceImpl service;


private ProjectId projectId;
private Timestamp timestamp;


@BeforeEach
public void setUp() {
projectId = new ProjectId("testProjectId");
timestamp = new Timestamp(System.currentTimeMillis());
}

@Test
public void GIVEN_validNewLinearizationRevisionsEvent_WHEN_registerEventCalled_THEN_revisionsEventsSavedToRepository() {
ProjectId projectId = new ProjectId("testProjectId");
Set<ProjectChangeForEntity> changes = Set.of(mock(ProjectChangeForEntity.class));
NewRevisionsEvent event = NewRevisionsEvent.create(EventId.generate(), projectId, changes);

Expand All @@ -55,12 +66,11 @@ public void GIVEN_validNewLinearizationRevisionsEvent_WHEN_registerEventCalled_T

@Test
public void GIVEN_validProjectIdAndSubject_WHEN_fetchPaginatedProjectChangesCalled_THEN_returnPaginatedProjectChanges() {
ProjectId projectId = new ProjectId("testProjectId");
OWLEntity mockEntity = mock(OWLEntity.class);
IRI mockIri = IRI.create("http://example.com/entity");
when(mockEntity.getIRI()).thenReturn(mockIri);

RevisionsEvent mockRevisionsEvent = RevisionsEvent.create(projectId, mockIri.toString(), ChangeType.UPDATE_ENTITY,12345L, new Document());
RevisionsEvent mockRevisionsEvent = RevisionsEvent.create(projectId, mockIri.toString(), ChangeType.UPDATE_ENTITY, 12345L, new Document());
PageRequest pageRequest = PageRequest.of(0, 1, Sort.by(Sort.Direction.DESC, "timestamp"));
org.springframework.data.domain.Page<RevisionsEvent> mockPage = new PageImpl<>(List.of(mockRevisionsEvent), pageRequest, 1);

Expand All @@ -81,9 +91,8 @@ public void GIVEN_validProjectIdAndSubject_WHEN_fetchPaginatedProjectChangesCall

@Test
public void GIVEN_nullSubject_WHEN_fetchPaginatedProjectChangesCalled_THEN_returnPaginatedProjectChanges() {
ProjectId projectId = new ProjectId("testProjectId");

RevisionsEvent mockRevisionsEvent = RevisionsEvent.create(projectId, null, ChangeType.CREATE_ENTITY,12345L, new Document());
RevisionsEvent mockRevisionsEvent = RevisionsEvent.create(projectId, null, ChangeType.CREATE_ENTITY, 12345L, new Document());
PageRequest pageRequest = PageRequest.of(0, 1, Sort.by(Sort.Direction.DESC, "timestamp"));
org.springframework.data.domain.Page<RevisionsEvent> mockPage = new PageImpl<>(List.of(mockRevisionsEvent), pageRequest, 1);

Expand All @@ -104,7 +113,6 @@ public void GIVEN_nullSubject_WHEN_fetchPaginatedProjectChangesCalled_THEN_retur

@Test
public void GIVEN_noResults_WHEN_fetchPaginatedProjectChangesCalled_THEN_returnEmptyPage() {
ProjectId projectId = new ProjectId("testProjectId");

PageRequest pageRequest = PageRequest.of(0, 1, Sort.by(Sort.Direction.DESC, "timestamp"));
org.springframework.data.domain.Page<RevisionsEvent> mockPage = new PageImpl<>(List.of(), pageRequest, 0);
Expand All @@ -119,4 +127,60 @@ public void GIVEN_noResults_WHEN_fetchPaginatedProjectChangesCalled_THEN_returnE
verify(repository).findAll(any(Example.class), eq(pageRequest));
verifyNoInteractions(projectChangeMapper);
}

@Test
public void GIVEN_noEntitiesChangedAfterTimestamp_WHEN_getChangedEntitiesAfterTimestampCalled_THEN_emptyChangedEntitiesReturned() {
when(repository.findByProjectIdAndTimestampAfter(projectId.id(), timestamp.getTime())).thenReturn(List.of());

ChangedEntities result = service.getChangedEntitiesAfterTimestamp(projectId, timestamp);

assertEquals(0, result.createdEntities().size());
assertEquals(0, result.updatedEntities().size());
assertEquals(0, result.deletedEntities().size());

verify(repository).findByProjectIdAndTimestampAfter(projectId.id(), timestamp.getTime());
}

@Test
public void GIVEN_entitiesChangedAfterTimestamp_WHEN_getChangedEntitiesAfterTimestampCalled_THEN_returnGroupedChangedEntities() {
RevisionsEvent createdEntity = RevisionsEvent.create(projectId, "entityIRI1", ChangeType.CREATE_ENTITY, timestamp.getTime(), new Document());
RevisionsEvent updatedEntity = RevisionsEvent.create(projectId, "entityIRI2", ChangeType.UPDATE_ENTITY, timestamp.getTime() + 1000, new Document());
RevisionsEvent deletedEntity = RevisionsEvent.create(projectId, "entityIRI3", ChangeType.DELETE_ENTITY, timestamp.getTime() + 2000, new Document());

when(repository.findByProjectIdAndTimestampAfter(projectId.id(), timestamp.getTime())).thenReturn(List.of(createdEntity, updatedEntity, deletedEntity));

ChangedEntities result = service.getChangedEntitiesAfterTimestamp(projectId, timestamp);

assertEquals(1, result.createdEntities().size());
assertEquals("entityIRI1", result.createdEntities().get(0));

assertEquals(1, result.updatedEntities().size());
assertEquals("entityIRI2", result.updatedEntities().get(0));

assertEquals(1, result.deletedEntities().size());
assertEquals("entityIRI3", result.deletedEntities().get(0));

verify(repository).findByProjectIdAndTimestampAfter(projectId.id(), timestamp.getTime());
}

@Test
public void GIVEN_multipleEntitiesChangedAfterTimestamp_WHEN_getChangedEntitiesAfterTimestampCalled_THEN_returnDeduplicatedChangedEntities() {
RevisionsEvent createdEntity1 = RevisionsEvent.create(projectId, "entityIRI1", ChangeType.CREATE_ENTITY, timestamp.getTime(), new Document());
RevisionsEvent createdEntity2 = RevisionsEvent.create(projectId, "entityIRI1", ChangeType.CREATE_ENTITY, timestamp.getTime() + 1000, new Document());
RevisionsEvent updatedEntity = RevisionsEvent.create(projectId, "entityIRI2", ChangeType.UPDATE_ENTITY, timestamp.getTime() + 2000, new Document());

when(repository.findByProjectIdAndTimestampAfter(projectId.id(), timestamp.getTime())).thenReturn(List.of(createdEntity1, createdEntity2, updatedEntity));

ChangedEntities result = service.getChangedEntitiesAfterTimestamp(projectId, timestamp);

assertEquals(1, result.createdEntities().size());
assertEquals("entityIRI1", result.createdEntities().get(0));

assertEquals(1, result.updatedEntities().size());
assertEquals("entityIRI2", result.updatedEntities().get(0));

assertEquals(0, result.deletedEntities().size());

verify(repository).findByProjectIdAndTimestampAfter(projectId.id(), timestamp.getTime());
}
}

0 comments on commit 08bc11c

Please sign in to comment.