From 780936e864c9ddd7bc990df1534efaf1f571a201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Ka=C5=88ka?= Date: Tue, 5 Nov 2024 12:58:40 +0100 Subject: [PATCH] [Enhancement kbss-cvut/termit-ui#520] Add tests for delete records and vocabulary content detailed history endpoint --- .../termit/persistence/dao/VocabularyDao.java | 2 +- .../persistence/dao/VocabularyDaoTest.java | 112 ++++++++++++++++++ .../changetracking/ChangeTrackingTest.java | 27 ++++- 3 files changed, 138 insertions(+), 3 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDao.java index 1e78b17d8..dba9ab1c3 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDao.java @@ -415,7 +415,7 @@ public List getDetailedHistoryOfContent(Vocabulary vocabul private TypedQuery createDetailedContentChangesQuery(Vocabulary vocabulary, VocabularyContentChangeFilterDto filter, Pageable pageReq) { TypedQuery query = em.createNativeQuery(""" - SELECT ?record WHERE { + SELECT DISTINCT ?record WHERE { GRAPH ?changeContext { ?record a ?changeRecord . } diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDaoTest.java index 23b72777c..af1d482d4 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDaoTest.java @@ -25,6 +25,7 @@ import cz.cvut.kbss.termit.dto.PrefixDeclaration; import cz.cvut.kbss.termit.dto.RdfsStatement; import cz.cvut.kbss.termit.dto.Snapshot; +import cz.cvut.kbss.termit.dto.filter.VocabularyContentChangeFilterDto; import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.event.AssetPersistEvent; @@ -37,13 +38,18 @@ import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.Vocabulary; import cz.cvut.kbss.termit.model.changetracking.AbstractChangeRecord; +import cz.cvut.kbss.termit.model.changetracking.DeleteChangeRecord; import cz.cvut.kbss.termit.model.changetracking.PersistChangeRecord; import cz.cvut.kbss.termit.model.changetracking.UpdateChangeRecord; import cz.cvut.kbss.termit.model.resource.Document; import cz.cvut.kbss.termit.model.resource.File; import cz.cvut.kbss.termit.model.util.EntityToOwlClassMapper; import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.dao.changetracking.ChangeRecordDao; +import cz.cvut.kbss.termit.persistence.dao.changetracking.ChangeTrackingContextResolver; +import cz.cvut.kbss.termit.util.Configuration; import cz.cvut.kbss.termit.util.Constants; +import cz.cvut.kbss.termit.util.Utils; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.vocabulary.RDF; @@ -59,6 +65,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.domain.Pageable; import org.springframework.test.annotation.DirtiesContext; import java.net.URI; @@ -108,6 +115,9 @@ class VocabularyDaoTest extends BaseDaoTestRunner { @Autowired private VocabularyDao sut; + @Autowired + private TermDao termDao; + private User author; @BeforeEach @@ -927,4 +937,106 @@ void getAnyExternalRelationsReturnsTermsWithBothRelations(URI termRelation) { } }); } + + @Test + void getDetailedHistoryOfContentReturnsRecordsForAllChangeTypes() { + enableRdfsInference(em); + final Configuration config = new Configuration(); + config.getChangetracking().getContext().setExtension("/zmeny"); + final ChangeTrackingContextResolver resolver = new ChangeTrackingContextResolver(em, config); + final ChangeRecordDao changeRecordDao = new ChangeRecordDao(resolver, em); + + final Vocabulary vocabulary = Generator.generateVocabularyWithId(); + final Term firstTerm = Generator.generateTermWithId(vocabulary.getUri()); + final Term termToRemove = Generator.generateTermWithId(vocabulary.getUri()); + + final List firstChanges = Generator.generateChangeRecords(firstTerm, author); + final List termToRemoveChanges = Generator.generateChangeRecords(termToRemove, author); + final DeleteChangeRecord deleteChangeRecord = new DeleteChangeRecord(); + deleteChangeRecord.setChangedEntity(termToRemove.getUri()); + deleteChangeRecord.setTimestamp(Utils.timestamp()); + deleteChangeRecord.setAuthor(author); + deleteChangeRecord.setLabel(termToRemove.getLabel()); + + transactional(() -> { + vocabulary.getGlossary().addRootTerm(firstTerm); + sut.persist(vocabulary); + Environment.addRelation(vocabulary.getUri(), URI.create(cz.cvut.kbss.termit.util.Vocabulary.s_p_ma_glosar), vocabulary.getGlossary().getUri(), em); + + termDao.persist(firstTerm, vocabulary); + termDao.persist(termToRemove, vocabulary); + + firstChanges.forEach(r -> changeRecordDao.persist(r, firstTerm)); + termToRemoveChanges.forEach(r -> changeRecordDao.persist(r, termToRemove)); + changeRecordDao.persist(deleteChangeRecord, termToRemove); + }); + + final VocabularyContentChangeFilterDto filter = new VocabularyContentChangeFilterDto(); + final int recordsCount = firstChanges.size() + termToRemoveChanges.size() + 1; + final Pageable pageable = Pageable.ofSize(recordsCount * 3); + final List contentChanges = sut.getDetailedHistoryOfContent(vocabulary, filter, pageable); + + assertEquals(recordsCount, contentChanges.size()); + final long persistCount = contentChanges.stream().filter(ch -> ch instanceof PersistChangeRecord).count(); + final long updatesCount = contentChanges.stream().filter(ch -> ch instanceof UpdateChangeRecord).count(); + final long deleteCount = contentChanges.stream().filter(ch -> ch instanceof DeleteChangeRecord).count(); + assertEquals(2, persistCount); + assertEquals(recordsCount - 3, updatesCount); + assertEquals(1, deleteCount); + } + + @Test + void getDetailedHistoryOfContentReturnsRecordsOfExistingTermFilteredByTermName() { + enableRdfsInference(em); + final Configuration config = new Configuration(); + config.getChangetracking().getContext().setExtension("/zmeny"); + final ChangeTrackingContextResolver resolver = new ChangeTrackingContextResolver(em, config); + final ChangeRecordDao changeRecordDao = new ChangeRecordDao(resolver, em); + + final String needle = "needle"; + final String haystack = "A label that contains needle somewhere"; + final String mud = "The n3edle is not here"; + + final Vocabulary vocabulary = Generator.generateVocabularyWithId(); + final Term firstTerm = Generator.generateTermWithId(vocabulary.getUri()); + firstTerm.setLabel(MultilingualString.create(haystack, null)); + final Term termToRemove = Generator.generateTermWithId(vocabulary.getUri()); + termToRemove.getLabel().set(mud); + + final List firstChanges = Generator.generateChangeRecords(firstTerm, author); + final List termToRemoveChanges = Generator.generateChangeRecords(termToRemove, author); + final DeleteChangeRecord deleteChangeRecord = new DeleteChangeRecord(); + deleteChangeRecord.setChangedEntity(termToRemove.getUri()); + deleteChangeRecord.setTimestamp(Utils.timestamp()); + deleteChangeRecord.setAuthor(author); + deleteChangeRecord.setLabel(termToRemove.getLabel()); + + transactional(() -> { + vocabulary.getGlossary().addRootTerm(firstTerm); + sut.persist(vocabulary); + Environment.addRelation(vocabulary.getUri(), URI.create(cz.cvut.kbss.termit.util.Vocabulary.s_p_ma_glosar), vocabulary.getGlossary().getUri(), em); + + termDao.persist(firstTerm, vocabulary); + termDao.persist(termToRemove, vocabulary); + + firstChanges.forEach(r -> changeRecordDao.persist(r, firstTerm)); + termToRemoveChanges.forEach(r -> changeRecordDao.persist(r, termToRemove)); + changeRecordDao.persist(deleteChangeRecord, termToRemove); + }); + + final VocabularyContentChangeFilterDto filter = new VocabularyContentChangeFilterDto(); + filter.setTermName(needle); + + final int recordsCount = termToRemoveChanges.size() + 1; + final Pageable pageable = Pageable.ofSize(recordsCount * 2); // page bigger than number of records + final List contentChanges = sut.getDetailedHistoryOfContent(vocabulary, filter, pageable); + + assertEquals(recordsCount, contentChanges.size()); + final long persistCount = contentChanges.stream().filter(ch -> ch instanceof PersistChangeRecord).count(); + final long updatesCount = contentChanges.stream().filter(ch -> ch instanceof UpdateChangeRecord).count(); + final long deleteCount = contentChanges.stream().filter(ch -> ch instanceof DeleteChangeRecord).count(); + assertEquals(1, persistCount); + assertEquals(recordsCount - 2, updatesCount); + assertEquals(1, deleteCount); + } } diff --git a/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackingTest.java b/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackingTest.java index 05069c385..d570a1f85 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackingTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackingTest.java @@ -27,6 +27,7 @@ import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.Vocabulary; import cz.cvut.kbss.termit.model.changetracking.AbstractChangeRecord; +import cz.cvut.kbss.termit.model.changetracking.DeleteChangeRecord; import cz.cvut.kbss.termit.model.changetracking.PersistChangeRecord; import cz.cvut.kbss.termit.model.changetracking.UpdateChangeRecord; import cz.cvut.kbss.termit.model.resource.File; @@ -52,6 +53,8 @@ import static org.hamcrest.Matchers.nullValue; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class ChangeTrackingTest extends BaseServiceTestRunner { @@ -141,7 +144,7 @@ void updatingVocabularyReferenceAndLiteralAttributesCreatesTwoUpdateRecords() { assertEquals(vocabulary.getUri(), chr.getChangedEntity()); assertThat(result.get(0), instanceOf(UpdateChangeRecord.class)); assertThat(((UpdateChangeRecord) chr).getChangedAttribute().toString(), anyOf(equalTo(DC.Terms.TITLE), - equalTo(cz.cvut.kbss.termit.util.Vocabulary.s_p_importuje_slovnik))); + equalTo(cz.cvut.kbss.termit.util.Vocabulary.s_p_importuje_slovnik))); }); } @@ -214,7 +217,7 @@ void updatingTermLiteralAttributesCreatesChangeRecordWithOriginalAndNewValue() { final List result = changeRecordDao.findAll(term); assertEquals(1, result.size()); assertEquals(Collections.singleton(originalDefinition), - ((UpdateChangeRecord) result.get(0)).getOriginalValue()); + ((UpdateChangeRecord) result.get(0)).getOriginalValue()); assertEquals(Collections.singleton(newDefinition), ((UpdateChangeRecord) result.get(0)).getNewValue()); } @@ -271,4 +274,24 @@ void updatingTermStateCreatesUpdateChangeRecord() { assertEquals(URI.create(cz.cvut.kbss.termit.util.Vocabulary.s_p_ma_stav_pojmu), ((UpdateChangeRecord) result.get(0)).getChangedAttribute()); } + + @Test + void deletingTermCreatesDeleteChangeRecord() { + enableRdfsInference(em); + final Term term = Generator.generateTermWithId(vocabulary.getUri()); + transactional(()-> { + em.persist(vocabulary, descriptorFactory.vocabularyDescriptor(vocabulary)); + term.setGlossary(vocabulary.getGlossary().getUri()); + em.persist(term, descriptorFactory.termDescriptor(vocabulary)); + Generator.addTermInVocabularyRelationship(term, vocabulary.getUri(), em); + }); + + termService.remove(term); + final List result = changeRecordDao.findAll(term); + assertEquals(1, result.size()); + final DeleteChangeRecord record = assertInstanceOf(DeleteChangeRecord.class, result.get(0)); + assertEquals(term.getUri(), record.getChangedEntity()); + assertNotNull(record.getLabel()); + assertEquals(term.getLabel(), record.getLabel()); + } }