Feature target type entity (#1162)

* Added Target Type model

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added Target Type JPA model

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added Target Type repository model classes

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Removed the name entity from Target Type

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Refactored the Target Type models

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added the DB migration script and updated the Target Type models

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added target type in target Mapper

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Changed the target type ID to Long

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added MYSQL DB migration script and removed the deleted column for target type

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Updated the DB migration script for target table

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added manyToMany reltation between target type and Ds type

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added POSTGRESQL DB migration script

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added MSSQL SERVER DB migration script

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added DB2 DB migration script

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added missing license header and java docs

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added on delete cascade in DB migration script

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added Target Type specification

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Removed the delete cascade and Added type API
Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* fixed API doc build

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added target type management test

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added target type events test

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added target type update and unassign to target

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added API tests for assigning target type to target

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added missing license header

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added missing docs

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Fixed sonar issues

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Fixed license header build issue

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Updated the attribute name to target type

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Fixed the review comments

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Removed unused error status variable

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added target API to assign target type

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Added the tests for assigning target type to target

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>

* Fixed the review comments for null check

Signed-off-by: Anand kumar <anand.kumar@bosch-si.com>
This commit is contained in:
Anand Kumar
2021-08-25 12:13:27 +02:00
committed by GitHub
parent 2574581b2c
commit 3fa1dd1be4
76 changed files with 4915 additions and 41 deletions

View File

@@ -76,6 +76,9 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest
@Autowired
protected TargetTagRepository targetTagRepository;
@Autowired
protected TargetTypeRepository targetTypeRepository;
@Autowired
protected DistributionSetTagRepository distributionSetTagRepository;

View File

@@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolationException;
@@ -27,6 +28,7 @@ import javax.validation.ConstraintViolationException;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.FilterParams;
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAttributesRequestedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
@@ -53,6 +55,7 @@ import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetMetadata;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
@@ -1038,6 +1041,67 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
assertThat(updated.getTarget().getId()).isEqualTo(target.getId());
}
@Test
@WithUser(allSpPermissions = true)
@Description("Checks that target type for a target can be created, updated and unassigned.")
public void createAndUpdateTargetTypeInTarget() {
// create a target type
List<TargetType> targetTypes = testdataFactory.createTargetTypes("targettype", 2);
assertThat(targetTypes).hasSize(2);
// create a target
final Target target = testdataFactory.createTarget("target1", "testtarget", targetTypes.get(0).getId());
// initial opt lock revision must be one
Optional<JpaTarget> targetFound = targetRepository.findById(target.getId());
assertThat(targetFound).isPresent();
assertThat(targetFound.get().getOptLockRevision()).isEqualTo(1);
assertThat(targetFound.get().getTargetType().getId()).isEqualTo(targetTypes.get(0).getId());
// update the target type
TargetUpdate targetUpdate = entityFactory.target().update(target.getControllerId()).targetType(targetTypes.get(1).getId());
targetManagement.update(targetUpdate);
// opt lock revision must be changed
Optional<JpaTarget> targetFound1 = targetRepository.findById(target.getId());
assertThat(targetFound1).isPresent();
assertThat(targetFound1.get().getOptLockRevision()).isEqualTo(2);
assertThat(targetFound1.get().getTargetType().getId()).isEqualTo(targetTypes.get(1).getId());
// unassign the target type
targetManagement.unAssignType(target.getControllerId());
// opt lock revision must be changed
Optional<JpaTarget> targetFound2 = targetRepository.findById(target.getId());
assertThat(targetFound2).isPresent();
assertThat(targetFound2.get().getOptLockRevision()).isEqualTo(3);
assertThat(targetFound2.get().getTargetType()).isNull();
}
@Test
@WithUser(allSpPermissions = true)
@Description("Checks that target type to a target can be assigned.")
public void assignTargetTypeInTarget() {
// create a target
final Target target = testdataFactory.createTarget("target1", "testtarget");
// initial opt lock revision must be one
Optional<JpaTarget> targetFound = targetRepository.findById(target.getId());
assertThat(targetFound).isPresent();
assertThat(targetFound.get().getOptLockRevision()).isEqualTo(1);
assertThat(targetFound.get().getTargetType()).isNull();
// create a target type
TargetType targetType = testdataFactory.findOrCreateTargetType("targettype");
assertThat(targetType).isNotNull();
// assign target type to target
targetManagement.assignType(targetFound.get().getControllerId(), targetType.getId());
// opt lock revision must be changed
Optional<JpaTarget> targetFound1 = targetRepository.findById(target.getId());
assertThat(targetFound1).isPresent();
assertThat(targetFound1.get().getOptLockRevision()).isEqualTo(2);
assertThat(targetFound1.get().getTargetType().getId()).isEqualTo(targetType.getId());
}
@Test
@Description("Queries and loads the metadata related to a given target.")
public void findAllTargetMetadataByControllerId() {

View File

@@ -0,0 +1,230 @@
/**
* Copyright (c) 2021 Bosch.IO GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.junit.jupiter.api.Test;
import javax.validation.ConstraintViolationException;
import java.util.Collections;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assertions.assertThrows;
@Feature("Component Tests - Repository")
@Story("Target Type Management")
public class TargetTypeManagementTest extends AbstractJpaIntegrationTest{
@Test
@Description("Verifies that management get access react as specified on calls for non existing entities by means "
+ "of Optional not present.")
@ExpectEvents({ @Expect(type = TargetTypeCreatedEvent.class, count = 0) })
public void nonExistingEntityAccessReturnsNotPresent() {
assertThat(targetTypeManagement.get(NOT_EXIST_IDL)).isNotPresent();
assertThat(targetTypeManagement.getByName(NOT_EXIST_ID)).isNotPresent();
}
@Test
@Description("Verifies that management queries react as specified on calls for non existing entities "
+ " by means of throwing EntityNotFoundException.")
@ExpectEvents({ @Expect(type = TargetTypeUpdatedEvent.class, count = 0) })
public void entityQueriesReferringToNotExistingEntitiesThrowsException() {
verifyThrownExceptionBy(() -> targetTypeManagement.delete(NOT_EXIST_IDL), "TargetType");
verifyThrownExceptionBy(() -> targetTypeManagement.update(entityFactory.targetType().update(NOT_EXIST_IDL)),
"TargetType");
}
@Test
@Description("Verify that a target type with invalid properties cannot be created or updated")
public void createAndUpdateTargetTypeWithInvalidFields() {
final TargetType targetType = targetTypeManagement
.create(entityFactory.targetType().create().name("targettype1").description("targettypedes1"));
createAndUpdateTargetTypeWithInvalidDescription(targetType);
createAndUpdateTargetTypeWithInvalidColour(targetType);
createAndUpdateTargetTypeWithInvalidName(targetType);
}
@Step
private void createAndUpdateTargetTypeWithInvalidDescription(final TargetType targetType) {
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetTypeManagement.create(
entityFactory.targetType().create().name("a").description(RandomStringUtils.randomAlphanumeric(TargetType.DESCRIPTION_MAX_SIZE + 1))))
.as("targetType with too long description should not be created");
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
() -> targetTypeManagement.create(entityFactory.targetType().create().name("a").description(INVALID_TEXT_HTML)))
.as("targetType with invalid description should not be created");
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetTypeManagement.update(
entityFactory.targetType().update(targetType.getId()).description(RandomStringUtils.randomAlphanumeric(TargetType.DESCRIPTION_MAX_SIZE + 1))))
.as("targetType with too long description should not be updated");
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).description(INVALID_TEXT_HTML)))
.as("targetType with invalid description should not be updated");
}
@Step
private void createAndUpdateTargetTypeWithInvalidColour(final TargetType targetType) {
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetTypeManagement.create(
entityFactory.targetType().create().name("a").colour(RandomStringUtils.randomAlphanumeric(TargetType.COLOUR_MAX_SIZE + 1))))
.as("targetType with too long colour should not be created");
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
() -> targetTypeManagement.create(entityFactory.targetType().create().name("a").colour(INVALID_TEXT_HTML)))
.as("targetType with invalid colour should not be created");
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetTypeManagement.update(
entityFactory.targetType().update(targetType.getId()).colour(RandomStringUtils.randomAlphanumeric(TargetType.COLOUR_MAX_SIZE + 1))))
.as("targetType with too long colour should not be updated");
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
() -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).colour(INVALID_TEXT_HTML)))
.as("targetType with invalid colour should not be updated");
}
@Step
private void createAndUpdateTargetTypeWithInvalidName(final TargetType targetType) {
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetTypeManagement
.create(entityFactory.targetType().create().name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))))
.as("targetType with too long name should not be created");
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetTypeManagement.create(entityFactory.targetType().create().name(INVALID_TEXT_HTML)))
.as("targetType with invalid name should not be created");
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetTypeManagement
.update(entityFactory.targetType().update(targetType.getId()).name(RandomStringUtils.randomAlphanumeric(
NamedEntity.NAME_MAX_SIZE + 1))))
.as("targetType with too long name should not be updated");
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(
() -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name(INVALID_TEXT_HTML)))
.as("targetType with invalid name should not be updated");
assertThatExceptionOfType(ConstraintViolationException.class)
.isThrownBy(() -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name("")))
.as("targetType with too short name should not be updated");
}
@Test
@Description("Tests the successful assignment of compatible distribution set types to a target type")
public void assignCompatibleDistributionSetTypesToTargetType(){
final TargetType targetType = targetTypeManagement
.create(entityFactory.targetType().create().name("targettype1").description("targettypedes1"));
DistributionSetType distributionSetType = testdataFactory.findOrCreateDistributionSetType("testDst", "dst1");
targetTypeManagement.assignCompatibleDistributionSetTypes(targetType.getId(), Collections.singletonList(distributionSetType.getId()));
Optional<JpaTargetType> targetTypeWithDsTypes = targetTypeRepository.findById(targetType.getId());
assertThat(targetTypeWithDsTypes).isPresent();
assertThat(targetTypeWithDsTypes.get().getCompatibleDistributionSetTypes()).extracting("key").contains("testDst");
}
@Test
@Description("Tests the successful removal of compatible distribution set types to a target type")
public void unassignCompatibleDistributionSetTypesToTargetType(){
final TargetType targetType = targetTypeManagement
.create(entityFactory.targetType().create().name("targettype11").description("targettypedes11"));
DistributionSetType distributionSetType = testdataFactory.findOrCreateDistributionSetType("testDst1", "dst11");
targetTypeManagement.assignCompatibleDistributionSetTypes(targetType.getId(), Collections.singletonList(distributionSetType.getId()));
Optional<JpaTargetType> targetTypeWithDsTypes = targetTypeRepository.findById(targetType.getId());
assertThat(targetTypeWithDsTypes).isPresent();
assertThat(targetTypeWithDsTypes.get().getCompatibleDistributionSetTypes()).extracting("key").contains("testDst1");
targetTypeManagement.unassignDistributionSetType(targetType.getId(),distributionSetType.getId());
Optional<JpaTargetType> targetTypeWithDsTypes1 = targetTypeRepository.findById(targetType.getId());
assertThat(targetTypeWithDsTypes1).isPresent();
assertThat(targetTypeWithDsTypes1.get().getCompatibleDistributionSetTypes()).hasSize(0);
}
@Test
@Description("Ensures that all types are retrieved through repository.")
public void findAllTargetTypes() {
testdataFactory.createTargetTypes("targettype", 10);
assertThat(targetTypeRepository.findAll()).as("Target type size").hasSize(10);
}
@Test
@Description("Ensures that a created target type is persisted in the repository as defined.")
public void createTargetType() {
final TargetType targetType = targetTypeManagement
.create(entityFactory.targetType().create().name("targettype1").description("targettypedes1").colour("colour1"));
assertThat(targetTypeRepository.findByName("targettype1").get().getDescription()).as("type found")
.isEqualTo("targettypedes1");
assertThat(targetTypeManagement.getByName("targettype1").get().getColour()).as("type found").isEqualTo("colour1");
assertThat(targetTypeManagement.get(targetType.getId()).get().getColour()).as("type found").isEqualTo("colour1");
}
@Test
@Description("Ensures that a deleted target type is removed from the repository as defined.")
public void deleteTargetType() {
// create test data
final TargetType targetType = targetTypeManagement
.create(entityFactory.targetType().create().name("targettype11").description("targettypedes11"));
assertThat(targetTypeRepository.findByName("targettype11").get().getDescription()).as("type found")
.isEqualTo("targettypedes11");
targetTypeManagement.delete(targetType.getId());
assertThat(targetTypeRepository.findById(targetType.getId())).as("No target type should be found").isNotPresent();
}
@Test
@Description("Tests the name update of a target type.")
public void updateTargetType() {
final TargetType targetType = targetTypeManagement
.create(entityFactory.targetType().create().name("targettype111").description("targettypedes111"));
assertThat(targetTypeRepository.findByName("targettype111").get().getDescription()).as("type found")
.isEqualTo("targettypedes111");
targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name("updatedtargettype111"));
assertThat(targetTypeRepository.findByName("updatedtargettype111")).as("Updated target type should be found").isPresent();
}
@Test
@Description("Ensures that a target type cannot be created if one exists already with that name (expects EntityAlreadyExistsException).")
public void failedDuplicateTargetTypeNameException() {
targetTypeManagement.create(entityFactory.targetType().create().name("targettype123"));
assertThrows(EntityAlreadyExistsException.class, () -> targetTypeManagement.create(entityFactory.targetType().create().name("targettype123")));
}
@Test
@Description("Ensures that a target type cannot be updated to a name that already exists (expects EntityAlreadyExistsException).")
public void failedDuplicateTargetTypeNameExceptionAfterUpdate() {
targetTypeManagement.create(entityFactory.targetType().create().name("targettype1234"));
TargetType targetType = targetTypeManagement.create(entityFactory.targetType().create().name("targettype12345"));
assertThrows(EntityAlreadyExistsException.class, () -> targetTypeManagement.update(entityFactory.targetType().update(targetType.getId()).name("targettype1234")));
}
}

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.event;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -20,10 +21,13 @@ import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.RolloutDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetTypeDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTypeUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.event.RepositoryEntityEventTest.RepositoryTestConfiguration;
@@ -31,6 +35,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -88,6 +93,38 @@ public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
assertThat(targetDeletedEvent.getEntityId()).isEqualTo(createdTarget.getId());
}
@Test
@Description("Verifies that the target type created event is published when a target type has been created")
public void targetTypeCreatedEventIsPublished() throws InterruptedException {
TargetType createdTargetType = testdataFactory.findOrCreateTargetType("targettype");
TargetTypeCreatedEvent targetTypeCreatedEvent = eventListener.waitForEvent(TargetTypeCreatedEvent.class);
assertThat(targetTypeCreatedEvent).isNotNull();
assertThat(targetTypeCreatedEvent.getEntity().getId()).isEqualTo(createdTargetType.getId());
}
@Test
@Description("Verifies that the target type updated event is published when a target type has been updated")
public void targetTypeUpdatedEventIsPublished() throws InterruptedException {
TargetType createdTargetType = testdataFactory.findOrCreateTargetType("targettype");
targetTypeManagement.update(entityFactory.targetType().update(createdTargetType.getId()).name("updatedtargettype"));
TargetTypeUpdatedEvent targetTypeUpdatedEvent = eventListener.waitForEvent(TargetTypeUpdatedEvent.class);
assertThat(targetTypeUpdatedEvent).isNotNull();
assertThat(targetTypeUpdatedEvent.getEntity().getId()).isEqualTo(createdTargetType.getId());
}
@Test
@Description("Verifies that the target type deleted event is published when a target type has been deleted")
public void targetTypeDeletedEventIsPublished() throws InterruptedException {
TargetType createdTargetType = testdataFactory.findOrCreateTargetType("targettype");
targetTypeManagement.delete(createdTargetType.getId());
TargetTypeDeletedEvent targetTypeDeletedEvent = eventListener.waitForEvent(TargetTypeDeletedEvent.class);
assertThat(targetTypeDeletedEvent).isNotNull();
assertThat(targetTypeDeletedEvent.getEntityId()).isEqualTo(createdTargetType.getId());
}
@Test
@Description("Verifies that the rollout deleted event is published when a rollout has been deleted")
public void rolloutDeletedEventIsPublished() throws InterruptedException {