ACS-4029: Update a category name - PUT /categories/{categoryId} (#1621)

* ACS-4029: Update a category name - PUT /categories/{categoryId}
This commit is contained in:
krdabrowski
2022-12-16 12:36:06 +01:00
committed by GitHub
parent 60a04b0402
commit cea3e37dd5
14 changed files with 776 additions and 187 deletions

View File

@@ -36,12 +36,21 @@ import org.alfresco.service.Experimental;
@Experimental
public interface Categories
{
Category getCategoryById(String id, Parameters params);
Category getCategoryById(String id, Parameters parameters);
List<Category> createSubcategories(String parentCategoryId, List<Category> categories, Parameters parameters);
CollectionWithPagingInfo<Category> getCategoryChildren(String parentCategoryId, Parameters params);
CollectionWithPagingInfo<Category> getCategoryChildren(String parentCategoryId, Parameters parameters);
void deleteCategoryById(String id, Parameters params);
/**
* Update category by ID. Currently, it's possible only to update the name of category.
*
* @param id Category ID.
* @param fixedCategoryModel Fixed category model.
* @return Updated category.
*/
Category updateCategoryById(String id, Category fixedCategoryModel);
void deleteCategoryById(String id, Parameters parameters);
}

View File

@@ -42,7 +42,8 @@ import org.alfresco.rest.framework.resource.parameters.Parameters;
*/
@EntityResource(name = "categories", title = "Categories")
public class CategoriesEntityResource implements EntityResourceAction.ReadById<Category>,
EntityResourceAction.Delete
EntityResourceAction.Update<Category>,
EntityResourceAction.Delete
{
private final Categories categories;
@@ -51,20 +52,45 @@ public class CategoriesEntityResource implements EntityResourceAction.ReadById<C
this.categories = categories;
}
@WebApiDescription(title = "Get category by its id",
description = "Retrieves a category given category node id",
successStatus = HttpServletResponse.SC_OK)
/**
* GET /categories/{categoryId}
*/
@WebApiDescription(
title = "Get category by its ID",
description = "Retrieves a category given category node id",
successStatus = HttpServletResponse.SC_OK
)
@Override
public Category readById(String id, Parameters parameters) throws EntityNotFoundException
{
return categories.getCategoryById(id, parameters);
}
@WebApiDescription(title = "Delete category",
description = "Delete a category given its node id",
successStatus = HttpServletResponse.SC_NO_CONTENT)
/**
* PUT /categories/{categoryId}
*/
@WebApiDescription(
title = "Update category",
description = "Update a single category by its ID",
successStatus = HttpServletResponse.SC_OK
)
@Override
public void delete(String id, Parameters parameters) {
public Category update(String id, Category categoryModel, Parameters parameters)
{
return categories.updateCategoryById(id, categoryModel);
}
/**
* DELETE /categories/{categoryId}
*/
@WebApiDescription(
title = "Delete category",
description = "Delete a category given its node ID",
successStatus = HttpServletResponse.SC_NO_CONTENT
)
@Override
public void delete(String id, Parameters parameters)
{
categories.deleteCategoryById(id, parameters);
}
}

View File

@@ -39,7 +39,8 @@ import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
@RelationshipResource(name = "subcategories", entityResource = CategoriesEntityResource.class, title = "Subcategories")
public class SubcategoriesRelation implements RelationshipResourceAction.Create<Category>, RelationshipResourceAction.Read<Category>
public class SubcategoriesRelation implements RelationshipResourceAction.Create<Category>,
RelationshipResourceAction.Read<Category>
{
private final Categories categories;
@@ -49,6 +50,9 @@ public class SubcategoriesRelation implements RelationshipResourceAction.Create<
this.categories = categories;
}
/**
* POST /categories/{categoryId}/subcategories
*/
@WebApiDescription(title = "Create a category",
description = "Creates one or more categories under a parent category",
successStatus = HttpServletResponse.SC_CREATED)
@@ -58,6 +62,9 @@ public class SubcategoriesRelation implements RelationshipResourceAction.Create<
return categories.createSubcategories(parentCategoryId, categoryList, parameters);
}
/**
* GET /categories/{categoryId}/subcategories
*/
@WebApiDescription(title = "List category direct children",
description = "Lists direct children of a parent category",
successStatus = HttpServletResponse.SC_OK)

