Protection against misuse with system-wide quota definitions (#670)
* Added quota for meta data per software module Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Added unit test for "meta data per module" quota Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * quota test enhancements Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Verify enforcement of meta data quota via REST Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Quota for distribution set meta data Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Verify enforcement of distribution set meta data quota via REST Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * software modules per distribution set quota Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Integration test enhancements for Modules per DistSet quota Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Quota for software module types per distribution set type Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Quota for max artifacts per software module Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Quotas for ActionStatus per Action and Messages per ActionStatus Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Quota attributes per target Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Quota targets per rollout group Signed-off-by: stefbehl <stefan.behl@bosch-si.com> * Quota max targets per rollout group Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per rollout group Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per rollout group Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per rollout group Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per group Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * quota max actions per target Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per rollout group Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max actions per target Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max actions per target Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per auto assignment Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per manual assignment Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per auto assignment Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per auto assign Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per auto assignment Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max actions per target Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per manual assignment Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix issues caused by merge Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Improve JavaDoc Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix Sonar issues Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix Sonar findings Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max artifact size Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Optimize quota configuration Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix test failures Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Improve test coverage Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max rollout groups per rollout Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Configure Rollout UI enhancements Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * UI enhancements Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Minor changes Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per group Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Quota max targets per group Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix Sonar findings Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix Sonar findings Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix Sonar finding Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix code review findings Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix review findings Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * New approach for 'max artifact size' enforcement Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix Sonar findings Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix failing tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Reduce max artifact size for tests Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com> * Fix Kai's review findings Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>
This commit is contained in:
committed by
Kai Zimmermann
parent
fcc15a0484
commit
6dd98d2134
@@ -9,6 +9,7 @@
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@@ -17,6 +18,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
@@ -25,6 +27,7 @@ import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
@@ -35,6 +38,8 @@ import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
@@ -67,12 +72,13 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
@ExpectEvents({ @Expect(type = SoftwareModuleDeletedEvent.class, count = 0) })
|
||||
public void entityQueriesReferringToNotExistingEntitiesThrowsException() throws URISyntaxException {
|
||||
|
||||
verifyThrownExceptionBy(() -> artifactManagement.create(IOUtils.toInputStream("test", "UTF-8"), NOT_EXIST_IDL,
|
||||
"xxx", null, null, false, null), "SoftwareModule");
|
||||
final String artifactData = "test";
|
||||
final int artifactSize = artifactData.length();
|
||||
verifyThrownExceptionBy(() -> artifactManagement.create(IOUtils.toInputStream(artifactData, "UTF-8"),
|
||||
NOT_EXIST_IDL, "xxx", null, null, false, null, artifactSize), "SoftwareModule");
|
||||
|
||||
verifyThrownExceptionBy(
|
||||
() -> artifactManagement.create(IOUtils.toInputStream("test", "UTF-8"), 1234L, "xxx", false),
|
||||
"SoftwareModule");
|
||||
verifyThrownExceptionBy(() -> artifactManagement.create(IOUtils.toInputStream(artifactData, "UTF-8"), 1234L,
|
||||
"xxx", false, artifactSize), "SoftwareModule");
|
||||
|
||||
verifyThrownExceptionBy(() -> artifactManagement.delete(NOT_EXIST_IDL), "Artifact");
|
||||
|
||||
@@ -86,59 +92,128 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
@Description("Test if a local artifact can be created by API including metadata.")
|
||||
public void createArtifact() throws NoSuchAlgorithmException, IOException {
|
||||
// checkbaseline
|
||||
|
||||
// check baseline
|
||||
assertThat(softwareModuleRepository.findAll()).hasSize(0);
|
||||
assertThat(artifactRepository.findAll()).hasSize(0);
|
||||
|
||||
JpaSoftwareModule sm = new JpaSoftwareModule(osType, "name 1", "version 1", null, null);
|
||||
sm = softwareModuleRepository.save(sm);
|
||||
final JpaSoftwareModule sm = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "name 1", "version 1", null, null));
|
||||
final JpaSoftwareModule sm2 = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "name 2", "version 2", null, null));
|
||||
softwareModuleRepository.save(new JpaSoftwareModule(osType, "name 3", "version 3", null, null));
|
||||
|
||||
JpaSoftwareModule sm2 = new JpaSoftwareModule(osType, "name 2", "version 2", null, null);
|
||||
sm2 = softwareModuleRepository.save(sm2);
|
||||
final int artifactSize = 5 * 1024;
|
||||
final byte random[] = RandomStringUtils.random(artifactSize).getBytes();
|
||||
|
||||
JpaSoftwareModule sm3 = new JpaSoftwareModule(osType, "name 3", "version 3", null, null);
|
||||
sm3 = softwareModuleRepository.save(sm3);
|
||||
try (final InputStream inputStream1 = new ByteArrayInputStream(random);
|
||||
final InputStream inputStream2 = new ByteArrayInputStream(random);
|
||||
final InputStream inputStream3 = new ByteArrayInputStream(random);
|
||||
final InputStream inputStream4 = new ByteArrayInputStream(random);) {
|
||||
|
||||
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
|
||||
final Artifact result = artifactManagement.create(inputStream1, sm.getId(), "file1", false, artifactSize);
|
||||
artifactManagement.create(inputStream2, sm.getId(), "file11", false, artifactSize);
|
||||
artifactManagement.create(inputStream3, sm.getId(), "file12", false, artifactSize);
|
||||
final Artifact result2 = artifactManagement.create(inputStream4, sm2.getId(), "file2", false, artifactSize);
|
||||
|
||||
final Artifact result = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1", false);
|
||||
artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file11", false);
|
||||
artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file12", false);
|
||||
final Artifact result2 = artifactManagement.create(new ByteArrayInputStream(random), sm2.getId(), "file2",
|
||||
false);
|
||||
assertThat(result).isInstanceOf(Artifact.class);
|
||||
assertThat(result.getSoftwareModule().getId()).isEqualTo(sm.getId());
|
||||
assertThat(result2.getSoftwareModule().getId()).isEqualTo(sm2.getId());
|
||||
assertThat(((JpaArtifact) result).getFilename()).isEqualTo("file1");
|
||||
assertThat(((JpaArtifact) result).getSha1Hash()).isNotNull();
|
||||
assertThat(result).isNotEqualTo(result2);
|
||||
assertThat(((JpaArtifact) result).getSha1Hash()).isEqualTo(((JpaArtifact) result2).getSha1Hash());
|
||||
|
||||
assertThat(result).isInstanceOf(Artifact.class);
|
||||
assertThat(result.getSoftwareModule().getId()).isEqualTo(sm.getId());
|
||||
assertThat(result2.getSoftwareModule().getId()).isEqualTo(sm2.getId());
|
||||
assertThat(((JpaArtifact) result).getFilename()).isEqualTo("file1");
|
||||
assertThat(((JpaArtifact) result).getSha1Hash()).isNotNull();
|
||||
assertThat(result).isNotEqualTo(result2);
|
||||
assertThat(((JpaArtifact) result).getSha1Hash()).isEqualTo(((JpaArtifact) result2).getSha1Hash());
|
||||
assertThat(artifactManagement.getByFilename("file1").get().getSha1Hash())
|
||||
.isEqualTo(HashGeneratorUtils.generateSHA1(random));
|
||||
assertThat(artifactManagement.getByFilename("file1").get().getMd5Hash())
|
||||
.isEqualTo(HashGeneratorUtils.generateMD5(random));
|
||||
|
||||
assertThat(artifactManagement.getByFilename("file1").get().getSha1Hash())
|
||||
.isEqualTo(HashGeneratorUtils.generateSHA1(random));
|
||||
assertThat(artifactManagement.getByFilename("file1").get().getMd5Hash())
|
||||
.isEqualTo(HashGeneratorUtils.generateMD5(random));
|
||||
assertThat(artifactRepository.findAll()).hasSize(4);
|
||||
assertThat(softwareModuleRepository.findAll()).hasSize(3);
|
||||
|
||||
assertThat(artifactRepository.findAll()).hasSize(4);
|
||||
assertThat(softwareModuleRepository.findAll()).hasSize(3);
|
||||
assertThat(softwareModuleManagement.get(sm.getId()).get().getArtifacts()).hasSize(3);
|
||||
}
|
||||
|
||||
assertThat(softwareModuleManagement.get(sm.getId()).get().getArtifacts()).hasSize(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the quota specifying the maximum number of artifacts per software module is enforced.")
|
||||
public void createArtifactsUntilQuotaIsExceeded() throws NoSuchAlgorithmException, IOException {
|
||||
|
||||
// create a software module
|
||||
final JpaSoftwareModule sm1 = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "sm1", "1.0", null, null));
|
||||
|
||||
// now create artifacts for this module until the quota is exceeded
|
||||
final long maxArtifacts = quotaManagement.getMaxArtifactsPerSoftwareModule();
|
||||
final List<Long> artifactIds = Lists.newArrayList();
|
||||
final int artifactSize = 5 * 1024;
|
||||
for (int i = 0; i < maxArtifacts; ++i) {
|
||||
final byte random[] = RandomStringUtils.random(artifactSize).getBytes();
|
||||
try (final InputStream inputStream = new ByteArrayInputStream(random)) {
|
||||
artifactIds.add(
|
||||
artifactManagement.create(inputStream, sm1.getId(), "file" + i, false, artifactSize).getId());
|
||||
}
|
||||
}
|
||||
assertThat(artifactRepository.findBySoftwareModuleId(PAGE, sm1.getId()).getTotalElements())
|
||||
.isEqualTo(maxArtifacts);
|
||||
|
||||
// create one mode to trigger the quota exceeded error
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> {
|
||||
final byte random[] = RandomStringUtils.random(artifactSize).getBytes();
|
||||
try (final InputStream inputStream = new ByteArrayInputStream(random)) {
|
||||
artifactManagement.create(inputStream, sm1.getId(), "file" + maxArtifacts, false, artifactSize);
|
||||
}
|
||||
});
|
||||
|
||||
// delete one of the artifacts
|
||||
artifactManagement.delete(artifactIds.get(0));
|
||||
assertThat(artifactRepository.findBySoftwareModuleId(PAGE, sm1.getId()).getTotalElements())
|
||||
.isEqualTo(maxArtifacts - 1);
|
||||
|
||||
// now we should be able to create an artifact again
|
||||
final byte random[] = RandomStringUtils.random(artifactSize).getBytes();
|
||||
try (final InputStream inputStream = new ByteArrayInputStream(random)) {
|
||||
artifactManagement.create(inputStream, sm1.getId(), "fileXYZ", false, artifactSize);
|
||||
assertThat(artifactRepository.findBySoftwareModuleId(PAGE, sm1.getId()).getTotalElements())
|
||||
.isEqualTo(maxArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that you cannot create artifacts which exceed the configured maximum size.")
|
||||
public void createArtifactFailsIfTooLarge() throws NoSuchAlgorithmException, IOException {
|
||||
|
||||
// create a software module
|
||||
final JpaSoftwareModule sm1 = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "sm1", "1.0", null, null));
|
||||
|
||||
// create an artifact that exceeds the configured quota
|
||||
final long maxSize = quotaManagement.getMaxArtifactSize();
|
||||
final int artifactSize = Math.toIntExact(maxSize) + 8;
|
||||
final byte random[] = RandomStringUtils.random(artifactSize).getBytes();
|
||||
try (final InputStream inputStream = new ByteArrayInputStream(random)) {
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> artifactManagement.create(inputStream, sm1.getId(), "file", false, artifactSize));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests hard delete directly on repository.")
|
||||
public void hardDeleteSoftwareModule() throws NoSuchAlgorithmException, IOException {
|
||||
JpaSoftwareModule sm = new JpaSoftwareModule(osType, "name 1", "version 1", null, null);
|
||||
sm = softwareModuleRepository.save(sm);
|
||||
|
||||
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
|
||||
final JpaSoftwareModule sm = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "name 1", "version 1", null, null));
|
||||
final int artifactSize = 5 * 1024;
|
||||
final byte random[] = RandomStringUtils.random(artifactSize).getBytes();
|
||||
try (final InputStream inputStream = new ByteArrayInputStream(random)) {
|
||||
artifactManagement.create(inputStream, sm.getId(), "file1", false, artifactSize);
|
||||
assertThat(artifactRepository.findAll()).hasSize(1);
|
||||
|
||||
artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1", false);
|
||||
assertThat(artifactRepository.findAll()).hasSize(1);
|
||||
|
||||
softwareModuleRepository.deleteAll();
|
||||
assertThat(artifactRepository.findAll()).hasSize(0);
|
||||
softwareModuleRepository.deleteAll();
|
||||
assertThat(artifactRepository.findAll()).hasSize(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,97 +227,109 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
@Description("Tests the deletion of a local artifact including metadata.")
|
||||
public void deleteArtifact() throws NoSuchAlgorithmException, IOException {
|
||||
JpaSoftwareModule sm = new JpaSoftwareModule(osType, "name 1", "version 1", null, null);
|
||||
sm = softwareModuleRepository.save(sm);
|
||||
|
||||
JpaSoftwareModule sm2 = new JpaSoftwareModule(osType, "name 2", "version 2", null, null);
|
||||
sm2 = softwareModuleRepository.save(sm2);
|
||||
final JpaSoftwareModule sm = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "name 1", "version 1", null, null));
|
||||
final JpaSoftwareModule sm2 = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "name 2", "version 2", null, null));
|
||||
|
||||
assertThat(artifactRepository.findAll()).isEmpty();
|
||||
|
||||
final Artifact result = artifactManagement.create(new RandomGeneratedInputStream(5 * 1024), sm.getId(), "file1",
|
||||
false);
|
||||
final Artifact result2 = artifactManagement.create(new RandomGeneratedInputStream(5 * 1024), sm2.getId(),
|
||||
"file2", false);
|
||||
final int artifactSize = 5 * 1024;
|
||||
try (final InputStream inputStream1 = new RandomGeneratedInputStream(artifactSize);
|
||||
final InputStream inputStream2 = new RandomGeneratedInputStream(artifactSize)) {
|
||||
|
||||
assertThat(artifactRepository.findAll()).hasSize(2);
|
||||
final Artifact result = artifactManagement.create(inputStream1, sm.getId(), "file1", false, artifactSize);
|
||||
final Artifact result2 = artifactManagement.create(inputStream2, sm2.getId(), "file2", false, artifactSize);
|
||||
|
||||
assertThat(result.getId()).isNotNull();
|
||||
assertThat(result2.getId()).isNotNull();
|
||||
assertThat(((JpaArtifact) result).getSha1Hash()).isNotEqualTo(((JpaArtifact) result2).getSha1Hash());
|
||||
assertThat(artifactRepository.findAll()).hasSize(2);
|
||||
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNotNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result2.getSha1Hash()))
|
||||
.isNotNull();
|
||||
assertThat(result.getId()).isNotNull();
|
||||
assertThat(result2.getId()).isNotNull();
|
||||
assertThat(((JpaArtifact) result).getSha1Hash()).isNotEqualTo(((JpaArtifact) result2).getSha1Hash());
|
||||
|
||||
artifactManagement.delete(result.getId());
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNotNull();
|
||||
assertThat(
|
||||
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result2.getSha1Hash()))
|
||||
.isNotNull();
|
||||
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result2.getSha1Hash()))
|
||||
.isNotNull();
|
||||
artifactManagement.delete(result.getId());
|
||||
|
||||
artifactManagement.delete(result2.getId());
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result2.getSha1Hash()))
|
||||
.isNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNull();
|
||||
assertThat(
|
||||
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result2.getSha1Hash()))
|
||||
.isNotNull();
|
||||
|
||||
assertThat(artifactRepository.findAll()).hasSize(0);
|
||||
artifactManagement.delete(result2.getId());
|
||||
assertThat(
|
||||
binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result2.getSha1Hash()))
|
||||
.isNull();
|
||||
|
||||
assertThat(artifactRepository.findAll()).hasSize(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test the deletion of an artifact metadata where the binary is still linked to another "
|
||||
+ "metadata element. The expected result is that the metadata is deleted but the binary kept.")
|
||||
public void deleteDuplicateArtifacts() throws NoSuchAlgorithmException, IOException {
|
||||
JpaSoftwareModule sm = new JpaSoftwareModule(osType, "name 1", "version 1", null, null);
|
||||
sm = softwareModuleRepository.save(sm);
|
||||
|
||||
JpaSoftwareModule sm2 = new JpaSoftwareModule(osType, "name 2", "version 2", null, null);
|
||||
sm2 = softwareModuleRepository.save(sm2);
|
||||
final JpaSoftwareModule sm = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "name 1", "version 1", null, null));
|
||||
final JpaSoftwareModule sm2 = softwareModuleRepository
|
||||
.save(new JpaSoftwareModule(osType, "name 2", "version 2", null, null));
|
||||
|
||||
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
|
||||
final int artifactSize = 5 * 1024;
|
||||
final byte random[] = RandomStringUtils.random(artifactSize).getBytes();
|
||||
|
||||
final Artifact result = artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1", false);
|
||||
final Artifact result2 = artifactManagement.create(new ByteArrayInputStream(random), sm2.getId(), "file2",
|
||||
false);
|
||||
try (final InputStream inputStream1 = new ByteArrayInputStream(random);
|
||||
final InputStream inputStream2 = new ByteArrayInputStream(random)) {
|
||||
final Artifact result = artifactManagement.create(inputStream1, sm.getId(), "file1", false, artifactSize);
|
||||
final Artifact result2 = artifactManagement.create(inputStream2, sm2.getId(), "file2", false, artifactSize);
|
||||
|
||||
assertThat(artifactRepository.findAll()).hasSize(2);
|
||||
assertThat(result.getId()).isNotNull();
|
||||
assertThat(result2.getId()).isNotNull();
|
||||
assertThat(((JpaArtifact) result).getSha1Hash()).isEqualTo(((JpaArtifact) result2).getSha1Hash());
|
||||
assertThat(artifactRepository.findAll()).hasSize(2);
|
||||
assertThat(result.getId()).isNotNull();
|
||||
assertThat(result2.getId()).isNotNull();
|
||||
assertThat(((JpaArtifact) result).getSha1Hash()).isEqualTo(((JpaArtifact) result2).getSha1Hash());
|
||||
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNotNull();
|
||||
artifactManagement.delete(result.getId());
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNotNull();
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNotNull();
|
||||
artifactManagement.delete(result.getId());
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNotNull();
|
||||
|
||||
artifactManagement.delete(result2.getId());
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNull();
|
||||
artifactManagement.delete(result2.getId());
|
||||
assertThat(binaryArtifactRepository.getArtifactBySha1(tenantAware.getCurrentTenant(), result.getSha1Hash()))
|
||||
.isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Loads an local artifact based on given ID.")
|
||||
public void findArtifact() throws NoSuchAlgorithmException, IOException {
|
||||
final Artifact result = artifactManagement.create(new RandomGeneratedInputStream(5 * 1024),
|
||||
testdataFactory.createSoftwareModuleOs().getId(), "file1", false);
|
||||
|
||||
assertThat(artifactManagement.get(result.getId()).get()).isEqualTo(result);
|
||||
final int artifactSize = 5 * 1024;
|
||||
try (final InputStream inputStream = new RandomGeneratedInputStream(artifactSize)) {
|
||||
final Artifact result = artifactManagement.create(inputStream,
|
||||
testdataFactory.createSoftwareModuleOs().getId(), "file1", false, artifactSize);
|
||||
assertThat(artifactManagement.get(result.getId()).get()).isEqualTo(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Loads an artifact binary based on given ID.")
|
||||
public void loadStreamOfArtifact() throws NoSuchAlgorithmException, IOException {
|
||||
final byte random[] = RandomStringUtils.random(5 * 1024).getBytes();
|
||||
|
||||
final Artifact result = artifactManagement.create(new ByteArrayInputStream(random),
|
||||
testdataFactory.createSoftwareModuleOs().getId(), "file1", false);
|
||||
|
||||
try (InputStream fileInputStream = artifactManagement.loadArtifactBinary(result.getSha1Hash()).get()
|
||||
.getFileInputStream()) {
|
||||
assertTrue("The stored binary matches the given binary",
|
||||
IOUtils.contentEquals(new ByteArrayInputStream(random), fileInputStream));
|
||||
final int artifactSize = 5 * 1024;
|
||||
final byte random[] = RandomStringUtils.random(artifactSize).getBytes();
|
||||
try (final InputStream input = new ByteArrayInputStream(random)) {
|
||||
final Artifact result = artifactManagement.create(input, testdataFactory.createSoftwareModuleOs().getId(),
|
||||
"file1", false, artifactSize);
|
||||
try (final InputStream inputStream = artifactManagement.loadArtifactBinary(result.getSha1Hash()).get()
|
||||
.getFileInputStream()) {
|
||||
assertTrue("The stored binary matches the given binary",
|
||||
IOUtils.contentEquals(new ByteArrayInputStream(random), inputStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,27 +347,31 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Description("Searches an artifact through the relations of a software module.")
|
||||
public void findArtifactBySoftwareModule() {
|
||||
public void findArtifactBySoftwareModule() throws IOException {
|
||||
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
||||
|
||||
assertThat(artifactManagement.findBySoftwareModule(PAGE, sm.getId())).isEmpty();
|
||||
|
||||
artifactManagement.create(new RandomGeneratedInputStream(5 * 1024), sm.getId(), "file1", false);
|
||||
|
||||
assertThat(artifactManagement.findBySoftwareModule(PAGE, sm.getId())).hasSize(1);
|
||||
final int artifactSize = 5 * 1024;
|
||||
try (final InputStream input = new RandomGeneratedInputStream(artifactSize)) {
|
||||
artifactManagement.create(input, sm.getId(), "file1", false, artifactSize);
|
||||
assertThat(artifactManagement.findBySoftwareModule(PAGE, sm.getId())).hasSize(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Searches an artifact through the relations of a software module and the filename.")
|
||||
public void findByFilenameAndSoftwareModule() {
|
||||
public void findByFilenameAndSoftwareModule() throws IOException {
|
||||
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
||||
|
||||
assertThat(artifactManagement.getByFilenameAndSoftwareModule("file1", sm.getId())).isNotPresent();
|
||||
|
||||
artifactManagement.create(new RandomGeneratedInputStream(5 * 1024), sm.getId(), "file1", false);
|
||||
artifactManagement.create(new RandomGeneratedInputStream(5 * 1024), sm.getId(), "file2", false);
|
||||
|
||||
assertThat(artifactManagement.getByFilenameAndSoftwareModule("file1", sm.getId())).isPresent();
|
||||
final int artifactSize = 5 * 1024;
|
||||
try (final InputStream inputStream1 = new RandomGeneratedInputStream(artifactSize);
|
||||
final InputStream inputStream2 = new RandomGeneratedInputStream(artifactSize)) {
|
||||
artifactManagement.create(inputStream1, sm.getId(), "file1", false, artifactSize);
|
||||
artifactManagement.create(inputStream2, sm.getId(), "file2", false, artifactSize);
|
||||
assertThat(artifactManagement.getByFilenameAndSoftwareModule("file1", sm.getId())).isPresent();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
@@ -430,7 +431,8 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6),
|
||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 2) })
|
||||
public void hasTargetArtifactAssignedIsTrueWithMultipleArtifacts() {
|
||||
final byte[] random = RandomUtils.nextBytes(5 * 1024);
|
||||
final int artifactSize = 5 * 1024;
|
||||
final byte[] random = RandomUtils.nextBytes(artifactSize);
|
||||
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("");
|
||||
final DistributionSet ds2 = testdataFactory.createDistributionSet("2");
|
||||
@@ -438,9 +440,9 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
// create two artifacts with identical SHA1 hash
|
||||
final Artifact artifact = artifactManagement.create(new ByteArrayInputStream(random),
|
||||
ds.findFirstModuleByType(osType).get().getId(), "file1", false);
|
||||
ds.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize);
|
||||
final Artifact artifact2 = artifactManagement.create(new ByteArrayInputStream(random),
|
||||
ds2.findFirstModuleByType(osType).get().getId(), "file1", false);
|
||||
ds2.findFirstModuleByType(osType).get().getId(), "file1", false, artifactSize);
|
||||
assertThat(artifact.getSha1Hash()).isEqualTo(artifact2.getSha1Hash());
|
||||
|
||||
assertThat(
|
||||
@@ -793,7 +795,7 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 2) })
|
||||
public void updateTargetAttributesFailsIfTooManyEntries() throws Exception {
|
||||
final String controllerId = "test123";
|
||||
final int allowedAttributes = 10;
|
||||
final int allowedAttributes = quotaManagement.getMaxAttributeEntriesPerTarget();
|
||||
testdataFactory.createTarget(controllerId);
|
||||
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> securityRule
|
||||
@@ -880,4 +882,69 @@ public class ControllerManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(messages.get(0)).as("Message of action-status").isEqualTo("proceeding message 2");
|
||||
assertThat(messages.get(1)).as("Message of action-status").isEqualTo("proceeding message 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the quota specifying the maximum number of status entries per action is enforced.")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 2),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
|
||||
@Expect(type = ActionCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2),
|
||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 2),
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 6) })
|
||||
public void addActionStatusUpdatesUntilQuotaIsExceeded() {
|
||||
|
||||
// any distribution set assignment causes 1 status entity to be created
|
||||
final int maxStatusEntries = quotaManagement.getMaxStatusEntriesPerAction() - 1;
|
||||
|
||||
// test for informational status
|
||||
final Long actionId1 = assignDistributionSet(testdataFactory.createDistributionSet("ds1"),
|
||||
testdataFactory.createTargets(1, "t1")).getActions().get(0);
|
||||
assertThat(actionId1).isNotNull();
|
||||
for (int i = 0; i < maxStatusEntries; ++i) {
|
||||
controllerManagement.addInformationalActionStatus(entityFactory.actionStatus().create(actionId1)
|
||||
.status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis()));
|
||||
}
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement
|
||||
.addInformationalActionStatus(entityFactory.actionStatus().create(actionId1).status(Status.WARNING)));
|
||||
|
||||
// test for update status (and mixed case)
|
||||
final Long actionId2 = assignDistributionSet(testdataFactory.createDistributionSet("ds2"),
|
||||
testdataFactory.createTargets(1, "t2")).getActions().get(0);
|
||||
assertThat(actionId2).isNotEqualTo(actionId1);
|
||||
for (int i = 0; i < maxStatusEntries; ++i) {
|
||||
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId2)
|
||||
.status(Status.WARNING).message("Msg " + i).occurredAt(System.currentTimeMillis()));
|
||||
}
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> controllerManagement
|
||||
.addInformationalActionStatus(entityFactory.actionStatus().create(actionId2).status(Status.WARNING)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the quota specifying the maximum number of messages per action status is enforced.")
|
||||
@ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
@Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = TargetUpdatedEvent.class, count = 1),
|
||||
@Expect(type = TargetAssignDistributionSetEvent.class, count = 1),
|
||||
@Expect(type = SoftwareModuleCreatedEvent.class, count = 3) })
|
||||
public void createActionStatusWithTooManyMessages() {
|
||||
|
||||
final int maxMessages = quotaManagement.getMaxMessagesPerActionStatus();
|
||||
|
||||
final Long actionId = assignDistributionSet(testdataFactory.createDistributionSet("ds1"),
|
||||
testdataFactory.createTargets(1)).getActions().get(0);
|
||||
assertThat(actionId).isNotNull();
|
||||
|
||||
final List<String> messages = Lists.newArrayList();
|
||||
IntStream.range(0, maxMessages).forEach(i -> messages.add(i, "msg"));
|
||||
|
||||
assertThat(controllerManagement.addInformationalActionStatus(
|
||||
entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING))).isNotNull();
|
||||
|
||||
messages.add("msg");
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> controllerManagement.addInformationalActionStatus(
|
||||
entityFactory.actionStatus().create(actionId).messages(messages).status(Status.WARNING)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||
@@ -35,6 +36,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
@@ -171,6 +173,37 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(actions.getContent().get(0).getId()).as("Action of target").isEqualTo(actionId);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test verifies that the 'max actions per target' quota is enforced if the assigned distribution set is changed permanently.")
|
||||
public void changeDistributionSetAssignmentUntilMaxActionsPerTargetQuotaIsExceeded() {
|
||||
|
||||
final int maxActions = quotaManagement.getMaxActionsPerTarget();
|
||||
final List<Target> testTargets = testdataFactory.createTargets(1);
|
||||
final DistributionSet ds1 = testdataFactory.createDistributionSet("ds1");
|
||||
final DistributionSet ds2 = testdataFactory.createDistributionSet("ds2");
|
||||
final DistributionSet ds3 = testdataFactory.createDistributionSet("ds3");
|
||||
|
||||
IntStream.range(0, maxActions).forEach(i -> {
|
||||
assignDistributionSet(i % 2 == 0 ? ds1 : ds2, testTargets);
|
||||
});
|
||||
|
||||
// change the distribution set one last time to trigger a quota hit
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> assignDistributionSet(ds3, testTargets));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Assigns the same distribution set to many targets until the 'max targets per manual assignment' quota is exceeded.")
|
||||
public void assignDistributionSetUntilQuotaIsExceeded() {
|
||||
|
||||
final int maxTargets = quotaManagement.getMaxTargetsPerManualAssignment();
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet();
|
||||
|
||||
assignDistributionSet(ds, testdataFactory.createTargets(maxTargets, "ok"));
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> assignDistributionSet(ds, testdataFactory.createTargets(maxTargets + 1, "fail")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test verifies that action-states of an action are found by using id-based search.")
|
||||
public void findActionStatusByActionId() {
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedE
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
|
||||
@@ -42,6 +43,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSe
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.MetaData;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
@@ -333,6 +335,51 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(createdMetadata.getValue()).isEqualTo(knownValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies the enforcement of the metadata quota per distribution set.")
|
||||
public void createDistributionSetMetadataUntilQuotaIsExceeded() {
|
||||
|
||||
// add meta data one by one
|
||||
final DistributionSet ds1 = testdataFactory.createDistributionSet("ds1");
|
||||
final int maxMetaData = quotaManagement.getMaxMetaDataEntriesPerDistributionSet();
|
||||
for (int i = 0; i < maxMetaData; ++i) {
|
||||
assertThat((JpaDistributionSetMetadata) createDistributionSetMetadata(ds1.getId(),
|
||||
new JpaDistributionSetMetadata("k" + i, ds1, "v" + i))).isNotNull();
|
||||
}
|
||||
|
||||
// quota exceeded
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> createDistributionSetMetadata(ds1.getId(), createDistributionSetMetadata(ds1.getId(),
|
||||
new JpaDistributionSetMetadata("k" + maxMetaData, ds1, "v" + maxMetaData))));
|
||||
|
||||
// add multiple meta data entries at once
|
||||
final DistributionSet ds2 = testdataFactory.createDistributionSet("ds2");
|
||||
final List<MetaData> metaData2 = new ArrayList<>();
|
||||
for (int i = 0; i < maxMetaData + 1; ++i) {
|
||||
metaData2.add(new JpaDistributionSetMetadata("k" + i, ds2, "v" + i));
|
||||
}
|
||||
// verify quota is exceeded
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> createDistributionSetMetadata(ds2.getId(), metaData2));
|
||||
|
||||
// add some meta data entries
|
||||
final DistributionSet ds3 = testdataFactory.createDistributionSet("ds3");
|
||||
final int firstHalf = Math.round(maxMetaData / 2);
|
||||
for (int i = 0; i < firstHalf; ++i) {
|
||||
createDistributionSetMetadata(ds3.getId(), new JpaDistributionSetMetadata("k" + i, ds3, "v" + i));
|
||||
}
|
||||
// add too many data entries
|
||||
final int secondHalf = maxMetaData - firstHalf;
|
||||
final List<MetaData> metaData3 = new ArrayList<>();
|
||||
for (int i = 0; i < secondHalf + 1; ++i) {
|
||||
metaData3.add(new JpaDistributionSetMetadata("kk" + i, ds3, "vv" + i));
|
||||
}
|
||||
// verify quota is exceeded
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> createDistributionSetMetadata(ds3.getId(), metaData3));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that distribution sets can assigned and unassigned to a distribution set tag.")
|
||||
public void assignAndUnassignDistributionSetToTag() {
|
||||
@@ -400,8 +447,8 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Description("Ensures that it is not possible to add a software module that is not defined of the DS's type.")
|
||||
public void updateDistributionSetUnsupportedModuleFails() {
|
||||
final DistributionSet set = distributionSetManagement
|
||||
.create(entityFactory.distributionSet().create().name("agent-hub2")
|
||||
.version(
|
||||
.create(entityFactory
|
||||
.distributionSet().create().name("agent-hub2").version(
|
||||
"1.0.5")
|
||||
.type(distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
|
||||
.key("test").name("test").mandatory(Arrays.asList(osType.getId()))).getKey()));
|
||||
@@ -443,6 +490,46 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(ds.isRequiredMigrationStep()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies the enforcement of the software module quota per distribution set.")
|
||||
public void assignSoftwareModulesUntilQuotaIsExceeded() {
|
||||
|
||||
// create some software modules
|
||||
final int maxModules = quotaManagement.getMaxSoftwareModulesPerDistributionSet();
|
||||
final List<Long> modules = Lists.newArrayList();
|
||||
for (int i = 0; i < maxModules + 1; ++i) {
|
||||
modules.add(testdataFactory.createSoftwareModuleApp("sm" + i).getId());
|
||||
}
|
||||
|
||||
// assign software modules one by one
|
||||
final DistributionSet ds1 = testdataFactory.createDistributionSetWithNoSoftwareModules("ds1", "1.0");
|
||||
for (int i = 0; i < maxModules; ++i) {
|
||||
distributionSetManagement.assignSoftwareModules(ds1.getId(), Collections.singletonList(modules.get(i)));
|
||||
}
|
||||
// add one more to cause the quota to be exceeded
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> {
|
||||
distributionSetManagement.assignSoftwareModules(ds1.getId(),
|
||||
Collections.singletonList(modules.get(maxModules)));
|
||||
});
|
||||
|
||||
// assign all software modules at once
|
||||
final DistributionSet ds2 = testdataFactory.createDistributionSetWithNoSoftwareModules("ds2", "1.0");
|
||||
// verify quota is exceeded
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> distributionSetManagement.assignSoftwareModules(ds2.getId(), modules));
|
||||
|
||||
// assign some software modules
|
||||
final DistributionSet ds3 = testdataFactory.createDistributionSetWithNoSoftwareModules("ds3", "1.0");
|
||||
final int firstHalf = Math.round(maxModules / 2);
|
||||
for (int i = 0; i < firstHalf; ++i) {
|
||||
distributionSetManagement.assignSoftwareModules(ds3.getId(), Collections.singletonList(modules.get(i)));
|
||||
}
|
||||
// assign the remaining modules to cause the quota to be exceeded
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> distributionSetManagement
|
||||
.assignSoftwareModules(ds3.getId(), modules.subList(firstHalf, modules.size())));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUser(allSpPermissions = true)
|
||||
@Description("Checks that metadata for a distribution set can be updated.")
|
||||
@@ -491,7 +578,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
final Iterator<DistributionSet> dsIterator = buildDistributionSets.iterator();
|
||||
final Iterator<Target> tIterator = buildTargetFixtures.iterator();
|
||||
final DistributionSet dsFirst = dsIterator.next();
|
||||
dsIterator.next();
|
||||
final DistributionSet dsSecond = dsIterator.next();
|
||||
final DistributionSet dsThree = dsIterator.next();
|
||||
final DistributionSet dsFour = dsIterator.next();
|
||||
@@ -775,7 +862,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
new JpaDistributionSetMetadata("key" + index, ds1, "value" + index));
|
||||
}
|
||||
|
||||
for (int index = 0; index < 20; index++) {
|
||||
for (int index = 0; index < 8; index++) {
|
||||
createDistributionSetMetadata(ds2.getId(),
|
||||
new JpaDistributionSetMetadata("key" + index, ds2, "value" + index));
|
||||
}
|
||||
@@ -789,8 +876,8 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(metadataOfDs1.getNumberOfElements()).isEqualTo(10);
|
||||
assertThat(metadataOfDs1.getTotalElements()).isEqualTo(10);
|
||||
|
||||
assertThat(metadataOfDs2.getNumberOfElements()).isEqualTo(20);
|
||||
assertThat(metadataOfDs2.getTotalElements()).isEqualTo(20);
|
||||
assertThat(metadataOfDs2.getNumberOfElements()).isEqualTo(8);
|
||||
assertThat(metadataOfDs2.getTotalElements()).isEqualTo(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -8,17 +8,26 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTypeCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
@@ -28,10 +37,6 @@ import org.junit.Test;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Step;
|
||||
@@ -193,7 +198,7 @@ public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTes
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the successfull module update of unused distribution set type which is in fact allowed.")
|
||||
@Description("Tests the successful module update of unused distribution set type which is in fact allowed.")
|
||||
public void updateUnassignedDistributionSetTypeModules() {
|
||||
final DistributionSetType updatableType = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("updatableType").name("to be deleted"));
|
||||
@@ -217,6 +222,55 @@ public class DistributionSetTypeManagementTest extends AbstractJpaIntegrationTes
|
||||
.containsOnly(runtimeType);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that the quota for software module types per distribution set type is enforced as expected.")
|
||||
public void quotaMaxSoftwareModuleTypes() {
|
||||
|
||||
final int quota = quotaManagement.getMaxSoftwareModuleTypesPerDistributionSetType();
|
||||
// create software module types
|
||||
final List<Long> moduleTypeIds = Lists.newArrayList();
|
||||
for (int i = 0; i < quota + 1; ++i) {
|
||||
final SoftwareModuleTypeCreate smCreate = entityFactory.softwareModuleType().create().name("smType_" + i)
|
||||
.description("smType_" + i).maxAssignments(1).colour("blue").key("smType_" + i);
|
||||
moduleTypeIds.add(softwareModuleTypeManagement.create(smCreate).getId());
|
||||
}
|
||||
|
||||
// assign all types at once
|
||||
final DistributionSetType dsType1 = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("dst1").name("dst1"));
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(
|
||||
() -> distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(dsType1.getId(), moduleTypeIds));
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(
|
||||
() -> distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(dsType1.getId(), moduleTypeIds));
|
||||
|
||||
// assign as many mandatory modules as possible
|
||||
final DistributionSetType dsType2 = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("dst2").name("dst2"));
|
||||
distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(dsType2.getId(),
|
||||
moduleTypeIds.subList(0, quota));
|
||||
assertThat(distributionSetTypeManagement.get(dsType2.getId())).isNotEmpty();
|
||||
assertThat(distributionSetTypeManagement.get(dsType2.getId()).get().getMandatoryModuleTypes().size())
|
||||
.isEqualTo(quota);
|
||||
// assign one more to trigger the quota exceeded error
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> distributionSetTypeManagement.assignMandatorySoftwareModuleTypes(dsType2.getId(),
|
||||
Collections.singletonList(moduleTypeIds.get(quota))));
|
||||
|
||||
// assign as many optional modules as possible
|
||||
final DistributionSetType dsType3 = distributionSetTypeManagement
|
||||
.create(entityFactory.distributionSetType().create().key("dst3").name("dst3"));
|
||||
distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(dsType3.getId(),
|
||||
moduleTypeIds.subList(0, quota));
|
||||
assertThat(distributionSetTypeManagement.get(dsType3.getId())).isNotEmpty();
|
||||
assertThat(distributionSetTypeManagement.get(dsType3.getId()).get().getOptionalModuleTypes().size())
|
||||
.isEqualTo(quota);
|
||||
// assign one more to trigger the quota exceeded error
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> distributionSetTypeManagement.assignOptionalSoftwareModuleTypes(dsType3.getId(),
|
||||
Collections.singletonList(moduleTypeIds.get(quota))));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the successfull update of used distribution set type meta data which is in fact allowed.")
|
||||
public void updateAssignedDistributionSetTypeMetaData() {
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -39,6 +42,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||
@@ -70,9 +74,6 @@ import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Step;
|
||||
@@ -1257,6 +1258,87 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
validateRolloutActionStatus(myRollout.getId(), expectedTargetCountStatus);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that a rollout cannot be created if the 'max targets per rollout group' quota is violated.")
|
||||
public void createRolloutFailsIfQuotaGroupQuotaIsViolated() throws Exception {
|
||||
|
||||
final int maxTargets = quotaManagement.getMaxTargetsPerRolloutGroup();
|
||||
|
||||
final int amountTargetsForRollout = maxTargets + 1;
|
||||
final int amountGroups = 1;
|
||||
final String successCondition = "50";
|
||||
final String errorCondition = "80";
|
||||
final String rolloutName = "rolloutTest";
|
||||
final String targetPrefixName = rolloutName;
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
|
||||
testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName);
|
||||
|
||||
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults()
|
||||
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition)
|
||||
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition)
|
||||
.errorAction(RolloutGroupErrorAction.PAUSE, null).build();
|
||||
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> rolloutManagement.create(
|
||||
entityFactory.rollout().create().name(rolloutName).description(rolloutName)
|
||||
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet),
|
||||
amountGroups, conditions));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify that a rollout cannot be created based on group definitions if the 'max targets per rollout group' quota is violated for one of the groups.")
|
||||
public void createRolloutWithGroupDefinitionsFailsIfQuotaGroupQuotaIsViolated() throws Exception {
|
||||
|
||||
final int maxTargets = quotaManagement.getMaxTargetsPerRolloutGroup();
|
||||
|
||||
final int amountTargetsForRollout = maxTargets * 2 + 2;
|
||||
final String rolloutName = "rolloutTest";
|
||||
final String targetPrefixName = rolloutName;
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet("dsFor" + rolloutName);
|
||||
testdataFactory.createTargets(amountTargetsForRollout, targetPrefixName + "-", targetPrefixName);
|
||||
|
||||
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
|
||||
|
||||
// create group definitions
|
||||
final RolloutGroupCreate group1 = entityFactory.rolloutGroup().create().conditions(conditions).name("group1")
|
||||
.targetPercentage(50.0F);
|
||||
final RolloutGroupCreate group2 = entityFactory.rolloutGroup().create().conditions(conditions).name("group2")
|
||||
.targetPercentage(100.0F);
|
||||
|
||||
// group1 exceeds the quota
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> rolloutManagement.create(
|
||||
entityFactory.rollout().create().name(rolloutName).description(rolloutName)
|
||||
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet),
|
||||
Arrays.asList(group1, group2), conditions));
|
||||
|
||||
// create group definitions
|
||||
final RolloutGroupCreate group3 = entityFactory.rolloutGroup().create().conditions(conditions).name("group3")
|
||||
.targetPercentage(1.0F);
|
||||
final RolloutGroupCreate group4 = entityFactory.rolloutGroup().create().conditions(conditions).name("group4")
|
||||
.targetPercentage(100.0F);
|
||||
|
||||
// group4 exceeds the quota
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> rolloutManagement.create(
|
||||
entityFactory.rollout().create().name(rolloutName).description(rolloutName)
|
||||
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet),
|
||||
Arrays.asList(group3, group4), conditions));
|
||||
|
||||
// create group definitions
|
||||
final RolloutGroupCreate group5 = entityFactory.rolloutGroup().create().conditions(conditions).name("group5")
|
||||
.targetPercentage(33.3F);
|
||||
final RolloutGroupCreate group6 = entityFactory.rolloutGroup().create().conditions(conditions).name("group6")
|
||||
.targetPercentage(66.6F);
|
||||
final RolloutGroupCreate group7 = entityFactory.rolloutGroup().create().conditions(conditions).name("group7")
|
||||
.targetPercentage(100.0F);
|
||||
|
||||
// should work fine
|
||||
assertThat(rolloutManagement.create(
|
||||
entityFactory.rollout().create().name(rolloutName).description(rolloutName)
|
||||
.targetFilterQuery("controllerId==" + targetPrefixName + "-*").set(distributionSet),
|
||||
Arrays.asList(group5, group6, group7), conditions)).isNotNull();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify the creation and the automatic start of a rollout.")
|
||||
public void createAndAutoStartRollout() throws Exception {
|
||||
@@ -1308,7 +1390,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify the creation of a Rollout with a groups definition.")
|
||||
@Description("Verify the creation of a rollout with a groups definition.")
|
||||
public void createRolloutWithGroupDefinition() throws Exception {
|
||||
final String rolloutName = "rolloutTest3";
|
||||
|
||||
@@ -1355,7 +1437,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(myRollout.getTotalTargets()).isEqualTo(amountTargetsInGroup1and2 + amountTargetsInGroup1);
|
||||
|
||||
final List<RolloutGroup> groups = rolloutGroupManagement.findByRollout(PAGE, myRollout.getId()).getContent();
|
||||
;
|
||||
|
||||
assertThat(groups.get(0).getStatus()).isEqualTo(RolloutGroupStatus.READY);
|
||||
assertThat(groups.get(0).getTotalTargets()).isEqualTo(amountTargetsInGroup1);
|
||||
|
||||
@@ -1368,7 +1450,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify Exception when a Rollout with Group definition is created that does not address all targets")
|
||||
@Description("Verify rollout creation fails if group definition does not address all targets")
|
||||
public void createRolloutWithGroupsNotMatchingTargets() throws Exception {
|
||||
final String rolloutName = "rolloutTest4";
|
||||
final int amountTargetsForRollout = 500;
|
||||
@@ -1389,7 +1471,7 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify Exception when a Rollout with Group definition is created that contains an illegal percentage")
|
||||
@Description("Verify rollout creation fails if group definition specifies illegal target percentage")
|
||||
public void createRolloutWithIllegalPercentage() throws Exception {
|
||||
final String rolloutName = "rolloutTest6";
|
||||
final int amountTargetsForRollout = 10;
|
||||
@@ -1410,18 +1492,18 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verify Exception when a Rollout is created with too much groups")
|
||||
@Description("Verify rollout creation fails if the 'max rollout groups per rollout' quota is violated.")
|
||||
public void createRolloutWithIllegalAmountOfGroups() throws Exception {
|
||||
final String rolloutName = "rolloutTest5";
|
||||
final int amountTargetsForRollout = 10;
|
||||
final int illegalGroupAmount = 501;
|
||||
final int targets = 10;
|
||||
final int maxGroups = quotaManagement.getMaxRolloutGroupsPerRollout();
|
||||
|
||||
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder().withDefaults().build();
|
||||
final RolloutCreate myRollout = generateTargetsAndRollout(rolloutName, amountTargetsForRollout);
|
||||
final RolloutCreate rollout = generateTargetsAndRollout(rolloutName, targets);
|
||||
|
||||
assertThatExceptionOfType(ValidationException.class)
|
||||
.isThrownBy(() -> rolloutManagement.create(myRollout, illegalGroupAmount, conditions))
|
||||
.withMessageContaining("not be greater than " + quotaManagement.getMaxRolloutGroupsPerRollout());
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> rolloutManagement.create(rollout, maxGroups + 1, conditions))
|
||||
.withMessageContaining("not be greater than " + maxGroups);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -23,6 +24,7 @@ import org.apache.commons.lang3.RandomUtils;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
@@ -361,13 +363,14 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
public void deleteSoftwareModulesWithSharedArtifact() throws IOException {
|
||||
|
||||
// Init artifact binary data, target and DistributionSets
|
||||
final byte[] source = RandomUtils.nextBytes(1024);
|
||||
final int artifactSize = 1024;
|
||||
final byte[] source = RandomUtils.nextBytes(artifactSize);
|
||||
|
||||
// [STEP1]: Create SoftwareModuleX and add a new ArtifactX
|
||||
SoftwareModule moduleX = createSoftwareModuleWithArtifacts(osType, "modulex", "v1.0", 0);
|
||||
|
||||
// [STEP2]: Create newArtifactX and add it to SoftwareModuleX
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleX.getId(), "artifactx", false);
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleX.getId(), "artifactx", false, artifactSize);
|
||||
moduleX = softwareModuleManagement.get(moduleX.getId()).get();
|
||||
final Artifact artifactX = moduleX.getArtifacts().iterator().next();
|
||||
|
||||
@@ -375,7 +378,7 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
SoftwareModule moduleY = createSoftwareModuleWithArtifacts(osType, "moduley", "v1.0", 0);
|
||||
|
||||
// [STEP4]: Assign the same ArtifactX to SoftwareModuleY
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleY.getId(), "artifactx", false);
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleY.getId(), "artifactx", false, artifactSize);
|
||||
moduleY = softwareModuleManagement.get(moduleY.getId()).get();
|
||||
final Artifact artifactY = moduleY.getArtifacts().iterator().next();
|
||||
|
||||
@@ -403,20 +406,21 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
public void deleteMultipleSoftwareModulesWhichShareAnArtifact() throws IOException {
|
||||
|
||||
// Init artifact binary data, target and DistributionSets
|
||||
final byte[] source = RandomUtils.nextBytes(1024);
|
||||
final int artifactSize = 1024;
|
||||
final byte[] source = RandomUtils.nextBytes(artifactSize);
|
||||
final Target target = testdataFactory.createTarget();
|
||||
|
||||
// [STEP1]: Create SoftwareModuleX and add a new ArtifactX
|
||||
SoftwareModule moduleX = createSoftwareModuleWithArtifacts(osType, "modulex", "v1.0", 0);
|
||||
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleX.getId(), "artifactx", false);
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleX.getId(), "artifactx", false, artifactSize);
|
||||
moduleX = softwareModuleManagement.get(moduleX.getId()).get();
|
||||
final Artifact artifactX = moduleX.getArtifacts().iterator().next();
|
||||
|
||||
// [STEP2]: Create SoftwareModuleY and add the same ArtifactX
|
||||
SoftwareModule moduleY = createSoftwareModuleWithArtifacts(osType, "moduley", "v1.0", 0);
|
||||
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleY.getId(), "artifactx", false);
|
||||
artifactManagement.create(new ByteArrayInputStream(source), moduleY.getId(), "artifactx", false, artifactSize);
|
||||
moduleY = softwareModuleManagement.get(moduleY.getId()).get();
|
||||
final Artifact artifactY = moduleY.getArtifacts().iterator().next();
|
||||
|
||||
@@ -462,9 +466,10 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
SoftwareModule softwareModule = softwareModuleManagement.create(entityFactory.softwareModule().create()
|
||||
.type(type).name(name).version(version).description("description of artifact " + name));
|
||||
|
||||
final int artifactSize = 5 * 1024;
|
||||
for (int i = 0; i < numberArtifacts; i++) {
|
||||
artifactManagement.create(new RandomGeneratedInputStream(5 * 1024), softwareModule.getId(),
|
||||
"file" + (i + 1), false);
|
||||
artifactManagement.create(new RandomGeneratedInputStream(artifactSize), softwareModule.getId(),
|
||||
"file" + (i + 1), false, artifactSize);
|
||||
}
|
||||
|
||||
// Verify correct Creation of SoftwareModule and corresponding artifacts
|
||||
@@ -652,14 +657,58 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
assertThat(softwareModuleMetadata.get(0).getEntityId()).isEqualTo(ah.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies the enforcement of the metadata quota per software module.")
|
||||
public void createSoftwareModuleMetadataUntilQuotaIsExceeded() {
|
||||
|
||||
// add meta data one by one
|
||||
final SoftwareModule module = testdataFactory.createSoftwareModuleApp("m1");
|
||||
final int maxMetaData = quotaManagement.getMaxMetaDataEntriesPerSoftwareModule();
|
||||
for (int i = 0; i < maxMetaData; ++i) {
|
||||
softwareModuleManagement.createMetaData(
|
||||
entityFactory.softwareModuleMetadata().create(module.getId()).key("k" + i).value("v" + i));
|
||||
}
|
||||
|
||||
// quota exceeded
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata()
|
||||
.create(module.getId()).key("k" + maxMetaData).value("v" + maxMetaData)));
|
||||
|
||||
// add multiple meta data entries at once
|
||||
final SoftwareModule module2 = testdataFactory.createSoftwareModuleApp("m2");
|
||||
final List<SoftwareModuleMetadataCreate> create = new ArrayList<>();
|
||||
for (int i = 0; i < maxMetaData + 1; ++i) {
|
||||
create.add(entityFactory.softwareModuleMetadata().create(module2.getId()).key("k" + i).value("v" + i));
|
||||
}
|
||||
// quota exceeded
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.createMetaData(create));
|
||||
|
||||
// add some meta data entries
|
||||
final SoftwareModule module3 = testdataFactory.createSoftwareModuleApp("m3");
|
||||
final int firstHalf = Math.round(maxMetaData / 2);
|
||||
for (int i = 0; i < firstHalf; ++i) {
|
||||
softwareModuleManagement.createMetaData(
|
||||
entityFactory.softwareModuleMetadata().create(module3.getId()).key("k" + i).value("v" + i));
|
||||
}
|
||||
// add too many data entries
|
||||
final int secondHalf = maxMetaData - firstHalf;
|
||||
final List<SoftwareModuleMetadataCreate> create2 = new ArrayList<>();
|
||||
for (int i = 0; i < secondHalf + 1; ++i) {
|
||||
create2.add(entityFactory.softwareModuleMetadata().create(module3.getId()).key("kk" + i).value("vv" + i));
|
||||
}
|
||||
// quota exceeded
|
||||
assertThatExceptionOfType(QuotaExceededException.class)
|
||||
.isThrownBy(() -> softwareModuleManagement.createMetaData(create2));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Checks that metadata for a software module cannot be created for an existing key.")
|
||||
public void createSoftwareModuleMetadataFailsIfKeyExists() {
|
||||
|
||||
final String knownKey1 = "myKnownKey1";
|
||||
final String knownValue1 = "myKnownValue1";
|
||||
final String knownValue2 = "myKnownValue2";
|
||||
|
||||
final SoftwareModule ah = testdataFactory.createSoftwareModuleApp();
|
||||
|
||||
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(ah.getId()).key(knownKey1)
|
||||
@@ -765,41 +814,43 @@ public class SoftwareModuleManagementTest extends AbstractJpaIntegrationTest {
|
||||
public void findAllSoftwareModuleMetadataBySwId() {
|
||||
|
||||
final SoftwareModule sw1 = testdataFactory.createSoftwareModuleApp();
|
||||
final int metadataCountSw1 = 8;
|
||||
|
||||
final SoftwareModule sw2 = testdataFactory.createSoftwareModuleOs();
|
||||
final int metadataCountSw2 = 10;
|
||||
|
||||
for (int index = 0; index < 10; index++) {
|
||||
for (int index = 0; index < metadataCountSw1; index++) {
|
||||
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(sw1.getId())
|
||||
.key("key" + index).value("value" + index).targetVisible(true));
|
||||
}
|
||||
|
||||
for (int index = 0; index < 20; index++) {
|
||||
for (int index = 0; index < metadataCountSw2; index++) {
|
||||
softwareModuleManagement.createMetaData(entityFactory.softwareModuleMetadata().create(sw2.getId())
|
||||
.key("key" + index).value("value" + index).targetVisible(false));
|
||||
}
|
||||
|
||||
Page<SoftwareModuleMetadata> metadataOfSw1 = softwareModuleManagement
|
||||
Page<SoftwareModuleMetadata> metadataSw1 = softwareModuleManagement
|
||||
.findMetaDataBySoftwareModuleId(new PageRequest(0, 100), sw1.getId());
|
||||
|
||||
Page<SoftwareModuleMetadata> metadataOfSw2 = softwareModuleManagement
|
||||
Page<SoftwareModuleMetadata> metadataSw2 = softwareModuleManagement
|
||||
.findMetaDataBySoftwareModuleId(new PageRequest(0, 100), sw2.getId());
|
||||
|
||||
assertThat(metadataOfSw1.getNumberOfElements()).isEqualTo(10);
|
||||
assertThat(metadataOfSw1.getTotalElements()).isEqualTo(10);
|
||||
assertThat(metadataSw1.getNumberOfElements()).isEqualTo(metadataCountSw1);
|
||||
assertThat(metadataSw1.getTotalElements()).isEqualTo(metadataCountSw1);
|
||||
|
||||
assertThat(metadataOfSw2.getNumberOfElements()).isEqualTo(20);
|
||||
assertThat(metadataOfSw2.getTotalElements()).isEqualTo(20);
|
||||
assertThat(metadataSw2.getNumberOfElements()).isEqualTo(metadataCountSw2);
|
||||
assertThat(metadataSw2.getTotalElements()).isEqualTo(metadataCountSw2);
|
||||
|
||||
metadataOfSw1 = softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(new PageRequest(0, 100),
|
||||
metadataSw1 = softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(new PageRequest(0, 100),
|
||||
sw1.getId());
|
||||
|
||||
metadataOfSw2 = softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(new PageRequest(0, 100),
|
||||
metadataSw2 = softwareModuleManagement.findMetaDataBySoftwareModuleIdAndTargetVisible(new PageRequest(0, 100),
|
||||
sw2.getId());
|
||||
|
||||
assertThat(metadataOfSw1.getNumberOfElements()).isEqualTo(10);
|
||||
assertThat(metadataOfSw1.getTotalElements()).isEqualTo(10);
|
||||
assertThat(metadataSw1.getNumberOfElements()).isEqualTo(metadataCountSw1);
|
||||
assertThat(metadataSw1.getTotalElements()).isEqualTo(metadataCountSw1);
|
||||
|
||||
assertThat(metadataOfSw2.getNumberOfElements()).isEqualTo(0);
|
||||
assertThat(metadataOfSw2.getTotalElements()).isEqualTo(0);
|
||||
assertThat(metadataSw2.getNumberOfElements()).isEqualTo(0);
|
||||
assertThat(metadataSw2.getTotalElements()).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,13 +134,13 @@ public class SystemManagementTest extends AbstractJpaIntegrationTest {
|
||||
private void createTestArtifact(final byte[] random) {
|
||||
final SoftwareModule sm = testdataFactory.createSoftwareModuleOs();
|
||||
|
||||
artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1", false);
|
||||
artifactManagement.create(new ByteArrayInputStream(random), sm.getId(), "file1", false, random.length);
|
||||
}
|
||||
|
||||
private void createDeletedTestArtifact(final byte[] random) {
|
||||
final DistributionSet ds = testdataFactory.createDistributionSet("deleted garbage", true);
|
||||
ds.getModules().stream().forEach(module -> {
|
||||
artifactManagement.create(new ByteArrayInputStream(random), module.getId(), "file1", false);
|
||||
artifactManagement.create(new ByteArrayInputStream(random), module.getId(), "file1", false, random.length);
|
||||
softwareModuleManagement.delete(module.getId());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
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.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@@ -24,6 +26,7 @@ import org.eclipse.hawkbit.repository.event.remote.entity.SoftwareModuleCreatedE
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetFilterQueryCreatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
@@ -34,8 +37,6 @@ import org.junit.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
@@ -97,6 +98,20 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
targetFilterQueryManagement.getByName(filterName).get());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Create a target filter query with an auto-assign distribution set and a query string that addresses too many targets.")
|
||||
public void createTargetFilterQueryThatExceedsQuota() {
|
||||
|
||||
// create targets
|
||||
final int maxTargets = quotaManagement.getMaxTargetsPerAutoAssignment();
|
||||
testdataFactory.createTargets(maxTargets + 1, "target%s");
|
||||
final DistributionSet set = testdataFactory.createDistributionSet();
|
||||
|
||||
// creation is supposed to work as there is no distribution set
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("testfilter").set(set.getId()).query("name==target*")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test searching a target filter query.")
|
||||
public void searchTargetFilterQuery() {
|
||||
@@ -181,6 +196,43 @@ public class TargetFilterQueryManagementTest extends AbstractJpaIntegrationTest
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Assigns a distribution set to an existing filter query and verifies that the quota 'max targets per auto assignment' is enforced.")
|
||||
public void assignDistributionSetToTargetFilterQueryThatExceedsQuota() {
|
||||
|
||||
// create targets
|
||||
final int maxTargets = quotaManagement.getMaxTargetsPerAutoAssignment();
|
||||
testdataFactory.createTargets(maxTargets + 1, "target%s");
|
||||
final DistributionSet distributionSet = testdataFactory.createDistributionSet();
|
||||
|
||||
// creation is supposed to work as there is no distribution set
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement
|
||||
.create(entityFactory.targetFilterQuery().create().name("testfilter").query("name==target*"));
|
||||
|
||||
// assigning a distribution set is supposed to fail as the query
|
||||
// addresses too many targets
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> targetFilterQueryManagement
|
||||
.updateAutoAssignDS(targetFilterQuery.getId(), distributionSet.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Updates an existing filter query with a query string that addresses too many targets.")
|
||||
public void updateTargetFilterQueryWithQueryThatExceedsQuota() {
|
||||
|
||||
// create targets
|
||||
final int maxTargets = quotaManagement.getMaxTargetsPerAutoAssignment();
|
||||
testdataFactory.createTargets(maxTargets + 1, "target%s");
|
||||
final DistributionSet set = testdataFactory.createDistributionSet();
|
||||
|
||||
// creation is supposed to work as the query does not exceed the quota
|
||||
final TargetFilterQuery targetFilterQuery = targetFilterQueryManagement.create(
|
||||
entityFactory.targetFilterQuery().create().name("testfilter").set(set.getId()).query("name==foo"));
|
||||
|
||||
// update with a query string that addresses too many targets
|
||||
assertThatExceptionOfType(QuotaExceededException.class).isThrownBy(() -> targetFilterQueryManagement
|
||||
.update(entityFactory.targetFilterQuery().update(targetFilterQuery.getId()).query("name==target*")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test removing distribution set while it has a relation to a target filter query")
|
||||
public void removeAssignDistributionSet() {
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
# Quota - START
|
||||
hawkbit.server.security.dos.maxStatusEntriesPerAction=10
|
||||
hawkbit.server.security.dos.maxAttributeEntriesPerTarget=10
|
||||
hawkbit.server.security.dos.maxMetaDataEntriesPerSoftwareModule=10
|
||||
hawkbit.server.security.dos.maxRolloutGroupsPerRollout=20
|
||||
hawkbit.server.security.dos.maxMessagesPerActionStatus=10
|
||||
hawkbit.server.security.dos.maxMetaDataEntriesPerDistributionSet=10
|
||||
hawkbit.server.security.dos.maxSoftwareModuleTypesPerDistributionSetType=10
|
||||
hawkbit.server.security.dos.maxSoftwareModulesPerDistributionSet=10
|
||||
hawkbit.server.security.dos.maxArtifactsPerSoftwareModule=10
|
||||
hawkbit.server.security.dos.maxTargetsPerRolloutGroup=1000
|
||||
hawkbit.server.security.dos.maxArtifactSize=1000000
|
||||
# Quota - END
|
||||
|
||||
# Debug utility functions - START
|
||||
|
||||
Reference in New Issue
Block a user