[TLC-674] Duplicate detection integration tests

One workflow REST IT test still failing even though
the same test in dspace-api service passes...
This commit is contained in:
Kim Shepherd
2024-01-17 17:29:42 +13:00
parent 554338b29d
commit 4e3e68fe56
3 changed files with 209 additions and 64 deletions

View File

@@ -21,6 +21,7 @@ import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.service.DuplicateDetectionService;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataValueService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.content.virtual.PotentialDuplicate;
import org.dspace.core.Constants;
import org.dspace.core.Context;
@@ -38,6 +39,8 @@ import org.dspace.services.ConfigurationService;
import org.dspace.versioning.VersionHistory;
import org.dspace.versioning.service.VersionHistoryService;
import org.dspace.workflow.WorkflowItem;
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
import org.springframework.beans.factory.annotation.Autowired;
/**
@@ -60,6 +63,10 @@ public class DuplicateDetectionServiceImpl implements DuplicateDetectionService
MetadataFieldService metadataFieldService;
@Autowired
MetadataValueService metadataValueService;
@Autowired
XmlWorkflowItemService workflowItemService;
@Autowired
WorkspaceItemService workspaceItemService;
/**
* Get a list of PotentialDuplicate objects (wrappers with some metadata included for previewing) that
@@ -137,6 +144,7 @@ public class DuplicateDetectionServiceImpl implements DuplicateDetectionService
// what submission / archived state it is in
if (indexableObject instanceof IndexableWorkspaceItem) {
workspaceItem = ((IndexableWorkspaceItem) indexableObject).getIndexedObject();
log.info("ITS A WORKSPACE ITEM ITS A WORKSPACE ITEM " + workspaceItem.getItem().getName());
// Only process workspace items that belong to the submitter
if (workspaceItem != null && workspaceItem.getSubmitter() != null
&& workspaceItem.getSubmitter().equals(context.getCurrentUser())) {
@@ -144,14 +152,18 @@ public class DuplicateDetectionServiceImpl implements DuplicateDetectionService
}
}
if (indexableObject instanceof IndexableWorkflowItem) {
log.info("ITS A WORKFLOW ITEM ITS A WORKFLOW ITEM");
workflowItem = ((IndexableWorkflowItem) indexableObject).getIndexedObject();
log.info("ITS A WORKFLOW ITEM ITS A WORKFLOW ITEM " + workflowItem.getItem().getName());
if (workflowItem != null) {
resultItem = workflowItem.getItem();
}
}
if (indexableObject instanceof IndexableItem) {
resultItem = ((IndexableItem) indexableObject).getIndexedObject();
log.info("NORMAL ITEM FOUND " + resultItem.getName());
// Attempt resolution of workflow or workspace items, tested later
workflowItem = workflowItemService.findByItem(context, resultItem);
workspaceItem = workspaceItemService.findByItem(context, resultItem);
}
// Result item must not be null, a template item, or actually identical to the original
@@ -224,6 +236,8 @@ public class DuplicateDetectionServiceImpl implements DuplicateDetectionService
} else if (authorizeService.isAdmin(context, resultItem)) {
// Admins can always read, return immediately
return Optional.of(potentialDuplicate);
} else {
log.error("No valid permission to return this item");
}
// By default, return an empty result

View File

@@ -16,19 +16,31 @@ import org.dspace.AbstractIntegrationTestWithDatabase;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.builder.WorkflowItemBuilder;
import org.dspace.builder.WorkspaceItemBuilder;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.DuplicateDetectionService;
import org.dspace.content.virtual.PotentialDuplicate;
import org.dspace.discovery.IndexingService;
import org.dspace.discovery.SearchService;
import org.dspace.discovery.SearchUtils;
import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.discovery.indexobject.IndexableWorkflowItem;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.GroupService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.workflow.factory.WorkflowServiceFactory;
import org.dspace.xmlworkflow.factory.XmlWorkflowFactory;
import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory;
import org.dspace.xmlworkflow.service.XmlWorkflowService;
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import scala.concurrent.impl.FutureConvertersImpl;
import static java.lang.Thread.sleep;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNull;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -45,7 +57,10 @@ public class DuplicateDetectionTest extends AbstractIntegrationTestWithDatabase
private SearchService searchService = SearchUtils.getSearchService();
private DuplicateDetectionService duplicateDetectionService = ContentServiceFactory.getInstance().getDuplicateDetectionService();
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
private XmlWorkflowService workflowService = XmlWorkflowServiceFactory.getInstance().getXmlWorkflowService();
private IndexingService indexingService = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("org.dspace.discovery.IndexingService", org.dspace.discovery.IndexingService.class);
private Collection col;
private Collection workflowCol;
private Item item1;
private Item item2;
private Item item3;
@@ -54,6 +69,7 @@ public class DuplicateDetectionTest extends AbstractIntegrationTestWithDatabase
private final String item1Title = "Public item I";
private final String item1Author = "Smith, Donald";
@Before
public void setUp() throws Exception {
super.setUp();
@@ -70,6 +86,8 @@ public class DuplicateDetectionTest extends AbstractIntegrationTestWithDatabase
parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build();
col = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection").build();
workflowCol = CollectionBuilder.createCollection(context, parentCommunity).withName("Workflow Collection")
.withWorkflowGroup("reviewer", admin).build();
// Ingest three example items with slightly different titles
// item2 is 1 edit distance from item1 and item3
@@ -93,7 +111,7 @@ public class DuplicateDetectionTest extends AbstractIntegrationTestWithDatabase
.withSubject("ExtraEntry 3")
.build();
context.setDispatcher("noindex");
//context.setDispatcher("noindex");
}
/**
@@ -191,4 +209,41 @@ public class DuplicateDetectionTest extends AbstractIntegrationTestWithDatabase
}
@Test
public void testSearchDuplicatesInWorkflow() throws Exception {
// Get potential duplicates of item 1:
// Expected: Public item II should appear as it has the configured levenshtein distance of 1
context.turnOffAuthorisationSystem();
WorkspaceItem workspaceItem = WorkspaceItemBuilder.createWorkspaceItem(context, workflowCol)
.withTitle("Unique title")
.withSubmitter(eperson)
.build();
WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, workflowCol)
.withTitle("Unique title")
.withSubmitter(eperson)
.build();
XmlWorkflowItem workflowItem1 = workflowService.start(context, workspaceItem);
XmlWorkflowItem workflowItem2 = workflowService.start(context, workspaceItem2);
// Force reindex of these workflow items, as test framework appears not to do this by default?
indexingService.reIndexContent(context, new IndexableItem(workflowItem1.getItem()));
indexingService.reIndexContent(context, new IndexableItem(workflowItem2.getItem()));
context.restoreAuthSystemState();
sleep(3600);
context.setCurrentUser(admin);
List<PotentialDuplicate> potentialDuplicates = duplicateDetectionService.getPotentialDuplicates(context, workflowItem1.getItem());
// Make sure result list is size 1
int size = 1;
assertEquals("Potential duplicates of item1 should have size " + size,
size, potentialDuplicates.size());
// The only member should be workflow item 2
assertEquals("Workflow item 2 should be be the detected duplicate",
workflowItem2.getItem().getID(), potentialDuplicates.get(0).getUuid());
}
}

View File

@@ -13,34 +13,40 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.ReplaceOperation;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.builder.WorkflowItemBuilder;
import org.dspace.builder.WorkspaceItemBuilder;
import org.dspace.content.Collection;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.WorkspaceItem;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.I18nUtil;
import org.dspace.discovery.IndexingService;
import org.dspace.discovery.indexobject.IndexableWorkflowItem;
import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.handle.service.HandleService;
import org.dspace.identifier.service.IdentifierService;
import org.dspace.services.ConfigurationService;
import org.dspace.xmlworkflow.service.XmlWorkflowService;
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static java.lang.Thread.sleep;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
@@ -65,11 +71,19 @@ public class DuplicateDetectionRestIT extends AbstractControllerIntegrationTest
CollectionService collectionService;
@Autowired
HandleService handleService;
@Autowired
WorkspaceItemService workspaceItemService;
@Autowired
XmlWorkflowItemService workflowItemService;
@Autowired
IdentifierService identifierService;
@Autowired
AuthorizeService authorizeService;
@Autowired
XmlWorkflowService workflowService;
private Collection col;
private Item item1;
private Item item2;
private Item item3;
private Collection simpleCol;
private final String item1IssueDate = "2011-10-17";
private final String item1Subject = "ExtraEntry 1";
private final String item1Title = "Public item I";
@@ -78,6 +92,8 @@ public class DuplicateDetectionRestIT extends AbstractControllerIntegrationTest
private final String item2IssueDate = "2012-10-17";
private EPerson anotherEPerson;
private static Logger log = LogManager.getLogger();
@Override
public void setUp() throws Exception {
super.setUp();
@@ -93,14 +109,16 @@ public class DuplicateDetectionRestIT extends AbstractControllerIntegrationTest
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build();
DSpaceObject dso = handleService.resolveToObject(context, "123456789/test-duplicate-detection");
if (dso == null) {
col = CollectionBuilder.createCollection(context, parentCommunity, "123456789/test-duplicate-detection")
.withWorkflowGroup("reviewer", admin)
.withName("Collection").build();
} else {
col = (Collection) dso;
}
col = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Test Collection")
.withWorkflowGroup(1, admin)
.build();
simpleCol = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Test Collection without Workflow")
.build();
eperson.setFirstName(context, "first");
eperson.setLastName(context, "last");
EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
anotherEPerson = ePersonService.findByEmail(context, "test-another-user@email.com");
if (anotherEPerson == null) {
@@ -114,39 +132,26 @@ public class DuplicateDetectionRestIT extends AbstractControllerIntegrationTest
// actually save the eperson to unit testing DB
ePersonService.update(context, anotherEPerson);
}
// Ingest three example items with slightly different titles
// item2 is 1 edit distance from item1 and item3
// item1 and item3 are 2 edit distance from each other
item1 = ItemBuilder.createItem(context, col)
.withTitle(item1Title) // Public item I
.withIssueDate(item1IssueDate)
.withAuthor(item1Author)
.withSubject(item1Subject)
.build();
item2 = ItemBuilder.createItem(context, col)
.withTitle("Public item II")
.withIssueDate(item2IssueDate)
.withAuthor("Smith, Donald X.")
.withSubject(item2Subject)
.build();
item3 = ItemBuilder.createItem(context, col)
.withTitle("Public item III")
.withIssueDate("2013-10-17")
.withAuthor("Smith, Donald Y.")
.withSubject("ExtraEntry 3")
.build();
context.dispatchEvents();
context.restoreAuthSystemState();
//context.setDispatcher("noindex");
context.restoreAuthSystemState();
}
@Test
public void itemsContainDuplicatesLinkTest() throws Exception {
String token = getAuthToken(admin.getEmail(), password);
log.error("EPERSON FULL NAME IS " + eperson.getFullName());
context.turnOffAuthorisationSystem();
WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, simpleCol)
.withTitle(item1Title)
.withSubject(item1Subject)
.withIssueDate(item1IssueDate)
.withAuthor(item1Author)
.withSubmitter(eperson)
.build();
XmlWorkflowItem wfi1 = workflowService.start(context, workspaceItem1);
Item item1 = wfi1.getItem();
context.restoreAuthSystemState();
getClient(token).perform(get("/api/core/items/" + item1.getID()))
.andExpect(status().isOk())
@@ -158,6 +163,41 @@ public class DuplicateDetectionRestIT extends AbstractControllerIntegrationTest
public void searchDuplicatesByLinkTest() throws Exception {
String token = getAuthToken(admin.getEmail(), password);
context.turnOffAuthorisationSystem();
// Ingest three example items with slightly different titles
// item2 is 1 edit distance from item1 and item3
// item1 and item3 are 2 edit distance from each other
WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, simpleCol)
.withTitle(item1Title)
.withSubject(item1Subject)
.withIssueDate(item1IssueDate)
.withAuthor(item1Author)
.withSubmitter(eperson)
.build();
WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, simpleCol)
.withTitle("Public item II")
.withIssueDate(item2IssueDate)
.withAuthor("Smith, Donald X.")
.withSubject(item2Subject)
.withSubmitter(eperson)
.build();
WorkspaceItem workspaceItem3 = WorkspaceItemBuilder.createWorkspaceItem(context, simpleCol)
.withTitle(item1Title)
.withTitle("Public item III")
.withIssueDate("2013-10-17")
.withAuthor("Smith, Donald Y.")
.withSubject("ExtraEntry 3")
.withSubmitter(eperson)
.build();
log.error("EPERSON FULL NAME IS " + eperson.getFullName());
XmlWorkflowItem wfi1 = workflowService.start(context, workspaceItem1);
XmlWorkflowItem wfi2 = workflowService.start(context, workspaceItem2);
Item item1 = wfi1.getItem();
Item item2 = wfi2.getItem();
context.restoreAuthSystemState();
getClient(token).perform(get("/api/core/items/" + item1.getID() + "/duplicates"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
@@ -184,9 +224,35 @@ public class DuplicateDetectionRestIT extends AbstractControllerIntegrationTest
public void submissionSectionDataTest() throws Exception {
// Test publication
context.turnOffAuthorisationSystem();
Collection workspaceCollection =
CollectionBuilder.createCollection(context, parentCommunity, "123456789/test-duplicate-detection")
.withName("Test Collection Workspace").build();
// Ingest three example items with slightly different titles
// item2 is 1 edit distance from item1 and item3
// item1 and item3 are 2 edit distance from each other
Item item1 = ItemBuilder.createItem(context, col)
.withTitle(item1Title) // Public item I
.withIssueDate(item1IssueDate)
.withAuthor(item1Author)
.withSubject(item1Subject)
.build();
Item item2 = ItemBuilder.createItem(context, col)
.withTitle("Public item II")
.withIssueDate(item2IssueDate)
.withAuthor("Smith, Donald X.")
.withSubject(item2Subject)
.build();
Item item3 = ItemBuilder.createItem(context, col)
.withTitle("Public item III")
.withIssueDate("2013-10-17")
.withAuthor("Smith, Donald Y.")
.withSubject("ExtraEntry 3")
.build();
// Create a new workspace item with a similar title to Item 1 (1 edit distance). Reuse other items
// metadata for the rest, as it is not relevant.
WorkspaceItem workspaceItem = WorkspaceItemBuilder.createWorkspaceItem(context, col)
WorkspaceItem workspaceItem = WorkspaceItemBuilder.createWorkspaceItem(context, workspaceCollection)
.withTitle("Public item X")
.withSubject(item2Subject)
.withIssueDate(item2IssueDate)
@@ -267,6 +333,11 @@ public class DuplicateDetectionRestIT extends AbstractControllerIntegrationTest
public void submissionSectionWorkspaceItemVisibilityTest() throws Exception {
// Test publication
context.turnOffAuthorisationSystem();
// Create a new collection with handle that maps to teh test-duplicate-detection submission config
col = CollectionBuilder.createCollection(context, parentCommunity, "123456789/test-duplicate-detection")
.withName("Test Collection with Duplicate Detection")
.withWorkflowGroup(1, admin)
.build();
// Create a new workspace item with a similar title to Item 1 (1 edit distance). Reuse other items
// metadata for the rest, as it is not relevant.
WorkspaceItem workspaceItem = WorkspaceItemBuilder.createWorkspaceItem(context, col)
@@ -316,44 +387,49 @@ public class DuplicateDetectionRestIT extends AbstractControllerIntegrationTest
*/
@Test
public void submissionSectionWorkflowItemVisibilityTest() throws Exception {
String reviewerToken = getAuthToken(admin.getEmail(), password);
context.turnOffAuthorisationSystem();
Item testItem = ItemBuilder.createItem(context, col)
.withTitle("Totally unique?") // Public item I
.withIssueDate(item1IssueDate)
.withAuthor(item1Author)
.withSubject(item1Subject)
.build();
// Create a new workspace item with a similar title to Item 1 (1 edit distance). Reuse other items
// metadata for the rest, as it is not relevant.
XmlWorkflowItem workflowItem1 = WorkflowItemBuilder.createWorkflowItem(context, col)
.withTitle("Totally unique!")
.withIssueDate("2017-10-17")
// Create a new collection with handle that maps to teh test-duplicate-detection submission config
parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build();
Collection workflowCol = CollectionBuilder.createCollection(context, parentCommunity)
.withName("Test Collection with Duplicate Detection")
.withWorkflowGroup("reviewer", admin)
.build();
//indexingService.indexContent(context, new IndexableWorkflowItem(workflowItem1));
context.dispatchEvents();
WorkspaceItem workspaceItem = WorkspaceItemBuilder.createWorkspaceItem(context, workflowCol)
.withTitle("Unique title")
.withSubmitter(eperson)
.build();
WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, workflowCol)
.withTitle("Unique title")
.withSubmitter(eperson)
.build();
XmlWorkflowItem workflowItem1 = workflowService.start(context, workspaceItem);
XmlWorkflowItem workflowItem2 = workflowService.start(context, workspaceItem2);
indexingService.reIndexContent(context, new IndexableItem(workflowItem1.getItem()));
indexingService.reIndexContent(context, new IndexableItem(workflowItem2.getItem()));
context.restoreAuthSystemState();
context.setCurrentUser(admin);
sleep(3600);
context.setCurrentUser(admin);
String reviewerToken = getAuthToken(admin.getEmail(), password);
// The reviewer should be able to see the workflow item as a potential duplicate of the test item
getClient(reviewerToken).perform(get("/api/core/items/" + testItem.getID() + "/duplicates"))
getClient(reviewerToken).perform(get("/api/core/items/" + workflowItem1.getItem().getID() + "/duplicates"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
// Valid duplicates array
.andExpect(jsonPath("$._embedded.duplicates", Matchers.hasSize(1)))
// UUID of only array member matches the new workflow item ID
.andExpect(jsonPath("$._embedded.duplicates[0].uuid").value(workflowItem1.getItem().getID().toString()));
.andExpect(jsonPath("$._embedded.duplicates[0].uuid").value(workflowItem2.getItem().getID().toString()));
// Another random user will NOT see this
getClient(getAuthToken(anotherEPerson.getEmail(), password))
.perform(get("/api/core/items/" + testItem.getID() + "/duplicates"))
.perform(get("/api/core/items/" + workflowItem1.getItem().getID() + "/duplicates"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
// Valid duplicates array
.andExpect(jsonPath("$._embedded.duplicates", Matchers.hasSize(0)));
}
}