DDI supports sha256 (#869)
* Add SHA256 file hash to ddi GET outputs Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com> * Integrate review findings for SHA256 changes Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com> * Renamed hashes to base16hases in store() parameters Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com> * Added missing javadoc according to sonarqube findings Signed-off-by: Alexander Dobler <alexander.dobler3@bosch-si.com>
This commit is contained in:
committed by
Dominic Schabel
parent
fba6cf9787
commit
bde3548846
@@ -62,16 +62,14 @@ public class ArtifactFilesystemRepository extends AbstractArtifactRepository {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ArtifactFilesystem(file, sha1, new DbArtifactHash(sha1, null), file.length(), null);
|
||||
return new ArtifactFilesystem(file, sha1, new DbArtifactHash(sha1, null, null), file.length(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractDbArtifact store(final String tenant, final String sha1Hash16, final String mdMD5Hash16,
|
||||
final String contentType, final String tempFile) throws IOException {
|
||||
protected AbstractDbArtifact store(final String tenant, final DbArtifactHash base16Hashes, final String contentType, final String tempFile) throws IOException {
|
||||
|
||||
final File file = new File(tempFile);
|
||||
return renameFileToSHA1Naming(tenant, file, new ArtifactFilesystem(file, sha1Hash16,
|
||||
new DbArtifactHash(sha1Hash16, mdMD5Hash16), file.length(), contentType));
|
||||
return renameFileToSHA1Naming(tenant, file, new ArtifactFilesystem(file, base16Hashes.getSha1(), base16Hashes, file.length(), contentType));
|
||||
}
|
||||
|
||||
private ArtifactFilesystem renameFileToSHA1Naming(final String tenant, final File file,
|
||||
|
||||
@@ -32,7 +32,7 @@ public class ArtifactFilesystemTest {
|
||||
public void getInputStreamOfNonExistingFileThrowsException() {
|
||||
final File file = new File("fileWhichTotalDoesNotExists");
|
||||
final ArtifactFilesystem underTest = new ArtifactFilesystem(file, "fileWhichTotalDoesNotExists",
|
||||
new DbArtifactHash("1", "2"), 0L, null);
|
||||
new DbArtifactHash("1", "2", "3"), 0L, null);
|
||||
try {
|
||||
underTest.getFileInputStream();
|
||||
Assertions.fail("Expected a FileNotFoundException because file does not exists");
|
||||
@@ -48,7 +48,7 @@ public class ArtifactFilesystemTest {
|
||||
createTempFile.deleteOnExit();
|
||||
|
||||
final ArtifactFilesystem underTest = new ArtifactFilesystem(createTempFile,
|
||||
ArtifactFilesystemTest.class.getSimpleName(), new DbArtifactHash("1", "2"), 0L, null);
|
||||
ArtifactFilesystemTest.class.getSimpleName(), new DbArtifactHash("1", "2", "3"), 0L, null);
|
||||
final byte[] buffer = new byte[1024];
|
||||
IOUtils.read(underTest.getFileInputStream(), buffer);
|
||||
}
|
||||
|
||||
@@ -42,27 +42,31 @@ public abstract class AbstractArtifactRepository implements ArtifactRepository {
|
||||
// is not used security related
|
||||
@SuppressWarnings("squid:S2070")
|
||||
public AbstractDbArtifact store(final String tenant, final InputStream content, final String filename,
|
||||
final String contentType, final DbArtifactHash hash) {
|
||||
final String contentType, final DbArtifactHash providedHashes) {
|
||||
final MessageDigest mdSHA1;
|
||||
final MessageDigest mdMD5;
|
||||
final MessageDigest mdSHA256;
|
||||
try {
|
||||
mdSHA1 = MessageDigest.getInstance("SHA1");
|
||||
mdMD5 = MessageDigest.getInstance("MD5");
|
||||
mdSHA256 = MessageDigest.getInstance("SHA-256");
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
throw new ArtifactStoreException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
String tempFile = null;
|
||||
try (final DigestInputStream inputstream = wrapInDigestInputStream(content, mdSHA1, mdMD5)) {
|
||||
try (final DigestInputStream inputstream = wrapInDigestInputStream(content, mdSHA1, mdMD5, mdSHA256)) {
|
||||
|
||||
tempFile = storeTempFile(inputstream);
|
||||
|
||||
final String sha1Hash16 = BaseEncoding.base16().lowerCase().encode(mdSHA1.digest());
|
||||
final String md5Hash16 = BaseEncoding.base16().lowerCase().encode(mdMD5.digest());
|
||||
final String sha256Hash16 = BaseEncoding.base16().lowerCase().encode(mdSHA256.digest());
|
||||
|
||||
checkHashes(sha1Hash16, md5Hash16, hash);
|
||||
checkHashes(sha1Hash16, md5Hash16, sha256Hash16, providedHashes);
|
||||
|
||||
return store(sanitizeTenant(tenant), sha1Hash16, md5Hash16, contentType, tempFile);
|
||||
return store(sanitizeTenant(tenant), new DbArtifactHash(sha1Hash16, md5Hash16, sha256Hash16), contentType,
|
||||
tempFile);
|
||||
} catch (final IOException e) {
|
||||
throw new ArtifactStoreException(e.getMessage(), e);
|
||||
} finally {
|
||||
@@ -100,27 +104,35 @@ public abstract class AbstractArtifactRepository implements ArtifactRepository {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkHashes(final String sha1Hash16, final String md5Hash16, final DbArtifactHash hash) {
|
||||
if (hash == null) {
|
||||
private static void checkHashes(final String sha1Hash16, final String md5Hash16, final String sha256Hash16,
|
||||
final DbArtifactHash providedHashes) {
|
||||
if (providedHashes == null) {
|
||||
return;
|
||||
}
|
||||
if (hash.getSha1() != null && !sha1Hash16.equals(hash.getSha1())) {
|
||||
throw new HashNotMatchException("The given sha1 hash " + hash.getSha1()
|
||||
+ " does not match with the calcualted sha1 hash " + sha1Hash16, HashNotMatchException.SHA1);
|
||||
if (areHashesNotMatching(providedHashes.getSha1(), sha1Hash16)) {
|
||||
throw new HashNotMatchException("The given sha1 hash " + providedHashes.getSha1()
|
||||
+ " does not match the calculated sha1 hash " + sha1Hash16, HashNotMatchException.SHA1);
|
||||
}
|
||||
if (hash.getMd5() != null && !md5Hash16.equals(hash.getMd5())) {
|
||||
throw new HashNotMatchException(
|
||||
"The given md5 hash " + hash.getMd5() + " does not match with the calcualted md5 hash " + md5Hash16,
|
||||
HashNotMatchException.MD5);
|
||||
if (areHashesNotMatching(providedHashes.getMd5(), md5Hash16)) {
|
||||
throw new HashNotMatchException("The given md5 hash " + providedHashes.getMd5()
|
||||
+ " does not match the calculated md5 hash " + md5Hash16, HashNotMatchException.MD5);
|
||||
}
|
||||
if (areHashesNotMatching(providedHashes.getSha256(), sha256Hash16)) {
|
||||
throw new HashNotMatchException("The given sha256 hash " + providedHashes.getSha256()
|
||||
+ " does not match the calculated sha256 hash " + sha256Hash16, HashNotMatchException.SHA256);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract AbstractDbArtifact store(final String tenant, final String sha1Hash16, final String mdMD5Hash16,
|
||||
private static boolean areHashesNotMatching(String providedHashValue, String hashValue) {
|
||||
return providedHashValue != null && !hashValue.equals(providedHashValue);
|
||||
}
|
||||
|
||||
protected abstract AbstractDbArtifact store(final String tenant, final DbArtifactHash base16Hashes,
|
||||
final String contentType, final String tempFile) throws IOException;
|
||||
|
||||
private static DigestInputStream wrapInDigestInputStream(final InputStream input, final MessageDigest mdSHA1,
|
||||
final MessageDigest mdMD5) {
|
||||
return new DigestInputStream(new DigestInputStream(input, mdMD5), mdSHA1);
|
||||
final MessageDigest mdMD5, final MessageDigest mdSHA256) {
|
||||
return new DigestInputStream(new DigestInputStream(new DigestInputStream(input, mdSHA256), mdMD5), mdSHA1);
|
||||
}
|
||||
|
||||
protected static String sanitizeTenant(final String tenant) {
|
||||
|
||||
@@ -21,6 +21,7 @@ public class HashNotMatchException extends RuntimeException {
|
||||
|
||||
public static final String SHA1 = "SHA-1";
|
||||
public static final String MD5 = "MD5";
|
||||
public static final String SHA256 = "SHA-256";
|
||||
|
||||
private final String hashFunction;
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ public class DbArtifactHash {
|
||||
|
||||
private final String md5;
|
||||
|
||||
private final String sha256;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@@ -25,10 +27,13 @@ public class DbArtifactHash {
|
||||
* the sha1 hash
|
||||
* @param md5
|
||||
* the md5 hash
|
||||
* @param sha256
|
||||
* the sha256 hash
|
||||
*/
|
||||
public DbArtifactHash(final String sha1, final String md5) {
|
||||
public DbArtifactHash(final String sha1, final String md5, final String sha256) {
|
||||
this.sha1 = sha1;
|
||||
this.md5 = md5;
|
||||
this.sha256 = sha256;
|
||||
}
|
||||
|
||||
public String getSha1() {
|
||||
@@ -39,4 +44,7 @@ public class DbArtifactHash {
|
||||
return md5;
|
||||
}
|
||||
|
||||
public String getSha256() {
|
||||
return sha256;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,14 +167,14 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that download and install event with software moduls and artifacts works")
|
||||
@Description("Verifies that download and install event with software modules and artifacts works")
|
||||
public void testSendDownloadRequest() {
|
||||
DistributionSet dsA = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
|
||||
SoftwareModule module = dsA.getModules().iterator().next();
|
||||
final List<AbstractDbArtifact> receivedList = new ArrayList<>();
|
||||
for (final Artifact artifact : testdataFactory.createArtifacts(module.getId())) {
|
||||
receivedList.add(new ArtifactFilesystem(new File("./test"), artifact.getSha1Hash(),
|
||||
new DbArtifactHash(artifact.getSha1Hash(), null), artifact.getSize(), null));
|
||||
new DbArtifactHash(artifact.getSha1Hash(), null, null), artifact.getSize(), null));
|
||||
}
|
||||
module = softwareModuleManagement.get(module.getId()).get();
|
||||
dsA = distributionSetManagement.get(dsA.getId()).get();
|
||||
|
||||
@@ -38,6 +38,11 @@ public interface Artifact extends TenantAwareBaseEntity {
|
||||
*/
|
||||
String getSha1Hash();
|
||||
|
||||
/**
|
||||
* @return SHA-256 hash of the artifact.
|
||||
*/
|
||||
String getSha256Hash();
|
||||
|
||||
/**
|
||||
* @return size of the artifact in bytes.
|
||||
*/
|
||||
|
||||
@@ -35,6 +35,8 @@ public class ArtifactUpload {
|
||||
|
||||
private final String providedSha1Sum;
|
||||
|
||||
private final String providedSha256Sum;
|
||||
|
||||
private final boolean overrideExisting;
|
||||
|
||||
private final String contentType;
|
||||
@@ -90,6 +92,7 @@ public class ArtifactUpload {
|
||||
this.filename = filename;
|
||||
this.providedMd5Sum = providedMd5Sum;
|
||||
this.providedSha1Sum = providedSha1Sum;
|
||||
this.providedSha256Sum = null;
|
||||
this.overrideExisting = overrideExisting;
|
||||
this.contentType = contentType;
|
||||
this.filesize = filesize;
|
||||
@@ -115,6 +118,10 @@ public class ArtifactUpload {
|
||||
return providedSha1Sum;
|
||||
}
|
||||
|
||||
public String getProvidedSha256Sum() {
|
||||
return providedSha256Sum;
|
||||
}
|
||||
|
||||
public boolean overrideExisting() {
|
||||
return overrideExisting;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
try {
|
||||
return artifactRepository.store(tenantAware.getCurrentTenant(), artifactUpload.getInputStream(),
|
||||
artifactUpload.getFilename(), artifactUpload.getContentType(),
|
||||
new DbArtifactHash(artifactUpload.getProvidedSha1Sum(), artifactUpload.getProvidedMd5Sum()));
|
||||
new DbArtifactHash(artifactUpload.getProvidedSha1Sum(), artifactUpload.getProvidedMd5Sum(), artifactUpload.getProvidedSha256Sum()));
|
||||
} catch (final ArtifactStoreException e) {
|
||||
throw new ArtifactUploadFailedException(e);
|
||||
} catch (final HashNotMatchException e) {
|
||||
@@ -256,6 +256,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
artifact = new JpaArtifact(result.getHashes().getSha1(), providedFilename, softwareModule);
|
||||
}
|
||||
artifact.setMd5Hash(result.getHashes().getMd5());
|
||||
artifact.setSha256Hash(result.getHashes().getSha256());
|
||||
artifact.setSha1Hash(result.getHashes().getSha1());
|
||||
artifact.setSize(result.getSize());
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
||||
@Column(name = "md5_hash", length = 32, updatable = false, nullable = true)
|
||||
private String md5Hash;
|
||||
|
||||
@Column(name = "sha256_hash", length = 64, updatable = false, nullable = true)
|
||||
private String sha256Hash;
|
||||
|
||||
@Column(name = "file_size", updatable = false)
|
||||
private long size;
|
||||
|
||||
@@ -94,6 +97,11 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
||||
return sha1Hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSha256Hash() {
|
||||
return sha256Hash;
|
||||
}
|
||||
|
||||
public void setMd5Hash(final String md5Hash) {
|
||||
this.md5Hash = md5Hash;
|
||||
}
|
||||
@@ -102,6 +110,11 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
|
||||
this.sha1Hash = sha1Hash;
|
||||
}
|
||||
|
||||
public void setSha256Hash(final String sha256Hash) {
|
||||
this.sha256Hash = sha256Hash;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return size;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE sp_artifact ADD COLUMN sha256_hash CHAR(64);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE sp_artifact ADD COLUMN sha256_hash CHAR(64);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE sp_artifact ADD COLUMN sha256_hash CHAR(64);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE sp_artifact ADD sha256_hash CHAR(64);
|
||||
@@ -139,6 +139,8 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTest {
|
||||
.isEqualTo(HashGeneratorUtils.generateSHA1(randomBytes));
|
||||
assertThat(artifactManagement.getByFilename("file1").get().getMd5Hash())
|
||||
.isEqualTo(HashGeneratorUtils.generateMD5(randomBytes));
|
||||
assertThat(artifactManagement.getByFilename("file1").get().getSha256Hash())
|
||||
.isEqualTo(HashGeneratorUtils.generateSHA256(randomBytes));
|
||||
|
||||
assertThat(artifactRepository.findAll()).hasSize(4);
|
||||
assertThat(softwareModuleRepository.findAll()).hasSize(3);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ddi.json.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
@@ -23,6 +25,10 @@ public class DdiArtifactHash {
|
||||
@JsonProperty
|
||||
private String md5;
|
||||
|
||||
@JsonProperty
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
private String sha256;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
@@ -34,11 +40,16 @@ public class DdiArtifactHash {
|
||||
* Public constructor.
|
||||
*
|
||||
* @param sha1
|
||||
* sha1 hash of the artifact
|
||||
* @param md5
|
||||
* md5 hash of the artifact
|
||||
* @param sha256
|
||||
* sha256 hash of the artifact
|
||||
*/
|
||||
public DdiArtifactHash(final String sha1, final String md5) {
|
||||
public DdiArtifactHash(final String sha1, final String md5, final String sha256) {
|
||||
this.sha1 = sha1;
|
||||
this.md5 = md5;
|
||||
this.sha256 = sha256;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,4 +66,10 @@ public class DdiArtifactHash {
|
||||
return md5;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sha256
|
||||
*/
|
||||
public String getSha256() {
|
||||
return sha256;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public final class DataConversionHelper {
|
||||
private static DdiArtifact createArtifact(final Target target, final ArtifactUrlHandler artifactUrlHandler,
|
||||
final Artifact artifact, final SystemManagement systemManagement, final HttpRequest request) {
|
||||
final DdiArtifact file = new DdiArtifact();
|
||||
file.setHashes(new DdiArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash()));
|
||||
file.setHashes(new DdiArtifactHash(artifact.getSha1Hash(), artifact.getMd5Hash(), artifact.getSha256Hash()));
|
||||
file.setFilename(artifact.getFilename());
|
||||
file.setSize(artifact.getSize());
|
||||
|
||||
|
||||
@@ -153,8 +153,9 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
getOsModule(ds), "test1.signature", ARTIFACT_SIZE);
|
||||
final Target savedTarget = createTargetAndAssertNoActiveActions();
|
||||
|
||||
List<Target> targetsAssignedToDs = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.FORCED,
|
||||
RepositoryModelConstants.NO_FORCE_TIME, Collections.singletonList(savedTarget.getControllerId()))
|
||||
final List<Target> targetsAssignedToDs = deploymentManagement
|
||||
.assignDistributionSet(ds.getId(), ActionType.FORCED, RepositoryModelConstants.NO_FORCE_TIME,
|
||||
Collections.singletonList(savedTarget.getControllerId()))
|
||||
.getAssignedEntity();
|
||||
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
|
||||
|
||||
@@ -172,7 +173,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(2);
|
||||
|
||||
// Run test
|
||||
long current = System.currentTimeMillis();
|
||||
final long current = System.currentTimeMillis();
|
||||
performGet(CONTROLLER_BY_ID, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
|
||||
DEFAULT_CONTROLLER_ID)
|
||||
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
|
||||
@@ -255,7 +256,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
|
||||
final Target savedTarget = createTargetAndAssertNoActiveActions();
|
||||
|
||||
List<Target> saved = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.SOFT,
|
||||
final List<Target> saved = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.SOFT,
|
||||
RepositoryModelConstants.NO_FORCE_TIME, Collections.singletonList(savedTarget.getControllerId()))
|
||||
.getAssignedEntity();
|
||||
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
|
||||
@@ -315,7 +316,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
|
||||
final Target savedTarget = createTargetAndAssertNoActiveActions();
|
||||
|
||||
List<Target> saved = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.TIMEFORCED,
|
||||
final List<Target> saved = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.TIMEFORCED,
|
||||
System.currentTimeMillis(), Collections.singletonList(savedTarget.getControllerId()))
|
||||
.getAssignedEntity();
|
||||
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
|
||||
@@ -334,7 +335,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
|
||||
// Run test
|
||||
|
||||
long current = System.currentTimeMillis();
|
||||
final long current = System.currentTimeMillis();
|
||||
performGet(CONTROLLER_BY_ID, MediaTypes.HAL_JSON, status().isOk(), tenantAware.getCurrentTenant(),
|
||||
DEFAULT_CONTROLLER_ID)
|
||||
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
|
||||
@@ -383,7 +384,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
|
||||
final Target savedTarget = createTargetAndAssertNoActiveActions();
|
||||
|
||||
List<Target> saved = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.DOWNLOAD_ONLY,
|
||||
final List<Target> saved = deploymentManagement.assignDistributionSet(ds.getId(), ActionType.DOWNLOAD_ONLY,
|
||||
RepositoryModelConstants.NO_FORCE_TIME, Collections.singletonList(savedTarget.getControllerId()))
|
||||
.getAssignedEntity();
|
||||
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, savedTarget.getControllerId())).hasSize(1);
|
||||
@@ -465,6 +466,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
contains(artifact.getMd5Hash())))
|
||||
.andExpect(jsonPath("$.deployment.chunks[?(@.part=='os')].artifacts[0].hashes.sha1",
|
||||
contains(artifact.getSha1Hash())))
|
||||
.andExpect(jsonPath("$.deployment.chunks[?(@.part=='os')].artifacts[0].hashes.sha256",
|
||||
contains(artifact.getSha256Hash())))
|
||||
.andExpect(jsonPath(
|
||||
"$.deployment.chunks[?(@.part=='os')].artifacts[0]._links.download-http.href",
|
||||
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/"
|
||||
@@ -480,6 +483,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
contains(artifactSignature.getMd5Hash())))
|
||||
.andExpect(jsonPath("$.deployment.chunks[?(@.part=='os')].artifacts[1].hashes.sha1",
|
||||
contains(artifactSignature.getSha1Hash())))
|
||||
.andExpect(jsonPath("$.deployment.chunks[?(@.part=='os')].artifacts[1].hashes.sha256",
|
||||
contains(artifactSignature.getSha256Hash())))
|
||||
.andExpect(
|
||||
jsonPath("$.deployment.chunks[?(@.part=='os')].artifacts[1]._links.download-http.href",
|
||||
contains(HTTP_LOCALHOST + tenantAware.getCurrentTenant() + "/controller/v1/"
|
||||
@@ -710,7 +715,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
postFeedback(MediaType.APPLICATION_JSON, DEFAULT_CONTROLLER_ID, 1234L,
|
||||
JsonBuilder.deploymentActionInProgressFeedback("1234"), status().isNotFound());
|
||||
|
||||
Target savedTarget = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID);
|
||||
final Target savedTarget = testdataFactory.createTarget(DEFAULT_CONTROLLER_ID);
|
||||
|
||||
// Action does not exists
|
||||
postFeedback(MediaType.APPLICATION_JSON, "4713", 1234L, JsonBuilder.deploymentActionInProgressFeedback("1234"),
|
||||
@@ -774,9 +779,8 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
final String missingResultInFeedback = JsonBuilder.missingResultInFeedback(action.getId().toString(), "closed",
|
||||
"test");
|
||||
postFeedback(MediaType.APPLICATION_JSON, "1080", action.getId(), missingResultInFeedback,
|
||||
status().isBadRequest())
|
||||
.andExpect(jsonPath("$.*", hasSize(3)))
|
||||
.andExpect(jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName())));
|
||||
status().isBadRequest()).andExpect(jsonPath("$.*", hasSize(3))).andExpect(
|
||||
jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -797,13 +801,12 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
final String missingFinishedResultInFeedback = JsonBuilder
|
||||
.missingFinishedResultInFeedback(action.getId().toString(), "closed", "test");
|
||||
postFeedback(MediaType.APPLICATION_JSON, "1080", action.getId(), missingFinishedResultInFeedback,
|
||||
status().isBadRequest())
|
||||
.andExpect(jsonPath("$.*", hasSize(3)))
|
||||
.andExpect(jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName())));
|
||||
status().isBadRequest()).andExpect(jsonPath("$.*", hasSize(3))).andExpect(
|
||||
jsonPath("$.exceptionClass", equalTo(MessageNotReadableException.class.getCanonicalName())));
|
||||
}
|
||||
|
||||
private void assertActionStatusCount(final int actionStatusCount, final int minActionStatusCountInPage) {
|
||||
Target target = targetManagement.getByControllerID(DdiDeploymentBaseTest.DEFAULT_CONTROLLER_ID).get();
|
||||
final Target target = targetManagement.getByControllerID(DdiDeploymentBaseTest.DEFAULT_CONTROLLER_ID).get();
|
||||
assertThat(target.getUpdateStatus()).isEqualTo(TargetUpdateStatus.PENDING);
|
||||
|
||||
assertTargetCountByStatus(1, 0, 0);
|
||||
@@ -834,16 +837,17 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
.andExpect(content().contentTypeCompatibleWith(mediaType));
|
||||
}
|
||||
|
||||
private ResultActions postFeedback(final MediaType mediaType, final String controllerId, final Long id, final String content,
|
||||
final ResultMatcher statusMatcher) throws Exception {
|
||||
private ResultActions postFeedback(final MediaType mediaType, final String controllerId, final Long id,
|
||||
final String content, final ResultMatcher statusMatcher) throws Exception {
|
||||
return postFeedback(mediaType, controllerId, id, content.getBytes(), statusMatcher);
|
||||
}
|
||||
|
||||
private ResultActions postFeedback(final MediaType mediaType, final String controllerId, final Long id, final byte[] content,
|
||||
final ResultMatcher statusMatcher) throws Exception {
|
||||
return mvc.perform(post(DEPLOYMENT_BASE + id + "/feedback", tenantAware.getCurrentTenant(), controllerId)
|
||||
.content(content).contentType(mediaType).accept(mediaType)).andDo(MockMvcResultPrinter.print())
|
||||
.andExpect(statusMatcher);
|
||||
private ResultActions postFeedback(final MediaType mediaType, final String controllerId, final Long id,
|
||||
final byte[] content, final ResultMatcher statusMatcher) throws Exception {
|
||||
return mvc
|
||||
.perform(post(DEPLOYMENT_BASE + id + "/feedback", tenantAware.getCurrentTenant(), controllerId)
|
||||
.content(content).contentType(mediaType).accept(mediaType))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(statusMatcher);
|
||||
}
|
||||
|
||||
private Target createTargetAndAssertNoActiveActions() {
|
||||
@@ -855,7 +859,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
}
|
||||
|
||||
private void assertStatusMessagesCount(final int actionStatusMessagesCount) {
|
||||
Iterable<ActionStatus> actionStatusMessages;
|
||||
final Iterable<ActionStatus> actionStatusMessages;
|
||||
actionStatusMessages = deploymentManagement.findActionStatusAll(PageRequest.of(0, 100, Direction.DESC, "id"))
|
||||
.getContent();
|
||||
assertThat(actionStatusMessages).hasSize(actionStatusMessagesCount);
|
||||
@@ -894,7 +898,7 @@ public class DdiDeploymentBaseTest extends AbstractDDiApiIntegrationTest {
|
||||
}
|
||||
|
||||
private void assertStatusAndActiveActionsCount(final TargetUpdateStatus status, final int activeActions) {
|
||||
Target target = targetManagement.getByControllerID(DdiDeploymentBaseTest.DEFAULT_CONTROLLER_ID).get();
|
||||
final Target target = targetManagement.getByControllerID(DdiDeploymentBaseTest.DEFAULT_CONTROLLER_ID).get();
|
||||
assertThat(target.getUpdateStatus()).isEqualTo(status);
|
||||
assertThat(deploymentManagement.findActiveActionsByTarget(PAGE, target.getControllerId()))
|
||||
.hasSize(activeActions);
|
||||
|
||||
@@ -112,6 +112,8 @@ final class DdiApiModelProperties {
|
||||
|
||||
static final String ARTIFACT_HASHES_SHA1 = "SHA1 hash of the artifact in Base 16 format";
|
||||
static final String ARTIFACT_HASHES_MD5 = "MD5 hash of the artifact";
|
||||
static final String ARTIFACT_HASHES_SHA256 = "SHA-256 hash of the artifact in Base 16 format";
|
||||
|
||||
static final String ARTIFACT_SIZE = "size of the artifact";
|
||||
|
||||
static final String ACTION_HISTORY = "Optional GET parameter to retrieve a given number of messages which are previously provided by the device. "
|
||||
|
||||
@@ -321,6 +321,8 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
|
||||
.description(DdiApiModelProperties.ARTIFACT_HASHES_SHA1),
|
||||
fieldWithPath("deployment.chunks[].artifacts[].hashes.md5")
|
||||
.description(DdiApiModelProperties.ARTIFACT_HASHES_MD5),
|
||||
fieldWithPath("deployment.chunks[].artifacts[].hashes.sha256")
|
||||
.description(DdiApiModelProperties.ARTIFACT_HASHES_SHA256),
|
||||
fieldWithPath("deployment.chunks[].artifacts[].size")
|
||||
.description(DdiApiModelProperties.ARTIFACT_SIZE),
|
||||
fieldWithPath("deployment.chunks[].artifacts[]._links.download")
|
||||
@@ -451,6 +453,8 @@ public class RootControllerDocumentationTest extends AbstractApiRestDocumentatio
|
||||
fieldWithPath("[]hashes").description(DdiApiModelProperties.ARTIFACTS),
|
||||
fieldWithPath("[]hashes.sha1").description(DdiApiModelProperties.ARTIFACT_HASHES_SHA1),
|
||||
fieldWithPath("[]hashes.md5").description(DdiApiModelProperties.ARTIFACT_HASHES_MD5),
|
||||
fieldWithPath("[]hashes.sha256")
|
||||
.description(DdiApiModelProperties.ARTIFACT_HASHES_SHA256),
|
||||
fieldWithPath("[]size").description(DdiApiModelProperties.ARTIFACT_SIZE),
|
||||
fieldWithPath("[]_links.download")
|
||||
.description(DdiApiModelProperties.ARTIFACT_HTTPS_DOWNLOAD_LINK_BY_CONTROLLER),
|
||||
|
||||
Reference in New Issue
Block a user