hawkBit rest docs (management & DDI API) (#688)

* hawkBit REST docs.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fiy gitignore.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Add to website.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Switch to generated docs.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Fix typos.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Review findings.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Otimizations.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Revert accidental checkin.

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>

* Add security link.
This commit is contained in:
Kai Zimmermann
2018-05-24 16:10:01 +02:00
committed by GitHub
parent 7126d68f31
commit 428e3af2bc
244 changed files with 11636 additions and 430 deletions

View File

@@ -0,0 +1,193 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.NamedVersionedEntity;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.web.servlet.ResultMatcher;
@SpringApplicationConfiguration(classes = { MgmtApiConfiguration.class })
public abstract class AbstractManagementApiIntegrationTest extends AbstractRestIntegrationTest {
protected static ResultMatcher applyBaseEntityMatcherOnArrayResult(final BaseEntity entity,
final String arrayElement) throws Exception {
return mvcResult -> {
jsonPath("$." + arrayElement + ".[?(@.id==" + entity.getId() + ")].createdBy",
contains(entity.getCreatedBy())).match(mvcResult);
jsonPath("$." + arrayElement + ".[?(@.id==" + entity.getId() + ")].createdAt",
contains(entity.getCreatedAt())).match(mvcResult);
jsonPath("$." + arrayElement + ".[?(@.id==" + entity.getId() + ")].lastModifiedBy",
contains(entity.getLastModifiedBy())).match(mvcResult);
jsonPath("$." + arrayElement + ".[?(@.id==" + entity.getId() + ")].lastModifiedAt",
contains(entity.getLastModifiedAt())).match(mvcResult);
};
}
protected static ResultMatcher applyTargetEntityMatcherOnArrayResult(final Target entity, final String arrayElement)
throws Exception {
return mvcResult -> {
jsonPath("$." + arrayElement + ".[?(@.controllerId==" + entity.getControllerId() + ")].createdBy",
contains(entity.getCreatedBy())).match(mvcResult);
jsonPath("$." + arrayElement + ".[?(@.controllerId==" + entity.getControllerId() + ")].createdAt",
contains(entity.getCreatedAt())).match(mvcResult);
jsonPath("$." + arrayElement + ".[?(@.controllerId==" + entity.getControllerId() + ")].lastModifiedBy",
contains(entity.getLastModifiedBy())).match(mvcResult);
jsonPath("$." + arrayElement + ".[?(@.controllerId==" + entity.getControllerId() + ")].lastModifiedAt",
contains(entity.getLastModifiedAt())).match(mvcResult);
};
}
protected static ResultMatcher applyBaseEntityMatcherOnPagedResult(final BaseEntity entity) throws Exception {
return applyBaseEntityMatcherOnArrayResult(entity, "content");
}
protected static ResultMatcher applyNamedEntityMatcherOnPagedResult(final NamedEntity entity) throws Exception {
return mvcResult -> {
applyBaseEntityMatcherOnPagedResult(entity).match(mvcResult);
jsonPath("$.content.[?(@.id==" + entity.getId() + ")].name", contains(entity.getName())).match(mvcResult);
jsonPath("$.content.[?(@.id==" + entity.getId() + ")].description", contains(entity.getDescription()))
.match(mvcResult);
};
}
protected static ResultMatcher applyNamedVersionedEntityMatcherOnPagedResult(final NamedVersionedEntity entity)
throws Exception {
return mvcResult -> {
applyNamedEntityMatcherOnPagedResult(entity).match(mvcResult);
jsonPath("$.content.[?(@.id==" + entity.getId() + ")].version", contains(entity.getVersion()))
.match(mvcResult);
};
}
protected static ResultMatcher applyTagMatcherOnPagedResult(final Tag entity) throws Exception {
return mvcResult -> {
applyNamedEntityMatcherOnPagedResult(entity).match(mvcResult);
jsonPath("$.content.[?(@.id==" + entity.getId() + ")].colour", contains(entity.getColour()))
.match(mvcResult);
};
}
protected static ResultMatcher applySelfLinkMatcherOnPagedResult(final BaseEntity entity, final String link)
throws Exception {
return mvcResult -> {
jsonPath("$.content.[?(@.id==" + entity.getId() + ")]._links.self.href", contains(link)).match(mvcResult);
};
}
protected static ResultMatcher applyBaseEntityMatcherOnArrayResult(final BaseEntity entity) throws Exception {
return mvcResult -> {
jsonPath("$.[?(@.id==" + entity.getId() + ")].createdBy", contains(entity.getCreatedBy())).match(mvcResult);
jsonPath("$.[?(@.id==" + entity.getId() + ")].createdAt", contains(entity.getCreatedAt())).match(mvcResult);
jsonPath("$.[?(@.id==" + entity.getId() + ")].lastModifiedBy", contains(entity.getLastModifiedBy()))
.match(mvcResult);
jsonPath("$.[?(@.id==" + entity.getId() + ")].lastModifiedAt", contains(entity.getLastModifiedAt()))
.match(mvcResult);
};
}
protected static ResultMatcher applyTargetEntityMatcherOnArrayResult(final Target entity) throws Exception {
return mvcResult -> {
jsonPath("$.[?(@.controllerId==" + entity.getControllerId() + ")].createdBy",
contains(entity.getCreatedBy())).match(mvcResult);
jsonPath("$.[?(@.controllerId==" + entity.getControllerId() + ")].createdAt",
contains(entity.getCreatedAt())).match(mvcResult);
jsonPath("$.[?(@.controllerId==" + entity.getControllerId() + ")].lastModifiedBy",
contains(entity.getLastModifiedBy())).match(mvcResult);
jsonPath("$.[?(@.controllerId==" + entity.getControllerId() + ")].lastModifiedAt",
contains(entity.getLastModifiedAt())).match(mvcResult);
};
}
protected static ResultMatcher applyNamedEntityMatcherOnArrayResult(final NamedEntity entity) throws Exception {
return mvcResult -> {
applyBaseEntityMatcherOnPagedResult(entity);
jsonPath("$.[?(@.id==" + entity.getId() + ")].name", contains(entity.getName())).match(mvcResult);
jsonPath("$.[?(@.id==" + entity.getId() + ")].description", contains(entity.getDescription()))
.match(mvcResult);
};
}
protected static ResultMatcher applyNamedVersionedEntityMatcherOnArrayResult(final NamedVersionedEntity entity)
throws Exception {
return mvcResult -> {
applyNamedEntityMatcherOnPagedResult(entity);
jsonPath("$.[?(@.id==" + entity.getId() + ")].version", contains(entity.getVersion())).match(mvcResult);
};
}
protected static ResultMatcher applyTagMatcherOnArrayResult(final Tag entity) throws Exception {
return mvcResult -> {
applyNamedEntityMatcherOnPagedResult(entity);
jsonPath("$.[?(@.id==" + entity.getId() + ")].colour", contains(entity.getColour())).match(mvcResult);
};
}
protected static ResultMatcher applySelfLinkMatcherOnArrayResult(final BaseEntity entity, final String link)
throws Exception {
return mvcResult -> {
jsonPath("$.[?(@.id==" + entity.getId() + ")]._links.self.href", contains(link)).match(mvcResult);
};
}
protected static ResultMatcher applyBaseEntityMatcherOnSingleResult(final BaseEntity entity) throws Exception {
return mvcResult -> {
jsonPath("createdBy", equalTo(entity.getCreatedBy())).match(mvcResult);
jsonPath("createdAt", equalTo(entity.getCreatedAt())).match(mvcResult);
jsonPath("lastModifiedBy", equalTo(entity.getLastModifiedBy())).match(mvcResult);
jsonPath("lastModifiedAt", equalTo(entity.getLastModifiedAt())).match(mvcResult);
};
}
protected static ResultMatcher applyNamedEntityMatcherOnSingleResult(final NamedEntity entity) throws Exception {
return mvcResult -> {
applyBaseEntityMatcherOnSingleResult(entity);
jsonPath("name", equalTo(entity.getName())).match(mvcResult);
jsonPath("description", equalTo(entity.getDescription())).match(mvcResult);
};
}
protected static ResultMatcher applyNamedVersionedEntityMatcherOnSingleResult(final NamedVersionedEntity entity)
throws Exception {
return mvcResult -> {
applyNamedEntityMatcherOnSingleResult(entity);
jsonPath("version", equalTo(entity.getVersion())).match(mvcResult);
};
}
protected static ResultMatcher applyTagMatcherOnSingleResult(final Tag entity) throws Exception {
return mvcResult -> {
applyNamedEntityMatcherOnSingleResult(entity);
jsonPath("colour", equalTo(entity.getColour())).match(mvcResult);
};
}
protected static ResultMatcher applySelfLinkMatcherOnSingleResult(final String link) throws Exception {
return mvcResult -> {
jsonPath("_links.self.href", equalTo(link)).match(mvcResult);
};
}
}

View File

@@ -0,0 +1,317 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTagDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdatedEvent;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONException;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultActions;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - Management API")
@Stories("Distribution Set Tag Resource")
public class MgmtDistributionSetTagResourceTest extends AbstractManagementApiIntegrationTest {
private static final String DISTRIBUTIONSETTAGS_ROOT = "http://localhost"
+ MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/";
@Test
@Description("Verfies that a paged result list of DS tags reflects the content on the repository side.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 2) })
public void getDistributionSetTags() throws Exception {
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(2);
final DistributionSetTag assigned = tags.get(0);
final DistributionSetTag unassigned = tags.get(1);
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(applyBaseEntityMatcherOnPagedResult(assigned))
.andExpect(applyBaseEntityMatcherOnPagedResult(unassigned))
.andExpect(applySelfLinkMatcherOnPagedResult(assigned, DISTRIBUTIONSETTAGS_ROOT + assigned.getId()))
.andExpect(applySelfLinkMatcherOnPagedResult(unassigned, DISTRIBUTIONSETTAGS_ROOT + unassigned.getId()))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
}
@Test
@Description("Verfies that a single result of a DS tag reflects the content on the repository side.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 2) })
public void getDistributionSetTag() throws Exception {
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(2);
final DistributionSetTag assigned = tags.get(0);
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + assigned.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(applyTagMatcherOnSingleResult(assigned))
.andExpect(applySelfLinkMatcherOnSingleResult(DISTRIBUTIONSETTAGS_ROOT + assigned.getId()))
.andExpect(jsonPath("_links.assignedDistributionSets.href",
equalTo(DISTRIBUTIONSETTAGS_ROOT + assigned.getId() + "/assigned?offset=0&limit=50{&sort,q}")));
}
@Test
@Description("Verifies that created DS tags are stored in the repository as send to the API.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 2) })
public void createDistributionSetTags() throws JSONException, Exception {
final Tag tagOne = entityFactory.tag().create().colour("testcol1").description("its a test1").name("thetest1")
.build();
final Tag tagTwo = entityFactory.tag().create().colour("testcol2").description("its a test2").name("thetest2")
.build();
final ResultActions result = mvc
.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING)
.content(JsonBuilder.tags(Arrays.asList(tagOne, tagTwo)))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
final Tag createdOne = distributionSetTagManagement.findByRsql(PAGE, "name==thetest1").getContent().get(0);
assertThat(createdOne.getName()).isEqualTo(tagOne.getName());
assertThat(createdOne.getDescription()).isEqualTo(tagOne.getDescription());
assertThat(createdOne.getColour()).isEqualTo(tagOne.getColour());
final Tag createdTwo = distributionSetTagManagement.findByRsql(PAGE, "name==thetest2").getContent().get(0);
assertThat(createdTwo.getName()).isEqualTo(tagTwo.getName());
assertThat(createdTwo.getDescription()).isEqualTo(tagTwo.getDescription());
assertThat(createdTwo.getColour()).isEqualTo(tagTwo.getColour());
result.andExpect(applyTagMatcherOnArrayResult(createdOne)).andExpect(applyTagMatcherOnArrayResult(createdTwo));
}
@Test
@Description("Verifies that an updated DS tag is stored in the repository as send to the API.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@Expect(type = DistributionSetTagUpdatedEvent.class, count = 1) })
public void updateDistributionSetTag() throws Exception {
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(1);
final DistributionSetTag original = tags.get(0);
final Tag update = entityFactory.tag().create().name("updatedName").colour("updatedCol")
.description("updatedDesc").build();
final ResultActions result = mvc
.perform(put(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + original.getId())
.content(JsonBuilder.tag(update)).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
final Tag updated = distributionSetTagManagement.findByRsql(PAGE, "name==updatedName").getContent().get(0);
assertThat(updated.getName()).isEqualTo(update.getName());
assertThat(updated.getDescription()).isEqualTo(update.getDescription());
assertThat(updated.getColour()).isEqualTo(update.getColour());
result.andExpect(applyTagMatcherOnArrayResult(updated)).andExpect(applyTagMatcherOnArrayResult(updated));
}
@Test
@Description("Verfies that the delete call is reflected by the repository.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@Expect(type = DistributionSetTagDeletedEvent.class, count = 1) })
public void deleteDistributionSetTag() throws Exception {
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(1);
final DistributionSetTag original = tags.get(0);
mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + original.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(distributionSetTagManagement.get(original.getId())).isNotPresent();
}
@Test
@Description("Ensures that assigned DS to tag in repository are listed with proper paging results.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 5),
@Expect(type = DistributionSetUpdatedEvent.class, count = 5) })
public void getAssignedDistributionSets() throws Exception {
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
final int setsAssigned = 5;
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
distributionSetManagement.toggleTagAssignment(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()),
tag.getName());
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(setsAssigned)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(setsAssigned)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(setsAssigned)));
}
@Test
@Description("Ensures that assigned DS to tag in repository are listed with proper paging results with paging limit parameter.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 5),
@Expect(type = DistributionSetUpdatedEvent.class, count = 5) })
public void getAssignedDistributionSetsWithPagingLimitRequestParameter() throws Exception {
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
final int setsAssigned = 5;
final int limitSize = 1;
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
distributionSetManagement.toggleTagAssignment(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()),
tag.getName());
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(setsAssigned)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)));
}
@Test
@Description("Ensures that assigned DS to tag in repository are listed with proper paging results with paging limit and offset parameter.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 5),
@Expect(type = DistributionSetUpdatedEvent.class, count = 5) })
public void getAssignedDistributionSetsWithPagingLimitAndOffsetRequestParameter() throws Exception {
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
final int setsAssigned = 5;
final int offsetParam = 2;
final int expectedSize = setsAssigned - offsetParam;
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
distributionSetManagement.toggleTagAssignment(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()),
tag.getName());
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(setsAssigned)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(setsAssigned)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
}
@Test
@Description("Verfies that tag assignments done through toggle API command are correctly assigned or unassigned.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = DistributionSetUpdatedEvent.class, count = 4) })
public void toggleTagAssignment() throws Exception {
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
final int setsAssigned = 2;
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
// 2 DistributionSetUpdateEvent
ResultActions result = toggle(tag, sets);
List<DistributionSet> updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent();
assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList()))
.containsAll(sets.stream().map(DistributionSet::getId).collect(Collectors.toList()));
result.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(0), "assignedDistributionSets"))
.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(1), "assignedDistributionSets"));
// 2 DistributionSetUpdateEvent
result = toggle(tag, sets);
updated = distributionSetManagement.findAll(PAGE).getContent();
result.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(0), "unassignedDistributionSets"))
.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(1), "unassignedDistributionSets"));
assertThat(distributionSetManagement.findByTag(PAGE, tag.getId())).isEmpty();
}
private ResultActions toggle(final DistributionSetTag tag, final List<DistributionSet> sets) throws Exception {
return mvc
.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId()
+ "/assigned/toggleTagAssignment").content(
JsonBuilder.ids(sets.stream().map(DistributionSet::getId).collect(Collectors.toList())))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
}
@Test
@Description("Verfies that tag assignments done through tag API command are correctly stored in the repository.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = DistributionSetUpdatedEvent.class, count = 2) })
public void assignDistributionSets() throws Exception {
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
final int setsAssigned = 2;
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
final ResultActions result = mvc
.perform(
post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.content(JsonBuilder
.ids(sets.stream().map(DistributionSet::getId).collect(Collectors.toList())))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
final List<DistributionSet> updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent();
assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList()))
.containsAll(sets.stream().map(DistributionSet::getId).collect(Collectors.toList()));
result.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(0)))
.andExpect(applyBaseEntityMatcherOnArrayResult(updated.get(1)));
}
@Test
@Description("Verfies that tag unassignments done through tag API command are correctly stored in the repository.")
@ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 2),
@Expect(type = DistributionSetUpdatedEvent.class, count = 3) })
public void unassignDistributionSet() throws Exception {
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
final int setsAssigned = 2;
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);
final DistributionSet assigned = sets.get(0);
final DistributionSet unassigned = sets.get(1);
distributionSetManagement.toggleTagAssignment(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()),
tag.getName());
mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned/"
+ unassigned.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
final List<DistributionSet> updated = distributionSetManagement.findByTag(PAGE, tag.getId()).getContent();
assertThat(updated.stream().map(DistributionSet::getId).collect(Collectors.toList()))
.containsOnly(assigned.getId());
}
}