View File

@@ -49,6 +49,7 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -57,9 +58,9 @@ import org.apache.commons.lang3.StringUtils;
public class CategoriesImpl implements Categories
{
static final String NOT_A_VALID_CATEGORY = "Node id does not refer to a valid category";
static final String NO_PERMISSION_TO_CREATE_A_CATEGORY = "Current user does not have permission to create a category";
static final String NO_PERMISSION_TO_DELETE_A_CATEGORY = "Current user does not have permission to delete a category";
private static final String NOT_NULL_OR_EMPTY = "Category name must not be null or empty";
static final String NO_PERMISSION_TO_MANAGE_A_CATEGORY = "Current user does not have permission to manage a category";
static final String NOT_NULL_OR_EMPTY = "Category name must not be null or empty";
static final String FIELD_NOT_MATCH = "Category field: %s does not match the original one";
private final AuthorityService authorityService;
private final CategoryService categoryService;
@@ -89,10 +90,7 @@ public class CategoriesImpl implements Categories
@Override
public List<Category> createSubcategories(String parentCategoryId, List<Category> categories, Parameters parameters)
{
if (!authorityService.hasAdminAuthority())
{
throw new PermissionDeniedException(NO_PERMISSION_TO_CREATE_A_CATEGORY);
}
verifyAdminAuthority();
final NodeRef parentNodeRef = getCategoryNodeRef(parentCategoryId);
final List<NodeRef> categoryNodeRefs = categories.stream()
.map(c -> createCategoryNodeRef(parentNodeRef, c))
@@ -116,15 +114,26 @@ public class CategoriesImpl implements Categories
}
@Override
public void deleteCategoryById(String id, Parameters params)
public Category updateCategoryById(final String id, final Category fixedCategoryModel)
{
if (!authorityService.hasAdminAuthority())
verifyAdminAuthority();
final NodeRef categoryNodeRef = getCategoryNodeRef(id);
if (isRootCategory(categoryNodeRef))
{
throw new PermissionDeniedException(NO_PERMISSION_TO_DELETE_A_CATEGORY);
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{id});
}
final NodeRef nodeRef = nodes.validateNode(id);
if (isNotACategory(nodeRef) || isRootCategory(nodeRef))
verifyCategoryFields(fixedCategoryModel);
return mapToCategory(changeCategoryName(categoryNodeRef, fixedCategoryModel.getName()));
}
@Override
public void deleteCategoryById(String id, Parameters parameters)
{
verifyAdminAuthority();
final NodeRef nodeRef = getCategoryNodeRef(id);
if (isRootCategory(nodeRef))
{
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{id});
}
@@ -132,6 +141,14 @@ public class CategoriesImpl implements Categories
nodeService.deleteNode(nodeRef);
}
private void verifyAdminAuthority()
{
if (!authorityService.hasAdminAuthority())
{
throw new PermissionDeniedException(NO_PERMISSION_TO_MANAGE_A_CATEGORY);
}
}
/**
* This method gets category NodeRef for a given category id.
* If '-root-' is passed as category id, then it's retrieved as a call to {@link org.alfresco.service.cmr.search.CategoryService#getRootCategoryNodeRef}
@@ -164,17 +181,10 @@ public class CategoriesImpl implements Categories
private NodeRef createCategoryNodeRef(NodeRef parentNodeRef, Category c)
{
if (StringUtils.isEmpty(c.getName())) {
throw new InvalidArgumentException(NOT_NULL_OR_EMPTY);
}
verifyCategoryFields(c);
return categoryService.createCategory(parentNodeRef, c.getName());
}
private boolean isNotACategory(NodeRef nodeRef)
{
return !nodes.isSubClass(nodeRef, ContentModel.TYPE_CATEGORY, false);
}
private Category mapToCategory(NodeRef nodeRef)
{
final Node categoryNode = nodes.getNode(nodeRef.getId());
@@ -188,6 +198,11 @@ public class CategoriesImpl implements Categories
.create();
}
private boolean isNotACategory(NodeRef nodeRef)
{
return !nodes.isSubClass(nodeRef, ContentModel.TYPE_CATEGORY, false);
}
private boolean isRootCategory(final NodeRef nodeRef)
{
final List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(nodeRef);
@@ -199,4 +214,37 @@ public class CategoriesImpl implements Categories
final NodeRef parentRef = nodeService.getPrimaryParent(nodeRef).getParentRef();
return isRootCategory(parentRef) ? PATH_ROOT : parentRef.getId();
}
/**
* Change category qualified name.
*
* @param categoryNodeRef Category node reference.
* @param newName New name.
* @return Updated category.
*/
private NodeRef changeCategoryName(final NodeRef categoryNodeRef, final String newName)
{
final ChildAssociationRef parentAssociation = nodeService.getPrimaryParent(categoryNodeRef);
if (parentAssociation == null)
{
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{categoryNodeRef.getId()});
}
nodeService.setProperty(categoryNodeRef, ContentModel.PROP_NAME, newName);
final QName newQName = QName.createQName(parentAssociation.getQName().getNamespaceURI(), QName.createValidLocalName(newName));
return nodeService.moveNode(parentAssociation.getChildRef(), parentAssociation.getParentRef(), parentAssociation.getTypeQName(), newQName).getChildRef();
}
/**
* Verify if fixed category name is not empty.
*
* @param fixedCategoryModel Fixed category model.
*/
private void verifyCategoryFields(final Category fixedCategoryModel)
{
if (StringUtils.isEmpty(fixedCategoryModel.getName()))
{
throw new InvalidArgumentException(NOT_NULL_OR_EMPTY);
}
}
}

