Move Mgmt artifacts into hawkbit-mgmt (#2003)

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-11-11 15:57:56 +02:00
committed by GitHub
parent 05d8d6cc7e
commit baab2fcf95
200 changed files with 167 additions and 114 deletions

View File

@@ -0,0 +1,236 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
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.mgmt.json.model.distributionset.MgmtActionType;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.DistributionSet;
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.repository.test.TestConfiguration;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.eclipse.hawkbit.rest.RestConfiguration;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.ResultMatcher;
@ContextConfiguration(classes = { MgmtApiConfiguration.class, RestConfiguration.class,
RepositoryApplicationConfiguration.class, TestConfiguration.class })
@Import(TestChannelBinderConfiguration.class)
@TestPropertySource(locations = "classpath:/mgmt-test.properties")
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);
};
}
protected static JSONObject getAssignmentObject(final Object id, final MgmtActionType type) {
final JSONObject obj = new JSONObject();
try {
obj.put("id", id);
obj.put("type", type.getName());
} catch (final JSONException e) {
e.printStackTrace();
}
return obj;
}
protected static JSONObject getAssignmentObject(final Object id, final MgmtActionType type, final int weight) {
try {
return getAssignmentObject(id, type).put("weight", weight);
} catch (final JSONException e) {
e.printStackTrace();
}
return new JSONObject();
}
// the set is a candidate for implicitly locking. So, lock it if not already locked
// set lock flag to true to avoid re-locking
static void implicitLock(final DistributionSet set) {
if (!set.isLocked()) {
((JpaDistributionSet) set).setOptLockRevision(set.getOptLockRevision() + 1);
((JpaDistributionSet) set).lock();
}
}
}

View File