View File

@@ -0,0 +1,667 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.assertj.core.util.Lists;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import com.jayway.jsonpath.JsonPath;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Step;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test for {@link MgmtDistributionSetTypeResource}.
*
*/
@Features("Component Tests - Management API")
@Stories("Distribution Set Type Resource")
public class MgmtDistributionSetTypeResourceTest extends AbstractManagementApiIntegrationTest {
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests.")
public void getDistributionSetTypes() throws Exception {
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
.key("test123").name("TestName123").description("Desc123").colour("col12"));
testType = distributionSetTypeManagement
.update(entityFactory.distributionSetType().update(testType.getId()).description("Desc1234"));
// 4 types overall (2 hawkbit tenant default, 1 test default and 1
// generated in this test)
mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[?(@.key==" + standardDsType.getKey() + ")]$..name",
contains(standardDsType.getName())))
.andExpect(jsonPath("$.content.[?(@.key==" + standardDsType.getKey() + ")]$..description",
contains(standardDsType.getDescription())))
.andExpect(jsonPath("$.content.[?(@.key==" + standardDsType.getKey() + ")]$..key",
contains(standardDsType.getKey())))
.andExpect(jsonPath("$.content.[?(@.key==test123)]$..id", contains(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[?(@.key==test123)]$..name", contains("TestName123")))
.andExpect(jsonPath("$.content.[?(@.key==test123)]$..description", contains("Desc1234")))
.andExpect(jsonPath("$.content.[?(@.key==test123)]$..createdBy", contains("uploadTester")))
.andExpect(jsonPath("$.content.[?(@.key==test123)]$..createdAt", contains(testType.getCreatedAt())))
.andExpect(jsonPath("$.content.[?(@.key==test123)]$..lastModifiedBy", contains("uploadTester")))
.andExpect(jsonPath("$.content.[?(@.key==test123)]$..lastModifiedAt",
contains(testType.getLastModifiedAt())))
.andExpect(jsonPath("$.content.[?(@.key==test123)]$..key", contains("test123")))
.andExpect(jsonPath("$.content.[?(@.key==test123)]$.._links.self.href",
contains("http://localhost/rest/v1/distributionsettypes/" + testType.getId())))
.andExpect(jsonPath("$.total", equalTo(5)));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with sorting by KEY.")
public void getDistributionSetTypesSortedByKey() throws Exception {
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
.key("zzzzz").name("TestName123").description("Desc123").colour("col12"));
testType = distributionSetTypeManagement
.update(entityFactory.distributionSetType().update(testType.getId()).description("Desc1234"));
// descending
mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "KEY:DESC")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[0].id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[0].name", equalTo("TestName123")))
.andExpect(jsonPath("$.content.[0].description", equalTo("Desc1234")))
.andExpect(jsonPath("$.content.[0].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.content.[0].createdAt", equalTo(testType.getCreatedAt())))
.andExpect(jsonPath("$.content.[0].lastModifiedBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.content.[0].lastModifiedAt", equalTo(testType.getLastModifiedAt())))
.andExpect(jsonPath("$.content.[0].key", equalTo("zzzzz")))
.andExpect(jsonPath("$.total", equalTo(DEFAULT_DS_TYPES + 1)));
// ascending
mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "KEY:ASC")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[4].id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[4].name", equalTo("TestName123")))
.andExpect(jsonPath("$.content.[4].description", equalTo("Desc1234")))
.andExpect(jsonPath("$.content.[4].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.content.[4].createdAt", equalTo(testType.getCreatedAt())))
.andExpect(jsonPath("$.content.[4].lastModifiedBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.content.[4].lastModifiedAt", equalTo(testType.getLastModifiedAt())))
.andExpect(jsonPath("$.content.[4].key", equalTo("zzzzz")))
.andExpect(jsonPath("$.total", equalTo(DEFAULT_DS_TYPES + 1)));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes POST requests.")
public void createDistributionSetTypes() throws Exception {
final List<DistributionSetType> types = createTestDistributionSetTestTypes();
final MvcResult mvcResult = runPostDistributionSetType(types);
verifyCreatedDistributionSetTypes(mvcResult);
}
@Step
private void verifyCreatedDistributionSetTypes(final MvcResult mvcResult) throws UnsupportedEncodingException {
final DistributionSetType created1 = distributionSetTypeManagement.getByKey("testKey1").get();
final DistributionSetType created2 = distributionSetTypeManagement.getByKey("testKey2").get();
final DistributionSetType created3 = distributionSetTypeManagement.getByKey("testKey3").get();
assertThat(created1.getMandatoryModuleTypes()).containsOnly(osType);
assertThat(created1.getOptionalModuleTypes()).containsOnly(runtimeType);
assertThat(created2.getOptionalModuleTypes()).containsOnly(osType, runtimeType, appType);
assertThat(created3.getMandatoryModuleTypes()).containsOnly(osType, runtimeType);
assertThat(
JsonPath.compile("[0]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
.isEqualTo("http://localhost/rest/v1/distributionsettypes/" + created1.getId());
assertThat(
JsonPath.compile("[1]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
.isEqualTo("http://localhost/rest/v1/distributionsettypes/" + created2.getId());
assertThat(
JsonPath.compile("[2]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
.isEqualTo("http://localhost/rest/v1/distributionsettypes/" + created3.getId());
assertThat(distributionSetTypeManagement.count()).isEqualTo(7);
}
@Step
private MvcResult runPostDistributionSetType(final List<DistributionSetType> types) throws Exception {
return mvc
.perform(post("/rest/v1/distributionsettypes/").content(JsonBuilder.distributionSetTypes(types))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo("TestName1")))
.andExpect(jsonPath("[0].key", equalTo("testKey1")))
.andExpect(jsonPath("[0].description", equalTo("Desc1")))
.andExpect(jsonPath("[0].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("[1].name", equalTo("TestName2")))
.andExpect(jsonPath("[1].key", equalTo("testKey2")))
.andExpect(jsonPath("[1].description", equalTo("Desc2")))
.andExpect(jsonPath("[1].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("[2].name", equalTo("TestName3")))
.andExpect(jsonPath("[2].key", equalTo("testKey3")))
.andExpect(jsonPath("[2].description", equalTo("Desc3")))
.andExpect(jsonPath("[2].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("[2].createdAt", not(equalTo(0)))).andReturn();
}
@Step
private List<DistributionSetType> createTestDistributionSetTestTypes() {
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES);
return Arrays.asList(
entityFactory.distributionSetType().create().key("testKey1").name("TestName1").description("Desc1")
.colour("col").mandatory(Arrays.asList(osType.getId()))
.optional(Arrays.asList(runtimeType.getId())).build(),
entityFactory.distributionSetType().create().key("testKey2").name("TestName2").description("Desc2")
.colour("col").optional(Arrays.asList(runtimeType.getId(), osType.getId(), appType.getId()))
.build(),
entityFactory.distributionSetType().create().key("testKey3").name("TestName3").description("Desc3")
.colour("col").mandatory(Arrays.asList(runtimeType.getId(), osType.getId())).build());
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes POST requests.")
public void addMandatoryModuleToDistributionSetType() throws Exception {
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
.key("test123").name("TestName123").description("Desc123").colour("col12"));
assertThat(testType.getOptLockRevision()).isEqualTo(1);
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType.getId())
.content("{\"id\":" + osType.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
testType = distributionSetTypeManagement.get(testType.getId()).get();
assertThat(testType.getLastModifiedBy()).isEqualTo("uploadTester");
assertThat(testType.getOptLockRevision()).isEqualTo(2);
assertThat(testType.getMandatoryModuleTypes()).containsExactly(osType);
assertThat(testType.getOptionalModuleTypes()).isEmpty();
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes POST requests.")
public void addOptionalModuleToDistributionSetType() throws Exception {
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
.key("test123").name("TestName123").description("Desc123").colour("col12"));
assertThat(testType.getOptLockRevision()).isEqualTo(1);
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId())
.content("{\"id\":" + osType.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
testType = distributionSetTypeManagement.get(testType.getId()).get();
assertThat(testType.getLastModifiedBy()).isEqualTo("uploadTester");
assertThat(testType.getOptLockRevision()).isEqualTo(2);
assertThat(testType.getOptionalModuleTypes()).containsExactly(osType);
assertThat(testType.getMandatoryModuleTypes()).isEmpty();
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Verifies quota enforcement for /rest/v1/distributionsettypes/{ID}/optionalmoduletypes POST requests.")
public void assignModuleTypesToDistributionSetTypeUntilQuotaExceeded() throws Exception {
// create software module types
final int maxSoftwareModuleTypes = quotaManagement.getMaxSoftwareModuleTypesPerDistributionSetType();
final List<Long> moduleTypeIds = Lists.newArrayList();
for (int i = 0; i < maxSoftwareModuleTypes + 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());
}
// verify quota enforcement for optional module types
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("testType").name("testType").description("testType").colour("col12"));
assertThat(testType.getOptLockRevision()).isEqualTo(1);
for (int i = 0; i < moduleTypeIds.size() - 1; ++i) {
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId())
.content("{\"id\":" + moduleTypeIds.get(i) + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
}
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId())
.content("{\"id\":" + moduleTypeIds.get(moduleTypeIds.size() - 1) + "}")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
// verify quota enforcement for mandatory module types
final DistributionSetType testType2 = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("testType2").name("testType2").description("testType2").colour("col12"));
assertThat(testType2.getOptLockRevision()).isEqualTo(1);
for (int i = 0; i < moduleTypeIds.size() - 1; ++i) {
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType2.getId())
.content("{\"id\":" + moduleTypeIds.get(i) + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
}
mvc.perform(post("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType2.getId())
.content("{\"id\":" + moduleTypeIds.get(moduleTypeIds.size() - 1) + "}")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes GET requests.")
public void getMandatoryModulesOfDistributionSetType() throws Exception {
final DistributionSetType testType = generateTestType();
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo(osType.getName())))
.andExpect(jsonPath("[0].description", equalTo(osType.getDescription())))
.andExpect(jsonPath("[0].maxAssignments", equalTo(1))).andExpect(jsonPath("[0].key", equalTo("os")));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes GET requests.")
public void getOptionalModulesOfDistributionSetType() throws Exception {
final DistributionSetType testType = generateTestType();
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo(appType.getName())))
.andExpect(jsonPath("[0].description", equalTo(appType.getDescription())))
.andExpect(jsonPath("[0].maxAssignments", equalTo(Integer.MAX_VALUE)))
.andExpect(jsonPath("[0].key", equalTo("application")));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes/{ID} GET requests.")
public void getMandatoryModuleOfDistributionSetType() throws Exception {
final DistributionSetType testType = generateTestType();
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes/{smtId}", testType.getId(),
osType.getId()).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.id", equalTo(osType.getId().intValue())))
.andExpect(jsonPath("$.name", equalTo(osType.getName())))
.andExpect(jsonPath("$.description", equalTo(osType.getDescription())))
.andExpect(jsonPath("$.createdBy", equalTo(osType.getCreatedBy())))
.andExpect(jsonPath("$.createdAt", equalTo(osType.getCreatedAt())))
.andExpect(jsonPath("$.lastModifiedBy", equalTo(osType.getLastModifiedBy())))
.andExpect(jsonPath("$.lastModifiedAt", equalTo(osType.getLastModifiedAt())));
}
private DistributionSetType generateTestType() {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test123").name("TestName123").description("Desc123").colour("col")
.mandatory(Arrays.asList(osType.getId())).optional(Arrays.asList(appType.getId())));
assertThat(testType.getOptLockRevision()).isEqualTo(1);
assertThat(testType.getOptionalModuleTypes()).containsExactly(appType);
assertThat(testType.getMandatoryModuleTypes()).containsExactly(osType);
return testType;
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes/{ID} GET requests.")
public void getOptionalModuleOfDistributionSetType() throws Exception {
final DistributionSetType testType = generateTestType();
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes/{smtId}", testType.getId(),
appType.getId()).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.id", equalTo(appType.getId().intValue())))
.andExpect(jsonPath("$.name", equalTo(appType.getName())))
.andExpect(jsonPath("$.description", equalTo(appType.getDescription())))
.andExpect(jsonPath("$.createdBy", equalTo(appType.getCreatedBy())))
.andExpect(jsonPath("$.createdAt", equalTo(appType.getCreatedAt())))
.andExpect(jsonPath("$.lastModifiedBy", equalTo(appType.getLastModifiedBy())))
.andExpect(jsonPath("$.lastModifiedAt", equalTo(appType.getLastModifiedAt())));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/mandatorymoduletypes/{ID} DELETE requests.")
public void removeMandatoryModuleToDistributionSetType() throws Exception {
DistributionSetType testType = generateTestType();
mvc.perform(delete("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes/{smtId}", testType.getId(),
osType.getId()).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
testType = distributionSetTypeManagement.get(testType.getId()).get();
assertThat(testType.getLastModifiedBy()).isEqualTo("uploadTester");
assertThat(testType.getOptLockRevision()).isEqualTo(2);
assertThat(testType.getOptionalModuleTypes()).containsExactly(appType);
assertThat(testType.getMandatoryModuleTypes()).isEmpty();
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID}/optionalmoduletypes/{ID} DELETE requests.")
public void removeOptionalModuleToDistributionSetType() throws Exception {
DistributionSetType testType = generateTestType();
mvc.perform(delete("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes/{smtId}", testType.getId(),
appType.getId()).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
testType = distributionSetTypeManagement.get(testType.getId()).get();
assertThat(testType.getLastModifiedBy()).isEqualTo("uploadTester");
assertThat(testType.getOptLockRevision()).isEqualTo(2);
assertThat(testType.getOptionalModuleTypes()).isEmpty();
assertThat(testType.getMandatoryModuleTypes()).containsExactly(osType);
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID} GET requests.")
public void getDistributionSetType() throws Exception {
DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
.key("test123").name("TestName123").description("Desc123").colour("col12"));
testType = distributionSetTypeManagement
.update(entityFactory.distributionSetType().update(testType.getId()).description("Desc1234"));
mvc.perform(get("/rest/v1/distributionsettypes/{dstId}", testType.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.name", equalTo("TestName123")))
.andExpect(jsonPath("$.description", equalTo("Desc1234")))
.andExpect(jsonPath("$.createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
.andExpect(jsonPath("$.lastModifiedBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.deleted", equalTo(testType.isDeleted())));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/DistributionSetTypes/{ID} DELETE requests (hard delete scenario).")
public void deleteDistributionSetTypeUnused() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test123").name("TestName123").description("Desc123").colour("col12"));
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES + 1);
mvc.perform(delete("/rest/v1/distributionsettypes/{dsId}", testType.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES);
}
@Test
@Description("Ensures that DS type deletion request to API on an entity that does not exist results in NOT_FOUND.")
public void deleteDistributionSetTypeThatDoesNotExistLeadsToNotFound() throws Exception {
mvc.perform(delete("/rest/v1/distributionsettypes/1234")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/DistributionSetTypes/{ID} DELETE requests (soft delete scenario).")
public void deleteDistributionSetTypeUsed() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test123").name("TestName123").description("Desc123").colour("col12"));
distributionSetManagement.create(entityFactory.distributionSet().create().name("sdfsd").description("dsfsdf")
.version("1").type(testType));
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES + 1);
assertThat(distributionSetManagement.count()).isEqualTo(1);
mvc.perform(get("/rest/v1/distributionsettypes/{dstId}", testType.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.deleted", equalTo(false)));
mvc.perform(delete("/rest/v1/distributionsettypes/{dstId}", testType.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get("/rest/v1/distributionsettypes/{dstId}", testType.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.deleted", equalTo(true)));
assertThat(distributionSetManagement.count()).isEqualTo(1);
assertThat(distributionSetTypeManagement.count()).isEqualTo(DEFAULT_DS_TYPES);
}
@Test
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID} PUT requests.")
public void updateDistributionSetTypeOnlyDescriptionAndNameUntouched() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.create(entityFactory.distributionSetType()
.create().key("test123").name("TestName123").description("Desc123").colour("col"));
final String body = new JSONObject().put("id", testType.getId()).put("description", "foobardesc")
.put("name", "nameShouldNotBeChanged").toString();
mvc.perform(put("/rest/v1/distributionsettypes/{smId}", testType.getId()).content(body)
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.description", equalTo("foobardesc")))
.andExpect(jsonPath("$.name", equalTo("TestName123"))).andReturn();
}
@Test
@Description("Tests the update of the deletion flag. It is verfied that the distribution set type can't be marked as deleted through update operation.")
public void updateDistributionSetTypeDeletedFlag() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement
.create(entityFactory.distributionSetType().create().key("test123").name("TestName123").colour("col"));
final String body = new JSONObject().put("id", testType.getId()).put("deleted", true).toString();
mvc.perform(put("/rest/v1/distributionsettypes/{dstId}", testType.getId()).content(body)
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.deleted", equalTo(false)));
}
@Test
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with paging.")
public void getDistributionSetTypesWithoutAddtionalRequestParameters() throws Exception {
// 4 types overall (3 hawkbit tenant default, 1 test default
final int types = 4;
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types)));
}
@Test
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with paging.")
public void getDistributionSetTypesWithPagingLimitRequestParameter() throws Exception {
final int types = DEFAULT_DS_TYPES;
final int limitSize = 1;
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)));
}
@Test
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes GET requests with paging.")
public void getDistributionSetTypesWithPagingLimitAndOffsetRequestParameter() throws Exception {
final int types = DEFAULT_DS_TYPES;
final int offsetParam = 2;
final int expectedSize = types - offsetParam;
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(types)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
}
@Test
@Description("Ensures that the server is behaving as expected on invalid requests (wrong media type, wrong ID etc.).")
public void invalidRequestsOnDistributionSetTypesResource() throws Exception {
// final DistributionSetType testDsType = distributionSetManagement
// .createDistributionSetType(entityFactory.distributionSetType().create().key("test123")
// .name("TestName123").description("Desc123").colour("col"));
final SoftwareModuleType testSmType = softwareModuleTypeManagement
.create(entityFactory.softwareModuleType().create().key("test123").name("TestName123"));
// DST does not exist
mvc.perform(get("/rest/v1/distributionsettypes/12345678")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
mvc.perform(get("/rest/v1/distributionsettypes/12345678/mandatorymoduletypes"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(get("/rest/v1/distributionsettypes/12345678/optionalmoduletypes"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(delete("/rest/v1/distributionsettypes/12345678")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// Module types incorrect
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes/565765656"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/565765656"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(get(
"/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes/" + osType.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes/"
+ testSmType.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(get(
"/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/" + osType.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(get(
"/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/" + appType.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/"
+ testSmType.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
// Modules types at creation time invalid
final DistributionSetType testNewType = entityFactory.distributionSetType().create().key("test123")
.name("TestName123").description("Desc123").colour("col").mandatory(Arrays.asList(osType.getId()))
.optional(Collections.emptyList()).build();
mvc.perform(post("/rest/v1/distributionsettypes")
.content(JsonBuilder.distributionSetTypes(Arrays.asList(testNewType)))
.contentType(MediaType.APPLICATION_OCTET_STREAM)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isUnsupportedMediaType());
// bad request - no content
mvc.perform(post("/rest/v1/distributionsettypes").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
// bad request - bad content
mvc.perform(post("/rest/v1/distributionsettypes").content("sdfjsdlkjfskdjf".getBytes())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
// Missing mandatory field name
mvc.perform(post("/rest/v1/distributionsettypes").content("[{\"description\":\"Desc123\",\"key\":\"test123\"}]")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
final DistributionSetType toLongName = entityFactory.distributionSetType().create().key("test123")
.name(RandomStringUtils.randomAlphanumeric(80)).build();
mvc.perform(post("/rest/v1/distributionsettypes")
.content(JsonBuilder.distributionSetTypes(Arrays.asList(toLongName)))
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
// not allowed methods
mvc.perform(put("/rest/v1/distributionsettypes")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete("/rest/v1/distributionsettypes")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(put("/rest/v1/distributionsettypes/" + standardDsType.getId() + "/mandatorymoduletypes"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
mvc.perform(put(
"/rest/v1/distributionsettypes/" + standardDsType.getId() + "/optionalmoduletypes/" + osType.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
}
@Test
@Description("Search erquest of software module types.")
public void searchDistributionSetTypeRsql() throws Exception {
distributionSetTypeManagement
.create(entityFactory.distributionSetType().create().key("test123").name("TestName123"));
distributionSetTypeManagement
.create(entityFactory.distributionSetType().create().key("test1234").name("TestName1234"));
final String rsqlFindLikeDs1OrDs2 = "name==TestName123,name==TestName1234";
mvc.perform(get("/rest/v1/distributionsettypes?q=" + rsqlFindLikeDs1OrDs2)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(2)))
.andExpect(jsonPath("total", equalTo(2))).andExpect(jsonPath("content[0].name", equalTo("TestName123")))
.andExpect(jsonPath("content[1].name", equalTo("TestName1234")));
}
private void createSoftwareModulesAlphabetical(final int amount) {
char character = 'a';
for (int index = 0; index < amount; index++) {
final String str = String.valueOf(character);
softwareModuleManagement.create(
entityFactory.softwareModule().create().name(str).description(str).vendor(str).version(str));
character++;
}
}
}

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.eclipse.hawkbit.cache.DownloadArtifactCache;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.cache.DownloadType;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - Management API")
@Stories("Download Resource")
public class MgmtDownloadResourceTest extends AbstractManagementApiIntegrationTest {
@Autowired
private DownloadIdCache downloadIdCache;
private static final String DOWNLOAD_ID_SHA1 = "downloadIdSha1";
private static final String DOWNLOAD_ID_NOT_AVAILABLE = "downloadIdNotAvailable";
@Before
public void setupCache() {
final DistributionSet distributionSet = testdataFactory.createDistributionSet("Test");
final SoftwareModule softwareModule = distributionSet.getModules().stream().findAny().get();
final Artifact artifact = testdataFactory.createArtifacts(softwareModule.getId()).stream().findAny().get();
downloadIdCache.put(DOWNLOAD_ID_SHA1, new DownloadArtifactCache(DownloadType.BY_SHA1, artifact.getSha1Hash()));
}
@Test
@Description("This test verifies the call of download artifact without a valid download id fails.")
public void testNoDownloadIdAvailable() throws Exception {
mvc.perform(get(
MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE
+ MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING,
tenantAware.getCurrentTenant(), DOWNLOAD_ID_NOT_AVAILABLE)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@Description("This test verifies the call of download artifact works and the download id will be removed.")
public void testDownload() throws Exception {
mvc.perform(get(
MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE
+ MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING,
tenantAware.getCurrentTenant(), DOWNLOAD_ID_SHA1)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// because cache is empty
mvc.perform(get(
MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING_BASE
+ MgmtRestConstants.DOWNLOAD_ID_V1_REQUEST_MAPPING,
tenantAware.getCurrentTenant(), DOWNLOAD_ID_SHA1)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
}

View File

@@ -0,0 +1,998 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.eclipse.hawkbit.rest.util.SuccessCondition;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.http.MediaType;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Step;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Tests for covering the {@link MgmtRolloutResource}.
*/
@Features("Component Tests - Management API")
@Stories("Rollout Resource")
public class MgmtRolloutResourceTest extends AbstractManagementApiIntegrationTest {
private static final String HREF_ROLLOUT_PREFIX = "http://localhost/rest/v1/rollouts/";
@Autowired
private RolloutManagement rolloutManagement;
@Autowired
private RolloutGroupManagement rolloutGroupManagement;
@Test
@Description("Testing that creating rollout with wrong body returns bad request")
public void createRolloutWithInvalidBodyReturnsBadRequest() throws Exception {
mvc.perform(post("/rest/v1/rollouts").content("invalid body").contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("errorCode", equalTo("hawkbit.server.error.rest.body.notReadable")));
}
@Test
@Description("Testing that creating rollout with insufficient permission returns forbidden")
@WithUser(allSpPermissions = true, removeFromAllPermission = "CREATE_ROLLOUT")
public void createRolloutWithInsufficientPermissionReturnsForbidden() throws Exception {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("name", "desc", 10, dsA.getId(), "name==test", null))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().is(403)).andReturn();
}
@Test
@Description("Testing that creating rollout with not exisiting distribution set returns not found")
public void createRolloutWithNotExistingDistributionSetReturnsNotFound() throws Exception {
mvc.perform(post("/rest/v1/rollouts").content(JsonBuilder.rollout("name", "desc", 10, 1234, "name==test", null))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound()).andReturn();
}
@Test
@Description("Testing that creating rollout with not valid formed target filter query returns bad request")
public void createRolloutWithNotWellFormedFilterReturnsBadRequest() throws Exception {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("name", "desc", 10, dsA.getId(), "name=test", null))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest())
.andExpect(jsonPath("errorCode", equalTo("hawkbit.server.error.rest.param.rsqlParamSyntax")))
.andReturn();
}
@Description("Ensures that the repository refuses to create rollout without a defined target filter set.")
public void missingTargetFilterQueryInRollout() throws Exception {
final String targetFilterQuery = null;
final DistributionSet dsA = testdataFactory.createDistributionSet("");
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout1", "desc", 10, dsA.getId(), targetFilterQuery, null))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest())
.andExpect(jsonPath("errorCode", equalTo("hawkbit.server.error.rest.param.rsqlParamSyntax")))
.andReturn();
}
@Test
@Description("Testing that rollout can be created")
public void createRollout() throws Exception {
testdataFactory.createTargets(20, "target", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
postRollout("rollout1", 10, dsA.getId(), "id==target*", 20);
}
@Test
@Description("Verifies that rollout cannot be created if too many rollout groups are specified.")
public void createRolloutWithTooManyRolloutGroups() throws Exception {
final int maxGroups = quotaManagement.getMaxRolloutGroupsPerRollout();
testdataFactory.createTargets(20, "target", "rollout");
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout1", "rollout1Desc", maxGroups + 1,
testdataFactory.createDistributionSet("ds").getId(), "id==target*",
new RolloutGroupConditionBuilder().withDefaults().build()))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
}
@Test
@Description("Verifies that rollout cannot be created if the 'max targets per rollout group' quota would be violated for one of the groups.")
public void createRolloutFailsIfRolloutGroupQuotaIsViolated() throws Exception {
final int maxTargets = quotaManagement.getMaxTargetsPerRolloutGroup();
testdataFactory.createTargets(maxTargets + 1, "target", "rollout");
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout1", "rollout1Desc", 1,
testdataFactory.createDistributionSet("ds").getId(), "id==target*",
new RolloutGroupConditionBuilder().withDefaults().build()))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(QuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
}
@Test
@Description("Testing that rollout can be created with groups")
public void createRolloutWithGroupDefinitions() throws Exception {
final DistributionSet dsA = testdataFactory.createDistributionSet("ro");
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "ro-target", "rollout");
final float percentTargetsInGroup1 = 20;
final float percentTargetsInGroup2 = 100;
final List<RolloutGroup> rolloutGroups = Arrays.asList(
entityFactory.rolloutGroup().create().name("Group1").description("Group1desc")
.targetPercentage(percentTargetsInGroup1).build(),
entityFactory.rolloutGroup().create().name("Group2").description("Group2desc")
.targetPercentage(percentTargetsInGroup2).build());
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout2", "desc", null, dsA.getId(), "id==ro-target*",
rolloutGroupConditions, rolloutGroups))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated()).andReturn();
}
@Test
@Description("Testing that no rollout with groups that have illegal percentages can be created")
public void createRolloutWithTooLowPercentage() throws Exception {
final DistributionSet dsA = testdataFactory.createDistributionSet("ro2");
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "ro-target", "rollout");
final List<RolloutGroup> rolloutGroups = Arrays.asList(
entityFactory.rolloutGroup().create().name("Group1").description("Group1desc").targetPercentage(0F)
.build(),
entityFactory.rolloutGroup().create().name("Group2").description("Group2desc").targetPercentage(100F)
.build());
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout4", "desc", null, dsA.getId(), "id==ro-target*",
rolloutGroupConditions, rolloutGroups))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
}
@Test
@Description("Testing that no rollout with groups that have illegal percentages can be created")
public void createRolloutWithTooHighPercentage() throws Exception {
final DistributionSet dsA = testdataFactory.createDistributionSet("ro2");
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "ro-target", "rollout");
final List<RolloutGroup> rolloutGroups = Arrays.asList(
entityFactory.rolloutGroup().create().name("Group1").description("Group1desc").targetPercentage(1F)
.build(),
entityFactory.rolloutGroup().create().name("Group2").description("Group2desc").targetPercentage(101F)
.build());
final RolloutGroupConditions rolloutGroupConditions = new RolloutGroupConditionBuilder().withDefaults().build();
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout("rollout4", "desc", null, dsA.getId(), "id==ro-target*",
rolloutGroupConditions, rolloutGroups))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
}
@Test
@Description("Testing the empty list is returned if no rollout exists")
public void noRolloutReturnsEmptyList() throws Exception {
mvc.perform(get("/rest/v1/rollouts").accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(0))).andExpect(jsonPath("$.total", equalTo(0)));
}
@Test
@Description("Retrieves single rollout from management API including extra data that is delivered only for single rollout access.")
public void retrieveSingleRollout() throws Exception {
testdataFactory.createTargets(20, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("rollout1").set(dsA.getId())
.targetFilterQuery("controllerId==rollout*"),
4, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
retrieveAndVerifyRolloutInCreating(dsA, rollout);
retrieveAndVerifyRolloutInReady(rollout);
retrieveAndVerifyRolloutInStarting(rollout);
retrieveAndVerifyRolloutInRunning(rollout);
}
@Step
private void retrieveAndVerifyRolloutInRunning(final Rollout rollout) throws Exception {
rolloutManagement.handleRollouts();
mvc.perform(get("/rest/v1/rollouts/" + rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("$.name", equalTo("rollout1"))).andExpect(jsonPath("$.status", equalTo("running")))
.andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(5)))
.andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(15)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)))
.andExpect(jsonPath("$.deleted", equalTo(false)));
}
@Step
private void retrieveAndVerifyRolloutInStarting(final Rollout rollout) throws Exception {
rolloutManagement.start(rollout.getId());
mvc.perform(get("/rest/v1/rollouts/" + rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("$.name", equalTo("rollout1"))).andExpect(jsonPath("$.status", equalTo("starting")))
.andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(20)))
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)))
.andExpect(jsonPath("$.deleted", equalTo(false)));
}
@Step
private void retrieveAndVerifyRolloutInReady(final Rollout rollout) throws Exception {
rolloutManagement.handleRollouts();
mvc.perform(get("/rest/v1/rollouts/" + rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("$.name", equalTo("rollout1"))).andExpect(jsonPath("$.status", equalTo("ready")))
.andExpect(jsonPath("$.lastModifiedBy", equalTo("bumlux")))
.andExpect(jsonPath("$.lastModifiedAt", not(equalTo(0))))
.andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(20)))
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)))
.andExpect(jsonPath("$.deleted", equalTo(false)));
}
@Step
private void retrieveAndVerifyRolloutInCreating(final DistributionSet dsA, final Rollout rollout) throws Exception {
mvc.perform(get("/rest/v1/rollouts/" + rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("$.name", equalTo("rollout1"))).andExpect(jsonPath("$.status", equalTo("creating")))
.andExpect(jsonPath("$.targetFilterQuery", equalTo("controllerId==rollout*")))
.andExpect(jsonPath("$.distributionSetId", equalTo(dsA.getId().intValue())))
.andExpect(jsonPath("$.createdBy", equalTo("bumlux")))
.andExpect(jsonPath("$.createdAt", not(equalTo(0))))
.andExpect(jsonPath("$.lastModifiedBy", equalTo("bumlux")))
.andExpect(jsonPath("$.lastModifiedAt", not(equalTo(0))))
.andExpect(jsonPath("$.totalTargets", equalTo(20)))
.andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(20)))
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)))
.andExpect(jsonPath("$._links.self.href", startsWith(HREF_ROLLOUT_PREFIX)))
.andExpect(jsonPath("$._links.start.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/start"))))
.andExpect(jsonPath("$._links.pause.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/pause"))))
.andExpect(
jsonPath("$._links.resume.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/resume"))))
.andExpect(jsonPath("$._links.groups.href",
allOf(startsWith(HREF_ROLLOUT_PREFIX), containsString("/deploygroups"))))
.andExpect(jsonPath("$.deleted", equalTo(false)));
}
@Test
@Description("Testing that rollout paged list contains rollouts")
public void rolloutPagedListContainsAllRollouts() throws Exception {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
testdataFactory.createTargets(20, "target", "rollout");
// setup - create 2 rollouts
postRollout("rollout1", 10, dsA.getId(), "id==target*", 20);
postRollout("rollout2", 5, dsA.getId(), "id==target-0001*", 10);
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
mvc.perform(get("/rest/v1/rollouts").accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2)))
.andExpect(jsonPath("content[0].name", equalTo("rollout1")))
.andExpect(jsonPath("content[0].status", equalTo("ready")))
.andExpect(jsonPath("content[0].targetFilterQuery", equalTo("id==target*")))
.andExpect(jsonPath("content[0].distributionSetId", equalTo(dsA.getId().intValue())))
.andExpect(jsonPath("content[0].createdBy", equalTo("bumlux")))
.andExpect(jsonPath("content[0].createdAt", not(equalTo(0))))
.andExpect(jsonPath("content[0].lastModifiedBy", equalTo("bumlux")))
.andExpect(jsonPath("content[0].lastModifiedAt", not(equalTo(0))))
.andExpect(jsonPath("content[0].totalTargets", equalTo(20)))
.andExpect(jsonPath("content[0].totalTargetsPerStatus").doesNotExist())
.andExpect(jsonPath("content[0]._links.self.href", startsWith(HREF_ROLLOUT_PREFIX)))
.andExpect(jsonPath("content[1].name", equalTo("rollout2")))
.andExpect(jsonPath("content[1].status", equalTo("ready")))
.andExpect(jsonPath("content[1].targetFilterQuery", equalTo("id==target-0001*")))
.andExpect(jsonPath("content[1].distributionSetId", equalTo(dsA.getId().intValue())))
.andExpect(jsonPath("content[1].createdBy", equalTo("bumlux")))
.andExpect(jsonPath("content[1].createdAt", not(equalTo(0))))
.andExpect(jsonPath("content[1].lastModifiedBy", equalTo("bumlux")))
.andExpect(jsonPath("content[1].lastModifiedAt", not(equalTo(0))))
.andExpect(jsonPath("content[1].totalTargets", equalTo(10)))
.andExpect(jsonPath("content[1].totalTargetsPerStatus").doesNotExist())
.andExpect(jsonPath("content[1]._links.self.href", startsWith(HREF_ROLLOUT_PREFIX)));
}
@Test
@Description("Testing that rollout paged list is limited by the query param limit")
public void rolloutPagedListIsLimitedToQueryParam() throws Exception {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
testdataFactory.createTargets(20, "target", "rollout");
// setup - create 2 rollouts
postRollout("rollout1", 10, dsA.getId(), "id==target*", 20);
postRollout("rollout2", 5, dsA.getId(), "id==target*", 20);
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
mvc.perform(get("/rest/v1/rollouts?limit=1").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(2)));
}
@Test
@Description("Testing that rollout paged list is limited by the query param limit")
public void retrieveRolloutGroupsForSpecificRollout() throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
// retrieve rollout groups from created rollout
mvc.perform(
get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(4))).andExpect(jsonPath("$.total", equalTo(4)))
.andExpect(jsonPath("$.content[0].status", equalTo("ready")))
.andExpect(jsonPath("$.content[1].status", equalTo("ready")))
.andExpect(jsonPath("$.content[2].status", equalTo("ready")))
.andExpect(jsonPath("$.content[3].status", equalTo("ready")));
}
@Test
@Description("Testing that starting the rollout switches the state to starting and then to running")
public void startingRolloutSwitchesIntoRunningState() throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
// starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// check rollout is in starting state
mvc.perform(get("/rest/v1/rollouts/{rolloutId}", rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("status", equalTo("starting")));
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
// check rollout is in running state
mvc.perform(get("/rest/v1/rollouts/{rolloutId}", rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("status", equalTo("running")));
}
@Test
@Description("Testing that pausing the rollout switches the state to paused")
public void pausingRolloutSwitchesIntoPausedState() throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
// starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
// pausing rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/pause", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// check rollout is in running state
mvc.perform(get("/rest/v1/rollouts/{rolloutId}", rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("status", equalTo("paused")));
}
@Test
@Description("Testing that resuming the rollout switches the state to running")
public void resumingRolloutSwitchesIntoRunningState() throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
// starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
// pausing rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/pause", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// resume rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/resume", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// check rollout is in running state
mvc.perform(get("/rest/v1/rollouts/{rolloutId}", rollout.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("status", equalTo("running")));
}
@Test
@Description("Testing that an already started rollout cannot be started again and returns bad request")
public void startingAlreadyStartedRolloutReturnsBadRequest() throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
// starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
// starting rollout - already started should lead into bad request
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("errorCode", equalTo("hawkbit.server.error.rollout.illegalstate")));
}
@Test
@Description("Testing that resuming a rollout which is not started leads to bad request")
public void resumingNotStartedRolloutReturnsBadRequest() throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
// resume not yet started rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/resume", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("errorCode", equalTo("hawkbit.server.error.rollout.illegalstate")));
}
@Test
@Description("Testing that starting rollout the first rollout group is in running state")
public void startingRolloutFirstRolloutGroupIsInRunningState() throws Exception {
// setup
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*");
// starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
// retrieve rollout groups from created rollout - 2 groups exists
// (amountTargets / groupSize = 2)
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups?sort=ID:ASC", rollout.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2)))
.andExpect(jsonPath("$.content[0].status", equalTo("running")))
.andExpect(jsonPath("$.content[1].status", equalTo("scheduled")));
}
@Test
@Description("Testing that a single rollout group can be retrieved")
public void retrieveSingleRolloutGroup() throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name("rollout1").set(dsA.getId())
.targetFilterQuery("controllerId==rollout*"),
4, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
final RolloutGroup firstGroup = rolloutGroupManagement
.findByRollout(new PageRequest(0, 1, Direction.ASC, "id"), rollout.getId()).getContent().get(0);
final RolloutGroup secondGroup = rolloutGroupManagement
.findByRollout(new PageRequest(1, 1, Direction.ASC, "id"), rollout.getId()).getContent().get(0);
retrieveAndVerifyRolloutGroupInCreating(rollout, firstGroup);
retrieveAndVerifyRolloutGroupInReady(rollout, firstGroup);
retrieveAndVerifyRolloutGroupInRunningAndScheduled(rollout, firstGroup, secondGroup);
}
@Step
private void retrieveAndVerifyRolloutGroupInRunningAndScheduled(final Rollout rollout,
final RolloutGroup firstGroup, final RolloutGroup secondGroup) throws Exception {
rolloutManagement.start(rollout.getId());
rolloutManagement.handleRollouts();
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}", rollout.getId(), firstGroup.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("status", equalTo("running")))
.andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(5)))
.andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)));
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}", rollout.getId(), secondGroup.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("status", equalTo("scheduled")))
.andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(5)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)));
}
@Step
private void retrieveAndVerifyRolloutGroupInReady(final Rollout rollout, final RolloutGroup firstGroup)
throws Exception {
rolloutManagement.handleRollouts();
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}", rollout.getId(), firstGroup.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("status", equalTo("ready")))
.andExpect(jsonPath("$.lastModifiedBy", equalTo("bumlux")))
.andExpect(jsonPath("$.lastModifiedAt", not(equalTo(0))))
.andExpect(jsonPath("$.totalTargets", equalTo(5)))
.andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(5)))
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)));
}
@Step
private void retrieveAndVerifyRolloutGroupInCreating(final Rollout rollout, final RolloutGroup firstGroup)
throws Exception {
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}", rollout.getId(), firstGroup.getId())
.accept(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("id", equalTo(firstGroup.getId().intValue())))
.andExpect(jsonPath("status", equalTo("creating"))).andExpect(jsonPath("name", endsWith("1")))
.andExpect(jsonPath("description", endsWith("1")))
.andExpect(jsonPath("$.targetFilterQuery", equalTo("")))
.andExpect(jsonPath("$.targetPercentage", equalTo(25.0)))
.andExpect(jsonPath("$.createdBy", equalTo("bumlux")))
.andExpect(jsonPath("$.createdAt", not(equalTo(0))))
.andExpect(jsonPath("$.lastModifiedBy", equalTo("bumlux")))
.andExpect(jsonPath("$.lastModifiedAt", not(equalTo(0))))
.andExpect(jsonPath("$.totalTargets", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)))
.andExpect(jsonPath("$._links.self.href", equalTo(
HREF_ROLLOUT_PREFIX + rollout.getId() + "/deploygroups/" + firstGroup.getId().intValue())));
}
@Test
@Description("Testing that the targets of rollout group can be retrieved")
public void retrieveTargetsFromRolloutGroup() throws Exception {
// setup
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*");
final RolloutGroup firstGroup = rolloutGroupManagement
.findByRollout(new PageRequest(0, 1, Direction.ASC, "id"), rollout.getId()).getContent().get(0);
// retrieve targets from the first rollout group with known ID
mvc.perform(
get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}/targets", rollout.getId(), firstGroup.getId())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(5))).andExpect(jsonPath("$.total", equalTo(5)));
}
@Test
@Description("Testing that the targets of rollout group can be retrieved with rsql query param")
public void retrieveTargetsFromRolloutGroupWithQuery() throws Exception {
// setup
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*");
final RolloutGroup firstGroup = rolloutGroupManagement
.findByRollout(new PageRequest(0, 1, Direction.ASC, "id"), rollout.getId()).getContent().get(0);
final String targetInGroup = rolloutGroupManagement.findTargetsOfRolloutGroup(PAGE, firstGroup.getId())
.getContent().get(0).getControllerId();
// retrieve targets from the first rollout group with known ID
mvc.perform(
get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}/targets", rollout.getId(), firstGroup.getId())
.accept(MediaType.APPLICATION_JSON).param("q", "controllerId==" + targetInGroup))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1)));
}
@Test
@Description("Testing that the targets of rollout group can be retrieved after the rollout has been started")
public void retrieveTargetsFromRolloutGroupAfterRolloutIsStarted() throws Exception {
// setup
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 2, dsA.getId(), "controllerId==rollout*");
rolloutManagement.start(rollout.getId());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
final RolloutGroup firstGroup = rolloutGroupManagement
.findByRollout(new PageRequest(0, 1, Direction.ASC, "id"), rollout.getId()).getContent().get(0);
// retrieve targets from the first rollout group with known ID
mvc.perform(
get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}/targets", rollout.getId(), firstGroup.getId())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(5))).andExpect(jsonPath("$.total", equalTo(5)));
}
@Test
@Description("Start the rollout in async mode")
public void startingRolloutSwitchesIntoRunningStateAsync() throws Exception {
final int amountTargets = 1000;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
// starting rollout
mvc.perform(post("/rest/v1/rollouts/{rolloutId}/start", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// Run here, because scheduler is disabled during tests
rolloutManagement.handleRollouts();
// check if running
assertThat(doWithTimeout(() -> getRollout(rollout.getId()), this::success, 60_000, 100)).isNotNull();
}
@Test
@Description("Deletion of a rollout")
public void deleteRollout() throws Exception {
final int amountTargets = 10;
testdataFactory.createTargets(amountTargets, "rolloutDelete", "rolloutDelete");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rolloutDelete", 4, dsA.getId(), "controllerId==rolloutDelete*");
// delete rollout
mvc.perform(delete("/rest/v1/rollouts/{rolloutid}", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(getRollout(rollout.getId()).getStatus()).isEqualTo(RolloutStatus.DELETING);
}
@Test
@Description("Soft deletion of a rollout: soft deletion appears when already running rollout is being deleted")
public void deleteRunningRollout() throws Exception {
final Rollout rollout = testdataFactory.createSoftDeletedRollout("softDeletedRollout");
mvc.perform(get("/rest/v1/rollouts/{rolloutid}", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.deleted", equalTo(true)));
assertThat(getRollout(rollout.getId()).getStatus()).isEqualTo(RolloutStatus.DELETED);
}
@Test
@Description("Testing that rollout paged list with rsql parameter")
public void getRolloutWithRSQLParam() throws Exception {
final int amountTargetsRollout1 = 25;
final int amountTargetsRollout2 = 25;
final int amountTargetsRollout3 = 25;
final int amountTargetsOther = 25;
testdataFactory.createTargets(amountTargetsRollout1, "rollout1", "rollout1");
testdataFactory.createTargets(amountTargetsRollout2, "rollout2", "rollout2");
testdataFactory.createTargets(amountTargetsRollout3, "rollout3", "rollout3");
testdataFactory.createTargets(amountTargetsOther, "other1", "other1");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
createRollout("rollout1", 5, dsA.getId(), "controllerId==rollout1*");
final Rollout rollout2 = createRollout("rollout2", 5, dsA.getId(), "controllerId==rollout2*");
createRollout("rollout3", 5, dsA.getId(), "controllerId==rollout3*");
createRollout("other1", 5, dsA.getId(), "controllerId==other1*");
mvc.perform(get("/rest/v1/rollouts").param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==*2")
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1)))
.andExpect(jsonPath("$.content[0].name", equalTo(rollout2.getName())));
mvc.perform(get("/rest/v1/rollouts").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==rollout*"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(3))).andExpect(jsonPath("$.total", equalTo(3)));
mvc.perform(get("/rest/v1/rollouts").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==*1")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2)));
}
@Test
@Description("Testing that rolloutgroup paged list with rsql parameter")
public void retrieveRolloutGroupsForSpecificRolloutWithRSQLParam() throws Exception {
// setup
final int amountTargets = 20;
testdataFactory.createTargets(amountTargets, "rollout", "rollout");
final DistributionSet dsA = testdataFactory.createDistributionSet("");
// create rollout including the created targets with prefix 'rollout'
final Rollout rollout = createRollout("rollout1", 4, dsA.getId(), "controllerId==rollout*");
// retrieve rollout groups from created rollout
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId())
.accept(MediaType.APPLICATION_JSON).param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1)))
.andExpect(jsonPath("$.content[0].name", equalTo("group-1")));
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId())
.accept(MediaType.APPLICATION_JSON).param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group*"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(4))).andExpect(jsonPath("$.total", equalTo(4)));
mvc.perform(
get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId()).accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1,name==group-2"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2)));
}
protected <T> T doWithTimeout(final Callable<T> callable, final SuccessCondition<T> successCondition,
final long timeout, final long pollInterval) throws Exception // NOPMD
{
if (pollInterval < 0) {
throw new IllegalArgumentException("pollInterval must non negative");
}
long duration = 0;
Exception exception = null;
T returnValue = null;
while (untilTimeoutReached(timeout, duration)) {
try {
returnValue = callable.call();
// clear exception
exception = null;
} catch (final Exception ex) {
exception = ex;
}
Thread.sleep(pollInterval);
duration += pollInterval > 0 ? pollInterval : 1;
if (exception == null && successCondition.success(returnValue)) {
return returnValue;
} else {
returnValue = null;
}
}
if (exception != null) {
throw exception;
}
return returnValue;
}
protected boolean untilTimeoutReached(final long timeout, final long duration) {
return duration <= timeout || timeout < 0;
}
private void postRollout(final String name, final int groupSize, final Long distributionSetId,
final String targetFilterQuery, final int targets) throws Exception {
mvc.perform(post("/rest/v1/rollouts")
.content(JsonBuilder.rollout(name, "desc", groupSize, distributionSetId, targetFilterQuery,
new RolloutGroupConditionBuilder().withDefaults().build()))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(jsonPath("$.name", equalTo(name))).andExpect(jsonPath("$.status", equalTo("creating")))
.andExpect(jsonPath("$.targetFilterQuery", equalTo(targetFilterQuery)))
.andExpect(jsonPath("$.description", equalTo("desc")))
.andExpect(jsonPath("$.distributionSetId", equalTo(distributionSetId.intValue())))
.andExpect(jsonPath("$.createdBy", equalTo("bumlux")))
.andExpect(jsonPath("$.createdAt", not(equalTo(0))))
.andExpect(jsonPath("$.lastModifiedBy", equalTo("bumlux")))
.andExpect(jsonPath("$.lastModifiedAt", not(equalTo(0))))
.andExpect(jsonPath("$.totalTargets", equalTo(targets)))
.andExpect(jsonPath("$.totalTargetsPerStatus.running", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.notstarted", equalTo(targets)))
.andExpect(jsonPath("$.totalTargetsPerStatus.scheduled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.cancelled", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.finished", equalTo(0)))
.andExpect(jsonPath("$.totalTargetsPerStatus.error", equalTo(0)))
.andExpect(jsonPath("$._links.self.href", startsWith(HREF_ROLLOUT_PREFIX)))
.andExpect(jsonPath("$._links.start.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/start"))))
.andExpect(jsonPath("$._links.pause.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/pause"))))
.andExpect(
jsonPath("$._links.resume.href", allOf(startsWith(HREF_ROLLOUT_PREFIX), endsWith("/resume"))))
.andExpect(jsonPath("$._links.groups.href",
allOf(startsWith(HREF_ROLLOUT_PREFIX), containsString("/deploygroups"))));
}
private Rollout createRollout(final String name, final int amountGroups, final long distributionSetId,
final String targetFilterQuery) {
final Rollout rollout = rolloutManagement.create(
entityFactory.rollout().create().name(name).set(distributionSetId).targetFilterQuery(targetFilterQuery),
amountGroups, new RolloutGroupConditionBuilder().withDefaults()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, "100").build());
// Run here, because Scheduler is disabled during tests
rolloutManagement.handleRollouts();
return rolloutManagement.get(rollout.getId()).get();
}
protected boolean success(final Rollout result) {
return result != null && result.getStatus() == RolloutStatus.RUNNING;
}
public Rollout getRollout(final Long rolloutId) throws Exception {
return rolloutManagement.get(rolloutId).get();
}
}

