Add validator duplicate IO name 75/59175/4
authoravigaffa <avi.gaffa@amdocs.com>
Mon, 6 Aug 2018 11:20:02 +0000 (14:20 +0300)
committerAvi Gaffa <avi.gaffa@amdocs.com>
Tue, 7 Aug 2018 13:28:52 +0000 (13:28 +0000)
fixes comments of patch set 1

Change-Id: I44bbbfd8f992871880f2efe26c08393879fcff77
Issue-ID: SDC-1518
Signed-off-by: avigaffa <avi.gaffa@amdocs.com>
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/WorkflowVersionController.java
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/exceptionshandlers/CustomizedResponseEntityExceptionHandler.java
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/WorkflowVersionValidator.java [deleted file]
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/validation/NoDuplicates.java [new file with mode: 0644]
workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/validation/NoDuplicatesValidator.java [new file with mode: 0644]
workflow-designer-be/src/main/java/org/onap/sdc/workflow/persistence/types/WorkflowVersion.java
workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/WorkflowVersionControllerTest.java
workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/types/WorkflowVersionValidatorTest.java [deleted file]
workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/validation/NoDuplicatesValidatorTest.java [new file with mode: 0644]

index 1f0c4fe..e7c9f63 100644 (file)
@@ -21,10 +21,11 @@ import static org.onap.sdc.workflow.api.RestParams.USER_ID_HEADER;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import javax.validation.Valid;
 import org.onap.sdc.workflow.api.types.CollectionResponse;
 import org.onap.sdc.workflow.api.types.VersionStateDto;
 import org.onap.sdc.workflow.api.types.VersionStatesFormatter;
-import org.onap.sdc.workflow.api.types.WorkflowVersionValidator;
 import org.onap.sdc.workflow.persistence.types.ArtifactEntity;
 import org.onap.sdc.workflow.persistence.types.WorkflowVersion;
 import org.onap.sdc.workflow.services.WorkflowVersionManager;