@@ -0,0 +1,599 @@
/**
* Copyright (c) 2022 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
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.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.awaitility.Awaitility;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtActionRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRepresentationMode;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.ResultActions;
/**
* Integration test for the {@link MgmtActionRestApi}.
*/
@Feature("Component Tests - Management API")
@Story("Action Resource")
class MgmtActionResourceTest extends AbstractManagementApiIntegrationTest {
private static final String JSON_PATH_ROOT = "$";
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_ID = ".id";
private static final String JSON_PATH_PAGED_LIST_CONTENT = JSON_PATH_ROOT + JSON_PATH_FIELD_CONTENT;
private static final String JSON_PATH_PAGED_LIST_SIZE = JSON_PATH_ROOT + JSON_PATH_FIELD_SIZE;
private static final String JSON_PATH_PAGED_LIST_TOTAL = JSON_PATH_ROOT + JSON_PATH_FIELD_TOTAL;
private static final String JSON_PATH_ACTION_ID = JSON_PATH_ROOT + JSON_PATH_FIELD_ID;
@Test
@Description("Handles the GET request of retrieving a specific action.")
public void getAction() throws Exception {
getAction(false);
}
@Test
@Description("Handles the GET request of retrieving a specific action with external reference.")
public void getActionExtRef() throws Exception {
getAction(true);
}
@Test
@Description("Verifies that actions can be filtered based on action status.")
void filterActionsByStatus() throws Exception {
// prepare test
final DistributionSet dsA = testdataFactory.createDistributionSet("");
assignDistributionSet(dsA, Collections.singletonList(testdataFactory.createTarget("knownTargetId")));
final String rsqlPendingStatus = "status==pending";
final String rsqlFinishedStatus = "status==finished";
final String rsqlPendingOrFinishedStatus = rsqlFinishedStatus + "," + rsqlPendingStatus;
// pending status one result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlPendingStatus))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content[0].status", equalTo("pending")));
// finished status none result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlFinishedStatus))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(0)))
.andExpect(jsonPath("size", equalTo(0)));
// pending or finished status one result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlPendingOrFinishedStatus))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content[0].status", equalTo("pending")));
}
@Test
@Description("Verifies that actions can be filtered based on the detailed action status.")
void filterActionsByDetailStatus() throws Exception {
// prepare test
final DistributionSet dsA = testdataFactory.createDistributionSet("");
assignDistributionSet(dsA, Collections.singletonList(testdataFactory.createTarget("knownTargetId")));
final String rsqlPendingStatus = "detailStatus==running";
final String rsqlFinishedStatus = "detailStatus==finished";
final String rsqlPendingOrFinishedStatus = rsqlFinishedStatus + "," + rsqlPendingStatus;
// running status one result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlPendingStatus))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1)))
.andExpect(jsonPath("content[0].detailStatus", equalTo("running")))
.andExpect(jsonPath("content[0].status", equalTo("pending")));
// finished status none result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlFinishedStatus))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(0)))
.andExpect(jsonPath("size", equalTo(0)));
// running or finished status one result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlPendingOrFinishedStatus))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1)))
.andExpect(jsonPath("content[0].detailStatus", equalTo("running")))
.andExpect(jsonPath("content[0].status", equalTo("pending")));
}
@Test
@Description("Verifies that actions can be filtered based on extRef.")
void filterActionsByExternalRef() throws Exception {
// prepare test
final String knownTargetId = "targetId";
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
final Action action0 = actions.get(0);
final Action action1 = actions.get(1);
final List<String> externalRefs = new ArrayList<>(2);
externalRefs.add("extRef");
externalRefs.add("extRef#123_1");
controllerManagement.updateActionExternalRef(action0.getId(), externalRefs.get(0));
controllerManagement.updateActionExternalRef(action1.getId(), externalRefs.get(1));
final String rsqlExtRef = "externalref==extRef";
final String rsqlExtRefWildcard = "externalref==extRef*";
final String rsqlExtRefNoMatch = "externalref==234extRef";
// pending status one result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlExtRef))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1)))
.andExpect(jsonPath("content[0].externalRef", equalTo(externalRefs.get(0))));
// finished status none result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlExtRefWildcard))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("total", equalTo(2)))
.andExpect(jsonPath("size", equalTo(2)));
// pending or finished status one result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlExtRefNoMatch))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("total", equalTo(0)))
.andExpect(jsonPath("size", equalTo(0)));
}
@Test
@Description("Verifies that actions can be filtered based on the action status code that was reported last.")
void filterActionsByLastStatusCode() throws Exception {
// assign a distribution set to three targets
final DistributionSet dsA = testdataFactory.createDistributionSet("");
final DistributionSetAssignmentResult assignmentResult = assignDistributionSet(dsA,
testdataFactory.createTargets("target1", "target2", "target3"));
final List<Action> actions = assignmentResult.getAssignedEntity();
assertThat(actions).hasSize(3);
// then simulate a status update with code 200 for the first action
final Action action = actions.get(0);
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(action.getId()).code(200)
.message("Update succeeded").status(Status.FINISHED));
// verify that one result is returned if the actions are filtered for
// status code 200
final String rsqlStatusCode = "lastStatusCode==200";
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlStatusCode))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content[0].status", equalTo("finished")));
// verify no result is returned if we filter for a non-existing status
// code
final String rsqlWrongStatusCode = "lastStatusCode==999";
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlWrongStatusCode))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(0)))
.andExpect(jsonPath("size", equalTo(0)));
}
@Test
@Description("Verifies that actions can be filtered based on distribution set fields.")
void filterActionsByDistributionSet() throws Exception {
// prepare test
final DistributionSet ds = testdataFactory.createDistributionSet("");
assignDistributionSet(ds, Collections.singletonList(testdataFactory.createTarget("knownTargetId")));
final String rsqlDsName = "distributionSet.name==" + ds.getName() + "*";
final String rsqlDsVersion = "distributionSet.version==" + ds.getVersion();
final String rsqlDsId = "distributionSet.id==" + ds.getId();
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlDsName)
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1))).andExpect(jsonPath("content.[0]._links.distributionset.name",
equalTo(ds.getName() + ":" + ds.getVersion())));
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlDsVersion))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1)));
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlDsName + "," + rsqlDsVersion))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1)));
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=distributionSet.name==FooBar"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(0)))
.andExpect(jsonPath("size", equalTo(0)));
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlDsId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1)));
}
@Test
@Description("Verifies that actions can be filtered based on rollout fields.")
void filterActionsByRollout() throws Exception {
// prepare test
final DistributionSet ds = testdataFactory.createDistributionSet();
final Target target0 = testdataFactory.createTarget("t0");
// manual assignment
assignDistributionSet(ds, Collections.singletonList(target0));
// rollout
final Target target1 = testdataFactory.createTarget("t1");
final Rollout rollout = testdataFactory.createRolloutByVariables("TestRollout", "TestDesc", 1,
"name==" + target1.getName(), ds, "50", "5");
rolloutManagement.start(rollout.getId());
rolloutHandler.handleAll();
final String rsqlRolloutName = "rollout.name==" + rollout.getName();
final String rsqlRolloutId = "rollout.id==" + rollout.getId();
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlRolloutName)
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1)))
.andExpect(jsonPath("content.[0]._links.target.name", equalTo(target1.getName()))).andExpect(jsonPath(
"content.[0]._links.distributionset.name", equalTo(ds.getName() + ":" + ds.getVersion())));
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlRolloutId)
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1)))
.andExpect(jsonPath("content.[0]._links.target.name", equalTo(target1.getName()))).andExpect(jsonPath(
"content.[0]._links.distributionset.name", equalTo(ds.getName() + ":" + ds.getVersion())));
}
@Test
@Description("Verifies that actions can be filtered based on target fields.")
void filterActionsByTargetProperties() throws Exception {
// prepare test
final Target target = testdataFactory.createTarget("knownTargetId", "knownTargetName", "http://0.0.0.0");
final DistributionSet ds = testdataFactory.createDistributionSet("");
assignDistributionSet(ds, Collections.singletonList(target));
final String rsqlTargetControllerId = "target.controllerId==knownTargetId";
final String rsqlTargetName = "target.name==knownTargetName";
final String rsqlTargetUpdateStatus = "target.updateStatus==pending";
final String rsqlTargetAddress = "target.address==http://0.0.0.0";
verifyResultsByTargetPropertyFilter(target, ds, rsqlTargetControllerId);
verifyResultsByTargetPropertyFilter(target, ds, rsqlTargetName);
verifyResultsByTargetPropertyFilter(target, ds, rsqlTargetUpdateStatus);
verifyResultsByTargetPropertyFilter(target, ds, rsqlTargetAddress);
}
@Test
@Description("Verifies that all available actions are returned if the complete collection is requested.")
void getActions() throws Exception {
getActions(false);
}
@Test
@Description("Verifies that all available actions (whit ext refs) are returned if the complete collection is requested.")
void getActionsExtRef() throws Exception {
getActions(true);
}
@Test
@Description("Verifies that a full representation of all actions is returned if the collection is requested for representation mode 'full'.")
void getActionsFullRepresentation() throws Exception {
final String knownTargetId = "targetId";
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
final Action action0 = actions.get(0);
final Action action1 = actions.get(1);
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
// verify action 1
.andExpect(jsonPath("content.[1].id", equalTo(action1.getId().intValue())))
.andExpect(jsonPath("content.[1].type", equalTo("update")))
.andExpect(jsonPath("content.[1].status", equalTo("pending")))
.andExpect(jsonPath("content.[1].detailStatus", equalTo("running")))
.andExpect(jsonPath("content.[1]._links.self.href",
equalTo(generateActionLink(knownTargetId, action1.getId()))))
.andExpect(jsonPath("content.[1]._links.target.href", equalTo(generateTargetLink(knownTargetId))))
.andExpect(jsonPath("content.[1]._links.distributionset.href",
equalTo(generateDistributionSetLink(action1))))
// verify action 0
.andExpect(jsonPath("content.[0].id", equalTo(action0.getId().intValue())))
.andExpect(jsonPath("content.[0].type", equalTo("cancel")))
.andExpect(jsonPath("content.[0].status", equalTo("pending")))
.andExpect(jsonPath("content.[0].detailStatus", equalTo("canceling")))
.andExpect(jsonPath("content.[0]._links.self.href",
equalTo(generateActionLink(knownTargetId, action0.getId()))))
.andExpect(jsonPath("content.[0]._links.target.href", equalTo(generateTargetLink(knownTargetId))))
.andExpect(jsonPath("content.[0]._links.distributionset.href",
equalTo(generateDistributionSetLink(action0))))
// verify collection properties
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
}
@Test
@Description("Verifies that the get request for actions returns an empty collection if no assignments have been done yet.")
void getActionsWithEmptyResult() throws Exception {
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(jsonPath("size", equalTo(0)))
.andExpect(jsonPath("content", hasSize(0))).andExpect(jsonPath("total", equalTo(0)));
}
@Test
@Description("Verifies paging is respected as expected.")
void getMultipleActionsWithPagingLimitRequestParameter() throws Exception {
final String knownTargetId = "targetId";
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
// page 1: one entry
final Action action0 = actions.get(0);
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1))
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
// verify action 0
.andExpect(jsonPath("content.[0].id", equalTo(action0.getId().intValue())))
.andExpect(jsonPath("content.[0].type", equalTo("cancel")))
.andExpect(jsonPath("content.[0].status", equalTo("pending")))
.andExpect(jsonPath("content.[0].detailStatus", equalTo(action0.getStatus().toString().toLowerCase())))
.andExpect(jsonPath("content.[0]._links.self.href",
equalTo(generateActionLink(knownTargetId, action0.getId()))))
// verify collection properties
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
// page 2: one entry
final Action action1 = actions.get(1);
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1))
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1))
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1))
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
// verify action 1
.andExpect(jsonPath("content.[0].id", equalTo(action1.getId().intValue())))
.andExpect(jsonPath("content.[0].type", equalTo("update")))
.andExpect(jsonPath("content.[0].status", equalTo("pending")))
.andExpect(jsonPath("content.[0].detailStatus", equalTo(action1.getStatus().toString().toLowerCase())))
.andExpect(jsonPath("content.[0]._links.self.href",
equalTo(generateActionLink(knownTargetId, action1.getId()))))
// verify collection properties
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
}
@Test
@Description("Verifies that the actions resource is read-only.")
void invalidRequestsOnActionResource() throws Exception {
final String knownTargetId = "targetId";
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
final Long actionId = actions.get(0).getId();
// not allowed methods
mvc.perform(post(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(put(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
}
@Test
@Description("Verifies that the correct action is returned")
void shouldRetrieveCorrectActionById() throws Exception {
final String knownTargetId = "targetId";
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
final Long actionId = actions.get(0).getId();
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "/" + actionId))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_ACTION_ID, equalTo(actionId.intValue())));
}
@Test
@Description("Verifies that NOT_FOUND is returned when there is no such action.")
void requestActionThatDoesNotExistsLeadsToNotFound() throws Exception {
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "/" + 101)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
private static String generateActionLink(final String targetId, final Long actionId) {
return "http://localhost" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetId + "/"
+ MgmtRestConstants.TARGET_V1_ACTIONS + "/" + actionId;
}
private static String generateTargetLink(final String targetId) {
return "http://localhost" + MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + targetId;
}
private static String generateDistributionSetLink(final Action action) {
return "http://localhost" + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING + "/"
+ action.getDistributionSet().getId();
}
@Step
private void verifyResultsByTargetPropertyFilter(final Target target, final DistributionSet ds,
final String rsqlTargetFilter) throws Exception {
// pending status one result
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "?q=" + rsqlTargetFilter)
.param(MgmtRestConstants.REQUEST_PARAMETER_REPRESENTATION_MODE, MgmtRepresentationMode.FULL.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()).andExpect(jsonPath("total", equalTo(1)))
.andExpect(jsonPath("size", equalTo(1)))
.andExpect(jsonPath("content.[0]._links.target.name", equalTo(target.getName()))).andExpect(jsonPath(
"content.[0]._links.distributionset.name", equalTo(ds.getName() + ":" + ds.getVersion())));
}
private void getActions(final boolean withExternalRef) throws Exception {
final String knownTargetId = "targetId";
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
final Action action0 = actions.get(0);
final Action action1 = actions.get(1);
final List<String> externalRefs = new ArrayList<>(2);
if (withExternalRef) {
externalRefs.add("extRef#123_0");
externalRefs.add("extRef#123_1");
controllerManagement.updateActionExternalRef(action0.getId(), externalRefs.get(0));
controllerManagement.updateActionExternalRef(action1.getId(), externalRefs.get(1));
}
final ResultActions resultActions =
mvc.perform(
get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC"))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
// verify action 1
.andExpect(jsonPath("content.[1].id", equalTo(action1.getId().intValue())))
.andExpect(jsonPath("content.[1].type", equalTo("update")))
.andExpect(jsonPath("content.[1].status", equalTo("pending")))
.andExpect(jsonPath("content.[1].detailStatus", equalTo("running")))
.andExpect(jsonPath("content.[1]._links.self.href",
equalTo(generateActionLink(knownTargetId, action1.getId()))))
// verify action 0
.andExpect(jsonPath("content.[0].id", equalTo(action0.getId().intValue())))
.andExpect(jsonPath("content.[0].type", equalTo("cancel")))
.andExpect(jsonPath("content.[0].status", equalTo("pending")))
.andExpect(jsonPath("content.[1].detailStatus", equalTo("running")))
.andExpect(jsonPath("content.[0]._links.self.href",
equalTo(generateActionLink(knownTargetId, action0.getId()))))
// verify collection properties
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
if (withExternalRef) {
resultActions
.andExpect(jsonPath("content.[1].externalRef", equalTo(externalRefs.get(1))))
.andExpect(jsonPath("content.[0].externalRef", equalTo(externalRefs.get(0))));
}
}
private void getAction(final boolean withExternalRef) throws Exception {
final String knownTargetId = "targetId";
// prepare ds
final DistributionSet ds = testdataFactory.createDistributionSet();
// rollout
final Target target = testdataFactory.createTarget(knownTargetId);
final Rollout rollout = testdataFactory.createRolloutByVariables("TestRollout", "TestDesc", 1,
"name==" + target.getName(), ds, "50", "5");
rolloutManagement.start(rollout.getId());
rolloutHandler.handleAll();
final List<Action> actions = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE)
.getContent();
assertThat(actions).hasSize(1);
final String externalRef = "externalRef#123";
if (withExternalRef) {
controllerManagement.updateActionExternalRef(actions.get(0).getId(), externalRef);
}
final ResultActions resultActions =
mvc.perform(get(MgmtRestConstants.ACTION_V1_REQUEST_MAPPING + "/{actionId}", actions.get(0).getId()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
if (withExternalRef) {
resultActions.andExpect(jsonPath("externalRef", equalTo(externalRef)));
}
}
private List<Action> generateTargetWithTwoUpdatesWithOneOverride(final String knownTargetId) {
return generateTargetWithTwoUpdatesWithOneOverrideWithMaintenanceWindow(knownTargetId, null, null, null);
}
private List<Action> generateTargetWithTwoUpdatesWithOneOverrideWithMaintenanceWindow(final String knownTargetId,
final String schedule, final String duration, final String timezone) {
final Target target = testdataFactory.createTarget(knownTargetId);
final Iterator<DistributionSet> sets = testdataFactory.createDistributionSets(2).iterator();
final DistributionSet one = sets.next();
final DistributionSet two = sets.next();
// Update
if (schedule == null) {
final List<Target> updatedTargets = assignDistributionSet(one, Collections.singletonList(target))
.getAssignedEntity().stream().map(Action::getTarget).collect(Collectors.toList());
// 2nd update
// sleep 10ms to ensure that we can sort by reportedAt
Awaitility.await().atMost(Duration.ofMillis(100)).atLeast(5, TimeUnit.MILLISECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> updatedTargets.stream().allMatch(t -> t.getLastModifiedAt() > 0L));
assignDistributionSet(two, updatedTargets);
} else {
final List<Target> updatedTargets = assignDistributionSetWithMaintenanceWindow(one.getId(),
target.getControllerId(), schedule, duration, timezone).getAssignedEntity().stream()
.map(Action::getTarget).collect(Collectors.toList());
// 2nd update
// sleep 10ms to ensure that we can sort by reportedAt
Awaitility.await().atMost(Duration.ofMillis(100)).atLeast(5, TimeUnit.MILLISECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> updatedTargets.stream().allMatch(t -> t.getLastModifiedAt() > 0L));
assignDistributionSetWithMaintenanceWindow(two.getId(), updatedTargets.get(0).getControllerId(), schedule,
duration, timezone);
}
// two updates, one cancellation
final List<Action> actions = deploymentManagement.findActionsByTarget(target.getControllerId(), PAGE)
.getContent();
assertThat(actions).hasSize(2);
return actions;
}
}

View File

@@ -0,0 +1,117 @@
/**
* Copyright (c) 2021 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
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 io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.test.TestConfiguration;
import org.eclipse.hawkbit.repository.test.matcher.EventVerifier;
import org.eclipse.hawkbit.repository.test.util.CleanupTestExecutionListener;
import org.eclipse.hawkbit.repository.test.util.JUnitTestLoggerExtension;
import org.eclipse.hawkbit.repository.test.util.SharedSqlTestDatabaseExtension;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.RestConfiguration;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.HttpHeaders;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.util.Base64Utils;
import org.springframework.web.context.WebApplicationContext;
/**
* Test for {@link MgmtBasicAuthResource}.
*/
@ActiveProfiles({ "test" })
@ExtendWith({ JUnitTestLoggerExtension.class, SharedSqlTestDatabaseExtension.class })
@SpringBootTest
// destroy the context after each test class because otherwise we get problem
// when context is
// refreshed we e.g. get two instances of CacheManager which leads to very
// strange test failures.
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
// Cleaning repository will fire "delete" events. We won't count them to the
// test execution. So, the order execution between EventVerifier and Cleanup is
// important!
@TestExecutionListeners(listeners = { EventVerifier.class, CleanupTestExecutionListener.class },
mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
@TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true")
@WebAppConfiguration
@AutoConfigureMockMvc
@ContextConfiguration(classes = { MgmtApiConfiguration.class, RestConfiguration.class,
RepositoryApplicationConfiguration.class, TestConfiguration.class })
@Import(TestChannelBinderConfiguration.class)
@Feature("Component Tests - Management API")
@Story("Basic auth Userinfo Resource")
public class MgmtBasicAuthResourceTest {
@Autowired
protected WebApplicationContext webApplicationContext;
@Autowired
MockMvc defaultMock;
private static final String TEST_USER = "testUser";
private static final String DEFAULT = "default";
@Test
@Description("Test of userinfo api with basic auth validation")
@WithUser(principal = TEST_USER)
public void validateBasicAuthWithUserDetails() throws Exception {
withSecurityMock().perform(get(MgmtRestConstants.AUTH_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON_VALUE))
.andExpect(jsonPath("$.username", equalTo(TEST_USER)))
.andExpect(jsonPath("$.tenant", equalTo(DEFAULT)));
}
@Test
@Description("Test of userinfo api with invalid basic auth fails")
public void validateBasicAuthFailsWithInvalidCredentials() throws Exception {
defaultMock.perform(get(MgmtRestConstants.AUTH_V1_REQUEST_MAPPING)
.header(HttpHeaders.AUTHORIZATION, getBasicAuth("wrongUser", "wrongSecret")))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isUnauthorized());
}
private String getBasicAuth(final String username, final String password) {
return "Basic " + Base64Utils.encodeToString((username + ":" + password).getBytes());
}
private MockMvc withSecurityMock() throws Exception {
return createMvcWebAppContext(webApplicationContext).build();
}
private DefaultMockMvcBuilder createMvcWebAppContext(final WebApplicationContext context) {
return MockMvcBuilders.webAppContextSetup(context);
}
}

View File

@@ -0,0 +1,196 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
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.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Arrays;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.servlet.server.Encoding;
import org.springframework.context.annotation.Import;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
/**
* With Spring Boot 2.2.x the default charset encoding became deprecated. In
* hawkBit we want to keep the old behavior for now and still return the charset
* in the response, which is achieved through enabling {@link Encoding} via
* properties.
*/
@SpringBootTest(properties = { "server.servlet.encoding.charset=UTF-8", "server.servlet.encoding.force=true" })
@Import(HttpEncodingAutoConfiguration.class)
@Feature("Component Tests - Management API")
@Story("Response Content-Type")
public class MgmtContentTypeTest extends AbstractManagementApiIntegrationTest {
private final String dsName = "DS-ö";
private DistributionSet ds;
@BeforeEach
public void setupBeforeTest() {
ds = testdataFactory.generateDistributionSet(dsName);
}
@Test
@Description("The response of a POST request shall contain charset=utf-8")
public void postDistributionSet_ContentTypeJsonUtf8_woAccept() throws Exception {
final MvcResult result = mvc.perform(
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
.contentType(MediaType.APPLICATION_JSON_UTF8)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isCreated()).andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
}
@Test
@Description("The response of a POST request shall contain charset=utf-8")
public void postDistributionSet_ContentTypeJsonUtf8_wAcceptJson() throws Exception {
final MvcResult result = mvc.perform(
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
}
@Test
@Description("The response of a POST request shall contain charset=utf-8")
public void postDistributionSet_ContentTypeJsonUtf8_wAcceptJsonUtf8() throws Exception {
final MvcResult result = mvc.perform(
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
}
@Test
@Description("The response of a POST request shall contain charset=utf-8")
public void postDistributionSet_ContentTypeJsonUtf8_wAcceptHalJson() throws Exception {
final MvcResult result = mvc.perform(
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
.contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaTypes.HAL_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
}
@Test
@Description("The response of a POST request shall contain charset=utf-8")
public void postDistributionSet_ContentTypeJson_woAccept() throws Exception {
final MvcResult result = mvc.perform(
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isCreated())
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
}
@Test
@Description("The response of a POST request shall contain charset=utf-8")
public void postDistributionSet_ContentTypeJson_wAcceptJson() throws Exception {
final MvcResult result = mvc.perform(
post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).content(JsonBuilder.distributionSets(Arrays.asList(ds)))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
}
@Test
@Description("The response of a POST request shall contain charset=utf-8")
public void postDistributionSet_ContentTypeJson_wAcceptJsonUtf8() throws Exception {
final MvcResult result = mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)
.content(JsonBuilder.distributionSets(Arrays.asList(ds))).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON_UTF8)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isCreated())
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
}
@Test
@Description("The response of a POST request shall contain charset=utf-8")
public void postDistributionSet_ContentTypeJson_wAcceptHalJson() throws Exception {
final MvcResult result = mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)
.content(JsonBuilder.distributionSets(Arrays.asList(ds))).contentType(MediaType.APPLICATION_JSON)
.accept(MediaTypes.HAL_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isCreated())
.andExpect(jsonPath("[0]name", equalTo(dsName))).andReturn();
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
}
@Test
@Description("The response of a GET request shall contain charset=utf-8")
public void getDistributionSet_woAccept() throws Exception {
final MvcResult result = mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andReturn();
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
}
@Test
@Description("The response of a GET request shall contain charset=utf-8")
public void getDistributionSet_wAcceptJson() throws Exception {
final MvcResult result = mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andReturn();
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
}
@Test
@Description("The response of a GET request shall contain charset=utf-8")
public void getDistributionSet_wAcceptJsonUtf8() throws Exception {
final MvcResult result = mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).accept(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andReturn();
assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE, getResponseHeaderContentType(result));
}
@Test
@Description("The response of a GET request shall contain charset=utf-8")
public void getDistributionSet_wAcceptHalJson() throws Exception {
final MvcResult result = mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING).accept(MediaTypes.HAL_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andReturn();
assertEquals(MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8", getResponseHeaderContentType(result));
}
private String getResponseHeaderContentType(MvcResult result) {
return result.getResponse().getHeader("Content-Type");
}
}