View File

@@ -0,0 +1,420 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import com.jayway.jsonpath.JsonPath;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test for {@link MgmtSoftwareModuleTypeResource}.
*
*/
@Features("Component Tests - Management API")
@Stories("Software Module Type Resource")
public class MgmtSoftwareModuleTypeResourceTest extends AbstractManagementApiIntegrationTest {
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests.")
public void getSoftwareModuleTypes() throws Exception {
final SoftwareModuleType testType = createTestType();
mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[?(@.key==" + osType.getKey() + ")].name", contains(osType.getName())))
.andExpect(jsonPath("$.content.[?(@.key==" + osType.getKey() + ")].description",
contains(osType.getDescription())))
.andExpect(jsonPath("$.content.[?(@.key==" + osType.getKey() + ")].maxAssignments", contains(1)))
.andExpect(jsonPath("$.content.[?(@.key==" + osType.getKey() + ")].key", contains("os")))
.andExpect(jsonPath("$.content.[?(@.key==" + runtimeType.getKey() + ")].name",
contains(runtimeType.getName())))
.andExpect(jsonPath("$.content.[?(@.key==" + runtimeType.getKey() + ")].description",
contains(runtimeType.getDescription())))
.andExpect(jsonPath("$.content.[?(@.key==" + runtimeType.getKey() + ")].maxAssignments", contains(1)))
.andExpect(jsonPath("$.content.[?(@.key==" + runtimeType.getKey() + ")].key", contains("runtime")))
.andExpect(jsonPath("$.content.[?(@.key==" + appType.getKey() + ")].name", contains(appType.getName())))
.andExpect(jsonPath("$.content.[?(@.key==" + appType.getKey() + ")].description",
contains(appType.getDescription())))
.andExpect(jsonPath("$.content.[?(@.key==" + appType.getKey() + ")].maxAssignments",
contains(Integer.MAX_VALUE)))
.andExpect(jsonPath("$.content.[?(@.key==" + appType.getKey() + ")].key", contains("application")))
.andExpect(jsonPath("$.content.[?(@.key==test123)].id", contains(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[?(@.key==test123)].name", contains("TestName123")))
.andExpect(jsonPath("$.content.[?(@.key==test123)].description", contains("Desc1234")))
.andExpect(jsonPath("$.content.[?(@.key==test123)].createdBy", contains("uploadTester")))
.andExpect(jsonPath("$.content.[?(@.key==test123)].createdAt", contains(testType.getCreatedAt())))
.andExpect(jsonPath("$.content.[?(@.key==test123)].lastModifiedBy", contains("uploadTester")))
.andExpect(jsonPath("$.content.[?(@.key==test123)].lastModifiedAt",
contains(testType.getLastModifiedAt())))
.andExpect(jsonPath("$.content.[?(@.key==test123)].maxAssignments", contains(5)))
.andExpect(jsonPath("$.content.[?(@.key==test123)].key", contains("test123")))
.andExpect(jsonPath("$.total", equalTo(4)));
}
private SoftwareModuleType createTestType() {
SoftwareModuleType testType = softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create()
.key("test123").name("TestName123").description("Desc123").maxAssignments(5));
testType = softwareModuleTypeManagement
.update(entityFactory.softwareModuleType().update(testType.getId()).description("Desc1234"));
return testType;
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with sorting by MAXASSIGNMENTS field.")
public void getSoftwareModuleTypesSortedByMaxAssignments() throws Exception {
final SoftwareModuleType testType = createTestType();
// descending
mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:DESC"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[1].id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[1].name", equalTo("TestName123")))
.andExpect(jsonPath("$.content.[1].description", equalTo("Desc1234")))
.andExpect(jsonPath("$.content.[1].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.content.[1].createdAt", equalTo(testType.getCreatedAt())))
.andExpect(jsonPath("$.content.[1].lastModifiedBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.content.[1].lastModifiedAt", equalTo(testType.getLastModifiedAt())))
.andExpect(jsonPath("$.content.[1].maxAssignments", equalTo(5)))
.andExpect(jsonPath("$.content.[1].key", equalTo("test123")))
.andExpect(jsonPath("$.total", equalTo(4)));
// ascending
mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:ASC"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[2].id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[2].name", equalTo("TestName123")))
.andExpect(jsonPath("$.content.[2].description", equalTo("Desc1234")))
.andExpect(jsonPath("$.content.[2].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.content.[2].createdAt", equalTo(testType.getCreatedAt())))
.andExpect(jsonPath("$.content.[2].lastModifiedBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.content.[2].lastModifiedAt", equalTo(testType.getLastModifiedAt())))
.andExpect(jsonPath("$.content.[2].maxAssignments", equalTo(5)))
.andExpect(jsonPath("$.content.[2].key", equalTo("test123")))
.andExpect(jsonPath("$.total", equalTo(4)));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes POST requests when max assignment is smaller than 1")
public void createSoftwareModuleTypesInvalidAssignmentBadRequest() throws Exception {
final List<SoftwareModuleType> types = new ArrayList<>();
types.add(entityFactory.softwareModuleType().create().key("test-1").name("TestName-1").maxAssignments(-1)
.build());
mvc.perform(post("/rest/v1/softwaremoduletypes/").content(JsonBuilder.softwareModuleTypes(types))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
types.clear();
types.add(entityFactory.softwareModuleType().create().key("test0").name("TestName0").maxAssignments(0).build());
mvc.perform(post("/rest/v1/softwaremoduletypes/").content(JsonBuilder.softwareModuleTypes(types))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes POST requests.")
public void createSoftwareModuleTypes() throws Exception {
final List<SoftwareModuleType> types = Arrays.asList(
entityFactory.softwareModuleType().create().key("test1").name("TestName1").description("Desc1")
.colour("col1").maxAssignments(1).build(),
entityFactory.softwareModuleType().create().key("test2").name("TestName2").description("Desc2")
.colour("col2").maxAssignments(2).build(),
entityFactory.softwareModuleType().create().key("test3").name("TestName3").description("Desc3")
.colour("col3").maxAssignments(3).build());
final MvcResult mvcResult = mvc
.perform(post("/rest/v1/softwaremoduletypes/").content(JsonBuilder.softwareModuleTypes(types))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo("TestName1"))).andExpect(jsonPath("[0].key", equalTo("test1")))
.andExpect(jsonPath("[0].description", equalTo("Desc1")))
.andExpect(jsonPath("[0].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("[0].maxAssignments", equalTo(1)))
.andExpect(jsonPath("[1].name", equalTo("TestName2"))).andExpect(jsonPath("[1].key", equalTo("test2")))
.andExpect(jsonPath("[1].description", equalTo("Desc2")))
.andExpect(jsonPath("[1].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("[1].maxAssignments", equalTo(2)))
.andExpect(jsonPath("[2].name", equalTo("TestName3"))).andExpect(jsonPath("[2].key", equalTo("test3")))
.andExpect(jsonPath("[2].description", equalTo("Desc3")))
.andExpect(jsonPath("[2].createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("[2].createdAt", not(equalTo(0))))
.andExpect(jsonPath("[2].maxAssignments", equalTo(3))).andReturn();
final SoftwareModuleType created1 = softwareModuleTypeManagement.getByKey("test1").get();
final SoftwareModuleType created2 = softwareModuleTypeManagement.getByKey("test2").get();
final SoftwareModuleType created3 = softwareModuleTypeManagement.getByKey("test3").get();
assertThat(
JsonPath.compile("[0]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
.isEqualTo("http://localhost/rest/v1/softwaremoduletypes/" + created1.getId());
assertThat(
JsonPath.compile("[1]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
.isEqualTo("http://localhost/rest/v1/softwaremoduletypes/" + created2.getId());
assertThat(
JsonPath.compile("[2]_links.self.href").read(mvcResult.getResponse().getContentAsString()).toString())
.isEqualTo("http://localhost/rest/v1/softwaremoduletypes/" + created3.getId());
assertThat(softwareModuleTypeManagement.count()).isEqualTo(6);
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} GET requests.")
public void getSoftwareModuleType() throws Exception {
final SoftwareModuleType testType = createTestType();
mvc.perform(get("/rest/v1/softwaremoduletypes/{smtId}", testType.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.name", equalTo("TestName123")))
.andExpect(jsonPath("$.description", equalTo("Desc1234")))
.andExpect(jsonPath("$.maxAssignments", equalTo(5)))
.andExpect(jsonPath("$.createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
.andExpect(jsonPath("$.lastModifiedBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
.andExpect(jsonPath("$.deleted", equalTo(testType.isDeleted())));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} DELETE requests (hard delete scenario).")
public void deleteSoftwareModuleTypeUnused() throws Exception {
final SoftwareModuleType testType = createTestType();
assertThat(softwareModuleTypeManagement.count()).isEqualTo(4);
mvc.perform(delete("/rest/v1/softwaremoduletypes/{smId}", testType.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(softwareModuleTypeManagement.count()).isEqualTo(3);
}
@Test
@Description("Ensures that module type deletion request to API on an entity that does not exist results in NOT_FOUND.")
public void deleteSoftwareModuleTypeThatDoesNotExistLeadsToNotFound() throws Exception {
mvc.perform(delete("/rest/v1/softwaremoduletypes/1234")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} DELETE requests (soft delete scenario).")
public void deleteSoftwareModuleTypeUsed() throws Exception {
final SoftwareModuleType testType = createTestType();
softwareModuleManagement
.create(entityFactory.softwareModule().create().type(testType).name("name").version("version"));
assertThat(softwareModuleTypeManagement.count()).isEqualTo(4);
mvc.perform(get("/rest/v1/softwaremoduletypes/{smtId}", testType.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.deleted", equalTo(false)));
mvc.perform(delete("/rest/v1/softwaremoduletypes/{smtId}", testType.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
mvc.perform(get("/rest/v1/softwaremoduletypes/{smtId}", testType.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.deleted", equalTo(true)));
assertThat(softwareModuleTypeManagement.count()).isEqualTo(3);
}
@Test
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes/{ID} PUT requests.")
public void updateSoftwareModuleTypeOnlyDescriptionAndNameUntouched() throws Exception {
final SoftwareModuleType testType = createTestType();
final String body = new JSONObject().put("id", testType.getId()).put("description", "foobardesc")
.put("name", "nameShouldNotBeChanged").toString();
mvc.perform(put("/rest/v1/softwaremoduletypes/{smId}", testType.getId()).content(body)
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.description", equalTo("foobardesc")))
.andExpect(jsonPath("$.name", equalTo("TestName123"))).andReturn();
}
@Test
@Description("Tests the update of the deletion flag. It is verfied that the software module type can't be marked as deleted through update operation.")
public void updateSoftwareModuleTypeDeletedFlag() throws Exception {
SoftwareModuleType testType = createTestType();
final String body = new JSONObject().put("id", testType.getId()).put("deleted", true).toString();
mvc.perform(put("/rest/v1/softwaremoduletypes/{smtId}", testType.getId()).content(body)
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
.andExpect(jsonPath("$.deleted", equalTo(false)));
testType = softwareModuleTypeManagement.get(testType.getId()).get();
assertThat(testType.getLastModifiedAt()).isEqualTo(testType.getLastModifiedAt());
assertThat(testType.isDeleted()).isEqualTo(false);
}
@Test
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with paging.")
public void getSoftwareModuleTypesWithoutAddtionalRequestParameters() throws Exception {
final int types = 3;
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(types)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(types)));
}
@Test
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with paging.")
public void getSoftwareModuleTypesWithPagingLimitRequestParameter() throws Exception {
final int types = 3;
final int limitSize = 1;
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)));
}
@Test
@Description("Checks the correct behaviour of /rest/v1/softwaremoduletypes GET requests with paging.")
public void getSoftwareModuleTypesWithPagingLimitAndOffsetRequestParameter() throws Exception {
final int types = 3;
final int offsetParam = 2;
final int expectedSize = types - offsetParam;
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(types)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(types)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
}
@Test
@Description("Ensures that the server is behaving as expected on invalid requests (wrong media type, wrong ID etc.).")
public void invalidRequestsOnSoftwaremoduleTypesResource() throws Exception {
final SoftwareModuleType testType = createTestType();
final List<SoftwareModuleType> types = Arrays.asList(testType);
// SM does not exist
mvc.perform(get("/rest/v1/softwaremoduletypes/12345678")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
mvc.perform(delete("/rest/v1/softwaremoduletypes/12345678")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// bad request - no content
mvc.perform(post("/rest/v1/softwaremoduletypes").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
// bad request - bad content
mvc.perform(post("/rest/v1/softwaremoduletypes").content("sdfjsdlkjfskdjf".getBytes())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
mvc.perform(post("/rest/v1/softwaremoduletypes").content(
"[{\"description\":\"Desc123\",\"id\":9223372036854775807,\"key\":\"test123\",\"maxAssignments\":5}]")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
final SoftwareModuleType toLongName = entityFactory.softwareModuleType().create().key("test123")
.name(RandomStringUtils.randomAlphanumeric(80)).build();
mvc.perform(
post("/rest/v1/softwaremoduletypes").content(JsonBuilder.softwareModuleTypes(Arrays.asList(toLongName)))
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
// unsupported media type
mvc.perform(post("/rest/v1/softwaremoduletypes").content(JsonBuilder.softwareModuleTypes(types))
.contentType(MediaType.APPLICATION_OCTET_STREAM)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isUnsupportedMediaType());
// not allowed methods
mvc.perform(put("/rest/v1/softwaremoduletypes")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete("/rest/v1/softwaremoduletypes")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
}
@Test
@Description("Search erquest of software module types.")
public void searchSoftwareModuleTypeRsql() throws Exception {
softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create().key("test123")
.name("TestName123").description("Desc123").maxAssignments(5));
softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create().key("test1234")
.name("TestName1234").description("Desc1234").maxAssignments(5));
final String rsqlFindLikeDs1OrDs2 = "name==TestName123,name==TestName1234";
mvc.perform(get("/rest/v1/softwaremoduletypes?q=" + rsqlFindLikeDs1OrDs2)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(2)))
.andExpect(jsonPath("total", equalTo(2))).andExpect(jsonPath("content[0].name", equalTo("TestName123")))
.andExpect(jsonPath("content[1].name", equalTo("TestName1234")));
}
private void createSoftwareModulesAlphabetical(final int amount) {
char character = 'a';
for (int index = 0; index < amount; index++) {
final String str = String.valueOf(character);
softwareModuleManagement.create(entityFactory.softwareModule().create().type(osType).name(str)
.description(str).vendor(str).version(str));
character++;
}
}
}

View File

@@ -0,0 +1,399 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.exception.QuotaExceededException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Spring MVC Tests against the MgmtTargetResource.
*
*/
@Features("Component Tests - Management API")
@Stories("Target Filter Query Resource")
public class MgmtTargetFilterQueryResourceTest extends AbstractManagementApiIntegrationTest {
private static final String JSON_PATH_ROOT = "$";
// fields, attributes
private static final String JSON_PATH_FIELD_ID = ".id";
private static final String JSON_PATH_FIELD_NAME = ".name";
private static final String JSON_PATH_FIELD_QUERY = ".query";
private static final String JSON_PATH_FIELD_CONTENT = ".content";
private static final String JSON_PATH_FIELD_SIZE = ".size";
private static final String JSON_PATH_FIELD_TOTAL = ".total";
private static final String JSON_PATH_FIELD_AUTO_ASSIGN_DS = ".autoAssignDistributionSet";
private static final String JSON_PATH_FIELD_EXCEPTION_CLASS = ".exceptionClass";
private static final String JSON_PATH_FIELD_ERROR_CODE = ".errorCode";
// target
// $.field
static final String JSON_PATH_PAGED_LIST_CONTENT = JSON_PATH_ROOT + JSON_PATH_FIELD_CONTENT;
static final String JSON_PATH_PAGED_LIST_SIZE = JSON_PATH_ROOT + JSON_PATH_FIELD_SIZE;
static final String JSON_PATH_PAGED_LIST_TOTAL = JSON_PATH_ROOT + JSON_PATH_FIELD_TOTAL;
private static final String JSON_PATH_NAME = JSON_PATH_ROOT + JSON_PATH_FIELD_NAME;
private static final String JSON_PATH_ID = JSON_PATH_ROOT + JSON_PATH_FIELD_ID;
private static final String JSON_PATH_QUERY = JSON_PATH_ROOT + JSON_PATH_FIELD_QUERY;
private static final String JSON_PATH_AUTO_ASSIGN_DS = JSON_PATH_ROOT + JSON_PATH_FIELD_AUTO_ASSIGN_DS;
private static final String JSON_PATH_EXCEPTION_CLASS = JSON_PATH_ROOT + JSON_PATH_FIELD_EXCEPTION_CLASS;
private static final String JSON_PATH_ERROR_CODE = JSON_PATH_ROOT + JSON_PATH_FIELD_ERROR_CODE;
@Test
@Description("Ensures that deletion is executed if permitted.")
public void deleteTargetFilterQueryReturnsOK() throws Exception {
final String filterName = "filter_01";
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name=test_01");
mvc.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId()))
.andExpect(status().isOk());
assertThat(targetFilterQueryManagement.get(filterQuery.getId())).isNotPresent();
}
@Test
@Description("Ensures that deletion is refused with not found if target does not exist.")
public void deleteTargetWhichDoesNotExistsLeadsToEntityNotFound() throws Exception {
final String notExistingId = "4395";
mvc.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + notExistingId))
.andExpect(status().isNotFound());
}
@Test
@Description("Ensures that update is refused with not found if target does not exist.")
public void updateTargetWhichDoesNotExistsLeadsToEntityNotFound() throws Exception {
final String notExistingId = "4395";
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + notExistingId).content("{}")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@Description("Ensures that update request is reflected by repository.")
public void updateTargetFilterQueryQuery() throws Exception {
final String filterName = "filter_02";
final String filterQuery = "name=test_02";
final String filterQuery2 = "name=test_02_changed";
final String body = new JSONObject().put("query", filterQuery2).toString();
// prepare
final TargetFilterQuery tfq = createSingleTargetFilterQuery(filterName, filterQuery);
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()).content(body)
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.id", equalTo(tfq.getId().intValue())))
.andExpect(jsonPath("$.query", equalTo(filterQuery2)))
.andExpect(jsonPath("$.name", equalTo(filterName)));
final TargetFilterQuery tfqCheck = targetFilterQueryManagement.get(tfq.getId()).get();
assertThat(tfqCheck.getQuery()).isEqualTo(filterQuery2);
assertThat(tfqCheck.getName()).isEqualTo(filterName);
}
@Test
@Description("Ensures that update request is reflected by repository.")
public void updateTargetFilterQueryName() throws Exception {
final String filterName = "filter_03";
final String filterName2 = "filter_03_changed";
final String filterQuery = "name=test_03";
final String body = new JSONObject().put("name", filterName2).toString();
// prepare
final TargetFilterQuery tfq = targetFilterQueryManagement
.create(entityFactory.targetFilterQuery().create().name(filterName).query(filterQuery));
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()).content(body)
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath("$.id", equalTo(tfq.getId().intValue())))
.andExpect(jsonPath("$.query", equalTo(filterQuery)))
.andExpect(jsonPath("$.name", equalTo(filterName2)));
final TargetFilterQuery tfqCheck = targetFilterQueryManagement.get(tfq.getId()).get();
assertThat(tfqCheck.getQuery()).isEqualTo(filterQuery);
assertThat(tfqCheck.getName()).isEqualTo(filterName2);
}
@Test
@Description("Ensures that request returns list of filters in defined format.")
public void getTargetFilterQueryWithoutAdditionalRequestParameters() throws Exception {
final int knownTargetAmount = 3;
final String idA = "a";
final String idB = "b";
final String idC = "c";
final String testQuery = "name=test";
createSingleTargetFilterQuery(idA, testQuery);
createSingleTargetFilterQuery(idB, testQuery);
createSingleTargetFilterQuery(idC, testQuery);
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)).andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print())
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(knownTargetAmount)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(knownTargetAmount)))
// idA
.andExpect(jsonPath("$.content.[?(@.name==" + idA + ")].name", contains(idA)))
.andExpect(jsonPath("$.content.[?(@.name==" + idA + ")].query", contains(testQuery)))
// idB
.andExpect(jsonPath("$.content.[?(@.name==" + idB + ")].name", contains(idB)))
.andExpect(jsonPath("$.content.[?(@.name==" + idB + ")].query", contains(testQuery)))
// idC
.andExpect(jsonPath("$.content.[?(@.name==" + idC + ")].name", contains(idC)))
.andExpect(jsonPath("$.content.[?(@.name==" + idC + ")].query", contains(testQuery)));
}
@Test
@Description("Ensures that request returns list of filters in defined format in size reduced by given limit parameter.")
public void getTargetWithPagingLimitRequestParameter() throws Exception {
final int limitSize = 1;
final int knownTargetAmount = 3;
final String idA = "a";
final String idB = "b";
final String idC = "c";
final String testQuery = "name=test";
createSingleTargetFilterQuery(idA, testQuery);
createSingleTargetFilterQuery(idB, testQuery);
createSingleTargetFilterQuery(idC, testQuery);
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)))
// idA
.andExpect(jsonPath("$.content.[?(@.name==" + idA + ")].name", contains(idA)))
.andExpect(jsonPath("$.content.[?(@.name==" + idA + ")].query", contains(testQuery)));
}
@Test
@Description("Ensures that request returns list of filters in defined format in size reduced by given limit and offset parameter.")
public void getTargetWithPagingLimitAndOffsetRequestParameter() throws Exception {
final int knownTargetAmount = 5;
final int offsetParam = 2;
final int expectedSize = knownTargetAmount - offsetParam;
final String idC = "c";
final String idD = "d";
final String idE = "e";
final String testQuery = "name=test";
createSingleTargetFilterQuery("a", testQuery);
createSingleTargetFilterQuery("b", testQuery);
createSingleTargetFilterQuery(idC, testQuery);
createSingleTargetFilterQuery(idD, testQuery);
createSingleTargetFilterQuery(idE, testQuery);
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(knownTargetAmount)))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(knownTargetAmount)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)))
// idA
.andExpect(jsonPath("$.content.[?(@.name==" + idC + ")].name", contains(idC)))
.andExpect(jsonPath("$.content.[?(@.name==" + idC + ")].query", contains(testQuery)))
// idB
.andExpect(jsonPath("$.content.[?(@.name==" + idD + ")].name", contains(idD)))
.andExpect(jsonPath("$.content.[?(@.name==" + idD + ")].query", contains(testQuery)))
// idC
.andExpect(jsonPath("$.content.[?(@.name==" + idE + ")].name", contains(idE)))
.andExpect(jsonPath("$.content.[?(@.name==" + idE + ")].query", contains(testQuery)));
}
@Test
@Description("Ensures that a single target filter query can be retrieved via its id.")
public void getSingleTarget() throws Exception {
// create first a target which can be retrieved by rest interface
final String knownQuery = "name=test01";
final String knownName = "someName";
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
+ tfq.getId();
// test
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(knownName)))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(knownQuery)))
.andExpect(jsonPath("$._links.self.href", equalTo(hrefPrefix)))
.andExpect(jsonPath("$._links.autoAssignDS.href", equalTo(hrefPrefix + "/autoAssignDS")));
}
@Test
@Description("Ensures that the retrieval of a non-existing target filter query results in a HTTP Not found error (404).")
public void getSingleTargetNoExistsResponseNotFound() throws Exception {
final String targetIdNotExists = "546546";
// test
final MvcResult mvcResult = mvc
.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + targetIdNotExists))
.andExpect(status().isNotFound()).andReturn();
// verify response json exception message
final ExceptionInfo exceptionInfo = ResourceUtility
.convertException(mvcResult.getResponse().getContentAsString());
assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_REPO_ENTITY_NOT_EXISTS.getKey());
}
@Test
@Description("Ensures that the creation of a target filter query based on an invalid request payload results in a HTTP Bad Request error (400).")
public void createTargetFilterQueryWithBadPayloadBadRequest() throws Exception {
final String notJson = "abc";
final MvcResult mvcResult = mvc
.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING).content(notJson)
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn();
assertThat(targetFilterQueryManagement.count()).isEqualTo(0);
// verify response json exception message
final ExceptionInfo exceptionInfo = ResourceUtility
.convertException(mvcResult.getResponse().getContentAsString());
assertThat(exceptionInfo.getExceptionClass()).isEqualTo(MessageNotReadableException.class.getName());
assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_REST_BODY_NOT_READABLE.getKey());
}
@Test
@Description("Ensures that the assignment of an auto-assign distribution set results in a HTTP Forbidden error (403) "
+ "if the (existing) query addresses too many targets.")
public void setAutoAssignDistributionSetOnFilterQueryThatExceedsQuota() throws Exception {
// create targets
final int maxTargets = quotaManagement.getMaxTargetsPerAutoAssignment();
testdataFactory.createTargets(maxTargets + 1, "target%s");
// create the filter query and the distribution set
final DistributionSet set = testdataFactory.createDistributionSet();
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery("1", "controllerId==target*");
mvc.perform(
post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId() + "/autoAssignDS")
.content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden())
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(QuotaExceededException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
}
@Test
@Description("Ensures that the update of a target filter query results in a HTTP Forbidden error (403) "
+ "if the updated query addresses too many targets.")
public void updateTargetFilterQueryWithQueryThatExceedsQuota() throws Exception {
// create targets
final int maxTargets = quotaManagement.getMaxTargetsPerAutoAssignment();
testdataFactory.createTargets(maxTargets + 1, "target%s");
// create the filter query and the distribution set
final DistributionSet set = testdataFactory.createDistributionSet();
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery("1", "controllerId==target1");
// assign the auto-assign distribution set, this should work
mvc.perform(
post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId() + "/autoAssignDS")
.content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(targetFilterQueryManagement.get(filterQuery.getId()).get().getAutoAssignDistributionSet())
.isEqualTo(set);
// update the query of the filter query to trigger a quota hit
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId())
.content("{\"query\":\"controllerId==target*\"}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden())
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(QuotaExceededException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
}
@Test
public void setAutoAssignDistributionSetToTargetFilterQuery() throws Exception {
final String knownQuery = "name==test05";
final String knownName = "filter05";
final DistributionSet set = testdataFactory.createDistributionSet();
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(targetFilterQueryManagement.get(tfq.getId()).get().getAutoAssignDistributionSet()).isEqualTo(set);
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
+ tfq.getId();
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(knownName)))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(knownQuery)))
.andExpect(jsonPath(JSON_PATH_AUTO_ASSIGN_DS, equalTo(set.getId().intValue())))
.andExpect(jsonPath("$._links.self.href", equalTo(hrefPrefix)))
.andExpect(jsonPath("$._links.autoAssignDS.href", equalTo(hrefPrefix + "/autoAssignDS")));
}
@Test
public void deleteAutoAssignDistributionSetOfTargetFilterQuery() throws Exception {
final String knownQuery = "name==test06";
final String knownName = "filter06";
final String dsName = "testDS";
final DistributionSet set = testdataFactory.createDistributionSet(dsName);
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
targetFilterQueryManagement.updateAutoAssignDS(tfq.getId(), set.getId());
assertThat(targetFilterQueryManagement.get(tfq.getId()).get().getAutoAssignDistributionSet()).isEqualTo(set);
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
.andExpect(status().isOk()).andExpect(jsonPath(JSON_PATH_NAME, equalTo(dsName)));
mvc.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
.andExpect(status().isNoContent());
assertThat(targetFilterQueryManagement.get(tfq.getId()).get().getAutoAssignDistributionSet()).isNull();
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
.andExpect(status().isNoContent());
}
private TargetFilterQuery createSingleTargetFilterQuery(final String name, final String query) {
return targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(name).query(query));
}
}

