/* * * Copyright 2015 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.netflix.genie.web.controllers; import com.github.fge.jsonpatch.JsonPatch; import com.google.common.collect.Lists; import com.netflix.genie.common.dto.Application; import com.netflix.genie.common.dto.ApplicationStatus; import com.netflix.genie.common.dto.Cluster; import com.netflix.genie.common.dto.ClusterStatus; import com.netflix.genie.common.dto.Command; import com.netflix.genie.common.dto.CommandStatus; import com.netflix.genie.core.jpa.repositories.JpaApplicationRepository; import com.netflix.genie.core.jpa.repositories.JpaClusterRepository; import com.netflix.genie.core.jpa.repositories.JpaCommandRepository; import com.netflix.genie.web.hateoas.resources.ClusterResource; import com.netflix.genie.web.hateoas.resources.CommandResource; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.MediaTypes; import org.springframework.http.MediaType; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.restdocs.operation.preprocess.Preprocessors; import org.springframework.restdocs.payload.PayloadDocumentation; import org.springframework.restdocs.request.RequestDocumentation; import org.springframework.restdocs.snippet.Attributes; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import java.util.Arrays; import java.util.List; import java.util.UUID; /** * Integration tests for the Commands REST API. * * @author tgianos * @since 3.0.0 */ //TODO: Add tests for error conditions public class CommandRestControllerIntegrationTests extends RestControllerIntegrationTestsBase { private static final String ID = UUID.randomUUID().toString(); private static final String NAME = "hive"; private static final String USER = "genie"; private static final String VERSION = "1.0.0"; private static final String EXECUTABLE = "/apps/hive/bin/hive"; private static final long CHECK_DELAY = 10000L; private static final String EXECUTABLE_PATH = "$.executable"; private static final String CHECK_DELAY_PATH = "$.checkDelay"; private static final String COMMANDS_LIST_PATH = EMBEDDED_PATH + ".commandList"; @Autowired private JpaApplicationRepository jpaApplicationRepository; @Autowired private JpaClusterRepository jpaClusterRepository; @Autowired private JpaCommandRepository jpaCommandRepository; /** * Cleanup after tests. */ @After public void cleanup() { this.jpaClusterRepository.deleteAll(); this.jpaCommandRepository.deleteAll(); this.jpaApplicationRepository.deleteAll(); } /** * Test creating a command without an ID. * * @throws Exception on configuration issue */ @Test public void canCreateCommandWithoutId() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); final RestDocumentationResultHandler creationResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.CONTENT_TYPE_HEADER, // Request headers Snippets.getCommandRequestPayload(), // Request fields Snippets.LOCATION_HEADER // Response headers ); final String id = this.createConfigResource( new Command.Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY).build(), creationResultHandler ); final RestDocumentationResultHandler getResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM, // path parameters Snippets.HAL_CONTENT_TYPE_HEADER, // response headers Snippets.getCommandResponsePayload(), // response payload Snippets.COMMAND_LINKS // response links ); this.mvc .perform(RestDocumentationRequestBuilders.get(COMMANDS_API + "/{id}", id)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath(ID_PATH, Matchers.is(id))) .andExpect(MockMvcResultMatchers.jsonPath(CREATED_PATH, Matchers.notNullValue())) .andExpect(MockMvcResultMatchers.jsonPath(UPDATED_PATH, Matchers.notNullValue())) .andExpect(MockMvcResultMatchers.jsonPath(NAME_PATH, Matchers.is(NAME))) .andExpect(MockMvcResultMatchers.jsonPath(USER_PATH, Matchers.is(USER))) .andExpect(MockMvcResultMatchers.jsonPath(VERSION_PATH, Matchers.is(VERSION))) .andExpect(MockMvcResultMatchers.jsonPath(STATUS_PATH, Matchers.is(CommandStatus.ACTIVE.toString()))) .andExpect(MockMvcResultMatchers.jsonPath(EXECUTABLE_PATH, Matchers.is(EXECUTABLE))) .andExpect(MockMvcResultMatchers.jsonPath(CHECK_DELAY_PATH, Matchers.is((int) CHECK_DELAY))) .andExpect(MockMvcResultMatchers.jsonPath(TAGS_PATH, Matchers.hasSize(2))) .andExpect(MockMvcResultMatchers.jsonPath(TAGS_PATH, Matchers.hasItem("genie.id:" + id))) .andExpect(MockMvcResultMatchers.jsonPath(TAGS_PATH, Matchers.hasItem("genie.name:" + NAME))) .andExpect(MockMvcResultMatchers.jsonPath(LINKS_PATH + ".*", Matchers.hasSize(3))) .andExpect(MockMvcResultMatchers.jsonPath(LINKS_PATH, Matchers.hasKey(SELF_LINK_KEY))) .andExpect(MockMvcResultMatchers.jsonPath(LINKS_PATH, Matchers.hasKey(CLUSTERS_LINK_KEY))) .andExpect(MockMvcResultMatchers.jsonPath(LINKS_PATH, Matchers.hasKey(APPLICATIONS_LINK_KEY))) .andDo(getResultHandler); Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(1L)); } /** * Test creating a Command with an ID. * * @throws Exception When issue in creation */ @Test public void canCreateCommandWithId() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command.Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY).withId(ID).build(), null ); this.mvc .perform(MockMvcRequestBuilders.get(COMMANDS_API + "/" + ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath(ID_PATH, Matchers.is(ID))) .andExpect(MockMvcResultMatchers.jsonPath(CREATED_PATH, Matchers.notNullValue())) .andExpect(MockMvcResultMatchers.jsonPath(UPDATED_PATH, Matchers.notNullValue())) .andExpect(MockMvcResultMatchers.jsonPath(NAME_PATH, Matchers.is(NAME))) .andExpect(MockMvcResultMatchers.jsonPath(USER_PATH, Matchers.is(USER))) .andExpect(MockMvcResultMatchers.jsonPath(VERSION_PATH, Matchers.is(VERSION))) .andExpect(MockMvcResultMatchers.jsonPath(STATUS_PATH, Matchers.is(CommandStatus.ACTIVE.toString()))) .andExpect(MockMvcResultMatchers.jsonPath(EXECUTABLE_PATH, Matchers.is(EXECUTABLE))) .andExpect(MockMvcResultMatchers.jsonPath(CHECK_DELAY_PATH, Matchers.is((int) CHECK_DELAY))) .andExpect(MockMvcResultMatchers.jsonPath(TAGS_PATH, Matchers.hasSize(2))) .andExpect(MockMvcResultMatchers.jsonPath(TAGS_PATH, Matchers.hasItem("genie.id:" + ID))) .andExpect(MockMvcResultMatchers.jsonPath(TAGS_PATH, Matchers.hasItem("genie.name:" + NAME))) .andExpect(MockMvcResultMatchers.jsonPath(LINKS_PATH + ".*", Matchers.hasSize(3))) .andExpect(MockMvcResultMatchers.jsonPath(LINKS_PATH, Matchers.hasKey(SELF_LINK_KEY))) .andExpect(MockMvcResultMatchers.jsonPath(LINKS_PATH, Matchers.hasKey(CLUSTERS_LINK_KEY))) .andExpect(MockMvcResultMatchers.jsonPath(LINKS_PATH, Matchers.hasKey(APPLICATIONS_LINK_KEY))); Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(1L)); } /** * Test to make sure the post API can handle bad input. * * @throws Exception on issue */ @Test public void canHandleBadInputToCreateCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); final Command cluster = new Command.Builder(null, null, null, null, null, -1L).build(); this.mvc.perform( MockMvcRequestBuilders .post(COMMANDS_API) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsBytes(cluster)) ).andExpect(MockMvcResultMatchers.status().isPreconditionFailed()); Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); } /** * Test to make sure that you can search for commands by various parameters. * * @throws Exception on configuration error */ @Test public void canFindCommands() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); final String id1 = UUID.randomUUID().toString(); final String id2 = UUID.randomUUID().toString(); final String id3 = UUID.randomUUID().toString(); final String name1 = UUID.randomUUID().toString(); final String name2 = UUID.randomUUID().toString(); final String name3 = UUID.randomUUID().toString(); final String user1 = UUID.randomUUID().toString(); final String user2 = UUID.randomUUID().toString(); final String user3 = UUID.randomUUID().toString(); final String version1 = UUID.randomUUID().toString(); final String version2 = UUID.randomUUID().toString(); final String version3 = UUID.randomUUID().toString(); final String executable1 = UUID.randomUUID().toString(); final String executable2 = UUID.randomUUID().toString(); final String executable3 = UUID.randomUUID().toString(); this.createConfigResource( new Command .Builder(name1, user1, version1, CommandStatus.ACTIVE, executable1, CHECK_DELAY) .withId(id1) .build(), null ); Thread.sleep(1000); this.createConfigResource( new Command .Builder(name2, user2, version2, CommandStatus.DEPRECATED, executable2, CHECK_DELAY) .withId(id2) .build(), null ); Thread.sleep(1000); this.createConfigResource( new Command .Builder(name3, user3, version3, CommandStatus.INACTIVE, executable3, CHECK_DELAY) .withId(id3) .build(), null ); final RestDocumentationResultHandler findResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.COMMAND_SEARCH_QUERY_PARAMETERS, // Request query parameters Snippets.HAL_CONTENT_TYPE_HEADER, // Response headers Snippets.COMMAND_SEARCH_RESULT_FIELDS, // Result fields Snippets.SEARCH_LINKS // HAL Links ); // Test finding all commands this.mvc .perform(MockMvcRequestBuilders.get(COMMANDS_API)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH, Matchers.hasSize(3))) .andDo(findResultHandler); // Try to limit the number of results this.mvc .perform(MockMvcRequestBuilders.get(COMMANDS_API).param("size", "2")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH, Matchers.hasSize(2))) .andDo(findResultHandler); // Query by name this.mvc .perform(MockMvcRequestBuilders.get(COMMANDS_API).param("name", name2)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH, Matchers.hasSize(1))) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH + "[0].id", Matchers.is(id2))) .andDo(findResultHandler); // Query by user this.mvc .perform(MockMvcRequestBuilders.get(COMMANDS_API).param("user", user3)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH, Matchers.hasSize(1))) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH + "[0].id", Matchers.is(id3))) .andDo(findResultHandler); // Query by statuses this.mvc .perform( MockMvcRequestBuilders .get(COMMANDS_API) .param("status", CommandStatus.ACTIVE.toString(), CommandStatus.INACTIVE.toString()) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH, Matchers.hasSize(2))) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH + "[0].id", Matchers.is(id3))) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH + "[1].id", Matchers.is(id1))) .andDo(findResultHandler); // Query by tags this.mvc .perform(MockMvcRequestBuilders.get(COMMANDS_API).param("tag", "genie.id:" + id1)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH, Matchers.hasSize(1))) .andExpect(MockMvcResultMatchers.jsonPath(COMMANDS_LIST_PATH + "[0].id", Matchers.is(id1))) .andDo(findResultHandler); //TODO: Add tests for sort, orderBy etc Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(3L)); } /** * Test to make sure that a command can be updated. * * @throws Exception on configuration errors */ @Test public void canUpdateCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String commandResource = COMMANDS_API + "/{id}"; final Command createdCommand = objectMapper .readValue( this.mvc.perform( MockMvcRequestBuilders.get(commandResource, ID) ) .andReturn() .getResponse() .getContentAsByteArray(), CommandResource.class ).getContent(); Assert.assertThat(createdCommand.getStatus(), Matchers.is(CommandStatus.ACTIVE)); final Command.Builder updateCommand = new Command.Builder( createdCommand.getName(), createdCommand.getUser(), createdCommand.getVersion(), CommandStatus.INACTIVE, createdCommand.getExecutable(), createdCommand.getCheckDelay() ) .withId(createdCommand.getId().orElseThrow(IllegalArgumentException::new)) .withCreated(createdCommand.getCreated().orElseThrow(IllegalArgumentException::new)) .withUpdated(createdCommand.getUpdated().orElseThrow(IllegalArgumentException::new)) .withTags(createdCommand.getTags()) .withConfigs(createdCommand.getConfigs()); createdCommand.getDescription().ifPresent(updateCommand::withDescription); createdCommand.getSetupFile().ifPresent(updateCommand::withSetupFile); final RestDocumentationResultHandler updateResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.CONTENT_TYPE_HEADER, // request header Snippets.ID_PATH_PARAM, // path parameters Snippets.getCommandRequestPayload() // payload fields ); this.mvc.perform( RestDocumentationRequestBuilders .put(commandResource, ID) .contentType(MediaType.APPLICATION_JSON) .content(this.objectMapper.writeValueAsBytes(updateCommand.build())) ) .andExpect(MockMvcResultMatchers.status().isNoContent()) .andDo(updateResultHandler); this.mvc .perform(MockMvcRequestBuilders.get(commandResource, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect( MockMvcResultMatchers.jsonPath(STATUS_PATH, Matchers.is(CommandStatus.INACTIVE.toString())) ); Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(1L)); } /** * Test to make sure that a command can be patched. * * @throws Exception on configuration errors */ @Test public void canPatchCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); final String id = this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String commandResource = COMMANDS_API + "/{id}"; this.mvc .perform(MockMvcRequestBuilders.get(commandResource, id)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath(NAME_PATH, Matchers.is(NAME))); final String newName = UUID.randomUUID().toString(); final String patchString = "[{ \"op\": \"replace\", \"path\": \"/name\", \"value\": \"" + newName + "\" }]"; final JsonPatch patch = JsonPatch.fromJson(this.objectMapper.readTree(patchString)); final RestDocumentationResultHandler patchResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.CONTENT_TYPE_HEADER, // request headers Snippets.ID_PATH_PARAM, // path params Snippets.PATCH_FIELDS // request payload ); this.mvc .perform( RestDocumentationRequestBuilders .patch(commandResource, id) .contentType(MediaType.APPLICATION_JSON) .content(this.objectMapper.writeValueAsBytes(patch)) ) .andExpect(MockMvcResultMatchers.status().isNoContent()) .andDo(patchResultHandler); this.mvc .perform(MockMvcRequestBuilders.get(commandResource, id)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath(NAME_PATH, Matchers.is(newName))); Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(1L)); } /** * Make sure can successfully delete all commands. * * @throws Exception on a configuration error */ @Test public void canDeleteAllCommands() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .build(), null ); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.DEPRECATED, EXECUTABLE, CHECK_DELAY) .build(), null ); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.INACTIVE, EXECUTABLE, CHECK_DELAY) .build(), null ); Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(3L)); final RestDocumentationResultHandler deleteResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()) ); this.mvc .perform(MockMvcRequestBuilders.delete(COMMANDS_API)) .andExpect(MockMvcResultMatchers.status().isNoContent()) .andDo(deleteResultHandler); Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); } /** * Test to make sure that you can delete a command. * * @throws Exception on configuration error */ @Test public void canDeleteACommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); final String id1 = UUID.randomUUID().toString(); final String id2 = UUID.randomUUID().toString(); final String id3 = UUID.randomUUID().toString(); final String name1 = UUID.randomUUID().toString(); final String name2 = UUID.randomUUID().toString(); final String name3 = UUID.randomUUID().toString(); final String user1 = UUID.randomUUID().toString(); final String user2 = UUID.randomUUID().toString(); final String user3 = UUID.randomUUID().toString(); final String version1 = UUID.randomUUID().toString(); final String version2 = UUID.randomUUID().toString(); final String version3 = UUID.randomUUID().toString(); final String executable1 = UUID.randomUUID().toString(); final String executable2 = UUID.randomUUID().toString(); final String executable3 = UUID.randomUUID().toString(); this.createConfigResource( new Command .Builder(name1, user1, version1, CommandStatus.ACTIVE, executable1, CHECK_DELAY) .withId(id1) .build(), null ); this.createConfigResource( new Command .Builder(name2, user2, version2, CommandStatus.ACTIVE, executable2, CHECK_DELAY) .withId(id2) .build(), null ); this.createConfigResource( new Command .Builder(name3, user3, version3, CommandStatus.ACTIVE, executable3, CHECK_DELAY) .withId(id3) .build(), null ); Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(3L)); final RestDocumentationResultHandler deleteResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM // path parameters ); this.mvc .perform(RestDocumentationRequestBuilders.delete(COMMANDS_API + "/{id}", id2)) .andExpect(MockMvcResultMatchers.status().isNoContent()) .andDo(deleteResultHandler); this.mvc .perform(MockMvcRequestBuilders.get(COMMANDS_API + "/{id}", id2)) .andExpect(MockMvcResultMatchers.status().isNotFound()); Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(2L)); } /** * Test to make sure we can add configurations to the command after it is created. * * @throws Exception on configuration problems */ @Test public void canAddConfigsToCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final RestDocumentationResultHandler addResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM, // path params Snippets.CONTENT_TYPE_HEADER, // request header PayloadDocumentation.requestFields(Snippets.CONFIG_FIELDS) // response fields ); final RestDocumentationResultHandler getResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM, // path params Snippets.JSON_CONTENT_TYPE_HEADER, // response headers PayloadDocumentation.responseFields(Snippets.CONFIG_FIELDS) // response fields ); this.canAddElementsToResource(COMMANDS_API + "/{id}/configs", ID, addResultHandler, getResultHandler); } /** * Test to make sure we can update the configurations for a command after it is created. * * @throws Exception on configuration problems */ @Test public void canUpdateConfigsForCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final RestDocumentationResultHandler updateResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.CONTENT_TYPE_HEADER, // Request header Snippets.ID_PATH_PARAM, // Path parameters PayloadDocumentation.requestFields(Snippets.CONFIG_FIELDS) // Request fields ); this.canUpdateElementsForResource(COMMANDS_API + "/{id}/configs", ID, updateResultHandler); } /** * Test to make sure we can delete the configurations for a command after it is created. * * @throws Exception on configuration problems */ @Test public void canDeleteConfigsForCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final RestDocumentationResultHandler deleteResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM ); this.canDeleteElementsFromResource(COMMANDS_API + "/{id}/configs", ID, deleteResultHandler); } /** * Test to make sure we can add tags to the command after it is created. * * @throws Exception on configuration problems */ @Test public void canAddTagsToCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String api = COMMANDS_API + "/{id}/tags"; final RestDocumentationResultHandler addResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.CONTENT_TYPE_HEADER, // Request header Snippets.ID_PATH_PARAM, // Path parameters PayloadDocumentation.requestFields(Snippets.TAGS_FIELDS) // Request fields ); final RestDocumentationResultHandler getResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM, // Path parameters Snippets.JSON_CONTENT_TYPE_HEADER, // Response header PayloadDocumentation.responseFields(Snippets.TAGS_FIELDS) ); this.canAddTagsToResource(api, ID, NAME, addResultHandler, getResultHandler); } /** * Test to make sure we can update the tags for a command after it is created. * * @throws Exception on configuration problems */ @Test public void canUpdateTagsForCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String api = COMMANDS_API + "/{id}/tags"; final RestDocumentationResultHandler updateResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.CONTENT_TYPE_HEADER, // Request header Snippets.ID_PATH_PARAM, // Path parameters PayloadDocumentation.requestFields(Snippets.TAGS_FIELDS) // Request fields ); this.canUpdateTagsForResource(api, ID, NAME, updateResultHandler); } /** * Test to make sure we can delete the tags for a command after it is created. * * @throws Exception on configuration problems */ @Test public void canDeleteTagsForCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String api = COMMANDS_API + "/{id}/tags"; final RestDocumentationResultHandler deleteResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM ); this.canDeleteTagsForResource(api, ID, NAME, deleteResultHandler); } /** * Test to make sure we can delete a tag for a command after it is created. * * @throws Exception on configuration problems */ @Test public void canDeleteTagForCommand() throws Exception { Assert.assertThat(this.jpaCommandRepository.count(), Matchers.is(0L)); this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String api = COMMANDS_API + "/{id}/tags"; final RestDocumentationResultHandler deleteResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM.and( RequestDocumentation.parameterWithName("tag").description("The tag to remove") ) ); this.canDeleteTagForResource(api, ID, NAME, deleteResultHandler); } /** * Make sure can add the applications for a command. * * @throws Exception on configuration error */ @Test public void canAddApplicationsForACommand() throws Exception { this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String commandApplicationsAPI = COMMANDS_API + "/{id}/applications"; this.mvc .perform(MockMvcRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.empty())); final String placeholder = UUID.randomUUID().toString(); final String applicationId1 = UUID.randomUUID().toString(); final String applicationId2 = UUID.randomUUID().toString(); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId1) .build(), null ); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId2) .build(), null ); final RestDocumentationResultHandler addResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.CONTENT_TYPE_HEADER, // Request Headers Snippets.ID_PATH_PARAM, // Path parameters PayloadDocumentation.requestFields( PayloadDocumentation .fieldWithPath("[]") .description("Array of application ids to add to existing set of applications") .attributes(Snippets.EMPTY_CONSTRAINTS) ) // Request payload ); this.mvc .perform( RestDocumentationRequestBuilders .post(commandApplicationsAPI, ID) .contentType(MediaType.APPLICATION_JSON) .content(this.objectMapper.writeValueAsBytes(Lists.newArrayList(applicationId1, applicationId2))) ) .andExpect(MockMvcResultMatchers.status().isNoContent()) .andDo(addResultHandler); this.mvc .perform(MockMvcRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))) .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.is(applicationId1))) .andExpect(MockMvcResultMatchers.jsonPath("$[1].id", Matchers.is(applicationId2))); //Shouldn't add anything this.mvc .perform( MockMvcRequestBuilders .post(commandApplicationsAPI, ID) .contentType(MediaType.APPLICATION_JSON) .content(this.objectMapper.writeValueAsBytes(Lists.newArrayList())) ) .andExpect(MockMvcResultMatchers.status().isPreconditionFailed()); final String applicationId3 = UUID.randomUUID().toString(); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId3) .build(), null ); this.mvc .perform( MockMvcRequestBuilders .post(commandApplicationsAPI, ID) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsBytes(Lists.newArrayList(applicationId3))) ) .andExpect(MockMvcResultMatchers.status().isNoContent()); final RestDocumentationResultHandler getResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM, // Path parameters Snippets.HAL_CONTENT_TYPE_HEADER, // Response Headers PayloadDocumentation.responseFields( PayloadDocumentation .fieldWithPath("[]") .description("The set of applications this command depends on") .attributes(Snippets.EMPTY_CONSTRAINTS) ) ); this.mvc .perform(RestDocumentationRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(3))) .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.is(applicationId1))) .andExpect(MockMvcResultMatchers.jsonPath("$[1].id", Matchers.is(applicationId2))) .andExpect(MockMvcResultMatchers.jsonPath("$[2].id", Matchers.is(applicationId3))) .andDo(getResultHandler); } /** * Make sure can set the applications for a command. * * @throws Exception on configuration error */ @Test public void canSetApplicationsForACommand() throws Exception { this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String commandApplicationsAPI = COMMANDS_API + "/{id}/applications"; this.mvc .perform(MockMvcRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.empty())); final String placeholder = UUID.randomUUID().toString(); final String applicationId1 = UUID.randomUUID().toString(); final String applicationId2 = UUID.randomUUID().toString(); final String applicationId3 = UUID.randomUUID().toString(); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId1) .build(), null ); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId2) .build(), null ); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId3) .build(), null ); final RestDocumentationResultHandler setResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.CONTENT_TYPE_HEADER, // Request Headers Snippets.ID_PATH_PARAM, // Path parameters PayloadDocumentation.requestFields( PayloadDocumentation .fieldWithPath("[]") .description("Array of application ids to replace the existing set of applications with") .attributes(Snippets.EMPTY_CONSTRAINTS) ) // Request payload ); this.mvc .perform( RestDocumentationRequestBuilders .put(commandApplicationsAPI, ID) .contentType(MediaType.APPLICATION_JSON) .content(this.objectMapper.writeValueAsBytes(Lists.newArrayList(applicationId1, applicationId2))) ) .andExpect(MockMvcResultMatchers.status().isNoContent()) .andDo(setResultHandler); this.mvc .perform(MockMvcRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))) .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.is(applicationId1))) .andExpect(MockMvcResultMatchers.jsonPath("$[1].id", Matchers.is(applicationId2))); // Should flip the order this.mvc .perform( MockMvcRequestBuilders .put(commandApplicationsAPI, ID) .contentType(MediaType.APPLICATION_JSON) .content(this.objectMapper.writeValueAsBytes(Lists.newArrayList(applicationId2, applicationId1))) ) .andExpect(MockMvcResultMatchers.status().isNoContent()); this.mvc .perform(MockMvcRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))) .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.is(applicationId2))) .andExpect(MockMvcResultMatchers.jsonPath("$[1].id", Matchers.is(applicationId1))); // Should reorder and add a new one this.mvc .perform( MockMvcRequestBuilders .put(commandApplicationsAPI, ID) .contentType(MediaType.APPLICATION_JSON) .content( objectMapper.writeValueAsBytes( Lists.newArrayList(applicationId1, applicationId2, applicationId3)) ) ) .andExpect(MockMvcResultMatchers.status().isNoContent()); this.mvc .perform(MockMvcRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(3))) .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.is(applicationId1))) .andExpect(MockMvcResultMatchers.jsonPath("$[1].id", Matchers.is(applicationId2))) .andExpect(MockMvcResultMatchers.jsonPath("$[2].id", Matchers.is(applicationId3))); //Should clear applications this.mvc .perform( MockMvcRequestBuilders .put(commandApplicationsAPI, ID) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsBytes(Lists.newArrayList())) ) .andExpect(MockMvcResultMatchers.status().isNoContent()); this.mvc .perform(MockMvcRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.empty())); } /** * Make sure that we can remove all the applications from a command. * * @throws Exception on configuration error */ @Test public void canRemoveApplicationsFromACommand() throws Exception { this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String commandApplicationsAPI = COMMANDS_API + "/{id}/applications"; final String placeholder = UUID.randomUUID().toString(); final String applicationId1 = UUID.randomUUID().toString(); final String applicationId2 = UUID.randomUUID().toString(); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId1) .build(), null ); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId2) .build(), null ); this.mvc .perform( MockMvcRequestBuilders .post(commandApplicationsAPI, ID) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsBytes(Lists.newArrayList(applicationId1, applicationId2))) ) .andExpect(MockMvcResultMatchers.status().isNoContent()); final RestDocumentationResultHandler deleteResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM // Path parameters ); this.mvc .perform(RestDocumentationRequestBuilders.delete(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isNoContent()) .andDo(deleteResultHandler); this.mvc .perform(MockMvcRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.empty())); } /** * Make sure that we can remove an application from a command. * * @throws Exception on configuration error */ @Test public void canRemoveApplicationFromACommand() throws Exception { this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String commandApplicationsAPI = COMMANDS_API + "/{id}/applications"; final String placeholder = UUID.randomUUID().toString(); final String applicationId1 = UUID.randomUUID().toString(); final String applicationId2 = UUID.randomUUID().toString(); final String applicationId3 = UUID.randomUUID().toString(); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId1) .build(), null ); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId2) .build(), null ); this.createConfigResource( new Application .Builder(placeholder, placeholder, placeholder, ApplicationStatus.ACTIVE) .withId(applicationId3) .build(), null ); this.mvc .perform( MockMvcRequestBuilders .post(commandApplicationsAPI, ID) .contentType(MediaType.APPLICATION_JSON) .content( this.objectMapper.writeValueAsBytes( Lists.newArrayList(applicationId1, applicationId2, applicationId3) ) ) ) .andExpect(MockMvcResultMatchers.status().isNoContent()); final RestDocumentationResultHandler deleteResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM.and( RequestDocumentation .parameterWithName("applicationId") .description("The id of the application to remove") ) // Path parameters ); this.mvc .perform(RestDocumentationRequestBuilders .delete(commandApplicationsAPI + "/{applicationId}", ID, applicationId2)) .andExpect(MockMvcResultMatchers.status().isNoContent()) .andDo(deleteResultHandler); this.mvc .perform(MockMvcRequestBuilders.get(commandApplicationsAPI, ID)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))) .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.is(applicationId1))) .andExpect(MockMvcResultMatchers.jsonPath("$[1].id", Matchers.is(applicationId3))); // Check reverse side of relationship this.mvc .perform(MockMvcRequestBuilders.get(APPLICATIONS_API + "/{id}/commands", applicationId1)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.is(ID))); this.mvc .perform(MockMvcRequestBuilders.get(APPLICATIONS_API + "/{id}/commands", applicationId2)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.empty())); this.mvc .perform(MockMvcRequestBuilders.get(APPLICATIONS_API + "/{id}/commands", applicationId3)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.is(ID))); } /** * Make sure can get all the clusters which use a given command. * * @throws Exception on configuration error */ @Test public void canGetClustersForCommand() throws Exception { this.createConfigResource( new Command .Builder(NAME, USER, VERSION, CommandStatus.ACTIVE, EXECUTABLE, CHECK_DELAY) .withId(ID) .build(), null ); final String placeholder = UUID.randomUUID().toString(); final String cluster1Id = UUID.randomUUID().toString(); final String cluster2Id = UUID.randomUUID().toString(); final String cluster3Id = UUID.randomUUID().toString(); this.createConfigResource( new Cluster.Builder(placeholder, placeholder, placeholder, ClusterStatus.UP).withId(cluster1Id).build(), null ); this.createConfigResource( new Cluster .Builder(placeholder, placeholder, placeholder, ClusterStatus.OUT_OF_SERVICE) .withId(cluster2Id) .build(), null ); this.createConfigResource( new Cluster .Builder(placeholder, placeholder, placeholder, ClusterStatus.TERMINATED) .withId(cluster3Id) .build(), null ); final List<String> commandIds = Lists.newArrayList(ID); this.mvc .perform( MockMvcRequestBuilders .post(CLUSTERS_API + "/" + cluster1Id + "/commands") .contentType(MediaType.APPLICATION_JSON) .content(this.objectMapper.writeValueAsBytes(commandIds)) ) .andExpect(MockMvcResultMatchers.status().isNoContent()); this.mvc .perform( MockMvcRequestBuilders .post(CLUSTERS_API + "/" + cluster3Id + "/commands") .contentType(MediaType.APPLICATION_JSON) .content(this.objectMapper.writeValueAsBytes(commandIds)) ) .andExpect(MockMvcResultMatchers.status().isNoContent()); Arrays.stream( this.objectMapper.readValue( this.mvc .perform(MockMvcRequestBuilders.get(COMMANDS_API + "/" + ID + "/clusters")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))) .andReturn() .getResponse() .getContentAsByteArray(), ClusterResource[].class ) ) .map(ClusterResource::getContent) .forEach( cluster -> { final String id = cluster.getId().orElseThrow(IllegalArgumentException::new); if (!id.equals(cluster1Id) && !id.equals(cluster3Id)) { Assert.fail(); } } ); // Test filtering final RestDocumentationResultHandler getResultHandler = MockMvcRestDocumentation.document( "{class-name}/{method-name}/{step}/", Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), Preprocessors.preprocessResponse(Preprocessors.prettyPrint()), Snippets.ID_PATH_PARAM, // Path parameters RequestDocumentation.requestParameters( RequestDocumentation .parameterWithName("status") .description("The status of clusters to search for") .attributes( Attributes.key(Snippets.CONSTRAINTS).value(CommandStatus.values()) ) .optional() ), // Query Parameters Snippets.HAL_CONTENT_TYPE_HEADER, // Response Headers PayloadDocumentation.responseFields( PayloadDocumentation .fieldWithPath("[]") .description("The list of clusters found") .attributes(Snippets.EMPTY_CONSTRAINTS) ) ); this.mvc .perform( RestDocumentationRequestBuilders .get(COMMANDS_API + "/{id}/clusters", ID) .param("status", ClusterStatus.UP.toString()) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.is(cluster1Id))) .andDo(getResultHandler); } }