View File

@@ -0,0 +1,504 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
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.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.resource.util.ResourceUtility;
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.exception.EntityNotFoundException;
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.json.model.ExceptionInfo;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultActions;
@Feature("Component Tests - Management API")
@Story("Distribution Set Tag Resource")
public class MgmtDistributionSetTagResourceTest extends AbstractManagementApiIntegrationTest {
private static final String DISTRIBUTIONSETTAGS_ROOT = "http://localhost"
+ MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/";
private static final Random RND = new Random();
@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_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("Handles the GET request of retrieving all distribution set tags based by parameter")
public void getDistributionSetTagsWithParameters() 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
+ "?limit=10&sort=name:ASC&offset=0&q=name==DsTag"))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@Test
@Description("Verifies that a paged result list of DS tags reflects the content on the repository side when filtered by distribution set id.")
public void getDistributionSetTagsByDistributionSetId() throws Exception {
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(2);
final DistributionSetTag tag1 = tags.get(0);
final DistributionSetTag tag2 = tags.get(1);
final DistributionSet distributionSet1 = testdataFactory.createDistributionSet();
final DistributionSet distributionSet2 = testdataFactory.createDistributionSet();
distributionSetManagement.assignTag(List.of(distributionSet1.getId(), distributionSet2.getId()), tag1.getId());
distributionSetManagement.assignTag(List.of(distributionSet1.getId()), tag2.getId());
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING)
.queryParam(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "distributionset.id==" + distributionSet1.getId())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(applyBaseEntityMatcherOnPagedResult(tag1))
.andExpect(applyBaseEntityMatcherOnPagedResult(tag2))
.andExpect(applySelfLinkMatcherOnPagedResult(tag1, DISTRIBUTIONSETTAGS_ROOT + tag1.getId()))
.andExpect(applySelfLinkMatcherOnPagedResult(tag2, DISTRIBUTIONSETTAGS_ROOT + tag2.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)));
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING)
.queryParam(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "distributionset.id==" + distributionSet2.getId())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(applyBaseEntityMatcherOnPagedResult(tag1))
.andExpect(applySelfLinkMatcherOnPagedResult(tag1, DISTRIBUTIONSETTAGS_ROOT + tag1.getId()))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(1)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
}
@Test
@Description("Verfies that a paged result list of DS tags reflects the content on the repository side when filtered by distribution set id field AND tag field.")
public void getDistributionSetTagsByDistributionSetIdAndTagDescription() throws Exception {
final List<DistributionSetTag> tags = testdataFactory.createDistributionSetTags(2);
final DistributionSetTag tag1 = tags.get(0);
final DistributionSetTag tag2 = tags.get(1);
final DistributionSet distributionSet1 = testdataFactory.createDistributionSet();
final DistributionSet distributionSet2 = testdataFactory.createDistributionSet();
distributionSetManagement.assignTag(List.of(distributionSet1.getId(), distributionSet2.getId()), tag1.getId());
distributionSetManagement.assignTag(List.of(distributionSet1.getId()), tag2.getId());
// pass here q directly as a pure string because .queryParam method delimiters the parameters in q with ,
// which is logical OR, we want AND here
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING
+ "?" + MgmtRestConstants.REQUEST_PARAMETER_SEARCH +
"=distributionset.id==" + distributionSet1.getId() + ";description==" + tag1.getDescription())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(applyBaseEntityMatcherOnPagedResult(tag1))
.andExpect(applySelfLinkMatcherOnPagedResult(tag1, DISTRIBUTIONSETTAGS_ROOT + tag1.getId()))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(1)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
}
@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_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")));
}
@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_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_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.assignTag(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()), tag.getId());
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.assignTag(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()), tag.getId());
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.assignTag(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()), tag.getId());
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();
}
@Test
@Description("Verifies 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 = 1),
@Expect(type = DistributionSetUpdatedEvent.class, count = 1) })
public void assignDistributionSet() throws Exception {
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
final DistributionSet set = testdataFactory.createDistributionSetsWithoutModules(1).get(0);
mvc.perform(post(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned/" +
set.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(set.getId());
}
@Test
@Description("Verifies 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 List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(2);
mvc.perform(
put(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.content(JsonBuilder.toArray(sets.stream().map(DistributionSet::getId).collect(Collectors.toList())))
.contentType(MediaType.APPLICATION_JSON))
.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()))
.containsAll(sets.stream().map(DistributionSet::getId).collect(Collectors.toList()));
}
@Test
@Description("Verifies 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.assignTag(sets.stream().map(BaseEntity::getId).collect(Collectors.toList()), tag.getId());
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());
}
@Test
@Description("Verifies 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 = 3),
@Expect(type = DistributionSetUpdatedEvent.class, count = 5) })
public void unassignDistributionSets() throws Exception {
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
final List<DistributionSet> sets = testdataFactory.createDistributionSetsWithoutModules(3);
final DistributionSet assigned = sets.get(0);
final DistributionSet unassigned0 = sets.get(1);
final DistributionSet unassigned1 = sets.get(2);
distributionSetManagement.assignTag(sets.stream().map(DistributionSet::getId).collect(Collectors.toList()), tag.getId());
mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.content(JsonBuilder.toArray(List.of(unassigned0.getId(), unassigned1.getId())))
.contentType(MediaType.APPLICATION_JSON))
.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());
}
@Test
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
@ExpectEvents({
@Expect(type = DistributionSetTagCreatedEvent.class, count = 1),
@Expect(type = DistributionSetCreatedEvent.class, count = 2) })
public void assignDistributionSetsNotFound() throws Exception {
final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0);
final List<Long> sets = testdataFactory.createDistributionSetsWithoutModules(2).stream().map(DistributionSet::getId).toList();
final List<Long> missing = new ArrayList<>();
for (int i = 0; i < 5; i++) {
while (true) {
final long id = Math.abs(RND.nextLong());
if (!sets.contains(id)) {
missing.add(id);
break;
}
}
}
Collections.sort(missing);
final List<Long> withMissing = new ArrayList<>(sets);
withMissing.addAll(missing);
mvc.perform(
put(MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.content(JsonBuilder.toArray(withMissing))
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound())
.andExpect(handler -> {
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
final Map<String, Object> info = exceptionInfo.getInfo();
assertThat(info).isNotNull();
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(DistributionSet.class.getSimpleName());
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
Collections.sort(notFound);
assertThat(notFound).isEqualTo(missing);
});
}
@Test
@Description("Verifies 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 assignDistributionSetsWithRequestBody() 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_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)));
}
// DEPRECATED flows
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_VALUE));
}
}

View File