@@ -55,32 +56,28 @@ import springfox.documentation.annotations.ApiIgnore;
 public class WorkflowVersionController {
 
     private final WorkflowVersionManager workflowVersionManager;
-    private final WorkflowVersionValidator versionValidator;
 
     @Autowired
-    public WorkflowVersionController(@Qualifier("workflowVersionManager") WorkflowVersionManager workflowVersionManager,
-            @Qualifier("WorkflowVersionValidator") WorkflowVersionValidator versionValidator) {
+    public WorkflowVersionController(
+            @Qualifier("workflowVersionManager") WorkflowVersionManager workflowVersionManager) {
         this.workflowVersionManager = workflowVersionManager;
-        this.versionValidator = versionValidator;
     }
 
-    @ApiImplicitParam(name = "state", dataType = "string", paramType = "query",
-            allowableValues = "DRAFT,CERTIFIED", value = "Filter by state")
+    @ApiImplicitParam(name = "state", dataType = "string", paramType = "query", allowableValues = "DRAFT,CERTIFIED",
+            value = "Filter by state")
     @GetMapping
     @ApiOperation("List workflow versions")
     public CollectionResponse<WorkflowVersion> list(@PathVariable("workflowId") String workflowId,
-            @ApiIgnore VersionStatesFormatter stateFilter,
-            @RequestHeader(USER_ID_HEADER) String user) {
+            @ApiIgnore VersionStatesFormatter stateFilter, @RequestHeader(USER_ID_HEADER) String user) {
         return new CollectionResponse<>(workflowVersionManager.list(workflowId, stateFilter.getVersionStates()));
     }
 
     @PostMapping
     @ApiOperation("Create workflow version")
-    public ResponseEntity<WorkflowVersion> create(@RequestBody WorkflowVersion version,
+    public ResponseEntity<WorkflowVersion> create(@RequestBody @Valid WorkflowVersion version,
             @PathVariable("workflowId") String workflowId,
             @RequestParam(value = "baseVersionId", required = false) String baseVersionId,
             @RequestHeader(USER_ID_HEADER) String user) {
-        versionValidator.validate(workflowId,version);
         WorkflowVersion createdVersion = workflowVersionManager.create(workflowId, baseVersionId, version);
         return new ResponseEntity<>(createdVersion, HttpStatus.CREATED);
     }
@@ -94,9 +91,8 @@ public class WorkflowVersionController {
 
     @PutMapping("/{versionId}")
     @ApiOperation("Update workflow version")
-    public void update(@RequestBody WorkflowVersion version, @PathVariable("workflowId") String workflowId,
+    public void update(@RequestBody @Valid WorkflowVersion version, @PathVariable("workflowId") String workflowId,
             @PathVariable("versionId") String versionId, @RequestHeader(USER_ID_HEADER) String user) {
-        versionValidator.validate(workflowId,version);
         version.setId(versionId);
         workflowVersionManager.update(workflowId, version);
     }
index e862290..02d68fd 100644 (file)
@@ -28,7 +28,7 @@ import org.onap.sdc.workflow.services.exceptions.UniqueValueViolationException;
 import org.onap.sdc.workflow.services.exceptions.VersionCreationException;
 import org.onap.sdc.workflow.services.exceptions.VersionModificationException;
 import org.onap.sdc.workflow.services.exceptions.VersionStateModificationException;
-import org.onap.sdc.workflow.services.exceptions.VersionValidationException;
+import org.springframework.context.support.DefaultMessageSourceResolvable;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -37,6 +37,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.ServletRequestBindingException;
 import org.springframework.web.bind.annotation.ControllerAdvice;
 import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.context.request.WebRequest;
 import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@@ -62,15 +63,18 @@ public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExce
         return new ResponseEntity<>(exception.getMessage(), BAD_REQUEST);
     }
 
-    //For workflowVersionValidator exception
     @Override
-    protected final ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException e,
+    protected final ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException exception,
             final HttpHeaders headers,
             final HttpStatus status,
             final WebRequest request) {
 
-        FieldError result = e.getBindingResult().getFieldError();
-       return new ResponseEntity<>(result.getDefaultMessage(), BAD_REQUEST);
+        String errorMsg = exception.getBindingResult().getFieldErrors().stream()
+                                   .map(DefaultMessageSourceResolvable::getDefaultMessage)
+                                   .findFirst()
+                                   .orElse(exception.getMessage());
+
+        return new ResponseEntity<>(errorMsg, BAD_REQUEST);
     }
 
     //For missing header exceptions
@@ -83,7 +87,7 @@ public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExce
 
 
     @ExceptionHandler({InvalidArtifactException.class, VersionModificationException.class,
-            VersionStateModificationException.class, VersionValidationException.class})
+            VersionStateModificationException.class})
     public final ResponseEntity<String> handleInvalidArtifactException(
             Exception exception) {
         return new ResponseEntity<>(exception.getMessage(), UNPROCESSABLE_ENTITY);
diff --git a/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/WorkflowVersionValidator.java b/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/types/WorkflowVersionValidator.java
deleted file mode 100644 (file)
index ef5e06c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.onap.sdc.workflow.api.types;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-import org.onap.sdc.workflow.persistence.types.ParameterEntity;
-import org.onap.sdc.workflow.persistence.types.WorkflowVersion;
-import org.onap.sdc.workflow.services.exceptions.VersionValidationException;
-import org.springframework.stereotype.Component;
-
-@Component("WorkflowVersionValidator")
-public class WorkflowVersionValidator {
-
-    public void validate(String workflowId, WorkflowVersion workflowVersion) {
-
-        if(containsDuplicates( workflowVersion.getInputs())){
-            throw new VersionValidationException(workflowId,"Input name must be unique");
-
-        }
-
-        if(containsDuplicates(workflowVersion.getOutputs())){
-            throw new VersionValidationException(workflowId ,"Output name must be unique");
-        }
-    }
-
-    private boolean containsDuplicates(Collection<ParameterEntity> parameters){
-        if(Objects.isNull(parameters) ||  parameters.size() < 2 ) {
-            return false;
-        }
-        Set<String> testSet = new HashSet<>();
-        return parameters.stream().anyMatch(s -> !testSet.add(s.getName()));
-    }
-}
diff --git a/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/validation/NoDuplicates.java b/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/validation/NoDuplicates.java
new file mode 100644 (file)
index 0000000..ca4932a
--- /dev/null
@@ -0,0 +1,21 @@
+package org.onap.sdc.workflow.api.validation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+@Target({ElementType.TYPE, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Constraint(validatedBy = {NoDuplicatesValidator.class})
+public @interface NoDuplicates {
+    String message();
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}
diff --git a/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/validation/NoDuplicatesValidator.java b/workflow-designer-be/src/main/java/org/onap/sdc/workflow/api/validation/NoDuplicatesValidator.java
new file mode 100644 (file)
index 0000000..13bbf0e
--- /dev/null
@@ -0,0 +1,21 @@
+package org.onap.sdc.workflow.api.validation;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import org.onap.sdc.workflow.persistence.types.ParameterEntity;
+
+public class NoDuplicatesValidator implements ConstraintValidator<NoDuplicates, Collection<ParameterEntity>> {
+
+    @Override
+    public boolean isValid(Collection<ParameterEntity> parameterEntities, ConstraintValidatorContext context) {
+        if (Objects.isNull(parameterEntities) || parameterEntities.size() < 2) {
+            return true;
+        }
+        Set<String> testSet = new HashSet<>();
+        return !parameterEntities.stream().anyMatch(s -> !testSet.add(s.getName()));
+    }
+}
index e3bbd64..b19f4a9 100644 (file)
@@ -21,6 +21,7 @@ import java.util.Collections;
 import java.util.Date;
 import javax.validation.Valid;
 import lombok.Data;
+import org.onap.sdc.workflow.api.validation.NoDuplicates;
 
 
 @Data
@@ -31,11 +32,13 @@ public class WorkflowVersion {
     private String description;
     private String baseId;
     private WorkflowVersionState state;
-    private boolean hasArtifact;
     @Valid
+    @NoDuplicates(message = "Inputs names must be unique")
     private Collection<ParameterEntity> inputs = Collections.emptyList();
     @Valid
+    @NoDuplicates(message = "Outputs names must be unique")
     private Collection<ParameterEntity> outputs = Collections.emptyList();
+    private boolean hasArtifact;
     private Date creationTime;
     private Date modificationTime;
 
index ec27c4b..65dae72 100644 (file)
@@ -2,9 +2,6 @@ package org.onap.sdc.workflow.api;
 
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -18,6 +15,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
 
 import com.google.gson.Gson;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,7 +24,8 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.onap.sdc.workflow.RestPath;
-import org.onap.sdc.workflow.api.types.WorkflowVersionValidator;
+import org.onap.sdc.workflow.persistence.types.ParameterEntity;
+import org.onap.sdc.workflow.persistence.types.ParameterType;
 import org.onap.sdc.workflow.persistence.types.WorkflowVersion;
 import org.onap.sdc.workflow.services.WorkflowVersionManager;
 import org.openecomp.sdc.versioning.dao.types.Version;
@@ -42,7 +41,6 @@ public class WorkflowVersionControllerTest {
     private static final String ITEM1_ID = "item_id_1";
     private static final String VERSION1_ID = "version_id_1";
     private static final String VERSION2_ID = "version_id_2";
-    private List<Version> versionList;
 
     private static final Gson GSON = new Gson();
 
@@ -51,38 +49,19 @@ public class WorkflowVersionControllerTest {
     @Mock
     private WorkflowVersionManager workflowVersionManagerMock;
 
-    @Mock
-    private WorkflowVersionValidator versionValidator;
-
     @InjectMocks
     private WorkflowVersionController workflowVersionController;
 
     @Before
     public void setUp() {
-        versionList = Arrays.asList( new Version(VERSION1_ID),new Version(VERSION2_ID));
         mockMvc = MockMvcBuilders.standaloneSetup(workflowVersionController).build();
     }
 
-/*    @Test
-    public void shouldReturnWorkflowVersionListWhenCallingVersionGetREST() throws Exception {
-
-        doReturn(versionList).when(workflowVersionManagerMock).list(ITEM1_ID, null);
-        mockMvc.perform(get(RestPath.getWorkflowVersions(ITEM1_ID)).header(RestParams.USER_ID_HEADER, USER_ID)
-                                                                   .contentType(APPLICATION_JSON)).andExpect(status().isOk())
-               .andExpect(jsonPath("$.results", hasSize(2)))
-               .andExpect(jsonPath("$.results[0].id", equalTo(VERSION1_ID)))
-               .andExpect(jsonPath("$.results[1].id", equalTo(VERSION2_ID)));
-
-        verify(workflowVersionManagerMock, times(1)).list(ITEM1_ID, null);
-    }*/
-
-
     @Test
     public void shouldCreateWorkflowVersionWhenCallingVersionsPostREST() throws Exception {
 
         WorkflowVersion version = new WorkflowVersion();
         version.setDescription("VersionDescription");
-        doNothing().when(versionValidator).validate(eq(ITEM1_ID),any(WorkflowVersion.class));
         mockMvc.perform(post(RestPath.getWorkflowVersions(ITEM1_ID)).header(RestParams.USER_ID_HEADER, USER_ID)
                                                                     .contentType(APPLICATION_JSON)
                                                                     .content(GSON.toJson(version)))
@@ -91,6 +70,21 @@ public class WorkflowVersionControllerTest {
         verify(workflowVersionManagerMock, times(1)).create(ITEM1_ID, null, version);
     }
 
+    @Test
+    public void shouldFailCreateWorkflowVersionWhenCallingVersionsPostRESTWithDuplicateInput() throws Exception {
+
+        WorkflowVersion version = new WorkflowVersion();
+        Collection<ParameterEntity> inputs =
+                Arrays.asList(createParameterEntity("name1"), createParameterEntity("name1"));
+        version.setInputs(inputs);
+        version.setDescription("VersionDescription");
+        mockMvc.perform(post(RestPath.getWorkflowVersions(ITEM1_ID)).header(RestParams.USER_ID_HEADER, USER_ID)
+                                                                    .contentType(APPLICATION_JSON)
+                                                                    .content(GSON.toJson(version)))
+               .andExpect(status().isBadRequest());
+
+    }
+
 
     @Test
     public void shouldReturnWorkflowVersionWhenExists() throws Exception {
@@ -107,7 +101,6 @@ public class WorkflowVersionControllerTest {
     public void shouldUpdateWorkflowVersionWhenCallingPutREST() throws Exception {
         WorkflowVersion version = new WorkflowVersion();
         version.setDescription("Updated");
-        doNothing().when(versionValidator).validate(eq(ITEM1_ID),any(WorkflowVersion.class));
 
         MockHttpServletResponse result = mockMvc.perform(
                 put(RestPath.getWorkflowVersion(ITEM1_ID, VERSION1_ID)).header(RestParams.USER_ID_HEADER, USER_ID)
@@ -121,4 +114,12 @@ public class WorkflowVersionControllerTest {
 
     }
 
+    private ParameterEntity createParameterEntity(String name) {
+        ParameterEntity parameterEntity = new ParameterEntity();
+        parameterEntity.setName(name);
+        parameterEntity.setMandatory(false);
+        parameterEntity.setType(ParameterType.STRING);
+        return parameterEntity;
+    }
+
 }
diff --git a/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/types/WorkflowVersionValidatorTest.java b/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/types/WorkflowVersionValidatorTest.java
deleted file mode 100644 (file)
index 9ea007c..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright © 2018 European Support Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onap.sdc.workflow.api.types;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.fail;
-
-import java.util.Arrays;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.onap.sdc.workflow.persistence.types.ParameterEntity;
-import org.onap.sdc.workflow.persistence.types.WorkflowVersion;
-import org.onap.sdc.workflow.services.exceptions.VersionValidationException;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-
-@RunWith(SpringJUnit4ClassRunner.class)
-public class WorkflowVersionValidatorTest {
-
-    private static final String ITEM1_ID = "item_id_1";
-
-    @InjectMocks
-    private WorkflowVersionValidator versionValidator;
-
-    @Test
-    public void invalidInputs() {
-        WorkflowVersion workflowVersion = new WorkflowVersion();
-        workflowVersion.setDescription("version description");
-        ParameterEntity input = new ParameterEntity();
-        input.setName("input1");
-        workflowVersion.setInputs(Arrays.asList(input, input));
-        try {
-            versionValidator.validate(ITEM1_ID, workflowVersion);
-            fail("Should have thrown VersionValidationException but did not!");
-
-        } catch (VersionValidationException ex) {
-            assertEquals(String.format("Error creating or modifying version for workflow with id %s: %s", ITEM1_ID,
-                    "Input name must be unique"), ex.getMessage());
-        }
-    }
-
-    @Test
-    public void invalidOtputs(){
-        WorkflowVersion workflowVersion = new WorkflowVersion();
-        workflowVersion.setDescription("version description");
-        ParameterEntity output = new ParameterEntity();
-        output.setName("output1");
-        workflowVersion.setOutputs(Arrays.asList(output, output));
-        try {
-            versionValidator.validate(ITEM1_ID, workflowVersion);
-            fail("Should have thrown VersionValidationException but did not!");
-
-        } catch (VersionValidationException ex) {
-            assertEquals(String.format("Error creating or modifying version for workflow with id %s: %s", ITEM1_ID,
-                    "Output name must be unique"), ex.getMessage());
-        }
-    }
-}
diff --git a/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/validation/NoDuplicatesValidatorTest.java b/workflow-designer-be/src/test/java/org/onap/sdc/workflow/api/validation/NoDuplicatesValidatorTest.java
new file mode 100644 (file)
index 0000000..bfc7dc3
--- /dev/null
@@ -0,0 +1,91 @@
+package org.onap.sdc.workflow.api.validation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import javax.validation.ConstraintValidatorContext;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.sdc.workflow.persistence.types.ParameterEntity;
+
+public class NoDuplicatesValidatorTest {
+
+    class AnnotationWrapper {
+
+        @NoDuplicates(message = "test message")
+        public Collection<ParameterEntity> collection;
+    }
+
+    private NoDuplicatesValidator noDuplicatesValidator;
+
+    @Mock
+    private ConstraintValidatorContext context;
+    @Mock
+    private ConstraintValidatorContext.ConstraintViolationBuilder constraintViolationBuilder;
+    @Mock
+    private ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext nodeBuilderCustomizableContext;
+
+    @Before
+    public void init() throws NoSuchFieldException {
+        MockitoAnnotations.initMocks(this);
+        when(context.buildConstraintViolationWithTemplate(anyString())).thenReturn(constraintViolationBuilder);
+        when(constraintViolationBuilder.addPropertyNode(anyString())).thenReturn(nodeBuilderCustomizableContext);
+        noDuplicatesValidator = initializeValidator(AnnotationWrapper.class);
+    }
+
+    @Test
+    public void shouldFailIfCollectionHaveMoreThen1ParameterEntityWithSameName() {
+        Collection<ParameterEntity> inputs =
+                Arrays.asList(createParameterEntity("name1"), createParameterEntity("name1"));
+
+        assertFalse(noDuplicatesValidator.isValid(inputs, context));
+    }
+
+    @Test
+    public void shouldPassIfCollectionDontHaveMoreThen1ParameterEntityWithSameName() {
+        Collection<ParameterEntity> inputs =
+                Arrays.asList(createParameterEntity("name2"), createParameterEntity("name1"));
+
+        assertTrue(noDuplicatesValidator.isValid(inputs, context));
+    }
+
+    @Test
+    public void shouldPassIfCollectionContainsOnlyOneObject() {
+        Collection<ParameterEntity> inputs =
+                Arrays.asList(createParameterEntity("name2"));
+
+        assertTrue(noDuplicatesValidator.isValid(inputs, context));
+    }
+
+    @Test
+    public void shouldPassIfCollectionIsNull() {
+        assertTrue(noDuplicatesValidator.isValid(null, context));
+    }
+
+    @Test
+    public void shouldPassIfCollectionIsEmpty() {
+        assertTrue(noDuplicatesValidator.isValid(new ArrayList<>(), context));
+    }
+
+    private NoDuplicatesValidator initializeValidator(Class<?> classWithAnnotation) throws NoSuchFieldException {
+        NoDuplicates constraint = classWithAnnotation.getField("collection").getAnnotation(NoDuplicates.class);
+        NoDuplicatesValidator validator = new NoDuplicatesValidator();
+        validator.initialize(constraint);
+        return validator;
+    }
+
+    private ParameterEntity createParameterEntity(String name) {
+        ParameterEntity parameterEntity = new ParameterEntity();
+        parameterEntity.setName(name);
+        return parameterEntity;
+    }
+}
\ No newline at end of file