View File

@@ -0,0 +1,313 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.event.remote.TargetTagDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.test.matcher.Expect;
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultActions;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Spring MVC Tests against the MgmtTargetTagResource.
*
*/
@Features("Component Tests - Management API")
@Stories("Target Tag Resource")
public class MgmtTargetTagResourceTest extends AbstractManagementApiIntegrationTest {
private static final String TARGETTAGS_ROOT = "http://localhost" + MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING
+ "/";
@Test
@Description("Verfies that a paged result list of target tags reflects the content on the repository side.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 2) })
public void getTargetTags() throws Exception {
final List<TargetTag> tags = testdataFactory.createTargetTags(2, "");
final TargetTag assigned = tags.get(0);
final TargetTag unassigned = tags.get(1);
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(applyTagMatcherOnPagedResult(assigned)).andExpect(applyTagMatcherOnPagedResult(unassigned))
.andExpect(applySelfLinkMatcherOnPagedResult(assigned, TARGETTAGS_ROOT + assigned.getId()))
.andExpect(applySelfLinkMatcherOnPagedResult(unassigned, TARGETTAGS_ROOT + unassigned.getId()))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
}
@Test
@Description("Verfies that a single result of a target tag reflects the content on the repository side.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 2) })
public void getTargetTag() throws Exception {
final List<TargetTag> tags = testdataFactory.createTargetTags(2, "");
final TargetTag assigned = tags.get(0);
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + assigned.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(applyTagMatcherOnSingleResult(assigned))
.andExpect(applySelfLinkMatcherOnSingleResult(TARGETTAGS_ROOT + assigned.getId()))
.andExpect(jsonPath("_links.assignedTargets.href",
equalTo(TARGETTAGS_ROOT + assigned.getId() + "/assigned?offset=0&limit=50{&sort,q}")));
}
@Test
@Description("Verifies that created target tags are stored in the repository as send to the API.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 2) })
public void createTargetTags() throws Exception {
final Tag tagOne = entityFactory.tag().create().colour("testcol1").description("its a test1").name("thetest1")
.build();
final Tag tagTwo = entityFactory.tag().create().colour("testcol2").description("its a test2").name("thetest2")
.build();
final ResultActions result = mvc
.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING)
.content(JsonBuilder.tags(Arrays.asList(tagOne, tagTwo)))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
final Tag createdOne = targetTagManagement.findByRsql(PAGE, "name==thetest1").getContent().get(0);
assertThat(createdOne.getName()).isEqualTo(tagOne.getName());
assertThat(createdOne.getDescription()).isEqualTo(tagOne.getDescription());
assertThat(createdOne.getColour()).isEqualTo(tagOne.getColour());
final Tag createdTwo = targetTagManagement.findByRsql(PAGE, "name==thetest2").getContent().get(0);
assertThat(createdTwo.getName()).isEqualTo(tagTwo.getName());
assertThat(createdTwo.getDescription()).isEqualTo(tagTwo.getDescription());
assertThat(createdTwo.getColour()).isEqualTo(tagTwo.getColour());
result.andExpect(applyTagMatcherOnArrayResult(createdOne)).andExpect(applyTagMatcherOnArrayResult(createdTwo));
}
@Test
@Description("Verifies that an updated target tag is stored in the repository as send to the API.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetTagUpdatedEvent.class, count = 1) })
public void updateTargetTag() throws Exception {
final List<TargetTag> tags = testdataFactory.createTargetTags(1, "");
final TargetTag original = tags.get(0);
final Tag update = entityFactory.tag().create().name("updatedName").colour("updatedCol")
.description("updatedDesc").build();
final ResultActions result = mvc
.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + original.getId())
.content(JsonBuilder.tag(update)).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
final Tag updated = targetTagManagement.findByRsql(PAGE, "name==updatedName").getContent().get(0);
assertThat(updated.getName()).isEqualTo(update.getName());
assertThat(updated.getDescription()).isEqualTo(update.getDescription());
assertThat(updated.getColour()).isEqualTo(update.getColour());
result.andExpect(applyTagMatcherOnArrayResult(updated)).andExpect(applyTagMatcherOnArrayResult(updated));
}
@Test
@Description("Verfies that the delete call is reflected by the repository.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetTagDeletedEvent.class, count = 1) })
public void deleteTargetTag() throws Exception {
final List<TargetTag> tags = testdataFactory.createTargetTags(1, "");
final TargetTag original = tags.get(0);
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + original.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(targetTagManagement.get(original.getId())).isNotPresent();
}
@Test
@Description("Ensures that assigned targets to tag in repository are listed with proper paging results.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetCreatedEvent.class, count = 5), @Expect(type = TargetUpdatedEvent.class, count = 5) })
public void getAssignedTargets() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final int targetsAssigned = 5;
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
targetManagement.toggleTagAssignment(targets.stream().map(Target::getControllerId).collect(Collectors.toList()),
tag.getName());
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(targetsAssigned)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(targetsAssigned)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(targetsAssigned)));
}
@Test
@Description("Ensures that assigned DS to tag in repository are listed with proper paging results with paging limit parameter.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetCreatedEvent.class, count = 5), @Expect(type = TargetUpdatedEvent.class, count = 5) })
public void getAssignedTargetsWithPagingLimitRequestParameter() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final int targetsAssigned = 5;
final int limitSize = 1;
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
targetManagement.toggleTagAssignment(targets.stream().map(Target::getControllerId).collect(Collectors.toList()),
tag.getName());
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(targetsAssigned)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)));
}
@Test
@Description("Ensures that assigned targets to tag in repository are listed with proper paging results with paging limit and offset parameter.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetCreatedEvent.class, count = 5), @Expect(type = TargetUpdatedEvent.class, count = 5) })
public void getAssignedTargetsWithPagingLimitAndOffsetRequestParameter() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final int targetsAssigned = 5;
final int offsetParam = 2;
final int expectedSize = targetsAssigned - offsetParam;
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
targetManagement.toggleTagAssignment(targets.stream().map(Target::getControllerId).collect(Collectors.toList()),
tag.getName());
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offsetParam))
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(targetsAssigned)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(targetsAssigned)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
}
@Test
@Description("verfies that tag assignments done through toggle API command are correctly assigned or unassigned.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 4) })
public void toggleTagAssignment() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final int targetsAssigned = 2;
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
ResultActions result = toggle(tag, targets);
List<Target> updated = targetManagement.findByTag(PAGE, tag.getId()).getContent();
assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))
.containsAll(targets.stream().map(Target::getControllerId).collect(Collectors.toList()));
result.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(0), "assignedTargets"))
.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(1), "assignedTargets"));
result = toggle(tag, targets);
updated = targetManagement.findAll(PAGE).getContent();
result.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(0), "unassignedTargets"))
.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(1), "unassignedTargets"));
assertThat(targetManagement.findByTag(PAGE, tag.getId())).isEmpty();
}
private ResultActions toggle(final TargetTag tag, final List<Target> targets) throws Exception {
return mvc
.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId()
+ "/assigned/toggleTagAssignment")
.content(JsonBuilder.controllerIds(
targets.stream().map(Target::getControllerId).collect(Collectors.toList())))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
}
@Test
@Description("Verfies that tag assignments done through tag API command are correctly stored in the repository.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 2) })
public void assignTargets() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final int targetsAssigned = 2;
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
final ResultActions result = mvc
.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.content(JsonBuilder.controllerIds(
targets.stream().map(Target::getControllerId).collect(Collectors.toList())))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE));
final List<Target> updated = targetManagement.findByTag(PAGE, tag.getId()).getContent();
assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))
.containsAll(targets.stream().map(Target::getControllerId).collect(Collectors.toList()));
result.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(0)))
.andExpect(applyTargetEntityMatcherOnArrayResult(updated.get(1)));
}
@Test
@Description("Verfies that tag unassignments done through tag API command are correctly stored in the repository.")
@ExpectEvents({ @Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetCreatedEvent.class, count = 2), @Expect(type = TargetUpdatedEvent.class, count = 3) })
public void unassignTarget() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final int targetsAssigned = 2;
final List<Target> targets = testdataFactory.createTargets(targetsAssigned);
final Target assigned = targets.get(0);
final Target unassigned = targets.get(1);
targetManagement.toggleTagAssignment(targets.stream().map(Target::getControllerId).collect(Collectors.toList()),
tag.getName());
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned/"
+ unassigned.getControllerId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
final List<Target> updated = targetManagement.findByTag(PAGE, tag.getId()).getContent();
assertThat(updated.stream().map(Target::getControllerId).collect(Collectors.toList()))
.containsOnly(assigned.getControllerId());
}
}

View File

@@ -0,0 +1,47 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import java.io.IOException;
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
import org.eclipse.hawkbit.mgmt.json.model.artifact.MgmtArtifact;
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Utility additions for the REST API tests.
*
*
*
*
*/
public final class ResourceUtility {
private static final ObjectMapper mapper = new ObjectMapper();
static ExceptionInfo convertException(final String jsonExceptionResponse)
throws JsonParseException, JsonMappingException, IOException {
return mapper.readValue(jsonExceptionResponse, ExceptionInfo.class);
}
static MgmtArtifact convertArtifactResponse(final String jsonResponse)
throws JsonParseException, JsonMappingException, IOException {
return mapper.readValue(jsonResponse, MgmtArtifact.class);
}
static <T> PagedList<T> mapResponse(final Class<T> clazz, final String responseBody)
throws JsonParseException, JsonMappingException, IOException {
return mapper.readValue(responseBody, PagedList.class);
}
}