@@ -0,0 +1,694 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
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.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.jayway.jsonpath.JsonPath;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.NamedEntity;
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.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
/**
* Test for {@link MgmtDistributionSetTypeResource}.
*/
@Feature("Component Tests - Management API")
@Story("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_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')].colour", contains("col12")))
.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_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].colour", equalTo("col12")))
.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_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].colour", equalTo("col12")))
.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);
}
@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 = new ArrayList<>();
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(AssignmentQuotaExceededException.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(AssignmentQuotaExceededException.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_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_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())));
}
@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"));
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_VALUE))
.andExpect(jsonPath("$.name", equalTo("TestName123")))
.andExpect(jsonPath("$.description", equalTo("Desc1234")))
.andExpect(jsonPath("$.colour").doesNotExist())
.andExpect(jsonPath("$.createdBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
.andExpect(jsonPath("$.lastModifiedBy", equalTo("uploadTester")))
.andExpect(jsonPath("$.deleted", equalTo(testType.isDeleted())));
}
@Test
@Description("Handles the GET request of retrieving all distribution set types within SP based on parameter.")
public void getDistributionSetTypesWithParameter() throws Exception {
mvc.perform(get(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING
+ "?limit=10&sort=name:ASC&offset=0&q=name==a"))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@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 updateDistributionSetTypeColourDescriptionAndNameUntouched() 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("colour", "updatedColour")
.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("$.colour", equalTo("updatedColour")))
.andExpect(jsonPath("$.name", equalTo("TestName123"))).andReturn();
}
@Test
@Description("Handles the PUT request for a single distribution set type within SP.")
public void updateDistributionSetTypeDescriptionAndColor() throws Exception {
final DistributionSetType testType = distributionSetTypeManagement.update(entityFactory.distributionSetType()
.update(testdataFactory.createDistributionSet().getType().getId()).description("Desc1234"));
final String body = new JSONObject()
.put("description", "an updated description")
.put("colour", "rgb(106,178,83)").toString();
mvc
.perform(put(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING + "/{distributionSetTypeId}",
testType.getId()).content(body).contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print());
}
@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 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(NamedEntity.NAME_MAX_SIZE + 1)).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")));
}
@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_VALUE))
.andExpect(jsonPath("[0].name", equalTo("TestName1")))
.andExpect(jsonPath("[0].key", equalTo("testKey1")))
.andExpect(jsonPath("[0].description", equalTo("Desc1")))
.andExpect(jsonPath("[0].colour", equalTo("col")))
.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());
}
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;
}
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,440 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
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 com.jayway.jsonpath.JsonPath;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.NamedEntity;
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.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
/**
* Test for {@link MgmtSoftwareModuleTypeResource}.
*/
@Feature("Component Tests - Management API")
@Story("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_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() + "')].colour").doesNotExist())
.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() + "')].colour").doesNotExist())
.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')].colour", contains("colour")))
.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)));
}
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Handles the GET request of retrieving all software module types within SP with parameters. In this case the first 10 result in ascending order by name where the name starts with 'a'.")
public void getSoftwareModuleTypesWithParameters() throws Exception {
final SoftwareModuleType testType = testdataFactory.findOrCreateSoftwareModuleType("test123");
softwareModuleTypeManagement
.update(entityFactory.softwareModuleType().update(testType.getId()).description("Desc1234").colour("rgb(106,178,83)"));
mvc.perform(get(MgmtRestConstants.SOFTWAREMODULETYPE_V1_REQUEST_MAPPING + "?limit=10&sort=name:ASC&offset=0&q=name==a")
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@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_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].colour", equalTo("colour")))
.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_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_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_VALUE))
.andExpect(jsonPath("$.name", equalTo("TestName123")))
.andExpect(jsonPath("$.description", equalTo("Desc1234")))
.andExpect(jsonPath("$.colour", equalTo("colour")))
.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 updateSoftwareModuleTypeColourDescriptionAndNameUntouched() throws Exception {
final SoftwareModuleType testType = createTestType();
final String body = new JSONObject().put("id", testType.getId()).put("description", "foobardesc")
.put("colour", "updatedColour").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("$.colour", equalTo("updatedColour")))
.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(NamedEntity.NAME_MAX_SIZE + 1)).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 SoftwareModuleType createTestType() {
SoftwareModuleType testType = softwareModuleTypeManagement.create(entityFactory.softwareModuleType().create()
.key("test123").name("TestName123").description("Desc123").colour("colour").maxAssignments(5));
testType = softwareModuleTypeManagement
.update(entityFactory.softwareModuleType().update(testType.getId()).description("Desc1234"));
return testType;
}
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,734 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.hawkbit.rest.util.MockMvcResultPrinter.print;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.startsWith;
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 java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Stream;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtActionType;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.resource.util.ResourceUtility;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.DeletedException;
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
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.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.web.util.UriUtils;
/**
* Spring MVC Tests against the MgmtTargetResource.
*/
@Feature("Component Tests - Management API")
@Story("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_CONFIRMATION_REQUIRED = ".confirmationRequired";
private static final String JSON_PATH_FIELD_CONTENT = ".content";
// target
// $.field
static final String JSON_PATH_PAGED_LIST_CONTENT = JSON_PATH_ROOT + JSON_PATH_FIELD_CONTENT;
private static final String JSON_PATH_FIELD_SIZE = ".size";
static final String JSON_PATH_PAGED_LIST_SIZE = JSON_PATH_ROOT + JSON_PATH_FIELD_SIZE;
private static final String JSON_PATH_FIELD_TOTAL = ".total";
static final String JSON_PATH_PAGED_LIST_TOTAL = JSON_PATH_ROOT + JSON_PATH_FIELD_TOTAL;
private static final String JSON_PATH_FIELD_AUTO_ASSIGN_DS = ".autoAssignDistributionSet";
private static final String JSON_PATH_FIELD_AUTO_ASSIGN_ACTION_TYPE = ".autoAssignActionType";
private static final String JSON_PATH_FIELD_EXCEPTION_CLASS = ".exceptionClass";
private static final String JSON_PATH_FIELD_ERROR_CODE = ".errorCode";
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_CONFIRMATION_REQUIRED = JSON_PATH_ROOT
+ JSON_PATH_FIELD_CONFIRMATION_REQUIRED;
private static final String JSON_PATH_AUTO_ASSIGN_DS = JSON_PATH_ROOT + JSON_PATH_FIELD_AUTO_ASSIGN_DS;
private static final String JSON_PATH_AUTO_ASSIGN_ACTION_TYPE = JSON_PATH_ROOT
+ JSON_PATH_FIELD_AUTO_ASSIGN_ACTION_TYPE;
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("Handles the GET request of retrieving all target filter queries within SP.")
public void getTargetFilterQueries() throws Exception {
final String filterName = "filter_01";
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name==test_01");
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING))
.andExpect(status().isOk())
.andDo(MockMvcResultPrinter.print());
}
@Test
@Description("Handles the GET request of retrieving all target filter queries within SP based by parameter. Required Permission: READ_TARGET.")
public void getTargetFilterQueriesWithParameters() throws Exception {
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "?limit=10&sort=name:ASC&offset=0&q=name==*1"))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print());
}
@Test
@Description("Handles the POST request of creating a new target filter query within SP.")
public void createTargetFilterQuery() throws Exception {
final String name = "test_02";
final String filterQuery = "name==test_02";
final String body = new JSONObject()
.put("name", name)
.put("query", filterQuery).toString();
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING)
.contentType(MediaType.APPLICATION_JSON).content(body))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isCreated());
}
@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(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(print()).andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_ID, equalTo(tfq.getId().intValue())))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(filterQuery2)))
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(filterName)))
.andExpect(jsonPath(JSON_PATH_CONFIRMATION_REQUIRED).doesNotExist());
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(print()).andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_ID, equalTo(tfq.getId().intValue())))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(filterQuery)))
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(filterName2)))
.andExpect(jsonPath(JSON_PATH_CONFIRMATION_REQUIRED).doesNotExist());
;
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(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(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
public void checkIfFullRepresentationInTargetFilterReturnsDistributionSetHrefWithFilter() throws Exception {
final String testQuery = "name==test";
final DistributionSet set = testdataFactory.createDistributionSet();
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery("a", testQuery);
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
+ filterQuery.getId();
final String distributionsetHrefPrefix = "http://localhost" + MgmtRestConstants.DISTRIBUTIONSET_V1_REQUEST_MAPPING;
final String dsQuery = "?offset=0&limit=50&q=name==" + set.getName() + ";" + "version==" + set.getVersion();
mvc.perform(
post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId() + "/autoAssignDS")
.content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(print()).andExpect(status().isOk());
final String result = mvc.perform(
get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId()))
.andExpect(jsonPath("$._links.autoAssignDS.href", equalTo(hrefPrefix + "/autoAssignDS")))
.andExpect(jsonPath("$._links.DS.href", startsWith(distributionsetHrefPrefix)))
.andReturn().getResponse().getContentAsString();
final String multipleResult = mvc.perform(
get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "?representation=full"))
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1)))
.andExpect(jsonPath("$.content[0]._links.DS.href", startsWith(distributionsetHrefPrefix)))
.andReturn().getResponse().getContentAsString();
final JSONObject singleJson = new JSONObject(result);
final JSONObject multipleJson = new JSONObject(multipleResult);
final String resultDSURI = singleJson.getJSONObject("_links").getJSONObject("DS").getString("href");
final String resultDSURIFromMultipleJson = multipleJson.getJSONArray("content").getJSONObject(0)
.getJSONObject("_links").getJSONObject("DS").getString("href");
Assertions.assertEquals(distributionsetHrefPrefix + dsQuery, UriUtils.decode(resultDSURI, StandardCharsets.UTF_8));
Assertions.assertEquals(distributionsetHrefPrefix + dsQuery,
UriUtils.decode(resultDSURIFromMultipleJson, StandardCharsets.UTF_8));
}
@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(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(print())
.andExpect(status().isOk()).andExpect(jsonPath(JSON_PATH_NAME, equalTo(knownName)))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(knownQuery)))
.andExpect(jsonPath(JSON_PATH_CONFIRMATION_REQUIRED).doesNotExist())
.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(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 creation of a target filter query based on an invalid RSQL query results in a HTTP Bad Request error (400).")
public void createTargetFilterWithInvalidQuery() throws Exception {
final String invalidQuery = "name=abc";
final String body = new JSONObject().put("query", invalidQuery).put("name", "invalidFilter").toString();
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING).content(body)
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isBadRequest()).andReturn();
assertThat(targetFilterQueryManagement.count()).isEqualTo(0);
}
@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");
// 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(print()).andExpect(status().isForbidden())
.andExpect(
jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(AssignmentQuotaExceededException.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");
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery("1", "controllerId==target1");
// create the filter query and the distribution set
final DistributionSet set = testdataFactory.createDistributionSet();
// 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(print()).andExpect(status().isOk());
implicitLock(set);
final TargetFilterQuery updatedFilterQuery = targetFilterQueryManagement.get(filterQuery.getId()).get();
assertThat(updatedFilterQuery.getAutoAssignDistributionSet()).isEqualTo(set);
assertThat(updatedFilterQuery.getAutoAssignActionType()).isEqualTo(ActionType.FORCED);
// 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(print()).andExpect(status().isForbidden())
.andExpect(
jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
}
@ParameterizedTest
@MethodSource("confirmationOptions")
@Description("Ensures that the distribution set auto-assignment works as intended with distribution set, action type and confirmation validation")
public void setAutoAssignDistributionSetToTargetFilterQuery(final boolean confirmationFlowActive,
final Boolean confirmationRequired) throws Exception {
final String knownQuery = "name==test05";
final String knownName = "filter05";
if (confirmationFlowActive) {
enableConfirmationFlow();
}
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
// set will be locked after first assignment
final DistributionSet set = testdataFactory.createDistributionSet();
verifyAutoAssignmentWithoutActionType(tfq, set, confirmationRequired);
verifyAutoAssignmentWithForcedActionType(tfq, set, confirmationRequired);
verifyAutoAssignmentWithSoftActionType(tfq, set, confirmationRequired);
verifyAutoAssignmentWithTimeForcedActionType(tfq, set);
verifyAutoAssignmentWithDownloadOnlyActionType(tfq, set, confirmationRequired);
verifyAutoAssignmentWithUnknownActionType(tfq, set);
verifyAutoAssignmentWithIncompleteDs(tfq);
verifyAutoAssignmentWithSoftDeletedDs(tfq);
}
@Test
@Description("Handles the GET request of retrieving a the auto assign distribution set of a target filter query within SP.")
public void getAssignDS() throws Exception {
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery("filter_01", "name==test_01");
final DistributionSet ds = testdataFactory.createDistributionSet("ds");
targetFilterQueryManagement
.updateAutoAssignDS(entityFactory.targetFilterQuery()
.updateAutoAssign(filterQuery.getId()).ds(ds.getId()));
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
filterQuery.getId()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@Test
@Description("Handles the POST request of setting a distribution set for auto assignment within SP.")
public void createAutoAssignDS() throws Exception {
enableMultiAssignments();
enableConfirmationFlow();
final String filterName = "filter_01";
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name==test_01");
final DistributionSet distributionSet = testdataFactory.createDistributionSet("ds");
final String autoAssignBody = new JSONObject().put("id", distributionSet.getId())
.put("type", MgmtActionType.SOFT.getName()).put("weight", 200).toString();
mvc
.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
filterQuery.getId()).contentType(MediaType.APPLICATION_JSON).content(autoAssignBody.toString()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@Test
@Description("Handles the DELETE request of deleting the auto assign distribution set from a target filter query within SP.")
public void deleteAutoAssignDS() throws Exception {
final String filterName = "filter_01";
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name==test_01");
mvc
.perform(delete(
MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
filterQuery.getId()))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNoContent());
}
@Test
@Description("Ensures that the deletion of auto-assignment distribution set works as intended, deleting the auto-assignment action type as well")
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(entityFactory.targetFilterQuery().updateAutoAssign(tfq.getId()).ds(set.getId()));
implicitLock(set);
final TargetFilterQuery updatedFilterQuery = targetFilterQueryManagement.get(tfq.getId()).get();
assertThat(updatedFilterQuery.getAutoAssignDistributionSet()).isEqualTo(set);
assertThat(updatedFilterQuery.getAutoAssignActionType()).isEqualTo(ActionType.FORCED);
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());
final TargetFilterQuery filterQueryWithDeletedDs = targetFilterQueryManagement.get(tfq.getId()).get();
assertThat(filterQueryWithDeletedDs.getAutoAssignDistributionSet()).isNull();
assertThat(filterQueryWithDeletedDs.getAutoAssignActionType()).isNull();
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
.andExpect(status().isNoContent());
}
@Test
@Description("An auto assignment containing a weight is only accepted when weight is valide and multi assignment is on.")
public void weightValidation() throws Exception {
final Long filterId = createSingleTargetFilterQuery("filter1", "name==*").getId();
final Long dsId = testdataFactory.createDistributionSet().getId();
final String invalideWeightRequest = new JSONObject().put("id", dsId).put("weight", Action.WEIGHT_MIN - 1)
.toString();
final String valideWeightRequest = new JSONObject().put("id", dsId).put("weight", 45).toString();
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
filterId).content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk());
enableMultiAssignments();
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
filterId).content(invalideWeightRequest).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode", equalTo("hawkbit.server.error.repo.constraintViolation")));
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/{targetFilterQueryId}/autoAssignDS",
filterId).content(valideWeightRequest).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk());
final List<TargetFilterQuery> filters = targetFilterQueryManagement.findAll(PAGE).getContent();
assertThat(filters).hasSize(1);
assertThat(filters.get(0).getAutoAssignWeight().get()).isEqualTo(45);
}
@ParameterizedTest
@ValueSource(booleans = { true, false })
@Description("Verify the confirmation required flag will be set based on the feature state")
void verifyConfirmationStateIfNotProvided(final boolean confirmationFlowActive) throws Exception {
final String knownQuery = "name==test05";
final String knownName = "filter05";
if (confirmationFlowActive) {
enableConfirmationFlow();
}
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
final DistributionSet set = testdataFactory.createDistributionSet();
// do not provide something about the confirmation
verifyAutoAssignmentByActionType(tfq, set, null, null);
assertThat(targetFilterQueryManagement.get(tfq.getId())).hasValueSatisfying(filter -> {
assertThat(filter.isConfirmationRequired()).isEqualTo(confirmationFlowActive);
});
}
private static Stream<Arguments> confirmationOptions() {
return Stream.of(Arguments.of(true, false), Arguments.of(true, true), Arguments.of(false, true),
Arguments.of(true, null), Arguments.of(false, null));
}
@Step
private void verifyAutoAssignmentWithoutActionType(final TargetFilterQuery tfq, final DistributionSet set,
final Boolean confirmationRequired) throws Exception {
verifyAutoAssignmentByActionType(tfq, set, null, confirmationRequired);
}
@Step
private void verifyAutoAssignmentWithForcedActionType(final TargetFilterQuery tfq, final DistributionSet set,
final Boolean confirmationRequired) throws Exception {
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.FORCED, confirmationRequired);
}
@Step
private void verifyAutoAssignmentWithSoftActionType(final TargetFilterQuery tfq, final DistributionSet set,
final Boolean confirmationRequired) throws Exception {
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.SOFT, confirmationRequired);
}
private void verifyAutoAssignmentByActionType(final TargetFilterQuery tfq, final DistributionSet set,
final MgmtActionType actionType, final Boolean confirmationRequired) throws Exception {
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
+ tfq.getId();
final JSONObject jsonObject = new JSONObject();
jsonObject.put("id", set.getId());
if (actionType != null) {
jsonObject.put("type", actionType.getName());
}
if (confirmationRequired != null) {
jsonObject.put("confirmationRequired", confirmationRequired);
}
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content(jsonObject.toString()).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk());
implicitLock(set);
final TargetFilterQuery updatedFilterQuery = targetFilterQueryManagement.get(tfq.getId()).get();
final MgmtActionType expectedActionType = actionType != null ? actionType : MgmtActionType.FORCED;
assertThat(updatedFilterQuery.getAutoAssignDistributionSet()).isEqualTo(set);
assertThat(updatedFilterQuery.getAutoAssignActionType())
.isEqualTo(MgmtRestModelMapper.convertActionType(expectedActionType));
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId())).andDo(print())
.andExpect(status().isOk()).andExpect(jsonPath(JSON_PATH_NAME, equalTo(tfq.getName())))
.andExpect(jsonPath(JSON_PATH_QUERY, equalTo(tfq.getQuery())))
.andExpect(isConfirmationFlowEnabled()
? jsonPath(JSON_PATH_CONFIRMATION_REQUIRED,
equalTo(confirmationRequired == null || confirmationRequired))
: jsonPath(JSON_PATH_CONFIRMATION_REQUIRED).doesNotExist())
.andExpect(jsonPath(JSON_PATH_AUTO_ASSIGN_DS, equalTo(set.getId().intValue())))
.andExpect(jsonPath(JSON_PATH_AUTO_ASSIGN_ACTION_TYPE, equalTo(expectedActionType.getName())))
.andExpect(jsonPath("$._links.self.href", equalTo(hrefPrefix)))
.andExpect(jsonPath("$._links.autoAssignDS.href", equalTo(hrefPrefix + "/autoAssignDS")));
}
@Step
private void verifyAutoAssignmentWithTimeForcedActionType(final TargetFilterQuery tfq, final DistributionSet set)
throws Exception {
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content("{\"id\":" + set.getId() + ", \"type\":\"" + MgmtActionType.TIMEFORCED.getName() + "\"}")
.contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isBadRequest())
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS,
equalTo(InvalidAutoAssignActionTypeException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE,
equalTo(SpServerError.SP_AUTO_ASSIGN_ACTION_TYPE_INVALID.getKey())));
}
@Step
private void verifyAutoAssignmentWithDownloadOnlyActionType(final TargetFilterQuery tfq, final DistributionSet set,
final Boolean confirmationRequired) throws Exception {
verifyAutoAssignmentByActionType(tfq, set, MgmtActionType.DOWNLOAD_ONLY, confirmationRequired);
}
@Step
private void verifyAutoAssignmentWithUnknownActionType(final TargetFilterQuery tfq, final DistributionSet set)
throws Exception {
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content("{\"id\":" + set.getId() + ", \"type\":\"unknown\"}").contentType(MediaType.APPLICATION_JSON))
.andDo(print()).andExpect(status().isBadRequest())
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(MessageNotReadableException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_REST_BODY_NOT_READABLE.getKey())));
}
@Step
private void verifyAutoAssignmentWithIncompleteDs(final TargetFilterQuery tfq) throws Exception {
final DistributionSet incompleteDistributionSet = distributionSetManagement
.create(entityFactory.distributionSet().create().name("incomplete").version("1")
.type(testdataFactory.findOrCreateDefaultTestDsType()));
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content("{\"id\":" + incompleteDistributionSet.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(print()).andExpect(status().isBadRequest())
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS,
equalTo(IncompleteDistributionSetException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_DS_INCOMPLETE.getKey())));
}
@Step
private void verifyAutoAssignmentWithSoftDeletedDs(final TargetFilterQuery tfq) throws Exception {
final DistributionSet softDeletedDs = testdataFactory.createDistributionSet("softDeleted");
assignDistributionSet(softDeletedDs, testdataFactory.createTarget("forSoftDeletedDs"));
distributionSetManagement.delete(softDeletedDs.getId());
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content("{\"id\":" + softDeletedDs.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(print()).andExpect(status().isNotFound())
.andExpect(jsonPath(JSON_PATH_EXCEPTION_CLASS, equalTo(DeletedException.class.getName())))
.andExpect(jsonPath(JSON_PATH_ERROR_CODE, equalTo(SpServerError.SP_DELETED.getKey())));
}
private TargetFilterQuery createSingleTargetFilterQuery(final String name, final String query) {
return targetFilterQueryManagement.create(entityFactory.targetFilterQuery().create().name(name).query(query));
}
}