View File

@@ -137,5 +137,4 @@ public class Category
return category;
}
}
}

View File

@@ -26,7 +26,9 @@
package org.alfresco.rest.api.categories;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
@@ -65,4 +67,17 @@ public class CategoriesEntityResourceTest
then(categoriesMock).shouldHaveNoMoreInteractions();
assertEquals(categoryMock, category);
}
@Test
public void testUpdateCategoryById()
{
given(categoriesMock.updateCategoryById(any(), any())).willReturn(categoryMock);
// when
final Category actualCategory = objectUnderTest.update(CATEGORY_ID, categoryMock, parametersMock);
then(categoriesMock).should().updateCategoryById(CATEGORY_ID, categoryMock);
then(categoriesMock).shouldHaveNoMoreInteractions();
assertThat(actualCategory).isNotNull();
}
}

View File

@@ -27,8 +27,15 @@
package org.alfresco.rest.api.impl;
import static org.alfresco.rest.api.Nodes.PATH_ROOT;
import static org.alfresco.rest.api.impl.CategoriesImpl.NOT_A_VALID_CATEGORY;
import static org.alfresco.rest.api.impl.CategoriesImpl.NOT_NULL_OR_EMPTY;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
@@ -56,7 +63,9 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -70,6 +79,8 @@ public class CategoriesImplTest
private static final String CATEGORY_NAME = "categoryName";
private static final String PARENT_ID = "parent-node-id";
private static final String CAT_ROOT_NODE_ID = "cat-root-node-id";
private static final NodeRef CATEGORY_NODE_REF = createNodeRefWithId(CATEGORY_ID);
private static final Category CATEGORY = createDefaultCategoryWithName(CATEGORY_NAME);
@Mock
private Nodes nodesMock;
@@ -89,12 +100,19 @@ public class CategoriesImplTest
@InjectMocks
private CategoriesImpl objectUnderTest;
@Before
public void setUp() throws Exception
{
given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
given(nodesMock.validateNode(eq(CATEGORY_ID))).willReturn(CATEGORY_NODE_REF);
given(nodesMock.isSubClass(any(), any(), anyBoolean())).willReturn(true);
}
@Test
public void shouldNotGetRootCategoryById()
{
final NodeRef categoryRootNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CAT_ROOT_NODE_ID);
given(nodesMock.validateNode(CAT_ROOT_NODE_ID)).willReturn(categoryRootNodeRef);
given(nodesMock.isSubClass(categoryRootNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
given(categoryChildAssociationRefMock.getQName()).willReturn(ContentModel.ASPECT_GEN_CLASSIFIABLE);
given(nodeServiceMock.getParentAssocs(categoryRootNodeRef)).willReturn(List.of(categoryChildAssociationRefMock));
@@ -107,7 +125,7 @@ public class CategoriesImplTest
then(nodeServiceMock).should().getParentAssocs(categoryRootNodeRef);
then(nodeServiceMock).shouldHaveNoMoreInteractions();
then(categoryServiceMock).shouldHaveNoInteractions();
then(authorityServiceMock).shouldHaveNoMoreInteractions();
then(authorityServiceMock).shouldHaveNoInteractions();
}
@Test
@@ -115,7 +133,6 @@ public class CategoriesImplTest
{
final NodeRef categoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
given(nodesMock.validateNode(CATEGORY_ID)).willReturn(categoryNodeRef);
given(nodesMock.isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
final Node categoryNode = new Node();
categoryNode.setName(CATEGORY_NAME);
categoryNode.setNodeId(CATEGORY_ID);
@@ -158,7 +175,6 @@ public class CategoriesImplTest
{
final NodeRef categoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
given(nodesMock.validateNode(CATEGORY_ID)).willReturn(categoryNodeRef);
given(nodesMock.isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
final Node categoryNode = new Node();
categoryNode.setName(CATEGORY_NAME);
categoryNode.setNodeId(CATEGORY_ID);
@@ -319,11 +335,10 @@ public class CategoriesImplTest
@Test
public void testCreateCategoryUnderRoot()
{
given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PATH_ROOT);
given(categoryServiceMock.getRootCategoryNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE))
.willReturn(Optional.of(parentCategoryNodeRef));
final NodeRef categoryNodeRef = prepareCategoryNodeRef();
final NodeRef categoryNodeRef = createNodeRefWithId(CATEGORY_ID);
given(categoryServiceMock.createCategory(parentCategoryNodeRef, CATEGORY_NAME)).willReturn(categoryNodeRef);
given(nodesMock.getNode(CATEGORY_ID)).willReturn(prepareCategoryNode());
final ChildAssociationRef parentAssoc = new ChildAssociationRef(null, parentCategoryNodeRef, null, categoryNodeRef);
@@ -361,11 +376,9 @@ public class CategoriesImplTest
@Test
public void testCreateCategory()
{
given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
final NodeRef categoryNodeRef = prepareCategoryNodeRef();
final NodeRef categoryNodeRef = createNodeRefWithId(CATEGORY_ID);
given(categoryServiceMock.createCategory(parentCategoryNodeRef, CATEGORY_NAME)).willReturn(categoryNodeRef);
given(nodesMock.getNode(CATEGORY_ID)).willReturn(prepareCategoryNode());
final ChildAssociationRef parentAssoc = new ChildAssociationRef(null, parentCategoryNodeRef, null, categoryNodeRef);
@@ -420,7 +433,6 @@ public class CategoriesImplTest
@Test
public void testCreateCategories_wrongParentNodeType()
{
given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(false);
@@ -441,7 +453,6 @@ public class CategoriesImplTest
@Test
public void testCreateCategories_nonExistingParentNode()
{
given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
given(nodesMock.validateNode(PARENT_ID)).willThrow(EntityNotFoundException.class);
//when
@@ -590,10 +601,177 @@ public class CategoriesImplTest
then(authorityServiceMock).shouldHaveNoInteractions();
}
private Node prepareCategoryNode()
@Test
public void testUpdateCategoryById()
{
final NodeRef parentNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
return prepareCategoryNode(CATEGORY_NAME, CATEGORY_ID, parentNodeRef);
final String categoryNewName = "categoryNewName";
final Category fixedCategory = createCategoryOnlyWithName(categoryNewName);
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
given(nodesMock.getNode(any())).willReturn(prepareCategoryNode(categoryNewName));
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
// when
final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, fixedCategory);
then(authorityServiceMock).should().hasAdminAuthority();
then(authorityServiceMock).shouldHaveNoMoreInteractions();
then(nodesMock).should().validateNode(CATEGORY_ID);
then(nodesMock).should().isSubClass(CATEGORY_NODE_REF, ContentModel.TYPE_CATEGORY, false);
then(nodesMock).should().getNode(CATEGORY_ID);
then(nodesMock).shouldHaveNoMoreInteractions();
then(nodeServiceMock).should().getParentAssocs(CATEGORY_NODE_REF);
then(nodeServiceMock).should().getChildAssocs(CATEGORY_NODE_REF, RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false);
then(nodeServiceMock).should().setProperty(CATEGORY_NODE_REF, ContentModel.PROP_NAME, categoryNewName);
then(nodeServiceMock).should(times(2)).getPrimaryParent(CATEGORY_NODE_REF);
final QName expectedNewQName = createCmQNameOf(categoryNewName);
then(nodeServiceMock).should().moveNode(CATEGORY_NODE_REF, parentCategoryNodeRef, ContentModel.ASSOC_SUBCATEGORIES, expectedNewQName);
then(nodeServiceMock).should().getParentAssocs(parentCategoryNodeRef);
then(nodeServiceMock).shouldHaveNoMoreInteractions();
then(categoryServiceMock).shouldHaveNoInteractions();
final Category expectedCategory = createDefaultCategoryWithName(categoryNewName);
assertThat(actualCategory)
.isNotNull().usingRecursiveComparison()
.isEqualTo(expectedCategory);
}
@Test
public void testUpdateCategoryById_noPermission()
{
given(authorityServiceMock.hasAdminAuthority()).willReturn(false);
// when
assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(CATEGORY_ID, CATEGORY));
then(nodesMock).shouldHaveNoInteractions();
then(nodeServiceMock).shouldHaveNoInteractions();
}
@Test
public void testUpdateCategoryById_categoryNodeNotFound()
{
given(nodesMock.validateNode(any(String.class))).willThrow(EntityNotFoundException.class);
// when
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(CATEGORY_ID, CATEGORY));
then(nodeServiceMock).shouldHaveNoInteractions();
}
@Test
public void testUpdateCategoryById_notACategory()
{
given(nodesMock.isSubClass(any(), any(), eq(false))).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(CATEGORY_ID, CATEGORY))
.withMessageContaining(NOT_A_VALID_CATEGORY);
then(nodeServiceMock).shouldHaveNoInteractions();
}
@Test
public void testUpdateCategoryById_isRootCategory()
{
given(categoryServiceMock.getRootCategoryNodeRef(any())).willReturn(Optional.of(createNodeRefWithId(PATH_ROOT)));
given(nodeServiceMock.getParentAssocs(any())).willReturn(List.of(categoryChildAssociationRefMock));
given(categoryChildAssociationRefMock.getQName()).willReturn(ContentModel.ASPECT_GEN_CLASSIFIABLE);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(PATH_ROOT, CATEGORY))
.withMessageContaining(NOT_A_VALID_CATEGORY);
then(categoryServiceMock).should().getRootCategoryNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
then(categoryServiceMock).shouldHaveNoMoreInteractions();
}
private List<String> getInvalidCategoryNames()
{
final List<String> invalidNames = new ArrayList<>();
invalidNames.add(null);
invalidNames.add("");
return invalidNames;
}
@Test
public void testUpdateCategoryById_emptyName()
{
for (String invalidName : getInvalidCategoryNames())
{
final Category categoryWithoutName = createCategoryOnlyWithName(invalidName);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(CATEGORY_ID, categoryWithoutName))
.withMessageContaining(NOT_NULL_OR_EMPTY);
}
}
@Test
public void testUpdateCategoryById_notMatchingIdField()
{
final String categoryNewName = "categoryNewName";
final Category categoryWithInvalidId = createCategoryOnlyWithName(categoryNewName);
categoryWithInvalidId.setId("different-" + CATEGORY_ID);
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
given(nodesMock.getNode(any())).willReturn(prepareCategoryNode(categoryNewName));
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
// when
final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, categoryWithInvalidId);
final Category expectedCategory = createDefaultCategoryWithName(categoryNewName);
assertThat(actualCategory)
.isNotNull().usingRecursiveComparison()
.isEqualTo(expectedCategory);
}
@Test
public void testUpdateCategoryById_notMatchingParentIdField()
{
final String categoryNewName = "categoryNewName";
final Category categoryWithInvalidParentId = createCategoryOnlyWithName(categoryNewName);
categoryWithInvalidParentId.setParentId("different-" + PARENT_ID);
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
given(nodesMock.getNode(any())).willReturn(prepareCategoryNode(categoryNewName));
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
// when
final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, categoryWithInvalidParentId);
final Category expectedCategory = createDefaultCategoryWithName(categoryNewName);
assertThat(actualCategory)
.isNotNull().usingRecursiveComparison()
.isEqualTo(expectedCategory);
}
@Test
public void testUpdateCategoryById_notMatchingHasChildrenField()
{
final String categoryNewName = "categoryNewName";
final Category categoryWithInvalidHasChildren = createCategoryOnlyWithName(categoryNewName);
categoryWithInvalidHasChildren.setHasChildren(true);
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
given(nodesMock.getNode(any())).willReturn(prepareCategoryNode(categoryNewName));
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
// when
final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, categoryWithInvalidHasChildren);
final Category expectedCategory = createDefaultCategoryWithName(categoryNewName);
assertThat(actualCategory)
.isNotNull().usingRecursiveComparison()
.isEqualTo(expectedCategory);
}
private Node prepareCategoryNode(final String name, final String id, final NodeRef parentNodeRef)
@@ -605,9 +783,15 @@ public class CategoriesImplTest
return categoryNode;
}
private NodeRef prepareCategoryNodeRef()
private Node prepareCategoryNode(final String name)
{
return new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
final NodeRef parentNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
return prepareCategoryNode(name, CATEGORY_ID, parentNodeRef);
}
private Node prepareCategoryNode()
{
return prepareCategoryNode(CATEGORY_NAME);
}
private List<Category> prepareCategories()
@@ -626,8 +810,7 @@ public class CategoriesImplTest
.willReturn(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID + "-" + i));
given(dummyChildAssocMock.getParentRef()).willReturn(parentCategoryNodeRef);
return dummyChildAssocMock;
})
.collect(Collectors.toList());
}).collect(Collectors.toList());
}
private void prepareCategoryNodeMocks(ChildAssociationRef childAssociationRef)
@@ -652,4 +835,34 @@ public class CategoriesImplTest
.create();
assertEquals(expectedCategory, category);
}
private static NodeRef createNodeRefWithId(final String id)
{
return new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id);
}
private static Category createCategoryOnlyWithName(final String name)
{
return Category.builder().name(name).create();
}
private static Category createDefaultCategoryWithName(final String name)
{
return Category.builder()
.id(CATEGORY_ID)
.name(name)
.parentId(PARENT_ID)
.hasChildren(false)
.create();
}
private static QName createCmQNameOf(final String name)
{
return QName.createQName(ContentModel.TYPE_CATEGORY.getNamespaceURI(), QName.createValidLocalName(name));
}
private static ChildAssociationRef createAssociationOf(final NodeRef parentNode, final NodeRef childNode, final QName childNodeName)
{
return new ChildAssociationRef(ContentModel.ASSOC_SUBCATEGORIES, parentNode, childNodeName, childNode);
}
}