View File

@@ -0,0 +1,669 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
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.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetTagRestApi;
import org.eclipse.hawkbit.mgmt.rest.resource.util.ResourceUtility;
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.exception.EntityNotFoundException;
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.json.model.ExceptionInfo;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultActions;
/**
* Spring MVC Tests against the MgmtTargetTagResource.
*/
@Feature("Component Tests - Management API")
@Story("Target Tag Resource")
public class MgmtTargetTagResourceTest extends AbstractManagementApiIntegrationTest {
private static final String TARGETTAGS_ROOT = "http://localhost" + MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/";
private static final Random RND = new Random();
@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_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("Handles the GET request of retrieving all targets tags within SP based by parameter")
public void getTargetTagsWithParameters() 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 + "?limit=10&sort=name:ASC&offset=0&q=name==targetTag"))
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print());
}
@Test
@Description("Verifies that a page result when listing tags reflects on the content in the repository when filtered by 2 fields - one tag field and one target field")
public void getTargetTagsFilteredByColor() throws Exception {
final String controllerId1 = "controllerTestId1";
final String controllerId2 = "controllerTestId2";
testdataFactory.createTarget(controllerId1);
testdataFactory.createTarget(controllerId2);
final List<TargetTag> tags = testdataFactory.createTargetTags(2, "");
final TargetTag tag1 = tags.get(0);
final TargetTag tag2 = tags.get(1);
targetManagement.assignTag(List.of(controllerId1, controllerId2), tag1.getId());
targetManagement.assignTag(List.of(controllerId2), tag2.getId());
// pass here q directly as a pure string because .queryParam method delimiters the parameters in q with ,
// which is logical OR, we want AND here
mvc.perform(get(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING +
"?" + MgmtRestConstants.REQUEST_PARAMETER_SEARCH + "=colour==" + tag2.getColour())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(applyTagMatcherOnPagedResult(tag2))
.andExpect(applySelfLinkMatcherOnPagedResult(tag2, TARGETTAGS_ROOT + tag2.getId()))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(1)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
}
@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_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")));
}
@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_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_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.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
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.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
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.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
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("Verifies 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 = 1),
@Expect(type = TargetUpdatedEvent.class, count = 1) })
public void assignTarget() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final Target assigned = testdataFactory.createTargets(1).get(0);
mvc.perform(post(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned/" +
assigned.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());
}
@Test
@Description("Verifies that tag assignments (multi targets) 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 List<Target> targets = testdataFactory.createTargets(2);
final Target assigned0 = targets.get(0);
final Target assigned1 = targets.get(1);
;
mvc.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.content(JsonBuilder.toArray(Arrays.asList(assigned0.getControllerId(), assigned1.getControllerId())))
.contentType(MediaType.APPLICATION_JSON))
.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(assigned0.getControllerId(), assigned1.getControllerId());
}
@Test
@Description("Verifies that tag assignments (multi targets) done through tag API command are correctly stored in the repository.")
@ExpectEvents({
@Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetCreatedEvent.class, count = 2) })
public void assignTargetsNotFound() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
final List<String> missing = new ArrayList<>();
for (int i = 0; i < 5; i++) {
while (true) {
final String id = String.valueOf(Math.abs(RND.nextLong()));
if (!targets.contains(id)) {
missing.add(id);
break;
}
}
}
Collections.sort(missing);
final List<String> withMissing = new ArrayList<>(targets);
withMissing.addAll(missing);
mvc.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.content(JsonBuilder.toArray(withMissing))
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound())
.andExpect(handler -> {
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
final Map<String, Object> info = exceptionInfo.getInfo();
assertThat(info).isNotNull();
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(Target.class.getSimpleName());
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
Collections.sort(notFound);
assertThat(notFound).isEqualTo(missing);
});
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent()).isEmpty();
}
@Test
@Description("Verifies that tag assignments (multi targets) 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 assignTargetsNotFoundTagAndFail() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
final List<String> missing = new ArrayList<>();
for (int i = 0; i < 5; i++) {
while (true) {
final String id = String.valueOf(Math.abs(RND.nextLong()));
if (!targets.contains(id)) {
missing.add(id);
break;
}
}
}
Collections.sort(missing);
final List<String> withMissing = new ArrayList<>(targets);
withMissing.addAll(missing);
mvc.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.param("onNotFoundPolicy", MgmtTargetTagRestApi.OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL.name())
.content(JsonBuilder.toArray(withMissing))
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound())
.andExpect(handler -> {
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
final Map<String, Object> info = exceptionInfo.getInfo();
assertThat(info).isNotNull();
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(Target.class.getSimpleName());
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
Collections.sort(notFound);
assertThat(notFound).isEqualTo(missing);
});
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent().stream().map(Target::getControllerId).sorted().toList())
.isEqualTo(targets.stream().sorted().toList());
}
@Test
@Description("Verifies that tag assignments (multi targets) 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 assignTargetsNotFoundTagAndSuccess() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
final List<String> missing = new ArrayList<>();
for (int i = 0; i < 5; i++) {
while (true) {
final String id = String.valueOf(Math.abs(RND.nextLong()));
if (!targets.contains(id)) {
missing.add(id);
break;
}
}
}
Collections.sort(missing);
final List<String> withMissing = new ArrayList<>(targets);
withMissing.addAll(missing);
mvc.perform(put(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.param("onNotFoundPolicy", MgmtTargetTagRestApi.OnNotFoundPolicy.ON_WHAT_FOUND_AND_SUCCESS.name())
.content(JsonBuilder.toArray(withMissing))
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent().stream().map(Target::getControllerId).sorted().toList())
.isEqualTo(targets.stream().sorted().toList());
}
@Test
@Description("Verifies 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 List<Target> targets = testdataFactory.createTargets(2);
final Target assigned = targets.get(0);
final Target unassigned = targets.get(1);
targetManagement.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
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());
}
@Test
@Description("Verifies that tag unassignments (multi targets) done through tag API command are correctly stored in the repository.")
@ExpectEvents({
@Expect(type = TargetTagCreatedEvent.class, count = 1),
@Expect(type = TargetCreatedEvent.class, count = 3),
@Expect(type = TargetUpdatedEvent.class, count = 5) })
public void unassignTargets() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final List<Target> targets = testdataFactory.createTargets(3);
final Target assigned = targets.get(0);
final Target unassigned0 = targets.get(1);
final Target unassigned1 = targets.get(2);
targetManagement.assignTag(targets.stream().map(Target::getControllerId).collect(Collectors.toList()), tag.getId());
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.content(JsonBuilder.toArray(Arrays.asList(unassigned0.getControllerId(), unassigned1.getControllerId())))
.contentType(MediaType.APPLICATION_JSON))
.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());
}
@Test
@Description("Verifies that tag assignments (multi targets) 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 unassignTargetsNotFound() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
final List<String> missing = new ArrayList<>();
for (int i = 0; i < 5; i++) {
while (true) {
final String id = String.valueOf(Math.abs(RND.nextLong()));
if (!targets.contains(id)) {
missing.add(id);
break;
}
}
}
Collections.sort(missing);
final List<String> withMissing = new ArrayList<>(targets);
withMissing.addAll(missing);
targetManagement.assignTag(targets, tag.getId());
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.content(JsonBuilder.toArray(withMissing))
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound())
.andExpect(handler -> {
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
final Map<String, Object> info = exceptionInfo.getInfo();
assertThat(info).isNotNull();
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(Target.class.getSimpleName());
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
Collections.sort(notFound);
assertThat(notFound).isEqualTo(missing);
});
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent().stream().map(Target::getControllerId).sorted().toList())
.isEqualTo(targets.stream().sorted().toList());
}
@Test
@Description("Verifies that tag assignments (multi targets) 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 = 4) })
public void unassignTargetsNotFoundUntagAndFail() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
final List<String> missing = new ArrayList<>();
for (int i = 0; i < 5; i++) {
while (true) {
final String id = String.valueOf(Math.abs(RND.nextLong()));
if (!targets.contains(id)) {
missing.add(id);
break;
}
}
}
Collections.sort(missing);
final List<String> withMissing = new ArrayList<>(targets);
withMissing.addAll(missing);
targetManagement.assignTag(targets, tag.getId());
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.param("onNotFoundPolicy", MgmtTargetTagRestApi.OnNotFoundPolicy.ON_WHAT_FOUND_AND_FAIL.name())
.content(JsonBuilder.toArray(withMissing))
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound())
.andExpect(handler -> {
final ExceptionInfo exceptionInfo = ResourceUtility.convertException(handler.getResponse().getContentAsString());
final Map<String, Object> info = exceptionInfo.getInfo();
assertThat(info).isNotNull();
assertThat(info.get(EntityNotFoundException.TYPE)).isEqualTo(Target.class.getSimpleName());
final List<String> notFound = (List<String>) info.get(EntityNotFoundException.ENTITY_ID);
Collections.sort(notFound);
assertThat(notFound).isEqualTo(missing);
});
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent()).isEmpty();
}
@Test
@Description("Verifies that tag assignments (multi targets) 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 = 4) })
public void unassignTargetsNotFoundUntagAndSuccess() throws Exception {
final TargetTag tag = testdataFactory.createTargetTags(1, "").get(0);
final List<String> targets = testdataFactory.createTargets(2).stream().map(Target::getControllerId).toList();
final List<String> missing = new ArrayList<>();
for (int i = 0; i < 5; i++) {
while (true) {
final String id = String.valueOf(Math.abs(RND.nextLong()));
if (!targets.contains(id)) {
missing.add(id);
break;
}
}
}
Collections.sort(missing);
final List<String> withMissing = new ArrayList<>(targets);
withMissing.addAll(missing);
targetManagement.assignTag(targets, tag.getId());
mvc.perform(delete(MgmtRestConstants.TARGET_TAG_V1_REQUEST_MAPPING + "/" + tag.getId() + "/assigned")
.param("onNotFoundPolicy", MgmtTargetTagRestApi.OnNotFoundPolicy.ON_WHAT_FOUND_AND_SUCCESS.name())
.content(JsonBuilder.toArray(withMissing))
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(targetManagement.findByTag(PAGE, tag.getId()).getContent()).isEmpty();
}
// DEPRECATED scenarios
@Test
@Description("Verifes 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();
}
@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 assignTargetsByRequestBody() 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(controllerIdsOld(
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_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)));
}
private static String controllerIdsOld(final Collection<String> ids) throws JSONException {
final JSONArray list = new JSONArray();
for (final String smID : ids) {
list.put(new JSONObject().put("controllerId", smID));
}
return list.toString();
}
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(controllerIdsOld(
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_VALUE));
}
}

View File

@@ -0,0 +1,648 @@
/**
* Copyright (c) 2021 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
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.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
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.Collection;
import java.util.Collections;
import java.util.List;
import com.jayway.jsonpath.JsonPath;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Step;
import io.qameta.allure.Story;
import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.builder.TargetTypeCreate;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
/**
* Spring MVC Tests against the MgmtTargetTypeResource.
*/
@Feature("Component Tests - Management API")
@Story("Target Type Resource")
class MgmtTargetTypeResourceTest extends AbstractManagementApiIntegrationTest {
private static final String TARGETTYPES_ENDPOINT = MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING;
private static final String TARGETTYPE_SINGLE_ENDPOINT = MgmtRestConstants.TARGETTYPE_V1_REQUEST_MAPPING
+ "/{typeid}";
private static final String TARGETTYPE_DSTYPES_ENDPOINT = TARGETTYPE_SINGLE_ENDPOINT + "/"
+ MgmtRestConstants.TARGETTYPE_V1_DS_TYPES;
private static final String TARGETTYPE_DSTYPE_SINGLE_ENDPOINT = TARGETTYPE_DSTYPES_ENDPOINT + "/{dstypeid}";
private static final String TEST_USER = "targetTypeTester";
private static final String SPACE_AND_DESCRIPTION = " description";
@Test
@WithUser(principal = "targetTypeTester", allSpPermissions = true, removeFromAllPermission = { SpPermission.READ_TARGET })
@Description("GET targettypes returns Forbidden when permission is missing")
void getTargetTypesWithoutPermission() throws Exception {
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isForbidden());
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes/{id} GET request.")
void getTargetType() throws Exception {
String typeName = "TestTypeGET";
TargetType testType = createTestTargetTypeInDB(typeName);
Long typeId = testType.getId();
mvc.perform(get(TARGETTYPE_SINGLE_ENDPOINT, typeId).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$.id", is(typeId), Long.class)).andExpect(jsonPath("$.name", equalTo(typeName)))
.andExpect(jsonPath("$.colour", is("#000000")))
.andExpect(jsonPath("$.description", equalTo(typeName + SPACE_AND_DESCRIPTION)))
.andExpect(jsonPath("$.createdBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
.andExpect(jsonPath("$.lastModifiedBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
.andExpect(jsonPath("$._links.self.href", equalTo("http://localhost/rest/v1/targettypes/" + typeId)))
.andExpect(jsonPath("$.deleted", equalTo(false)))
.andExpect(jsonPath("$.key", equalTo(typeName + " key")))
.andExpect(jsonPath("$._links.compatibledistributionsettypes.href",
equalTo("http://localhost/rest/v1/targettypes/" + typeId + "/compatibledistributionsettypes")));
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests.")
void getTargetTypes() throws Exception {
String typeName = "TestTypeGET";
int count = 5;
List<TargetType> testTypes = createTestTargetTypesInDB(typeName, count);
ResultActions resultActions = mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print());
for (int index = 0; index < count; index++) {
Long typeId = testTypes.get(index).getId();
resultActions.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].id", contains(typeId.intValue())))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].name", contains(typeName + index)))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].colour", contains("#000000")))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].description",
contains(typeName + SPACE_AND_DESCRIPTION)))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].createdBy", contains(TEST_USER)))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].createdAt",
contains(testTypes.get(index).getCreatedAt())))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].lastModifiedBy", contains(TEST_USER)))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].lastModifiedAt",
contains(testTypes.get(index).getLastModifiedAt())))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].deleted", contains(false)))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')].key", contains(typeName + index + " key")))
.andExpect(jsonPath("$.content.[?(@.id=='" + typeId + "')]._links.self.href",
contains("http://localhost/rest/v1/targettypes/" + typeId)))
.andExpect(
jsonPath("$.content.[?(@.id=='" + typeId + "')]._links.compatibledistributionsettypes.href")
.doesNotExist())
.andExpect(jsonPath("$.total", equalTo(count))).andExpect(jsonPath("$.size", equalTo(count)));
}
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests without prior created target types.")
void getDefaultTargetTypes() throws Exception {
// 0 types overall (no default types are created)
final int types = 0;
mvc.perform(get(TARGETTYPES_ENDPOINT)).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
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests with sorting by name.")
void getTargetTypesSortedByName() throws Exception {
String typeNameA = "ATestTypeGETsorted";
String typeNameB = "BTestTypeGETsorted";
String typeNameC = "CTestTypeGETsorted";
TargetType testTypeB = createTestTargetTypeInDB(typeNameB);
TargetType testTypeC = createTestTargetTypeInDB(typeNameC);
TargetType testTypeA = createTestTargetTypeInDB(typeNameA);
testTypeA = targetTypeManagement
.update(entityFactory.targetType().update(testTypeA.getId()).description("Updated description"));
// descending
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "name:DESC")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$.content.[0].id", equalTo(testTypeC.getId().intValue())))
.andExpect(jsonPath("$.content.[0].name", equalTo(typeNameC)))
.andExpect(jsonPath("$.content.[0].colour", equalTo("#000000")))
.andExpect(jsonPath("$.content.[0].description", equalTo(typeNameC + SPACE_AND_DESCRIPTION)))
.andExpect(jsonPath("$.content.[0].createdBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$.content.[0].createdAt", equalTo(testTypeC.getCreatedAt())))
.andExpect(jsonPath("$.content.[0].lastModifiedBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$.content.[0].lastModifiedAt", equalTo(testTypeC.getLastModifiedAt())))
.andExpect(jsonPath("$.content.[0].deleted", equalTo(false)))
.andExpect(jsonPath("$.content.[0].key", equalTo(typeNameC + " key")))
.andExpect(jsonPath("$.content.[0]._links.self.href",
equalTo("http://localhost/rest/v1/targettypes/" + testTypeC.getId())))
.andExpect(jsonPath("$.content.[0]._links.compatibledistributionsettypes.href").doesNotExist())
.andExpect(jsonPath("$.total", equalTo(3))).andExpect(jsonPath("$.size", equalTo(3)))
.andExpect(jsonPath("$.content.[1].name", equalTo(typeNameB)))
.andExpect(jsonPath("$.content.[2].name", equalTo(typeNameA)));
// ascending
mvc.perform(get(TARGETTYPES_ENDPOINT).accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "name:ASC")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$.content.[0].id", equalTo(testTypeA.getId().intValue())))
.andExpect(jsonPath("$.content.[0].name", equalTo(typeNameA)))
.andExpect(jsonPath("$.content.[0].description", equalTo("Updated description")))
.andExpect(jsonPath("$.content.[0].colour", equalTo("#000000")))
.andExpect(jsonPath("$.content.[0].createdBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$.content.[0].createdAt", equalTo(testTypeA.getCreatedAt())))
.andExpect(jsonPath("$.content.[0].lastModifiedBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$.content.[0].lastModifiedAt", equalTo(testTypeA.getLastModifiedAt())))
.andExpect(jsonPath("$.content.[0].deleted", equalTo(false)))
.andExpect(jsonPath("$.content.[0].key", equalTo(typeNameA + " key")))
.andExpect(jsonPath("$.content.[0]._links.self.href",
equalTo("http://localhost/rest/v1/targettypes/" + testTypeA.getId())))
.andExpect(jsonPath("$.content.[0]._links.compatibledistributionsettypes.href").doesNotExist())
.andExpect(jsonPath("$.total", equalTo(3))).andExpect(jsonPath("$.size", equalTo(3)))
.andExpect(jsonPath("$.content.[1].name", equalTo(typeNameB)))
.andExpect(jsonPath("$.content.[2].name", equalTo(typeNameC)));
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests with paging.")
void getTargetTypesWithPagingLimitRequestParameter() throws Exception {
final String typePrefix = "TestTypeGETPaging";
final int count = 10;
final int limit = 3;
createTestTargetTypesInDB(typePrefix, count);
mvc.perform(get(TARGETTYPES_ENDPOINT).param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT,
String.valueOf(limit))).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(count)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(limit)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(limit)));
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes GET requests with paging and offset.")
void getTargetTypesWithPagingLimitAndOffsetRequestParameter() throws Exception {
final int count = 10;
final int offset = 2;
final int expectedSize = count - offset;
final String typePrefix = "TestTypeGETPaging";
createTestTargetTypesInDB(typePrefix, count);
mvc.perform(get(TARGETTYPES_ENDPOINT)
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(offset))
.param(MgmtRestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(count)))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_TOTAL, equalTo(count)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_SIZE, equalTo(expectedSize)))
.andExpect(jsonPath(MgmtTargetResourceTest.JSON_PATH_PAGED_LIST_CONTENT, hasSize(expectedSize)));
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID} PUT requests.")
void updateTargetType() throws Exception {
String typeName = "TestTypePUT";
final TargetType testType = createTestTargetTypeInDB(typeName);
final String body = new JSONObject().put("id", testType.getId()).put("description", "updated description")
.put("name", "TestTypePUTupdated").put("colour", "#ffffff").toString();
mvc.perform(
put(TARGETTYPE_SINGLE_ENDPOINT, 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("updated description")))
.andExpect(jsonPath("$.name", equalTo("TestTypePUTupdated")))
.andExpect(jsonPath("$.colour", equalTo("#ffffff"))).andReturn();
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes/{id} GET requests.")
void getUpdatedTargetType() throws Exception {
final String initialTypeName = "TestTypeGET";
TargetType testType = createTestTargetTypeInDB(initialTypeName);
final String typeNameUpdated = "TestTypeGETupdated";
testType = targetTypeManagement.update(entityFactory.targetType().update(testType.getId()).name(typeNameUpdated)
.description("Updated Description").colour("#ffffff"));
mvc.perform(get(TARGETTYPE_SINGLE_ENDPOINT, testType.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$.name", equalTo(typeNameUpdated)))
.andExpect(jsonPath("$.description", equalTo("Updated Description")))
.andExpect(jsonPath("$.colour", equalTo("#ffffff")))
.andExpect(jsonPath("$.createdBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$.createdAt", equalTo(testType.getCreatedAt())))
.andExpect(jsonPath("$.lastModifiedBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$.lastModifiedAt", equalTo(testType.getLastModifiedAt())))
.andExpect(jsonPath("$.deleted", equalTo(false)))
.andExpect(jsonPath("$.key", equalTo(initialTypeName + " key")));
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes POST requests.")
void createTargetTypes() throws Exception {
String typeName = "TestTypePOST";
final List<TargetType> types = buildTestTargetTypesWithoutDsTypes(typeName, 5);
runPostTargetTypeAndVerify(types);
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes POST requests.")
void addDistributionSetTypeToTargetType() throws Exception {
String typeName = "TestTypeAddDs";
TargetType testType = createTestTargetTypeInDB(typeName);
assertThat(testType.getOptLockRevision()).isEqualTo(1);
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())
.content("[{\"id\":" + standardDsType.getId() + "}]").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
testType = targetTypeManagement.get(testType.getId()).get();
assertThat(testType.getLastModifiedBy()).isEqualTo(TEST_USER);
assertThat(testType.getOptLockRevision()).isEqualTo(2);
assertThat(testType.getCompatibleDistributionSetTypes()).containsExactly(standardDsType);
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes GET requests.")
void getDistributionSetsOfTargetType() throws Exception {
String typeName = "TestTypeGetDs";
final TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
mvc.perform(get(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$[0].name", equalTo(standardDsType.getName())))
.andExpect(jsonPath("$[0].description", equalTo(standardDsType.getDescription())))
.andExpect(jsonPath("$[0].key", equalTo("test_default_ds_type")))
.andExpect(jsonPath("$[0]._links.self.href",
equalTo("http://localhost/rest/v1/distributionsettypes/" + standardDsType.getId())));
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes/{ID} GET requests.")
void getDistributionSetOfTargetTypeReturnsNotAllowed() throws Exception {
String typeName = "TestTypeAddDs";
final TargetType testType = createTestTargetTypeInDB(typeName);
mvc.perform(get(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), standardDsType.getId())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID}/compatibledistributionsettypes/{ID} DELETE requests.")
void removeDsTypeFromTargetType() throws Exception {
String typeName = "TestTypeRemoveDs";
TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
mvc.perform(delete(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), standardDsType.getId())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
testType = targetTypeManagement.get(testType.getId()).get();
assertThat(testType.getLastModifiedBy()).isEqualTo(TEST_USER);
assertThat(testType.getOptLockRevision()).isEqualTo(2);
assertThat(testType.getCompatibleDistributionSetTypes()).isEmpty();
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/distributionsettypes/{ID} DELETE requests.")
void deletingDsTypeRemovesAssignmentFromTargetType() throws Exception {
String typeName = "TestTypeRemoveDs";
TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
assertThat(testType.getCompatibleDistributionSetTypes()).hasSize(1);
assertThat(distributionSetTypeManagement.getByKey(standardDsType.getKey())).isNotEmpty();
mvc.perform(delete(MgmtRestConstants.DISTRIBUTIONSETTYPE_V1_REQUEST_MAPPING + "/" + standardDsType.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
testType = targetTypeManagement.get(testType.getId()).get();
assertThat(testType.getLastModifiedBy()).isEqualTo(TEST_USER);
assertThat(testType.getOptLockRevision()).isEqualTo(2);
assertThat(testType.getCompatibleDistributionSetTypes()).isEmpty();
assertThat(distributionSetTypeManagement.getByKey(standardDsType.getKey())).isEmpty();
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID} DELETE requests - Deletion when not in use.")
void deleteTargetTypeUnused() throws Exception {
String typeName = "TestTypeUnusedDelete";
final TargetType testType = createTestTargetTypeInDB(typeName);
assertThat(targetTypeManagement.count()).isEqualTo(1);
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
assertThat(targetTypeManagement.count()).isZero();
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Checks the correct behaviour of /rest/v1/targettypes/{ID} DELETE requests - Deletion not possible when in use.")
void deleteTargetTypeUsed() throws Exception {
String typeName = "TestTypeUsedDelete";
final TargetType testType = createTestTargetTypeInDB(typeName);
targetManagement.create(entityFactory.target().create().controllerId("target").name("TargetOfTestType")
.description("target description").targetType(testType.getId()));
assertThat(targetTypeManagement.count()).isEqualTo(1);
assertThat(targetManagement.count()).isEqualTo(1);
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isConflict());
assertThat(targetManagement.count()).isEqualTo(1);
assertThat(targetTypeManagement.count()).isEqualTo(1);
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Ensures that target type deletion request to API on an entity that does not exist results in NOT_FOUND.")
void deleteTargetTypeThatDoesNotExistLeadsToNotFound() throws Exception {
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, 1234)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Tests the update of the deletion flag. It is verified that the target type can't be marked as deleted through update operation.")
void updateTargetTypeDeletedFlag() throws Exception {
String typeName = "TestTypePUT";
final TargetType testType = createTestTargetTypeInDB(typeName);
final String body = new JSONObject().put("id", testType.getId()).put("deleted", true).toString();
mvc.perform(
put(TARGETTYPE_SINGLE_ENDPOINT, 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))); // don't delete with update
}
@Test
@Description("Ensures that the server is behaving as expected on invalid requests (wrong media type, wrong ID etc.).")
void invalidRequestsOnTargetTypesResource() throws Exception {
String typeName = "TestTypeInvalidReq";
final TargetType testType = createTestTargetTypeInDB(typeName, Collections.singletonList(standardDsType));
// target type does not exist
mvc.perform(get(TARGETTYPE_SINGLE_ENDPOINT, 12345678)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
mvc.perform(get(TARGETTYPE_DSTYPES_ENDPOINT, 123456789)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
mvc.perform(delete(TARGETTYPE_SINGLE_ENDPOINT, 123456789)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// target types at creation time invalid
final TargetType testNewType = createTestTargetTypeInDB(typeName + "Another",
Collections.singletonList(standardDsType));
mvc.perform(post(TARGETTYPES_ENDPOINT).content(JsonBuilder.targetTypes(Collections.singletonList(testNewType)))
.contentType(MediaType.APPLICATION_OCTET_STREAM)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isUnsupportedMediaType());
// bad request - no content
mvc.perform(post(TARGETTYPES_ENDPOINT).contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest());
// bad request - bad content
mvc.perform(post(TARGETTYPES_ENDPOINT).content("sdfjsdlkjfskdjf".getBytes())
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
// Missing mandatory field name
mvc.perform(post(TARGETTYPES_ENDPOINT).content("[{\"description\":\"Desc123\"}]")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
final TargetType tooLongName = entityFactory.targetType().create()
.name(RandomStringUtils.randomAlphanumeric(NamedEntity.NAME_MAX_SIZE + 1)).build();
mvc.perform(post(TARGETTYPES_ENDPOINT).content(JsonBuilder.targetTypes(Collections.singletonList(tooLongName)))
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
// ds types
mvc.perform(get(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(delete(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNotFound());
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).content("{\"id\":1}")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId()).content("[{\"id\":44456}]")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isNotFound());
// not allowed methods
mvc.perform(put(TARGETTYPES_ENDPOINT)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete(TARGETTYPES_ENDPOINT)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(put(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(delete(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId(), 565765)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(put(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
mvc.perform(post(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765)
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isMethodNotAllowed());
mvc.perform(get(TARGETTYPE_DSTYPE_SINGLE_ENDPOINT, testType.getId(), 565765))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isMethodNotAllowed());
}
@Test
@Description("Search request of target types.")
void searchTargetTypeRsql() throws Exception {
targetTypeManagement.create(entityFactory.targetType().create().name("TestName123"));
targetTypeManagement.create(entityFactory.targetType().create().name("TestName1234"));
final String rsqlFindLikeDs1OrDs2 = "name==TestName123,name==TestName1234";
mvc.perform(get(TARGETTYPES_ENDPOINT + "?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")));
}
@Test
@WithUser(principal = TEST_USER, allSpPermissions = true)
@Description("Verifies quota enforcement for /rest/v1/targettypes/{ID}/compatibledistributionsettypes POST requests.")
void assignDistributionSetTypeToTargetTypeUntilQuotaExceeded() throws Exception {
final TargetType testType = createTestTargetTypeInDB("TestTypeQuota");
// create distribution set types
final int maxDistributionSetTypes = quotaManagement.getMaxDistributionSetTypesPerTargetType();
final List<Long> dsTypeIds = new ArrayList<>();
for (int i = 0; i < maxDistributionSetTypes + 1; ++i) {
final DistributionSetType ds = testdataFactory.findOrCreateDistributionSetType("dsType_" + i,
"dsType_" + i);
dsTypeIds.add(ds.getId());
}
// verify quota enforcement for distribution set types
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())
.content(JsonBuilder.ids(dsTypeIds.subList(0, dsTypeIds.size() - 1)))
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(post(TARGETTYPE_DSTYPES_ENDPOINT, testType.getId())
.content("[{\"id\":" + dsTypeIds.get(dsTypeIds.size() - 1) + "}]")
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden())
.andExpect(jsonPath("$.exceptionClass", equalTo(AssignmentQuotaExceededException.class.getName())))
.andExpect(jsonPath("$.errorCode", equalTo(SpServerError.SP_QUOTA_EXCEEDED.getKey())));
}
@Step
private TargetType buildTestTargetTypeBody(String name) {
return prepareTestTargetType(name, null).build();
}
private TargetTypeCreate prepareTestTargetType(String name, Collection<DistributionSetType> dsTypes) {
TargetTypeCreate create = entityFactory.targetType().create().name(name)
.description("Description of the test type").colour("#aaaaaa");
if (dsTypes != null && !dsTypes.isEmpty()) {
create.compatible(Collections.singletonList(standardDsType.getId()));
}
return create;
}
@Step
private List<TargetType> createTestTargetTypesInDB(String namePrefix, int count) {
return testdataFactory.createTargetTypes(namePrefix, count);
}
@Step
private TargetType createTestTargetTypeInDB(String name) {
return testdataFactory.findOrCreateTargetType(name);
}
@Step
private TargetType createTestTargetTypeInDB(String name, List<DistributionSetType> dsTypes) {
TargetType targetType = testdataFactory.createTargetType(name, dsTypes);
assertThat(targetType.getOptLockRevision()).isEqualTo(1);
return targetType;
}
@Step
private List<TargetType> buildTestTargetTypesWithoutDsTypes(String namePrefix, int count) {
final List<TargetType> types = new ArrayList<>();
for (int index = 0; index < count; index++) {
types.add(buildTestTargetTypeBody(namePrefix + index));
}
return types;
}
@Step
private void runPostTargetTypeAndVerify(final List<TargetType> types) throws Exception {
int size = types.size();
ResultActions resultActions = mvc
.perform(post(TARGETTYPES_ENDPOINT).content(JsonBuilder.targetTypes(types))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print());
for (int index = 0; index < size; index++) {
resultActions.andExpect(status().isCreated()).andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(jsonPath("$[" + index + "].id").exists())
.andExpect(jsonPath("$[" + index + "].name", startsWith("TestTypePOST")))
.andExpect(jsonPath("$[" + index + "].colour", hasToString("#aaaaaa")))
.andExpect(jsonPath("$[" + index + "].description",
equalTo("Description of the test type")))
.andExpect(jsonPath("$[" + index + "].createdBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$[" + index + "].createdAt").exists())
.andExpect(jsonPath("$[" + index + "].lastModifiedBy", equalTo(TEST_USER)))
.andExpect(jsonPath("$[" + index + "].lastModifiedAt").exists())
.andExpect(jsonPath("$[" + index + "].deleted", equalTo(false)))
.andExpect(jsonPath("$[" + index + "].key", startsWith("TestTypePOST")))
.andExpect(jsonPath("$[" + index + "]._links.self.href",
startsWith("http://localhost/rest/v1/targettypes/")))
.andExpect(
jsonPath("$[" + index + "]._links.compatibledistributionsettypes.href")
.doesNotExist());
}
MvcResult mvcResult = resultActions.andReturn();
for (int index = 0; index < size; index++) {
String name = "TestTypePOST" + index;
final TargetType created = targetTypeManagement.getByName(name).get();
assertThat(JsonPath.compile("$[ ?(@.name=='" + name + "') ].id")
.read(mvcResult.getResponse().getContentAsString()).toString()).contains(String.valueOf(created.getId()));
assertThat(JsonPath.compile("$[ ?(@.name=='" + name + "') ]._links.self.href")
.read(mvcResult.getResponse().getContentAsString()).toString()).contains("/" + created.getId());
}
assertThat(targetTypeManagement.count()).isEqualTo(size);
}
}

View File

@@ -0,0 +1,358 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
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.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValueRequest;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultMatcher;
/**
* Spring MVC Tests against the MgmtTenantManagementResource.
*/
@Feature("Component Tests - Management API")
@Story("Tenant Management Resource")
public class MgmtTenantManagementResourceTest extends AbstractManagementApiIntegrationTest {
private static final String KEY_MULTI_ASSIGNMENTS = "multi.assignments.enabled";
private static final String KEY_AUTO_CLOSE = "repository.actions.autoclose.enabled";
private static final String ROLLOUT_APPROVAL_ENABLED = "rollout.approval.enabled";
private static final String AUTHENTICATION_GATEWAYTOKEN_ENABLED = "authentication.gatewaytoken.enabled";
private static final String AUTHENTICATION_GATEWAYTOKEN_KEY = "authentication.gatewaytoken.key";
private static final String DEFAULT_DISTRIBUTION_SET_TYPE_KEY = "default.ds.type";
@Test
@Description("Handles GET request for receiving all tenant specific configurations.")
public void getTenantConfigurations() throws Exception {
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs"))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
//check for TenantMetadata additional properties
.andExpect(jsonPath("$.['" + DEFAULT_DISTRIBUTION_SET_TYPE_KEY + "']").exists())
.andExpect(jsonPath("$.['" + DEFAULT_DISTRIBUTION_SET_TYPE_KEY + "'].value", equalTo(getActualDefaultDsType().intValue())));
}
@Test
@Description("Handles GET request for receiving a tenant specific configuration.")
public void getTenantConfiguration() throws Exception {
//Test TenantConfiguration property
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@Test
@Description("Handles GET request for receiving (TenantMetadata - DefaultDsType) a tenant specific configuration.")
public void getTenantMetadata() throws Exception {
//Test TenantMetadata property
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
DEFAULT_DISTRIBUTION_SET_TYPE_KEY))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.value", equalTo(getActualDefaultDsType().intValue())));
}
@Test
@Description("Handles PUT request for settings values in tenant specific configuration.")
public void putTenantConfiguration() throws Exception {
final MgmtSystemTenantConfigurationValueRequest bodyPut = new MgmtSystemTenantConfigurationValueRequest();
bodyPut.setValue("exampleToken");
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(bodyPut);
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY).content(json)
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@Test
@Description("Handles PUT request for settings values (TenantMetadata - DefaultDsType) in tenant specific configuration, which is TenantMetadata")
public void putTenantMetadata() throws Exception {
final MgmtSystemTenantConfigurationValueRequest bodyPut = new MgmtSystemTenantConfigurationValueRequest();
long updatedTestDefaultDsType = createTestDistributionSetType();
bodyPut.setValue(updatedTestDefaultDsType);
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(bodyPut);
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
DEFAULT_DISTRIBUTION_SET_TYPE_KEY).content(json)
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
//check if after Rest success, value is really changed in TenantMetadata
assertEquals(updatedTestDefaultDsType, getActualDefaultDsType(),
"Rest endpoint for updating the Default DistributionSetType completed successfully, but the actual value was not changed.");
}
@Test
@Description("Update DefaultDistributionSetType Fails if given DistributionSetType ID does not exist.")
public void putTenantMetadataFails() throws Exception {
long oldDefaultDsType = getActualDefaultDsType();
//try an invalid input
String newDefaultDsType = new JSONObject().put("value", true).toString();
assertDefaultDsTypeUpdateBadRequestFails(newDefaultDsType, oldDefaultDsType, status().isBadRequest());
//try an invalid input
newDefaultDsType = new JSONObject().put("value", "someInvalidInput").toString();
assertDefaultDsTypeUpdateBadRequestFails(newDefaultDsType, oldDefaultDsType, status().isBadRequest());
//try valid input, but the given DistributionSetType Id does not exist..
newDefaultDsType = new JSONObject().put("value", 99999).toString();
assertDefaultDsTypeUpdateBadRequestFails(newDefaultDsType, oldDefaultDsType, status().isNotFound());
}
@Test
@Description("The 'multi.assignments.enabled' property must not be changed to false.")
public void deactivateMultiAssignment() throws Exception {
final String bodyActivate = new JSONObject().put("value", true).toString();
final String bodyDeactivate = new JSONObject().put("value", false).toString();
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_MULTI_ASSIGNMENTS)
.content(bodyActivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_MULTI_ASSIGNMENTS)
.content(bodyDeactivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden());
}
@Test
@Description("The Batch configuration should not be applied, because of invalid TenantConfiguration props")
public void changeBatchConfigurationShouldFailOnInvalidTenantConfiguration() throws Exception {
//in this scenario
// some TenantConfiguration are not valid,
// TenantMetadata - DefaultDSType ID is valid,
//in the end batch configuration update must fail, and thus, not a single config should be actually changed
long testValidDistributionSetType = createTestDistributionSetType();
boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue();
String oldAuthGatewayToken = (String) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue();
//test TenantConfiguration with invalid config value, and a valid TenantMetadata - Default DistributionSetType id
assertBatchConfigurationFails(!oldRolloutApprovalConfig, "invalid-config-value", oldAuthGatewayToken + "randomSuffix0",
testValidDistributionSetType, status().isBadRequest());
}
@Test
@Description("The Batch configuration should not be applied, because of invalid TenantMetadata (DefaultDistributionSetType)")
public void changeBatchConfigurationShouldOnInvalidTenantMetadata() throws Exception {
//in this scenario
// all TenantConfiguration have valid and new values - using old values, inverted
// TenantMetadata - DefaultDSType ID is invalid
//in the end batch configuration update must fail, and thus, not a single config should be actually changed.
boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue();
boolean oldAuthGatewayTokenEnabled = (Boolean) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED)
.getValue();
String oldAuthGatewayToken = (String) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue();
//invalid TenantMetadata Default DistributionSetType, it is expected to be a number. Testing invalid type - string
//not a single configuration should be changed after the failure
Object testInvalidDistributionSetType = "someInvalidInput";
assertBatchConfigurationFails(!oldRolloutApprovalConfig, !oldAuthGatewayTokenEnabled, oldAuthGatewayToken + "randomSuffix1",
testInvalidDistributionSetType, status().isBadRequest());
//invalid TenantMetadata Default DistributionSetType, it is expected to be a number. Testing invalid type - bool
//not a single configuration should be changed after the failure
testInvalidDistributionSetType = true;
assertBatchConfigurationFails(!oldRolloutApprovalConfig, !oldAuthGatewayTokenEnabled, oldAuthGatewayToken + "randomSuffix2",
testInvalidDistributionSetType, status().isBadRequest());
//Valid TenantMetadata Default DistributionSetType, it is expected to be a number. Testing valid type - but given DistributionSetType Id does not exist.
//not a single configuration should be changed after the failure
testInvalidDistributionSetType = 9999;
assertBatchConfigurationFails(!oldRolloutApprovalConfig, !oldAuthGatewayTokenEnabled, oldAuthGatewayToken + "randomSuffix2",
testInvalidDistributionSetType, status().isNotFound());
}
@Test
@Description("The Batch configuration should be applied")
public void changeBatchConfiguration() throws Exception {
long updatedDistributionSetType = createTestDistributionSetType();
boolean updatedRolloutApprovalEnabled = true;
boolean updatedAuthGatewayTokenEnabled = true;
String updatedAuthGatewayTokenKey = "54321";
JSONObject configuration = new JSONObject();
configuration.put(ROLLOUT_APPROVAL_ENABLED, updatedRolloutApprovalEnabled);
configuration.put(AUTHENTICATION_GATEWAYTOKEN_ENABLED, updatedAuthGatewayTokenEnabled);
configuration.put(AUTHENTICATION_GATEWAYTOKEN_KEY, updatedAuthGatewayTokenKey);
configuration.put(DEFAULT_DISTRIBUTION_SET_TYPE_KEY, updatedDistributionSetType);
String body = configuration.toString();
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs")
.content(body).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
//assert all changes were applied after Rest Success
assertEquals(updatedDistributionSetType, getActualDefaultDsType(),
"Change BatchConfiguration was successful but TenantMetadata - Default DistributionSetType was not actually changed.");
assertEquals(updatedRolloutApprovalEnabled, tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(),
"Change BatchConfiguration was successful but TenantConfiguration property was not actually changed.");
assertEquals(updatedAuthGatewayTokenEnabled,
tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED).getValue(),
"Change BatchConfiguration was successful but TenantConfiguration property was not actually changed.");
assertEquals(updatedAuthGatewayTokenKey,
tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue(),
"Change BatchConfiguration was successful but TenantConfiguration property was not actually changed.");
}
@Test
@Description("The 'repository.actions.autoclose.enabled' property must not be modified if Multi-Assignments is enabled.")
public void autoCloseCannotBeModifiedIfMultiAssignmentIsEnabled() throws Exception {
final String bodyActivate = new JSONObject().put("value", true).toString();
final String bodyDeactivate = new JSONObject().put("value", false).toString();
// enable Multi-Assignments
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_MULTI_ASSIGNMENTS)
.content(bodyActivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
// try to enable Auto-Close
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_AUTO_CLOSE)
.content(bodyActivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden());
// try to disable Auto-Close
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}", KEY_AUTO_CLOSE)
.content(bodyDeactivate).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isForbidden());
}
@Test
@Description("Handles DELETE request deleting a tenant specific configuration.")
public void deleteTenantConfiguration() throws Exception {
mvc.perform(delete(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk());
}
@Test
@Description("Tests DELETE request must Fail for TenantMetadata properties.")
public void deleteTenantMetadataFail() throws Exception {
mvc.perform(delete(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
DEFAULT_DISTRIBUTION_SET_TYPE_KEY))
.andDo(MockMvcResultPrinter.print())
.andExpect(status().isBadRequest());
}
@Test
@Description("Handles GET request for receiving all tenant specific configurations depending on read gateway token permissions.")
void getTenantConfigurationReadGWToken() throws Exception {
SecurityContextSwitch.runAs(SecurityContextSwitch.withUser("tenant_admin", SpPermission.TENANT_CONFIGURATION), () -> {
tenantConfigurationManagement.addOrUpdateConfiguration(
TenantConfigurationProperties.TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY,
"123");
return null;
});
// TODO - should be able to read with TENANT_CONFIGURATION but somehow here the role hierarchy doesn't play
// checked in mgmt / update server runtime PreAuthorizeEnabledTest
SecurityContextSwitch.runAs(
SecurityContextSwitch.withUser("tenant_admin", SpPermission.READ_TENANT_CONFIGURATION, SpPermission.READ_GATEWAY_SEC_TOKEN),
() -> {
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs"))
.andDo(MockMvcResultPrinter.print())
.andDo(m -> System.out.println("-> 1: " + m.getResponse().getContentAsString()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAYTOKEN_KEY + "']").exists())
.andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAYTOKEN_KEY + "'].value", equalTo("123")));
return null;
});
SecurityContextSwitch.runAs(SecurityContextSwitch.withUser("tenant_read", SpPermission.READ_TENANT_CONFIGURATION), () -> {
mvc.perform(get(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs"))
.andDo(MockMvcResultPrinter.print())
.andDo(m -> System.out.println("-> 2: " + m.getResponse().getContentAsString()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.['" + AUTHENTICATION_GATEWAYTOKEN_KEY + "']").doesNotExist());
return null;
});
}
private Long createTestDistributionSetType() {
DistributionSetType testDefaultDsType = distributionSetTypeManagement.create(entityFactory.distributionSetType().create()
.key("test123").name("TestName123").description("TestDefaultDsType"));
testDefaultDsType = distributionSetTypeManagement
.update(entityFactory.distributionSetType().update(testDefaultDsType.getId()).description("TestDefaultDsType"));
return testDefaultDsType.getId();
}
private void assertDefaultDsTypeUpdateBadRequestFails(String newDefaultDsType, long oldDefaultDsType, ResultMatcher resultMatchers)
throws Exception {
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{keyName}",
DEFAULT_DISTRIBUTION_SET_TYPE_KEY).content(newDefaultDsType)
.contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print())
.andExpect(resultMatchers);
assertEquals(oldDefaultDsType, getActualDefaultDsType(),
"Rest endpoint for updating DefaultDistributionType failed, but actual value changed unexpectedly.");
}
private void assertBatchConfigurationFails(Object newRolloutApprovalEnabled, Object newAuthGatewayTokenEnabled, Object newGatewayToken,
Object newDistributionSetTypeId, ResultMatcher resultMatchers) throws Exception {
long oldDefaultDsType = getActualDefaultDsType();
boolean oldRolloutApprovalConfig = (Boolean) tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue();
boolean oldAuthGatewayTokenEnabled = (Boolean) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED)
.getValue();
String oldAuthGatewayToken = (String) tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue();
JSONObject configuration = new JSONObject();
configuration.put(ROLLOUT_APPROVAL_ENABLED, newRolloutApprovalEnabled);
configuration.put(AUTHENTICATION_GATEWAYTOKEN_ENABLED, newAuthGatewayTokenEnabled);
configuration.put(AUTHENTICATION_GATEWAYTOKEN_KEY, newGatewayToken);
configuration.put(DEFAULT_DISTRIBUTION_SET_TYPE_KEY, newDistributionSetTypeId);
String body = configuration.toString();
mvc.perform(put(MgmtRestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs")
.content(body).contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(resultMatchers);
//Check if TenantMetadata and TenantConfiguration is not changed as Batch config failed
assertEquals(oldDefaultDsType, getActualDefaultDsType(),
"Batch configuration update Failed, but TenantMetadata - DistributionSetType was actually changed.");
assertEquals(oldRolloutApprovalConfig, tenantConfigurationManagement.getConfigurationValue(ROLLOUT_APPROVAL_ENABLED).getValue(),
"Batch configuration update Failed, but TenantConfiguration was actually changed.");
assertEquals(oldAuthGatewayTokenEnabled,
tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_ENABLED).getValue(),
"Batch configuration update Failed, but TenantConfiguration was actually changed.");
assertEquals(oldAuthGatewayToken, tenantConfigurationManagement.getConfigurationValue(AUTHENTICATION_GATEWAYTOKEN_KEY).getValue(),
"Batch configuration update Failed, but TenantConfiguration was actually changed.");
}
private Long getActualDefaultDsType() {
return systemManagement.getTenantMetadata().getDefaultDsType().getId();
}
}

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.mgmt.rest.resource.util;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
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;
/**
* Utility additions for the REST API tests.
*/
public final class ResourceUtility {
private static final ObjectMapper mapper = new ObjectMapper();
public static ExceptionInfo convertException(final String jsonExceptionResponse)
throws JsonParseException, JsonMappingException, IOException {
return mapper.readValue(jsonExceptionResponse, ExceptionInfo.class);
}
public static MgmtArtifact convertArtifactResponse(final String jsonResponse)
throws JsonParseException, JsonMappingException, IOException {
return mapper.readValue(jsonResponse, MgmtArtifact.class);
}
public static <T> PagedList<T> mapResponse(final Class<T> clazz, final String responseBody)
throws JsonParseException, JsonMappingException, IOException {
return mapper.readValue(responseBody, PagedList.class);
}
}

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.mgmt.rest.resource.util;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.List;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterSyntaxErrorException;
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedDirectionException;
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.TargetFields;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Sort.Order;
@Feature("Component Tests - Management API")
@Story("Sorting parameter")
public class SortUtilityTest {
private static final String SORT_PARAM_1 = "NAME:ASC";
private static final String SORT_PARAM_2 = "NAME:ASC, DESCRIPTION:DESC";
private static final String SYNTAX_FAILURE_SORT_PARAM = "NAME:ASC DESCRIPTION:DESC";
private static final String WRONG_DIRECTION_PARAM = "NAME:ASDF";
private static final String CASE_INSENSITIVE_DIRECTION_PARAM = "NaME:ASC";
private static final String CASE_INSENSITIVE_DIRECTION_PARAM_1 = "name:ASC";
private static final String WRONG_FIELD_PARAM = "ASDF:ASC";
@Test
@Description("Ascending sorting based on name.")
public void parseSortParam1() {
final List<Order> parse = SortUtility.parse(TargetFields.class, SORT_PARAM_1);
assertThat(parse).as("Count of parsing parameter").hasSize(1);
}
@Test
@Description("Ascending sorting based on name and descending sorting based on description.")
public void parseSortParam2() {
final List<Order> parse = SortUtility.parse(TargetFields.class, SORT_PARAM_2);
assertThat(parse).as("Count of parsing parameter").hasSize(2);
}
@Test
@Description("Sorting with wrong syntax leads to SortParameterSyntaxErrorException.")
public void parseWrongSyntaxParam() {
assertThrows(SortParameterSyntaxErrorException.class,
() -> SortUtility.parse(TargetFields.class, SYNTAX_FAILURE_SORT_PARAM));
}
@Test
@Description("Sorting based on name with case sensitive is possible.")
public void parsingIsNotCaseSensitive() {
SortUtility.parse(TargetFields.class, CASE_INSENSITIVE_DIRECTION_PARAM);
SortUtility.parse(TargetFields.class, CASE_INSENSITIVE_DIRECTION_PARAM_1);
}
@Test
@Description("Sorting with unknown direction order leads to SortParameterUnsupportedDirectionException.")
public void parseWrongDirectionParam() {
assertThrows(SortParameterUnsupportedDirectionException.class,
() -> SortUtility.parse(TargetFields.class, WRONG_DIRECTION_PARAM));
}
@Test
@Description("Sorting with unknown field leads to SortParameterUnsupportedFieldException.")
public void parseWrongFieldParam() {
assertThrows(SortParameterUnsupportedFieldException.class,
() -> SortUtility.parse(TargetFields.class, WRONG_FIELD_PARAM));
}
}

View File

@@ -0,0 +1,14 @@
#
# Copyright (c) 2018 Microsoft and others
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Logging START - activate to see request/response details
#logging.level.org.eclipse.hawkbit.rest.util.MockMvcResultPrinter=DEBUG
# Logging END